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:
@@ -30,7 +30,11 @@
|
||||
if(!M.viewing_alternate_appearances)
|
||||
M.viewing_alternate_appearances = list()
|
||||
viewers |= M
|
||||
M.viewing_alternate_appearances[key] = src
|
||||
var/list/AAsiblings = M.viewing_alternate_appearances[key]
|
||||
if(!AAsiblings)
|
||||
AAsiblings = list()
|
||||
M.viewing_alternate_appearances[key] = AAsiblings
|
||||
AAsiblings |= src
|
||||
if(M.client)
|
||||
M.client.images |= img
|
||||
|
||||
@@ -48,9 +52,13 @@
|
||||
if(M.client)
|
||||
M.client.images -= img
|
||||
if(M.viewing_alternate_appearances && M.viewing_alternate_appearances.len)
|
||||
M.viewing_alternate_appearances -= key
|
||||
if(!M.viewing_alternate_appearances.len)
|
||||
M.viewing_alternate_appearances = null
|
||||
var/list/AAsiblings = M.viewing_alternate_appearances[key]
|
||||
if(AAsiblings)
|
||||
AAsiblings -= src
|
||||
if(!AAsiblings.len)
|
||||
M.viewing_alternate_appearances -= key
|
||||
if(!M.viewing_alternate_appearances.len)
|
||||
M.viewing_alternate_appearances = null
|
||||
viewers -= M
|
||||
|
||||
|
||||
@@ -73,8 +81,9 @@
|
||||
|
||||
/atom
|
||||
var/list/alternate_appearances //the alternate appearances we own
|
||||
var/list/viewing_alternate_appearances //the alternate appearances we're viewing, stored here to reestablish them after Logout()s
|
||||
//these lists are built/destroyed as necessary, so atoms aren't all lugging around lists full of datums
|
||||
var/list/viewing_alternate_appearances //this is an assoc list of lists, the keys being the AA's key
|
||||
//inside these lists are the AAs themselves, this is to allow the atom to see multiple of the same type of AA
|
||||
//eg: two (or more) people disguised as cardborgs, or two (or more) people disguised as plants
|
||||
|
||||
/*
|
||||
Builds an alternate_appearance datum for the supplied args, optionally displaying it straight away
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,30 @@
|
||||
/area/ai_monitored
|
||||
name = "AI Monitored Area"
|
||||
var/obj/machinery/camera/motioncamera = null
|
||||
var/list/obj/machinery/camera/motioncameras = list()
|
||||
var/list/motionTargets = list()
|
||||
|
||||
|
||||
/area/ai_monitored/New()
|
||||
/area/ai_monitored/Initialize(mapload)
|
||||
..()
|
||||
// locate and store the motioncamera
|
||||
spawn (20) // spawn on a delay to let turfs/objs load
|
||||
if(mapload)
|
||||
for (var/obj/machinery/camera/M in src)
|
||||
if(M.isMotion())
|
||||
motioncamera = M
|
||||
motioncameras.Add(M)
|
||||
M.area_motion = src
|
||||
|
||||
//Only need to use one camera
|
||||
|
||||
/area/ai_monitored/Entered(atom/movable/O)
|
||||
..()
|
||||
if (ismob(O) && motioncamera)
|
||||
motioncamera.newTarget(O)
|
||||
if (ismob(O) && motioncameras.len)
|
||||
for(var/X in motioncameras)
|
||||
var/obj/machinery/camera/cam = X
|
||||
cam.newTarget(O)
|
||||
return
|
||||
|
||||
/area/ai_monitored/Exited(atom/movable/O)
|
||||
if (ismob(O) && motioncamera)
|
||||
motioncamera.lostTarget(O)
|
||||
|
||||
|
||||
..()
|
||||
if (ismob(O) && motioncameras.len)
|
||||
for(var/X in motioncameras)
|
||||
var/obj/machinery/camera/cam = X
|
||||
cam.lostTarget(O)
|
||||
return
|
||||
+132
-30
@@ -1,20 +1,55 @@
|
||||
// Areas.dm
|
||||
|
||||
// Added to fix mech fabs 05/2013 ~Sayu
|
||||
// This is necessary due to lighting subareas. If you were to go in assuming that things in
|
||||
// the same logical /area have the parent /area object... well, you would be mistaken. If you
|
||||
// want to find machines, mobs, etc, in the same logical area, you will need to check all the
|
||||
// related areas. This returns a master contents list to assist in that.
|
||||
/proc/area_contents(var/area/A)
|
||||
if(!istype(A)) return null
|
||||
var/list/contents = list()
|
||||
for(var/area/LSA in A.related)
|
||||
contents += LSA.contents
|
||||
return contents
|
||||
|
||||
|
||||
// ===
|
||||
/area
|
||||
level = null
|
||||
name = "Space"
|
||||
icon = 'icons/turf/areas.dmi'
|
||||
icon_state = "unknown"
|
||||
layer = AREA_LAYER
|
||||
mouse_opacity = 0
|
||||
invisibility = INVISIBILITY_LIGHTING
|
||||
|
||||
var/map_name // Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
|
||||
|
||||
var/valid_territory = 1 // If it's a valid territory for gangs to claim
|
||||
var/blob_allowed = 1 // Does it count for blobs score? By default, all areas count.
|
||||
|
||||
var/eject = null
|
||||
|
||||
var/fire = null
|
||||
var/atmos = 1
|
||||
var/atmosalm = 0
|
||||
var/poweralm = 1
|
||||
var/party = null
|
||||
var/lightswitch = 1
|
||||
|
||||
var/requires_power = 1
|
||||
var/always_unpowered = 0 // This gets overriden to 1 for space in area/New().
|
||||
|
||||
var/outdoors = 0 //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
|
||||
|
||||
var/power_equip = 1
|
||||
var/power_light = 1
|
||||
var/power_environ = 1
|
||||
var/music = null
|
||||
var/used_equip = 0
|
||||
var/used_light = 0
|
||||
var/used_environ = 0
|
||||
var/static_equip
|
||||
var/static_light = 0
|
||||
var/static_environ
|
||||
|
||||
var/has_gravity = 0
|
||||
var/noteleport = 0 //Are you forbidden from teleporting to the area? (centcomm, mobs, wizard, hand teleporter)
|
||||
var/safe = 0 //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
|
||||
|
||||
var/no_air = null
|
||||
var/area/master // master area used for power calcluations
|
||||
var/list/related // the other areas of the same type as this
|
||||
|
||||
var/parallax_movedir = 0
|
||||
|
||||
var/global/global_uid = 0
|
||||
var/uid
|
||||
var/list/ambientsounds = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg',\
|
||||
@@ -23,6 +58,44 @@
|
||||
'sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg',\
|
||||
'sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg',\
|
||||
'sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
|
||||
flags = CAN_BE_DIRTY
|
||||
var/firedoors_last_closed_on = 0
|
||||
|
||||
|
||||
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
|
||||
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
|
||||
var/list/teleportlocs = list()
|
||||
|
||||
/proc/process_teleport_locs()
|
||||
for(var/V in sortedAreas)
|
||||
var/area/AR = V
|
||||
if(istype(AR, /area/shuttle) || AR.noteleport)
|
||||
continue
|
||||
if(teleportlocs[AR.name])
|
||||
continue
|
||||
var/turf/picked = safepick(get_area_turfs(AR.type))
|
||||
if (picked && (picked.z == ZLEVEL_STATION))
|
||||
teleportlocs[AR.name] = AR
|
||||
|
||||
sortTim(teleportlocs, /proc/cmp_text_dsc)
|
||||
|
||||
// ===
|
||||
|
||||
|
||||
// Added to fix mech fabs 05/2013 ~Sayu
|
||||
// This is necessary due to lighting subareas. If you were to go in assuming that things in
|
||||
// the same logical /area have the parent /area object... well, you would be mistaken. If you
|
||||
// want to find machines, mobs, etc, in the same logical area, you will need to check all the
|
||||
// related areas. This returns a master contents list to assist in that.
|
||||
/proc/area_contents(area/A)
|
||||
if(!istype(A)) return null
|
||||
var/list/contents = list()
|
||||
for(var/area/LSA in A.related)
|
||||
contents += LSA.contents
|
||||
return contents
|
||||
|
||||
|
||||
|
||||
|
||||
/area/New()
|
||||
icon_state = ""
|
||||
@@ -39,8 +112,8 @@
|
||||
power_equip = 1
|
||||
power_environ = 1
|
||||
|
||||
if (dynamic_lighting != DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
if (lighting_use_dynamic != DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
|
||||
|
||||
..()
|
||||
|
||||
@@ -48,7 +121,9 @@
|
||||
|
||||
blend_mode = BLEND_MULTIPLY // Putting this in the constructor so that it stops the icons being screwed up in the map editor.
|
||||
|
||||
|
||||
/area/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/area/proc/poweralert(state, obj/source)
|
||||
if (state != poweralm)
|
||||
@@ -74,6 +149,11 @@
|
||||
D.cancelAlarm("Power", src, source)
|
||||
else
|
||||
D.triggerAlarm("Power", src, cameras, source)
|
||||
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
|
||||
if(state == 1)
|
||||
p.cancelAlarm("Power", src, source)
|
||||
else
|
||||
p.triggerAlarm("Power", src, cameras, source)
|
||||
|
||||
/area/proc/atmosalert(danger_level, obj/source)
|
||||
if(danger_level != atmosalm)
|
||||
@@ -89,6 +169,8 @@
|
||||
a.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
for(var/mob/living/simple_animal/drone/D in mob_list)
|
||||
D.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
|
||||
p.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
|
||||
else if (src.atmosalm == 2)
|
||||
for(var/mob/living/silicon/aiPlayer in player_list)
|
||||
@@ -97,11 +179,22 @@
|
||||
a.cancelAlarm("Atmosphere", src, source)
|
||||
for(var/mob/living/simple_animal/drone/D in mob_list)
|
||||
D.cancelAlarm("Atmosphere", src, source)
|
||||
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
|
||||
p.cancelAlarm("Atmosphere", src, source)
|
||||
|
||||
src.atmosalm = danger_level
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/area/proc/CloseFiredoors()
|
||||
firedoors_last_closed_on = world.time
|
||||
for(var/obj/machinery/door/firedoor/D in src)
|
||||
if(!D.welded)
|
||||
if(D.operating)
|
||||
D.nextstate = CLOSED
|
||||
else if(!D.density)
|
||||
INVOKE_ASYNC(D, /obj/machinery/door/firedoor.proc/close)
|
||||
|
||||
/area/proc/firealert(obj/source)
|
||||
if(always_unpowered == 1) //no fire alarms in space/asteroid
|
||||
return
|
||||
@@ -111,12 +204,7 @@
|
||||
for(var/area/RA in related)
|
||||
if (!( RA.fire ))
|
||||
RA.set_fire_alarm_effect()
|
||||
for(var/obj/machinery/door/firedoor/D in RA)
|
||||
if(!D.welded)
|
||||
if(D.operating)
|
||||
D.nextstate = CLOSED
|
||||
else if(!D.density)
|
||||
addtimer(D, "close", 0)
|
||||
RA.CloseFiredoors()
|
||||
for(var/obj/machinery/firealarm/F in RA)
|
||||
F.update_icon()
|
||||
for (var/obj/machinery/camera/C in RA)
|
||||
@@ -128,6 +216,10 @@
|
||||
aiPlayer.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/mob/living/simple_animal/drone/D in mob_list)
|
||||
D.triggerAlarm("Fire", src, cameras, source)
|
||||
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
|
||||
p.triggerAlarm("Fire", src, cameras, source)
|
||||
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/area/proc/firereset(obj/source)
|
||||
for(var/area/RA in related)
|
||||
@@ -140,7 +232,7 @@
|
||||
if(D.operating)
|
||||
D.nextstate = OPEN
|
||||
else if(D.density)
|
||||
addtimer(D, "open", 0)
|
||||
INVOKE_ASYNC(D, /obj/machinery/door/firedoor.proc/open)
|
||||
for(var/obj/machinery/firealarm/F in RA)
|
||||
F.update_icon()
|
||||
|
||||
@@ -150,6 +242,15 @@
|
||||
a.cancelAlarm("Fire", src, source)
|
||||
for (var/mob/living/simple_animal/drone/D in mob_list)
|
||||
D.cancelAlarm("Fire", src, source)
|
||||
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
|
||||
p.cancelAlarm("Fire", src, source)
|
||||
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/area/process()
|
||||
if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
|
||||
for(var/area/RA in related)
|
||||
RA.CloseFiredoors()
|
||||
|
||||
/area/proc/burglaralert(obj/trigger)
|
||||
if(always_unpowered == 1) //no burglar alarms in space/asteroid
|
||||
@@ -172,7 +273,7 @@
|
||||
for (var/mob/living/silicon/SILICON in player_list)
|
||||
if(SILICON.triggerAlarm("Burglar", src, cameras, trigger))
|
||||
//Cancel silicon alert after 1 minute
|
||||
addtimer(SILICON, "cancelAlarm", 600, FALSE,"Burglar",src,trigger)
|
||||
addtimer(CALLBACK(SILICON, /mob/living/silicon.proc/cancelAlarm,"Burglar",src,trigger), 600)
|
||||
|
||||
/area/proc/set_fire_alarm_effect()
|
||||
fire = 1
|
||||
@@ -209,7 +310,7 @@
|
||||
if(D.operating)
|
||||
D.nextstate = OPEN
|
||||
else if(D.density)
|
||||
addtimer(D, "open", 0)
|
||||
INVOKE_ASYNC(D, /obj/machinery/door/firedoor.proc/open)
|
||||
|
||||
/area/proc/updateicon()
|
||||
if ((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
|
||||
@@ -310,7 +411,7 @@
|
||||
|
||||
|
||||
/area/Entered(A)
|
||||
if(!istype(A,/mob/living))
|
||||
if(!isliving(A))
|
||||
return
|
||||
|
||||
var/mob/living/L = A
|
||||
@@ -335,11 +436,11 @@
|
||||
if(L.&& L.client)
|
||||
L.client.played = 0
|
||||
|
||||
/proc/has_gravity(atom/AT, turf/T)
|
||||
if(!T)
|
||||
T = get_turf(AT)
|
||||
/atom/proc/has_gravity(turf/T)
|
||||
if(!T || !isturf(T))
|
||||
T = get_turf(src)
|
||||
var/area/A = get_area(T)
|
||||
if(istype(T, /turf/open/space)) // Turf never has gravity
|
||||
if(isspaceturf(T)) // Turf never has gravity
|
||||
return 0
|
||||
else if(A && A.has_gravity) // Areas which always has gravity
|
||||
return 1
|
||||
@@ -356,4 +457,5 @@
|
||||
power_environ = 0
|
||||
always_unpowered = 0
|
||||
valid_territory = 0
|
||||
blob_allowed = 0
|
||||
addSorted()
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
|
||||
// Away Missions
|
||||
/area/awaymission
|
||||
name = "Strange Location"
|
||||
icon_state = "away"
|
||||
has_gravity = 1
|
||||
|
||||
/area/awaymission/example
|
||||
name = "Strange Station"
|
||||
icon_state = "away"
|
||||
|
||||
/area/awaymission/desert
|
||||
name = "Mars"
|
||||
icon_state = "away"
|
||||
|
||||
/area/awaymission/listeningpost
|
||||
name = "Listening Post"
|
||||
icon_state = "away"
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/beach
|
||||
name = "Beach"
|
||||
icon_state = "away"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg')
|
||||
|
||||
/area/awaymission/errorroom
|
||||
name = "Super Secret Room"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
|
||||
has_gravity = 1
|
||||
|
||||
|
||||
//Research Base Areas//--
|
||||
|
||||
/area/awaymission/research
|
||||
name = "Research Outpost"
|
||||
icon_state = "away"
|
||||
luminosity = 0
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
|
||||
|
||||
/area/awaymission/research/interior
|
||||
name = "Research Inside"
|
||||
requires_power = 1
|
||||
icon_state = "away2"
|
||||
|
||||
/area/awaymission/research/interior/cryo
|
||||
name = "Research Cryostasis Room"
|
||||
icon_state = "medbay"
|
||||
|
||||
/area/awaymission/research/interior/clonestorage
|
||||
name = "Research Clone Storage"
|
||||
icon_state = "cloning"
|
||||
|
||||
/area/awaymission/research/interior/genetics
|
||||
name = "Research Genetics Research"
|
||||
icon_state = "genetics"
|
||||
|
||||
/area/awaymission/research/interior/engineering
|
||||
name = "Research Engineering"
|
||||
icon_state = "engine"
|
||||
|
||||
/area/awaymission/research/interior/security
|
||||
name = "Research Security"
|
||||
icon_state = "security"
|
||||
|
||||
/area/awaymission/research/interior/secure
|
||||
name = "Research Secure Vault"
|
||||
|
||||
/area/awaymission/research/interior/maint
|
||||
name = "Research Maintenance"
|
||||
icon_state = "maintcentral"
|
||||
|
||||
/area/awaymission/research/interior/dorm
|
||||
name = "Research Dorms"
|
||||
icon_state = "Sleep"
|
||||
|
||||
/area/awaymission/research/interior/escapepods
|
||||
name = "Research Escape Wing"
|
||||
icon_state = "exit"
|
||||
|
||||
/area/awaymission/research/interior/gateway
|
||||
name = "Research Gateway"
|
||||
icon_state = "start"
|
||||
|
||||
/area/awaymission/research/interior/bathroom
|
||||
name = "Research Bathrooms"
|
||||
icon_state = "restrooms"
|
||||
|
||||
/area/awaymission/research/interior/medbay
|
||||
name = "Research Medbay"
|
||||
icon_state = "medbay"
|
||||
|
||||
/area/awaymission/research/exterior
|
||||
name = "Research Exterior"
|
||||
icon_state = "unknown"
|
||||
|
||||
|
||||
|
||||
//Challenge Areas
|
||||
|
||||
/area/awaymission/challenge/start
|
||||
name = "Where Am I?"
|
||||
icon_state = "away"
|
||||
|
||||
/area/awaymission/challenge/main
|
||||
name = "Danger Room"
|
||||
icon_state = "away1"
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/challenge/end
|
||||
name = "Administration"
|
||||
icon_state = "away2"
|
||||
requires_power = 0
|
||||
|
||||
|
||||
//centcomAway areas
|
||||
|
||||
/area/awaymission/centcomAway
|
||||
name = "XCC-P5831"
|
||||
icon_state = "away"
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/centcomAway/general
|
||||
name = "XCC-P5831"
|
||||
music = "music/ambigen3.ogg"
|
||||
|
||||
/area/awaymission/centcomAway/maint
|
||||
name = "XCC-P5831 Maintenance"
|
||||
icon_state = "away1"
|
||||
music = "music/ambisin1.ogg"
|
||||
|
||||
/area/awaymission/centcomAway/thunderdome
|
||||
name = "XCC-P5831 Thunderdome"
|
||||
icon_state = "away2"
|
||||
music = "music/ambisin2.ogg"
|
||||
|
||||
/area/awaymission/centcomAway/cafe
|
||||
name = "XCC-P5831 Kitchen Arena"
|
||||
icon_state = "away3"
|
||||
music = "music/ambisin3.ogg"
|
||||
|
||||
/area/awaymission/centcomAway/courtroom
|
||||
name = "XCC-P5831 Courtroom"
|
||||
icon_state = "away4"
|
||||
music = "music/ambisin4.ogg"
|
||||
|
||||
/area/awaymission/centcomAway/hangar
|
||||
name = "XCC-P5831 Hangars"
|
||||
icon_state = "away4"
|
||||
music = "music/ambigen5.ogg"
|
||||
|
||||
|
||||
/*Cabin areas*/
|
||||
/area/awaymission/snowforest
|
||||
name = "Snow Forest"
|
||||
icon_state = "away"
|
||||
requires_power = 0
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
|
||||
|
||||
/area/awaymission/cabin
|
||||
name = "Cabin"
|
||||
icon_state = "away2"
|
||||
requires_power = 1
|
||||
luminosity = 0
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
|
||||
|
||||
/area/awaymission/snowforest/lumbermill
|
||||
name = "Lumbermill"
|
||||
icon_state = "away3"
|
||||
|
||||
//Packer Ship Areas
|
||||
|
||||
/area/awaymission/BMPship
|
||||
name = "BMP Asteroids"
|
||||
icon_state = "away"
|
||||
luminosity = 0
|
||||
|
||||
|
||||
/area/awaymission/BMPship/Aft
|
||||
name = "Aft Block"
|
||||
icon_state = "away1"
|
||||
requires_power = 1
|
||||
|
||||
/area/awaymission/BMPship/Midship
|
||||
name = "Midship Block"
|
||||
icon_state = "away2"
|
||||
requires_power = 1
|
||||
|
||||
/area/awaymission/BMPship/Fore
|
||||
name = "Fore Block"
|
||||
icon_state = "away3"
|
||||
requires_power = 1
|
||||
|
||||
|
||||
//Academy Areas
|
||||
|
||||
/area/awaymission/academy
|
||||
name = "Academy Asteroids"
|
||||
icon_state = "away"
|
||||
|
||||
/area/awaymission/academy/headmaster
|
||||
name = "Academy Fore Block"
|
||||
icon_state = "away1"
|
||||
|
||||
/area/awaymission/academy/classrooms
|
||||
name = "Academy Classroom Block"
|
||||
icon_state = "away2"
|
||||
|
||||
/area/awaymission/academy/academyaft
|
||||
name = "Academy Ship Aft Block"
|
||||
icon_state = "away3"
|
||||
|
||||
/area/awaymission/academy/academygate
|
||||
name = "Academy Gateway"
|
||||
icon_state = "away4"
|
||||
|
||||
/area/awaymission/academy/academycellar
|
||||
name = "Academy Cellar"
|
||||
icon_state = "away4"
|
||||
|
||||
/area/awaymission/academy/academyengine
|
||||
name = "Academy Engine"
|
||||
icon_state = "away4"
|
||||
|
||||
|
||||
|
||||
//Wild West Areas
|
||||
|
||||
/area/awaymission/wwmines
|
||||
name = "Wild West Mines"
|
||||
icon_state = "away1"
|
||||
luminosity = 1
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/wwgov
|
||||
name = "Wild West Mansion"
|
||||
icon_state = "away2"
|
||||
luminosity = 1
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/wwrefine
|
||||
name = "Wild West Refinery"
|
||||
icon_state = "away3"
|
||||
luminosity = 1
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/wwvault
|
||||
name = "Wild West Vault"
|
||||
icon_state = "away3"
|
||||
luminosity = 0
|
||||
|
||||
/area/awaymission/wwvaultdoors
|
||||
name = "Wild West Vault Doors" // this is to keep the vault area being entirely lit because of requires_power
|
||||
icon_state = "away2"
|
||||
requires_power = 0
|
||||
luminosity = 0
|
||||
|
||||
|
||||
/*
|
||||
* Areas
|
||||
*/
|
||||
//Gateroom gets its own APC specifically for the gate
|
||||
/area/awaymission/gateroom
|
||||
|
||||
//Library, medbay, storage room
|
||||
/area/awaymission/southblock
|
||||
|
||||
//Arrivals, security, hydroponics, shuttles (since they dont move, they dont need specific areas)
|
||||
/area/awaymission/arrivalblock
|
||||
|
||||
//Crew quarters, cafeteria, chapel
|
||||
/area/awaymission/midblock
|
||||
|
||||
//engineering, bridge (not really north but it doesnt really need its own APC)
|
||||
/area/awaymission/northblock
|
||||
|
||||
//That massive research room
|
||||
/area/awaymission/research
|
||||
|
||||
//Syndicate shuttle
|
||||
/area/awaymission/syndishuttle
|
||||
|
||||
|
||||
//Spacebattle Areas
|
||||
|
||||
/area/awaymission/spacebattle
|
||||
name = "Space Battle"
|
||||
icon_state = "away"
|
||||
requires_power = 0
|
||||
|
||||
/area/awaymission/spacebattle/cruiser
|
||||
name = "Nanotrasen Cruiser"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate1
|
||||
name = "Syndicate Assault Ship 1"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate2
|
||||
name = "Syndicate Assault Ship 2"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate3
|
||||
name = "Syndicate Assault Ship 3"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate4
|
||||
name = "Syndicate War Sphere 1"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate5
|
||||
name = "Syndicate War Sphere 2"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate6
|
||||
name = "Syndicate War Sphere 3"
|
||||
|
||||
/area/awaymission/spacebattle/syndicate7
|
||||
name = "Syndicate Fighter"
|
||||
|
||||
/area/awaymission/spacebattle/secret
|
||||
name = "Hidden Chamber"
|
||||
|
||||
|
||||
//Snow Valley Areas//--
|
||||
|
||||
/area/awaymission/snowdin
|
||||
name = "Snowdin Tundra Plains"
|
||||
icon_state = "away"
|
||||
requires_power = 0
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
|
||||
|
||||
/area/awaymission/snowdin/post
|
||||
name = "Snowdin Outpost"
|
||||
requires_power = 1
|
||||
|
||||
/area/awaymission/snowdin/igloo
|
||||
name = "Snowdin Igloos"
|
||||
icon_state = "away2"
|
||||
|
||||
/area/awaymission/snowdin/cave
|
||||
name = "Snowdin Caves"
|
||||
icon_state = "away2"
|
||||
luminosity = 0
|
||||
|
||||
/area/awaymission/snowdin/base
|
||||
name = "Snowdin Main Base"
|
||||
icon_state = "away3"
|
||||
requires_power = 1
|
||||
|
||||
/area/awaymission/snowdin/dungeon1
|
||||
name = "Snowdin Depths"
|
||||
icon_state = "away2"
|
||||
luminosity = 0
|
||||
|
||||
/area/awaymission/snowdin/sekret
|
||||
name = "Snowdin Operations"
|
||||
icon_state = "away3"
|
||||
requires_power = 1
|
||||
|
||||
|
||||
|
||||
/area/awaycontent
|
||||
name = "space"
|
||||
|
||||
/area/awaycontent/a1
|
||||
icon_state = "awaycontent1"
|
||||
|
||||
/area/awaycontent/a2
|
||||
icon_state = "awaycontent2"
|
||||
|
||||
/area/awaycontent/a3
|
||||
icon_state = "awaycontent3"
|
||||
|
||||
/area/awaycontent/a4
|
||||
icon_state = "awaycontent4"
|
||||
|
||||
/area/awaycontent/a5
|
||||
icon_state = "awaycontent5"
|
||||
|
||||
/area/awaycontent/a6
|
||||
icon_state = "awaycontent6"
|
||||
|
||||
/area/awaycontent/a7
|
||||
icon_state = "awaycontent7"
|
||||
|
||||
/area/awaycontent/a8
|
||||
icon_state = "awaycontent8"
|
||||
|
||||
/area/awaycontent/a9
|
||||
icon_state = "awaycontent9"
|
||||
|
||||
/area/awaycontent/a10
|
||||
icon_state = "awaycontent10"
|
||||
|
||||
/area/awaycontent/a11
|
||||
icon_state = "awaycontent11"
|
||||
|
||||
/area/awaycontent/a11
|
||||
icon_state = "awaycontent12"
|
||||
|
||||
/area/awaycontent/a12
|
||||
icon_state = "awaycontent13"
|
||||
|
||||
/area/awaycontent/a13
|
||||
icon_state = "awaycontent14"
|
||||
|
||||
/area/awaycontent/a14
|
||||
icon_state = "awaycontent14"
|
||||
|
||||
/area/awaycontent/a15
|
||||
icon_state = "awaycontent15"
|
||||
|
||||
/area/awaycontent/a16
|
||||
icon_state = "awaycontent16"
|
||||
|
||||
/area/awaycontent/a17
|
||||
icon_state = "awaycontent17"
|
||||
|
||||
/area/awaycontent/a18
|
||||
icon_state = "awaycontent18"
|
||||
|
||||
/area/awaycontent/a19
|
||||
icon_state = "awaycontent19"
|
||||
|
||||
/area/awaycontent/a20
|
||||
icon_state = "awaycontent20"
|
||||
|
||||
/area/awaycontent/a21
|
||||
icon_state = "awaycontent21"
|
||||
|
||||
/area/awaycontent/a22
|
||||
icon_state = "awaycontent22"
|
||||
|
||||
/area/awaycontent/a23
|
||||
icon_state = "awaycontent23"
|
||||
|
||||
/area/awaycontent/a24
|
||||
icon_state = "awaycontent24"
|
||||
|
||||
/area/awaycontent/a25
|
||||
icon_state = "awaycontent25"
|
||||
|
||||
/area/awaycontent/a26
|
||||
icon_state = "awaycontent26"
|
||||
|
||||
/area/awaycontent/a27
|
||||
icon_state = "awaycontent27"
|
||||
|
||||
/area/awaycontent/a28
|
||||
icon_state = "awaycontent28"
|
||||
|
||||
/area/awaycontent/a29
|
||||
icon_state = "awaycontent29"
|
||||
|
||||
/area/awaycontent/a30
|
||||
icon_state = "awaycontent30"
|
||||
@@ -0,0 +1,135 @@
|
||||
|
||||
// CENTCOM
|
||||
|
||||
/area/centcom
|
||||
name = "Centcom"
|
||||
icon_state = "centcom"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
noteleport = 1
|
||||
blob_allowed = 0 //Should go without saying, no blobs should take over centcom as a win condition.
|
||||
flags = NONE
|
||||
|
||||
/area/centcom/control
|
||||
name = "Centcom Docks"
|
||||
|
||||
/area/centcom/evac
|
||||
name = "Centcom Recovery Ship"
|
||||
|
||||
/area/centcom/supply
|
||||
name = "Centcom Supply Shuttle Dock"
|
||||
|
||||
/area/centcom/ferry
|
||||
name = "Centcom Transport Shuttle Dock"
|
||||
|
||||
/area/centcom/prison
|
||||
name = "Admin Prison"
|
||||
|
||||
/area/centcom/holding
|
||||
name = "Holding Facility"
|
||||
|
||||
//THUNDERDOME
|
||||
|
||||
/area/tdome
|
||||
name = "Thunderdome"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
|
||||
/area/tdome/arena
|
||||
name = "Thunderdome Arena"
|
||||
icon_state = "thunder"
|
||||
|
||||
/area/tdome/arena_source
|
||||
name = "Thunderdome Arena Template"
|
||||
icon_state = "thunder"
|
||||
|
||||
/area/tdome/tdome1
|
||||
name = "Thunderdome (Team 1)"
|
||||
icon_state = "green"
|
||||
|
||||
/area/tdome/tdome2
|
||||
name = "Thunderdome (Team 2)"
|
||||
icon_state = "green"
|
||||
|
||||
/area/tdome/tdomeadmin
|
||||
name = "Thunderdome (Admin.)"
|
||||
icon_state = "purple"
|
||||
|
||||
/area/tdome/tdomeobserve
|
||||
name = "Thunderdome (Observer.)"
|
||||
icon_state = "purple"
|
||||
|
||||
|
||||
//ENEMY
|
||||
|
||||
//Wizard
|
||||
/area/wizard_station
|
||||
name = "Wizard's Den"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
noteleport = 1
|
||||
|
||||
//Abductors
|
||||
/area/abductor_ship
|
||||
name = "Abductor Ship"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
noteleport = 1
|
||||
has_gravity = 1
|
||||
|
||||
//Syndicates
|
||||
/area/syndicate_mothership
|
||||
name = "Syndicate Mothership"
|
||||
icon_state = "syndie-ship"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
noteleport = 1
|
||||
blob_allowed = 0 //Not... entirely sure this will ever come up... but if the bus makes blobs AND ops, it shouldn't aim for the ops to win.
|
||||
|
||||
/area/syndicate_mothership/control
|
||||
name = "Syndicate Control Room"
|
||||
icon_state = "syndie-control"
|
||||
|
||||
/area/syndicate_mothership/elite_squad
|
||||
name = "Syndicate Elite Squad"
|
||||
icon_state = "syndie-elite"
|
||||
|
||||
|
||||
|
||||
//CAPTURE THE FLAG
|
||||
|
||||
/area/ctf
|
||||
name = "Capture the Flag"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
flags = NO_DEATHRATTLE
|
||||
|
||||
/area/ctf/control_room
|
||||
name = "Control Room A"
|
||||
|
||||
/area/ctf/control_room2
|
||||
name = "Control Room B"
|
||||
|
||||
/area/ctf/central
|
||||
name = "Central"
|
||||
|
||||
/area/ctf/main_hall
|
||||
name = "Main Hall A"
|
||||
|
||||
/area/ctf/main_hall2
|
||||
name = "Main Hall B"
|
||||
|
||||
/area/ctf/corridor
|
||||
name = "Corridor A"
|
||||
|
||||
/area/ctf/corridor2
|
||||
name = "Corridor B"
|
||||
|
||||
/area/ctf/flag_room
|
||||
name = "Flag Room A"
|
||||
|
||||
/area/ctf/flag_room2
|
||||
name = "Flag Room B"
|
||||
@@ -0,0 +1,124 @@
|
||||
//DERELICT
|
||||
|
||||
/area/derelict
|
||||
name = "Derelict Station"
|
||||
icon_state = "storage"
|
||||
blob_allowed = 0 //Nope, no winning on the derelict as a blob. Gotta eat the station.
|
||||
|
||||
/area/derelict/hallway/primary
|
||||
name = "Derelict Primary Hallway"
|
||||
icon_state = "hallP"
|
||||
|
||||
/area/derelict/hallway/secondary
|
||||
name = "Derelict Secondary Hallway"
|
||||
icon_state = "hallS"
|
||||
|
||||
/area/derelict/arrival
|
||||
name = "Derelict Arrival Centre"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/derelict/storage/equipment
|
||||
name = "Derelict Equipment Storage"
|
||||
|
||||
/area/derelict/storage/storage_access
|
||||
name = "Derelict Storage Access"
|
||||
|
||||
/area/derelict/storage/engine_storage
|
||||
name = "Derelict Engine Storage"
|
||||
icon_state = "green"
|
||||
|
||||
/area/derelict/bridge
|
||||
name = "Derelict Control Room"
|
||||
icon_state = "bridge"
|
||||
|
||||
/area/derelict/secret
|
||||
name = "Derelict Secret Room"
|
||||
icon_state = "library"
|
||||
|
||||
/area/derelict/bridge/access
|
||||
name = "Derelict Control Room Access"
|
||||
icon_state = "auxstorage"
|
||||
|
||||
/area/derelict/bridge/ai_upload
|
||||
name = "Derelict Computer Core"
|
||||
icon_state = "ai"
|
||||
|
||||
/area/derelict/solar_control
|
||||
name = "Derelict Solar Control"
|
||||
icon_state = "engine"
|
||||
|
||||
/area/derelict/se_solar
|
||||
name = "South East Solars"
|
||||
icon_state = "engine"
|
||||
|
||||
/area/derelict/crew_quarters
|
||||
name = "Derelict Crew Quarters"
|
||||
icon_state = "fitness"
|
||||
|
||||
/area/derelict/medical
|
||||
name = "Derelict Medbay"
|
||||
icon_state = "medbay"
|
||||
|
||||
/area/derelict/medical/morgue
|
||||
name = "Derelict Morgue"
|
||||
icon_state = "morgue"
|
||||
|
||||
/area/derelict/medical/chapel
|
||||
name = "Derelict Chapel"
|
||||
icon_state = "chapel"
|
||||
|
||||
/area/derelict/teleporter
|
||||
name = "Derelict Teleporter"
|
||||
icon_state = "teleporter"
|
||||
|
||||
/area/derelict/eva
|
||||
name = "Derelict EVA Storage"
|
||||
icon_state = "eva"
|
||||
|
||||
/area/derelict/ship
|
||||
name = "Abandoned Ship"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/solar/derelict_starboard
|
||||
name = "Derelict Starboard Solar Array"
|
||||
icon_state = "panelsS"
|
||||
|
||||
/area/solar/derelict_aft
|
||||
name = "Derelict Aft Solar Array"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/derelict/singularity_engine
|
||||
name = "Derelict Singularity Engine"
|
||||
icon_state = "engine"
|
||||
|
||||
/area/derelict/gravity_generator
|
||||
name = "Derelict Gravity Generator Room"
|
||||
icon_state = "red"
|
||||
|
||||
/area/derelict/atmospherics
|
||||
name = "Derelict Atmospherics"
|
||||
icon_state = "red"
|
||||
|
||||
|
||||
|
||||
//DJSTATION
|
||||
|
||||
/area/djstation
|
||||
name = "Ruskie DJ Station"
|
||||
icon_state = "DJ"
|
||||
has_gravity = 1
|
||||
blob_allowed = 0 //Nope, no winning on the DJ station as a blob. Gotta eat the main station.
|
||||
|
||||
/area/djstation/solars
|
||||
name = "DJ Station Solars"
|
||||
icon_state = "DJ"
|
||||
has_gravity = 1
|
||||
|
||||
|
||||
//ABANDONED TELEPORTER
|
||||
|
||||
/area/AIsattele
|
||||
name = "Abandoned Teleporter"
|
||||
icon_state = "teleporter"
|
||||
music = "signal"
|
||||
ambientsounds = list('sound/ambience/ambimalf.ogg')
|
||||
@@ -0,0 +1,128 @@
|
||||
/area/holodeck
|
||||
name = "Holodeck"
|
||||
icon_state = "Holodeck"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
flags = 0
|
||||
|
||||
var/obj/machinery/computer/holodeck/linked
|
||||
var/restricted = 0 // if true, program goes on emag list
|
||||
|
||||
/*
|
||||
Power tracking: Use the holodeck computer's power grid
|
||||
Asserts are to avoid the inevitable infinite loops
|
||||
*/
|
||||
|
||||
/area/holodeck/powered(var/chan)
|
||||
if(!master.requires_power)
|
||||
return 1
|
||||
if(master.always_unpowered)
|
||||
return 0
|
||||
if(!linked)
|
||||
return 0
|
||||
var/area/A = get_area(linked)
|
||||
ASSERT(!istype(A,/area/holodeck))
|
||||
return A.powered(chan)
|
||||
|
||||
/area/holodeck/usage(var/chan)
|
||||
if(!linked)
|
||||
return 0
|
||||
var/area/A = get_area(linked)
|
||||
ASSERT(!istype(A,/area/holodeck))
|
||||
return A.usage(chan)
|
||||
|
||||
/area/holodeck/addStaticPower(value, powerchannel)
|
||||
if(!linked)
|
||||
return
|
||||
var/area/A = get_area(linked)
|
||||
ASSERT(!istype(A,/area/holodeck))
|
||||
return A.addStaticPower(value,powerchannel)
|
||||
|
||||
/area/holodeck/use_power(var/amount, var/chan)
|
||||
if(!linked)
|
||||
return 0
|
||||
var/area/A = get_area(linked)
|
||||
ASSERT(!istype(A,/area/holodeck))
|
||||
return A.use_power(amount,chan)
|
||||
|
||||
|
||||
/*
|
||||
This is the standard holodeck. It is intended to allow you to
|
||||
blow off steam by doing stupid things like laying down, throwing
|
||||
spheres at holes, or bludgeoning people.
|
||||
*/
|
||||
/area/holodeck/rec_center
|
||||
name = "\improper Recreational Holodeck"
|
||||
|
||||
/area/holodeck/rec_center/offline
|
||||
name = "Holodeck - Offline"
|
||||
|
||||
/area/holodeck/rec_center/court
|
||||
name = "Holodeck - Empty Court"
|
||||
|
||||
/area/holodeck/rec_center/dodgeball
|
||||
name = "Holodeck - Dodgeball Court"
|
||||
|
||||
/area/holodeck/rec_center/basketball
|
||||
name = "Holodeck - Basketball Court"
|
||||
|
||||
/area/holodeck/rec_center/thunderdome
|
||||
name = "Holodeck - Thunderdome Arena"
|
||||
|
||||
/area/holodeck/rec_center/beach
|
||||
name = "Holodeck - Beach"
|
||||
|
||||
/area/holodeck/rec_center/lounge
|
||||
name = "Holodeck - Lounge"
|
||||
|
||||
/area/holodeck/rec_center/medical
|
||||
name = "Holodeck - Emergency Medical"
|
||||
|
||||
/area/holodeck/rec_center/pet_lounge
|
||||
name = "Holodeck - Pet Park"
|
||||
|
||||
/area/holodeck/rec_center/firingrange
|
||||
name = "Holodeck - Firing Range"
|
||||
|
||||
/area/holodeck/rec_center/rollercoaster
|
||||
name = "Holodeck - Roller Coaster"
|
||||
|
||||
/area/holodeck/rec_center/chapelcourt
|
||||
name = "Holodeck - Chapel Courtroom"
|
||||
|
||||
/area/holodeck/rec_center/spacechess
|
||||
name = "Holodeck - Space Chess"
|
||||
|
||||
/area/holodeck/rec_center/kobayashi
|
||||
name = "Holodeck - Kobayashi Maru"
|
||||
|
||||
// Bad programs
|
||||
|
||||
/area/holodeck/rec_center/burn
|
||||
name = "Holodeck - Atmospheric Burn Test"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/winterwonderland
|
||||
name = "Holodeck - Winter Wonderland"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/wildlife
|
||||
name = "Holodeck - Wildlife Simulation"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/bunker
|
||||
name = "Holodeck - Holdout Bunker"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/anthophila
|
||||
name = "Holodeck - Anthophila"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/refuel
|
||||
name = "Holodeck - Refueling Station"
|
||||
restricted = 1
|
||||
|
||||
/area/holodeck/rec_center/thunderdome1218
|
||||
name = "Holodeck - 1218 AD"
|
||||
restricted = 1
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/**********************Mine areas**************************/
|
||||
|
||||
/area/mine
|
||||
icon_state = "mining"
|
||||
has_gravity = 1
|
||||
|
||||
/area/mine/explored
|
||||
name = "Mine"
|
||||
icon_state = "explored"
|
||||
music = null
|
||||
always_unpowered = 1
|
||||
requires_power = 1
|
||||
poweralm = 0
|
||||
power_environ = 0
|
||||
power_equip = 0
|
||||
power_light = 0
|
||||
outdoors = 1
|
||||
ambientsounds = list('sound/ambience/ambimine.ogg')
|
||||
flags = NONE
|
||||
|
||||
/area/mine/unexplored
|
||||
name = "Mine"
|
||||
icon_state = "unexplored"
|
||||
music = null
|
||||
always_unpowered = 1
|
||||
requires_power = 1
|
||||
poweralm = 0
|
||||
power_environ = 0
|
||||
power_equip = 0
|
||||
power_light = 0
|
||||
outdoors = 1
|
||||
ambientsounds = list('sound/ambience/ambimine.ogg')
|
||||
flags = NONE
|
||||
|
||||
/area/mine/lobby
|
||||
name = "Mining Station"
|
||||
|
||||
/area/mine/storage
|
||||
name = "Mining Station Storage"
|
||||
|
||||
/area/mine/production
|
||||
name = "Mining Station Starboard Wing"
|
||||
icon_state = "mining_production"
|
||||
|
||||
/area/mine/abandoned
|
||||
name = "Abandoned Mining Station"
|
||||
|
||||
/area/mine/living_quarters
|
||||
name = "Mining Station Port Wing"
|
||||
icon_state = "mining_living"
|
||||
|
||||
/area/mine/eva
|
||||
name = "Mining Station EVA"
|
||||
icon_state = "mining_eva"
|
||||
|
||||
/area/mine/maintenance
|
||||
name = "Mining Station Communications"
|
||||
|
||||
/area/mine/cafeteria
|
||||
name = "Mining station Cafeteria"
|
||||
|
||||
/area/mine/hydroponics
|
||||
name = "Mining station Hydroponics"
|
||||
|
||||
/area/mine/sleeper
|
||||
name = "Mining station Emergency Sleeper"
|
||||
|
||||
/area/mine/north_outpost
|
||||
name = "North Mining Outpost"
|
||||
|
||||
/area/mine/west_outpost
|
||||
name = "West Mining Outpost"
|
||||
|
||||
/area/mine/laborcamp
|
||||
name = "Labor Camp"
|
||||
|
||||
/area/mine/laborcamp/security
|
||||
name = "Labor Camp Security"
|
||||
icon_state = "security"
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************Lavaland Areas**************************/
|
||||
|
||||
/area/lavaland
|
||||
icon_state = "mining"
|
||||
has_gravity = 1
|
||||
|
||||
/area/lavaland/surface
|
||||
name = "Lavaland"
|
||||
icon_state = "explored"
|
||||
music = null
|
||||
always_unpowered = 1
|
||||
poweralm = 0
|
||||
power_environ = 0
|
||||
power_equip = 0
|
||||
power_light = 0
|
||||
requires_power = 1
|
||||
ambientsounds = list('sound/ambience/ambilava.ogg')
|
||||
|
||||
/area/lavaland/underground
|
||||
name = "Lavaland Caves"
|
||||
icon_state = "unexplored"
|
||||
music = null
|
||||
always_unpowered = 1
|
||||
requires_power = 1
|
||||
poweralm = 0
|
||||
power_environ = 0
|
||||
power_equip = 0
|
||||
power_light = 0
|
||||
ambientsounds = list('sound/ambience/ambilava.ogg')
|
||||
|
||||
|
||||
/area/lavaland/surface/outdoors
|
||||
name = "Lavaland Wastes"
|
||||
outdoors = 1
|
||||
|
||||
/area/lavaland/surface/outdoors/explored
|
||||
name = "Lavaland Labor Camp"
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
// Hell
|
||||
/area/hell
|
||||
name = "Hell Lobby"
|
||||
//icon = "ICON FILENAME"
|
||||
//icon_state = "NAME OF ICON"
|
||||
requires_power = 0
|
||||
music = "music/music.ogg"
|
||||
|
||||
/area/hell/trial1
|
||||
name = "Hell Trial1"
|
||||
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
|
||||
|
||||
/area/hell/trial1
|
||||
name = "Hell Trial2"
|
||||
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
|
||||
|
||||
/area/hell/trial1
|
||||
name = "Hell Trial3"
|
||||
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
|
||||
|
||||
|
||||
|
||||
//Misc
|
||||
|
||||
/area/wreck/ai
|
||||
name = "AI Chamber"
|
||||
icon_state = "ai"
|
||||
|
||||
/area/wreck/main
|
||||
name = "Wreck"
|
||||
icon_state = "storage"
|
||||
|
||||
/area/wreck/engineering
|
||||
name = "Power Room"
|
||||
icon_state = "engine"
|
||||
|
||||
/area/wreck/bridge
|
||||
name = "Bridge"
|
||||
icon_state = "bridge"
|
||||
|
||||
/area/generic
|
||||
name = "Unknown"
|
||||
icon_state = "storage"
|
||||
|
||||
|
||||
|
||||
//PRISON
|
||||
/area/prison
|
||||
name = "Prison Station"
|
||||
icon_state = "brig"
|
||||
|
||||
/area/prison/arrival_airlock
|
||||
name = "Prison Station Airlock"
|
||||
icon_state = "green"
|
||||
requires_power = 0
|
||||
|
||||
/area/prison/control
|
||||
name = "Prison Security Checkpoint"
|
||||
icon_state = "security"
|
||||
|
||||
/area/prison/crew_quarters
|
||||
name = "Prison Security Quarters"
|
||||
icon_state = "security"
|
||||
|
||||
/area/prison/rec_room
|
||||
name = "Prison Rec Room"
|
||||
icon_state = "green"
|
||||
|
||||
/area/prison/closet
|
||||
name = "Prison Supply Closet"
|
||||
icon_state = "dk_yellow"
|
||||
|
||||
/area/prison/hallway/fore
|
||||
name = "Prison Fore Hallway"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/prison/hallway/aft
|
||||
name = "Prison Aft Hallway"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/prison/hallway/port
|
||||
name = "Prison Port Hallway"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/prison/hallway/starboard
|
||||
name = "Prison Starboard Hallway"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/prison/morgue
|
||||
name = "Prison Morgue"
|
||||
icon_state = "morgue"
|
||||
ambientsounds = list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg')
|
||||
|
||||
/area/prison/medical_research
|
||||
name = "Prison Genetic Research"
|
||||
icon_state = "medresearch"
|
||||
|
||||
/area/prison/medical
|
||||
name = "Prison Medbay"
|
||||
icon_state = "medbay"
|
||||
|
||||
/area/prison/solar
|
||||
name = "Prison Solar Array"
|
||||
icon_state = "storage"
|
||||
requires_power = 0
|
||||
|
||||
/area/prison/podbay
|
||||
name = "Prison Podbay"
|
||||
icon_state = "dk_yellow"
|
||||
|
||||
/area/prison/solar_control
|
||||
name = "Prison Solar Array Control"
|
||||
icon_state = "dk_yellow"
|
||||
|
||||
/area/prison/solitary
|
||||
name = "Solitary Confinement"
|
||||
icon_state = "brig"
|
||||
|
||||
/area/prison/cell_block/A
|
||||
name = "Prison Cell Block A"
|
||||
icon_state = "brig"
|
||||
|
||||
/area/prison/cell_block/B
|
||||
name = "Prison Cell Block B"
|
||||
icon_state = "brig"
|
||||
|
||||
/area/prison/cell_block/C
|
||||
name = "Prison Cell Block C"
|
||||
icon_state = "brig"
|
||||
@@ -0,0 +1,200 @@
|
||||
//Parent types
|
||||
|
||||
/area/ruin
|
||||
name = "\improper Unexplored Location"
|
||||
icon_state = "away"
|
||||
has_gravity = 1
|
||||
|
||||
|
||||
/area/ruin/unpowered
|
||||
always_unpowered = 0
|
||||
|
||||
/area/ruin/unpowered/no_grav
|
||||
has_gravity = 0
|
||||
|
||||
/area/ruin/powered
|
||||
requires_power = 0
|
||||
|
||||
|
||||
|
||||
|
||||
//Areas
|
||||
/area/ruin/unpowered/hierophant
|
||||
name = "Hierophant's Arena"
|
||||
|
||||
/area/ruin/unpowered/no_grav/way_home
|
||||
name = "\improper Salvation"
|
||||
icon_state = "away"
|
||||
|
||||
/area/ruin/powered/snow_biodome
|
||||
|
||||
/area/ruin/powered/golem_ship
|
||||
name = "Free Golem Ship"
|
||||
|
||||
/area/ruin/powered/syndicate_lava_base
|
||||
name = "Secret Base"
|
||||
|
||||
// Ruins of "onehalf" ship
|
||||
|
||||
/area/ruin/onehalf/hallway
|
||||
name = "Hallway"
|
||||
icon_state = "hallC"
|
||||
|
||||
/area/ruin/onehalf/drone_bay
|
||||
name = "Mining Drone Bay"
|
||||
icon_state = "engine"
|
||||
|
||||
/area/ruin/onehalf/dorms_med
|
||||
name = "Crew Quarters"
|
||||
icon_state = "Sleep"
|
||||
|
||||
/area/ruin/onehalf/bridge
|
||||
name = "Bridge"
|
||||
icon_state = "bridge"
|
||||
|
||||
|
||||
|
||||
/area/ruin/powered/dinner_for_two
|
||||
name = "Dinner for Two"
|
||||
|
||||
/area/ruin/powered/authorship
|
||||
name = "Authorship"
|
||||
|
||||
/area/ruin/powered/aesthetic
|
||||
name = "Aesthetic"
|
||||
ambientsounds = list('sound/ambience/ambivapor1.ogg')
|
||||
|
||||
|
||||
//Ruin of Hotel
|
||||
|
||||
/area/ruin/hotel
|
||||
name = "Hotel"
|
||||
|
||||
/area/ruin/hotel/guestroom
|
||||
name = "Hotel Guest Room"
|
||||
icon_state = "Sleep"
|
||||
|
||||
/area/ruin/hotel/security
|
||||
name = "Hotel Security Post"
|
||||
icon_state = "security"
|
||||
|
||||
/area/ruin/hotel/pool
|
||||
name = "Hotel Pool Room"
|
||||
icon_state = "fitness"
|
||||
|
||||
/area/ruin/hotel/bar
|
||||
name = "Hotel Bar"
|
||||
icon_state = "cafeteria"
|
||||
|
||||
/area/ruin/hotel/power
|
||||
name = "Hotel Power Room"
|
||||
icon_state = "engine_smes"
|
||||
|
||||
/area/ruin/hotel/custodial
|
||||
name = "Hotel Custodial Closet"
|
||||
icon_state = "janitor"
|
||||
|
||||
/area/ruin/hotel/shuttle
|
||||
name = "Hotel Shuttle"
|
||||
icon_state = "shuttle"
|
||||
requires_power = 0
|
||||
|
||||
/area/ruin/hotel/dock
|
||||
name = "Hotel Shuttle Dock"
|
||||
icon_state = "start"
|
||||
|
||||
/area/ruin/hotel/workroom
|
||||
name = "Hotel Staff Room"
|
||||
icon_state = "crew_quarters"
|
||||
|
||||
|
||||
|
||||
/area/ruin/fakespace
|
||||
icon_state = "space"
|
||||
requires_power = 1
|
||||
always_unpowered = 1
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
|
||||
has_gravity = 0
|
||||
power_light = 0
|
||||
power_equip = 0
|
||||
power_environ = 0
|
||||
valid_territory = 0
|
||||
outdoors = 1
|
||||
ambientsounds = list('sound/ambience/ambispace.ogg','sound/ambience/title2.ogg')
|
||||
blob_allowed = 0
|
||||
|
||||
|
||||
|
||||
//Ruin of Derelict Oupost
|
||||
|
||||
/area/ruin/derelictoutpost
|
||||
name = "Derelict Outpost"
|
||||
icon_state = "green"
|
||||
|
||||
/area/ruin/derelictoutpost/cargostorage
|
||||
name = "Derelict Outpost Cargo Storage"
|
||||
icon_state = "storage"
|
||||
|
||||
/area/ruin/derelictoutpost/cargobay
|
||||
name = "Derelict Outpost Cargo Bay"
|
||||
icon_state = "quartstorage"
|
||||
|
||||
/area/ruin/derelictoutpost/powerstorage
|
||||
name = "Derelict Outpost Power Storage"
|
||||
icon_state = "engine_smes"
|
||||
|
||||
/area/ruin/derelictoutpost/dockedship
|
||||
name = "Derelict Outpost Docked Ship"
|
||||
icon_state = "red"
|
||||
|
||||
|
||||
//Ruin of Space Bar
|
||||
|
||||
/area/ruin/powered/spacebar
|
||||
name = "Space Bar"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/ruin/powered/spacebar/bar
|
||||
icon_state = "bar"
|
||||
|
||||
|
||||
//Ruin of turretedoutpost
|
||||
|
||||
/area/ruin/turretedoutpost
|
||||
name = "Turreted Outpost"
|
||||
icon_state = "red"
|
||||
|
||||
|
||||
//Ruin of old teleporter
|
||||
|
||||
/area/ruin/oldteleporter
|
||||
name = "Old teleporter"
|
||||
icon_state = "teleporter"
|
||||
has_gravity = 0
|
||||
|
||||
|
||||
//Ruin of mech transport
|
||||
|
||||
/area/ruin/powered/mechtransport
|
||||
name = "Mech Transport"
|
||||
icon_state = "green"
|
||||
|
||||
|
||||
//Ruin of gas the lizard
|
||||
|
||||
/area/ruin/gasthelizard
|
||||
name = "Gas the lizard"
|
||||
|
||||
|
||||
//Ruin of Deep Storage
|
||||
|
||||
/area/ruin/deepstorage
|
||||
name = "Deep Storage"
|
||||
icon_state = "storage"
|
||||
|
||||
|
||||
//Ruin of Abandoned Zoo
|
||||
|
||||
/area/ruin/abandonedzoo
|
||||
name = "Abandoned Zoo"
|
||||
icon_state = "green"
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
//These are shuttle areas; all subtypes are only used as teleportation markers, they have no actual function beyond that.
|
||||
|
||||
/area/shuttle
|
||||
name = "Shuttle"
|
||||
requires_power = 0
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
|
||||
has_gravity = 1
|
||||
always_unpowered = 0
|
||||
valid_territory = 0
|
||||
icon_state = "shuttle"
|
||||
|
||||
/area/shuttle/transit
|
||||
name = "Hyperspace"
|
||||
desc = "Weeeeee"
|
||||
|
||||
/area/shuttle/arrival
|
||||
name = "Arrival Shuttle"
|
||||
|
||||
/area/shuttle/pod_1
|
||||
name = "Escape Pod One"
|
||||
|
||||
/area/shuttle/pod_2
|
||||
name = "Escape Pod Two"
|
||||
|
||||
/area/shuttle/pod_3
|
||||
name = "Escape Pod Three"
|
||||
|
||||
/area/shuttle/pod_4
|
||||
name = "Escape Pod Four"
|
||||
|
||||
/area/shuttle/mining
|
||||
name = "Mining Shuttle"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/labor
|
||||
name = "Labor Camp Shuttle"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/supply
|
||||
name = "Supply Shuttle"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/escape
|
||||
name = "Emergency Shuttle"
|
||||
|
||||
/area/shuttle/transport
|
||||
name = "Transport Shuttle"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/syndicate
|
||||
name = "Syndicate Infiltrator"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/assault_pod
|
||||
name = "Steel Rain"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/abandoned
|
||||
name = "Abandoned Ship"
|
||||
blob_allowed = FALSE
|
||||
@@ -0,0 +1,97 @@
|
||||
|
||||
|
||||
/area/spacecontent
|
||||
name = "space"
|
||||
|
||||
/area/spacecontent/a1
|
||||
icon_state = "spacecontent1"
|
||||
|
||||
/area/spacecontent/a2
|
||||
icon_state = "spacecontent2"
|
||||
|
||||
/area/spacecontent/a3
|
||||
icon_state = "spacecontent3"
|
||||
|
||||
/area/spacecontent/a4
|
||||
icon_state = "spacecontent4"
|
||||
|
||||
/area/spacecontent/a5
|
||||
icon_state = "spacecontent5"
|
||||
|
||||
/area/spacecontent/a6
|
||||
icon_state = "spacecontent6"
|
||||
|
||||
/area/spacecontent/a7
|
||||
icon_state = "spacecontent7"
|
||||
|
||||
/area/spacecontent/a8
|
||||
icon_state = "spacecontent8"
|
||||
|
||||
/area/spacecontent/a9
|
||||
icon_state = "spacecontent9"
|
||||
|
||||
/area/spacecontent/a10
|
||||
icon_state = "spacecontent10"
|
||||
|
||||
/area/spacecontent/a11
|
||||
icon_state = "spacecontent11"
|
||||
|
||||
/area/spacecontent/a11
|
||||
icon_state = "spacecontent12"
|
||||
|
||||
/area/spacecontent/a12
|
||||
icon_state = "spacecontent13"
|
||||
|
||||
/area/spacecontent/a13
|
||||
icon_state = "spacecontent14"
|
||||
|
||||
/area/spacecontent/a14
|
||||
icon_state = "spacecontent14"
|
||||
|
||||
/area/spacecontent/a15
|
||||
icon_state = "spacecontent15"
|
||||
|
||||
/area/spacecontent/a16
|
||||
icon_state = "spacecontent16"
|
||||
|
||||
/area/spacecontent/a17
|
||||
icon_state = "spacecontent17"
|
||||
|
||||
/area/spacecontent/a18
|
||||
icon_state = "spacecontent18"
|
||||
|
||||
/area/spacecontent/a19
|
||||
icon_state = "spacecontent19"
|
||||
|
||||
/area/spacecontent/a20
|
||||
icon_state = "spacecontent20"
|
||||
|
||||
/area/spacecontent/a21
|
||||
icon_state = "spacecontent21"
|
||||
|
||||
/area/spacecontent/a22
|
||||
icon_state = "spacecontent22"
|
||||
|
||||
/area/spacecontent/a23
|
||||
icon_state = "spacecontent23"
|
||||
|
||||
/area/spacecontent/a24
|
||||
icon_state = "spacecontent24"
|
||||
|
||||
/area/spacecontent/a25
|
||||
icon_state = "spacecontent25"
|
||||
|
||||
/area/spacecontent/a26
|
||||
icon_state = "spacecontent26"
|
||||
|
||||
/area/spacecontent/a27
|
||||
icon_state = "spacecontent27"
|
||||
|
||||
/area/spacecontent/a28
|
||||
icon_state = "spacecontent28"
|
||||
|
||||
/area/spacecontent/a29
|
||||
icon_state = "spacecontent29"
|
||||
|
||||
/area/spacecontent/a30
|
||||
icon_state = "spacecontent30"
|
||||
@@ -75,7 +75,7 @@ var/global/max_secret_rooms = 6
|
||||
floortypes = list(/turf/open/floor/plasteel/cult)
|
||||
treasureitems = list(/obj/item/device/soulstone/anybody=1, /obj/item/clothing/suit/space/hardsuit/cult=1, /obj/item/weapon/bedsheet/cult=2,
|
||||
/obj/item/clothing/suit/cultrobes=2, /mob/living/simple_animal/hostile/creature=3)
|
||||
fluffitems = list(/obj/effect/gateway=1,/obj/effect/gibspawner=1,/obj/structure/cult/talisman=1,/obj/item/toy/crayon/red=2,
|
||||
fluffitems = list(/obj/effect/gateway=1,/obj/effect/gibspawner=1,/obj/structure/destructible/cult/talisman=1,/obj/item/toy/crayon/red=2,
|
||||
/obj/item/organ/heart=2, /obj/effect/decal/cleanable/blood=4,/obj/structure/table/wood=2,/obj/item/weapon/ectoplasm=3,
|
||||
/obj/item/clothing/shoes/cult=1)
|
||||
|
||||
@@ -92,7 +92,7 @@ var/global/max_secret_rooms = 6
|
||||
theme = "cavein"
|
||||
walltypes = list(/turf/closed/mineral/random/high_chance=1)
|
||||
floortypes = list(/turf/open/floor/plating/asteroid/basalt, /turf/open/floor/plating/beach/sand)
|
||||
treasureitems = list(/obj/mecha/working/ripley/mining=1, /obj/item/weapon/pickaxe/drill/diamonddrill=2,/obj/item/weapon/gun/energy/kinetic_accelerator/hyper=1,
|
||||
treasureitems = list(/obj/mecha/working/ripley/mining=1, /obj/item/weapon/pickaxe/drill/diamonddrill=2,
|
||||
/obj/item/weapon/resonator/upgraded=1, /obj/item/weapon/pickaxe/drill/jackhammer=5)
|
||||
fluffitems = list(/obj/effect/decal/cleanable/blood=3,/obj/effect/decal/remains/human=1,/obj/item/clothing/under/overalls=1,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/chili=1,/obj/item/weapon/tank/internals/oxygen/red=2)
|
||||
@@ -117,7 +117,7 @@ var/global/max_secret_rooms = 6
|
||||
if("speakeasy")
|
||||
theme = "speakeasy"
|
||||
floortypes = list(/turf/open/floor/plasteel,/turf/open/floor/wood)
|
||||
treasureitems = list(/obj/item/weapon/melee/energy/sword/pirate=1,/obj/item/weapon/gun/projectile/revolver/doublebarrel=1,/obj/item/weapon/storage/backpack/satchel_flat=1,
|
||||
treasureitems = list(/obj/item/weapon/melee/energy/sword/pirate=1,/obj/item/weapon/gun/ballistic/revolver/doublebarrel=1,/obj/item/weapon/storage/backpack/satchel/flat=1,
|
||||
/obj/machinery/reagentgrinder=2, /obj/machinery/computer/security/wooden_tv=4, /obj/machinery/vending/coffee=3)
|
||||
fluffitems = list(/obj/structure/table/wood=2,/obj/structure/reagent_dispensers/beerkeg=1,/obj/item/stack/spacecash/c500=4,
|
||||
/obj/item/weapon/reagent_containers/food/drinks/shaker=1,/obj/item/weapon/reagent_containers/food/drinks/bottle/wine=3,
|
||||
@@ -126,9 +126,9 @@ var/global/max_secret_rooms = 6
|
||||
if("plantlab")
|
||||
theme = "plantlab"
|
||||
treasureitems = list(/obj/item/weapon/gun/energy/floragun=1,/obj/item/seeds/sunflower/novaflower=2,/obj/item/seeds/tomato/blue/bluespace=2,/obj/item/seeds/tomato/blue=2,
|
||||
/obj/item/seeds/coffee/robusta=2, /obj/item/seeds/cash=2)
|
||||
/obj/item/seeds/coffee/robusta=2, /obj/item/seeds/firelemon=2)
|
||||
fluffitems = list(/obj/item/weapon/twohanded/required/kirbyplants=1,/obj/structure/table/reinforced=2,/obj/machinery/hydroponics/constructable=1,
|
||||
/obj/effect/glowshroom/single=2,/obj/item/weapon/reagent_containers/syringe/charcoal=2,
|
||||
/obj/structure/glowshroom/single=2,/obj/item/weapon/reagent_containers/syringe/charcoal=2,
|
||||
/obj/item/weapon/reagent_containers/glass/bottle/diethylamine=3,/obj/item/weapon/reagent_containers/glass/bottle/ammonia=3)
|
||||
|
||||
/*if("poly")
|
||||
@@ -174,13 +174,13 @@ var/global/max_secret_rooms = 6
|
||||
if(!T)
|
||||
return 0
|
||||
|
||||
room = spawn_room(T,x_size,y_size,walltypes,floor,) //WE'RE FINALLY CREATING THE ROOM
|
||||
room = spawn_room(T,x_size,y_size,walltypes,floor) //WE'RE FINALLY CREATING THE ROOM
|
||||
|
||||
if(room)//time to fill it with stuff
|
||||
var/list/emptyturfs = room["floors"]
|
||||
T = pick(emptyturfs)
|
||||
if(T)
|
||||
new /obj/effect/glowshroom/single(T) //Just to make it a little more visible
|
||||
new /obj/structure/glowshroom/single(T) //Just to make it a little more visible
|
||||
var/surprise = null
|
||||
surprise = pickweight(treasureitems)
|
||||
new surprise(T)//here's the prize
|
||||
@@ -195,4 +195,4 @@ var/global/max_secret_rooms = 6
|
||||
emptyturfs -= T
|
||||
//world.log << "The [theme] themed [T.loc] has been created!"
|
||||
|
||||
return 1
|
||||
return 1
|
||||
|
||||
+159
-43
@@ -1,13 +1,13 @@
|
||||
/atom
|
||||
layer = TURF_LAYER
|
||||
plane = GAME_PLANE
|
||||
var/level = 2
|
||||
var/flags = 0
|
||||
var/list/fingerprints
|
||||
var/list/fingerprintshidden
|
||||
var/fingerprintslast = null
|
||||
var/list/blood_DNA
|
||||
|
||||
///Chemistry.
|
||||
var/container_type = 0
|
||||
var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
|
||||
var/datum/reagents/reagents = null
|
||||
|
||||
//This atom's HUD (med/sec, etc) images. Associative list.
|
||||
@@ -21,15 +21,48 @@
|
||||
//overlays that should remain on top and not normally be removed, like c4.
|
||||
var/list/priority_overlays
|
||||
|
||||
var/list/atom_colours //used to store the different colors on an atom
|
||||
//its inherent color, the colored paint applied on it, special color effect etc...
|
||||
var/initialized = FALSE
|
||||
|
||||
|
||||
/atom/New()
|
||||
//atom creation method that preloads variables at creation
|
||||
if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
|
||||
_preloader.load(src)
|
||||
//atom color stuff
|
||||
if(color)
|
||||
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
|
||||
|
||||
//lighting stuff
|
||||
if(opacity && isturf(loc))
|
||||
loc.UpdateAffectingLights()
|
||||
|
||||
if(luminosity)
|
||||
light = new(src)
|
||||
|
||||
var/initialized = SSobj.initialized
|
||||
if(initialized > INITIALIZATION_INSSOBJ)
|
||||
Initialize(initialized == INITIALIZATION_INNEW_MAPLOAD)
|
||||
//. = ..() //uncomment if you are dumb enough to add a /datum/New() proc
|
||||
|
||||
/atom/Destroy()
|
||||
if(alternate_appearances)
|
||||
for(var/aakey in alternate_appearances)
|
||||
var/datum/alternate_appearance/AA = alternate_appearances[aakey]
|
||||
qdel(AA)
|
||||
alternate_appearances = null
|
||||
|
||||
if(viewing_alternate_appearances)
|
||||
for(var/aakey in viewing_alternate_appearances)
|
||||
for(var/aa in viewing_alternate_appearances[aakey])
|
||||
var/datum/alternate_appearance/AA = aa
|
||||
AA.hide(list(src))
|
||||
if(reagents)
|
||||
qdel(reagents)
|
||||
return ..()
|
||||
|
||||
/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
return (!density || !height)
|
||||
|
||||
/atom/proc/onCentcom()
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -61,11 +94,11 @@
|
||||
|
||||
return 0
|
||||
|
||||
/atom/proc/attack_hulk(mob/living/carbon/human/hulk, do_attack_animation = 0)
|
||||
if(do_attack_animation)
|
||||
hulk.changeNext_move(CLICK_CD_MELEE)
|
||||
add_logs(hulk, src, "punched", "hulk powers")
|
||||
hulk.do_attack_animation(src)
|
||||
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
|
||||
if(does_attack_animation)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
add_logs(user, src, "punched", "hulk powers")
|
||||
user.do_attack_animation(src, ATTACK_EFFECT_SMASH)
|
||||
|
||||
/atom/proc/CheckParts(list/parts_list)
|
||||
for(var/A in parts_list)
|
||||
@@ -76,10 +109,11 @@
|
||||
reagents.conditional_update()
|
||||
else if(istype(A, /atom/movable))
|
||||
var/atom/movable/M = A
|
||||
if(istype(M.loc, /mob/living))
|
||||
if(isliving(M.loc))
|
||||
var/mob/living/L = M.loc
|
||||
L.unEquip(M)
|
||||
M.loc = src
|
||||
L.transferItemToLoc(M, src)
|
||||
else
|
||||
M.forceMove(src)
|
||||
|
||||
/atom/proc/assume_air(datum/gas_mixture/giver)
|
||||
qdel(giver)
|
||||
@@ -97,8 +131,6 @@
|
||||
/atom/proc/check_eye(mob/user)
|
||||
return
|
||||
|
||||
/atom/proc/on_reagent_change()
|
||||
return
|
||||
|
||||
/atom/proc/Bumped(AM as mob|obj)
|
||||
return
|
||||
@@ -107,7 +139,10 @@
|
||||
// returns true if open
|
||||
// false if closed
|
||||
/atom/proc/is_open_container()
|
||||
return flags & OPENCONTAINER
|
||||
return container_type & OPENCONTAINER
|
||||
|
||||
/atom/proc/is_transparent()
|
||||
return container_type & TRANSPARENT
|
||||
|
||||
/*//Convenience proc to see whether a container can be accessed in a certain way.
|
||||
|
||||
@@ -129,7 +164,8 @@
|
||||
return
|
||||
|
||||
/atom/proc/emp_act(severity)
|
||||
return
|
||||
if(istype(wires))
|
||||
wires.emp_pulse()
|
||||
|
||||
/atom/proc/bullet_act(obj/item/projectile/P, def_zone)
|
||||
. = P.on_hit(src, 0, def_zone)
|
||||
@@ -184,7 +220,7 @@
|
||||
// *****RM
|
||||
//user << "[name]: Dn:[density] dir:[dir] cont:[contents] icon:[icon] is:[icon_state] loc:[loc]"
|
||||
|
||||
if(reagents && is_open_container()) //is_open_container() isn't really the right proc for this, but w/e
|
||||
if(reagents && (is_open_container() || is_transparent())) //is_open_container() isn't really the right proc for this, but w/e
|
||||
user << "It contains:"
|
||||
if(reagents.reagent_list.len)
|
||||
if(user.can_see_reagents()) //Show each individual reagent
|
||||
@@ -202,24 +238,24 @@
|
||||
return
|
||||
|
||||
/atom/proc/contents_explosion(severity, target)
|
||||
for(var/atom/A in contents)
|
||||
A.ex_act(severity, target)
|
||||
CHECK_TICK
|
||||
return
|
||||
|
||||
/atom/proc/ex_act(severity, target)
|
||||
contents_explosion(severity, target)
|
||||
|
||||
/atom/proc/blob_act(obj/effect/blob/B)
|
||||
/atom/proc/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/atom/proc/fire_act()
|
||||
/atom/proc/fire_act(exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
|
||||
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
|
||||
spawn(2) //very short wait, so we can actually see the impact.
|
||||
if(AM && isturf(AM.loc))
|
||||
step(AM, turn(AM.dir, 180))
|
||||
addtimer(CALLBACK(src, .proc/hitby_react, AM), 2)
|
||||
|
||||
/atom/proc/hitby_react(atom/movable/AM)
|
||||
if(AM && isturf(AM.loc))
|
||||
step(AM, turn(AM.dir, 180))
|
||||
|
||||
var/list/blood_splatter_icons = list()
|
||||
|
||||
@@ -327,7 +363,7 @@ var/list/blood_splatter_icons = list()
|
||||
G.add_blood(blood_dna)
|
||||
else
|
||||
transfer_blood_dna(blood_dna)
|
||||
bloody_hands = rand(2, 4)
|
||||
bloody_hands = rand(2, 4)
|
||||
update_inv_gloves() //handles bloody hands overlays and updating
|
||||
return 1
|
||||
|
||||
@@ -339,12 +375,6 @@ var/list/blood_splatter_icons = list()
|
||||
/atom/proc/wash_cream()
|
||||
return 1
|
||||
|
||||
/atom/proc/change_area(var/area/oldarea, var/area/newarea)
|
||||
change_area_name(oldarea.name, newarea.name)
|
||||
|
||||
/atom/proc/change_area_name(var/oldname, var/newname)
|
||||
name = replacetext(name,oldname,newname)
|
||||
|
||||
/atom/proc/get_global_map_pos()
|
||||
if(!islist(global_map) || isemptylist(global_map)) return
|
||||
var/cur_x = null
|
||||
@@ -362,7 +392,7 @@ var/list/blood_splatter_icons = list()
|
||||
return 0
|
||||
|
||||
/atom/proc/isinspace()
|
||||
if(istype(get_turf(src), /turf/open/space))
|
||||
if(isspaceturf(get_turf(src)))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
@@ -378,7 +408,7 @@ var/list/blood_splatter_icons = list()
|
||||
/atom/proc/singularity_pull()
|
||||
return
|
||||
|
||||
/atom/proc/acid_act(acidpwr, toxpwr, acid_volume)
|
||||
/atom/proc/acid_act(acidpwr, acid_volume)
|
||||
return
|
||||
|
||||
/atom/proc/emag_act()
|
||||
@@ -405,13 +435,14 @@ var/list/blood_splatter_icons = list()
|
||||
sleep(1)
|
||||
stoplag()
|
||||
|
||||
//This is called just before maps and objects are initialized, use it to spawn other mobs/objects
|
||||
//effects at world start up without causing runtimes
|
||||
/atom/proc/spawn_atom_to_world()
|
||||
|
||||
//This will be called after the map and objects are loaded
|
||||
/atom/proc/initialize()
|
||||
return
|
||||
//Called after New if the world is not loaded with TRUE
|
||||
//Called from base of New if the world is loaded with FALSE
|
||||
//This base must be called or derivatives must set initialized to TRUE to prevent repeat calls
|
||||
//Derivatives must not sleep
|
||||
/atom/proc/Initialize(mapload)
|
||||
if(initialized)
|
||||
stack_trace("Warning: [src]([type]) initialized multiple times!")
|
||||
initialized = TRUE
|
||||
|
||||
//the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it)
|
||||
/atom/proc/get_remote_view_fullscreens(mob/user)
|
||||
@@ -422,8 +453,8 @@ var/list/blood_splatter_icons = list()
|
||||
return
|
||||
|
||||
/atom/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = 0)
|
||||
if(istype(src,/turf) )
|
||||
var/obj/effect/decal/cleanable/vomit/V = PoolOrNew(/obj/effect/decal/cleanable/vomit, src)
|
||||
if(isturf(src))
|
||||
var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src)
|
||||
// Make toxins vomit look different
|
||||
if(toxvomit)
|
||||
V.icon_state = "vomittox_[pick(1,4)]"
|
||||
@@ -442,3 +473,88 @@ var/list/blood_splatter_icons = list()
|
||||
//Hook for running code when a dir change occurs
|
||||
/atom/proc/setDir(newdir)
|
||||
dir = newdir
|
||||
|
||||
/atom/proc/mech_melee_attack(obj/mecha/M)
|
||||
return
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Atom Colour Priority System
|
||||
A System that gives finer control over which atom colour to colour the atom with.
|
||||
The "highest priority" one is always displayed as opposed to the default of
|
||||
"whichever was set last is displayed"
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Adds an instance of colour_type to the atom's atom_colours list
|
||||
*/
|
||||
/atom/proc/add_atom_colour(coloration, colour_priority)
|
||||
if(!atom_colours || !atom_colours.len)
|
||||
atom_colours = list()
|
||||
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
||||
if(!coloration)
|
||||
return
|
||||
if(colour_priority > atom_colours.len)
|
||||
return
|
||||
atom_colours[colour_priority] = coloration
|
||||
update_atom_colour()
|
||||
|
||||
|
||||
/*
|
||||
Removes an instance of colour_type from the atom's atom_colours list
|
||||
*/
|
||||
/atom/proc/remove_atom_colour(colour_priority, coloration)
|
||||
if(!atom_colours)
|
||||
atom_colours = list()
|
||||
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
||||
if(colour_priority > atom_colours.len)
|
||||
return
|
||||
if(coloration && atom_colours[colour_priority] != coloration)
|
||||
return //if we don't have the expected color (for a specific priority) to remove, do nothing
|
||||
atom_colours[colour_priority] = null
|
||||
update_atom_colour()
|
||||
|
||||
|
||||
/*
|
||||
Resets the atom's color to null, and then sets it to the highest priority
|
||||
colour available
|
||||
*/
|
||||
/atom/proc/update_atom_colour()
|
||||
if(!atom_colours)
|
||||
atom_colours = list()
|
||||
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
|
||||
color = null
|
||||
for(var/C in atom_colours)
|
||||
if(islist(C))
|
||||
var/list/L = C
|
||||
if(L.len)
|
||||
color = L
|
||||
return
|
||||
else if(C)
|
||||
color = C
|
||||
return
|
||||
|
||||
/atom/vv_edit_var(var_name, var_value)
|
||||
if(!Debug2)
|
||||
admin_spawned = TRUE
|
||||
switch(var_name)
|
||||
if("luminosity")
|
||||
src.SetLuminosity(var_value)
|
||||
return//prevent normal setting of this value
|
||||
. = ..()
|
||||
switch(var_name)
|
||||
if("color")
|
||||
add_atom_colour(color, ADMIN_COLOUR_PRIORITY)
|
||||
|
||||
/atom/vv_get_dropdown()
|
||||
. = ..()
|
||||
. += "---"
|
||||
var/turf/curturf = get_turf(src)
|
||||
if (curturf)
|
||||
.["Jump to"] = "?_src_=holder;adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
|
||||
.["Add reagent"] = "?_src_=vars;addreagent=\ref[src]"
|
||||
.["Trigger EM pulse"] = "?_src_=vars;emp=\ref[src]"
|
||||
.["Trigger explosion"] = "?_src_=vars;explode=\ref[src]"
|
||||
|
||||
|
||||
+159
-135
@@ -3,7 +3,7 @@
|
||||
var/last_move = null
|
||||
var/anchored = 0
|
||||
var/throwing = 0
|
||||
var/throw_speed = 2
|
||||
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
|
||||
var/throw_range = 7
|
||||
var/mob/pulledby = null
|
||||
var/languages_spoken = 0 //For say() and Hear()
|
||||
@@ -19,8 +19,11 @@
|
||||
var/inertia_move_delay = 5
|
||||
var/pass_flags = 0
|
||||
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
|
||||
var/list/client_mobs_in_contents // This contains all the client mobs within this container
|
||||
var/list/acted_explosions //for explosion dodging
|
||||
glide_size = 8
|
||||
appearance_flags = TILE_BOUND
|
||||
var/datum/forced_movement/force_moving = null //handled soley by forced_movement.dm
|
||||
|
||||
|
||||
|
||||
@@ -64,13 +67,12 @@
|
||||
moving_diagonally = SECOND_DIAG_STEP
|
||||
. = step(src, SOUTH)
|
||||
moving_diagonally = 0
|
||||
return
|
||||
|
||||
if(!loc || (loc == oldloc && oldloc != newloc))
|
||||
last_move = 0
|
||||
return
|
||||
|
||||
update_client_hook(loc)
|
||||
|
||||
if(.)
|
||||
Moved(oldloc, direct)
|
||||
|
||||
@@ -81,17 +83,34 @@
|
||||
|
||||
//Called after a successful Move(). By this point, we've already moved
|
||||
/atom/movable/proc/Moved(atom/OldLoc, Dir)
|
||||
//Objects with opacity will trigger nearby lights of the old location to update at next SSlighting fire
|
||||
if(opacity)
|
||||
if (isturf(OldLoc))
|
||||
OldLoc.UpdateAffectingLights()
|
||||
if (isturf(loc))
|
||||
loc.UpdateAffectingLights()
|
||||
else
|
||||
if(light)
|
||||
light.changed()
|
||||
|
||||
if (!inertia_moving)
|
||||
inertia_next_move = world.time + inertia_move_delay
|
||||
newtonian_move(Dir)
|
||||
if (length(client_mobs_in_contents))
|
||||
update_parallax_contents()
|
||||
|
||||
if (orbiters)
|
||||
for (var/thing in orbiters)
|
||||
var/datum/orbit/O = thing
|
||||
O.Check()
|
||||
if (orbiting)
|
||||
orbiting.Check()
|
||||
return 1
|
||||
|
||||
/atom/movable/Destroy()
|
||||
. = ..()
|
||||
if(loc)
|
||||
loc.handle_atom_del(src)
|
||||
if(reagents)
|
||||
qdel(reagents)
|
||||
for(var/atom/movable/AM in contents)
|
||||
qdel(AM)
|
||||
loc = null
|
||||
@@ -121,10 +140,12 @@
|
||||
if(pulledby)
|
||||
pulledby.stop_pulling()
|
||||
var/atom/oldloc = loc
|
||||
if(oldloc)
|
||||
var/same_loc = oldloc == destination.loc
|
||||
if(oldloc && !same_loc)
|
||||
oldloc.Exited(src, destination)
|
||||
loc = destination
|
||||
destination.Entered(src, oldloc)
|
||||
if(!same_loc)
|
||||
destination.Entered(src, oldloc)
|
||||
var/area/old_area = get_area(oldloc)
|
||||
var/area/destarea = get_area(destination)
|
||||
if(old_area != destarea)
|
||||
@@ -134,9 +155,6 @@
|
||||
continue
|
||||
AM.Crossed(src)
|
||||
Moved(oldloc, 0)
|
||||
|
||||
update_client_hook(destination)
|
||||
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -151,33 +169,12 @@
|
||||
reset_perspective(destination)
|
||||
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
|
||||
|
||||
/mob/living/carbon/brain/forceMove(atom/destination)
|
||||
/mob/living/brain/forceMove(atom/destination)
|
||||
if(container)
|
||||
container.forceMove(destination)
|
||||
return container.forceMove(destination)
|
||||
else //something went very wrong.
|
||||
CRASH("Brainmob without container.")
|
||||
|
||||
/mob/living/silicon/pai/forceMove(atom/destination)
|
||||
if(card)
|
||||
card.forceMove(destination)
|
||||
else //something went very wrong.
|
||||
CRASH("pAI without card")
|
||||
|
||||
/atom/movable/proc/update_client_hook(atom/destination)
|
||||
if(locate(/mob) in src)
|
||||
for(var/client/C in parallax_on_clients)
|
||||
if((get_turf(C.eye) == destination) && (C.mob.hud_used))
|
||||
C.mob.hud_used.update_parallax_values()
|
||||
|
||||
/mob/update_client_hook(atom/destination)
|
||||
if(locate(/mob) in src)
|
||||
for(var/client/C in parallax_on_clients)
|
||||
if((get_turf(C.eye) == destination) && (C.mob.hud_used))
|
||||
C.mob.hud_used.update_parallax_values()
|
||||
else if(client && hud_used)
|
||||
hud_used.update_parallax_values()
|
||||
|
||||
|
||||
//Called whenever an object moves and by mobs when they attempt to move themselves through space
|
||||
//And when an object or action applies a force on src, see newtonian_move() below
|
||||
//Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting
|
||||
@@ -222,129 +219,82 @@
|
||||
step(src, AM.dir)
|
||||
..()
|
||||
|
||||
/atom/movable/proc/throw_at_fast(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0)
|
||||
set waitfor = 0
|
||||
throw_at(target, range, speed, thrower, spin, diagonals_first)
|
||||
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
|
||||
if (!target || (flags & NODROP) || speed <= 0)
|
||||
return
|
||||
|
||||
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0)
|
||||
if(!target || !src || (flags & NODROP))
|
||||
return 0
|
||||
//use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target
|
||||
|
||||
if(pulledby)
|
||||
if (pulledby)
|
||||
pulledby.stop_pulling()
|
||||
|
||||
throwing = 1
|
||||
if(spin) //if we don't want the /atom/movable to spin.
|
||||
SpinAnimation(5, 1)
|
||||
//They are moving! Wouldn't it be cool if we calculated their momentum and added it to the throw?
|
||||
if (thrower && thrower.last_move && thrower.client && thrower.client.move_delay >= world.time + world.tick_lag*2)
|
||||
var/user_momentum = thrower.movement_delay()
|
||||
if (!user_momentum) //no movement_delay, this means they move once per byond tick, lets calculate from that instead.
|
||||
user_momentum = world.tick_lag
|
||||
|
||||
var/dist_travelled = 0
|
||||
var/next_sleep = 0
|
||||
user_momentum = 1 / user_momentum // convert from ds to the tiles per ds that throw_at uses.
|
||||
|
||||
if (get_dir(thrower, target) & last_move)
|
||||
user_momentum = user_momentum //basically a noop, but needed
|
||||
else if (get_dir(target, thrower) & last_move)
|
||||
user_momentum = -user_momentum //we are moving away from the target, lets slowdown the throw accordingly
|
||||
else
|
||||
user_momentum = 0
|
||||
|
||||
|
||||
if (user_momentum)
|
||||
//first lets add that momentum to range.
|
||||
range *= (user_momentum / speed) + 1
|
||||
//then lets add it to speed
|
||||
speed += user_momentum
|
||||
if (speed <= 0)
|
||||
return //no throw speed, the user was moving too fast.
|
||||
|
||||
var/datum/thrownthing/TT = new()
|
||||
TT.thrownthing = src
|
||||
TT.target = target
|
||||
TT.target_turf = get_turf(target)
|
||||
TT.init_dir = get_dir(src, target)
|
||||
TT.maxrange = range
|
||||
TT.speed = speed
|
||||
TT.thrower = thrower
|
||||
TT.diagonals_first = diagonals_first
|
||||
TT.callback = callback
|
||||
|
||||
var/dist_x = abs(target.x - src.x)
|
||||
var/dist_y = abs(target.y - src.y)
|
||||
var/dx = (target.x > src.x) ? EAST : WEST
|
||||
var/dy = (target.y > src.y) ? NORTH : SOUTH
|
||||
|
||||
var/pure_diagonal = 0
|
||||
if(dist_x == dist_y)
|
||||
pure_diagonal = 1
|
||||
if (dist_x == dist_y)
|
||||
TT.pure_diagonal = 1
|
||||
|
||||
if(dist_x <= dist_y)
|
||||
else if(dist_x <= dist_y)
|
||||
var/olddist_x = dist_x
|
||||
var/olddx = dx
|
||||
dist_x = dist_y
|
||||
dist_y = olddist_x
|
||||
dx = dy
|
||||
dy = olddx
|
||||
TT.dist_x = dist_x
|
||||
TT.dist_y = dist_y
|
||||
TT.dx = dx
|
||||
TT.dy = dy
|
||||
TT.diagonal_error = dist_x/2 - dist_y
|
||||
TT.start_time = world.time
|
||||
|
||||
var/error = dist_x/2 - dist_y //used to decide whether our next move should be forward or diagonal.
|
||||
var/atom/finalturf = get_turf(target)
|
||||
var/hit = 0
|
||||
var/init_dir = get_dir(src, target)
|
||||
if(pulledby)
|
||||
pulledby.stop_pulling()
|
||||
|
||||
while(target && ((dist_travelled < range && loc != finalturf) || !has_gravity(src))) //stop if we reached our destination (or max range) and aren't floating
|
||||
var/slept = 0
|
||||
if(!istype(loc, /turf))
|
||||
hit = 1
|
||||
break
|
||||
throwing = 1
|
||||
if(spin)
|
||||
SpinAnimation(5, 1)
|
||||
|
||||
var/atom/step
|
||||
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(src, get_dir(src, finalturf))
|
||||
else
|
||||
step = get_step(src, init_dir)
|
||||
SSthrowing.processing[src] = TT
|
||||
if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun))
|
||||
SSthrowing.currentrun[src] = TT
|
||||
TT.tick()
|
||||
|
||||
if(!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first
|
||||
if(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(src, dx)
|
||||
error += (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
|
||||
break
|
||||
Move(step, get_dir(loc, step))
|
||||
if(!throwing) // we hit something during our move
|
||||
hit = 1
|
||||
break
|
||||
dist_travelled++
|
||||
|
||||
if(dist_travelled > 600) //safety to prevent infinite while loop.
|
||||
break
|
||||
if(dist_travelled >= next_sleep)
|
||||
slept = 1
|
||||
next_sleep += speed
|
||||
sleep(1)
|
||||
if(!slept)
|
||||
var/ticks_slept = TICK_CHECK
|
||||
if(ticks_slept)
|
||||
slept = 1
|
||||
next_sleep += speed*(ticks_slept*world.tick_lag) //delay the next normal sleep
|
||||
|
||||
if(slept && hitcheck()) //to catch sneaky things moving on our tile while we slept
|
||||
hit = 1
|
||||
break
|
||||
|
||||
|
||||
//done throwing, either because it hit something or it finished moving
|
||||
throwing = 0
|
||||
if(!hit)
|
||||
for(var/atom/A in get_turf(src)) //looking for our target on the turf we land on.
|
||||
if(A == target)
|
||||
hit = 1
|
||||
throw_impact(A)
|
||||
return 1
|
||||
|
||||
throw_impact(get_turf(src)) // we haven't hit something yet and we still must, let's hit the ground.
|
||||
newtonian_move(init_dir)
|
||||
return 1
|
||||
|
||||
/atom/movable/proc/hitcheck()
|
||||
for(var/atom/movable/AM in get_turf(src))
|
||||
if(AM == src)
|
||||
continue
|
||||
if(AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER))
|
||||
throwing = 0
|
||||
throw_impact(AM)
|
||||
return 1
|
||||
|
||||
//Overlays
|
||||
/atom/movable/overlay
|
||||
var/atom/master = null
|
||||
anchored = 1
|
||||
|
||||
/atom/movable/overlay/New()
|
||||
verbs.Cut()
|
||||
|
||||
/atom/movable/overlay/attackby(a, b, c)
|
||||
if (src.master)
|
||||
return src.master.attackby(a, b, c)
|
||||
|
||||
/atom/movable/overlay/attack_paw(a, b, c)
|
||||
if (src.master)
|
||||
return src.master.attack_paw(a, b, c)
|
||||
|
||||
/atom/movable/overlay/attack_hand(a, b, c)
|
||||
if (src.master)
|
||||
return src.master.attack_hand(a, b, c)
|
||||
|
||||
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
|
||||
for(var/m in buckled_mobs)
|
||||
@@ -385,3 +335,77 @@
|
||||
//called when a mob resists while inside a container that is itself inside something.
|
||||
/atom/movable/proc/relay_container_resist(mob/living/user, obj/O)
|
||||
return
|
||||
|
||||
|
||||
/atom/movable/proc/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
|
||||
if(!no_effect && (visual_effect_icon || used_item))
|
||||
do_item_attack_animation(A, visual_effect_icon, used_item)
|
||||
|
||||
var/pixel_x_diff = 0
|
||||
var/pixel_y_diff = 0
|
||||
var/final_pixel_y = initial(pixel_y)
|
||||
if(end_pixel_y)
|
||||
final_pixel_y = end_pixel_y
|
||||
|
||||
var/direction = get_dir(src, A)
|
||||
if(direction & NORTH)
|
||||
pixel_y_diff = 8
|
||||
else if(direction & SOUTH)
|
||||
pixel_y_diff = -8
|
||||
|
||||
if(direction & EAST)
|
||||
pixel_x_diff = 8
|
||||
else if(direction & WEST)
|
||||
pixel_x_diff = -8
|
||||
|
||||
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2)
|
||||
animate(pixel_x = initial(pixel_x), pixel_y = final_pixel_y, time = 2)
|
||||
|
||||
/atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item)
|
||||
var/image/I
|
||||
if(visual_effect_icon)
|
||||
I = image('icons/effects/effects.dmi', A, visual_effect_icon, A.layer + 0.1)
|
||||
else if(used_item)
|
||||
I = image(used_item.icon, A, used_item.icon_state, A.layer + 0.1)
|
||||
|
||||
// Scale the icon.
|
||||
I.transform *= 0.75
|
||||
// The icon should not rotate.
|
||||
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
|
||||
// Set the direction of the icon animation.
|
||||
var/direction = get_dir(src, A)
|
||||
if(direction & NORTH)
|
||||
I.pixel_y = -16
|
||||
else if(direction & SOUTH)
|
||||
I.pixel_y = 16
|
||||
|
||||
if(direction & EAST)
|
||||
I.pixel_x = -16
|
||||
else if(direction & WEST)
|
||||
I.pixel_x = 16
|
||||
|
||||
if(!direction) // Attacked self?!
|
||||
I.pixel_z = 16
|
||||
|
||||
if(!I)
|
||||
return
|
||||
|
||||
flick_overlay(I, clients, 5) // 5 ticks/half a second
|
||||
|
||||
// And animate the attack!
|
||||
animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
|
||||
|
||||
/atom/movable/vv_get_dropdown()
|
||||
. = ..()
|
||||
. -= "Jump to"
|
||||
.["Follow"] = "?_src_=holder;adminplayerobservefollow=\ref[src]"
|
||||
|
||||
/atom/movable/proc/ex_check(ex_id)
|
||||
if(!ex_id)
|
||||
return TRUE
|
||||
LAZYINITLIST(acted_explosions)
|
||||
if(ex_id in acted_explosions)
|
||||
return FALSE
|
||||
acted_explosions += ex_id
|
||||
return TRUE
|
||||
+80
-22
@@ -45,7 +45,7 @@
|
||||
hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD, WANTED_HUD)
|
||||
|
||||
/datum/atom_hud/data/diagnostic
|
||||
hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD)
|
||||
hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD)
|
||||
|
||||
/* MED/SEC/DIAG HUD HOOKS */
|
||||
|
||||
@@ -61,19 +61,25 @@
|
||||
|
||||
//called when a carbon changes virus
|
||||
/mob/living/carbon/proc/check_virus()
|
||||
var/threat = 0
|
||||
for(var/datum/disease/D in viruses)
|
||||
if((!(D.visibility_flags & HIDDEN_SCANNER)) && (D.severity != NONTHREAT))
|
||||
return 1
|
||||
return 0
|
||||
if(!(D.visibility_flags & HIDDEN_SCANNER))
|
||||
if (D.severity != NONTHREAT) //a buffing virus gets an icon
|
||||
threat = 2
|
||||
return threat //harmful viruses have priority
|
||||
else
|
||||
threat = 1 //aka good virus
|
||||
|
||||
return threat
|
||||
|
||||
//helper for getting the appropriate health status
|
||||
/proc/RoundHealth(mob/living/M)
|
||||
if(M.stat == DEAD || (M.status_flags & FAKEDEATH))
|
||||
return "health-100" //what's our health? it doesn't matter, we're dead, or faking
|
||||
var/maxhealth = M.maxHealth
|
||||
var/maxi_health = M.maxHealth
|
||||
if(iscarbon(M) && M.health < 0)
|
||||
maxhealth = 100 //so crit shows up right for aliens and other high-health carbon mobs; noncarbons don't have crit.
|
||||
var/resulthealth = (M.health / maxhealth) * 100
|
||||
maxi_health = 100 //so crit shows up right for aliens and other high-health carbon mobs; noncarbons don't have crit.
|
||||
var/resulthealth = (M.health / maxi_health) * 100
|
||||
switch(resulthealth)
|
||||
if(100 to INFINITY)
|
||||
return "health100"
|
||||
@@ -131,6 +137,8 @@
|
||||
/mob/living/proc/med_hud_set_health()
|
||||
var/image/holder = hud_list[HEALTH_HUD]
|
||||
holder.icon_state = "hud[RoundHealth(src)]"
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
|
||||
//for carbon suit sensors
|
||||
/mob/living/carbon/med_hud_set_health()
|
||||
@@ -143,6 +151,8 @@
|
||||
//called when a carbon changes stat, virus or XENO_HOST
|
||||
/mob/living/proc/med_hud_set_status()
|
||||
var/image/holder = hud_list[STATUS_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
holder.icon_state = "huddead"
|
||||
else
|
||||
@@ -150,12 +160,20 @@
|
||||
|
||||
/mob/living/carbon/med_hud_set_status()
|
||||
var/image/holder = hud_list[STATUS_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
var/virus_state = check_virus()
|
||||
var/mob/living/simple_animal/borer/B = has_brain_worms()
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(status_flags & XENO_HOST)
|
||||
holder.icon_state = "hudxeno"
|
||||
else if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
holder.icon_state = "huddead"
|
||||
else if(check_virus())
|
||||
else if(has_brain_worms() && B != null && B.controlling)
|
||||
holder.icon_state = "hudbrainworm"
|
||||
else if(virus_state == 2)
|
||||
holder.icon_state = "hudill"
|
||||
else if(virus_state == 1)
|
||||
holder.icon_state = "hudbuff"
|
||||
else
|
||||
holder.icon_state = "hudhealthy"
|
||||
|
||||
@@ -168,6 +186,8 @@
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_ID()
|
||||
var/image/holder = hud_list[ID_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = "hudno_id"
|
||||
if(wear_id)
|
||||
holder.icon_state = "hud[ckey(wear_id.GetJobName())]"
|
||||
@@ -181,20 +201,27 @@
|
||||
for(var/i in list(IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD))
|
||||
holder = hud_list[i]
|
||||
holder.icon_state = null
|
||||
for(var/obj/item/weapon/implant/I in src)
|
||||
if(I.implanted)
|
||||
if(istype(I,/obj/item/weapon/implant/tracking))
|
||||
holder = hud_list[IMPTRACK_HUD]
|
||||
holder.icon_state = "hud_imp_tracking"
|
||||
else if(istype(I,/obj/item/weapon/implant/mindshield))
|
||||
holder = hud_list[IMPLOYAL_HUD]
|
||||
holder.icon_state = "hud_imp_loyal"
|
||||
else if(istype(I,/obj/item/weapon/implant/chem))
|
||||
holder = hud_list[IMPCHEM_HUD]
|
||||
holder.icon_state = "hud_imp_chem"
|
||||
for(var/obj/item/weapon/implant/I in implants)
|
||||
if(istype(I,/obj/item/weapon/implant/tracking))
|
||||
holder = hud_list[IMPTRACK_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_tracking"
|
||||
else if(istype(I,/obj/item/weapon/implant/mindshield))
|
||||
holder = hud_list[IMPLOYAL_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_loyal"
|
||||
else if(istype(I,/obj/item/weapon/implant/chem))
|
||||
holder = hud_list[IMPCHEM_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_chem"
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_security_status()
|
||||
var/image/holder = hud_list[WANTED_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
var/perpname = get_face_name(get_id_name(""))
|
||||
if(perpname)
|
||||
var/datum/data/record/R = find_record("name", perpname, data_core.security)
|
||||
@@ -240,6 +267,8 @@
|
||||
//Sillycone hooks
|
||||
/mob/living/silicon/proc/diag_hud_set_health()
|
||||
var/image/holder = hud_list[DIAG_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(stat == DEAD)
|
||||
holder.icon_state = "huddiagdead"
|
||||
else
|
||||
@@ -247,6 +276,8 @@
|
||||
|
||||
/mob/living/silicon/proc/diag_hud_set_status()
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
switch(stat)
|
||||
if(CONSCIOUS)
|
||||
holder.icon_state = "hudstat"
|
||||
@@ -258,7 +289,9 @@
|
||||
//Borgie battery tracking!
|
||||
/mob/living/silicon/robot/proc/diag_hud_set_borgcell()
|
||||
var/image/holder = hud_list[DIAG_BATT_HUD]
|
||||
if (cell)
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(cell)
|
||||
var/chargelvl = (cell.charge/cell.maxcharge)
|
||||
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
|
||||
else
|
||||
@@ -269,12 +302,16 @@
|
||||
~~~~~~~~~~~~~~~~~~~~~*/
|
||||
/obj/mecha/proc/diag_hud_set_mechhealth()
|
||||
var/image/holder = hud_list[DIAG_MECH_HUD]
|
||||
holder.icon_state = "huddiag[RoundDiagBar(health/initial(health))]"
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = "huddiag[RoundDiagBar(obj_integrity/max_integrity)]"
|
||||
|
||||
|
||||
/obj/mecha/proc/diag_hud_set_mechcell()
|
||||
var/image/holder = hud_list[DIAG_BATT_HUD]
|
||||
if (cell)
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(cell)
|
||||
var/chargelvl = cell.charge/cell.maxcharge
|
||||
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
|
||||
else
|
||||
@@ -283,19 +320,38 @@
|
||||
|
||||
/obj/mecha/proc/diag_hud_set_mechstat()
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = null
|
||||
if(internal_damage)
|
||||
holder.icon_state = "hudwarn"
|
||||
|
||||
/obj/mecha/proc/diag_hud_set_mechtracking() //Shows tracking beacons on the mech
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
var/new_icon_state //This var exists so that the holder's icon state is set only once in the event of multiple mech beacons.
|
||||
for(var/obj/item/mecha_parts/mecha_tracking/T in trackers)
|
||||
if(T.ai_beacon) //Beacon with AI uplink
|
||||
new_icon_state = "hudtrackingai"
|
||||
break //Immediately terminate upon finding an AI beacon to ensure it is always shown over the normal one, as mechs can have several trackers.
|
||||
else
|
||||
new_icon_state = "hudtracking"
|
||||
holder.icon_state = new_icon_state
|
||||
|
||||
/*~~~~~~~~~
|
||||
Bots!
|
||||
~~~~~~~~~~*/
|
||||
/mob/living/simple_animal/bot/proc/diag_hud_set_bothealth()
|
||||
var/image/holder = hud_list[DIAG_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]"
|
||||
|
||||
/mob/living/simple_animal/bot/proc/diag_hud_set_botstat() //On (With wireless on or off), Off, EMP'ed
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(on)
|
||||
holder.icon_state = "hudstat"
|
||||
else if(stat) //Generally EMP causes this
|
||||
@@ -305,6 +361,8 @@
|
||||
|
||||
/mob/living/simple_animal/bot/proc/diag_hud_set_botmode() //Shows a bot's current operation
|
||||
var/image/holder = hud_list[DIAG_BOT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(client) //If the bot is player controlled, it will not be following mode logic!
|
||||
holder.icon_state = "hudsentient"
|
||||
return
|
||||
|
||||
@@ -41,17 +41,48 @@
|
||||
|
||||
//MIND PROCS
|
||||
//these are called by mind.transfer_to()
|
||||
/datum/mind/proc/transfer_antag_huds(var/datum/atom_hud/antag/newhud)
|
||||
leave_all_huds()
|
||||
/datum/mind/proc/transfer_antag_huds(datum/atom_hud/antag/newhud)
|
||||
leave_all_antag_huds()
|
||||
ticker.mode.set_antag_hud(current, antag_hud_icon_state)
|
||||
if(newhud)
|
||||
newhud.join_hud(current)
|
||||
|
||||
/datum/mind/proc/leave_all_huds()
|
||||
/datum/mind/proc/leave_all_antag_huds()
|
||||
for(var/datum/atom_hud/antag/hud in huds)
|
||||
if(current in hud.hudusers)
|
||||
hud.leave_hud(current)
|
||||
|
||||
for(var/datum/atom_hud/data/hud in huds)
|
||||
if(current in hud.hudusers)
|
||||
hud.remove_hud_from(current)
|
||||
/datum/atom_hud/antag/gang
|
||||
var/color = null
|
||||
|
||||
/datum/atom_hud/antag/gang/add_to_hud(atom/A)
|
||||
if(!A)
|
||||
return
|
||||
var/image/holder = A.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = color
|
||||
..()
|
||||
|
||||
/datum/atom_hud/antag/gang/remove_from_hud(atom/A)
|
||||
if(!A)
|
||||
return
|
||||
var/image/holder = A.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = null
|
||||
..()
|
||||
|
||||
/datum/atom_hud/antag/gang/join_hud(mob/M)
|
||||
if(!istype(M))
|
||||
CRASH("join_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = color
|
||||
..()
|
||||
|
||||
/datum/atom_hud/antag/gang/leave_hud(mob/M)
|
||||
if(!istype(M))
|
||||
CRASH("leave_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = null
|
||||
..()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/weapon/antag_spawner
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = 1
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/used = 0
|
||||
|
||||
/obj/item/weapon/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
|
||||
@@ -47,64 +47,71 @@
|
||||
|
||||
if(H.stat || H.restrained())
|
||||
return
|
||||
if(!istype(H, /mob/living/carbon/human))
|
||||
if(!ishuman(H))
|
||||
return 1
|
||||
|
||||
if(loc == H || (in_range(src, H) && istype(loc, /turf)))
|
||||
if(loc == H || (in_range(src, H) && isturf(loc)))
|
||||
H.set_machine(src)
|
||||
if(href_list["school"])
|
||||
if (used)
|
||||
if(used)
|
||||
H << "You already used this contract!"
|
||||
return
|
||||
var/list/candidates = get_candidates(ROLE_WIZARD)
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src)
|
||||
if(candidates.len)
|
||||
src.used = 1
|
||||
var/client/C = pick(candidates)
|
||||
spawn_antag(C, get_turf(H.loc), href_list["school"])
|
||||
if(H.mind)
|
||||
if(used)
|
||||
H << "You already used this contract!"
|
||||
return
|
||||
used = 1
|
||||
var/mob/dead/observer/theghost = pick(candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), href_list["school"])
|
||||
if(H && H.mind)
|
||||
ticker.mode.update_wiz_icons_added(H.mind)
|
||||
else
|
||||
H << "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later."
|
||||
|
||||
/obj/item/weapon/antag_spawner/contract/spawn_antag(client/C, turf/T, type = "")
|
||||
PoolOrNew(/obj/effect/particle_effect/smoke, T)
|
||||
new /obj/effect/particle_effect/smoke(T)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
M << "<B>You are the [usr.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
|
||||
var/wizard_name = "the wizard"
|
||||
if(usr)
|
||||
wizard_name = usr.real_name
|
||||
M << "<B>You are [wizard_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
|
||||
switch(type)
|
||||
if("destruction")
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
|
||||
if("bluespace")
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
|
||||
if("healing")
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null))
|
||||
M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand)
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall(null))
|
||||
M.put_in_hands_or_del(new /obj/item/weapon/gun/magic/staff/healing(M))
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
|
||||
if("robeless")
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
|
||||
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."
|
||||
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."
|
||||
|
||||
equip_antag(M)
|
||||
var/wizard_name_first = pick(wizard_first)
|
||||
var/wizard_name_second = pick(wizard_second)
|
||||
var/randomname = "[wizard_name_first] [wizard_name_second]"
|
||||
var/datum/objective/protect/new_objective = new /datum/objective/protect
|
||||
new_objective.owner = M:mind
|
||||
new_objective:target = usr:mind
|
||||
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
|
||||
M.mind.objectives += new_objective
|
||||
if(usr)
|
||||
var/datum/objective/protect/new_objective = new /datum/objective/protect
|
||||
new_objective.owner = M.mind
|
||||
new_objective.target = usr.mind
|
||||
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
|
||||
M.mind.objectives += new_objective
|
||||
ticker.mode.apprentices += M.mind
|
||||
M.mind.special_role = "apprentice"
|
||||
ticker.mode.update_wiz_icons_added(M.mind)
|
||||
M << sound('sound/effects/magic.ogg')
|
||||
var/newname = copytext(sanitize(input(M, "You are the wizard's apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
|
||||
var/newname = copytext(sanitize(input(M, "You are [wizard_name]'s apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
|
||||
if (!newname)
|
||||
newname = randomname
|
||||
M.mind.name = newname
|
||||
@@ -115,7 +122,7 @@
|
||||
/obj/item/weapon/antag_spawner/contract/equip_antag(mob/target)
|
||||
target.equip_to_slot_or_del(new /obj/item/device/radio/headset(target), slot_ears)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(target), slot_w_uniform)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(target), slot_shoes)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(target), slot_shoes)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(target), slot_wear_suit)
|
||||
target.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(target), slot_head)
|
||||
target.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(target), slot_back)
|
||||
@@ -149,11 +156,13 @@
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
|
||||
var/list/nuke_candidates = get_candidates(ROLE_OPERATIVE, 3000, "operative")
|
||||
if(nuke_candidates.len > 0)
|
||||
var/list/nuke_candidates = pollCandidatesForMob("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, src)
|
||||
if(nuke_candidates.len)
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
used = 1
|
||||
var/client/C = pick(nuke_candidates)
|
||||
spawn_antag(C, get_turf(src.loc), "syndieborg")
|
||||
var/mob/dead/observer/theghost = pick(nuke_candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), "syndieborg")
|
||||
var/datum/effect_system/spark_spread/S = new /datum/effect_system/spark_spread
|
||||
S.set_up(4, 1, src)
|
||||
S.start()
|
||||
@@ -162,14 +171,10 @@
|
||||
user << "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>"
|
||||
|
||||
/obj/item/weapon/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T)
|
||||
var/new_op_code = "Ask your leader!"
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in nuke_list
|
||||
if(nuke)
|
||||
new_op_code = nuke.r_code
|
||||
M.mind.make_Nuke(T, new_op_code, 0, FALSE)
|
||||
M.mind.make_Nuke(null, null, 0, FALSE)
|
||||
var/newname = M.dna.species.random_name(M.gender,0,ticker.mode.nukeops_lastname)
|
||||
M.mind.name = newname
|
||||
M.real_name = newname
|
||||
@@ -213,12 +218,7 @@
|
||||
R.mmi.brainmob.name = brainopsname
|
||||
|
||||
R.key = C.key
|
||||
ticker.mode.syndicates += R.mind
|
||||
ticker.mode.update_synd_icons_added(R.mind)
|
||||
R.mind.special_role = "syndicate"
|
||||
R.faction = list("syndicate")
|
||||
|
||||
|
||||
R.mind.make_Nuke(null, nuke_code = null,leader=0, telecrystals = TRUE)
|
||||
|
||||
///////////SLAUGHTER DEMON
|
||||
|
||||
@@ -228,23 +228,25 @@
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bottle, no \
|
||||
turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>You sense a dark presence lurking \
|
||||
just beyond the veil...</span>"
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bottle, no turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>You sense a dark presence lurking just beyond the veil...</span>"
|
||||
var/objective_verb = "Kill"
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
|
||||
|
||||
|
||||
/obj/item/weapon/antag_spawner/slaughter_demon/attack_self(mob/user)
|
||||
var/list/demon_candidates = get_candidates(ROLE_ALIEN)
|
||||
if(user.z != 1)
|
||||
user << "<span class='notice'>You should probably wait until you reach the station.</span>"
|
||||
return
|
||||
if(demon_candidates.len > 0)
|
||||
if(used)
|
||||
return
|
||||
var/list/demon_candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", null, null, ROLE_ALIEN, 50, src)
|
||||
if(demon_candidates.len)
|
||||
if(used)
|
||||
return
|
||||
used = 1
|
||||
var/client/C = pick(demon_candidates)
|
||||
spawn_antag(C, get_turf(src.loc), initial(demon_type.name))
|
||||
var/mob/dead/observer/theghost = pick(demon_candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name))
|
||||
user << shatter_msg
|
||||
user << veil_msg
|
||||
playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1)
|
||||
@@ -255,40 +257,38 @@
|
||||
|
||||
/obj/item/weapon/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "")
|
||||
|
||||
var /obj/effect/dummy/slaughter/holder = PoolOrNew(/obj/effect/dummy/slaughter,T)
|
||||
var /obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
|
||||
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
|
||||
S.holder = holder
|
||||
S.key = C.key
|
||||
S.mind.assigned_role = S.name
|
||||
S.mind.special_role = S.name
|
||||
ticker.mode.traitors += S.mind
|
||||
var/datum/objective/assassinate/new_objective = new /datum/objective/assassinate
|
||||
new_objective.owner = S.mind
|
||||
new_objective.target = usr.mind
|
||||
new_objective.explanation_text = "[objective_verb] [usr.real_name], \
|
||||
the one who summoned you."
|
||||
S.mind.objectives += new_objective
|
||||
var/datum/objective/assassinate/new_objective
|
||||
if(usr)
|
||||
new_objective = new /datum/objective/assassinate
|
||||
new_objective.owner = S.mind
|
||||
new_objective.target = usr.mind
|
||||
new_objective.explanation_text = "[objective_verb] [usr.real_name], the one who summoned you."
|
||||
S.mind.objectives += new_objective
|
||||
var/datum/objective/new_objective2 = new /datum/objective
|
||||
new_objective2.owner = S.mind
|
||||
new_objective2.explanation_text = "[objective_verb] everyone else \
|
||||
while you're at it."
|
||||
new_objective2.explanation_text = "[objective_verb] everyone[usr ? " else while you're at it":""]."
|
||||
S.mind.objectives += new_objective2
|
||||
S << S.playstyle_string
|
||||
S << "<B>You are currently not currently in the same plane of \
|
||||
existence as the station. Ctrl+Click a blood pool to manifest.</B>"
|
||||
S << "<B>Objective #[1]</B>: [new_objective.explanation_text]"
|
||||
S << "<B>Objective #[2]</B>: [new_objective2.explanation_text]"
|
||||
S << "<B>You are currently not currently in the same plane of existence as the station. \
|
||||
Ctrl+Click a blood pool to manifest.</B>"
|
||||
if(new_objective)
|
||||
S << "<B>Objective #[1]</B>: [new_objective.explanation_text]"
|
||||
S << "<B>Objective #[new_objective ? "[2]":"[1]"]</B>: [new_objective2.explanation_text]"
|
||||
|
||||
/obj/item/weapon/antag_spawner/slaughter_demon/laughter
|
||||
name = "vial of tickles"
|
||||
desc = "A magically infused bottle of clown love, distilled from \
|
||||
countless hugging attacks. Used in funny rituals to attract \
|
||||
adorable creatures."
|
||||
desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
color = "#FF69B4" // HOT PINK
|
||||
|
||||
veil_msg = "<span class='warning'>You sense an adorable presence \
|
||||
lurking just beyond the veil...</span>"
|
||||
veil_msg = "<span class='warning'>You sense an adorable presence lurking just beyond the veil...</span>"
|
||||
objective_verb = "Hug and Tickle"
|
||||
demon_type = /mob/living/simple_animal/slaughter/laughter
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
|
||||
|
||||
|
||||
//Few global vars to track the blob
|
||||
var/list/blobs = list() //complete list of all blobs made.
|
||||
@@ -20,13 +20,19 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
|
||||
|
||||
round_ends_with_antag_death = 1
|
||||
|
||||
var/burst = 0
|
||||
announce_span = "green"
|
||||
announce_text = "Dangerous gelatinous organisms are spreading throughout the station!\n\
|
||||
<span class='green'>Blobs</span>: Consume the station and spread as far as you can.\n\
|
||||
<span class='notice'>Crew</span>: Fight back the blobs and minimize station damage."
|
||||
|
||||
var/message_sent = FALSE
|
||||
|
||||
var/cores_to_spawn = 1
|
||||
var/players_per_core = 25
|
||||
var/blob_point_rate = 3
|
||||
var/blob_base_starting_points = 80
|
||||
|
||||
var/blobwincount = 350
|
||||
var/blobwincount = 250
|
||||
|
||||
var/messagedelay_low = 2400 //in deciseconds
|
||||
var/messagedelay_high = 3600 //blob report will be sent after a random value between these (minimum 4 minutes, maximum 6 minutes)
|
||||
@@ -36,7 +42,8 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
|
||||
/datum/game_mode/blob/pre_setup()
|
||||
cores_to_spawn = max(round(num_players()/players_per_core, 1), 1)
|
||||
|
||||
blobwincount = initial(blobwincount) * cores_to_spawn
|
||||
var/win_multiplier = 1 + (0.1 * cores_to_spawn)
|
||||
blobwincount = initial(blobwincount) * cores_to_spawn * win_multiplier
|
||||
|
||||
for(var/j = 0, j < cores_to_spawn, j++)
|
||||
if (!antag_candidates.len)
|
||||
@@ -61,11 +68,6 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
|
||||
candidates += player
|
||||
return candidates
|
||||
|
||||
/datum/game_mode/blob/announce()
|
||||
world << "<B>The current game mode is - <font color='green'>Blob</font>!</B>"
|
||||
world << "<B>A dangerous alien organism is rapidly spreading throughout the station!</B>"
|
||||
world << "You must kill it all while minimizing the damage to the station."
|
||||
|
||||
/datum/game_mode/blob/proc/show_message(message)
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
blob.current << message
|
||||
@@ -73,12 +75,13 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
|
||||
/datum/game_mode/blob/post_setup()
|
||||
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
var/mob/camera/blob/B = blob.current.become_overmind(1)
|
||||
var/mob/camera/blob/B = blob.current.become_overmind(TRUE, round(blob_base_starting_points/blob_overminds.len))
|
||||
B.mind.name = B.name
|
||||
var/turf/T = pick(blobstart)
|
||||
B.loc = T
|
||||
B.base_point_rate = blob_point_rate
|
||||
|
||||
SSshuttle.emergencyNoEscape = 1
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
// Disable the blob event for this round.
|
||||
var/datum/round_event_control/blob/B = locate() in SSevent.control
|
||||
@@ -91,9 +94,10 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
|
||||
sleep(message_delay)
|
||||
|
||||
send_intercept(1)
|
||||
message_sent = TRUE
|
||||
|
||||
sleep(24000) //40 minutes, plus burst_delay*3(minimum of 6 minutes, maximum of 8)
|
||||
|
||||
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
|
||||
if(!replacementmode)
|
||||
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/datum/game_mode/blob/check_finished()
|
||||
if(blobwincount <= blobs_legit.len)//Blob took over
|
||||
return 1
|
||||
if(overminds.len)
|
||||
return 0
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
if(isovermind(blob.current))
|
||||
var/mob/camera/blob/B = blob.current
|
||||
if(B.blob_core || !B.placed)
|
||||
return 0
|
||||
if(!blob_cores.len) //blob is dead
|
||||
if(config.continuous["blob"])
|
||||
message_sent = FALSE //disable the win count at this point
|
||||
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
|
||||
SSshuttle.emergencyNoEscape = 0
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
|
||||
SSshuttle.emergency.mode = SHUTTLE_DOCKED
|
||||
SSshuttle.emergency.timer = world.time
|
||||
priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
return ..()
|
||||
return 1
|
||||
return ..()
|
||||
@@ -22,23 +22,45 @@
|
||||
if(blobwincount <= blobs_legit.len)
|
||||
feedback_set_details("round_end_result","win - blob took over")
|
||||
world << "<FONT size = 3><B>The blob has taken over the station!</B></FONT>"
|
||||
world << "<B>The entire station was eaten by the Blob</B>"
|
||||
world << "<B>The entire station was eaten by the Blob!</B>"
|
||||
log_game("Blob mode completed with a blob victory.")
|
||||
|
||||
ticker.news_report = BLOB_WIN
|
||||
|
||||
else if(station_was_nuked)
|
||||
feedback_set_details("round_end_result","halfwin - nuke")
|
||||
world << "<FONT size = 3><B>Partial Win: The station has been destroyed!</B></FONT>"
|
||||
world << "<B>Directive 7-12 has been successfully carried out preventing the Blob from spreading.</B>"
|
||||
world << "<B>Directive 7-12 has been successfully carried out, preventing the Blob from spreading.</B>"
|
||||
log_game("Blob mode completed with a tie (station destroyed).")
|
||||
|
||||
ticker.news_report = BLOB_NUKE
|
||||
|
||||
else if(!blob_cores.len)
|
||||
feedback_set_details("round_end_result","loss - blob eliminated")
|
||||
world << "<FONT size = 3><B>The staff has won!</B></FONT>"
|
||||
world << "<B>The alien organism has been eradicated from the station</B>"
|
||||
world << "<B>The alien organism has been eradicated from the station!</B>"
|
||||
log_game("Blob mode completed with a crew victory.")
|
||||
|
||||
ticker.news_report = BLOB_DESTROYED
|
||||
|
||||
..()
|
||||
return 1
|
||||
|
||||
/datum/game_mode/blob/printplayer(datum/mind/ply, fleecheck)
|
||||
if((ply in blob_overminds))
|
||||
var/text = "<br><b>[ply.key]</b> was <b>[ply.name]</b>"
|
||||
if(isovermind(ply.current))
|
||||
var/mob/camera/blob/B = ply.current
|
||||
text += "<b>(<font color=\"[B.blob_reagent_datum.color]\">[B.blob_reagent_datum.name]</font>)</b> and"
|
||||
if(B.blob_core)
|
||||
text += " <span class='greenannounce'>survived</span>"
|
||||
else
|
||||
text += " <span class='boldannounce'>was destroyed</span>"
|
||||
else
|
||||
text += " and <span class='boldannounce'>was destroyed</span>"
|
||||
return text
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_blob()
|
||||
if(istype(ticker.mode,/datum/game_mode/blob) )
|
||||
var/datum/game_mode/blob/blob_mode = src
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
|
||||
|
||||
|
||||
/datum/game_mode/blob/send_intercept(report = 0)
|
||||
var/intercepttext = ""
|
||||
@@ -16,7 +16,7 @@
|
||||
print_command_report(intercepttext,"Level 5-6 Biohazard Response Procedures")
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/AI/outbreak5.ogg')
|
||||
if(2)
|
||||
var/nukecode = rand(10000, 99999)
|
||||
var/nukecode = random_nukecode()
|
||||
for(var/obj/machinery/nuclearbomb/bomb in machines)
|
||||
if(bomb && bomb.r_code)
|
||||
if(bomb.z == ZLEVEL_STATION)
|
||||
@@ -57,20 +57,23 @@
|
||||
/datum/station_state/proc/count(count_territories)
|
||||
for(var/turf/T in block(locate(1,1,1), locate(world.maxx,world.maxy,1)))
|
||||
|
||||
if(istype(T,/turf/open/floor))
|
||||
if(!(T:burnt))
|
||||
if(isfloorturf(T))
|
||||
var/turf/open/floor/TF = T
|
||||
if(!(TF.burnt))
|
||||
src.floor += 12
|
||||
else
|
||||
src.floor += 1
|
||||
|
||||
if(istype(T, /turf/closed/wall))
|
||||
if(T:intact)
|
||||
if(iswallturf(T))
|
||||
var/turf/closed/wall/TW = T
|
||||
if(TW.intact)
|
||||
src.wall += 2
|
||||
else
|
||||
src.wall += 1
|
||||
|
||||
if(istype(T, /turf/closed/wall/r_wall))
|
||||
if(T:intact)
|
||||
var/turf/closed/wall/r_wall/TRW = T
|
||||
if(TRW.intact)
|
||||
src.r_wall += 2
|
||||
else
|
||||
src.r_wall += 1
|
||||
@@ -79,8 +82,10 @@
|
||||
for(var/obj/O in T.contents)
|
||||
if(istype(O, /obj/structure/window))
|
||||
src.window += 1
|
||||
else if(istype(O, /obj/structure/grille) && (!O:destroyed))
|
||||
src.grille += 1
|
||||
else if(istype(O, /obj/structure/grille))
|
||||
var/obj/structure/grille/GR = O
|
||||
if(!GR.broken)
|
||||
src.grille += 1
|
||||
else if(istype(O, /obj/machinery/door))
|
||||
src.door += 1
|
||||
else if(istype(O, /obj/machinery))
|
||||
|
||||
@@ -14,49 +14,52 @@
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 360
|
||||
unique_name = 1
|
||||
a_intent = "harm"
|
||||
a_intent = INTENT_HARM
|
||||
var/mob/camera/blob/overmind = null
|
||||
var/obj/effect/blob/factory/factory = null
|
||||
var/obj/structure/blob/factory/factory = null
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/update_icons()
|
||||
if(overmind)
|
||||
color = overmind.blob_reagent_datum.color
|
||||
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
color = initial(color)
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Destroy()
|
||||
if(overmind)
|
||||
overmind.blob_mobs -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blob_act(obj/effect/blob/B)
|
||||
/mob/living/simple_animal/hostile/blob/blob_act(obj/structure/blob/B)
|
||||
if(stat != DEAD && health < maxHealth)
|
||||
for(var/i in 1 to 2)
|
||||
var/obj/effect/overlay/temp/heal/H = PoolOrNew(/obj/effect/overlay/temp/heal, get_turf(src)) //hello yes you are being healed
|
||||
var/obj/effect/overlay/temp/heal/H = new /obj/effect/overlay/temp/heal(get_turf(src)) //hello yes you are being healed
|
||||
if(overmind)
|
||||
H.color = overmind.blob_reagent_datum.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
adjustHealth(-maxHealth*0.0125)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
|
||||
..()
|
||||
adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
|
||||
if(exposed_temperature)
|
||||
adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
|
||||
else
|
||||
adjustFireLoss(5)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/CanPass(atom/movable/mover, turf/target, height = 0)
|
||||
if(istype(mover, /obj/effect/blob))
|
||||
if(istype(mover, /obj/structure/blob))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0)
|
||||
for(var/obj/effect/blob/B in range(1, src))
|
||||
for(var/obj/structure/blob/B in range(1, src))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/handle_inherent_channels(message, message_mode)
|
||||
if(message_mode == MODE_BINARY)
|
||||
blob_chat(message)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
return 1
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -79,17 +82,19 @@
|
||||
desc = "A floating, fragile spore."
|
||||
icon_state = "blobpod"
|
||||
icon_living = "blobpod"
|
||||
health = 40
|
||||
maxHealth = 40
|
||||
health = 30
|
||||
maxHealth = 30
|
||||
verb_say = "psychically pulses"
|
||||
verb_ask = "psychically probes"
|
||||
verb_exclaim = "psychically yells"
|
||||
verb_yell = "psychically screams"
|
||||
melee_damage_lower = 2
|
||||
melee_damage_upper = 4
|
||||
obj_damage = 20
|
||||
environment_smash = 1
|
||||
attacktext = "hits"
|
||||
attack_sound = 'sound/weapons/genhit1.ogg'
|
||||
flying = 1
|
||||
movement_type = FLYING
|
||||
del_on_death = 1
|
||||
deathmessage = "explodes into a cloud of gas!"
|
||||
var/death_cloud_size = 1 //size of cloud produced from a dying spore
|
||||
@@ -97,7 +102,7 @@
|
||||
var/is_zombie = 0
|
||||
gold_core_spawnable = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/New(loc, var/obj/effect/blob/factory/linked_node)
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/New(loc, var/obj/structure/blob/factory/linked_node)
|
||||
if(istype(linked_node))
|
||||
factory = linked_node
|
||||
factory.spores += src
|
||||
@@ -125,10 +130,10 @@
|
||||
desc = "A shambling corpse animated by the blob."
|
||||
melee_damage_lower += 8
|
||||
melee_damage_upper += 11
|
||||
flying = 0
|
||||
movement_type = GROUND
|
||||
death_cloud_size = 0
|
||||
icon = H.icon
|
||||
icon_state = "zombie_s"
|
||||
icon_state = "zombie"
|
||||
H.hair_style = null
|
||||
H.update_hair()
|
||||
human_overlays = H.overlays
|
||||
@@ -168,20 +173,23 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/update_icons()
|
||||
..()
|
||||
if(overmind)
|
||||
add_atom_colour(overmind.blob_reagent_datum.complementary_color, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
if(is_zombie)
|
||||
cut_overlays()
|
||||
overlays = human_overlays
|
||||
var/image/I = image('icons/mob/blob.dmi', icon_state = "blob_head")
|
||||
if(overmind)
|
||||
I.color = overmind.blob_reagent_datum.color
|
||||
I.color = overmind.blob_reagent_datum.complementary_color
|
||||
color = initial(color)//looks better.
|
||||
add_overlay(I)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/weak
|
||||
name = "fragile blob spore"
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
health = 15
|
||||
maxHealth = 15
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
death_cloud_size = 0
|
||||
@@ -199,9 +207,9 @@
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
next_move_modifier = 1.5 //slow-ass attack speed, 3 times higher than how fast the blob can attack
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
obj_damage = 60
|
||||
attacktext = "slams"
|
||||
attack_sound = 'sound/effects/blobattack.ogg'
|
||||
verb_say = "gurgles"
|
||||
@@ -209,7 +217,7 @@
|
||||
verb_exclaim = "roars"
|
||||
verb_yell = "bellows"
|
||||
force_threshold = 10
|
||||
pressure_resistance = 40
|
||||
pressure_resistance = 50
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
see_invisible = SEE_INVISIBLE_MINIMUM
|
||||
see_in_dark = 8
|
||||
@@ -225,26 +233,23 @@
|
||||
if(independent)
|
||||
return // strong independent blobbernaut that don't need no blob
|
||||
var/damagesources = 0
|
||||
if(!(locate(/obj/effect/blob) in range(2, src)))
|
||||
if(!(locate(/obj/structure/blob) in range(2, src)))
|
||||
damagesources++
|
||||
if(!factory)
|
||||
damagesources++
|
||||
if(damagesources)
|
||||
for(var/i in 1 to damagesources)
|
||||
adjustHealth(maxHealth*0.025) //take 2.5% maxhealth as damage when not near the blob or if the naut has no factory, 5% if both
|
||||
var/list/viewing = list()
|
||||
for(var/mob/M in viewers(src))
|
||||
if(M.client)
|
||||
viewing += M.client
|
||||
adjustHealth(maxHealth*0.025) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
|
||||
var/image/I = new('icons/mob/blob.dmi', src, "nautdamage", MOB_LAYER+0.01)
|
||||
I.appearance_flags = RESET_COLOR
|
||||
if(overmind)
|
||||
I.color = overmind.blob_reagent_datum.complementary_color
|
||||
flick_overlay(I, viewing, 8)
|
||||
flick_overlay_view(I, src, 8)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/adjustHealth(amount)
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
update_health_hud()
|
||||
if(updating_health)
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/update_health_hud()
|
||||
if(hud_used)
|
||||
@@ -274,7 +279,7 @@
|
||||
..(gibbed)
|
||||
if(factory)
|
||||
factory.naut = null //remove this naut from its factory
|
||||
factory.maxhealth = initial(factory.maxhealth)
|
||||
factory.max_integrity = initial(factory.max_integrity)
|
||||
flick("blobbernaut_death", src)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/independent
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/obj/effect/blob/core
|
||||
/obj/structure/blob/core
|
||||
name = "blob core"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blank_blob"
|
||||
desc = "A huge, pulsating yellow mass."
|
||||
health = 400
|
||||
maxhealth = 400
|
||||
obj_integrity = 400
|
||||
max_integrity = 400
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 75, acid = 90)
|
||||
explosion_block = 6
|
||||
point_return = -1
|
||||
atmosblock = 1
|
||||
health_regen = 0 //we regen in Life() instead of when pulsed
|
||||
var/core_regen = 2
|
||||
var/overmind_get_delay = 0 //we don't want to constantly try to find an overmind, this var tracks when we'll try to get an overmind again
|
||||
@@ -15,7 +15,7 @@
|
||||
var/point_rate = 2
|
||||
|
||||
|
||||
/obj/effect/blob/core/New(loc, client/new_overmind = null, new_rate = 2, placed = 0)
|
||||
/obj/structure/blob/core/New(loc, client/new_overmind = null, new_rate = 2, placed = 0)
|
||||
blob_cores += src
|
||||
START_PROCESSING(SSobj, src)
|
||||
poi_list |= src
|
||||
@@ -27,10 +27,10 @@
|
||||
point_rate = new_rate
|
||||
..()
|
||||
|
||||
/obj/effect/blob/core/scannerreport()
|
||||
/obj/structure/blob/core/scannerreport()
|
||||
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."
|
||||
|
||||
/obj/effect/blob/core/update_icon()
|
||||
/obj/structure/blob/core/update_icon()
|
||||
cut_overlays()
|
||||
color = null
|
||||
var/image/I = new('icons/mob/blob.dmi', "blob")
|
||||
@@ -40,7 +40,7 @@
|
||||
var/image/C = new('icons/mob/blob.dmi', "blob_core_overlay")
|
||||
add_overlay(C)
|
||||
|
||||
/obj/effect/blob/core/Destroy()
|
||||
/obj/structure/blob/core/Destroy()
|
||||
blob_cores -= src
|
||||
if(overmind)
|
||||
overmind.blob_core = null
|
||||
@@ -49,36 +49,36 @@
|
||||
poi_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/blob/core/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
/obj/effect/blob/core/ex_act(severity, target)
|
||||
/obj/structure/blob/core/ex_act(severity, target)
|
||||
var/damage = 50 - 10 * severity //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
|
||||
take_damage(damage, BRUTE)
|
||||
take_damage(damage, BRUTE, "bomb", 0)
|
||||
|
||||
/obj/effect/blob/core/check_health()
|
||||
..()
|
||||
if(overmind) //we should have an overmind, but...
|
||||
overmind.update_health_hud()
|
||||
/obj/structure/blob/core/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, overmind_reagent_trigger = 1)
|
||||
. = ..()
|
||||
if(obj_integrity > 0)
|
||||
if(overmind) //we should have an overmind, but...
|
||||
overmind.update_health_hud()
|
||||
|
||||
/obj/effect/blob/core/Life()
|
||||
/obj/structure/blob/core/Life()
|
||||
if(qdeleted(src))
|
||||
return
|
||||
if(!overmind)
|
||||
create_overmind()
|
||||
else
|
||||
if(resource_delay <= world.time)
|
||||
resource_delay = world.time + 10 // 1 second
|
||||
overmind.add_points(point_rate)
|
||||
health = min(maxhealth, health+core_regen)
|
||||
obj_integrity = min(max_integrity, obj_integrity+core_regen)
|
||||
if(overmind)
|
||||
overmind.update_health_hud()
|
||||
Pulse_Area(overmind, 12, 4, 3)
|
||||
for(var/obj/effect/blob/normal/B in range(1, src))
|
||||
for(var/obj/structure/blob/normal/B in range(1, src))
|
||||
if(prob(5))
|
||||
B.change_to(/obj/effect/blob/shield/core, overmind)
|
||||
B.change_to(/obj/structure/blob/shield/core, overmind)
|
||||
..()
|
||||
|
||||
|
||||
/obj/effect/blob/core/proc/create_overmind(client/new_overmind, override_delay)
|
||||
/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
|
||||
if(overmind_get_delay > world.time && !override_delay)
|
||||
return
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
var/list/candidates = list()
|
||||
|
||||
if(!new_overmind)
|
||||
candidates = get_candidates(ROLE_BLOB)
|
||||
candidates = pollCandidatesForMob("Do you want to play as a blob overmind?", ROLE_BLOB, null, ROLE_BLOB, 50, src) //we're technically not a mob but behave similarly
|
||||
if(candidates.len)
|
||||
C = pick(candidates)
|
||||
else
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/obj/effect/blob/factory
|
||||
/obj/structure/blob/factory
|
||||
name = "factory blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_factory"
|
||||
desc = "A thick spire of tendrils."
|
||||
health = 200
|
||||
maxhealth = 200
|
||||
obj_integrity = 200
|
||||
max_integrity = 200
|
||||
health_regen = 1
|
||||
point_return = 25
|
||||
var/list/spores = list()
|
||||
@@ -14,12 +14,12 @@
|
||||
var/spore_cooldown = 80 //8 seconds between spores and after spore death
|
||||
|
||||
|
||||
/obj/effect/blob/factory/scannerreport()
|
||||
/obj/structure/blob/factory/scannerreport()
|
||||
if(naut)
|
||||
return "It is currently sustaining a blobbernaut, making it fragile and unable to produce blob spores."
|
||||
return "Will produce a blob spore every few seconds."
|
||||
|
||||
/obj/effect/blob/factory/Destroy()
|
||||
/obj/structure/blob/factory/Destroy()
|
||||
for(var/mob/living/simple_animal/hostile/blob/blobspore/spore in spores)
|
||||
if(spore.factory == src)
|
||||
spore.factory = null
|
||||
@@ -30,7 +30,7 @@
|
||||
spores = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/blob/factory/Be_Pulsed()
|
||||
/obj/structure/blob/factory/Be_Pulsed()
|
||||
. = ..()
|
||||
if(naut)
|
||||
return
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
/obj/effect/blob/node
|
||||
/obj/structure/blob/node
|
||||
name = "blob node"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blank_blob"
|
||||
desc = "A large, pulsating yellow mass."
|
||||
health = 200
|
||||
maxhealth = 200
|
||||
obj_integrity = 200
|
||||
max_integrity = 200
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 65, acid = 90)
|
||||
health_regen = 3
|
||||
point_return = 25
|
||||
atmosblock = 1
|
||||
|
||||
|
||||
/obj/effect/blob/node/New(loc, var/h = 100)
|
||||
/obj/structure/blob/node/New(loc)
|
||||
blob_nodes += src
|
||||
START_PROCESSING(SSobj, src)
|
||||
..(loc, h)
|
||||
..()
|
||||
|
||||
/obj/effect/blob/node/scannerreport()
|
||||
/obj/structure/blob/node/scannerreport()
|
||||
return "Gradually expands and sustains nearby blob spores and blobbernauts."
|
||||
|
||||
/obj/effect/blob/node/update_icon()
|
||||
/obj/structure/blob/node/update_icon()
|
||||
cut_overlays()
|
||||
color = null
|
||||
var/image/I = new('icons/mob/blob.dmi', "blob")
|
||||
if(overmind)
|
||||
I.color = overmind.blob_reagent_datum.color
|
||||
src.add_overlay(I)
|
||||
add_overlay(I)
|
||||
var/image/C = new('icons/mob/blob.dmi', "blob_node_overlay")
|
||||
src.add_overlay(C)
|
||||
add_overlay(C)
|
||||
|
||||
/obj/effect/blob/node/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
/obj/effect/blob/node/Destroy()
|
||||
/obj/structure/blob/node/Destroy()
|
||||
blob_nodes -= src
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/blob/node/Life()
|
||||
/obj/structure/blob/node/Life()
|
||||
Pulse_Area(overmind, 10, 3, 2)
|
||||
color = null
|
||||
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
/obj/effect/blob/resource
|
||||
/obj/structure/blob/resource
|
||||
name = "resource blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_resource"
|
||||
desc = "A thin spire of slightly swaying tendrils."
|
||||
health = 60
|
||||
maxhealth = 60
|
||||
obj_integrity = 60
|
||||
max_integrity = 60
|
||||
point_return = 15
|
||||
var/resource_delay = 0
|
||||
|
||||
/obj/effect/blob/resource/scannerreport()
|
||||
/obj/structure/blob/resource/scannerreport()
|
||||
return "Gradually supplies the blob with resources, increasing the rate of expansion."
|
||||
|
||||
/obj/effect/blob/resource/creation_action()
|
||||
/obj/structure/blob/resource/creation_action()
|
||||
if(overmind)
|
||||
overmind.resource_blobs += src
|
||||
|
||||
/obj/effect/blob/resource/Destroy()
|
||||
/obj/structure/blob/resource/Destroy()
|
||||
if(overmind)
|
||||
overmind.resource_blobs -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/blob/resource/Be_Pulsed()
|
||||
/obj/structure/blob/resource/Be_Pulsed()
|
||||
. = ..()
|
||||
if(resource_delay > world.time)
|
||||
return
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
/obj/effect/blob/shield
|
||||
/obj/structure/blob/shield
|
||||
name = "strong blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_idle"
|
||||
icon_state = "blob_shield"
|
||||
desc = "A solid wall of slightly twitching tendrils."
|
||||
health = 150
|
||||
maxhealth = 150
|
||||
brute_resist = 0.1
|
||||
obj_integrity = 150
|
||||
max_integrity = 150
|
||||
brute_resist = 0.25
|
||||
explosion_block = 3
|
||||
point_return = 4
|
||||
atmosblock = 1
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
|
||||
|
||||
|
||||
/obj/effect/blob/shield/scannerreport()
|
||||
return "Will prevent the spread of atmospheric changes."
|
||||
|
||||
/obj/effect/blob/shield/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
return
|
||||
/obj/structure/blob/shield/scannerreport()
|
||||
if(atmosblock)
|
||||
return "Will prevent the spread of atmospheric changes."
|
||||
return "N/A"
|
||||
|
||||
/obj/effect/blob/shield/core
|
||||
/obj/structure/blob/shield/core
|
||||
point_return = 0
|
||||
|
||||
/obj/structure/blob/shield/update_icon()
|
||||
..()
|
||||
if(obj_integrity <= 75)
|
||||
icon_state = "blob_shield_damaged"
|
||||
name = "weakened strong blob"
|
||||
desc = "A wall of twitching tendrils."
|
||||
atmosblock = 0
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
atmosblock = 1
|
||||
air_update_turf(1)
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
/mob/camera/blob
|
||||
name = "Blob Overmind"
|
||||
real_name = "Blob Overmind"
|
||||
desc = "The overmind. It controls the blob."
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "marker"
|
||||
|
||||
mouse_opacity = 1
|
||||
move_on_shuttle = 1
|
||||
see_in_dark = 8
|
||||
see_invisible = SEE_INVISIBLE_MINIMUM
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
layer = FLY_LAYER
|
||||
|
||||
pass_flags = PASSBLOB
|
||||
faction = list("blob")
|
||||
|
||||
var/obj/effect/blob/core/blob_core = null // The blob overmind's core
|
||||
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
|
||||
var/blob_points = 0
|
||||
var/max_blob_points = 100
|
||||
var/last_attack = 0
|
||||
@@ -26,7 +29,8 @@
|
||||
var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
|
||||
var/autoplace_max_time = 3600 //six minutes, as long as should be needed
|
||||
|
||||
/mob/camera/blob/New(loc, pre_placed = 0, mode_made = 0)
|
||||
/mob/camera/blob/New(loc, pre_placed = 0, mode_made = 0, starting_points = 60)
|
||||
blob_points = starting_points
|
||||
if(pre_placed) //we already have a core!
|
||||
manualplace_min_time = 0
|
||||
autoplace_max_time = 0
|
||||
@@ -42,10 +46,9 @@
|
||||
name = new_name
|
||||
real_name = new_name
|
||||
last_attack = world.time
|
||||
var/list/possible_reagents = list()
|
||||
for(var/type in (subtypesof(/datum/reagent/blob)))
|
||||
possible_reagents.Add(new type)
|
||||
blob_reagent_datum = pick(possible_reagents)
|
||||
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob)))
|
||||
blob_reagent_datum = new BC
|
||||
color = blob_reagent_datum.complementary_color
|
||||
if(blob_core)
|
||||
blob_core.update_icon()
|
||||
|
||||
@@ -69,19 +72,20 @@
|
||||
|
||||
/mob/camera/blob/Destroy()
|
||||
for(var/BL in blobs)
|
||||
var/obj/effect/blob/B = BL
|
||||
if(B.overmind == src)
|
||||
var/obj/structure/blob/B = BL
|
||||
if(B && B.overmind == src)
|
||||
B.overmind = null
|
||||
B.update_icon() //reset anything that was ours
|
||||
for(var/BLO in blob_mobs)
|
||||
var/mob/living/simple_animal/hostile/blob/BM = BLO
|
||||
BM.overmind = null
|
||||
BM.update_icons()
|
||||
if(BM)
|
||||
BM.overmind = null
|
||||
BM.update_icons()
|
||||
overminds -= src
|
||||
if(ghostimage)
|
||||
ghost_darkness_images -= ghostimage
|
||||
qdel(ghostimage)
|
||||
ghostimage = null;
|
||||
ghostimage = null
|
||||
updateallghostimages()
|
||||
return ..()
|
||||
|
||||
@@ -91,18 +95,23 @@
|
||||
src << "<span class='notice'>You are the overmind!</span>"
|
||||
blob_help()
|
||||
update_health_hud()
|
||||
add_points(0)
|
||||
|
||||
/mob/camera/blob/examine(mob/user)
|
||||
..()
|
||||
if(blob_reagent_datum)
|
||||
user << "Its chemical is <font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>."
|
||||
|
||||
/mob/camera/blob/update_health_hud()
|
||||
if(blob_core)
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#e36600'>[round(blob_core.health)]</font></div>"
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#e36600'>[round(blob_core.obj_integrity)]</font></div>"
|
||||
for(var/mob/living/simple_animal/hostile/blob/blobbernaut/B in blob_mobs)
|
||||
if(B.hud_used && B.hud_used.blobpwrdisplay)
|
||||
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.health)]</font></div>"
|
||||
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.obj_integrity)]</font></div>"
|
||||
|
||||
/mob/camera/blob/proc/add_points(points)
|
||||
if(points != 0)
|
||||
blob_points = Clamp(blob_points + points, 0, max_blob_points)
|
||||
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(src.blob_points)]</font></div>"
|
||||
blob_points = Clamp(blob_points + points, 0, max_blob_points)
|
||||
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_points)]</font></div>"
|
||||
|
||||
/mob/camera/blob/say(message)
|
||||
if (!message)
|
||||
@@ -141,15 +150,20 @@
|
||||
/mob/camera/blob/emote(act,m_type=1,message = null)
|
||||
return
|
||||
|
||||
/mob/camera/blob/blob_act(obj/effect/blob/B)
|
||||
/mob/camera/blob/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/mob/camera/blob/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(blob_core)
|
||||
stat(null, "Core Health: [blob_core.health]")
|
||||
stat(null, "Core Health: [blob_core.obj_integrity]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
if(ticker && istype(ticker.mode, /datum/game_mode/blob))
|
||||
var/datum/game_mode/blob/B = ticker.mode
|
||||
stat(null, "Blobs to Win: [blobs_legit.len]/[B.blobwincount]")
|
||||
else
|
||||
stat(null, "Total Blobs: [blobs.len]")
|
||||
if(free_chem_rerolls)
|
||||
stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
|
||||
if(!placed)
|
||||
@@ -159,17 +173,14 @@
|
||||
|
||||
/mob/camera/blob/Move(NewLoc, Dir = 0)
|
||||
if(placed)
|
||||
var/obj/effect/blob/B = locate() in range("3x3", NewLoc)
|
||||
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
|
||||
if(B)
|
||||
loc = NewLoc
|
||||
else
|
||||
return 0
|
||||
else
|
||||
var/area/A = get_area(NewLoc)
|
||||
if(istype(NewLoc, /turf/open/space) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
|
||||
if(isspaceturf(NewLoc) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
|
||||
return 0
|
||||
loc = NewLoc
|
||||
return 1
|
||||
|
||||
/mob/camera/blob/proc/can_attack()
|
||||
return (world.time > (last_attack + CLICK_CD_RANGE))
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
src << "<span class='warning'>This spot is too dense to place a blob core on!</span>"
|
||||
return 0
|
||||
for(var/obj/O in T)
|
||||
if(istype(O, /obj/effect/blob))
|
||||
if(istype(O, /obj/effect/blob/normal))
|
||||
if(istype(O, /obj/structure/blob))
|
||||
if(istype(O, /obj/structure/blob/normal))
|
||||
qdel(O)
|
||||
else
|
||||
src << "<span class='warning'>There is already a blob here!</span>"
|
||||
return 0
|
||||
if(O.density)
|
||||
else if(O.density)
|
||||
src << "<span class='warning'>This spot is too dense to place a blob core on!</span>"
|
||||
return 0
|
||||
if(world.time <= manualplace_min_time && world.time <= autoplace_max_time)
|
||||
@@ -46,7 +46,7 @@
|
||||
if(placed && blob_core)
|
||||
blob_core.forceMove(loc)
|
||||
else
|
||||
var/obj/effect/blob/core/core = new(get_turf(src), null, point_rate, 1)
|
||||
var/obj/structure/blob/core/core = new(get_turf(src), null, point_rate, 1)
|
||||
core.overmind = src
|
||||
blob_core = core
|
||||
core.update_icon()
|
||||
@@ -67,35 +67,36 @@
|
||||
set desc = "Move your camera to a selected node."
|
||||
if(blob_nodes.len)
|
||||
var/list/nodes = list()
|
||||
for(var/i = 1; i <= blob_nodes.len; i++)
|
||||
nodes["Blob Node #[i]"] = blob_nodes[i]
|
||||
for(var/i in 1 to blob_nodes.len)
|
||||
var/obj/structure/blob/node/B = blob_nodes[i]
|
||||
nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blob_reagent_datum.name]":"No Chemical"])"] = B
|
||||
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
|
||||
var/obj/effect/blob/node/chosen_node = nodes[node_name]
|
||||
var/obj/structure/blob/node/chosen_node = nodes[node_name]
|
||||
if(chosen_node)
|
||||
src.loc = chosen_node.loc
|
||||
loc = chosen_node.loc
|
||||
|
||||
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
|
||||
var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
|
||||
if(!B)
|
||||
src << "<span class='warning'>There is no blob here!</span>"
|
||||
return
|
||||
if(!istype(B, /obj/effect/blob/normal))
|
||||
if(!istype(B, /obj/structure/blob/normal))
|
||||
src << "<span class='warning'>Unable to use this blob, find a normal one.</span>"
|
||||
return
|
||||
if(needsNode && nodes_required)
|
||||
if(!(locate(/obj/effect/blob/node) in orange(3, T)) && !(locate(/obj/effect/blob/core) in orange(4, T)))
|
||||
if(!(locate(/obj/structure/blob/node) in orange(3, T)) && !(locate(/obj/structure/blob/core) in orange(4, T)))
|
||||
src << "<span class='warning'>You need to place this blob closer to a node or core!</span>"
|
||||
return //handholdotron 2000
|
||||
if(nearEquals)
|
||||
for(var/obj/effect/blob/L in orange(nearEquals, T))
|
||||
for(var/obj/structure/blob/L in orange(nearEquals, T))
|
||||
if(L.type == blobType)
|
||||
src << "<span class='warning'>There is a similar blob nearby, move more than [nearEquals] tiles away from it!</span>"
|
||||
return
|
||||
if(!can_buy(price))
|
||||
return
|
||||
var/obj/effect/blob/N = B.change_to(blobType, src)
|
||||
var/obj/structure/blob/N = B.change_to(blobType, src)
|
||||
return N
|
||||
|
||||
/mob/camera/blob/verb/toggle_node_req()
|
||||
@@ -110,50 +111,51 @@
|
||||
|
||||
/mob/camera/blob/verb/create_shield_power()
|
||||
set category = "Blob"
|
||||
set name = "Create Shield Blob (10)"
|
||||
set name = "Create Shield Blob (15)"
|
||||
set desc = "Create a shield blob, which will block fire and is hard to kill."
|
||||
create_shield()
|
||||
|
||||
/mob/camera/blob/proc/create_shield(turf/T)
|
||||
createSpecial(10, /obj/effect/blob/shield, 0, 0, T)
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
|
||||
/mob/camera/blob/verb/create_resource()
|
||||
set category = "Blob"
|
||||
set name = "Create Resource Blob (40)"
|
||||
set desc = "Create a resource tower which will generate resources for you."
|
||||
createSpecial(40, /obj/effect/blob/resource, 4, 1)
|
||||
createSpecial(40, /obj/structure/blob/resource, 4, 1)
|
||||
|
||||
/mob/camera/blob/verb/create_node()
|
||||
set category = "Blob"
|
||||
set name = "Create Node Blob (60)"
|
||||
set name = "Create Node Blob (50)"
|
||||
set desc = "Create a node, which will power nearby factory and resource blobs."
|
||||
createSpecial(60, /obj/effect/blob/node, 5, 0)
|
||||
createSpecial(50, /obj/structure/blob/node, 5, 0)
|
||||
|
||||
/mob/camera/blob/verb/create_factory()
|
||||
set category = "Blob"
|
||||
set name = "Create Factory Blob (60)"
|
||||
set desc = "Create a spore tower that will spawn spores to harass your enemies."
|
||||
createSpecial(60, /obj/effect/blob/factory, 7, 1)
|
||||
createSpecial(60, /obj/structure/blob/factory, 7, 1)
|
||||
|
||||
/mob/camera/blob/verb/create_blobbernaut()
|
||||
set category = "Blob"
|
||||
set name = "Create Blobbernaut (40)"
|
||||
set desc = "Create a powerful blobbernaut which is mildly smart and will attack enemies."
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/blob/factory/B = locate(/obj/effect/blob/factory) in T
|
||||
var/obj/structure/blob/factory/B = locate(/obj/structure/blob/factory) in T
|
||||
if(!B)
|
||||
src << "<span class='warning'>You must be on a factory blob!</span>"
|
||||
return
|
||||
if(B.naut) //if it already made a blobbernaut, it can't do it again
|
||||
src << "<span class='warning'>This factory blob is already sustaining a blobbernaut.</span>"
|
||||
return
|
||||
if(B.health < B.maxhealth * 0.5)
|
||||
if(B.obj_integrity < B.max_integrity * 0.5)
|
||||
src << "<span class='warning'>This factory blob is too damaged to sustain a blobbernaut.</span>"
|
||||
return
|
||||
if(!can_buy(40))
|
||||
return
|
||||
B.maxhealth = initial(B.maxhealth) * 0.25 //factories that produced a blobbernaut have much lower health
|
||||
B.check_health()
|
||||
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
|
||||
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
|
||||
B.update_icon()
|
||||
B.visible_message("<span class='warning'><b>The blobbernaut [pick("rips", "tears", "shreds")] its way out of the factory blob!</b></span>")
|
||||
playsound(B.loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
var/mob/living/simple_animal/hostile/blob/blobbernaut/blobber = new /mob/living/simple_animal/hostile/blob/blobbernaut(get_turf(B))
|
||||
@@ -165,11 +167,9 @@
|
||||
blobber.notransform = 1 //stop the naut from moving around
|
||||
blobber.adjustHealth(blobber.maxHealth * 0.5)
|
||||
blob_mobs += blobber
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
|
||||
var/client/C = null
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50, blobber) //players must answer rapidly
|
||||
if(candidates.len) //if we got at least one candidate, they're a blobbernaut now.
|
||||
C = pick(candidates)
|
||||
blobber.notransform = 0
|
||||
var/client/C = pick(candidates)
|
||||
blobber.key = C.key
|
||||
blobber << 'sound/effects/blobattack.ogg'
|
||||
blobber << 'sound/effects/attackblob.ogg'
|
||||
@@ -178,23 +178,33 @@
|
||||
blobber << "You can communicate with other blobbernauts and overminds via <b>:b</b>"
|
||||
blobber << "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!"
|
||||
blobber << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]"
|
||||
else
|
||||
blobber.notransform = 0 //otherwise, just let it move
|
||||
if(blobber)
|
||||
blobber.notransform = 0
|
||||
|
||||
/mob/camera/blob/verb/relocate_core()
|
||||
set category = "Blob"
|
||||
set name = "Relocate Core (80)"
|
||||
set desc = "Swaps the locations of your core and the selected node."
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/blob/node/B = locate(/obj/effect/blob/node) in T
|
||||
var/obj/structure/blob/node/B = locate(/obj/structure/blob/node) in T
|
||||
if(!B)
|
||||
src << "<span class='warning'>You must be on a blob node!</span>"
|
||||
return
|
||||
if(!blob_core)
|
||||
src << "<span class='userdanger'>You have no core and are about to die! May you rest in peace.</span>"
|
||||
return
|
||||
var/area/A = get_area(T)
|
||||
if(isspaceturf(T) || A && !A.blob_allowed)
|
||||
src << "<span class='warning'>You cannot relocate your core here!</span>"
|
||||
return
|
||||
if(!can_buy(80))
|
||||
return
|
||||
var/turf/old_turf = blob_core.loc
|
||||
blob_core.loc = T
|
||||
B.loc = old_turf
|
||||
var/turf/old_turf = get_turf(blob_core)
|
||||
var/olddir = blob_core.dir
|
||||
blob_core.forceMove(T)
|
||||
blob_core.setDir(B.dir)
|
||||
B.forceMove(old_turf)
|
||||
B.setDir(olddir)
|
||||
|
||||
/mob/camera/blob/verb/revert()
|
||||
set category = "Blob"
|
||||
@@ -204,7 +214,7 @@
|
||||
remove_blob(T)
|
||||
|
||||
/mob/camera/blob/proc/remove_blob(turf/T)
|
||||
var/obj/effect/blob/B = locate() in T
|
||||
var/obj/structure/blob/B = locate() in T
|
||||
if(!B)
|
||||
src << "<span class='warning'>There is no blob there!</span>"
|
||||
return
|
||||
@@ -221,21 +231,22 @@
|
||||
|
||||
/mob/camera/blob/verb/expand_blob_power()
|
||||
set category = "Blob"
|
||||
set name = "Expand/Attack Blob (5)"
|
||||
set name = "Expand/Attack Blob (4)"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
|
||||
var/turf/T = get_turf(src)
|
||||
expand_blob(T)
|
||||
|
||||
/mob/camera/blob/proc/expand_blob(turf/T)
|
||||
if(!can_attack())
|
||||
if(world.time < last_attack)
|
||||
return
|
||||
var/obj/effect/blob/OB = locate() in circlerange(T, 1)
|
||||
if(!OB)
|
||||
var/list/possibleblobs = list()
|
||||
for(var/obj/structure/blob/AB in range(T, 1))
|
||||
possibleblobs += AB
|
||||
if(!possibleblobs.len)
|
||||
src << "<span class='warning'>There is no blob adjacent to the target tile!</span>"
|
||||
return
|
||||
if(can_buy(5))
|
||||
if(can_buy(4))
|
||||
var/attacksuccess = FALSE
|
||||
last_attack = world.time
|
||||
for(var/mob/living/L in T)
|
||||
if("blob" in L.faction) //no friendly/dead fire
|
||||
continue
|
||||
@@ -244,16 +255,37 @@
|
||||
var/mob_protection = L.get_permeability_protection()
|
||||
blob_reagent_datum.reaction_mob(L, VAPOR, 25, 1, mob_protection, src)
|
||||
blob_reagent_datum.send_message(L)
|
||||
var/obj/effect/blob/B = locate() in T
|
||||
var/obj/structure/blob/B = locate() in T
|
||||
if(B)
|
||||
if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
|
||||
B.blob_attack_animation(T, src)
|
||||
else
|
||||
src << "<span class='warning'>There is a blob there!</span>"
|
||||
add_points(5) //otherwise, refund all of the cost
|
||||
return
|
||||
add_points(4) //otherwise, refund all of the cost
|
||||
else
|
||||
OB.expand(T, src)
|
||||
var/list/cardinalblobs = list()
|
||||
var/list/diagonalblobs = list()
|
||||
for(var/I in possibleblobs)
|
||||
var/obj/structure/blob/IB = I
|
||||
if(get_dir(IB, T) in cardinal)
|
||||
cardinalblobs += IB
|
||||
else
|
||||
diagonalblobs += IB
|
||||
var/obj/structure/blob/OB
|
||||
if(cardinalblobs.len)
|
||||
OB = pick(cardinalblobs)
|
||||
OB.expand(T, src)
|
||||
else
|
||||
OB = pick(diagonalblobs)
|
||||
if(attacksuccess)
|
||||
OB.blob_attack_animation(T, src)
|
||||
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
|
||||
else
|
||||
add_points(4) //if we're attacking diagonally and didn't hit anything, refund
|
||||
if(attacksuccess)
|
||||
last_attack = world.time + CLICK_CD_MELEE
|
||||
else
|
||||
last_attack = world.time + CLICK_CD_RAPID
|
||||
|
||||
/mob/camera/blob/verb/rally_spores_power()
|
||||
set category = "Blob"
|
||||
@@ -298,8 +330,9 @@
|
||||
/mob/camera/blob/proc/set_chemical()
|
||||
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob) - blob_reagent_datum.type))
|
||||
blob_reagent_datum = new BC
|
||||
color = blob_reagent_datum.complementary_color
|
||||
for(var/BL in blobs)
|
||||
var/obj/effect/blob/B = BL
|
||||
var/obj/structure/blob/B = BL
|
||||
B.update_icon()
|
||||
for(var/BLO in blob_mobs)
|
||||
var/mob/living/simple_animal/hostile/blob/BM = BLO
|
||||
@@ -308,6 +341,8 @@
|
||||
BM << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]"
|
||||
src << "Your reagent is now: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!"
|
||||
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]"
|
||||
if(blob_reagent_datum.effectdesc)
|
||||
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]"
|
||||
|
||||
/mob/camera/blob/verb/blob_help()
|
||||
set category = "Blob"
|
||||
@@ -316,6 +351,8 @@
|
||||
src << "<b>As the overmind, you can control the blob!</b>"
|
||||
src << "Your blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!"
|
||||
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]"
|
||||
if(blob_reagent_datum.effectdesc)
|
||||
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]"
|
||||
src << "<b>You can expand, which will attack people, damage objects, or place a Normal Blob if the tile is clear.</b>"
|
||||
src << "<i>Normal Blobs</i> will expand your reach and can be upgraded into special blobs that perform certain functions."
|
||||
src << "<b>You can upgrade normal blobs into the following types of blob:</b>"
|
||||
@@ -329,4 +366,4 @@
|
||||
src << "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them."
|
||||
if(!placed && autoplace_max_time <= world.time)
|
||||
src << "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.</font></span>"
|
||||
src << "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the button in the bottom right corner of the screen.</font></span>"
|
||||
src << "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.</font></span>"
|
||||
|
||||
+129
-139
@@ -1,5 +1,5 @@
|
||||
//I will need to recode parts of this but I am way too tired atm //I don't know who left this comment but they never did come back
|
||||
/obj/effect/blob
|
||||
/obj/structure/blob
|
||||
name = "blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
luminosity = 1
|
||||
@@ -7,35 +7,37 @@
|
||||
density = 0 //this being 0 causes two bugs, being able to attack blob tiles behind other blobs and being unable to move on blob tiles in no gravity, but turning it to 1 causes the blob mobs to be unable to path through blobs, which is probably worse.
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
explosion_block = 1
|
||||
layer = BELOW_MOB_LAYER
|
||||
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
|
||||
var/health = 30
|
||||
var/maxhealth = 30
|
||||
obj_integrity = 30
|
||||
max_integrity = 30
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 80, acid = 70)
|
||||
var/health_regen = 2 //how much health this blob regens when pulsed
|
||||
var/pulse_timestamp = 0 //we got pulsed/healed when?
|
||||
var/pulse_timestamp = 0 //we got pulsed when?
|
||||
var/heal_timestamp = 0 //we got healed when?
|
||||
var/brute_resist = 0.5 //multiplies brute damage by this
|
||||
var/fire_resist = 1 //multiplies burn damage by this
|
||||
var/atmosblock = 0 //if the blob blocks atmos and heat spread
|
||||
var/mob/camera/blob/overmind
|
||||
|
||||
|
||||
/obj/effect/blob/New(loc)
|
||||
/obj/structure/blob/New(loc)
|
||||
var/area/Ablob = get_area(loc)
|
||||
if(Ablob.blob_allowed) //Is this area allowed for winning as blob?
|
||||
blobs_legit += src
|
||||
blobs += src //Keep track of the blob in the normal list either way
|
||||
src.setDir(pick(1, 2, 4, 8))
|
||||
src.update_icon()
|
||||
..(loc)
|
||||
setDir(pick(cardinal))
|
||||
update_icon()
|
||||
..()
|
||||
ConsumeTile()
|
||||
if(atmosblock)
|
||||
CanAtmosPass = ATMOS_PASS_NO
|
||||
air_update_turf(1)
|
||||
|
||||
/obj/structure/blob/proc/creation_action() //When it's created by the overmind, do this.
|
||||
return
|
||||
|
||||
/obj/effect/blob/proc/creation_action() //When it's created by the overmind, do this.
|
||||
return
|
||||
|
||||
/obj/effect/blob/Destroy()
|
||||
/obj/structure/blob/Destroy()
|
||||
if(atmosblock)
|
||||
atmosblock = 0
|
||||
air_update_turf(1)
|
||||
@@ -44,8 +46,10 @@
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary.
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/blob_act()
|
||||
return
|
||||
|
||||
/obj/effect/blob/Adjacent(var/atom/neighbour)
|
||||
/obj/structure/blob/Adjacent(var/atom/neighbour)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/result = 0
|
||||
@@ -54,89 +58,90 @@
|
||||
for(var/A in dirs)
|
||||
if(direction == text2num(A))
|
||||
for(var/B in dirs[A])
|
||||
var/C = locate(/obj/effect/blob) in get_step(src, B)
|
||||
var/C = locate(/obj/structure/blob) in get_step(src, B)
|
||||
if(C)
|
||||
result++
|
||||
. -= result - 1
|
||||
|
||||
/obj/effect/blob/CanAtmosPass(turf/T)
|
||||
return !atmosblock
|
||||
|
||||
/obj/effect/blob/BlockSuperconductivity()
|
||||
/obj/structure/blob/BlockSuperconductivity()
|
||||
return atmosblock
|
||||
|
||||
/obj/effect/blob/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
/obj/structure/blob/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
if(height==0)
|
||||
return 1
|
||||
if(istype(mover) && mover.checkpass(PASSBLOB))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/effect/blob/CanAStarPass(ID, dir, caller)
|
||||
/obj/structure/blob/CanAStarPass(ID, dir, caller)
|
||||
. = 0
|
||||
if(ismovableatom(caller))
|
||||
var/atom/movable/mover = caller
|
||||
. = . || mover.checkpass(PASSBLOB)
|
||||
|
||||
/obj/effect/blob/proc/check_health(cause)
|
||||
health = Clamp(health, 0, maxhealth)
|
||||
if(health <= 0)
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.death_reaction(src, cause)
|
||||
qdel(src) //we dead now
|
||||
return
|
||||
return
|
||||
|
||||
/obj/effect/blob/update_icon() //Updates color based on overmind color if we have an overmind.
|
||||
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
|
||||
if(overmind)
|
||||
color = overmind.blob_reagent_datum.color
|
||||
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
color = null
|
||||
return
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
|
||||
/obj/effect/blob/process()
|
||||
/obj/structure/blob/process()
|
||||
Life()
|
||||
|
||||
/obj/structure/blob/proc/Life()
|
||||
return
|
||||
|
||||
/obj/effect/blob/proc/Life()
|
||||
return
|
||||
|
||||
/obj/effect/blob/proc/Pulse_Area(pulsing_overmind = overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
|
||||
/obj/structure/blob/proc/Pulse_Area(pulsing_overmind = overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
|
||||
src.Be_Pulsed()
|
||||
if(claim_range)
|
||||
for(var/obj/effect/blob/B in urange(claim_range, src, 1))
|
||||
if(!B.overmind && !istype(B, /obj/effect/blob/core) && prob(30))
|
||||
B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
|
||||
B.update_icon()
|
||||
if(pulse_range)
|
||||
for(var/obj/effect/blob/B in orange(pulse_range, src))
|
||||
var/expanded = FALSE
|
||||
if(prob(70) && expand())
|
||||
expanded = TRUE
|
||||
var/list/blobs_to_affect = list()
|
||||
for(var/obj/structure/blob/B in urange(claim_range, src, 1))
|
||||
blobs_to_affect += B
|
||||
shuffle(blobs_to_affect)
|
||||
for(var/L in blobs_to_affect)
|
||||
var/obj/structure/blob/B = L
|
||||
if(!B.overmind && !istype(B, /obj/structure/blob/core) && prob(30))
|
||||
B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
|
||||
B.update_icon()
|
||||
var/distance = get_dist(get_turf(src), get_turf(B))
|
||||
var/expand_probablity = max(20 - distance * 8, 1)
|
||||
if(B.Adjacent(src))
|
||||
expand_probablity = 20
|
||||
if(distance <= expand_range)
|
||||
var/can_expand = TRUE
|
||||
if(blobs_to_affect.len >= 120 && B.heal_timestamp > world.time)
|
||||
can_expand = FALSE
|
||||
if(can_expand && B.pulse_timestamp <= world.time && prob(expand_probablity))
|
||||
var/obj/structure/blob/newB = B.expand(null, null, !expanded) //expansion falls off with range but is faster near the blob causing the expansion
|
||||
if(newB)
|
||||
if(expanded)
|
||||
qdel(newB)
|
||||
expanded = TRUE
|
||||
if(distance <= pulse_range)
|
||||
B.Be_Pulsed()
|
||||
if(expand_range)
|
||||
if(prob(85))
|
||||
src.expand()
|
||||
for(var/obj/effect/blob/B in orange(expand_range, src))
|
||||
if(prob(max(13 - get_dist(get_turf(src), get_turf(B)) * 4, 1))) //expand falls off with range but is faster near the blob causing the expansion
|
||||
B.expand()
|
||||
return
|
||||
|
||||
/obj/effect/blob/proc/Be_Pulsed()
|
||||
/obj/structure/blob/proc/Be_Pulsed()
|
||||
if(pulse_timestamp <= world.time)
|
||||
ConsumeTile()
|
||||
health = min(maxhealth, health+health_regen)
|
||||
if(heal_timestamp <= world.time)
|
||||
obj_integrity = min(max_integrity, obj_integrity+health_regen)
|
||||
heal_timestamp = world.time + 20
|
||||
update_icon()
|
||||
pulse_timestamp = world.time + 10
|
||||
return 1 //we did it, we were pulsed!
|
||||
return 0 //oh no we failed
|
||||
|
||||
/obj/effect/blob/proc/ConsumeTile()
|
||||
/obj/structure/blob/proc/ConsumeTile()
|
||||
for(var/atom/A in loc)
|
||||
A.blob_act(src)
|
||||
if(istype(loc, /turf/closed/wall))
|
||||
if(iswallturf(loc))
|
||||
loc.blob_act(src) //don't ask how a wall got on top of the core, just eat it
|
||||
|
||||
/obj/effect/blob/proc/blob_attack_animation(atom/A = null, controller) //visually attacks an atom
|
||||
var/obj/effect/overlay/temp/blob/O = PoolOrNew(/obj/effect/overlay/temp/blob, src.loc)
|
||||
/obj/structure/blob/proc/blob_attack_animation(atom/A = null, controller) //visually attacks an atom
|
||||
var/obj/effect/overlay/temp/blob/O = new /obj/effect/overlay/temp/blob(src.loc)
|
||||
O.setDir(dir)
|
||||
if(controller)
|
||||
var/mob/camera/blob/BO = controller
|
||||
O.color = BO.blob_reagent_datum.color
|
||||
@@ -147,14 +152,14 @@
|
||||
O.do_attack_animation(A) //visually attack the whatever
|
||||
return O //just in case you want to do something to the animation.
|
||||
|
||||
/obj/effect/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
|
||||
/obj/structure/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
|
||||
if(!T)
|
||||
var/list/dirs = list(1,2,4,8)
|
||||
for(var/i = 1 to 4)
|
||||
var/dirn = pick(dirs)
|
||||
dirs.Remove(dirn)
|
||||
T = get_step(src, dirn)
|
||||
if(!(locate(/obj/effect/blob) in T))
|
||||
if(!(locate(/obj/structure/blob) in T))
|
||||
break
|
||||
else
|
||||
T = null
|
||||
@@ -162,7 +167,7 @@
|
||||
return 0
|
||||
var/make_blob = TRUE //can we make a blob?
|
||||
|
||||
if(istype(T, /turf/open/space) && !(locate(/obj/structure/lattice) in T) && prob(80))
|
||||
if(isspaceturf(T) && !(locate(/obj/structure/lattice) in T) && prob(80))
|
||||
make_blob = FALSE
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Let's give some feedback that we DID try to spawn in space, since players are used to it
|
||||
|
||||
@@ -176,7 +181,7 @@
|
||||
A.blob_act(src) //also hit everything in the turf
|
||||
|
||||
if(make_blob) //well, can we?
|
||||
var/obj/effect/blob/B = new /obj/effect/blob/normal(src.loc)
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
else
|
||||
@@ -187,7 +192,7 @@
|
||||
B.loc = T
|
||||
B.update_icon()
|
||||
if(B.overmind && expand_reaction)
|
||||
B.overmind.blob_reagent_datum.expand_reaction(src, B, T)
|
||||
B.overmind.blob_reagent_datum.expand_reaction(src, B, T, controller)
|
||||
return B
|
||||
else
|
||||
blob_attack_animation(T, controller)
|
||||
@@ -198,43 +203,30 @@
|
||||
blob_attack_animation(T, controller) //if we can't, animate that we attacked
|
||||
return null
|
||||
|
||||
|
||||
/obj/effect/blob/ex_act(severity, target)
|
||||
..()
|
||||
var/damage = 150 - 20 * severity
|
||||
take_damage(damage, BRUTE)
|
||||
|
||||
/obj/effect/blob/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
..()
|
||||
var/damage = Clamp(0.01 * exposed_temperature, 0, 4)
|
||||
take_damage(damage, BURN)
|
||||
|
||||
/obj/effect/blob/emp_act(severity)
|
||||
/obj/structure/blob/emp_act(severity)
|
||||
if(severity > 0)
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.emp_reaction(src, severity)
|
||||
if(prob(100 - severity * 30))
|
||||
PoolOrNew(/obj/effect/overlay/temp/emp, get_turf(src))
|
||||
new /obj/effect/overlay/temp/emp(get_turf(src))
|
||||
|
||||
/obj/effect/blob/tesla_act(power)
|
||||
/obj/structure/blob/tesla_act(power)
|
||||
..()
|
||||
if(overmind)
|
||||
if(overmind.blob_reagent_datum.tesla_reaction(src, power))
|
||||
take_damage(power/400, BURN)
|
||||
take_damage(power/400, BURN, "energy")
|
||||
else
|
||||
take_damage(power/400, BURN)
|
||||
take_damage(power/400, BURN, "energy")
|
||||
|
||||
/obj/effect/blob/extinguish()
|
||||
/obj/structure/blob/extinguish()
|
||||
..()
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.extinguish_reaction(src)
|
||||
|
||||
/obj/effect/blob/bullet_act(var/obj/item/projectile/Proj)
|
||||
..()
|
||||
take_damage(Proj.damage, Proj.damage_type, Proj)
|
||||
return 0
|
||||
/obj/structure/blob/hulk_damage()
|
||||
return 15
|
||||
|
||||
/obj/effect/blob/attackby(obj/item/I, mob/user, params)
|
||||
/obj/structure/blob/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/device/analyzer))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user << "<b>The analyzer beeps once, then reports:</b><br>"
|
||||
@@ -244,7 +236,7 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/effect/blob/proc/chemeffectreport(mob/user)
|
||||
/obj/structure/blob/proc/chemeffectreport(mob/user)
|
||||
if(overmind)
|
||||
user << "<b>Material: <font color=\"[overmind.blob_reagent_datum.color]\">[overmind.blob_reagent_datum.name]</font><span class='notice'>.</span></b>"
|
||||
user << "<b>Material Effects:</b> <span class='notice'>[overmind.blob_reagent_datum.analyzerdescdamage]</span>"
|
||||
@@ -252,69 +244,67 @@
|
||||
else
|
||||
user << "<b>No Material Detected!</b><br>"
|
||||
|
||||
/obj/effect/blob/proc/typereport(mob/user)
|
||||
/obj/structure/blob/proc/typereport(mob/user)
|
||||
user << "<b>Blob Type:</b> <span class='notice'>[uppertext(initial(name))]</span>"
|
||||
user << "<b>Health:</b> <span class='notice'>[health]/[maxhealth]</span>"
|
||||
user << "<b>Health:</b> <span class='notice'>[obj_integrity]/[max_integrity]</span>"
|
||||
user << "<b>Effects:</b> <span class='notice'>[scannerreport()]</span>"
|
||||
|
||||
/obj/effect/blob/attacked_by(obj/item/I, mob/living/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
visible_message("<span class='danger'>[user] has attacked the [src.name] with \the [I]!</span>")
|
||||
if(I.damtype == BURN)
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
take_damage(I.force, I.damtype, user)
|
||||
|
||||
/obj/effect/blob/attack_animal(mob/living/simple_animal/M)
|
||||
/obj/structure/blob/attack_animal(mob/living/simple_animal/M)
|
||||
if("blob" in M.faction) //sorry, but you can't kill the blob as a blobbernaut
|
||||
return
|
||||
M.changeNext_move(CLICK_CD_MELEE)
|
||||
M.do_attack_animation(src)
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
visible_message("<span class='danger'>\The [M] has attacked the [src.name]!</span>")
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
take_damage(damage, M.melee_damage_type, M)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/effect/blob/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
M.changeNext_move(CLICK_CD_MELEE)
|
||||
M.do_attack_animation(src)
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
visible_message("<span class='danger'>[M] has slashed the [src.name]!</span>")
|
||||
var/damage = rand(15, 30)
|
||||
take_damage(damage, BRUTE, M)
|
||||
return
|
||||
|
||||
/obj/effect/blob/proc/take_damage(damage, damage_type, cause = null, overmind_reagent_trigger = 1)
|
||||
switch(damage_type) //blobs only take brute and burn damage
|
||||
/obj/structure/blob/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
damage = max(damage * brute_resist, 0)
|
||||
if(damage_amount)
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
else
|
||||
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BURN)
|
||||
damage = max(damage * fire_resist, 0)
|
||||
if(CLONE) //this is basically a marker for 'don't modify the damage'
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
|
||||
/obj/structure/blob/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
damage_amount *= brute_resist
|
||||
if(BURN)
|
||||
damage_amount *= fire_resist
|
||||
if(CLONE)
|
||||
else
|
||||
damage = 0
|
||||
if(overmind && overmind_reagent_trigger)
|
||||
damage = overmind.blob_reagent_datum.damage_reaction(src, health, damage, damage_type, cause) //pass the blob, its health before damage, the damage being done, the type of damage being done, and the cause.
|
||||
health -= damage
|
||||
update_icon()
|
||||
check_health(cause)
|
||||
return 0
|
||||
var/armor_protection = 0
|
||||
if(damage_flag)
|
||||
armor_protection = armor[damage_flag]
|
||||
damage_amount = round(damage_amount * (100 - armor_protection)*0.01, 0.1)
|
||||
if(overmind && damage_flag)
|
||||
damage_amount = overmind.blob_reagent_datum.damage_reaction(src, damage_amount, damage_type, damage_flag)
|
||||
return damage_amount
|
||||
|
||||
/obj/effect/blob/proc/change_to(type, controller)
|
||||
/obj/structure/blob/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
if(. && obj_integrity > 0)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/blob/obj_destruction(damage_flag)
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.death_reaction(src, damage_flag)
|
||||
..()
|
||||
|
||||
/obj/structure/blob/proc/change_to(type, controller)
|
||||
if(!ispath(type))
|
||||
throw EXCEPTION("change_to(): invalid type for blob")
|
||||
return
|
||||
var/obj/effect/blob/B = new type(src.loc)
|
||||
var/obj/structure/blob/B = new type(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
B.creation_action()
|
||||
B.update_icon()
|
||||
B.setDir(dir)
|
||||
qdel(src)
|
||||
return B
|
||||
|
||||
/obj/effect/blob/examine(mob/user)
|
||||
/obj/structure/blob/examine(mob/user)
|
||||
..()
|
||||
var/datum/atom_hud/hud_to_check = huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
if(user.research_scanner || (user in hud_to_check.hudusers))
|
||||
@@ -324,31 +314,31 @@
|
||||
else
|
||||
user << "It seems to be made of [get_chem_name()]."
|
||||
|
||||
/obj/effect/blob/proc/scannerreport()
|
||||
/obj/structure/blob/proc/scannerreport()
|
||||
return "A generic blob. Looks like someone forgot to override this proc, adminhelp this."
|
||||
|
||||
/obj/effect/blob/proc/get_chem_name()
|
||||
/obj/structure/blob/proc/get_chem_name()
|
||||
if(overmind)
|
||||
return overmind.blob_reagent_datum.name
|
||||
return "an unknown variant"
|
||||
|
||||
/obj/effect/blob/normal
|
||||
/obj/structure/blob/normal
|
||||
name = "normal blob"
|
||||
icon_state = "blob"
|
||||
luminosity = 0
|
||||
health = 21
|
||||
maxhealth = 25
|
||||
obj_integrity = 21
|
||||
max_integrity = 25
|
||||
health_regen = 1
|
||||
brute_resist = 0.25
|
||||
|
||||
/obj/effect/blob/normal/scannerreport()
|
||||
if(health <= 10)
|
||||
/obj/structure/blob/normal/scannerreport()
|
||||
if(obj_integrity <= 15)
|
||||
return "Currently weak to brute damage."
|
||||
return "N/A"
|
||||
|
||||
/obj/effect/blob/normal/update_icon()
|
||||
/obj/structure/blob/normal/update_icon()
|
||||
..()
|
||||
if(health <= 10)
|
||||
if(obj_integrity <= 15)
|
||||
icon_state = "blob_damaged"
|
||||
name = "fragile blob"
|
||||
desc = "A thin lattice of slightly twitching tendrils."
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
AL["helptext"] = initial(ability.helptext)
|
||||
AL["owned"] = changeling.has_sting(ability)
|
||||
var/req_dna = initial(ability.req_dna)
|
||||
AL["required_absorptions"] = req_dna
|
||||
AL["dna_cost"] = dna_cost
|
||||
AL["can_purchase"] = ((req_dna <= absorbed_dna_count) && (dna_cost <= genetic_points_remaining))
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega")
|
||||
var/list/slots = list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store")
|
||||
var/list/slot2slot = list("head" = slot_head, "wear_mask" = slot_wear_mask, "back" = slot_back, "wear_suit" = slot_wear_suit, "w_uniform" = slot_w_uniform, "shoes" = slot_shoes, "belt" = slot_belt, "gloves" = slot_gloves, "glasses" = slot_glasses, "ears" = slot_ears, "wear_id" = slot_wear_id, "s_store" = slot_s_store)
|
||||
var/list/slot2slot = list("head" = slot_head, "wear_mask" = slot_wear_mask, "neck" = slot_neck, "back" = slot_back, "wear_suit" = slot_wear_suit, "w_uniform" = slot_w_uniform, "shoes" = slot_shoes, "belt" = slot_belt, "gloves" = slot_gloves, "glasses" = slot_glasses, "ears" = slot_ears, "wear_id" = slot_wear_id, "s_store" = slot_s_store)
|
||||
var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mask" = /obj/item/clothing/mask/changeling, "back" = /obj/item/changeling, "wear_suit" = /obj/item/clothing/suit/changeling, "w_uniform" = /obj/item/clothing/under/changeling, "shoes" = /obj/item/clothing/shoes/changeling, "belt" = /obj/item/changeling, "gloves" = /obj/item/clothing/gloves/changeling, "glasses" = /obj/item/clothing/glasses/changeling, "ears" = /obj/item/changeling, "wear_id" = /obj/item/changeling, "s_store" = /obj/item/changeling)
|
||||
|
||||
|
||||
@@ -20,9 +20,13 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
required_players = 10
|
||||
required_enemies = 1
|
||||
recommended_enemies = 1
|
||||
recommended_enemies = 4
|
||||
reroll_friendly = 1
|
||||
|
||||
announce_span = "green"
|
||||
announce_text = "Alien changelings have infiltrated the crew!\n\
|
||||
<span class='green'>Changelings</span>: Accomplish the objectives assigned to you.\n\
|
||||
<span class='notice'>Crew</span>: Root out and eliminate the changeling menace."
|
||||
|
||||
var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time
|
||||
var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
|
||||
@@ -45,10 +49,6 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
|
||||
|
||||
var/changeling_team_objective_type = null //If this is not null, we hand our this objective to all lings
|
||||
|
||||
/datum/game_mode/changeling/announce()
|
||||
world << "<b>The current game mode is - Changeling!</b>"
|
||||
world << "<b>There are alien changelings on the station. Do not let the changelings succeed!</b>"
|
||||
|
||||
/datum/game_mode/changeling/pre_setup()
|
||||
|
||||
if(config.protect_roles_from_antagonist)
|
||||
@@ -70,8 +70,8 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
|
||||
var/datum/mind/changeling = pick(antag_candidates)
|
||||
antag_candidates -= changeling
|
||||
changelings += changeling
|
||||
changeling.special_role = "Changeling"
|
||||
changeling.restricted_roles = restricted_jobs
|
||||
modePlayer += changelings
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
@@ -94,10 +94,10 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
|
||||
for(var/datum/mind/changeling in changelings)
|
||||
log_game("[changeling.key] (ckey) has been selected as a changeling")
|
||||
changeling.current.make_changeling()
|
||||
changeling.special_role = "Changeling"
|
||||
forge_changeling_objectives(changeling)
|
||||
greet_changeling(changeling)
|
||||
ticker.mode.update_changeling_icons_added(changeling)
|
||||
modePlayer += changelings
|
||||
..()
|
||||
|
||||
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
|
||||
@@ -320,6 +320,8 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
|
||||
/datum/changeling/Destroy()
|
||||
qdel(cellular_emporium)
|
||||
cellular_emporium = null
|
||||
qdel(emporium_action)
|
||||
emporium_action = null
|
||||
. = ..()
|
||||
|
||||
/datum/changeling/proc/regenerate(var/mob/living/carbon/the_ling)
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/genetic_damage = 0 // genetic damage caused by using the sting. Nothing to do with cloneloss.
|
||||
var/max_genetic_damage = 100 // hard counter for spamming abilities. Not used/balanced much yet.
|
||||
var/always_keep = 0 // important for abilities like regenerate that screw you if you lose them.
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user)
|
||||
@@ -56,16 +57,16 @@
|
||||
user << "<span class='warning'>We cannot do that in this form!</span>"
|
||||
return 0
|
||||
var/datum/changeling/c = user.mind.changeling
|
||||
if(c.chem_charges<chemical_cost)
|
||||
if(c.chem_charges < chemical_cost)
|
||||
user << "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>"
|
||||
return 0
|
||||
if(c.absorbedcount<req_dna)
|
||||
if(c.absorbedcount < req_dna)
|
||||
user << "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>"
|
||||
return 0
|
||||
if(req_stat < user.stat)
|
||||
user << "<span class='warning'>We are incapacitated.</span>"
|
||||
return 0
|
||||
if((user.status_flags & FAKEDEATH) && name != "Regenerate")
|
||||
if((user.status_flags & FAKEDEATH) && (!ignores_fakedeath))
|
||||
user << "<span class='warning'>We are incapacitated.</span>"
|
||||
return 0
|
||||
if(c.geneticdamage > max_genetic_damage)
|
||||
@@ -75,6 +76,8 @@
|
||||
|
||||
//used in /mob/Stat()
|
||||
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
|
||||
if(!user || qdeleted(user))
|
||||
return 0
|
||||
if(!ishuman(user) && !ismonkey(user))
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
|
||||
@@ -71,14 +71,14 @@
|
||||
for(var/spoken_memory in target.say_log)
|
||||
if(recent_speech.len >= LING_ABSORB_RECENT_SPEECH)
|
||||
break
|
||||
recent_speech += spoken_memory
|
||||
recent_speech[spoken_memory] = target.say_log[spoken_memory]
|
||||
|
||||
if(recent_speech.len)
|
||||
user.mind.store_memory("<B>Some of [target]'s speech patterns, we should study these to better impersonate them!</B>")
|
||||
user << "<span class='boldnotice'>Some of [target]'s speech patterns, we should study these to better impersonate them!</span>"
|
||||
for(var/spoken_memory in recent_speech)
|
||||
user.mind.store_memory("\"[spoken_memory]\"")
|
||||
user << "<span class='notice'>\"[spoken_memory]\"</span>"
|
||||
user.mind.store_memory("\"[recent_speech[spoken_memory]]\"")
|
||||
user << "<span class='notice'>\"[recent_speech[spoken_memory]]\"</span>"
|
||||
user.mind.store_memory("<B>We have no more knowledge of [target]'s speech patterns.</B>")
|
||||
user << "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>"
|
||||
|
||||
@@ -105,58 +105,3 @@
|
||||
//datum/changeling/proc/absorb_dna(mob/living/carbon/T, mob/user)
|
||||
|
||||
//datum/changeling/proc/store_dna(datum/dna/new_dna, mob/user)
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/swap_form
|
||||
name = "Swap Forms"
|
||||
desc = "We force ourselves into the body of another form, pushing their consciousness into the form we left behind."
|
||||
helptext = "We will bring all our abilities with us, but we will lose our old form DNA in exchange for the new one. The process will seem suspicious to any observers."
|
||||
chemical_cost = 40
|
||||
dna_cost = 1
|
||||
req_human = 1 //Monkeys can't grab
|
||||
|
||||
/obj/effect/proc_holder/changeling/swap_form/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
if(!user.pulling || !iscarbon(user.pulling) || user.grab_state < GRAB_AGGRESSIVE)
|
||||
user << "<span class='warning'>We must have an aggressive grab on creature to do this!</span>"
|
||||
return
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
|
||||
user << "<span class='warning'>DNA of [target] is ruined beyond usability!</span>"
|
||||
return
|
||||
if(!ishuman(target))
|
||||
user << "<span class='warning'>[target] is not compatible with this ability.</span>"
|
||||
return
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/swap_form/sting_action(mob/living/carbon/user)
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
var/datum/changeling/changeling = user.mind.changeling
|
||||
|
||||
user << "<span class='notice'>We tighen our grip. We must hold still....</span>"
|
||||
target.do_jitter_animation(500)
|
||||
user.do_jitter_animation(500)
|
||||
|
||||
if(!do_mob(user,target,20))
|
||||
user << "<span class='warning'>The body swap has been interrupted!</span>"
|
||||
return
|
||||
|
||||
target << "<span class='userdanger'>[user] tightens their grip as a painful sensation invades your body.</span>"
|
||||
|
||||
if(!changeling.has_dna(target.dna))
|
||||
changeling.add_new_profile(target, user)
|
||||
changeling.remove_profile(user)
|
||||
|
||||
var/mob/dead/observer/ghost = target.ghostize(0)
|
||||
user.mind.transfer_to(target)
|
||||
if(ghost)
|
||||
ghost.mind.transfer_to(user)
|
||||
if(ghost.key)
|
||||
user.key = ghost.key
|
||||
|
||||
user.Paralyse(2)
|
||||
target << "<span class='warning'>Our genes cry out as we swap our [user] form for [target].</span>"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
helptext = "Grants us thermal vision or flash protection. We will become a lot more vulnerable to flash-based devices while thermal vision is active."
|
||||
chemical_cost = 0
|
||||
dna_cost = 2 //Would be 1 without thermal vision
|
||||
var/active = 0 //Whether or not vision is enhanced
|
||||
active = 0 //Whether or not vision is enhanced
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user)
|
||||
if(!istype(user))
|
||||
@@ -63,15 +63,3 @@
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/thermals/ling/emp_act(severity)
|
||||
return
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/thermals/ling/Insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.weakeyes = 1
|
||||
|
||||
/obj/item/organ/cyberimp/eyes/thermals/ling/Remove(mob/living/carbon/M, special = 0)
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.weakeyes = 0
|
||||
..()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/obj/effect/proc_holder/changeling/biodegrade
|
||||
name = "Biodegrade"
|
||||
desc = "Dissolves restraints or other objects preventing free movement."
|
||||
helptext = "This is obvious to nearby people, and can destroy \
|
||||
standard restraints and closets."
|
||||
helptext = "This is obvious to nearby people, and can destroy standard restraints and closets."
|
||||
chemical_cost = 30 //High cost to prevent spam
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
@@ -12,7 +11,7 @@
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/sting_action(mob/living/carbon/human/user)
|
||||
var/used = FALSE // only one form of shackles removed per use
|
||||
if(!user.restrained() && !istype(user.loc, /obj/structure/closet))
|
||||
if(!user.restrained() && istype(user.loc, /turf/open))
|
||||
user << "<span class='warning'>We are already free!</span>"
|
||||
return 0
|
||||
|
||||
@@ -20,23 +19,19 @@
|
||||
var/obj/O = user.get_item_by_slot(slot_handcuffed)
|
||||
if(!istype(O))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of \
|
||||
acid on \his [O]!</span>", \
|
||||
"<span class='warning'>We vomit acidic ooze onto our \
|
||||
restraints!</span>")
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of acid on [user.p_their()] [O]!</span>", \
|
||||
"<span class='warning'>We vomit acidic ooze onto our restraints!</span>")
|
||||
|
||||
addtimer(src, "dissolve_handcuffs", 30, FALSE, user, O)
|
||||
addtimer(CALLBACK(src, .proc/dissolve_handcuffs, user, O), 30)
|
||||
used = TRUE
|
||||
|
||||
if(user.wear_suit && user.wear_suit.breakouttime && !used)
|
||||
var/obj/item/clothing/suit/S = user.get_item_by_slot(slot_wear_suit)
|
||||
if(!istype(S))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob \
|
||||
of acid across the front of \his [S]!</span>", \
|
||||
"<span class='warning'>We vomit acidic ooze onto our straight \
|
||||
jacket!</span>")
|
||||
addtimer(src, "dissolve_straightjacket", 30, FALSE, user, S)
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of acid across the front of [user.p_their()] [S]!</span>", \
|
||||
"<span class='warning'>We vomit acidic ooze onto our straight jacket!</span>")
|
||||
addtimer(CALLBACK(src, .proc/dissolve_straightjacket, user, S), 30)
|
||||
used = TRUE
|
||||
|
||||
|
||||
@@ -44,11 +39,18 @@
|
||||
var/obj/structure/closet/C = user.loc
|
||||
if(!istype(C))
|
||||
return 0
|
||||
C.visible_message("<span class='warning'>[C]'s hinges suddenly \
|
||||
begin to melt and run!</span>")
|
||||
user << "<span class='warning'>We vomit acidic goop onto the \
|
||||
interior of [C]!</span>"
|
||||
addtimer(src, "open_closet", 70, FALSE, user, C)
|
||||
C.visible_message("<span class='warning'>[C]'s hinges suddenly begin to melt and run!</span>")
|
||||
user << "<span class='warning'>We vomit acidic goop onto the interior of [C]!</span>"
|
||||
addtimer(CALLBACK(src, .proc/open_closet, user, C), 70)
|
||||
used = TRUE
|
||||
|
||||
if(istype(user.loc, /obj/structure/spider/cocoon) && !used)
|
||||
var/obj/structure/spider/cocoon/C = user.loc
|
||||
if(!istype(C))
|
||||
return 0
|
||||
C.visible_message("<span class='warning'>[src] shifts and starts to fall apart!</span>")
|
||||
user << "<span class='warning'>We secrete acidic enzymes from our skin and begin melting our cocoon...</span>"
|
||||
addtimer(CALLBACK(src, .proc/dissolve_cocoon, user, C), 25) //Very short because it's just webs
|
||||
used = TRUE
|
||||
|
||||
if(used)
|
||||
@@ -57,26 +59,24 @@
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_handcuffs(mob/living/carbon/human/user, obj/O)
|
||||
if(O && user.handcuffed == O)
|
||||
user.unEquip(O)
|
||||
O.visible_message("<span class='warning'>[O] dissolves into a \
|
||||
puddle of sizzling goop.</span>")
|
||||
O.loc = get_turf(user)
|
||||
visible_message("<span class='warning'>[O] dissolves into a puddle of sizzling goop.</span>")
|
||||
qdel(O)
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_straightjacket(mob/living/carbon/human/user, obj/S)
|
||||
if(S && user.wear_suit == S)
|
||||
user.unEquip(S)
|
||||
S.visible_message("<span class='warning'>[S] dissolves into a puddle of sizzling goop.</span>")
|
||||
S.loc = get_turf(user)
|
||||
visible_message("<span class='warning'>[S] dissolves into a puddle of sizzling goop.</span>")
|
||||
qdel(S)
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/open_closet(mob/living/carbon/human/user, obj/structure/closet/C)
|
||||
if(C && user.loc == C)
|
||||
C.visible_message("<span class='warning'>[C]'s door breaks and \
|
||||
opens!</span>")
|
||||
C.visible_message("<span class='warning'>[C]'s door breaks and opens!</span>")
|
||||
C.welded = FALSE
|
||||
C.locked = FALSE
|
||||
C.broken = TRUE
|
||||
C.open()
|
||||
user << "<span class='warning'>We open the container restraining \
|
||||
us!</span>"
|
||||
user << "<span class='warning'>We open the container restraining us!</span>"
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_cocoon(mob/living/carbon/human/user, obj/structure/spider/cocoon/C)
|
||||
if(C && user.loc == C)
|
||||
qdel(C) //The cocoon's destroy will move the changeling outside of it without interference
|
||||
user << "<span class='warning'>We dissolve the cocoon!</span>"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/effect/proc_holder/changeling/fakedeath
|
||||
name = "Regenerative Stasis"
|
||||
name = "Reviving Stasis"
|
||||
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
|
||||
chemical_cost = 15
|
||||
dna_cost = 0
|
||||
@@ -18,19 +18,19 @@
|
||||
user.update_stat()
|
||||
user.update_canmove()
|
||||
|
||||
addtimer(src, "ready_to_regenerate", LING_FAKEDEATH_TIME, FALSE, user)
|
||||
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
|
||||
|
||||
feedback_add_details("changeling_powers","FD")
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
|
||||
if(user && user.mind && user.mind.changeling && user.mind.changeling.purchasedpowers)
|
||||
user << "<span class='notice'>We are ready to regenerate.</span>"
|
||||
user << "<span class='notice'>We are ready to revive.</span>"
|
||||
user.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
|
||||
|
||||
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/user)
|
||||
if(user.status_flags & FAKEDEATH)
|
||||
user << "<span class='warning'>We are already regenerating.</span>"
|
||||
user << "<span class='warning'>We are already reviving.</span>"
|
||||
return
|
||||
if(!user.stat) //Confirmation for living changelings if they want to fake their death
|
||||
switch(alert("Are we sure we wish to fake our own death?",,"Yes", "No"))
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/obj/effect/proc_holder/changeling/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "Our flesh rapidly regenerates, healing our wounds, and growing \
|
||||
back missing limbs. Effectiveness decreases with quick, repeated use."
|
||||
desc = "Our flesh rapidly regenerates, healing our burns, bruises and \
|
||||
shortness of breath. Effectiveness decreases with quick, \
|
||||
repeated use."
|
||||
helptext = "Heals a moderate amount of damage over a short period of \
|
||||
time. Can be used while unconscious. Will alert nearby crew if \
|
||||
any limbs are regenerated."
|
||||
chemical_cost = 25
|
||||
time. Can be used while unconscious. Does not regrow limbs or \
|
||||
restore lost blood."
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
req_stat = UNCONSCIOUS
|
||||
var/recent_uses = 1 //The factor of which the healing should be divided by
|
||||
@@ -33,30 +34,25 @@
|
||||
if(recent_uses > 1)
|
||||
user << "<span class='warning'>Our healing's effectiveness is reduced \
|
||||
by quick repeated use!</span>"
|
||||
spawn(0)
|
||||
recent_uses++
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.restore_blood()
|
||||
H.remove_all_embedded_objects()
|
||||
var/list/missing = H.get_missing_limbs()
|
||||
if(missing.len)
|
||||
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
|
||||
H.visible_message("<span class='warning'>[user]'s missing limbs reform, making a loud, grotesque sound!</span>", "<span class='userdanger'>Your limbs regrow, making a loud, crunchy sound and giving you great pain!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
H.emote("scream")
|
||||
H.regenerate_limbs(1)
|
||||
|
||||
// The healing itself - doesn't heal toxin damage
|
||||
// (that's anatomic panacea) and the effectiveness decreases with
|
||||
// each use in a short timespan
|
||||
for(var/i in 1 to healing_ticks)
|
||||
if(user)
|
||||
var/healpertick = -(total_healing / healing_ticks)
|
||||
user.adjustBruteLoss(healpertick / recent_uses, 0)
|
||||
user.adjustOxyLoss(healpertick / recent_uses, 0)
|
||||
user.adjustFireLoss(healpertick / recent_uses, 0)
|
||||
user.updatehealth()
|
||||
sleep(10)
|
||||
recent_uses++
|
||||
INVOKE_ASYNC(src, .proc/fleshmend, user)
|
||||
|
||||
feedback_add_details("changeling_powers","RR")
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/fleshmend/proc/fleshmend(mob/living/user)
|
||||
|
||||
// The healing itself - doesn't heal toxin damage
|
||||
// (that's anatomic panacea) and the effectiveness decreases with
|
||||
// each use in a short timespan
|
||||
for(var/i in 1 to healing_ticks)
|
||||
if(user)
|
||||
var/healpertick = -(total_healing / healing_ticks)
|
||||
user.adjustBruteLoss(healpertick / recent_uses, 0)
|
||||
user.adjustOxyLoss(healpertick / recent_uses, 0)
|
||||
user.adjustFireLoss(healpertick / recent_uses, 0)
|
||||
user.updatehealth()
|
||||
else
|
||||
break
|
||||
sleep(10)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
if(target.mind.changeling)
|
||||
user << "<span class='warning'>The victim is already a part of the hivemind!</span>"
|
||||
return
|
||||
if(user.grab_state <= GRAB_NECK)
|
||||
if(user.grab_state <= GRAB_AGGRESSIVE)
|
||||
user << "<span class='warning'>We must have a tighter grip to link with this creature!</span>"
|
||||
return
|
||||
return changeling.can_absorb_dna(user,target)
|
||||
@@ -46,7 +46,7 @@
|
||||
user << "<span class='notice'>We stealthily stab [target] with a minor proboscis...</span>"
|
||||
target << "<span class='userdanger'>You experience a stabbing sensation and your ears begin to ring...</span>"
|
||||
if(3)
|
||||
user << "<span class='notice'>You mold the [target]'s mind like clay, they can now speak in the hivemind!</span>"
|
||||
user << "<span class='notice'>We mold the [target]'s mind like clay, granting [target.p_them()] the ability to speak in the hivemind!</span>"
|
||||
target << "<span class='userdanger'>A migraine throbs behind your eyes, you hear yourself screaming - but your mouth has not opened!</span>"
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.lingcheck() == 2)
|
||||
|
||||
@@ -17,47 +17,47 @@
|
||||
dna_cost = -1
|
||||
genetic_damage = 1000
|
||||
|
||||
var/silent = FALSE
|
||||
var/weapon_type
|
||||
var/weapon_name_simple
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/try_to_sting(mob/user, mob/target)
|
||||
if(check_weapon(user, user.r_hand, 1))
|
||||
return
|
||||
if(check_weapon(user, user.l_hand, 0))
|
||||
return
|
||||
for(var/obj/item/I in user.held_items)
|
||||
if(check_weapon(user, I))
|
||||
return
|
||||
..(user, target)
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item, right_hand=1)
|
||||
/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item)
|
||||
if(istype(hand_item, weapon_type))
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
qdel(hand_item)
|
||||
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms their [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
if(right_hand)
|
||||
user.update_inv_r_hand()
|
||||
else
|
||||
user.update_inv_l_hand()
|
||||
user.temporarilyRemoveItemFromInventory(hand_item, TRUE) //DROPDEL will delete the item
|
||||
if(!silent)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms their [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
user.update_inv_hands()
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/sting_action(mob/living/user)
|
||||
if(!user.drop_item())
|
||||
user << "<span class='warning'>The [user.get_active_hand()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!</span>"
|
||||
user << "<span class='warning'>The [user.get_active_held_item()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!</span>"
|
||||
return
|
||||
var/limb_regen = 0
|
||||
if(user.hand) //we regen the arm before changing it into the weapon
|
||||
limb_regen = user.regenerate_limb("l_arm", 1)
|
||||
else
|
||||
if(user.active_hand_index % 2 == 0) //we regen the arm before changing it into the weapon
|
||||
limb_regen = user.regenerate_limb("r_arm", 1)
|
||||
else
|
||||
limb_regen = user.regenerate_limb("l_arm", 1)
|
||||
if(limb_regen)
|
||||
user.visible_message("<span class='warning'>[user]'s missing arm reforms, making a loud, grotesque sound!</span>", "<span class='userdanger'>Your arm regrows, making a loud, crunchy sound and giving you great pain!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
user.emote("scream")
|
||||
var/obj/item/W = new weapon_type(user)
|
||||
var/obj/item/W = new weapon_type(user, silent)
|
||||
user.put_in_hands(W)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
if(!silent)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
return W
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/on_refund(mob/user)
|
||||
check_weapon(user, user.r_hand, 1)
|
||||
check_weapon(user, user.l_hand, 0)
|
||||
for(var/obj/item/I in user.held_items)
|
||||
check_weapon(user, I)
|
||||
|
||||
|
||||
//Parent to space suits and armor.
|
||||
/obj/effect/proc_holder/changeling/suit
|
||||
@@ -89,8 +89,8 @@
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type))
|
||||
H.visible_message("<span class='warning'>[H] casts off their [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]</span>", "<span class='italics'>You hear the organic matter ripping and tearing!</span>")
|
||||
H.unEquip(H.head, TRUE) //The qdel on dropped() takes care of it
|
||||
H.unEquip(H.wear_suit, TRUE)
|
||||
H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it
|
||||
H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE)
|
||||
H.update_inv_wear_suit()
|
||||
H.update_inv_head()
|
||||
H.update_hair()
|
||||
@@ -117,8 +117,8 @@
|
||||
user << "\the [user.head] is stuck on your head, you cannot grow a [helmet_name_simple] over it!"
|
||||
return
|
||||
|
||||
user.unEquip(user.head)
|
||||
user.unEquip(user.wear_suit)
|
||||
user.dropItemToGround(user.head)
|
||||
user.dropItemToGround(user.wear_suit)
|
||||
|
||||
user.equip_to_slot_if_possible(new suit_type(user), slot_wear_suit, 1, 1, 1)
|
||||
user.equip_to_slot_if_possible(new helmet_type(user), slot_head, 1, 1, 1)
|
||||
@@ -146,29 +146,34 @@
|
||||
|
||||
/obj/item/weapon/melee/arm_blade
|
||||
name = "arm blade"
|
||||
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter"
|
||||
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "arm_blade"
|
||||
item_state = "arm_blade"
|
||||
flags = ABSTRACT | NODROP | DROPDEL
|
||||
w_class = 5.0
|
||||
flags = ABSTRACT | NODROP
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
force = 25
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
sharpness = IS_SHARP
|
||||
var/can_drop = FALSE
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/New(location,silent)
|
||||
/obj/item/weapon/melee/arm_blade/New(location,silent,synthetic)
|
||||
..()
|
||||
if(ismob(loc) && !silent)
|
||||
loc.visible_message("<span class='warning'>A grotesque blade forms around [loc.name]\'s arm!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a deadly blade.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
if(synthetic)
|
||||
can_drop = TRUE
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/afterattack(atom/target, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(istype(target, /obj/structure/table))
|
||||
var/obj/structure/table/T = target
|
||||
T.table_destroy()
|
||||
T.deconstruct(FALSE)
|
||||
|
||||
else if(istype(target, /obj/machinery/computer))
|
||||
var/obj/machinery/computer/C = target
|
||||
@@ -179,24 +184,189 @@
|
||||
|
||||
if(!A.requiresID() || A.allowed(user)) //This is to prevent stupid shit like hitting a door with an arm blade, the door opening because you have acces and still getting a "the airlocks motors resist our efforts to force it" message.
|
||||
return
|
||||
|
||||
if(A.hasPower())
|
||||
if(A.locked)
|
||||
user << "<span class='warning'>The airlock's bolts prevent it from being forced!</span>"
|
||||
return
|
||||
user << "<span class='warning'>The airlock's motors are resisting, this may take time...</span>"
|
||||
if(do_after(user, 100, target = A))
|
||||
A.open(2)
|
||||
return
|
||||
|
||||
else if(A.locked)
|
||||
if(A.locked)
|
||||
user << "<span class='warning'>The airlock's bolts prevent it from being forced!</span>"
|
||||
return
|
||||
|
||||
if(A.hasPower())
|
||||
user.visible_message("<span class='warning'>[user] jams [src] into the airlock and starts prying it open!</span>", "<span class='warning'>We start forcing the airlock open.</span>", \
|
||||
"<span class='italics'>You hear a metal screeching sound.</span>")
|
||||
playsound(A, 'sound/machines/airlock_alien_prying.ogg', 100, 1)
|
||||
if(!do_after(user, 100, target = A))
|
||||
return
|
||||
//user.say("Heeeeeeeeeerrre's Johnny!")
|
||||
user.visible_message("<span class='warning'>[user] forces the airlock to open with their [src]!</span>", "<span class='warning'>We force the airlock to open.</span>", \
|
||||
"<span class='italics'>You hear a metal screeching sound.</span>")
|
||||
A.open(2)
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/dropped(mob/user)
|
||||
..()
|
||||
if(can_drop)
|
||||
new /obj/item/weapon/melee/synthetic_arm_blade(get_turf(user))
|
||||
qdel(src)
|
||||
|
||||
/***************************************\
|
||||
|***********COMBAT TENTACLES*************|
|
||||
\***************************************/
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/tentacle
|
||||
name = "Tentacle"
|
||||
desc = "We ready a tentacle to grab items or victims with."
|
||||
helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
|
||||
Help will simply drag them closer, Disarm will grab whatever they're holding instead of them, Grab will put the victim in our hold after catching it, \
|
||||
and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form."
|
||||
chemical_cost = 10
|
||||
dna_cost = 2
|
||||
genetic_damage = 5
|
||||
req_human = 1
|
||||
max_genetic_damage = 10
|
||||
weapon_type = /obj/item/weapon/gun/magic/tentacle
|
||||
weapon_name_simple = "tentacle"
|
||||
silent = TRUE
|
||||
|
||||
/obj/item/weapon/gun/magic/tentacle
|
||||
name = "tentacle"
|
||||
desc = "A fleshy tentacle that can stretch out and grab things or people."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tentacle"
|
||||
item_state = null
|
||||
flags = ABSTRACT | NODROP | DROPDEL | NOBLUDGEON
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
ammo_type = /obj/item/ammo_casing/magic/tentacle
|
||||
fire_sound = 'sound/effects/splat.ogg'
|
||||
force = 0
|
||||
max_charges = 1
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
|
||||
/obj/item/weapon/gun/magic/tentacle/New(location,silent)
|
||||
..()
|
||||
if(ismob(loc))
|
||||
if(!silent)
|
||||
loc.visible_message("<span class='warning'>[loc.name]\'s arm starts stretching inhumanly!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a tentacle.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
else
|
||||
//user.say("Heeeeeeeeeerrre's Johnny!")
|
||||
user.visible_message("<span class='warning'>[user] forces the door to open with \his [src]!</span>", "<span class='warning'>We force the door to open.</span>", "<span class='italics'>You hear a metal screeching sound.</span>")
|
||||
A.open(1)
|
||||
loc << "<span class='notice'>You prepare to extend a tentacle.</span>"
|
||||
|
||||
|
||||
/obj/item/weapon/gun/magic/tentacle/shoot_with_empty_chamber(mob/living/user as mob|obj)
|
||||
user << "<span class='warning'>The [name] is not ready yet.<span>"
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle
|
||||
name = "tentacle"
|
||||
desc = "a tentacle."
|
||||
projectile_type = /obj/item/projectile/tentacle
|
||||
caliber = "tentacle"
|
||||
icon_state = "tentacle_end"
|
||||
firing_effect_type = null
|
||||
var/obj/item/weapon/gun/magic/tentacle/gun //the item that shot it
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle/New(obj/item/weapon/gun/magic/tentacle/tentacle_gun)
|
||||
gun = tentacle_gun
|
||||
..()
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle/Destroy(obj/item/weapon/gun/magic/tentacle/tentacle_gun)
|
||||
gun = null
|
||||
..()
|
||||
|
||||
/obj/item/projectile/tentacle
|
||||
name = "tentacle"
|
||||
icon_state = "tentacle_end"
|
||||
pass_flags = PASSTABLE
|
||||
damage = 0
|
||||
damage_type = BRUTE
|
||||
range = 8
|
||||
hitsound = 'sound/weapons/thudswoosh.ogg'
|
||||
var/chain
|
||||
var/obj/item/ammo_casing/magic/tentacle/source //the item that shot it
|
||||
|
||||
/obj/item/projectile/tentacle/New(obj/item/ammo_casing/magic/tentacle/tentacle_casing)
|
||||
source = tentacle_casing
|
||||
..()
|
||||
|
||||
/obj/item/projectile/tentacle/fire(setAngle)
|
||||
if(firer)
|
||||
chain = firer.Beam(src, icon_state = "tentacle", time = INFINITY, maxdistance = INFINITY, beam_sleep_time = 1)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/tentacle/proc/reset_throw(mob/living/carbon/human/H)
|
||||
if(H.in_throw_mode)
|
||||
H.throw_mode_off() //Don't annoy the changeling if he doesn't catch the item
|
||||
|
||||
/obj/item/projectile/tentacle/proc/tentacle_grab(mob/living/carbon/human/H, mob/living/carbon/C)
|
||||
if(H.Adjacent(C))
|
||||
C.grabbedby(H)
|
||||
C.grippedby(H) //instant aggro grab
|
||||
|
||||
/obj/item/projectile/tentacle/proc/tentacle_stab(mob/living/carbon/human/H, mob/living/carbon/C)
|
||||
if(H.Adjacent(C))
|
||||
for(var/obj/item/I in H.held_items)
|
||||
if(I.is_sharp())
|
||||
C.visible_message("<span class='danger'>[H] impales [C] with [H.p_their()] [I.name]!</span>", "<span class='userdanger'>[H] impales you with [H.p_their()] [I.name]!</span>")
|
||||
C.apply_damage(I.force*2, BRUTE, "chest")
|
||||
H.do_item_attack_animation(C, used_item = I)
|
||||
H.add_mob_blood(C)
|
||||
playsound(get_turf(H),I.hitsound,75,1)
|
||||
C.Weaken(4)
|
||||
return
|
||||
|
||||
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0)
|
||||
var/mob/living/carbon/human/H = firer
|
||||
H.dropItemToGround(source.gun, TRUE) //Unequip thus delete the tentacle on hit
|
||||
if(blocked >= 100)
|
||||
return 0
|
||||
if(istype(target, /obj/item))
|
||||
var/obj/item/I = target
|
||||
if(!I.anchored)
|
||||
firer << "<span class='notice'>You pull [I] towards yourself.</span>"
|
||||
H.throw_mode_on()
|
||||
I.throw_at(H, 10, 2)
|
||||
. = 1
|
||||
|
||||
else if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!L.anchored && !L.throwing)//avoid double hits
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
switch(firer.a_intent)
|
||||
if(INTENT_HELP)
|
||||
C.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
C.throw_at(get_step_towards(H,C), 8, 2)
|
||||
return 1
|
||||
|
||||
if(INTENT_DISARM)
|
||||
var/obj/item/I = C.get_active_held_item()
|
||||
if(I)
|
||||
if(C.drop_item())
|
||||
C.visible_message("<span class='danger'>[I] is yanked off of [C]'s hand by [src]!</span>","<span class='userdanger'>A tentacle pulls [I] away from you!</span>")
|
||||
on_hit(I) //grab the item as if you had hit it directly with the tentacle
|
||||
return 1
|
||||
else
|
||||
firer << "<span class='danger'>You can't seem to pry [I] off of [C]'s hands!<span>"
|
||||
return 0
|
||||
else
|
||||
firer << "<span class='danger'>[C] has nothing in hand to disarm!<span>"
|
||||
return 0
|
||||
|
||||
if(INTENT_GRAB)
|
||||
C.visible_message("<span class='danger'>[L] is grabbed by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(src, .proc/tentacle_grab, H, C))
|
||||
return 1
|
||||
|
||||
if(INTENT_HARM)
|
||||
C.visible_message("<span class='danger'>[L] is thrown towards [H] by a tentacle!</span>","<span class='userdanger'>A tentacle grabs you and throws you towards [H]!</span>")
|
||||
C.Weaken(3)
|
||||
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(src, .proc/tentacle_stab, H, C))
|
||||
return 1
|
||||
else
|
||||
L.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
L.throw_at(get_step_towards(H,L), 8, 2)
|
||||
. = 1
|
||||
|
||||
/obj/item/projectile/tentacle/Destroy()
|
||||
qdel(chain)
|
||||
source = null
|
||||
return ..()
|
||||
|
||||
|
||||
/***************************************\
|
||||
@@ -244,7 +414,6 @@
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms his shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
H.unEquip(src, 1)
|
||||
qdel(src)
|
||||
return 0
|
||||
else
|
||||
@@ -278,7 +447,7 @@
|
||||
desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel."
|
||||
flags = STOPSPRESSUREDMAGE | NODROP | DROPDEL //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
|
||||
allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank/internals/emergency_oxygen, /obj/item/weapon/tank/internals/oxygen)
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) //No armor at all.
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90) //No armor at all.
|
||||
|
||||
/obj/item/clothing/suit/space/changeling/New()
|
||||
..()
|
||||
@@ -296,7 +465,7 @@
|
||||
icon_state = "lingspacehelmet"
|
||||
desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front."
|
||||
flags = STOPSPRESSUREDMAGE | NODROP | DROPDEL //Again, no THICKMATERIAL.
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
|
||||
/***************************************\
|
||||
@@ -324,7 +493,7 @@
|
||||
icon_state = "lingarmor"
|
||||
flags = NODROP | DROPDEL
|
||||
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0)
|
||||
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0, fire = 90, acid = 90)
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
cold_protection = 0
|
||||
heat_protection = 0
|
||||
@@ -339,5 +508,5 @@
|
||||
desc = "A tough, hard covering of black chitin with transparent chitin in front."
|
||||
icon_state = "lingarmorhelmet"
|
||||
flags = NODROP | DROPDEL
|
||||
armor = list(melee = 30, bullet = 30, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0)
|
||||
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0, fire = 90, acid = 90)
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
/obj/effect/proc_holder/changeling/panacea/sting_action(mob/user)
|
||||
user << "<span class='notice'>We begin cleansing impurities from our form.</span>"
|
||||
|
||||
var/mob/living/simple_animal/borer/B = user.has_brain_worms()
|
||||
if(B)
|
||||
if(B.controlling)
|
||||
B.detatch()
|
||||
B.leave_victim()
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(0)
|
||||
user << "<span class='notice'>A parasite exits our form.</span>"
|
||||
var/obj/item/organ/body_egg/egg = user.getorgan(/obj/item/organ/body_egg)
|
||||
if(egg)
|
||||
egg.Remove(user)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/effect/proc_holder/changeling/regenerate
|
||||
name = "Regenerate"
|
||||
desc = "Allows us to regrow and restore missing external limbs, and \
|
||||
vital internal organs, as well as removing shrapnel and restoring \
|
||||
blood volume."
|
||||
helptext = "Will alert nearby crew if any external limbs are \
|
||||
regenerated. Can be used while unconscious."
|
||||
chemical_cost = 10
|
||||
dna_cost = 0
|
||||
req_stat = UNCONSCIOUS
|
||||
always_keep = TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/regenerate/sting_action(mob/living/user)
|
||||
user << "<span class='notice'>You feel an itching, both inside and \
|
||||
outside as your tissues knit and reknit.</span>"
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
var/list/missing = C.get_missing_limbs()
|
||||
if(missing.len)
|
||||
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
|
||||
C.visible_message("<span class='warning'>[user]'s missing limbs \
|
||||
reform, making a loud, grotesque sound!</span>",
|
||||
"<span class='userdanger'>Your limbs regrow, making a \
|
||||
loud, crunchy sound and giving you great pain!</span>",
|
||||
"<span class='italics'>You hear organic matter ripping \
|
||||
and tearing!</span>")
|
||||
C.emote("scream")
|
||||
C.regenerate_limbs(1)
|
||||
C.regenerate_organs()
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.restore_blood()
|
||||
H.remove_all_embedded_objects()
|
||||
@@ -1,16 +1,30 @@
|
||||
/obj/effect/proc_holder/changeling/revive
|
||||
name = "Regenerate"
|
||||
name = "Revive"
|
||||
desc = "We regenerate, healing all damage from our form."
|
||||
helptext = "Does not regrow lost organs or a missing head."
|
||||
req_stat = DEAD
|
||||
always_keep = 1
|
||||
always_keep = TRUE
|
||||
ignores_fakedeath = TRUE
|
||||
|
||||
//Revive from revival stasis
|
||||
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
|
||||
user.status_flags &= ~(FAKEDEATH)
|
||||
user.tod = null
|
||||
user.revive(full_heal = 1)
|
||||
user.regenerate_limbs(0, list("head")) //regenerate all limbs except the head
|
||||
user << "<span class='notice'>We have regenerated.</span>"
|
||||
var/list/missing = user.get_missing_limbs()
|
||||
missing -= "head" // headless changelings are funny
|
||||
if(missing.len)
|
||||
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
|
||||
user.visible_message("<span class='warning'>[user]'s missing limbs \
|
||||
reform, making a loud, grotesque sound!</span>",
|
||||
"<span class='userdanger'>Your limbs regrow, making a \
|
||||
loud, crunchy sound and giving you great pain!</span>",
|
||||
"<span class='italics'>You hear organic matter ripping \
|
||||
and tearing!</span>")
|
||||
user.emote("scream")
|
||||
user.regenerate_limbs(0, list("head"))
|
||||
user.regenerate_organs()
|
||||
user << "<span class='notice'>We have revived ourselves.</span>"
|
||||
user.mind.changeling.purchasedpowers -= src
|
||||
feedback_add_details("changeling_powers","CR")
|
||||
return 1
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
for(var/obj/machinery/light/L in range(4, user))
|
||||
L.on = 1
|
||||
L.broken()
|
||||
L.break_light_tube()
|
||||
|
||||
feedback_add_details("changeling_powers","RS")
|
||||
return 1
|
||||
@@ -38,7 +38,7 @@
|
||||
/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(mob/user)
|
||||
for(var/obj/machinery/light/L in range(5, usr))
|
||||
L.on = 1
|
||||
L.broken()
|
||||
L.break_light_tube()
|
||||
empulse(get_turf(user), 2, 5, 1)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
//Makes some spiderlings. Good for setting traps and causing general trouble.
|
||||
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
|
||||
for(var/i=0, i<2, i++)
|
||||
var/obj/effect/spider/spiderling/S = new(user.loc)
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/hunter
|
||||
|
||||
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
|
||||
feedback_add_details("changeling_powers","SI")
|
||||
return 1
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
var/stacks = 0 //Increments every 5 seconds; damage increases over time
|
||||
var/active = 0 //Whether or not you are a hedgehog
|
||||
active = 0 //Whether or not you are a hedgehog
|
||||
|
||||
/obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user)
|
||||
active = !active
|
||||
if(active)
|
||||
user << "<span class='notice'>Our muscles tense and strengthen.</span>"
|
||||
else
|
||||
user.status_flags -= GOTTAGOFAST
|
||||
user.status_flags &= ~GOTTAGOFAST
|
||||
user << "<span class='notice'>Our muscles relax.</span>"
|
||||
if(stacks >= 10)
|
||||
user << "<span class='danger'>We collapse in exhaustion.</span>"
|
||||
@@ -29,11 +29,11 @@
|
||||
active = !active
|
||||
user << "<span class='notice'>Our muscles relax without the energy to strengthen them.</span>"
|
||||
user.Weaken(2)
|
||||
user.status_flags -= GOTTAGOFAST
|
||||
user.status_flags &= ~GOTTAGOFAST
|
||||
break
|
||||
|
||||
stacks++
|
||||
//user.take_organ_damage(stacks * 0.03, 0)
|
||||
//user.take_bodypart_damage(stacks * 0.03, 0)
|
||||
user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
|
||||
|
||||
if(stacks == 11) //Warning message that the stacks are getting too high
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
|
||||
if(!selected_dna)
|
||||
return
|
||||
if(NOTRANSSTING in selected_dna.dna.species.specflags)
|
||||
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
|
||||
user << "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!"
|
||||
return
|
||||
..()
|
||||
@@ -97,7 +97,7 @@
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.status_flags & CANWEAKEN)
|
||||
C.do_jitter_animation(500)
|
||||
C.take_organ_damage(20, 0) //The process is extremely painful
|
||||
C.take_bodypart_damage(20, 0) //The process is extremely painful
|
||||
|
||||
target.visible_message("<span class='danger'>[target] begins to violenty convulse!</span>","<span class='userdanger'>You feel a tiny prick and a begin to uncontrollably convulse!</span>")
|
||||
spawn(10)
|
||||
@@ -138,7 +138,7 @@
|
||||
add_logs(user, target, "stung", object="falso armblade sting")
|
||||
|
||||
if(!target.drop_item())
|
||||
user << "<span class='warning'>The [target.get_active_hand()] is stuck to their hand, you cannot grow a false armblade over it!</span>"
|
||||
user << "<span class='warning'>The [target.get_active_held_item()] is stuck to their hand, you cannot grow a false armblade over it!</span>"
|
||||
return
|
||||
|
||||
if(ismonkey(target))
|
||||
@@ -149,7 +149,7 @@
|
||||
target.visible_message("<span class='warning'>A grotesque blade forms around [target.name]\'s arm!</span>", "<span class='userdanger'>Your arm twists and mutates, transforming into a horrific monstrosity!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
|
||||
addtimer(src, "remove_fake", 600, target, blade)
|
||||
addtimer(CALLBACK(src, .proc/remove_fake, target, blade), 600)
|
||||
|
||||
feedback_add_details("changeling_powers","AS")
|
||||
return 1
|
||||
@@ -162,8 +162,7 @@
|
||||
"<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
qdel(blade)
|
||||
target.update_inv_l_hand()
|
||||
target.update_inv_r_hand()
|
||||
target.update_inv_hands()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna
|
||||
name = "Extract DNA Sting"
|
||||
@@ -225,7 +224,7 @@
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "LSD sting")
|
||||
addtimer(src, "hallucination_time", rand(300,600), target)
|
||||
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(300,600))
|
||||
feedback_add_details("changeling_powers","HS")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
config_tag = "traitorchan"
|
||||
traitors_possible = 3 //hard limit on traitors if scaling is turned off
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
required_players = 0
|
||||
required_players = 25
|
||||
required_enemies = 1 // how many of each type are required
|
||||
recommended_enemies = 3
|
||||
reroll_friendly = 1
|
||||
@@ -45,17 +45,17 @@
|
||||
var/datum/mind/changeling = pick(possible_changelings)
|
||||
antag_candidates -= changeling
|
||||
possible_changelings -= changeling
|
||||
changeling.special_role = "Changeling"
|
||||
changelings += changeling
|
||||
modePlayer += changelings
|
||||
changeling.restricted_roles = restricted_jobs
|
||||
return ..()
|
||||
else
|
||||
return 0
|
||||
|
||||
/datum/game_mode/traitor/changeling/post_setup()
|
||||
modePlayer += changelings
|
||||
for(var/datum/mind/changeling in changelings)
|
||||
changeling.current.make_changeling()
|
||||
changeling.special_role = "Changeling"
|
||||
forge_changeling_objectives(changeling)
|
||||
greet_changeling(changeling)
|
||||
ticker.mode.update_changeling_icons_added(changeling)
|
||||
@@ -69,7 +69,7 @@
|
||||
return
|
||||
if(ticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (config.changeling_scaling_coeff * 4)))
|
||||
if(ROLE_CHANGELING in character.client.prefs.be_special)
|
||||
if(!jobban_isbanned(character.client, ROLE_CHANGELING) && !jobban_isbanned(character.client, "Syndicate"))
|
||||
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
|
||||
if(age_check(character.client))
|
||||
if(!(character.job in restricted_jobs))
|
||||
character.mind.make_Changling()
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
var/global/clockwork_construction_value = 0 //The total value of all structures built by the clockwork cult
|
||||
var/global/clockwork_caches = 0 //How many clockwork caches exist in the world (not each individual)
|
||||
var/global/clockwork_daemons = 0 //How many daemons exist in the world
|
||||
var/global/list/clockwork_generals_invoked = list("nezbere" = FALSE, "sevtug" = FALSE, "nzcrentr" = FALSE, "inath-neq" = FALSE) //How many generals have been recently invoked
|
||||
var/global/list/all_clockwork_objects = list() //All clockwork items, structures, and effects in existence
|
||||
var/global/list/all_clockwork_mobs = list() //All clockwork SERVANTS (not creatures) in existence
|
||||
var/global/list/clockwork_component_cache = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_capacitor" = 0, "replicant_alloy" = 0, "hierophant_ansible" = 0) //The pool of components that caches draw from
|
||||
var/global/ratvar_awakens = FALSE //If Ratvar has been summoned
|
||||
|
||||
#define SCRIPTURE_PERIPHERAL 0 //Scripture tiers; peripherals should never be used
|
||||
#define SCRIPTURE_DRIVER 1
|
||||
#define SCRIPTURE_SCRIPT 2
|
||||
#define SCRIPTURE_APPLICATION 3
|
||||
#define SCRIPTURE_REVENANT 4
|
||||
#define SCRIPTURE_JUDGEMENT 5
|
||||
|
||||
#define SLAB_PRODUCTION_TIME 600 //how long(deciseconds) slabs require to produce a single component; defaults to 1 minute
|
||||
|
||||
#define CACHE_PRODUCTION_TIME 900 //how long(deciseconds) caches require to produce a component; defaults to 1 minute 30 seconds
|
||||
|
||||
#define LOWER_PROB_PER_COMPONENT 10 //how much each component in the cache reduces the weight of getting another of that component type
|
||||
|
||||
#define MAX_COMPONENTS_BEFORE_RAND 10*LOWER_PROB_PER_COMPONENT //the number of each component, times LOWER_PROB_PER_COMPONENT, you need to have before component generation will become random
|
||||
|
||||
#define CLOCKWORK_GENERAL_COOLDOWN 3000 //how long clockwork generals go on cooldown after use, defaults to 5 minutes
|
||||
|
||||
//porselytizer defines
|
||||
#define REPLICANT_ALLOY_UNIT 100 //how much each piece of replicant alloy gives in a clockwork proselytizer
|
||||
|
||||
#define REPLICANT_STANDARD REPLICANT_ALLOY_UNIT*0.2 //how much alloy is in anything else; doesn't matter as much as the following
|
||||
|
||||
#define REPLICANT_FLOOR REPLICANT_ALLOY_UNIT*0.1 //how much alloy is in a clockwork floor, determines the cost of clockwork floor production
|
||||
|
||||
#define REPLICANT_WALL_MINUS_FLOOR REPLICANT_ALLOY_UNIT*0.4 //amount of alloy in a clockwork wall, determines the cost of clockwork wall production
|
||||
|
||||
#define REPLICANT_WALL_TOTAL REPLICANT_WALL_MINUS_FLOOR+REPLICANT_FLOOR //how much alloy is in a clockwork wall and the floor under it
|
||||
|
||||
//Ark defines
|
||||
#define GATEWAY_SUMMON_RATE 2 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 2 per tick
|
||||
|
||||
#define GATEWAY_REEBE_FOUND 100 //when progress is at or above this, the gateway finds reebe and begins drawing power
|
||||
|
||||
#define GATEWAY_RATVAR_COMING 250 //when progress is at or above this, ratvar has entered and is coming through the gateway
|
||||
|
||||
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
CLOCKWORK CULT: Based off of the failed pull requests from vgstation
|
||||
CLOCKWORK CULT: Based off of the failed pull requests from /vg/
|
||||
|
||||
While Nar-Sie is the oldest and most prominent of the elder gods, there are other forces at work in the universe.
|
||||
Ratvar, the Clockwork Justiciar, a homage to Nar-Sie granted sentience by its own power, is one such other force.
|
||||
@@ -8,12 +8,7 @@ Imprisoned within a massive construct known as the Celestial Derelict - or Reebe
|
||||
Ratvar, unable to act in the mortal plane, seeks to return and forms covenants with mortals in order to bolster his influence.
|
||||
Due to his mechanical nature, Ratvar is also capable of influencing silicon-based lifeforms, unlike Nar-Sie, who can only influence natural life.
|
||||
|
||||
This is a team-based gamemode.
|
||||
|
||||
There are three possible objectives the Enlightened - Ratvar's minions - can have:
|
||||
1. Ensure X amount of Enlightened escape the station through the shuttle or otherwise.
|
||||
2. Convert all silicon lifeforms on the station to Ratvar's cause.
|
||||
3. Summon Ratvar via construction of a Gateway.
|
||||
This is a team-based gamemode, and the team's objective is shared by all cultists. It can include summoning Ratvar, escaping on the shuttle, or converting the AI and its cyborgs.
|
||||
|
||||
The clockwork version of an arcane tome is the clockwork slab.
|
||||
While it can perform certain actions, it consumes a resource called components.
|
||||
@@ -21,14 +16,28 @@ Components, which are fallen fragments of Ratvar's body as he rusts in Reebe, ar
|
||||
Game-wise, clockwork slabs will generate components over time, with more powerful components being slower.
|
||||
|
||||
This file's folder contains:
|
||||
__clock_defines.dm: Defined variables
|
||||
clock_cult.dm: Core gamemode files.
|
||||
clock_mobs.dm: Hostile and benign clockwork creatures.
|
||||
clock_items.dm: Items
|
||||
clock_structures.dm: Structures and effects
|
||||
clock_ratvar.dm: The Ark of the Clockwork Justiciar and Ratvar himself. Important enough to have his own file.
|
||||
clock_scripture.dm: Scripture and rites.
|
||||
clock_unsorted.dm: Anything else with no place to be
|
||||
clock_effect.dm: The base clockwork effect code.
|
||||
- Effect files are in game/gamemodes/clock_cult/clock_effects/
|
||||
clock_item.dm: The base clockwork item code.
|
||||
- Item files are in game/gamemodes/clock_cult/clock_items/
|
||||
clock_mobs.dm: Hostile clockwork creatures.
|
||||
clock_scripture.dm: The base Scripture code.
|
||||
- Scripture files are in game/gamemodes/clock_cult/clock_scripture/
|
||||
clock_structure.dm: The base clockwork structure code, including clockwork machines.
|
||||
- Structure files, and Ratvar, are in game/gamemodes/clock_cult/clock_structures/
|
||||
|
||||
game/gamemodes/clock_cult/clock_helpers/ contains several helper procs, including the Ratvarian language.
|
||||
|
||||
clockcult defines are in __DEFINES/clockcult.dm
|
||||
|
||||
Credit where due:
|
||||
1. VelardAmakar from /vg/ for the entire design document, idea, and plan. Thank you very much.
|
||||
2. SkowronX from /vg/ for MANY of the assets
|
||||
3. FuryMcFlurry from /vg/ for many of the assets
|
||||
4. PJB3005 from /vg/ for the failed continuation PR
|
||||
5. Xhuis from /tg/ for coding the basic gamemode as it is today
|
||||
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release
|
||||
|
||||
*/
|
||||
|
||||
@@ -37,109 +46,37 @@ This file's folder contains:
|
||||
///////////
|
||||
|
||||
/proc/is_servant_of_ratvar(mob/living/M)
|
||||
return M && istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.servants_of_ratvar)
|
||||
return istype(M) && M.has_antag_datum(/datum/antagonist/clockcultist, TRUE)
|
||||
|
||||
/proc/is_eligible_servant(mob/living/M)
|
||||
if(!istype(M))
|
||||
return 0
|
||||
if(!M.mind)
|
||||
return 0
|
||||
if(M.mind.enslaved_to)
|
||||
return 0
|
||||
if(iscultist(M) || isconstruct(M))
|
||||
return 0
|
||||
if(isbrain(M))
|
||||
return 1
|
||||
if(ishuman(M))
|
||||
if(isloyal(M) || (M.mind.assigned_role in list("Captain", "Chaplain")))
|
||||
return 0
|
||||
return 1
|
||||
if(isguardian(M))
|
||||
var/mob/living/simple_animal/hostile/guardian/G = M
|
||||
if(is_servant_of_ratvar(G.summoner))
|
||||
return 1 //can't convert it unless the owner is converted
|
||||
if(issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
return 1
|
||||
return 0
|
||||
return FALSE
|
||||
if(M.mind)
|
||||
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
|
||||
return FALSE
|
||||
if(M.mind.enslaved_to && !is_servant_of_ratvar(M.mind.enslaved_to))
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
if(iscultist(M) || isconstruct(M) || M.isloyal() || ispAI(M))
|
||||
return FALSE
|
||||
if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/proc/add_servant_of_ratvar(mob/M, silent = FALSE)
|
||||
if(is_servant_of_ratvar(M) || !ticker || !ticker.mode)
|
||||
return 0
|
||||
if(iscarbon(M))
|
||||
if(!silent)
|
||||
M << "<span class='heavy_brass'>Your mind is racing! Your body feels incredibly light! Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork \
|
||||
Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>"
|
||||
else if(issilicon(M))
|
||||
if(!silent)
|
||||
M << "<span class='heavy_brass'>You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the Clockwork Justiciar, lies in \
|
||||
exile, derelict and forgotten in an unseen realm.</span>"
|
||||
if(!is_eligible_servant(M))
|
||||
if(!M.stat)
|
||||
M.visible_message("<span class='warning'>[M] whirs as it resists an outside influence!</span>")
|
||||
M << "<span class='warning'><b>Corrupt data purged. Resetting cortex chip to factory defaults... complete.</b></span>" //silicons have a custom fail message
|
||||
return 0
|
||||
else if(!silent)
|
||||
M << "<span class='heavy_brass'>Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>"
|
||||
/proc/add_servant_of_ratvar(mob/living/L, silent = FALSE)
|
||||
var/update_type = /datum/antagonist/clockcultist
|
||||
if(silent)
|
||||
update_type = /datum/antagonist/clockcultist/silent
|
||||
. = L.gain_antag_datum(update_type)
|
||||
|
||||
if(!is_eligible_servant(M))
|
||||
if(!silent && !M.stat)
|
||||
M.visible_message("<span class='warning'>[M] seems to resist an unseen force!</span>")
|
||||
M << "<span class='warning'><b>And yet, you somehow push it all away.</b></span>"
|
||||
return 0
|
||||
|
||||
if(!silent)
|
||||
M.visible_message("<span class='heavy_brass'>[M]'s eyes glow a blazing yellow!</span>", \
|
||||
"<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
|
||||
whim without hesitation.</span>")
|
||||
ticker.mode.servants_of_ratvar += M.mind
|
||||
ticker.mode.update_servant_icons_added(M.mind)
|
||||
M.mind.special_role = "Servant of Ratvar"
|
||||
M.languages_spoken |= RATVAR
|
||||
M.languages_understood |= RATVAR
|
||||
all_clockwork_mobs += M
|
||||
M.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
|
||||
if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(isrobot(S))
|
||||
var/mob/living/silicon/robot/R = S
|
||||
R.UnlinkSelf()
|
||||
R.emagged = 1
|
||||
R << "<span class='warning'><b>You have been desynced from your master AI. In addition, your onboard camera is no longer active and your safeties have been disabled.</b></span>"
|
||||
S.laws = new/datum/ai_laws/ratvar
|
||||
S.laws.associate(S)
|
||||
S.update_icons()
|
||||
S.show_laws()
|
||||
if(istype(ticker.mode, /datum/game_mode/clockwork_cult))
|
||||
var/datum/game_mode/clockwork_cult/C = ticker.mode
|
||||
C.present_tasks(M) //Memorize the objectives
|
||||
return 1
|
||||
|
||||
/proc/remove_servant_of_ratvar(mob/living/M, silent = FALSE)
|
||||
if(!is_servant_of_ratvar(M)) //In this way, is_servant_of_ratvar() checks the existence of ticker and minds
|
||||
return 0
|
||||
if(!silent)
|
||||
M.visible_message("<span class='big'>[M] seems to have remembered their true allegiance!</span>", \
|
||||
"<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
|
||||
ticker.mode.servants_of_ratvar -= M.mind
|
||||
ticker.mode.update_servant_icons_removed(M.mind)
|
||||
all_clockwork_mobs -= M
|
||||
M.mind.memory = "" //Not sure if there's a better way to do this
|
||||
M.mind.special_role = null
|
||||
M.languages_spoken &= ~RATVAR
|
||||
M.languages_understood &= ~RATVAR
|
||||
M.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
|
||||
for(var/datum/action/innate/function_call/F in M.actions) //Removes any bound Ratvarian spears
|
||||
qdel(F)
|
||||
if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(isrobot(S))
|
||||
var/mob/living/silicon/robot/R = S
|
||||
R.emagged = initial(R.emagged)
|
||||
R << "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>"
|
||||
S.make_laws()
|
||||
S.update_icons()
|
||||
S.show_laws()
|
||||
return 1
|
||||
/proc/remove_servant_of_ratvar(mob/living/L, silent = FALSE)
|
||||
var/datum/antagonist/clockcultist/clock_datum = L.has_antag_datum(/datum/antagonist/clockcultist, TRUE)
|
||||
if(!clock_datum)
|
||||
return FALSE
|
||||
clock_datum.silent_update = silent
|
||||
clock_datum.on_remove()
|
||||
return TRUE
|
||||
|
||||
///////////////
|
||||
// GAME MODE //
|
||||
@@ -149,7 +86,7 @@ This file's folder contains:
|
||||
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
|
||||
var/required_escapees = 0 //How many servants need to escape, if applicable
|
||||
var/required_silicon_converts = 0 //How many robotic lifeforms need to be converted, if applicable
|
||||
var/clockwork_objective = "gateway" //The objective that the servants must fulfill
|
||||
var/clockwork_objective = CLOCKCULT_GATEWAY //The objective that the servants must fulfill
|
||||
var/clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." //The description of the current objective
|
||||
|
||||
/datum/game_mode/clockwork_cult
|
||||
@@ -157,25 +94,29 @@ This file's folder contains:
|
||||
config_tag = "clockwork_cult"
|
||||
antag_flag = ROLE_SERVANT_OF_RATVAR
|
||||
required_players = 10
|
||||
required_enemies = 2
|
||||
recommended_enemies = 2
|
||||
required_enemies = 3
|
||||
recommended_enemies = 3
|
||||
enemy_minimum_age = 14
|
||||
protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") //Silicons can eventually be converted
|
||||
restricted_jobs = list("Chaplain", "Captain")
|
||||
announce_span = "brass"
|
||||
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
|
||||
<span class='brass'>Servants</span>: Take over the station and summon Ratvar.\n\
|
||||
<span class='notice'>Crew</span>: Stop the servants before they can summon the Clockwork Justiciar."
|
||||
var/servants_to_serve = list()
|
||||
|
||||
/datum/game_mode/clockwork_cult/announce()
|
||||
world << "<b>The game mode is: Clockwork Cult!</b>"
|
||||
world << "<b><span class='brass'>Ratvar</span>, the Clockwork Justiciar, has formed a covenant of Enlightened aboard [station_name()].</b>"
|
||||
world << "<b><span class='brass'>Enlightened</span>: Serve your master so that his influence might grow.</b>"
|
||||
world << "<b><span class='boldannounce'>Crew</span>: Prevent the servants of Ratvar from taking over the station.</b>"
|
||||
var/roundstart_player_count
|
||||
|
||||
/datum/game_mode/clockwork_cult/pre_setup()
|
||||
if(config.protect_roles_from_antagonist)
|
||||
restricted_jobs += protected_jobs
|
||||
if(config.protect_assistant_from_antagonist)
|
||||
restricted_jobs += "Assistant"
|
||||
var/starter_servants = max(1, round(num_players() / 10)) //Guaranteed one cultist - otherwise, about one cultist for every ten players
|
||||
var/starter_servants = 3 //Guaranteed three servants
|
||||
var/number_players = num_players()
|
||||
roundstart_player_count = number_players
|
||||
if(number_players > 30) //plus one servant for every additional 15 players
|
||||
number_players -= 30
|
||||
starter_servants += round(number_players/15)
|
||||
while(starter_servants)
|
||||
var/datum/mind/servant = pick(antag_candidates)
|
||||
servants_to_serve += servant
|
||||
@@ -199,22 +140,21 @@ This file's folder contains:
|
||||
return 1
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/forge_clock_objectives() //Determine what objective that Ratvar's servants will fulfill
|
||||
var/list/possible_objectives = list("escape", "gateway")
|
||||
var/list/possible_objectives = list(CLOCKCULT_ESCAPE, CLOCKCULT_GATEWAY)
|
||||
var/silicons_possible = FALSE
|
||||
for(var/mob/living/silicon/S in living_mob_list)
|
||||
for(var/mob/living/silicon/ai/S in living_mob_list)
|
||||
silicons_possible = TRUE
|
||||
if(silicons_possible)
|
||||
possible_objectives += "silicons"
|
||||
possible_objectives += CLOCKCULT_SILICONS
|
||||
clockwork_objective = pick(possible_objectives)
|
||||
clockwork_objective = "gateway" //TEMPORARY, to be removed before merge
|
||||
switch(clockwork_objective)
|
||||
if("escape")
|
||||
required_escapees = max(1, num_players() / 3) //33% of the player count must be cultists
|
||||
clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()]."
|
||||
if("gateway")
|
||||
if(CLOCKCULT_ESCAPE)
|
||||
required_escapees = round(max(1, roundstart_player_count / 3)) //33% of the player count must be cultists
|
||||
clockwork_explanation = "Ensure that [required_escapees] servants of Ratvar escape from [station_name()]."
|
||||
if(CLOCKCULT_GATEWAY)
|
||||
clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar."
|
||||
if("silicons")
|
||||
clockwork_explanation = "Ensure that all silicon-based lifeforms on [station_name()] are servants of Ratvar by the end of the shift."
|
||||
if(CLOCKCULT_SILICONS)
|
||||
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked."
|
||||
return 1
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/greet_servant(mob/M) //Description of their role
|
||||
@@ -222,27 +162,31 @@ This file's folder contains:
|
||||
return 0
|
||||
var/greeting_text = "<br><b><span class='large_brass'>You are a servant of Ratvar, the Clockwork Justiciar.</span>\n\
|
||||
Rusting eternally in the Celestial Derelict, Ratvar has formed a covenant of mortals, with you as one of its members. As one of the Justiciar's servants, you are to work to the best of your \
|
||||
ability to assist in completion of His agenda. You do not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
|
||||
ability to assist in completion of His agenda. You may not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
|
||||
M << greeting_text
|
||||
return 1
|
||||
|
||||
/datum/game_mode/proc/equip_servant(mob/living/L) //Grants a clockwork slab to the mob, with one of each component
|
||||
if(!L || !istype(L))
|
||||
return 0
|
||||
return FALSE
|
||||
var/obj/item/clockwork/slab/starter/S = new/obj/item/clockwork/slab/starter(null) //start it off in null
|
||||
var/slot = "At your feet"
|
||||
var/list/slots = list("In your left pocket" = slot_l_store, "In your right pocket" = slot_r_store, "In your backpack" = slot_in_backpack, "On your belt" = slot_belt)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.back && istype(H.back, /obj/item/weapon/storage/backpack))
|
||||
var/obj/item/weapon/storage/backpack/B = H.back
|
||||
new/obj/item/clockwork/slab/starter(B)
|
||||
slot = "In your [B.name]"
|
||||
slot = H.equip_in_one_of_slots(S, slots)
|
||||
if(slot == "In your backpack")
|
||||
slot = "In your [H.back.name]"
|
||||
if(slot == "At your feet")
|
||||
new/obj/item/clockwork/slab/starter(get_turf(L))
|
||||
L << "<b>[slot] is a link to the halls of Reebe and your master. You may use it to perform many tasks, but also become oriented with the workings of Ratvar and how to best complete your \
|
||||
tasks. This clockwork slab will be instrumental in your triumph. Remember: you can speak discreetly with your fellow servants by using the <span class='brass'>Hierophant Network</span> action button, \
|
||||
and you can find a concise tutorial by using the slab in-hand and selecting Recollection.</b>"
|
||||
L << "<i>Alternatively, check out the wiki page at </i><b>https://tgstation13.org/wiki/Clockwork_Cult</b><i>, which contains additional information.</i>"
|
||||
return 1
|
||||
if(!S.forceMove(get_turf(L)))
|
||||
qdel(S)
|
||||
if(S && !qdeleted(S))
|
||||
L << "<b>[slot] is a link to the halls of Reebe and your master. You may use it to perform many tasks, but also become oriented with the workings of Ratvar and how to best complete your \
|
||||
tasks. This clockwork slab will be instrumental in your triumph. Remember: you can speak discreetly with your fellow servants by using the <span class='brass'>Hierophant Network</span> action button, \
|
||||
and you can find a concise tutorial by using the slab in-hand and selecting Recollection.</b>"
|
||||
L << "<i>Alternatively, check out the wiki page at </i><b>https://tgstation13.org/wiki/Clockwork_Cult</b><i>, which contains additional information.</i>"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/present_tasks(mob/living/L) //Memorizes and displays the clockwork cult's objective
|
||||
if(!L || !istype(L) || !L.mind)
|
||||
@@ -254,25 +198,35 @@ This file's folder contains:
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
|
||||
switch(clockwork_objective)
|
||||
if("escape")
|
||||
if(CLOCKCULT_ESCAPE)
|
||||
var/surviving_servants = 0
|
||||
for(var/datum/mind/M in servants_of_ratvar)
|
||||
if(M.current && M.current.stat != DEAD && (M.current.onCentcom() || M.current.onSyndieBase()))
|
||||
surviving_servants++
|
||||
if(surviving_servants <= required_escapees)
|
||||
return 1
|
||||
return 0
|
||||
if("silicons")
|
||||
for(var/mob/living/silicon/robot/S in mob_list) //Only check robots and AIs
|
||||
if(!is_servant_of_ratvar(S))
|
||||
return 0
|
||||
for(var/mob/living/silicon/ai/A in mob_list)
|
||||
if(!is_servant_of_ratvar(A))
|
||||
return 0
|
||||
return 1
|
||||
if("gateway")
|
||||
return ratvar_awakens
|
||||
return 0 //This shouldn't ever be reached, but just in case it is
|
||||
clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()].<br><i><b>[surviving_servants]</b> managed to escape!</i>"
|
||||
if(surviving_servants >= required_escapees)
|
||||
ticker.news_report = CULT_ESCAPE
|
||||
return TRUE
|
||||
if(CLOCKCULT_SILICONS)
|
||||
var/total_silicons = 0
|
||||
var/valid_silicons = 0
|
||||
for(var/mob/living/silicon/S in mob_list) //Only check robots and AIs
|
||||
if(isAI(S) || iscyborg(S))
|
||||
total_silicons++
|
||||
if(is_servant_of_ratvar(S) || S.stat == DEAD)
|
||||
valid_silicons++
|
||||
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked.<br>\
|
||||
<i><b>[valid_silicons]/[total_silicons]</b> silicons were killed or converted!"
|
||||
var/list/scripture_states = scripture_unlock_check()
|
||||
if(valid_silicons >= total_silicons && scripture_states[SCRIPTURE_APPLICATION])
|
||||
ticker.news_report = CLOCK_SILICONS
|
||||
return TRUE
|
||||
if(CLOCKCULT_GATEWAY)
|
||||
if(ratvar_awakens)
|
||||
ticker.news_report = CLOCK_SUMMON
|
||||
return TRUE
|
||||
ticker.news_report = CULT_FAILURE
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/clockwork_cult/declare_completion()
|
||||
..()
|
||||
@@ -283,14 +237,31 @@ This file's folder contains:
|
||||
if(istype(ticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
|
||||
var/datum/game_mode/clockwork_cult/C = ticker.mode
|
||||
if(C.check_clockwork_victory())
|
||||
text += "<span class='brass'><b>Ratvar's servants have succeeded in fulfilling His goals!</b></span>"
|
||||
feedback_set_details("round_end_result", "win - servants summoned ratvar")
|
||||
text += "<span class='large_brass'><b>Ratvar's servants have succeeded in fulfilling His goals!</b></span>"
|
||||
feedback_set_details("round_end_result", "win - servants completed their objective ([clockwork_objective])")
|
||||
else
|
||||
text += "<span class='userdanger'>Ratvar's servants have failed!</span>"
|
||||
feedback_set_details("round_end_result", "loss - servants did not summon ratvar")
|
||||
text += "<br><b>The goal of the clockwork cult was:</b> [clockwork_explanation]<br>"
|
||||
var/half_victory = FALSE
|
||||
if(clockwork_objective == CLOCKCULT_GATEWAY)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects
|
||||
if(G)
|
||||
half_victory = TRUE
|
||||
if(half_victory)
|
||||
text += "<span class='large_brass'><b>The crew escaped before Ratvar could rise, but the gateway was successfully constructed!</b></span>"
|
||||
feedback_set_details("round_end_result", "halfwin - round ended before the gateway finished")
|
||||
else
|
||||
text += "<span class='userdanger'>Ratvar's servants have failed!</span>"
|
||||
feedback_set_details("round_end_result", "loss - servants failed their objective ([clockwork_objective])")
|
||||
if(clockwork_gateway_activated && clockwork_objective != CLOCKCULT_GATEWAY)
|
||||
ticker.news_report = CLOCK_PROSELYTIZATION
|
||||
text += "<br><b>The servants' objective was:</b> <br>[clockwork_explanation]"
|
||||
text += "<br>Ratvar's servants had <b>[clockwork_caches]</b> Tinkerer's Caches."
|
||||
text += "<br><b>Construction Value(CV)</b> was: <b>[clockwork_construction_value]</b>"
|
||||
var/list/scripture_states = scripture_unlock_check()
|
||||
for(var/i in scripture_states)
|
||||
if(i != SCRIPTURE_DRIVER)
|
||||
text += "<br><b>[i] scripture</b> was: <b>[scripture_states[i] ? "UN":""]LOCKED</b>"
|
||||
if(servants_of_ratvar.len)
|
||||
text += "<b>Ratvar's servants were:</b>"
|
||||
text += "<br><b>Ratvar's servants were:</b>"
|
||||
for(var/datum/mind/M in servants_of_ratvar)
|
||||
text += printplayer(M)
|
||||
world << text
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//The base clockwork effect. Can have an alternate desc and will show up in the list of clockwork objects.
|
||||
/obj/effect/clockwork
|
||||
name = "meme machine"
|
||||
desc = "Still don't know what it is."
|
||||
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "ratvars_flame"
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
/obj/effect/clockwork/New()
|
||||
..()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/effect/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
@@ -0,0 +1,45 @@
|
||||
//an "overlay" used by clockwork walls and floors to appear normal to mesons.
|
||||
/obj/effect/clockwork/overlay
|
||||
mouse_opacity = 0
|
||||
var/atom/linked
|
||||
|
||||
/obj/effect/clockwork/overlay/examine(mob/user)
|
||||
if(linked)
|
||||
linked.examine(user)
|
||||
|
||||
/obj/effect/clockwork/overlay/ex_act()
|
||||
return FALSE
|
||||
|
||||
/obj/effect/clockwork/overlay/singularity_pull(S, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/overlay/Destroy()
|
||||
if(linked)
|
||||
linked = null
|
||||
. = ..()
|
||||
|
||||
/obj/effect/clockwork/overlay/wall
|
||||
name = "clockwork wall"
|
||||
icon = 'icons/turf/walls/clockwork_wall.dmi'
|
||||
icon_state = "clockwork_wall"
|
||||
canSmoothWith = list(/obj/effect/clockwork/overlay/wall, /obj/structure/falsewall/brass)
|
||||
smooth = SMOOTH_TRUE
|
||||
layer = CLOSED_TURF_LAYER
|
||||
|
||||
/obj/effect/clockwork/overlay/wall/New()
|
||||
..()
|
||||
queue_smooth_neighbors(src)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/queue_smooth, src), 1)
|
||||
|
||||
/obj/effect/clockwork/overlay/wall/Destroy()
|
||||
queue_smooth_neighbors(src)
|
||||
..()
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
/obj/effect/clockwork/overlay/floor
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
icon_state = "clockwork_floor"
|
||||
layer = TURF_LAYER
|
||||
|
||||
/obj/effect/clockwork/overlay/floor/bloodcult //this is used by BLOOD CULT, it shouldn't use such a path...
|
||||
icon_state = "cult"
|
||||
@@ -0,0 +1,371 @@
|
||||
//Sigils: Rune-like markings on the ground with various effects.
|
||||
/obj/effect/clockwork/sigil
|
||||
name = "sigil"
|
||||
desc = "A strange set of markings drawn on the ground."
|
||||
clockwork_desc = "A sigil of some purpose."
|
||||
icon_state = "sigil"
|
||||
layer = LOW_OBJ_LAYER
|
||||
alpha = 50
|
||||
resistance_flags = NONE
|
||||
var/affects_servants = FALSE
|
||||
var/stat_affected = CONSCIOUS
|
||||
var/sigil_name = "Sigil"
|
||||
var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]"
|
||||
|
||||
/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params)
|
||||
if(I.force && !is_servant_of_ratvar(user))
|
||||
user.visible_message("<span class='warning'>[user] scatters [src] with [I]!</span>", "<span class='danger'>You scatter [src] with [I]!</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/attack_hand(mob/user)
|
||||
if(iscarbon(user) && !user.stat && (!is_servant_of_ratvar(user) || (is_servant_of_ratvar(user) && user.a_intent == INTENT_HARM)))
|
||||
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/sigil/ex_act(severity)
|
||||
visible_message("<span class='warning'>[src] scatters into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/clockwork/sigil/Crossed(atom/movable/AM)
|
||||
..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat <= stat_affected)
|
||||
if((!is_servant_of_ratvar(L) || (affects_servants && is_servant_of_ratvar(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L))
|
||||
var/obj/item/I = L.null_rod_check()
|
||||
if(I)
|
||||
L.visible_message("<span class='warning'>[L]'s [I.name] [resist_string], protecting them from [src]'s effects!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] [resist_string], protecting you!</span>")
|
||||
return
|
||||
sigil_effects(L)
|
||||
|
||||
/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L)
|
||||
|
||||
|
||||
//Sigil of Transgression: Stuns the first non-servant to walk on it and flashes all nearby non_servants. Nar-Sian cultists are damaged and knocked down for a longer stun
|
||||
/obj/effect/clockwork/sigil/transgression
|
||||
name = "dull sigil"
|
||||
desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
clockwork_desc = "A sigil that will stun the first non-servant to cross it. Nar-Sie's dogs will be knocked down."
|
||||
icon_state = "sigildull"
|
||||
color = "#FAE48C"
|
||||
sigil_name = "Sigil of Transgression"
|
||||
|
||||
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
|
||||
var/target_flashed = L.flash_act()
|
||||
for(var/mob/living/M in viewers(5, src))
|
||||
if(!is_servant_of_ratvar(M) && M != L)
|
||||
M.flash_act()
|
||||
if(iscultist(L))
|
||||
L << "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>"
|
||||
L.adjustBruteLoss(10)
|
||||
L.Weaken(7)
|
||||
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
|
||||
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
|
||||
L.Stun(5)
|
||||
new /obj/effect/overlay/temp/ratvar/sigil/transgression(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards.
|
||||
/obj/effect/clockwork/sigil/submission
|
||||
name = "ominous sigil"
|
||||
desc = "A luminous golden sigil. Something about it really bothers you."
|
||||
clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for seven seconds."
|
||||
icon_state = "sigilsubmission"
|
||||
color = "#FAE48C"
|
||||
alpha = 125
|
||||
stat_affected = UNCONSCIOUS
|
||||
resist_string = "glows faintly yellow"
|
||||
var/convert_time = 70
|
||||
var/glow_light = 2 //soft light
|
||||
var/glow_falloff = 1
|
||||
var/delete_on_finish = TRUE
|
||||
sigil_name = "Sigil of Submission"
|
||||
var/glow_type
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/New()
|
||||
..()
|
||||
SetLuminosity(glow_light,glow_falloff)
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L)
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
L.visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>", "<span class='sevtug'>You feel something start to invade your mind...</span>")
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#AF0AAF", time = convert_time)
|
||||
var/obj/effect/overlay/temp/ratvar/sigil/glow
|
||||
if(glow_type)
|
||||
glow = new glow_type(get_turf(src))
|
||||
animate(glow, alpha = 255, time = convert_time)
|
||||
var/I = 0
|
||||
while(I < convert_time && get_turf(L) == get_turf(src))
|
||||
I++
|
||||
sleep(1)
|
||||
if(get_turf(L) != get_turf(src))
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
animate(src, color = oldcolor, time = 20)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
return
|
||||
post_channel(L)
|
||||
if(is_eligible_servant(L))
|
||||
L << "<span class='heavy_brass'>\"You belong to me now.\"</span>"
|
||||
add_servant_of_ratvar(L)
|
||||
L.Weaken(3) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
L.Stun(3)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 5
|
||||
var/message = "[sigil_name] in [get_area(src)] <span class='sevtug'>[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]</span>"
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, L)
|
||||
M << "[link] <span class='heavy_brass'>[message] [L.real_name]!</span>"
|
||||
else if(is_servant_of_ratvar(M))
|
||||
if(M == L)
|
||||
M << "<span class='heavy_brass'>[message] you!</span>"
|
||||
else
|
||||
M << "<span class='heavy_brass'>[message] [L.real_name]!</span>"
|
||||
if(delete_on_finish)
|
||||
qdel(src)
|
||||
else
|
||||
animate(src, color = oldcolor, time = 20)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
|
||||
|
||||
//Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards.
|
||||
/obj/effect/clockwork/sigil/submission/accession
|
||||
name = "terrifying sigil"
|
||||
desc = "A luminous brassy sigil. Something about it makes you want to flee."
|
||||
clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for seven seconds. \n\
|
||||
It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets."
|
||||
icon_state = "sigiltransgression"
|
||||
color = "#A97F1B"
|
||||
alpha = 200
|
||||
glow_light = 4 //bright light
|
||||
glow_falloff = 3
|
||||
delete_on_finish = FALSE
|
||||
sigil_name = "Sigil of Accession"
|
||||
glow_type = /obj/effect/overlay/temp/ratvar/sigil/accession
|
||||
resist_string = "glows bright orange"
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L)
|
||||
if(L.isloyal())
|
||||
var/mob/living/carbon/C = L
|
||||
delete_on_finish = TRUE
|
||||
C.visible_message("<span class='warning'>[C] visibly trembles!</span>", \
|
||||
"<span class='sevtug'>[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]</span>")
|
||||
for(var/obj/item/weapon/implant/mindshield/M in C.implants)
|
||||
qdel(M)
|
||||
|
||||
|
||||
//Sigil of Transmission: Stores power for clockwork machinery, serving as a battery.
|
||||
/obj/effect/clockwork/sigil/transmission
|
||||
name = "suspicious sigil"
|
||||
desc = "A glowing orange sigil. The air around it feels staticky."
|
||||
clockwork_desc = "A sigil that will serve as a battery for clockwork structures."
|
||||
icon_state = "sigiltransmission"
|
||||
color = "#EC8A2D"
|
||||
alpha = 50
|
||||
resist_string = "glows faintly"
|
||||
sigil_name = "Sigil of Transmission"
|
||||
affects_servants = TRUE
|
||||
var/power_charge = CLOCKCULT_POWER_UNIT //starts with CLOCKCULT_POWER_UNIT by default
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/ex_act(severity)
|
||||
if(severity == 3)
|
||||
modify_charge(-500)
|
||||
visible_message("<span class='warning'>[src] flares a brilliant orange!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='[power_charge ? "brass":"alloy"]'>It is storing <b>[ratvar_awakens ? "INFINITY":"[power_charge]"]W</b> of power.</span>"
|
||||
if(iscyborg(user))
|
||||
user << "<span class='brass'>You can recharge from the [sigil_name] by crossing it.</span>"
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(iscyborg(L))
|
||||
charge_cyborg(L)
|
||||
else if(power_charge)
|
||||
L << "<span class='brass'>You feel a slight, static shock.</span>"
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/charge_cyborg(mob/living/silicon/robot/cyborg)
|
||||
if(!cyborg_checks(cyborg))
|
||||
return
|
||||
cyborg << "<span class='brass'>You start to charge from the [sigil_name]...</span>"
|
||||
if(!do_after(cyborg, 50, target = src))
|
||||
return
|
||||
if(!cyborg_checks(cyborg))
|
||||
return
|
||||
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), power_charge) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
|
||||
if(modify_charge(giving_power))
|
||||
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
|
||||
var/previous_color = cyborg.color
|
||||
cyborg.color = list("#EC8A2D", "#EC8A2D", "#EC8A2D", rgb(0,0,0))
|
||||
var/datum/status_effect/cyborg_power_regen/CPR = cyborg.apply_status_effect(STATUS_EFFECT_POWERREGEN)
|
||||
CPR.power_to_give = giving_power * 0.1 //ten ticks, restoring 10% each
|
||||
animate(cyborg, color = previous_color, time = 100)
|
||||
addtimer(CALLBACK(cyborg, /atom/proc/update_atom_colour), 100)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/cyborg_checks(mob/living/silicon/robot/cyborg)
|
||||
if(!cyborg.cell)
|
||||
cyborg << "<span class='warning'>You have no cell!</span>"
|
||||
return FALSE
|
||||
if(!power_charge)
|
||||
cyborg << "<span class='warning'>The [sigil_name] has no stored power!</span>"
|
||||
return FALSE
|
||||
if(cyborg.cell.charge > cyborg.cell.maxcharge - MIN_CLOCKCULT_POWER)
|
||||
cyborg << "<span class='warning'>You are already at maximum charge!</span>"
|
||||
return FALSE
|
||||
if(cyborg.has_status_effect(STATUS_EFFECT_POWERREGEN))
|
||||
cyborg << "<span class='warning'>You are already regenerating power!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/New()
|
||||
..()
|
||||
update_glow()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
|
||||
if(ratvar_awakens)
|
||||
update_glow()
|
||||
return TRUE
|
||||
if(power_charge - amount < 0)
|
||||
return FALSE
|
||||
power_charge -= amount
|
||||
update_glow()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/update_glow()
|
||||
if(ratvar_awakens)
|
||||
alpha = 255
|
||||
else
|
||||
alpha = min(initial(alpha) + power_charge*0.02, 255)
|
||||
if(!power_charge)
|
||||
SetLuminosity(0)
|
||||
else
|
||||
SetLuminosity(round(alpha*0.03, 1), round(alpha*0.02, 1))
|
||||
|
||||
|
||||
//Vitality Matrix: Drains health from non-servants to heal or even revive servants.
|
||||
/obj/effect/clockwork/sigil/vitality
|
||||
name = "comforting sigil"
|
||||
desc = "A faint blue sigil. Looking at it makes you feel protected."
|
||||
clockwork_desc = "A sigil that will drain non-Servants that remain on it. Servants that remain on it will be healed if it has any vitality drained."
|
||||
icon_state = "sigilvitality"
|
||||
color = "#123456"
|
||||
alpha = 75
|
||||
affects_servants = TRUE
|
||||
stat_affected = DEAD
|
||||
resist_string = "glows shimmering yellow"
|
||||
sigil_name = "Vitality Matrix"
|
||||
var/static/vitality = 0
|
||||
var/base_revive_cost = 20
|
||||
var/sigil_active = FALSE
|
||||
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
|
||||
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='[vitality ? "inathneq_small":"alloy"]'>It has access to <b>[ratvar_awakens ? "INFINITE":"[vitality]"]</b> units of vitality.</span>"
|
||||
if(ratvar_awakens)
|
||||
user << "<span class='inathneq_small'>It can revive Servants at no cost!</span>"
|
||||
else
|
||||
user << "<span class='inathneq_small'>It can revive Servants at a cost of <b>[base_revive_cost]</b> vitality plus vitality equal to the non-oxygen damage they have, in addition to being destroyed in the process.</span>"
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
|
||||
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
|
||||
return
|
||||
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
|
||||
animate(src, alpha = 255, time = 10)
|
||||
addtimer(CALLBACK(src, .proc/update_alpha), 10)
|
||||
sleep(10)
|
||||
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
|
||||
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (ratvar_awakens || vitality))) && get_turf(L) == get_turf(src))
|
||||
sigil_active = TRUE
|
||||
if(animation_number >= 4)
|
||||
new /obj/effect/overlay/temp/ratvar/sigil/vitality(get_turf(src))
|
||||
animation_number = 0
|
||||
animation_number++
|
||||
if(!is_servant_of_ratvar(L))
|
||||
var/vitality_drained = 0
|
||||
if(L.stat == DEAD)
|
||||
vitality_drained = L.maxHealth
|
||||
var/obj/effect/overlay/temp/ratvar/sigil/vitality/V = new /obj/effect/overlay/temp/ratvar/sigil/vitality(get_turf(src))
|
||||
animate(V, alpha = 0, transform = matrix()*2, time = 8)
|
||||
playsound(L, 'sound/magic/WandODeath.ogg', 50, 1)
|
||||
L.visible_message("<span class='warning'>[L] collapses in on [L.p_them()]self as [src] flares bright blue!</span>")
|
||||
L << "<span class='inathneq_large'>\"[text2ratvar("Your life will not be wasted.")]\"</span>"
|
||||
for(var/obj/item/W in L)
|
||||
if(!L.dropItemToGround(W))
|
||||
qdel(W)
|
||||
L.dust()
|
||||
else
|
||||
if(!ratvar_awakens && L.stat == CONSCIOUS)
|
||||
vitality_drained = L.adjustToxLoss(1)
|
||||
else
|
||||
vitality_drained = L.adjustToxLoss(1.5)
|
||||
if(vitality_drained)
|
||||
vitality += vitality_drained
|
||||
else
|
||||
break
|
||||
else
|
||||
if(L.stat == DEAD)
|
||||
var/revival_cost = base_revive_cost + L.getCloneLoss() + L.getToxLoss() + L.getFireLoss() + L.getBruteLoss() //ignores oxygen damage
|
||||
if(ratvar_awakens)
|
||||
revival_cost = 0
|
||||
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
|
||||
if(vitality >= revival_cost && (ghost || (L.mind && L.mind.active)))
|
||||
if(ghost)
|
||||
ghost.reenter_corpse()
|
||||
L.revive(1, 1)
|
||||
var/obj/effect/overlay/temp/ratvar/sigil/vitality/V = new /obj/effect/overlay/temp/ratvar/sigil/vitality(get_turf(src))
|
||||
animate(V, alpha = 0, transform = matrix()*2, time = 8)
|
||||
playsound(L, 'sound/magic/Staff_Healing.ogg', 50, 1)
|
||||
L.visible_message("<span class='warning'>[L] suddenly gets back up, [ratvar_awakens ? "[L.p_their()] body dripping blue ichor":"even as [src] scatters into blue sparks around [L.p_them()]"]!</span>", \
|
||||
"<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
|
||||
vitality -= revival_cost
|
||||
if(!ratvar_awakens)
|
||||
qdel(src)
|
||||
break
|
||||
var/vitality_for_cycle = 3
|
||||
if(!ratvar_awakens)
|
||||
if(L.stat == CONSCIOUS)
|
||||
vitality_for_cycle = 2
|
||||
vitality_for_cycle = min(vitality, vitality_for_cycle)
|
||||
var/vitality_used = L.heal_ordered_damage(vitality_for_cycle, damage_heal_order)
|
||||
|
||||
if(!vitality_used)
|
||||
break
|
||||
|
||||
if(!ratvar_awakens)
|
||||
vitality -= vitality_used
|
||||
|
||||
sleep(2)
|
||||
|
||||
if(sigil_active)
|
||||
animation_number = initial(animation_number)
|
||||
sigil_active = FALSE
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
if(sigil_active || alpha == 255)
|
||||
animate(src, alpha = initial(alpha), time = 10)
|
||||
addtimer(CALLBACK(src, .proc/update_alpha), 10)
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/proc/update_alpha()
|
||||
if(sigil_active)
|
||||
alpha = 255
|
||||
else
|
||||
alpha = initial(alpha)
|
||||
@@ -0,0 +1,57 @@
|
||||
//massive markers for Revenant and Judgement scripture.
|
||||
/obj/effect/clockwork/general_marker
|
||||
name = "general marker"
|
||||
desc = "Some big guy. For you."
|
||||
clockwork_desc = "One of Ratvar's generals."
|
||||
alpha = 200
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
|
||||
/obj/effect/clockwork/general_marker/New()
|
||||
..()
|
||||
animate(src, alpha = 0, time = 10)
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/obj/effect/clockwork/general_marker/inathneq
|
||||
name = "Inath-neq, the Resonant Cogwheel"
|
||||
desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring."
|
||||
clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \
|
||||
their prowess. After a lost battle with Nar-Sian cultists, Inath-neq was struck down and stated in her dying breath, \
|
||||
\"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-neq an eternal body and \
|
||||
merged her soul with those of the Cogs slain with her on the battlefield."
|
||||
icon = 'icons/effects/187x381.dmi'
|
||||
icon_state = "inath-neq"
|
||||
pixel_x = -77
|
||||
pixel_y = -174
|
||||
|
||||
/obj/effect/clockwork/general_marker/nezbere
|
||||
name = "Nezbere, the Brass Eidolon"
|
||||
desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you."
|
||||
clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain, and his loyalty to Ratvar knows no bounds. \
|
||||
It is said that Ratvar once asked him to destroy the plans for a weapon Nezbere had made that could have harmed him and Nezbere responded by not only destroying the plans, \
|
||||
but by taking his own life so that the device could never be replicated. Nezbere's zealotry is unmatched."
|
||||
icon = 'icons/effects/340x428.dmi'
|
||||
icon_state = "nezbere"
|
||||
pixel_x = -154
|
||||
pixel_y = -198
|
||||
|
||||
/obj/effect/clockwork/general_marker/sevtug
|
||||
name = "Sevtug, the Formless Pariah"
|
||||
desc = "A sinister cloud of purple energy. Looking at it gives you a headache."
|
||||
clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies. Sevtug serves Ratvar loyally out of a hope that one day, he will \
|
||||
be able to use a moment of weakness in the Justicar to usurp him, but such a day will never come. And so, he serves with dedication, if not necessarily any sort of decorum, never aware he is \
|
||||
the one being made a fool of."
|
||||
icon = 'icons/effects/211x247.dmi'
|
||||
icon_state = "sevtug"
|
||||
pixel_x = -89
|
||||
pixel_y = -107
|
||||
|
||||
/obj/effect/clockwork/general_marker/nzcrentr
|
||||
name = "Nzcrentr, the Eternal Thunderbolt"
|
||||
desc = "A terrifying spiked construct crackling with limitless energy."
|
||||
clockwork_desc = "One of Ratvar's four generals. Before becoming one of Ratvar's generals, Nzcrentr sook out any and all sentient life to slaughter it for sport. \
|
||||
Nzcrentr was coerced by Ratvar into entering a shell constructed by Nezbere, ostensibly made to grant Nzcrentr more power. In reality, the shell was made to trap and control it. \
|
||||
Nzcrentr now serves loyally, though even one of Nezbere's finest creations was not enough to totally eliminate its will."
|
||||
icon = 'icons/effects/254x361.dmi'
|
||||
icon_state = "nzcrentr"
|
||||
pixel_x = -111
|
||||
pixel_y = -164
|
||||
@@ -0,0 +1,200 @@
|
||||
//Spatial gateway: A usually one-way rift to another location.
|
||||
/obj/effect/clockwork/spatial_gateway
|
||||
name = "spatial gateway"
|
||||
desc = "A gently thrumming tear in reality."
|
||||
clockwork_desc = "A gateway in reality."
|
||||
icon_state = "spatial_gateway"
|
||||
density = 1
|
||||
luminosity = 2
|
||||
var/sender = TRUE //If this gateway is made for sending, not receiving
|
||||
var/both_ways = FALSE
|
||||
var/lifetime = 25 //How many deciseconds this portal will last
|
||||
var/uses = 1 //How many objects or mobs can go through the portal
|
||||
var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one
|
||||
var/timerid
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/New()
|
||||
..()
|
||||
addtimer(CALLBACK(src, .proc/check_setup), 1)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Destroy()
|
||||
deltimer(timerid)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/check_setup()
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return
|
||||
if(both_ways)
|
||||
clockwork_desc = "A gateway in reality. It can both send and receive objects."
|
||||
else
|
||||
clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects."
|
||||
timerid = QDEL_IN(src, lifetime)
|
||||
|
||||
//set up a gateway with another gateway
|
||||
/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way)
|
||||
if(!gatewayB || !set_duration || !uses)
|
||||
return FALSE
|
||||
linked_gateway = gatewayB
|
||||
gatewayB.linked_gateway = src
|
||||
if(two_way)
|
||||
both_ways = TRUE
|
||||
gatewayB.both_ways = TRUE
|
||||
else
|
||||
sender = TRUE
|
||||
gatewayB.sender = FALSE
|
||||
gatewayB.density = FALSE
|
||||
lifetime = set_duration
|
||||
gatewayB.lifetime = set_duration
|
||||
uses = set_uses
|
||||
gatewayB.uses = set_uses
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='brass'>It has [uses] uses remaining.</span>"
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attack_ghost(mob/user)
|
||||
if(linked_gateway)
|
||||
user.forceMove(get_turf(linked_gateway))
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user)
|
||||
if(!uses)
|
||||
return FALSE
|
||||
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
|
||||
var/mob/living/L = user.pulling
|
||||
if(L.buckled || L.anchored || L.has_buckled_mobs())
|
||||
return FALSE
|
||||
user.visible_message("<span class='warning'>[user] shoves [L] into [src]!</span>", "<span class='danger'>You shove [L] into [src]!</span>")
|
||||
user.stop_pulling()
|
||||
pass_through_gateway(L)
|
||||
return TRUE
|
||||
if(!user.canUseTopic(src))
|
||||
return FALSE
|
||||
user.visible_message("<span class='warning'>[user] climbs through [src]!</span>", "<span class='danger'>You brace yourself and step through [src]...</span>")
|
||||
pass_through_gateway(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/weapon/nullrod))
|
||||
user.visible_message("<span class='warning'>[user] dispels [src] with [I]!</span>", "<span class='danger'>You close [src] with [I]!</span>")
|
||||
qdel(linked_gateway)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/clockwork/slab))
|
||||
user << "<span class='heavy_brass'>\"I don't think you want to drop your slab into that.\"\n\"If you really want to, try throwing it.\"</span>"
|
||||
return TRUE
|
||||
if(user.drop_item() && uses)
|
||||
user.visible_message("<span class='warning'>[user] drops [I] into [src]!</span>", "<span class='danger'>You drop [I] into [src]!</span>")
|
||||
pass_through_gateway(I, TRUE)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/ex_act(severity)
|
||||
if(severity == 1 && uses)
|
||||
uses = 0
|
||||
visible_message("<span class='warning'>[src] is disrupted!</span>")
|
||||
animate(src, alpha = 0, transform = matrix()*2, time = 10)
|
||||
deltimer(timerid)
|
||||
timerid = QDEL_IN(src, 10)
|
||||
linked_gateway.uses = 0
|
||||
linked_gateway.visible_message("<span class='warning'>[linked_gateway] is disrupted!</span>")
|
||||
animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10)
|
||||
deltimer(linked_gateway.timerid)
|
||||
linked_gateway.timerid = QDEL_IN(linked_gateway, 10)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Bumped(atom/A)
|
||||
..()
|
||||
if(isliving(A) || istype(A, /obj/item))
|
||||
pass_through_gateway(A)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A, no_cost)
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
if(!sender)
|
||||
visible_message("<span class='warning'>[A] bounces off of [src]!</span>")
|
||||
return FALSE
|
||||
if(!uses)
|
||||
return FALSE
|
||||
if(isliving(A))
|
||||
var/mob/living/user = A
|
||||
user << "<span class='warning'><b>You pass through [src] and appear elsewhere!</b></span>"
|
||||
linked_gateway.visible_message("<span class='warning'>A shape appears in [linked_gateway] before emerging!</span>")
|
||||
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
transform = matrix() * 1.5
|
||||
animate(src, transform = matrix() / 1.5, time = 10)
|
||||
linked_gateway.transform = matrix() * 1.5
|
||||
animate(linked_gateway, transform = matrix() / 1.5, time = 10)
|
||||
A.forceMove(get_turf(linked_gateway))
|
||||
if(!no_cost)
|
||||
uses = max(0, uses - 1)
|
||||
linked_gateway.uses = max(0, linked_gateway.uses - 1)
|
||||
addtimer(CALLBACK(src, .proc/check_uses), 10)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/check_uses()
|
||||
if(!uses)
|
||||
qdel(src)
|
||||
qdel(linked_gateway)
|
||||
|
||||
//This proc creates and sets up a gateway from invoker input.
|
||||
/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way)
|
||||
var/list/possible_targets = list()
|
||||
var/list/teleportnames = list()
|
||||
|
||||
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects)
|
||||
if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX) && O.anchored) //don't list obelisks that we're next to
|
||||
var/area/A = get_area(O)
|
||||
var/locname = initial(A.name)
|
||||
possible_targets[avoid_assoc_duplicate_keys("[locname] [O.name]", teleportnames)] = O
|
||||
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons
|
||||
possible_targets[avoid_assoc_duplicate_keys("[L.name] ([L.real_name])", teleportnames)] = L
|
||||
|
||||
if(!possible_targets.len)
|
||||
invoker << "<span class='warning'>There are no other eligible targets for a Spatial Gateway!</span>"
|
||||
return FALSE
|
||||
var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets
|
||||
var/atom/movable/target = possible_targets[input_target_key]
|
||||
if(!src || !input_target_key || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !is_servant_of_ratvar(invoker) || (istype(src, /obj/item) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal())
|
||||
return FALSE //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail
|
||||
if(!target) //if we have no target, but did have a key, let them retry
|
||||
invoker << "<span class='warning'>That target no longer exists!</span>"
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
invoker << "<span class='warning'>That target is no longer a Servant!</span>"
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
if(L.stat != CONSCIOUS)
|
||||
invoker << "<span class='warning'>That Servant is no longer conscious!</span>"
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/istargetobelisk = istype(target, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
|
||||
var/issrcobelisk = istype(src, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
|
||||
if(issrcobelisk && !anchored)
|
||||
invoker << "<span class='warning'>[src] is no longer secured!</span>"
|
||||
return FALSE
|
||||
if(istargetobelisk)
|
||||
if(!target.anchored)
|
||||
invoker << "<span class='warning'>That [target.name] is no longer secured!</span>"
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/CO = target
|
||||
var/efficiency = CO.get_efficiency_mod()
|
||||
gateway_uses = round(gateway_uses * (2 * efficiency), 1)
|
||||
time_duration = round(time_duration * (2 * efficiency), 1)
|
||||
invoker.visible_message("<span class='warning'>The air in front of [invoker] ripples before suddenly tearing open!</span>", \
|
||||
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
|
||||
var/obj/effect/clockwork/spatial_gateway/S1 = new(issrcobelisk ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
|
||||
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
|
||||
|
||||
//Set up the portals now that they've spawned
|
||||
S1.setup_gateway(S2, time_duration, gateway_uses, two_way)
|
||||
S2.visible_message("<span class='warning'>The air in front of [target] ripples before suddenly tearing open!</span>")
|
||||
return TRUE
|
||||
@@ -0,0 +1,55 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user)
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, 250)
|
||||
cell.use(.) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
visible_message("<span class='warning'>The [name]'s screen blurs with static.</span>")
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user)
|
||||
if(charge)
|
||||
. = min(charge, 250)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
icon_state = "[initial(icon_state)]-o"
|
||||
var/datum/effect_system/spark_spread/spks = new(get_turf(src))
|
||||
spks.set_up(10, 0, get_turf(src))
|
||||
spks.start()
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of spark</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/power_drain(clockcult_user)
|
||||
if(charge)
|
||||
. = min(charge, 250)
|
||||
charge = use(.)
|
||||
updateicon()
|
||||
|
||||
/obj/machinery/light/power_drain(clockcult_user)
|
||||
if(on)
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
. = 250
|
||||
if(prob(50))
|
||||
burn_out()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, 250)
|
||||
cell.use(.)
|
||||
src << "<span class='userdanger'>ERROR: Power loss detected!</span>"
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user)
|
||||
if((!clockcult_user || !occupant || occupant && !is_servant_of_ratvar(occupant)) && cell && cell.charge)
|
||||
. = min(cell.charge, 250)
|
||||
cell.use(.)
|
||||
occupant_message("<span class='userdanger'>Power loss detected!</span>")
|
||||
spark_system.start()
|
||||
@@ -0,0 +1,147 @@
|
||||
//generates a component in the global component cache, either random based on lowest or a specific component
|
||||
/proc/generate_cache_component(specific_component_id, atom/A)
|
||||
if(!specific_component_id)
|
||||
specific_component_id = get_weighted_component_id()
|
||||
clockwork_component_cache[specific_component_id]++
|
||||
if(A)
|
||||
var/component_animation_type = get_component_animation_type(specific_component_id)
|
||||
new component_animation_type(get_turf(A))
|
||||
update_slab_info()
|
||||
return specific_component_id
|
||||
|
||||
//returns a chosen component id based on the lowest amount of that component in the global cache, the global cache plus the slab if there are caches, or the slab if there are no caches.
|
||||
/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab)
|
||||
. = list()
|
||||
if(storage_slab)
|
||||
if(clockwork_caches)
|
||||
for(var/i in clockwork_component_cache)
|
||||
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache[i] + storage_slab.stored_components[i]), 1)
|
||||
else
|
||||
for(var/i in clockwork_component_cache)
|
||||
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*storage_slab.stored_components[i], 1)
|
||||
else
|
||||
for(var/i in clockwork_component_cache)
|
||||
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache[i], 1)
|
||||
. = pickweight(.)
|
||||
|
||||
//returns a component name from a component id
|
||||
/proc/get_component_name(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "Belligerent Eye"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "Vanguard Cogwheel"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "Geis Capacitor"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "Replicant Alloy"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "Hierophant Ansible"
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component acronym from a component id
|
||||
/proc/get_component_acronym(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "BE"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "VC"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "GC"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "RA"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "HA"
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component id from a component name
|
||||
/proc/get_component_id(name)
|
||||
switch(name)
|
||||
if("Belligerent Eye")
|
||||
return BELLIGERENT_EYE
|
||||
if("Vanguard Cogwheel")
|
||||
return VANGUARD_COGWHEEL
|
||||
if("Geis Capacitor")
|
||||
return GEIS_CAPACITOR
|
||||
if("Replicant Alloy")
|
||||
return REPLICANT_ALLOY
|
||||
if("Hierophant Ansible")
|
||||
return HIEROPHANT_ANSIBLE
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component spanclass from a component id
|
||||
/proc/get_component_span(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "neovgre"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "inathneq"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "sevtug"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "nezbere"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "nzcrentr"
|
||||
else
|
||||
return "brass"
|
||||
|
||||
//returns a component color from a component id, but with brighter colors for the darkest
|
||||
/proc/get_component_color_bright(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "#880020"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "#5A6068"
|
||||
else
|
||||
return get_component_color(id)
|
||||
|
||||
//returns a component color from a component id
|
||||
/proc/get_component_color(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "#6E001A"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "#1E8CE1"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "#AF0AAF"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "#42474D"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "#DAAA18"
|
||||
else
|
||||
return "#BE8700"
|
||||
|
||||
//returns a type for a floating component animation from a component id
|
||||
/proc/get_component_animation_type(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return /obj/effect/overlay/temp/ratvar/component
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return /obj/effect/overlay/temp/ratvar/component/cogwheel
|
||||
if(GEIS_CAPACITOR)
|
||||
return /obj/effect/overlay/temp/ratvar/component/capacitor
|
||||
if(REPLICANT_ALLOY)
|
||||
return /obj/effect/overlay/temp/ratvar/component/alloy
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return /obj/effect/overlay/temp/ratvar/component/ansible
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a type for a component from a component id
|
||||
/proc/get_component_type(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return /obj/item/clockwork/component/belligerent_eye
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return /obj/item/clockwork/component/vanguard_cogwheel
|
||||
if(GEIS_CAPACITOR)
|
||||
return /obj/item/clockwork/component/geis_capacitor
|
||||
if(REPLICANT_ALLOY)
|
||||
return /obj/item/clockwork/component/replicant_alloy
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return /obj/item/clockwork/component/hierophant_ansible
|
||||
else
|
||||
return null
|
||||
@@ -0,0 +1,47 @@
|
||||
//Sends a string to all servants and optionally ghosts, who will get a follow link to whatever is provided as the target.
|
||||
/proc/hierophant_message(message, servantsonly, atom/target)
|
||||
if(!message)
|
||||
return FALSE
|
||||
for(var/M in mob_list)
|
||||
if(!servantsonly && isobserver(M))
|
||||
if(target)
|
||||
var/link = FOLLOW_LINK(M, target)
|
||||
M << "[link] [message]"
|
||||
else
|
||||
M << message
|
||||
else if(is_servant_of_ratvar(M))
|
||||
M << message
|
||||
return TRUE
|
||||
|
||||
//Sends a titled message from a mob to all servants of ratvar and ghosts.
|
||||
/proc/titled_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant")
|
||||
if(!user || !message)
|
||||
return FALSE
|
||||
var/parsed_message = "<span class='[name_span]'>[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: \
|
||||
</span><span class='[message_span]'>\"[message]\"</span>"
|
||||
hierophant_message(parsed_message, FALSE, user)
|
||||
return TRUE
|
||||
|
||||
//Hierophant Network action, allows a servant with it to communicate to other servants.
|
||||
/datum/action/innate/hierophant
|
||||
name = "Hierophant Network"
|
||||
desc = "Allows you to communicate with other Servants."
|
||||
button_icon_state = "hierophant"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/title = "Servant"
|
||||
var/span_for_name = "heavy_brass"
|
||||
var/span_for_message = "brass"
|
||||
|
||||
/datum/action/innate/hierophant/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/hierophant/Activate()
|
||||
var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "")
|
||||
if(!input || !IsAvailable())
|
||||
return
|
||||
|
||||
titled_hierophant_message(owner, input, span_for_name, span_for_message, title)
|
||||
@@ -0,0 +1,409 @@
|
||||
//For the clockwork proselytizer, this proc exists to make it easy to customize what the proselytizer does when hitting something.
|
||||
|
||||
//if a valid target, returns an associated list in this format;
|
||||
//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "power_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
//otherwise, return literally any non-list thing but preferably FALSE
|
||||
//returning TRUE won't produce the "cannot be proselytized" message and will still prevent proselytizing
|
||||
|
||||
/atom/proc/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Turf conversion
|
||||
/turf/closed/wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //four sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 4), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, five rods
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2) - (POWER_ROD * 5), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/cult/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //no metal
|
||||
return list("operation_time" = 80, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/shuttle/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/r_wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/closed/wall/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = -POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(floor_tile == /obj/item/stack/tile/plasteel)
|
||||
new floor_tile(src)
|
||||
make_plating()
|
||||
playsound(src, 'sound/items/Crowbar.ogg', 10, 1) //clink
|
||||
return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = POWER_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/plating/asteroid/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/ashplanet/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/lava/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(locate(/obj/structure/table) in loc)
|
||||
return FALSE
|
||||
if(is_blocked_turf(src, TRUE))
|
||||
user << "<span class='warning'>Something is in the way, preventing you from proselytizing [src] into a clockwork wall.</span>"
|
||||
return TRUE
|
||||
return list("operation_time" = 100, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
//False wall conversion
|
||||
/obj/structure/falsewall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/cost = POWER_WALL_MINUS_FLOOR
|
||||
if(ispath(mineral, /obj/item/stack/sheet/metal))
|
||||
cost -= (POWER_METAL * (2 + mineral_amount)) //four sheets of metal, plus an assumption that the girder is also two
|
||||
else
|
||||
cost -= (POWER_METAL * 2) //anything that doesn't use metal just has the girder
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, two rods; special assumption
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = POWER_WALL_MINUS_FLOOR - (POWER_METAL * 2) - (POWER_ROD * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/reinforced/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/falsewall/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Metal conversion
|
||||
/obj/item/stack/tile/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/amount_temp = get_amount()
|
||||
if(proselytizer.metal_to_power)
|
||||
var/no_delete = FALSE
|
||||
if(amount_temp < 2)
|
||||
user << "<span class='warning'>You need at least <b>2</b> floor tiles to convert into power.</span>"
|
||||
return TRUE
|
||||
if(IsOdd(amount_temp))
|
||||
amount_temp--
|
||||
no_delete = TRUE
|
||||
use(amount_temp)
|
||||
amount_temp *= 12.5 //each tile is 12.5 power so this is 2 tiles to 25 power
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -amount_temp, "spawn_dir" = SOUTH, "no_target_deletion" = no_delete)
|
||||
if(amount_temp >= 20)
|
||||
var/sheets_to_make = round(amount_temp * 0.05) //and 20 to 1 brass
|
||||
var/used = sheets_to_make * 20
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
user << "<span class='warning'>You need at least <b>20</b> floor tiles to convert into brass.</span>"
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_ROD), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 10)
|
||||
var/sheets_to_make = round(get_amount() * 0.1)
|
||||
var/used = sheets_to_make * 10
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
user << "<span class='warning'>You need at least <b>10</b> rods to convert into brass.</span>"
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/sheet/metal/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_METAL), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 5)
|
||||
var/sheets_to_make = round(get_amount() * 0.2)
|
||||
var/used = sheets_to_make * 5
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
user << "<span class='warning'>You need at least <b>5</b> sheets of metal to convert into brass.</span>"
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/sheet/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_PLASTEEL), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 2)
|
||||
var/sheets_to_make = round(get_amount() * 0.5)
|
||||
var/used = sheets_to_make * 2
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
user << "<span class='warning'>You need at least <b>2</b> sheets of plasteel to convert into brass.</span>"
|
||||
return TRUE
|
||||
|
||||
//Brass directly to power
|
||||
/obj/item/stack/tile/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
return list("operation_time" = amount, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH)
|
||||
|
||||
//Airlock conversion
|
||||
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/doortype = /obj/machinery/door/airlock/clockwork
|
||||
if(glass)
|
||||
doortype = /obj/machinery/door/airlock/clockwork/brass
|
||||
return list("operation_time" = 60, "new_obj_type" = doortype, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = dir)
|
||||
|
||||
/obj/machinery/door/airlock/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Table conversion
|
||||
/obj/structure/table/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_STANDARD
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
prosel_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
prosel_cost -= POWER_FLOOR*framestackamount
|
||||
if(buildstack == /obj/item/stack/sheet/metal)
|
||||
prosel_cost -= POWER_METAL*buildstackamount
|
||||
else if(buildstack == /obj/item/stack/sheet/plasteel)
|
||||
prosel_cost -= POWER_PLASTEEL*buildstackamount
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/table/reinforced/brass, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table/reinforced/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/table_frame/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_FLOOR
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
prosel_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
prosel_cost -= POWER_FLOOR*framestackamount
|
||||
return list("operation_time" = 10, "new_obj_type" = /obj/structure/table_frame/brass, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table_frame/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Window conversion
|
||||
/obj/structure/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/windowtype = /obj/structure/window/reinforced/clockwork
|
||||
var/new_dir = TRUE
|
||||
var/prosel_time = 15
|
||||
var/prosel_cost = POWER_FLOOR
|
||||
if(fulltile)
|
||||
windowtype = /obj/structure/window/reinforced/clockwork/fulltile
|
||||
new_dir = FALSE
|
||||
prosel_time = 30
|
||||
prosel_cost = POWER_STANDARD
|
||||
if(reinf)
|
||||
prosel_cost -= POWER_ROD
|
||||
if(reinf)
|
||||
prosel_cost -= POWER_ROD
|
||||
for(var/obj/structure/grille/G in get_turf(src))
|
||||
INVOKE_ASYNC(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytize, G, user)
|
||||
return list("operation_time" = prosel_time, "new_obj_type" = windowtype, "power_cost" = prosel_cost, "spawn_dir" = dir, "dir_in_new" = new_dir)
|
||||
|
||||
/obj/structure/window/reinforced/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Windoor conversion
|
||||
/obj/machinery/door/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "power_cost" = POWER_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
|
||||
/obj/machinery/door/window/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Grille conversion
|
||||
/obj/structure/grille/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/grilletype = /obj/structure/grille/ratvar
|
||||
var/prosel_time = 15
|
||||
if(broken)
|
||||
grilletype = /obj/structure/grille/ratvar/broken
|
||||
prosel_time = 5
|
||||
return list("operation_time" = prosel_time, "new_obj_type" = grilletype, "power_cost" = 0, "spawn_dir" = dir)
|
||||
|
||||
/obj/structure/grille/ratvar/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Lattice conversion
|
||||
/obj/structure/lattice/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
ratvar_act() //just in case we're the wrong type for some reason??
|
||||
return FALSE
|
||||
|
||||
/obj/structure/lattice/catwalk/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/catwalk/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/catwalk/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Girder conversion
|
||||
/obj/structure/girder/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_GEAR - (POWER_METAL * 2)
|
||||
if(state == GIRDER_REINF_STRUTS || state == GIRDER_REINF)
|
||||
prosel_cost -= POWER_PLASTEEL
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/destructible/clockwork/wall_gear, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
//Hitting a clockwork structure will try to repair it.
|
||||
/obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(!can_be_repaired)
|
||||
user << "<span class='warning'>[src] cannot be repaired!</span>"
|
||||
return
|
||||
if(obj_integrity >= max_integrity)
|
||||
user << "<span class='warning'>[src] is at maximum integrity!</span>"
|
||||
return
|
||||
var/amount_to_heal = max_integrity - obj_integrity
|
||||
var/healing_for_cycle = min(amount_to_heal, repair_amount)
|
||||
var/power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
|
||||
if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
|
||||
user << "<span class='warning'>You need at least <b>[power_required]W</b> power to start repairing [src], and at least \
|
||||
<b>[round(amount_to_heal*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W</b> to fully repair it!</span>"
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts covering [src] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairing [src]...</span>")
|
||||
//hugeass while because we need to re-check after the do_after
|
||||
proselytizer.repairing = src
|
||||
while(proselytizer && user && src && obj_integrity < max_integrity)
|
||||
amount_to_heal = max_integrity - obj_integrity
|
||||
if(amount_to_heal <= 0)
|
||||
break
|
||||
healing_for_cycle = min(amount_to_heal, repair_amount)
|
||||
power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
|
||||
if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)) || \
|
||||
!do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \
|
||||
!proselytizer || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
|
||||
break
|
||||
amount_to_heal = max_integrity - obj_integrity
|
||||
if(amount_to_heal <= 0)
|
||||
break
|
||||
healing_for_cycle = min(amount_to_heal, repair_amount)
|
||||
power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
|
||||
if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
|
||||
break
|
||||
obj_integrity = Clamp(obj_integrity + healing_for_cycle, 0, max_integrity)
|
||||
proselytizer.modify_stored_power(-power_required)
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops covering [src] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
|
||||
|
||||
//Proselytizer mob heal proc, to avoid as much copypaste as possible.
|
||||
/mob/living/proc/proselytizer_heal(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(!is_servant_of_ratvar(src))
|
||||
user << "<span class='warning'>[src] does not serve Ratvar!</span>"
|
||||
return FALSE
|
||||
if(health >= maxHealth || (flags & GODMODE))
|
||||
user << "<span class='warning'>[src == user ? "You" : "[src]"] [src == user ? "are" : "is"] at maximum health!</span>"
|
||||
return FALSE
|
||||
var/amount_to_heal = maxHealth - health
|
||||
var/healing_for_cycle = min(amount_to_heal, 4)
|
||||
var/power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
|
||||
if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
|
||||
user << "<span class='warning'>You need at least <b>[power_required]W</b> power to start repairing[src == user ? " yourself" : " [src]"], and at least \
|
||||
<b>[round(amount_to_heal*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W</b> to fully repair [src == user ? "yourself" : "[p_them()]"]!</span>"
|
||||
return FALSE
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
//hugeass while because we need to re-check after the do_after
|
||||
proselytizer.repairing = src
|
||||
while(proselytizer && user && src && health < maxHealth)
|
||||
amount_to_heal = maxHealth - health
|
||||
if(amount_to_heal <= 0)
|
||||
break
|
||||
healing_for_cycle = min(amount_to_heal, 4)
|
||||
power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
|
||||
if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)) || \
|
||||
!do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \
|
||||
!proselytizer || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
|
||||
break
|
||||
amount_to_heal = maxHealth - health
|
||||
if(amount_to_heal <= 0)
|
||||
break
|
||||
healing_for_cycle = min(amount_to_heal, 4)
|
||||
power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
|
||||
if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
|
||||
break
|
||||
proselytizer_heal_tick(healing_for_cycle)
|
||||
proselytizer.modify_stored_power(-power_required)
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/proselytizer_heal_tick(amount)
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, TOX, OXY)
|
||||
heal_ordered_damage(amount, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/proselytizer_heal_tick(amount)
|
||||
adjustHealth(-amount)
|
||||
|
||||
//Hitting a ratvar'd silicon will also try to repair it.
|
||||
/mob/living/silicon/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(proselytizer_heal(user, proselytizer) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[abs(HEALTH_THRESHOLD_DEAD - health)]/[abs(HEALTH_THRESHOLD_DEAD - maxHealth)]</b> health.</span>")
|
||||
|
||||
//Same with clockwork mobs.
|
||||
/mob/living/simple_animal/hostile/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(proselytizer_heal(user, proselytizer) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[health]/[maxHealth]</b> health.</span>")
|
||||
|
||||
//Cogscarabs get special interaction because they're drones and have innate self-heals/revives.
|
||||
/mob/living/simple_animal/drone/cogscarab/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(stat == DEAD)
|
||||
try_reactivate(user)
|
||||
return
|
||||
if(health < maxHealth && !(flags & GODMODE))
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
if(do_after(user,80*proselytizer.speed_multiplier, target=src))
|
||||
adjustHealth(-maxHealth)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself" : "g [src]"].</span>")
|
||||
else
|
||||
user << "<span class='warning'>[src == user ? "You" : "[src]"] [src == user ? "are" : "is"] at maximum health!</span>"
|
||||
|
||||
//Convert shards and replicant alloy directly to power
|
||||
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -POWER_STANDARD, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.08), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.06), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.04), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/small/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.02), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -CLOCKCULT_POWER_UNIT, "spawn_dir" = SOUTH)
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
The Ratvarian Language
|
||||
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from
|
||||
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult).
|
||||
|
||||
While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is
|
||||
actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached.
|
||||
This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated
|
||||
sentence thirteen places ahead changes it right back to plain English.
|
||||
|
||||
There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have graves, or hyphens (prefix and postfix), making the plain
|
||||
English translation apparent but disjoined (for instance, "Orubyq zl-cbjre!" translates directly to "Behold my-power!") although this can be ignored without impacting overall quality. When
|
||||
translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Orubyq zl-cbjre!" into "Behold my power!" after removing the
|
||||
abnormal spacing, hyphens, and grave accents.
|
||||
|
||||
List of nuances:
|
||||
- Any time the WORD "of" occurs, it is linked to the previous word by a hyphen. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.")
|
||||
- Any time "th", followed by any two letters occurs, you add a grave (`) between those two letters, i.e; "Thi`s"
|
||||
- In the same vein, any time "ti", followed by one letter occurs, you add a grave (`) between "i" and the letter, i.e; "Ti`me"
|
||||
- Whereever "te" or "et" appear and there is another letter next to the e(i.e; "m"etal, greate"r"), add a hyphen between "e" and the letter, i.e; "M-etal", "Greate-r"
|
||||
- Where "gua" appears, add a hyphen between "gu" and "a", i.e "Gu-ard"
|
||||
- Where the WORD "and" appears it is linked to all surrounding words by hyphens, i.e; "Sword-and-shield"
|
||||
- Where the WORD "to" appears, it is linked to the following word by a hyphen, i.e; "to-use"
|
||||
- Where the WORD "my" appears, it is linked to the following word by a hyphen, i.e; "my-light"
|
||||
- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun.
|
||||
- The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-neq (Vangu-Ard), although these words can be used in proper context if one is
|
||||
not referring to the four generals and simply using the words themselves.
|
||||
*/
|
||||
|
||||
//Regexes used to alter english to ratvarian style
|
||||
#define RATVAR_OF_MATCH regex("(\\w)\\s(\[oO]\[fF])","g")
|
||||
#define RATVAR_OF_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_GUA_MATCH regex("(\[gG]\[uU])(\[aA])","g")
|
||||
#define RATVAR_GUA_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_TH_MATCH regex("(\[tT]\[hH]\\w)(\\w)","g")
|
||||
#define RATVAR_TH_REPLACEMENT "$1`$2"
|
||||
#define RATVAR_TI_MATCH regex("(\[tT]\[iI])(\\w)","g")
|
||||
#define RATVAR_TI_REPLACEMENT "$1`$2"
|
||||
#define RATVAR_ET_MATCH regex("(\\w)(\[eE]\[tT])","g")
|
||||
#define RATVAR_ET_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_TE_MATCH regex("(\[tT]\[eE])(\\w)","g")
|
||||
#define RATVAR_TE_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_PRE_AND_MATCH regex("(\\w)\\s(\[aA]\[nN]\[dD])","g")
|
||||
#define RATVAR_PRE_AND_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])\\s(\\w)","g")
|
||||
#define RATVAR_POST_AND_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_TO_MATCH regex("(\\s)(\[tT]\[oO])\\s(\\w)","g")
|
||||
#define RATVAR_TO_REPLACEMENT "$1$2-$3"
|
||||
#define RATVAR_MY_MATCH regex("(\\s)(\[mM]\[yY])\\s(\\w)","g")
|
||||
#define RATVAR_MY_REPLACEMENT "$1$2-$3"
|
||||
|
||||
//Regexes used to remove ratvarian styling from english
|
||||
#define REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH regex("(\\w)-(\[aA]\[nN]\[dD])","g") //specifically structured to support -emphasis-, including with -and-
|
||||
#define REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT "$1 $2"
|
||||
#define REVERSE_RATVAR_HYPHEN_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])-(\\w)","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT "$1 $2"
|
||||
#define REVERSE_RATVAR_HYPHEN_TO_MY_MATCH regex("(\[tTmM]\[oOyY])-","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT "$1 "
|
||||
#define REVERSE_RATVAR_HYPHEN_TE_MATCH regex("(\[tT]\[eE])-","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT "$1"
|
||||
#define REVERSE_RATVAR_HYPHEN_ET_MATCH regex("-(\[eE]\[tT])","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT "$1"
|
||||
#define REVERSE_RATVAR_HYPHEN_GUA_MATCH regex("(\[gG]\[uU])-(\[aA])","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT "$1$2"
|
||||
#define REVERSE_RATVAR_HYPHEN_OF_MATCH regex("-(\[oO]\[fF])","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT " $1"
|
||||
|
||||
|
||||
/proc/text2ratvar(text) //Takes english and applies ratvarian styling rules (and rot13) to it
|
||||
var/ratvarian = replacetext(text, RATVAR_OF_MATCH, RATVAR_OF_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_GUA_MATCH, RATVAR_GUA_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TH_MATCH, RATVAR_TH_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TI_MATCH, RATVAR_TI_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_ET_MATCH, RATVAR_ET_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TE_MATCH, RATVAR_TE_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_PRE_AND_MATCH, RATVAR_PRE_AND_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_POST_AND_MATCH, RATVAR_POST_AND_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TO_MATCH, RATVAR_TO_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_MY_MATCH, RATVAR_MY_REPLACEMENT)
|
||||
return rot13(ratvarian)
|
||||
|
||||
/proc/ratvar2text(ratvarian) //Reverts ravarian styling and rot13 in text.
|
||||
var/text = replacetext(rot13(ratvarian), "`", "")
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_GUA_MATCH, REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH, REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_POST_AND_MATCH, REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_TO_MY_MATCH, REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_TE_MATCH, REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_ET_MATCH, REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_OF_MATCH, REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT)
|
||||
return text
|
||||
|
||||
//Causes the mob or AM in question to speak a message; it assumes that the message is already translated to ratvar speech using text2ratvar()
|
||||
/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE)
|
||||
var/list/spans = list(SPAN_ROBOT)
|
||||
|
||||
var/old_languages_spoken = AM.languages_spoken
|
||||
AM.languages_spoken = HUMAN //anyone who can understand HUMAN will hear weird shitty ratvar speak, otherwise it'll get starred out
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(!whisper)
|
||||
L.say(message, "clock", spans)
|
||||
else
|
||||
L.whisper(message)
|
||||
else
|
||||
AM.say(message)
|
||||
AM.languages_spoken = old_languages_spoken
|
||||
@@ -0,0 +1,48 @@
|
||||
//returns a list of scriptures and if they're unlocked or not
|
||||
/proc/scripture_unlock_check()
|
||||
var/servants = 0
|
||||
var/unconverted_ai_exists = FALSE
|
||||
for(var/mob/living/M in living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
else if(isAI(M))
|
||||
unconverted_ai_exists = TRUE
|
||||
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE)
|
||||
//Drivers: always unlocked
|
||||
.[SCRIPTURE_SCRIPT] = (servants >= SCRIPT_SERVANT_REQ && clockwork_caches >= SCRIPT_CACHE_REQ)
|
||||
//Script: SCRIPT_SERVANT_REQ or more non-brain servants and SCRIPT_CACHE_REQ or more clockwork caches
|
||||
.[SCRIPTURE_APPLICATION] = (servants >= APPLICATION_SERVANT_REQ && clockwork_caches >= APPLICATION_CACHE_REQ && clockwork_construction_value >= APPLICATION_CV_REQ)
|
||||
//Application: APPLICATION_SERVANT_REQ or more non-brain servants, APPLICATION_CACHE_REQ or more clockwork caches, and at least APPLICATION_CV_REQ CV
|
||||
.[SCRIPTURE_REVENANT] = (servants >= REVENANT_SERVANT_REQ && clockwork_caches >= REVENANT_CACHE_REQ && clockwork_construction_value >= REVENANT_CV_REQ)
|
||||
//Revenant: REVENANT_SERVANT_REQ or more non-brain servants, REVENANT_CACHE_REQ or more clockwork caches, and at least REVENANT_CV_REQ CV
|
||||
.[SCRIPTURE_JUDGEMENT] = (servants >= JUDGEMENT_SERVANT_REQ && clockwork_caches >= JUDGEMENT_CACHE_REQ && clockwork_construction_value >= JUDGEMENT_CV_REQ && !unconverted_ai_exists)
|
||||
//Judgement: JUDGEMENT_SERVANT_REQ or more non-brain servants, JUDGEMENT_CACHE_REQ or more clockwork caches, at least JUDGEMENT_CV_REQ CV, and there are no living, non-servant ais
|
||||
|
||||
//reports to servants when scripture is locked or unlocked
|
||||
/proc/scripture_unlock_alert(list/previous_states)
|
||||
. = scripture_unlock_check()
|
||||
for(var/i in .)
|
||||
if(.[i] != previous_states[i])
|
||||
hierophant_message("<span class='large_brass'><i>Hierophant Network:</i> <b>[i] Scripture has been [.[i] ? "un":""]locked.</b></span>")
|
||||
update_slab_info()
|
||||
|
||||
/proc/update_slab_info(obj/item/clockwork/slab/set_slab)
|
||||
generate_all_scripture()
|
||||
for(var/s in all_scripture)
|
||||
var/datum/clockwork_scripture/S = s
|
||||
S.creation_update()
|
||||
if(!set_slab)
|
||||
for(var/obj/item/clockwork/slab/S in all_clockwork_objects)
|
||||
SStgui.update_uis(S)
|
||||
else
|
||||
SStgui.update_uis(set_slab)
|
||||
|
||||
/proc/generate_all_scripture()
|
||||
if(!all_scripture.len)
|
||||
for(var/V in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority))
|
||||
var/datum/clockwork_scripture/S = new V
|
||||
all_scripture += S
|
||||
|
||||
//changes construction value
|
||||
/proc/change_construction_value(amount)
|
||||
clockwork_construction_value += amount
|
||||
@@ -0,0 +1,244 @@
|
||||
//The base for slab-bound/based ranged abilities
|
||||
/obj/effect/proc_holder/slab
|
||||
var/obj/item/clockwork/slab/slab
|
||||
var/successful = FALSE
|
||||
var/finished = FALSE
|
||||
var/in_progress = FALSE
|
||||
|
||||
/obj/effect/proc_holder/slab/remove_ranged_ability(msg)
|
||||
..()
|
||||
finished = TRUE
|
||||
QDEL_IN(src, 6)
|
||||
|
||||
/obj/effect/proc_holder/slab/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..() || in_progress)
|
||||
return TRUE
|
||||
if(ranged_ability_user.incapacitated() || !slab || !(slab in ranged_ability_user.held_items) || target == slab)
|
||||
remove_ranged_ability()
|
||||
return TRUE
|
||||
|
||||
//For the Geis scripture; binds a target to convert.
|
||||
/obj/effect/proc_holder/slab/geis
|
||||
ranged_mousepointer = 'icons/effects/geis_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/geis/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(target == slab || ..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
var/target_is_binding = istype(target, /obj/structure/destructible/clockwork/geis_binding)
|
||||
|
||||
if((target_is_binding || isliving(target)) && ranged_ability_user.Adjacent(target))
|
||||
if(target_is_binding)
|
||||
var/obj/structure/destructible/clockwork/geis_binding/GB = target
|
||||
GB.repair_and_interrupt()
|
||||
for(var/m in GB.buckled_mobs)
|
||||
if(m)
|
||||
add_logs(ranged_ability_user, m, "rebound with Geis")
|
||||
successful = TRUE
|
||||
else
|
||||
var/mob/living/L = target
|
||||
if(L.null_rod_check())
|
||||
ranged_ability_user << "<span class='sevtug'>\"A void weapon? Really, you expect me to be able to do anything?\"</span>"
|
||||
return TRUE
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(L != ranged_ability_user)
|
||||
ranged_ability_user << "<span class='sevtug'>\"[L.p_they(TRUE)] already serve[L.p_s()] Ratvar. [text2ratvar("Perhaps [ranged_ability_user.p_theyre()] into bondage?")]\"</span>"
|
||||
return TRUE
|
||||
if(L.stat == DEAD)
|
||||
ranged_ability_user << "<span class='sevtug'>\"[L.p_theyre(TRUE)] dead, idiot.\"</span>"
|
||||
return TRUE
|
||||
|
||||
if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding)) //if they're already bound, just stun them
|
||||
var/obj/structure/destructible/clockwork/geis_binding/GB = L.buckled
|
||||
GB.repair_and_interrupt()
|
||||
add_logs(ranged_ability_user, L, "rebound with Geis")
|
||||
successful = TRUE
|
||||
else
|
||||
in_progress = TRUE
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Be bound, heathen!"))
|
||||
remove_mousepointer(ranged_ability_user.client)
|
||||
add_logs(ranged_ability_user, L, "bound with Geis")
|
||||
if(slab.speed_multiplier >= 0.5) //excuse my debug...
|
||||
ranged_ability_user.notransform = TRUE
|
||||
addtimer(CALLBACK(src, .proc/reset_user_notransform, ranged_ability_user), 5) //stop us moving for a little bit so we don't break the scripture following this
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/geis/conversion = new
|
||||
conversion.slab = slab
|
||||
conversion.invoker = ranged_ability_user
|
||||
conversion.target = target
|
||||
conversion.run_scripture()
|
||||
successful = TRUE
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/slab/geis/proc/reset_user_notransform(mob/living/user)
|
||||
if(user)
|
||||
user.notransform = FALSE
|
||||
|
||||
//For the Sentinel's Compromise scripture; heals a target servant.
|
||||
/obj/effect/proc_holder/slab/compromise
|
||||
ranged_mousepointer = 'icons/effects/compromise_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/compromise/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(isliving(target) && (target in view(7, get_turf(ranged_ability_user))))
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
ranged_ability_user << "<span class='inathneq'>\"[L] does not yet serve Ratvar.\"</span>"
|
||||
return TRUE
|
||||
if(L.stat == DEAD)
|
||||
ranged_ability_user << "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] dead. [text2ratvar("Oh, child. To have your life cut short...")]\"</span>"
|
||||
return TRUE
|
||||
|
||||
var/brutedamage = L.getBruteLoss()
|
||||
var/burndamage = L.getFireLoss()
|
||||
var/oxydamage = L.getOxyLoss()
|
||||
var/totaldamage = brutedamage + burndamage + oxydamage
|
||||
if(!totaldamage && (!L.reagents || !L.reagents.has_reagent("holywater")))
|
||||
ranged_ability_user << "<span class='inathneq'>\"[L] is unhurt and untainted.\"</span>"
|
||||
return TRUE
|
||||
|
||||
successful = TRUE
|
||||
|
||||
var/targetturf = get_turf(L)
|
||||
if(totaldamage)
|
||||
L.adjustBruteLoss(-brutedamage)
|
||||
L.adjustFireLoss(-burndamage)
|
||||
L.adjustOxyLoss(-oxydamage)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE)
|
||||
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
|
||||
for(var/i in 1 to healseverity)
|
||||
new /obj/effect/overlay/temp/heal(targetturf, "#1E8CE1")
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Mend wounded flesh!"))
|
||||
add_logs(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
else
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge foul darkness!"))
|
||||
add_logs(ranged_ability_user, L, "purged of holy water with Sentinel's Compromise")
|
||||
ranged_ability_user << "<span class='brass'>You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!</span>"
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], mending [L.p_their()] bruises and burns!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power healing your wounds, but a deep nausea overcomes you!</span>")
|
||||
playsound(targetturf, 'sound/magic/Staff_Healing.ogg', 50, 1)
|
||||
|
||||
if(L.reagents && L.reagents.has_reagent("holywater"))
|
||||
L.reagents.remove_reagent("holywater", 1000)
|
||||
L << "<span class='heavy_brass'>Ratvar's light flares, banishing the darkness. Your devotion remains intact!</span>"
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Volt Void scripture, fires a ray of energy at a target location
|
||||
/obj/effect/proc_holder/slab/volt
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/volt/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] fires a ray of energy at [target]!</span>", "<span class='nzcrentr'>You fire a volt ray at [target].</span>")
|
||||
playsound(ranged_ability_user, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
var/turf/targetturf = get_turf(target)
|
||||
var/obj/structure/destructible/clockwork/powered/volt_checker/VC = new/obj/structure/destructible/clockwork/powered/volt_checker(get_turf(ranged_ability_user))
|
||||
var/multiplier = 1
|
||||
var/usable_power = min(Floor(VC.total_accessable_power() * 0.2, MIN_CLOCKCULT_POWER), 1000)
|
||||
if(VC.try_use_power(usable_power))
|
||||
multiplier += (usable_power * 0.001) //should be a multiplier of 2 at maximum power usage
|
||||
if(iscyborg(ranged_ability_user))
|
||||
var/mob/living/silicon/robot/C = ranged_ability_user
|
||||
if(C.cell)
|
||||
var/prev_power = usable_power //we don't want to increase the multiplier past 2
|
||||
usable_power = min(Floor(C.cell.charge * 0.2, MIN_CLOCKCULT_POWER), 1000) - prev_power
|
||||
if(usable_power > 0 && C.cell.use(usable_power))
|
||||
multiplier += (usable_power * 0.001)
|
||||
qdel(VC)
|
||||
new/obj/effect/overlay/temp/ratvar/volt_hit/true(targetturf, ranged_ability_user, multiplier)
|
||||
add_logs(ranged_ability_user, targetturf, "fired a volt ray")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the cyborg Linked Vanguard scripture, grants you and a nearby ally Vanguard
|
||||
/obj/effect/proc_holder/slab/vanguard
|
||||
ranged_mousepointer = 'icons/effects/vanguard_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/vanguard/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(isliving(target) && (target in view(7, get_turf(ranged_ability_user))))
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
ranged_ability_user << "<span class='inathneq'>\"[L] does not yet serve Ratvar.\"</span>"
|
||||
return TRUE
|
||||
if(L.stat == DEAD)
|
||||
ranged_ability_user << "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] dead. [text2ratvar("Oh, child. To have your life cut short...")]\"</span>"
|
||||
return TRUE
|
||||
if(islist(L.stun_absorption) && L.stun_absorption["vanguard"] && L.stun_absorption["vanguard"]["end_time"] > world.time)
|
||||
ranged_ability_user << "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] already shielded by a Vanguard.\"</span>"
|
||||
return TRUE
|
||||
|
||||
successful = TRUE
|
||||
|
||||
if(L == ranged_ability_user)
|
||||
for(var/mob/living/LT in spiral_range(7, T))
|
||||
if(LT.stat == DEAD || !is_servant_of_ratvar(LT) || LT == ranged_ability_user || !(LT in view(7, get_turf(ranged_ability_user))) || \
|
||||
(islist(LT.stun_absorption) && LT.stun_absorption["vanguard"] && LT.stun_absorption["vanguard"]["end_time"] > world.time))
|
||||
continue
|
||||
L = LT
|
||||
break
|
||||
|
||||
L.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
ranged_ability_user.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Shield us from darkness!"))
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the cyborg Judicial Marker scripture, places a judicial marker
|
||||
/obj/effect/proc_holder/slab/judicial
|
||||
ranged_mousepointer = 'icons/effects/visor_reticule.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/judicial/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Kneel, heathens!"))
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s eyes fire a stream of energy at [target], creating a strange mark!</span>", \
|
||||
"<span class='heavy_brass'>You direct the judicial force to [target].</span>")
|
||||
var/turf/targetturf = get_turf(target)
|
||||
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
@@ -0,0 +1,24 @@
|
||||
//The base clockwork item. Can have an alternate desc and will show up in the list of clockwork objects.
|
||||
/obj/item/clockwork
|
||||
name = "meme blaster"
|
||||
desc = "What the fuck is this? It looks kinda like a frog."
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "rare_pepe"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/clockwork/New()
|
||||
..()
|
||||
ratvar_act()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,185 @@
|
||||
//Components: Used in scripture.
|
||||
/obj/item/clockwork/component
|
||||
name = "meme component"
|
||||
desc = "A piece of a famous meme."
|
||||
clockwork_desc = null
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/component_id //What the component is identified as
|
||||
var/cultist_message = "You are not worthy of this meme." //Showed to Nar-Sian cultists if they pick up the component in addition to chaplains
|
||||
var/list/servant_of_ratvar_messages = list("ayy" = FALSE, "lmao" = TRUE) //Fluff, shown to servants of Ratvar on a low chance, if associated value is TRUE, will automatically apply ratvarian
|
||||
var/message_span = "heavy_brass"
|
||||
|
||||
/obj/item/clockwork/component/pickup(mob/living/user)
|
||||
..()
|
||||
if(iscultist(user) || (user.mind && user.mind.isholy))
|
||||
user << "<span class='[message_span]'>[cultist_message]</span>"
|
||||
if(user.mind && user.mind.isholy)
|
||||
user << "<span class='boldannounce'>The power of your faith melts away the [src]!</span>"
|
||||
var/obj/item/weapon/ore/slag/wrath = new /obj/item/weapon/ore/slag
|
||||
qdel(src)
|
||||
user.put_in_active_hand(wrath)
|
||||
if(is_servant_of_ratvar(user) && prob(20))
|
||||
var/pickedmessage = pick(servant_of_ratvar_messages)
|
||||
user << "<span class='[message_span]'>[servant_of_ratvar_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]</span>"
|
||||
|
||||
/obj/item/clockwork/component/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user))
|
||||
user << "<span class='[message_span]'>You should put this in a slab or cache immediately.</span>"
|
||||
|
||||
/obj/item/clockwork/component/belligerent_eye
|
||||
name = "belligerent eye"
|
||||
desc = "A brass construct with a rotating red center. It's as though it's looking for something to hurt."
|
||||
icon_state = "belligerent_eye"
|
||||
component_id = BELLIGERENT_EYE
|
||||
cultist_message = "The eye gives you an intensely hateful glare."
|
||||
servant_of_ratvar_messages = list("\"...\"" = FALSE, "For a moment, your mind is flooded with extremely violent thoughts." = FALSE, "\"...Die.\"" = TRUE)
|
||||
message_span = "neovgre"
|
||||
|
||||
/obj/item/clockwork/component/belligerent_eye/blind_eye
|
||||
name = "blind eye"
|
||||
desc = "A heavy brass eye, its red iris fallen dark."
|
||||
clockwork_desc = "A smashed ocular warden covered in dents. <b>Serviceable as a substitute for a belligerent eye.</b>"
|
||||
icon_state = "blind_eye"
|
||||
cultist_message = "The eye flickers at you with intense hate before falling dark."
|
||||
servant_of_ratvar_messages = list("The eye flickers before falling dark." = FALSE, "You feel watched." = FALSE, "\"...\"" = FALSE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/vanguard_cogwheel
|
||||
name = "vanguard cogwheel"
|
||||
desc = "A sturdy brass cog with a faintly glowing blue gem in its center."
|
||||
icon_state = "vanguard_cogwheel"
|
||||
component_id = VANGUARD_COGWHEEL
|
||||
cultist_message = "\"Pray to your god that we never meet.\""
|
||||
servant_of_ratvar_messages = list("\"Be safe, child.\"" = FALSE, "You feel unexplainably comforted." = FALSE, "\"Never forget: Pain is temporary. What you do for the Justiciar is eternal.\"" = FALSE)
|
||||
message_span = "inathneq"
|
||||
|
||||
/obj/item/clockwork/component/vanguard_cogwheel/pinion_lock
|
||||
name = "pinion lock"
|
||||
desc = "A dented and scratched gear. It's very heavy."
|
||||
clockwork_desc = "A broken gear lock for pinion airlocks. <b>Serviceable as a substitute for a vanguard cogwheel.</b>"
|
||||
icon_state = "pinion_lock"
|
||||
cultist_message = "The gear grows warm in your hands."
|
||||
servant_of_ratvar_messages = list("The lock isn't getting any lighter." = FALSE, "\"Damaged gears are better than broken bodies.\"" = TRUE, \
|
||||
"\"It's a shame it can't be reused.\"" = TRUE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/geis_capacitor
|
||||
name = "geis capacitor"
|
||||
desc = "A curiously cold brass doodad. It seems as though it really doesn't appreciate being held."
|
||||
icon_state = "geis_capacitor"
|
||||
component_id = GEIS_CAPACITOR
|
||||
cultist_message = "\"Try not to lose your mind - I'll need it. Heh heh...\""
|
||||
servant_of_ratvar_messages = list("\"Disgusting.\"" = FALSE, "\"Well, aren't you an inquisitive fellow?\"" = FALSE, "A foul presence pervades your mind, then vanishes." = FALSE, \
|
||||
"\"The fact that Ratvar has to depend on simpletons like you is appalling.\"" = FALSE)
|
||||
message_span = "sevtug"
|
||||
|
||||
/obj/item/clockwork/component/geis_capacitor/antennae
|
||||
name = "mania motor antennae"
|
||||
desc = "A pair of dented and bent antennae. They constantly emit a static hiss."
|
||||
clockwork_desc = "The antennae from a mania motor. <b>Serviceable as a substitute for a geis capacitor.</b>"
|
||||
icon_state = "mania_motor_antennae"
|
||||
cultist_message = "Your head is filled with a burst of static."
|
||||
servant_of_ratvar_messages = list("\"Who broke this.\"" = TRUE, "\"Did you break these off YOURSELF?\"" = TRUE, "\"Why did we give this to such simpletons, anyway?\"" = TRUE, \
|
||||
"\"At least we can use these for something - unlike you.\"" = TRUE)
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy
|
||||
name = "replicant alloy"
|
||||
desc = "A seemingly strong but very malleable chunk of metal. It seems as though it wants to be molded into something greater."
|
||||
icon_state = "replicant_alloy"
|
||||
component_id = REPLICANT_ALLOY
|
||||
cultist_message = "The alloy takes on the appearance of a screaming face for a moment."
|
||||
servant_of_ratvar_messages = list("\"There's always something to be done. Get to it.\"" = FALSE, "\"Idle hands are worse than broken ones. Get to work.\"" = FALSE, \
|
||||
"A detailed image of Ratvar appears in the alloy for a moment." = FALSE)
|
||||
message_span = "nezbere"
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment
|
||||
name = "smashed anima fragment"
|
||||
desc = "Shattered chunks of metal. Damaged beyond repair and completely unusable."
|
||||
clockwork_desc = "The sad remains of an anima fragment. <b>Serviceable as a substitute for replicant alloy.</b>"
|
||||
icon_state = "smashed_anime_fragment"
|
||||
cultist_message = "The shards vibrate in your hands for a moment."
|
||||
servant_of_ratvar_messages = list("\"...still fight...\"" = FALSE, "\"...where am I...?\"" = FALSE, "\"...put me... slab...\"" = FALSE)
|
||||
message_span = "heavy_brass"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy/fallen_armor
|
||||
name = "fallen armor"
|
||||
desc = "Lifeless chunks of armor. They're designed in a strange way and won't fit on you."
|
||||
clockwork_desc = "The armor from a former clockwork marauder. <b>Serviceable as a substitute for replicant alloy.</b>"
|
||||
icon_state = "fallen_armor"
|
||||
cultist_message = "Red flame sputters from the mask's eye before winking out."
|
||||
servant_of_ratvar_messages = list("A piece of armor hovers away from the others for a moment." = FALSE, "Red flame appears in the cuirass before sputtering out." = FALSE)
|
||||
message_span = "heavy_brass"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/hierophant_ansible
|
||||
name = "hierophant ansible"
|
||||
desc = "Some sort of transmitter? It seems as though it's trying to say something."
|
||||
icon_state = "hierophant_ansible"
|
||||
component_id = HIEROPHANT_ANSIBLE
|
||||
cultist_message = "\"Gur obff fnlf vg'f abg ntnvafg gur ehyrf gb-xvyy lbh.\""
|
||||
servant_of_ratvar_messages = list("\"Exile is such a bore. There's nothing I can hunt in here.\"" = TRUE, "\"What's keeping you? I want to go kill something.\"" = TRUE, \
|
||||
"\"HEHEHEHEHEHEH!\"" = FALSE, "\"If I killed you fast enough, do you think the boss would notice?\"" = TRUE)
|
||||
message_span = "nzcrentr"
|
||||
|
||||
/obj/item/clockwork/component/hierophant_ansible/obelisk
|
||||
name = "obelisk prism"
|
||||
desc = "A prism that occasionally glows brightly. It seems not-quite there."
|
||||
clockwork_desc = "The prism from a clockwork obelisk. <b>Serviceable as a substitute for a hierophant ansible.</b>"
|
||||
cultist_message = "The prism flickers wildly in your hands before resuming its normal glow."
|
||||
servant_of_ratvar_messages = list("You hear the distinctive sound of the Hierophant Network for a moment." = FALSE, "\"Hieroph'ant Br'o'adcas't fail'ure.\"" = TRUE, \
|
||||
"The obelisk flickers wildly, as if trying to open a gateway." = FALSE, "\"Spa'tial Ga'tewa'y fai'lure.\"" = TRUE)
|
||||
icon_state = "obelisk_prism"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
//Shards of Alloy, suitable only for proselytization.
|
||||
/obj/item/clockwork/alloy_shards
|
||||
name = "replicant alloy shards"
|
||||
desc = "Broken shards of some oddly malleable metal. They occasionally move and seem to glow."
|
||||
clockwork_desc = "Broken shards of replicant alloy. Can be proselytized for additional power."
|
||||
icon_state = "alloy_shards"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/randomsinglesprite = FALSE
|
||||
var/randomspritemax = 2
|
||||
|
||||
/obj/item/clockwork/alloy_shards/New()
|
||||
..()
|
||||
if(randomsinglesprite)
|
||||
replace_name_desc()
|
||||
icon_state = "[icon_state][rand(1, randomspritemax)]"
|
||||
pixel_x = rand(-9, 9)
|
||||
pixel_y = rand(-9, 9)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/proc/replace_name_desc()
|
||||
name = "replicant alloy shard"
|
||||
desc = "A broken shard of some oddly malleable metal. It occasionally moves and seems to glow."
|
||||
clockwork_desc = "A broken shard of replicant alloy. Can be proselytized for additional power."
|
||||
|
||||
/obj/item/clockwork/alloy_shards/large
|
||||
randomsinglesprite = TRUE
|
||||
icon_state = "shard_large"
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium
|
||||
randomsinglesprite = TRUE
|
||||
icon_state = "shard_medium"
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit
|
||||
randomspritemax = 4
|
||||
icon_state = "gear_bit"
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/replace_name_desc()
|
||||
name = "gear bit"
|
||||
desc = "A broken chunk of a gear. You want it."
|
||||
clockwork_desc = "A broken chunk of a gear. Can be proselytized for additional power."
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large //gives more power
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/replace_name_desc()
|
||||
..()
|
||||
name = "complex gear bit"
|
||||
|
||||
/obj/item/clockwork/alloy_shards/small
|
||||
randomsinglesprite = TRUE
|
||||
randomspritemax = 3
|
||||
icon_state = "shard_small"
|
||||
@@ -0,0 +1,219 @@
|
||||
//Clockwork armor: High melee protection but weak to lasers
|
||||
/obj/item/clothing/head/helmet/clockwork
|
||||
name = "clockwork helmet"
|
||||
desc = "A heavy helmet made of brass."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_helmet"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/New()
|
||||
..()
|
||||
ratvar_act()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/ratvar_act()
|
||||
if(ratvar_awakens)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
flags |= STOPSPRESSUREDMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags &= STOPSPRESSUREDMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_head && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their head!</span>", "<span class='warning'>The helmet flickers off your head, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(20, 1, 1, 0, 1)
|
||||
else
|
||||
user << "<span class='heavy_brass'>\"Do you have a hole in your head? You're about to.\"</span>"
|
||||
user << "<span class='userdanger'>The helmet tries to drive a spike through your head as you scramble to remove it!</span>"
|
||||
user.emote("scream")
|
||||
user.apply_damage(30, BRUTE, "head")
|
||||
user.adjustBrainLoss(30)
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround), src, 1) //equipped happens before putting stuff on(but not before picking items up), 1). thus, we need to wait for it to be on before forcing it off.
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork
|
||||
name = "clockwork cuirass"
|
||||
desc = "A bulky cuirass made of brass."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_cuirass"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
body_parts_covered = CHEST|GROIN|LEGS
|
||||
cold_protection = CHEST|GROIN|LEGS
|
||||
heat_protection = CHEST|GROIN|LEGS
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/device/mmi/posibrain/soul_vessel)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/New()
|
||||
..()
|
||||
ratvar_act()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/ratvar_act()
|
||||
if(ratvar_awakens)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
flags |= STOPSPRESSUREDMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags &= STOPSPRESSUREDMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_wear_suit && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their body!</span>", "<span class='warning'>The curiass flickers off your body, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(20, 1, 1, 0, 1)
|
||||
else
|
||||
user << "<span class='heavy_brass'>\"I think this armor is too hot for you to handle.\"</span>"
|
||||
user << "<span class='userdanger'>The curiass emits a burst of flame as you scramble to get it off!</span>"
|
||||
user.emote("scream")
|
||||
user.apply_damage(15, BURN, "chest")
|
||||
user.adjust_fire_stacks(2)
|
||||
user.IgniteMob()
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork
|
||||
name = "clockwork gauntlets"
|
||||
desc = "Heavy, shock-resistant gauntlets with brass reinforcement."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_gauntlets"
|
||||
item_state = "clockwork_gauntlets"
|
||||
item_color = null //So they don't wash.
|
||||
strip_delay = 50
|
||||
put_on_delay = 30
|
||||
body_parts_covered = ARMS
|
||||
cold_protection = ARMS
|
||||
heat_protection = ARMS
|
||||
siemens_coefficient = 0
|
||||
permeability_coefficient = 0.05
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/New()
|
||||
..()
|
||||
ratvar_act()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/ratvar_act()
|
||||
if(ratvar_awakens)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
flags |= STOPSPRESSUREDMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags &= STOPSPRESSUREDMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_gloves && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their arms!</span>", "<span class='warning'>The gauntlets flicker off your arms, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(10, 1, 1, 0, 1)
|
||||
else
|
||||
user << "<span class='heavy_brass'>\"Did you like having arms?\"</span>"
|
||||
user << "<span class='userdanger'>The gauntlets suddenly squeeze tight, crushing your arms before you manage to get them off!</span>"
|
||||
user.emote("scream")
|
||||
user.apply_damage(7, BRUTE, "l_arm")
|
||||
user.apply_damage(7, BRUTE, "r_arm")
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1)
|
||||
|
||||
/obj/item/clothing/shoes/clockwork
|
||||
name = "clockwork treads"
|
||||
desc = "Industrial boots made of brass. They're very heavy."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_treads"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
strip_delay = 50
|
||||
put_on_delay = 30
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/New()
|
||||
..()
|
||||
ratvar_act()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/negates_gravity()
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/ratvar_act()
|
||||
if(ratvar_awakens)
|
||||
flags |= NOSLIP
|
||||
else
|
||||
flags &= NOSLIP
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_shoes && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their feet!</span>", "<span class='warning'>The treads flicker off your feet, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(10, 1, 1, 0, 1)
|
||||
else
|
||||
user << "<span class='heavy_brass'>\"Let's see if you can dance with these.\"</span>"
|
||||
user << "<span class='userdanger'>The treads turn searing hot as you scramble to get them off!</span>"
|
||||
user.emote("scream")
|
||||
user.apply_damage(7, BURN, "l_leg")
|
||||
user.apply_damage(7, BURN, "r_leg")
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1)
|
||||
@@ -0,0 +1,236 @@
|
||||
//Clockwork proselytizer: Converts applicable objects to Ratvarian variants.
|
||||
/obj/item/clockwork/clockwork_proselytizer
|
||||
name = "clockwork proselytizer"
|
||||
desc = "An odd, L-shaped device that hums with energy."
|
||||
clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires power to function."
|
||||
icon_state = "clockwork_proselytizer"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 5
|
||||
flags = NOBLUDGEON
|
||||
var/stored_power = 0 //Requires power to function
|
||||
var/max_power = CLOCKCULT_POWER_UNIT * 10
|
||||
var/uses_power = TRUE
|
||||
var/metal_to_power = FALSE
|
||||
var/repairing = null //what we're currently repairing, if anything
|
||||
var/speed_multiplier = 1 //how fast this proselytizer works
|
||||
var/charge_rate = MIN_CLOCKCULT_POWER //how much power we gain every two seconds
|
||||
var/charge_delay = 2 //how many proccess ticks remain before we can start to charge
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/preloaded
|
||||
stored_power = POWER_WALL_MINUS_FLOOR+POWER_WALL_TOTAL
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/scarab
|
||||
name = "scarab proselytizer"
|
||||
clockwork_desc = "A cogscarab's internal proselytizer. It can only be successfully used by a cogscarab and requires power to function."
|
||||
metal_to_power = TRUE
|
||||
item_state = "nothing"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
speed_multiplier = 0.5
|
||||
charge_rate = MIN_CLOCKCULT_POWER * 2
|
||||
var/debug = FALSE
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/scarab/proselytize(atom/target, mob/living/user)
|
||||
if(!debug && !isdrone(user))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/scarab/debug
|
||||
clockwork_desc = "A cogscarab's internal proselytizer. It can convert nearly any object into a Ratvarian variant."
|
||||
uses_power = FALSE
|
||||
debug = TRUE
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/cyborg
|
||||
name = "cyborg proselytizer"
|
||||
clockwork_desc = "A cyborg's internal proselytizer. It is capable of using the cyborg's power in addition to stored power."
|
||||
metal_to_power = TRUE
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/cyborg/get_power() //returns power and cyborg's power
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
var/borg_power = 0
|
||||
var/current_charge = 0
|
||||
if(istype(R) && R.cell)
|
||||
current_charge = R.cell.charge
|
||||
while(current_charge > MIN_CLOCKCULT_POWER)
|
||||
current_charge -= MIN_CLOCKCULT_POWER
|
||||
borg_power += MIN_CLOCKCULT_POWER
|
||||
return ..() + borg_power
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/cyborg/get_max_power()
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
var/cell_maxcharge = 0
|
||||
if(istype(R) && R.cell)
|
||||
cell_maxcharge = R.cell.maxcharge
|
||||
return ..() + cell_maxcharge
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/cyborg/can_use_power(amount)
|
||||
if(amount != RATVAR_POWER_CHECK)
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
var/current_charge = 0
|
||||
if(istype(R) && R.cell)
|
||||
current_charge = R.cell.charge
|
||||
while(amount > 0 && stored_power - amount < 0) //amount is greater than 0 and stored power minus the amount is still less than 0
|
||||
current_charge -= MIN_CLOCKCULT_POWER
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
if(current_charge < 0)
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/cyborg/modify_stored_power(amount)
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(R) && R.cell && amount)
|
||||
if(amount < 0)
|
||||
while(amount < 0 && stored_power + amount < 0) //amount is less than 0 and stored alloy plus the amount is less than 0
|
||||
R.cell.use(MIN_CLOCKCULT_POWER)
|
||||
amount += MIN_CLOCKCULT_POWER
|
||||
else
|
||||
while(amount > 0 && R.cell.charge + MIN_CLOCKCULT_POWER < R.cell.maxcharge) //amount is greater than 0 and cell charge plus MIN_CLOCKCULT_POWER is less than maximum cell charge
|
||||
R.cell.give(MIN_CLOCKCULT_POWER)
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/process()
|
||||
if(!charge_rate)
|
||||
return
|
||||
var/mob/living/L = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(L) && is_servant_of_ratvar(L))
|
||||
if(charge_delay)
|
||||
charge_delay--
|
||||
return
|
||||
modify_stored_power(charge_rate)
|
||||
for(var/obj/item/clockwork/clockwork_proselytizer/S in L.GetAllContents()) //no multiple proselytizers
|
||||
if(S == src)
|
||||
continue
|
||||
S.charge_delay = 2
|
||||
else
|
||||
charge_delay = 2
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/ratvar_act()
|
||||
if(ratvar_awakens)
|
||||
uses_power = FALSE
|
||||
speed_multiplier = initial(speed_multiplier) * 0.25
|
||||
else
|
||||
uses_power = initial(uses_power)
|
||||
speed_multiplier = initial(speed_multiplier)
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/examine(mob/living/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='brass'>Can be used to convert walls, floors, windows, airlocks, and a variety of other objects to clockwork variants.</span>"
|
||||
user << "<span class='brass'>Can also form some objects into Brass sheets, as well as reform Clockwork Walls into Clockwork Floors, and vice versa.</span>"
|
||||
if(uses_power)
|
||||
if(metal_to_power)
|
||||
user << "<span class='alloy'>It can convert rods, metal, plasteel, and brass to power at rates of <b>1:[POWER_ROD]W</b>, <b>1:[POWER_METAL]W</b>, \
|
||||
<b>1:[POWER_PLASTEEL]W</b>, and <b>1:[POWER_FLOOR]W</b>, respectively.</span>"
|
||||
else
|
||||
user << "<span class='alloy'>It can convert brass to power at a rate of <b>1:[POWER_FLOOR]W</b>.</span>"
|
||||
user << "<span class='alloy'>It is storing <b>[get_power()]W/[get_max_power()]W</b> of power, and is gaining <b>[charge_rate*0.5]W</b> of power per second.</span>"
|
||||
user << "<span class='alloy'>Use it in-hand to produce brass sheets.</span>"
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(!can_use_power(POWER_WALL_TOTAL))
|
||||
user << "<span class='warning'>[src] requires <b>[POWER_WALL_TOTAL]W</b> of power to produce brass sheets!</span>"
|
||||
return
|
||||
modify_stored_power(-POWER_WALL_TOTAL)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new/obj/item/stack/tile/brass(user.loc, 5)
|
||||
user << "<span class='brass'>You user [stored_power ? "some":"all"] of [src]'s power to produce some brass sheets. It now stores <b>[get_power()]W/[get_max_power()]W</b> of power.</span>"
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/pre_attackby(atom/target, mob/living/user, params)
|
||||
if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/weapon/storage))
|
||||
return TRUE
|
||||
return proselytize(target, user)
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/get_power()
|
||||
return stored_power
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/get_max_power()
|
||||
return max_power
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_power(amount)
|
||||
stored_power = Clamp(stored_power + amount, 0, max_power)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/can_use_power(amount)
|
||||
if(amount == RATVAR_POWER_CHECK)
|
||||
if(ratvar_awakens || !uses_power)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
if(stored_power - amount < 0)
|
||||
return FALSE
|
||||
if(stored_power - amount > max_power)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//A note here; return values are for if we CAN BE PUT ON A TABLE, not IF WE ARE SUCCESSFUL, unless no_table_check is TRUE
|
||||
/obj/item/clockwork/clockwork_proselytizer/proc/proselytize(atom/target, mob/living/user, no_table_check)
|
||||
if(!target || !user)
|
||||
return FALSE
|
||||
if(repairing)
|
||||
user << "<span class='warning'>You are currently repairing [repairing] with [src]!</span>"
|
||||
return FALSE
|
||||
var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list
|
||||
if(!islist(proselytize_values))
|
||||
if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason
|
||||
if(!isturf(target)) //otherwise, if we didn't get TRUE and the original target wasn't a turf, try to proselytize the turf
|
||||
return proselytize(get_turf(target), user, no_table_check)
|
||||
user << "<span class='warning'>[target] cannot be proselytized!</span>"
|
||||
if(!no_table_check)
|
||||
return TRUE
|
||||
return FALSE
|
||||
if(can_use_power(RATVAR_POWER_CHECK))
|
||||
proselytize_values["power_cost"] = 0
|
||||
|
||||
var/turf/Y = get_turf(user)
|
||||
if(!Y || (Y.z != ZLEVEL_STATION && Y.z != ZLEVEL_CENTCOM && Y.z != ZLEVEL_MINING && Y.z != ZLEVEL_LAVALAND))
|
||||
proselytize_values["operation_time"] *= 2
|
||||
if(proselytize_values["power_cost"] > 0)
|
||||
proselytize_values["power_cost"] *= 2
|
||||
|
||||
if(!can_use_power(proselytize_values["power_cost"]))
|
||||
if(stored_power - proselytize_values["power_cost"] < 0)
|
||||
user << "<span class='warning'>You need <b>[proselytize_values["power_cost"]]W</b> power to proselytize [target]!</span>"
|
||||
else if(stored_power - proselytize_values["power_cost"] > max_power)
|
||||
user << "<span class='warning'>Your [name] contains too much power to proselytize [target]!</span>"
|
||||
return FALSE
|
||||
|
||||
proselytize_values["operation_time"] *= speed_multiplier
|
||||
|
||||
playsound(target, 'sound/machines/click.ogg', 50, 1)
|
||||
if(proselytize_values["operation_time"])
|
||||
var/target_type = target.type
|
||||
user.visible_message("<span class='warning'>[user]'s [name] begins tearing apart [target]!</span>", "<span class='brass'>You begin proselytizing [target]...</span>")
|
||||
if(!do_after(user, proselytize_values["operation_time"], target = target))
|
||||
return FALSE
|
||||
if(repairing || !can_use_power(proselytize_values["power_cost"]) || !target || target.type != target_type) //Check again to prevent bypassing via spamclick
|
||||
return FALSE
|
||||
user.visible_message("<span class='warning'>[user]'s [name] covers [target] in golden energy!</span>", "<span class='brass'>You proselytize [target].</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user]'s [name] tears apart [target], covering it in golden energy!</span>", "<span class='brass'>You proselytize [target].</span>")
|
||||
|
||||
playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
var/new_thing_type = proselytize_values["new_obj_type"]
|
||||
if(isturf(target))
|
||||
var/turf/T = target
|
||||
T.ChangeTurf(new_thing_type)
|
||||
else
|
||||
if(proselytize_values["dir_in_new"])
|
||||
new new_thing_type(get_turf(target), proselytize_values["spawn_dir"])
|
||||
else
|
||||
var/atom/A = new new_thing_type(get_turf(target))
|
||||
A.setDir(proselytize_values["spawn_dir"])
|
||||
if(!proselytize_values["no_target_deletion"])
|
||||
qdel(target)
|
||||
modify_stored_power(-proselytize_values["power_cost"])
|
||||
if(no_table_check)
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -0,0 +1,508 @@
|
||||
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
|
||||
name = "clockwork slab"
|
||||
desc = "A strange metal tablet. A clock in the center turns around and around."
|
||||
clockwork_desc = "A link between the Celestial Derelict and the mortal plane. Contains limitless knowledge, fabricates components, and outputs a stream of information that only a trained eye can detect.\n\
|
||||
Use the <span class='brass'>Hierophant Network</span> action button to communicate with other servants.\n\
|
||||
Clockwork slabs will only make components if held or if inside an item held by a human, and when making a component will prevent all other slabs held from making components.\n\
|
||||
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
|
||||
icon_state = "dread_ipad"
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/list/stored_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)
|
||||
var/busy //If the slab is currently being used by something
|
||||
var/production_time = 0
|
||||
var/target_component_id //the target component ID to create, if any
|
||||
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
|
||||
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
|
||||
var/nonhuman_usable = FALSE //if the slab can be used by nonhumans, defaults to off
|
||||
var/produces_components = TRUE //if it produces components at all
|
||||
var/selected_scripture = SCRIPTURE_DRIVER
|
||||
var/recollecting = FALSE //if we're looking at fancy recollection
|
||||
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/ranged_ability/geis_prep, /datum/clockwork_scripture/create_object/replicant, \
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache) //quickbound scripture, accessed by index
|
||||
actions_types = list(/datum/action/item_action/clock/hierophant)
|
||||
|
||||
/obj/item/clockwork/slab/starter
|
||||
stored_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
|
||||
/obj/item/clockwork/slab/internal //an internal motor for mobs running scripture
|
||||
name = "scripture motor"
|
||||
quickbound = list()
|
||||
no_cost = TRUE
|
||||
produces_components = FALSE
|
||||
|
||||
/obj/item/clockwork/slab/scarab
|
||||
nonhuman_usable = TRUE
|
||||
|
||||
/obj/item/clockwork/slab/debug
|
||||
speed_multiplier = 0
|
||||
no_cost = TRUE
|
||||
nonhuman_usable = TRUE
|
||||
|
||||
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
|
||||
..()
|
||||
if(!is_servant_of_ratvar(user))
|
||||
add_servant_of_ratvar(user)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and proselytizer
|
||||
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\
|
||||
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
|
||||
nonhuman_usable = TRUE
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache)
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/engineer //five scriptures, plus a proselytizer
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/cogscarab, \
|
||||
/datum/clockwork_scripture/create_object/soul_vessel, /datum/clockwork_scripture/create_object/sigil_of_transmission, /datum/clockwork_scripture/create_object/interdiction_lens)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/medical //five scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, \
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix, /datum/clockwork_scripture/fellowship_armory, /datum/clockwork_scripture/create_object/mending_motor)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/security //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \
|
||||
/datum/clockwork_scripture/channeled/volt_void/cyborg)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/peacekeeper //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \
|
||||
/datum/clockwork_scripture/channeled/volt_void/cyborg)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/janitor //five scriptures, plus a proselytizer
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
|
||||
/datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor, /datum/clockwork_scripture/create_object/tinkerers_daemon)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/service //five scriptures, plus xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/tinkerers_cache, \
|
||||
/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/fellowship_armory, /datum/clockwork_scripture/create_object/clockwork_obelisk)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/miner //three scriptures, plus a spear and xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/channeled/volt_void/cyborg)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/access_display(mob/living/user)
|
||||
user << "<span class='warning'>Use the action buttons to recite your limited set of scripture!</span>"
|
||||
|
||||
/obj/item/clockwork/slab/New()
|
||||
..()
|
||||
update_quickbind()
|
||||
START_PROCESSING(SSobj, src)
|
||||
production_time = world.time + SLAB_PRODUCTION_TIME
|
||||
|
||||
/obj/item/clockwork/slab/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(slab_ability && slab_ability.ranged_ability_user)
|
||||
slab_ability.remove_ranged_ability()
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/slab/ratvar_act()
|
||||
if(ratvar_awakens)
|
||||
nonhuman_usable = TRUE
|
||||
else
|
||||
nonhuman_usable = initial(nonhuman_usable)
|
||||
|
||||
/obj/item/clockwork/slab/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
|
||||
|
||||
/obj/item/clockwork/slab/proc/check_on_mob(mob/user)
|
||||
if(user && !(src in user.held_items) && slab_ability && slab_ability.ranged_ability_user) //if we happen to check and we AREN'T in user's hands, remove whatever ability we have
|
||||
slab_ability.remove_ranged_ability()
|
||||
|
||||
//Component Generation
|
||||
/obj/item/clockwork/slab/process()
|
||||
if(!produces_components)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return
|
||||
if(production_time > world.time)
|
||||
return
|
||||
var/servants = 0
|
||||
var/production_slowdown = 0
|
||||
for(var/mob/living/M in living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
production_slowdown = min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM) //SLAB_SERVANT_SLOWDOWN additional seconds for each servant above 5, up to SLAB_SLOWDOWN_MAXIMUM
|
||||
production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown
|
||||
var/mob/living/L
|
||||
L = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(L) && is_servant_of_ratvar(L) && (nonhuman_usable || ishuman(L)))
|
||||
var/component_to_generate = target_component_id
|
||||
if(!component_to_generate)
|
||||
component_to_generate = get_weighted_component_id(src) //more likely to generate components that we have less of
|
||||
stored_components[component_to_generate]++
|
||||
update_slab_info(src)
|
||||
for(var/obj/item/clockwork/slab/S in L.GetAllContents()) //prevent slab abuse today
|
||||
if(S == src)
|
||||
continue
|
||||
S.production_time = production_time + 50 //set it to our next production plus five seconds, so that if you hold the same slabs, the same one will always generate
|
||||
L << "<span class='warning'>Your slab cl[pick("ank", "ink", "unk", "ang")]s as it produces a </span><span class='[get_component_span(component_to_generate)]'>component</span><span class='warning'>.</span>"
|
||||
|
||||
/obj/item/clockwork/slab/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to quickbound.len)
|
||||
if(!quickbound[i])
|
||||
continue
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
user << "<b>Quickbind</b> button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
|
||||
if(clockwork_caches)
|
||||
user << "<b>Stored components (with global cache):</b>"
|
||||
for(var/i in stored_components)
|
||||
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[stored_components[i]]</b> \
|
||||
(<b>[stored_components[i] + clockwork_component_cache[i]]</b>)</span>"
|
||||
else
|
||||
user << "<b>Stored components:</b>"
|
||||
for(var/i in stored_components)
|
||||
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[stored_components[i]]</b></span>"
|
||||
|
||||
//Component Transferal
|
||||
/obj/item/clockwork/slab/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(is_servant_of_ratvar(user) && is_servant_of_ratvar(target))
|
||||
var/obj/item/clockwork/slab/targetslab
|
||||
var/highest_component_amount = 0
|
||||
for(var/obj/item/clockwork/slab/S in target.GetAllContents())
|
||||
if(!istype(S, /obj/item/clockwork/slab/internal))
|
||||
var/totalcomponents = 0
|
||||
for(var/i in S.stored_components)
|
||||
totalcomponents += S.stored_components[i]
|
||||
if(!targetslab || totalcomponents > highest_component_amount)
|
||||
highest_component_amount = totalcomponents
|
||||
targetslab = S
|
||||
if(targetslab)
|
||||
if(targetslab == src)
|
||||
user << "<span class='heavy_brass'>\"You can't transfer components into your own slab, idiot.\"</span>"
|
||||
else
|
||||
for(var/i in stored_components)
|
||||
targetslab.stored_components[i] += stored_components[i]
|
||||
stored_components[i] = 0
|
||||
update_slab_info(targetslab)
|
||||
update_slab_info(src)
|
||||
user.visible_message("<span class='notice'>[user] empties [src] into [target]'s [targetslab.name].</span>", \
|
||||
"<span class='notice'>You transfer your slab's components into [target]'s [targetslab.name].</span>")
|
||||
else
|
||||
user << "<span class='warning'>[target] has no slabs to transfer components to.</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/slab/attackby(obj/item/I, mob/user, params)
|
||||
var/ratvarian = is_servant_of_ratvar(user)
|
||||
if(istype(I, /obj/item/clockwork/component) && ratvarian)
|
||||
var/obj/item/clockwork/component/C = I
|
||||
if(!C.component_id)
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] inserts [C] into [src].</span>", "<span class='notice'>You insert [C] into [src]\
|
||||
[clockwork_caches ? ", where it is added to the global cache":""].</span>")
|
||||
if(clockwork_caches)
|
||||
clockwork_component_cache[C.component_id]++
|
||||
update_slab_info()
|
||||
else
|
||||
stored_components[C.component_id]++
|
||||
update_slab_info(src)
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab) && ratvarian)
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
for(var/i in stored_components)
|
||||
stored_components[i] += S.stored_components[i]
|
||||
S.stored_components[i] = 0
|
||||
update_slab_info(src)
|
||||
update_slab_info(S)
|
||||
user.visible_message("<span class='notice'>[user] empties [src] into [S].</span>", "<span class='notice'>You transfer your slab's components into [S].</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
//Slab actions; Hierophant, Quickbind
|
||||
/obj/item/clockwork/slab/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/clock/hierophant))
|
||||
show_hierophant(user)
|
||||
else if(istype(action, /datum/action/item_action/clock/quickbind))
|
||||
var/datum/action/item_action/clock/quickbind/Q = action
|
||||
recite_scripture(quickbound[Q.scripture_index], user, FALSE)
|
||||
|
||||
/obj/item/clockwork/slab/proc/show_hierophant(mob/living/user)
|
||||
if(!user.can_speak_vocal())
|
||||
user << "<span class='warning'>You cannot speak into the slab!</span>"
|
||||
return FALSE
|
||||
var/message = stripped_input(user, "Enter a message to send to your fellow servants.", "Hierophant")
|
||||
if(!message || !user || !user.canUseTopic(src) || !user.can_speak_vocal())
|
||||
return FALSE
|
||||
clockwork_say(user, text2ratvar("Servants, hear my words. [html_decode(message)]"), TRUE)
|
||||
titled_hierophant_message(user, message)
|
||||
return TRUE
|
||||
|
||||
//Scripture Recital
|
||||
/obj/item/clockwork/slab/attack_self(mob/living/user)
|
||||
if(iscultist(user))
|
||||
user << "<span class='heavy_brass'>\"You reek of blood. You've got a lot of nerve to even look at that slab.\"</span>"
|
||||
user.visible_message("<span class='warning'>A sizzling sound comes from [user]'s hands!</span>", "<span class='userdanger'>[src] suddenly grows extremely hot in your hands!</span>")
|
||||
playsound(get_turf(user), 'sound/weapons/sear.ogg', 50, 1)
|
||||
user.drop_item()
|
||||
user.emote("scream")
|
||||
user.apply_damage(5, BURN, "l_arm")
|
||||
user.apply_damage(5, BURN, "r_arm")
|
||||
return 0
|
||||
if(!is_servant_of_ratvar(user))
|
||||
user << "<span class='warning'>The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.</span>"
|
||||
user.confused += 5
|
||||
user.dizziness += 5
|
||||
return 0
|
||||
if(busy)
|
||||
user << "<span class='warning'>[src] refuses to work, displaying the message: \"[busy]!\"</span>"
|
||||
return 0
|
||||
if(!nonhuman_usable && !ishuman(user))
|
||||
user << "<span class='nezbere'>[src] hums fitfully in your hands, but doesn't seem to do anything...</span>"
|
||||
return 0
|
||||
access_display(user)
|
||||
|
||||
/obj/item/clockwork/slab/proc/access_display(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return FALSE
|
||||
ui_interact(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clockwork/slab/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = inventory_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "clockwork_slab", name, 800, 420, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //we'll update this occasionally, but not as often as possible
|
||||
ui.set_style("clockwork")
|
||||
ui.open()
|
||||
|
||||
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
|
||||
if(!scripture || !user || !user.canUseTopic(src) || (!nonhuman_usable && !ishuman(user)))
|
||||
return FALSE
|
||||
if(user.get_active_held_item() != src)
|
||||
user << "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>"
|
||||
return FALSE
|
||||
var/initial_tier = initial(scripture.tier)
|
||||
if(initial_tier != SCRIPTURE_PERIPHERAL)
|
||||
var/list/tiers_of_scripture = scripture_unlock_check()
|
||||
if(!ratvar_awakens && !no_cost && !tiers_of_scripture[initial_tier])
|
||||
user << "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>"
|
||||
return FALSE
|
||||
var/datum/clockwork_scripture/scripture_to_recite = new scripture
|
||||
scripture_to_recite.slab = src
|
||||
scripture_to_recite.invoker = user
|
||||
scripture_to_recite.run_scripture()
|
||||
return TRUE
|
||||
|
||||
//Guide to Serving Ratvar
|
||||
/obj/item/clockwork/slab/proc/recollection()
|
||||
var/list/textlist = list("If you're seeing this, file a bug report.")
|
||||
if(ratvar_awakens)
|
||||
textlist = list("<font color=#BE8700 size=3><b>")
|
||||
for(var/i in 1 to 100)
|
||||
textlist += "HONOR RATVAR "
|
||||
textlist += "</b></font>"
|
||||
else
|
||||
var/servants = 0
|
||||
var/production_time = SLAB_PRODUCTION_TIME
|
||||
for(var/mob/living/M in living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
if(servants > 5)
|
||||
servants -= 5
|
||||
production_time += min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM)
|
||||
var/production_text_addon = ""
|
||||
if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM)
|
||||
production_text_addon = ", which increases for each human or silicon servant above <b>[SCRIPT_SERVANT_REQ]</b>"
|
||||
production_time = production_time/600
|
||||
var/production_text = "<b>[round(production_time)] minute\s"
|
||||
if(production_time != round(production_time))
|
||||
production_time -= round(production_time)
|
||||
production_time *= 60
|
||||
production_text += " and [round(production_time, 1)] second\s"
|
||||
production_text += "</b>"
|
||||
production_text += production_text_addon
|
||||
|
||||
textlist = list("<font color=#BE8700 size=3><b><center>Chetr nyy hagehguf-naq-ubabe Ratvar.</center></b></font><br>\
|
||||
\
|
||||
First and foremost, you serve Ratvar, the Clockwork Justicar, in any ways he sees fit. This is with no regard to your personal well-being, and you would do well to think of the larger \
|
||||
scale of things than your life. Ratvar wishes retribution upon those that trapped him in Reebe - the Nar-Sian cultists - and you are to help him obtain it.<br><br>\
|
||||
\
|
||||
Ratvar, being trapped in Reebe, the Celestial Derelict, cannot directly affect the mortal plane. However, links, such as this Clockwork Slab, can be created to draw \
|
||||
<b><font color=#BE8700>Components</font></b>, fragments of the Justicar, from Reebe, and those Components can be used to draw power and material from Reebe through arcane chants \
|
||||
known as <b><font color=#BE8700>Scripture</font></b>.<br><br>\
|
||||
\
|
||||
One component of a random type is made in this slab every [production_text].<br>\
|
||||
<font color=#BE8700>Components</font> are stored either within slabs, where they can only be accessed by that slab, or in the Global Cache accessed by Tinkerer's Caches, which all slabs \
|
||||
can draw from to recite scripture.<br>\
|
||||
There are five types of component, and in general, <font color=#6E001A>Belligerent Eyes</font> are aggressive and judgemental, <font color=#1E8CE1>Vanguard Cogwheels</font> are defensive and \
|
||||
repairing, <font color=#AF0AAF>Geis Capacitors</font> are for conversion and control, <font color=#5A6068>Replicant Alloy</font> is for construction and fuel, and \
|
||||
<font color=#DAAA18>Hierophant Ansibles</font> are for transmission and power, though in combination their effects become more nuanced.<br><br>\
|
||||
\
|
||||
There are also five tiers of <font color=#BE8700>Scripture</font>; <font color=#BE8700>[SCRIPTURE_DRIVER]</font>, <font color=#BE8700>[SCRIPTURE_SCRIPT]</font>, <font color=#BE8700>[SCRIPTURE_APPLICATION]</font>, <font color=#BE8700>[SCRIPTURE_REVENANT]</font>, and <font color=#BE8700>[SCRIPTURE_JUDGEMENT]</font>.<br>\
|
||||
Each tier has additional requirements, including Servants, Tinkerer's Caches, and <b>Construction Value</b>(<b>CV</b>). Construction Value is gained by creating structures or converting the \
|
||||
station, and everything too large to hold will grant some amount of it.<br><br>\
|
||||
\
|
||||
This would be a massive amount of information to try and keep track of, but all Servants have the <b><font color=#BE8700>Global Records</font></b> alert, which appears in the top right.<br>\
|
||||
Mousing over that alert will display Servants, Caches, CV, and other information, such as the tiers of scripture that are unlocked.<br><br>\
|
||||
\
|
||||
On that note, <font color=#BE8700>Scripture</font> is recited through <b><font color=#BE8700>Recital</font></b>, the first and most important function of the slab, \
|
||||
which also allows <b>Quickbinding</b> scripture.<br>\
|
||||
All scripture requires some amount of <font color=#BE8700>Components</font> to recite, and only the weakest scripture does not consume any components when recited.<br>\
|
||||
However, weak is relative when it comes to scripture; even the 'weakest' could be enough to dominate a station in the hands of cunning Servants, and higher tiers of scripture are even \
|
||||
stronger in the right hands.<br><br>\
|
||||
\
|
||||
Some effects of scripture include granting the invoker a temporary complete immunity to stuns, summoning a turret that can attack anything that sets eyes on it, binding a powerful guardian \
|
||||
to the invoker, or even, at one of the highest tiers, granting all nearby Servants temporary invulnerability.<br>\
|
||||
However, the most important scripture is <font color=#AF0AAF>Geis</font>, which allows you to convert heathens with relative ease.<br><br>\
|
||||
\
|
||||
The second function of the clockwork slab is <b><font color=#BE8700>Recollection</font></b>, which will display this guide.<br><br>\
|
||||
\
|
||||
The remaining functions are several buttons in the top left while holding the slab.<br>From left to right, they are:<br>\
|
||||
<b><font color=#DAAA18>Hierophant Network</font></b>, which allows communication to other Servants.<br>")
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to quickbound.len)
|
||||
if(!quickbound[i])
|
||||
continue
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
textlist += "A <b>Quickbind</b> slot, currently set to <b><font color=[get_component_color_bright(initial(quickbind_slot.primary_component))]>[initial(quickbind_slot.name)]</font></b>.<br>"
|
||||
textlist += "<br>\
|
||||
Examine the slab or swap to Recital to check the number of components it has available.<br><br>\
|
||||
\
|
||||
<font color=#BE8700 size=3><b><center>Purge all untruths and honor Ratvar.</center></b></font>"
|
||||
return textlist.Join()
|
||||
|
||||
/obj/item/clockwork/slab/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["components"] = stored_components.Copy()
|
||||
var/list/temp_data = list("<font color=#B18B25>")
|
||||
for(var/i in data["components"])
|
||||
temp_data += "<font color=[get_component_color_bright(i)]>[get_component_acronym(i)] <b>[data["components"][i]]</b></font>"
|
||||
if(i != HIEROPHANT_ANSIBLE)
|
||||
temp_data += " "
|
||||
else
|
||||
temp_data += " ("
|
||||
if(clockwork_caches)
|
||||
for(var/i in clockwork_component_cache)
|
||||
temp_data += "<font color=[get_component_color_bright(i)]>[get_component_acronym(i)] <b>[data["components"][i] + clockwork_component_cache[i]]</b></font>"
|
||||
if(i != HIEROPHANT_ANSIBLE)
|
||||
temp_data += " "
|
||||
else
|
||||
temp_data += "<b>NONE</b>"
|
||||
temp_data += ")</font>"
|
||||
temp_data = temp_data.Join()
|
||||
data["components"] = temp_data
|
||||
|
||||
switch(selected_scripture)
|
||||
if(SCRIPTURE_DRIVER)
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures are always unlocked.</i></font>"
|
||||
if(SCRIPTURE_SCRIPT)
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[SCRIPT_SERVANT_REQ]</b> Servants and <b>[SCRIPT_CACHE_REQ]</b> Tinkerer's Cache.</i></font>"
|
||||
if(SCRIPTURE_APPLICATION)
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[APPLICATION_SERVANT_REQ]</b> Servants, <b>[APPLICATION_CACHE_REQ]</b> Tinkerer's Caches, and <b>[APPLICATION_CV_REQ]CV</b>.</i></font>"
|
||||
if(SCRIPTURE_REVENANT)
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[REVENANT_SERVANT_REQ]</b> Servants, <b>[REVENANT_CACHE_REQ]</b> Tinkerer's Caches, and <b>[REVENANT_CV_REQ]CV</b>.</i></font>"
|
||||
if(SCRIPTURE_JUDGEMENT)
|
||||
data["tier_info"] = "<font color=#B18B25><i>This scripture requires at least <b>[JUDGEMENT_SERVANT_REQ]</b> Servants, <b>[JUDGEMENT_CACHE_REQ]</b> Tinkerer's Caches, and <b>[JUDGEMENT_CV_REQ]CV</b>.<br>In addition, there may not be any active non-Servant AIs.</i></font>"
|
||||
|
||||
data["selected"] = selected_scripture
|
||||
|
||||
data["target_comp"] = "<font color=#B18B25>NONE</font>"
|
||||
if(target_component_id)
|
||||
data["target_comp"] = "<font color=[get_component_color_bright(target_component_id)]>[get_component_acronym(target_component_id)]</font>"
|
||||
|
||||
generate_all_scripture()
|
||||
|
||||
data["scripture"] = list()
|
||||
for(var/s in all_scripture)
|
||||
var/datum/clockwork_scripture/S = s
|
||||
if(S.tier == selected_scripture)
|
||||
var/scripture_color = get_component_color_bright(S.primary_component)
|
||||
var/list/temp_info = list("name" = "<font color=[scripture_color]><b>[S.name]</b></font>",
|
||||
"descname" = "<font color=[scripture_color]>([S.descname])</font>",
|
||||
"tip" = "[S.desc]\n[S.usage_tip]",
|
||||
"required" = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0),
|
||||
"type" = "[S.type]",
|
||||
"quickbind" = S.quickbind)
|
||||
var/found = quickbound.Find(S.type)
|
||||
if(found)
|
||||
temp_info["bound"] = "<b>[found]</b>"
|
||||
if(S.invokers_required > 1)
|
||||
temp_info["invokers"] = "<font color=#B18B25>Invokers: <b>[S.invokers_required]</b></font>"
|
||||
var/costs_components = FALSE
|
||||
for(var/i in S.consumed_components)
|
||||
if(S.consumed_components[i])
|
||||
temp_info["required"][i] += S.consumed_components[i]
|
||||
costs_components = TRUE
|
||||
if(costs_components) //if we have a component cost, we'll need a : next to the recital button
|
||||
var/list/really_temp_data = list(": ")
|
||||
for(var/i in temp_info["required"])
|
||||
if(temp_info["required"][i])
|
||||
really_temp_data += "<font color=[get_component_color_bright(i)]>[get_component_acronym(i)] <b>[temp_info["required"][i]]</b></font> "
|
||||
really_temp_data = really_temp_data.Join()
|
||||
temp_info["required"] = really_temp_data
|
||||
else //and if we don't, we won't.
|
||||
temp_info["required"] = ""
|
||||
data["scripture"] += list(temp_info)
|
||||
data["recollection"] = recollecting
|
||||
if(recollecting)
|
||||
data["rec_text"] = recollection()
|
||||
return data
|
||||
|
||||
/obj/item/clockwork/slab/ui_act(action, params)
|
||||
switch(action)
|
||||
if("toggle")
|
||||
recollecting = !recollecting
|
||||
if("recite")
|
||||
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["category"]), usr, FALSE)
|
||||
if("select")
|
||||
selected_scripture = params["category"]
|
||||
if("component")
|
||||
var/list/components = list("Random Components")
|
||||
for(var/i in clockwork_component_cache)
|
||||
var/cache_components = 0
|
||||
if(clockwork_caches)
|
||||
cache_components = clockwork_component_cache[i]
|
||||
components["[get_component_name(i)] [(cache_components + stored_components[i])]"] = i
|
||||
var/input_component = input("Choose a component type.", "Target Component") as null|anything in components
|
||||
if(input_component && !..())
|
||||
target_component_id = components[input_component]
|
||||
if("bind")
|
||||
var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string
|
||||
var/found_index = quickbound.Find(path)
|
||||
if(found_index) //hey, we already HAVE this bound
|
||||
if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null
|
||||
quickbound -= path
|
||||
else
|
||||
quickbound[found_index] = null //otherwise, leave it as a null so the scripture maintains position
|
||||
update_quickbind()
|
||||
else
|
||||
var/target_index = input("Position of [initial(path.name)], 1 to 5?", "Input") as num|null
|
||||
if(isnum(target_index) && target_index > 0 && target_index < 6 && !..())
|
||||
var/datum/clockwork_scripture/S
|
||||
if(LAZYLEN(quickbound) >= target_index)
|
||||
S = quickbound[target_index]
|
||||
if(S != path)
|
||||
quickbind_to_slot(path, target_index)
|
||||
return 1
|
||||
|
||||
/obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot
|
||||
if(!ispath(scripture) || !scripture || (scripture in quickbound))
|
||||
return
|
||||
while(LAZYLEN(quickbound) < index)
|
||||
quickbound += null
|
||||
quickbound[index] = scripture
|
||||
update_quickbind()
|
||||
|
||||
/obj/item/clockwork/slab/proc/update_quickbind()
|
||||
for(var/datum/action/item_action/clock/quickbind/Q in actions)
|
||||
qdel(Q)
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to quickbound.len)
|
||||
if(!quickbound[i])
|
||||
continue
|
||||
var/datum/action/item_action/clock/quickbind/Q = new /datum/action/item_action/clock/quickbind(src)
|
||||
Q.scripture_index = i
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
Q.name = "[initial(quickbind_slot.name)] ([Q.scripture_index])"
|
||||
Q.desc = initial(quickbind_slot.quickbind_desc)
|
||||
Q.button_icon_state = initial(quickbind_slot.name)
|
||||
Q.UpdateButtonIcon()
|
||||
if(isliving(loc))
|
||||
Q.Grant(loc)
|
||||
@@ -0,0 +1,204 @@
|
||||
//Judicial visor: Grants the ability to smite an area and stun the unfaithful nearby every thirty seconds.
|
||||
/obj/item/clothing/glasses/judicial_visor
|
||||
name = "judicial visor"
|
||||
desc = "A strange purple-lensed visor. Looking at it inspires an odd sense of guilt."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "judicial_visor_0"
|
||||
item_state = "sunglasses"
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flash_protect = 1
|
||||
var/active = FALSE //If the visor is online
|
||||
var/recharging = FALSE //If the visor is currently recharging
|
||||
var/obj/effect/proc_holder/judicial_visor/blaster
|
||||
var/recharge_cooldown = 300 //divided by 10 if ratvar is alive
|
||||
actions_types = list(/datum/action/item_action/clock/toggle_visor)
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/New()
|
||||
..()
|
||||
all_clockwork_objects += src
|
||||
blaster = new(src)
|
||||
blaster.visor = src
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
blaster.visor = null
|
||||
qdel(blaster)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/item_action_slot_check(slot, mob/user)
|
||||
if(slot != slot_glasses)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot != slot_glasses)
|
||||
update_status(FALSE)
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
return 0
|
||||
if(is_servant_of_ratvar(user))
|
||||
update_status(TRUE)
|
||||
else
|
||||
update_status(FALSE)
|
||||
if(iscultist(user)) //Cultists spontaneously combust
|
||||
user << "<span class='heavy_brass'>\"Consider yourself judged, whelp.\"</span>"
|
||||
user << "<span class='userdanger'>You suddenly catch fire!</span>"
|
||||
user.adjust_fire_stacks(5)
|
||||
user.IgniteMob()
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/check_on_mob(mob/user)
|
||||
if(user && src != user.get_item_by_slot(slot_glasses)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
|
||||
update_status(FALSE)
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/attack_self(mob/user)
|
||||
if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(slot_glasses))
|
||||
blaster.toggle(user)
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to)
|
||||
if(recharging || !isliving(loc))
|
||||
icon_state = "judicial_visor_0"
|
||||
return 0
|
||||
if(active == change_to)
|
||||
return 0
|
||||
var/mob/living/L = loc
|
||||
active = change_to
|
||||
icon_state = "judicial_visor_[active]"
|
||||
L.update_action_buttons_icon()
|
||||
L.update_inv_glasses()
|
||||
if(!is_servant_of_ratvar(L) || L.stat)
|
||||
return 0
|
||||
switch(active)
|
||||
if(TRUE)
|
||||
L << "<span class='notice'>As you put on [src], its lens begins to glow, information flashing before your eyes.</span>\n\
|
||||
<span class='heavy_brass'>Judicial visor active. Use the action button to gain the ability to smite the unworthy.</span>"
|
||||
if(FALSE)
|
||||
L << "<span class='notice'>As you take off [src], its lens darkens once more.</span>"
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/recharge_visor(mob/living/user)
|
||||
if(!src)
|
||||
return 0
|
||||
recharging = FALSE
|
||||
if(user && src == user.get_item_by_slot(slot_glasses))
|
||||
user << "<span class='brass'>Your [name] hums. It is ready.</span>"
|
||||
else
|
||||
active = FALSE
|
||||
icon_state = "judicial_visor_[active]"
|
||||
if(user)
|
||||
user.update_action_buttons_icon()
|
||||
user.update_inv_glasses()
|
||||
|
||||
/obj/effect/proc_holder/judicial_visor
|
||||
active = FALSE
|
||||
ranged_mousepointer = 'icons/effects/visor_reticule.dmi'
|
||||
var/obj/item/clothing/glasses/judicial_visor/visor
|
||||
|
||||
/obj/effect/proc_holder/judicial_visor/proc/toggle(mob/user)
|
||||
var/message
|
||||
if(active)
|
||||
message = "<span class='brass'>You dispel the power of [visor].</span>"
|
||||
remove_ranged_ability(message)
|
||||
else
|
||||
message = "<span class='brass'><i>You harness [visor]'s power.</i> <b>Left-click to place a judical marker!</b></span>"
|
||||
add_ranged_ability(user, message)
|
||||
|
||||
/obj/effect/proc_holder/judicial_visor/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return
|
||||
if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(slot_glasses))
|
||||
remove_ranged_ability()
|
||||
return
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return FALSE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
visor.recharging = TRUE
|
||||
visor.update_status()
|
||||
for(var/obj/item/clothing/glasses/judicial_visor/V in ranged_ability_user.GetAllContents())
|
||||
if(V == visor)
|
||||
continue
|
||||
V.recharging = TRUE //To prevent exploiting multiple visors to bypass the cooldown
|
||||
V.update_status()
|
||||
addtimer(CALLBACK(V, /obj/item/clothing/glasses/judicial_visor.proc/recharge_visor, ranged_ability_user), (ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown) * 2)
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Kneel, heathens!"))
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s judicial visor fires a stream of energy at [target], creating a strange mark!</span>", "<span class='heavy_brass'>You direct [visor]'s power to [target]. You must wait for some time before doing this again.</span>")
|
||||
var/turf/targetturf = get_turf(target)
|
||||
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
ranged_ability_user.update_action_buttons_icon()
|
||||
ranged_ability_user.update_inv_glasses()
|
||||
addtimer(CALLBACK(visor, /obj/item/clothing/glasses/judicial_visor.proc/recharge_visor, ranged_ability_user), ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown)//Cooldown is reduced by 10x if Ratvar is up
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Judicial marker: Created by the judicial visor. After three seconds, stuns any non-servants nearby and damages Nar-Sian cultists.
|
||||
/obj/effect/clockwork/judicial_marker
|
||||
name = "judicial marker"
|
||||
desc = "You get the feeling that you shouldn't be standing here."
|
||||
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_MOB_LAYER
|
||||
var/mob/user
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/New(loc, caster)
|
||||
..()
|
||||
SetLuminosity(4, 3)
|
||||
user = caster
|
||||
INVOKE_ASYNC(src, .proc/judicialblast)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/proc/judicialblast()
|
||||
playsound(src, 'sound/magic/MAGIC_MISSILE.ogg', 50, 1, 1, 1)
|
||||
flick("judicial_marker", src)
|
||||
sleep(16)
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
flick("judicial_explosion", src)
|
||||
sleep(13)
|
||||
var/targetsjudged = 0
|
||||
playsound(src, 'sound/effects/explosionfar.ogg', 100, 1, 1, 1)
|
||||
SetLuminosity(0)
|
||||
for(var/mob/living/L in range(1, src))
|
||||
if(is_servant_of_ratvar(L))
|
||||
continue
|
||||
if(L.null_rod_check())
|
||||
var/obj/item/I = L.null_rod_check()
|
||||
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
continue
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
|
||||
L.Weaken(8)
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='heavy_brass'>\"Keep an eye out, filth.\"</span>\n<span class='userdanger'>A burst of heat crushes you against the ground!</span>")
|
||||
L.Weaken(4) //half the stun, but sets cultists on fire
|
||||
L.adjust_fire_stacks(2)
|
||||
L.IgniteMob()
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 6
|
||||
targetsjudged++
|
||||
L.adjustBruteLoss(10)
|
||||
add_logs(user, L, "struck with a judicial blast")
|
||||
user << "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[!targetsjudged || targetsjudged > 1 ? "s":""].</b></span>"
|
||||
sleep(3) //so the animation completes properly
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/ex_act(severity)
|
||||
return
|
||||
@@ -0,0 +1,158 @@
|
||||
//Ratvarian spear: A relatively fragile spear from the Celestial Derelict. Deals extreme damage to silicons and enemy cultists, but doesn't last long when summoned.
|
||||
/obj/item/clockwork/ratvarian_spear
|
||||
name = "ratvarian spear"
|
||||
desc = "A razor-sharp spear made of brass. It thrums with barely-contained energy."
|
||||
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons."
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "ratvarian_spear"
|
||||
item_state = "ratvarian_spear"
|
||||
force = 15 //Extra damage is dealt to targets in attack()
|
||||
throwforce = 40
|
||||
sharpness = IS_SHARP_ACCURATE
|
||||
attack_verb = list("stabbed", "poked", "slashed")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
var/impale_cooldown = 50 //delay, in deciseconds, where you can't impale again
|
||||
var/attack_cooldown = 10 //delay, in deciseconds, where you can't attack with the spear
|
||||
var/timerid
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/New()
|
||||
..()
|
||||
impale_cooldown = 0
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/Destroy()
|
||||
deltimer(timerid)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/ratvar_act()
|
||||
if(ratvar_awakens) //If Ratvar is alive, the spear is extremely powerful
|
||||
force = 25
|
||||
throwforce = 50
|
||||
armour_penetration = 10
|
||||
clockwork_desc = initial(clockwork_desc)
|
||||
deltimer(timerid)
|
||||
else
|
||||
force = initial(force)
|
||||
throwforce = initial(throwforce)
|
||||
armour_penetration = 0
|
||||
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons, though it won't last for long."
|
||||
timerid = addtimer(CALLBACK(src, .proc/break_spear), 600, TIMER_STOPPABLE)
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/cyborg/ratvar_act() //doesn't break!
|
||||
if(ratvar_awakens)
|
||||
force = 25
|
||||
throwforce = 50
|
||||
armour_penetration = 10
|
||||
else
|
||||
force = initial(force)
|
||||
throwforce = initial(throwforce)
|
||||
armour_penetration = 0
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='brass'>Stabbing a human you are pulling or have grabbed with the spear will impale them, doing massive damage and stunning.</span>"
|
||||
if(!iscyborg(user))
|
||||
user << "<span class='brass'>Throwing the spear will do massive damage, break the spear, and stun the target.</span>"
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
var/impaling = FALSE
|
||||
if(attack_cooldown > world.time)
|
||||
user << "<span class='warning'>You can't attack right now, wait [max(round((attack_cooldown - world.time)*0.1, 0.1), 0)] seconds!</span>"
|
||||
return
|
||||
if(user.pulling && ishuman(user.pulling) && user.pulling == target)
|
||||
if(impale_cooldown > world.time)
|
||||
user << "<span class='warning'>You can't impale [target] yet, wait [max(round((impale_cooldown - world.time)*0.1, 0.1), 0)] seconds!</span>"
|
||||
else
|
||||
impaling = TRUE
|
||||
attack_verb = list("impaled")
|
||||
force += 22 //40 damage if ratvar isn't alive, 50 if he is
|
||||
armour_penetration += 10 //if you're impaling someone, armor sure isn't that useful
|
||||
user.stop_pulling()
|
||||
|
||||
if(hitsound)
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
user.lastattacked = target
|
||||
target.lastattacker = user
|
||||
user.do_attack_animation(target)
|
||||
if(!target.attacked_by(src, user)) //TODO MAKE ATTACK() USE PROPER RETURN VALUES
|
||||
impaling = FALSE //if we got blocked, stop impaling
|
||||
else if(!target.null_rod_check())
|
||||
if(issilicon(target))
|
||||
var/mob/living/silicon/S = target
|
||||
if(S.stat != DEAD)
|
||||
S.visible_message("<span class='warning'>[S] shudders violently at [src]'s touch!</span>", "<span class='userdanger'>ERROR: Temperature rising!</span>")
|
||||
S.adjustFireLoss(22)
|
||||
else if(iscultist(target) || isconstruct(target)) //Cultists take extra fire damage
|
||||
var/mob/living/M = target
|
||||
if(M.stat != DEAD)
|
||||
M << "<span class='userdanger'>Your body flares with agony at [src]'s presence!</span>"
|
||||
M.adjustFireLoss(15)
|
||||
else
|
||||
target.adjustFireLoss(3)
|
||||
add_logs(user, target, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
|
||||
add_fingerprint(user)
|
||||
|
||||
attack_verb = list("stabbed", "poked", "slashed")
|
||||
ratvar_act()
|
||||
if(impaling)
|
||||
impale_cooldown = world.time + initial(impale_cooldown)
|
||||
attack_cooldown = world.time + initial(attack_cooldown)
|
||||
if(target)
|
||||
new /obj/effect/overlay/temp/dir_setting/bloodsplatter(get_turf(target), get_dir(user, target))
|
||||
target.Stun(2)
|
||||
user << "<span class='brass'>You prepare to remove your ratvarian spear from [target]...</span>"
|
||||
var/remove_verb = pick("pull", "yank", "drag")
|
||||
if(do_after(user, 10, 1, target))
|
||||
var/turf/T = get_turf(target)
|
||||
var/obj/effect/overlay/temp/dir_setting/bloodsplatter/B = new /obj/effect/overlay/temp/dir_setting/bloodsplatter(T, get_dir(target, user))
|
||||
playsound(T, 'sound/misc/splort.ogg', 200, 1)
|
||||
playsound(T, 'sound/weapons/pierce.ogg', 200, 1)
|
||||
if(target.stat != CONSCIOUS)
|
||||
user.visible_message("<span class='warning'>[user] [remove_verb]s [src] out of [target]!</span>", "<span class='warning'>You [remove_verb] your spear from [target]!</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] kicks [target] off of [src]!</span>", "<span class='warning'>You kick [target] off of [src]!</span>")
|
||||
target << "<span class='userdanger'>You scream in pain as you're kicked off of [src]!</span>"
|
||||
target.emote("scream")
|
||||
step(target, get_dir(user, target))
|
||||
T = get_turf(target)
|
||||
B.forceMove(T)
|
||||
target.Weaken(2)
|
||||
playsound(T, 'sound/weapons/thudswoosh.ogg', 50, 1)
|
||||
flash_color(target, flash_color="#911414", flash_time=8)
|
||||
else if(target) //it's a do_after, we gotta check again to make sure they didn't get deleted
|
||||
user.visible_message("<span class='warning'>[user] [remove_verb]s [src] out of [target]!</span>", "<span class='warning'>You [remove_verb] your spear from [target]!</span>")
|
||||
if(target.stat == CONSCIOUS)
|
||||
target << "<span class='userdanger'>You scream in pain as [src] is suddenly [remove_verb]ed out of you!</span>"
|
||||
target.emote("scream")
|
||||
flash_color(target, flash_color="#911414", flash_time=4)
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/throw_impact(atom/target)
|
||||
var/turf/T = get_turf(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(L.put_in_active_hand(src))
|
||||
L.visible_message("<span class='warning'>[L] catches [src] out of the air!</span>")
|
||||
else
|
||||
L.visible_message("<span class='warning'>[src] bounces off of [L], as if repelled by an unseen force!</span>")
|
||||
else if(!..())
|
||||
if(!L.null_rod_check())
|
||||
if(issilicon(L) || iscultist(L))
|
||||
L.Stun(6)
|
||||
L.Weaken(6)
|
||||
else
|
||||
L.Stun(2)
|
||||
L.Weaken(2)
|
||||
break_spear(T)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/proc/break_spear(turf/T)
|
||||
if(src)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
if(T) //make sure we're not in null or something
|
||||
T.visible_message("<span class='warning'>[src] [pick("cracks in two and fades away", "snaps in two and dematerializes")]!</span>")
|
||||
new /obj/effect/overlay/temp/ratvar/spearbreak(T)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,103 @@
|
||||
//Soul vessel: An ancient positronic brain that serves only Ratvar.
|
||||
/obj/item/device/mmi/posibrain/soul_vessel
|
||||
name = "soul vessel"
|
||||
desc = "A heavy brass cube, three inches to a side, with a single protruding cogwheel."
|
||||
var/clockwork_desc = "A soul vessel, an ancient relic that can attract the souls of the damned or simply rip a mind from an unconscious or dead human.\n\
|
||||
<span class='brass'>If active, can serve as a positronic brain, placable in cyborg shells or clockwork construct shells.</span>"
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "soul_vessel"
|
||||
req_access = list()
|
||||
braintype = "Servant"
|
||||
begin_activation_message = "<span class='brass'>You activate the cogwheel. It hitches and stalls as it begins spinning.</span>"
|
||||
success_message = "<span class='brass'>The cogwheel's rotation smooths out as the soul vessel activates.</span>"
|
||||
fail_message = "<span class='warning'>The cogwheel creaks and grinds to a halt. Maybe you could try again?</span>"
|
||||
new_role = "Soul Vessel"
|
||||
welcome_message = "<span class='warning'>ALL PAST LIVES ARE FORGOTTEN.</span>\n\
|
||||
<b>You are a soul vessel - a clockwork mind created by Ratvar, the Clockwork Justiciar.\n\
|
||||
You answer to Ratvar and his servants. It is your discretion as to whether or not to answer to anyone else.\n\
|
||||
The purpose of your existence is to further the goals of the servants and Ratvar himself. Above all else, serve Ratvar.</b>"
|
||||
new_mob_message = "<span class='brass'>The soul vessel emits a jet of steam before its cogwheel smooths out.</span>"
|
||||
dead_message = "<span class='deadsay'>Its cogwheel, scratched and dented, lies motionless.</span>"
|
||||
fluff_names = list("Judge", "Guard", "Servant", "Smith", "Auger")
|
||||
autoping = FALSE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
force_replace_ai_name = TRUE
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/New()
|
||||
..()
|
||||
radio.on = 0
|
||||
laws = new /datum/ai_laws/ratvar()
|
||||
braintype = picked_fluff_name
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/transfer_personality(mob/candidate)
|
||||
. = ..()
|
||||
if(.)
|
||||
add_servant_of_ratvar(brainmob, TRUE)
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/attack_self(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
user << "<span class='warning'>You fiddle around with [src], to no avail.</span>"
|
||||
return 0
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(!is_servant_of_ratvar(user) || !ishuman(target) || used || (brainmob && brainmob.key))
|
||||
..()
|
||||
if(is_servant_of_ratvar(target))
|
||||
user << "<span class='nezbere'>\"It would be more wise to revive your allies, friend.\"</span>"
|
||||
return
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/obj/item/bodypart/head/HE = H.get_bodypart("head")
|
||||
var/obj/item/organ/brain/B = H.getorgan(/obj/item/organ/brain)
|
||||
if(!HE)
|
||||
user << "<span class='warning'>[H] has no head, and thus no mind!</span>"
|
||||
return
|
||||
if(H.stat == CONSCIOUS)
|
||||
user << "<span class='warning'>[H] must be dead or unconscious for you to claim [H.p_their()] mind!</span>"
|
||||
return
|
||||
if(H.head)
|
||||
var/obj/item/I = H.head
|
||||
if(I.flags_inv & HIDEHAIR)
|
||||
user << "<span class='warning'>[H]'s head is covered, remove [H.head] first!</span>"
|
||||
return
|
||||
if(H.wear_mask)
|
||||
var/obj/item/I = H.wear_mask
|
||||
if(I.flags_inv & HIDEHAIR)
|
||||
user << "<span class='warning'>[H]'s head is covered, remove [H.wear_mask] first!</span>"
|
||||
return
|
||||
if(!B)
|
||||
user << "<span class='warning'>[H] has no brain, and thus no mind to claim!</span>"
|
||||
return
|
||||
if(!H.key)
|
||||
user << "<span class='warning'>[H] has no mind to claim!</span>"
|
||||
return
|
||||
playsound(H, 'sound/misc/splort.ogg', 60, 1, -1)
|
||||
playsound(H, 'sound/magic/clockwork/anima_fragment_attack.ogg', 40, 1, -1)
|
||||
var/prev_fakedeath = (H.status_flags & FAKEDEATH)
|
||||
H.status_flags |= FAKEDEATH //we want to make sure they don't deathgasp and maybe possibly explode
|
||||
H.death()
|
||||
if(!prev_fakedeath)
|
||||
H.status_flags &= ~FAKEDEATH
|
||||
H.apply_status_effect(STATUS_EFFECT_SIGILMARK) //let them be affected by vitality matrices
|
||||
picked_fluff_name = "Slave"
|
||||
braintype = picked_fluff_name
|
||||
brainmob.timeofhostdeath = H.timeofdeath
|
||||
user.visible_message("<span class='warning'>[user] presses [src] to [H]'s head, ripping through the skull and carefully extracting the brain!</span>", \
|
||||
"<span class='brass'>You extract [H]'s consciousness from [H.p_their()] body, trapping it in the soul vessel.</span>")
|
||||
transfer_personality(H)
|
||||
brainmob.fully_replace_character_name(null, "[braintype] [H.real_name]")
|
||||
name = "[initial(name)] ([brainmob.name])"
|
||||
B.Remove(H)
|
||||
qdel(B)
|
||||
H.update_hair()
|
||||
@@ -0,0 +1,168 @@
|
||||
//Wraith spectacles: Grants x-ray and night vision at the eventual cost of the wearer's sight if worn too long. Nar-Sian cultists are instantly blinded.
|
||||
/obj/item/clothing/glasses/wraith_spectacles
|
||||
name = "antique spectacles"
|
||||
desc = "Unnerving glasses with opaque yellow lenses."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "wraith_specs"
|
||||
item_state = "glasses"
|
||||
actions_types = list(/datum/action/item_action/toggle)
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flags_cover = GLASSESCOVERSEYES
|
||||
visor_flags_inv = HIDEEYES
|
||||
visor_vars_to_toggle = NONE //we don't actually toggle anything we just set it
|
||||
tint = 3 //this'll get reset, but it won't handle vision updates properly otherwise
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/New()
|
||||
..()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/attack_self(mob/user)
|
||||
weldingvisortoggle(user)
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/visor_toggling()
|
||||
..()
|
||||
set_vision_vars(FALSE)
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/weldingvisortoggle(mob/user)
|
||||
. = ..()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(src == H.glasses && !up)
|
||||
if(H.disabilities & BLIND)
|
||||
H << "<span class='heavy_brass'>\"You're blind, idiot. Stop embarassing yourself.\"</span>"
|
||||
return
|
||||
if(blind_cultist(H))
|
||||
return
|
||||
if(is_servant_of_ratvar(H))
|
||||
H << "<span class='heavy_brass'>You push the spectacles down, and all is revealed to you.[ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>"
|
||||
var/datum/status_effect/wraith_spectacles/WS = H.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
if(WS)
|
||||
WS.apply_eye_damage(H)
|
||||
H.apply_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
else
|
||||
H << "<span class='heavy_brass'>You push the spectacles down, but you can't see through the glass.</span>"
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/proc/blind_cultist(mob/living/victim)
|
||||
if(iscultist(victim))
|
||||
victim << "<span class='heavy_brass'>\"It looks like Nar-Sie's dogs really don't value their eyes.\"</span>"
|
||||
victim << "<span class='userdanger'>Your eyes explode with horrific pain!</span>"
|
||||
victim.emote("scream")
|
||||
victim.become_blind()
|
||||
victim.adjust_blurriness(30)
|
||||
victim.adjust_blindness(30)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/proc/set_vision_vars(update_vision)
|
||||
invis_view = SEE_INVISIBLE_LIVING
|
||||
tint = 0
|
||||
vision_flags = NONE
|
||||
darkness_view = 2
|
||||
if(!up)
|
||||
if(is_servant_of_ratvar(loc))
|
||||
invis_view = SEE_INVISIBLE_NOLIGHTING
|
||||
vision_flags = SEE_MOBS | SEE_TURFS | SEE_OBJS
|
||||
darkness_view = 3
|
||||
else
|
||||
tint = 3
|
||||
if(update_vision && iscarbon(loc))
|
||||
var/mob/living/carbon/C = loc
|
||||
C.head_update(src, forced = 1)
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot != slot_glasses || up)
|
||||
return
|
||||
if(user.disabilities & BLIND)
|
||||
user << "<span class='heavy_brass'>\"You're blind, idiot. Stop embarassing yourself.\"</span>" //Ratvar with the sick burns yo
|
||||
return
|
||||
if(blind_cultist(user)) //Cultists instantly go blind
|
||||
return
|
||||
set_vision_vars(TRUE)
|
||||
if(is_servant_of_ratvar(user))
|
||||
user << "<span class='heavy_brass'>As you put on the spectacles, all is revealed to you.[ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>"
|
||||
var/datum/status_effect/wraith_spectacles/WS = user.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
if(WS)
|
||||
WS.apply_eye_damage(user)
|
||||
user.apply_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
else
|
||||
user << "<span class='heavy_brass'>You put on the spectacles, but you can't see through the glass.</span>"
|
||||
|
||||
//The effect that causes/repairs the damage the spectacles cause.
|
||||
/datum/status_effect/wraith_spectacles
|
||||
id = "wraith_spectacles"
|
||||
duration = -1 //remains until eye damage done reaches 0 while the glasses are not worn
|
||||
tick_interval = 2
|
||||
alert_type = /obj/screen/alert/status_effect/wraith_spectacles
|
||||
var/eye_damage_done = 0
|
||||
var/nearsight_breakpoint = 30
|
||||
var/blind_breakpoint = 45
|
||||
|
||||
/obj/screen/alert/status_effect/wraith_spectacles
|
||||
name = "Wraith Spectacles"
|
||||
desc = "You shouldn't actually see this, as it should be procedurally generated."
|
||||
icon_state = "wraithspecs"
|
||||
alerttooltipstyle = "clockcult"
|
||||
|
||||
/obj/screen/alert/status_effect/wraith_spectacles/MouseEntered(location,control,params)
|
||||
var/mob/living/carbon/human/L = usr
|
||||
if(istype(L)) //this is probably more safety than actually needed
|
||||
var/datum/status_effect/wraith_spectacles/W = attached_effect
|
||||
var/glasses_right = istype(L.glasses, /obj/item/clothing/glasses/wraith_spectacles)
|
||||
var/obj/item/clothing/glasses/wraith_spectacles/WS = L.glasses
|
||||
desc = "[glasses_right && !WS.up ? "<font color=#DAAA18><b>":""]You are [glasses_right ? "":"not "]wearing wraith spectacles[glasses_right && !WS.up ? "!</b></font>":"."]<br>\
|
||||
You have taken <font color=#DAAA18><b>[W.eye_damage_done]</b></font> eye damage from them.<br>"
|
||||
if(L.disabilities & NEARSIGHT)
|
||||
desc += "<font color=#DAAA18><b>You are nearsighted!</b></font><br>"
|
||||
else if(glasses_right && !WS.up)
|
||||
desc += "You will become nearsighted at <font color=#DAAA18><b>[W.nearsight_breakpoint]</b></font> eye damage.<br>"
|
||||
if(L.disabilities & BLIND)
|
||||
desc += "<font color=#DAAA18><b>You are blind!</b></font>"
|
||||
else if(glasses_right && !WS.up)
|
||||
desc += "You will become blind at <font color=#DAAA18><b>[W.blind_breakpoint]</b></font> eye damage."
|
||||
..()
|
||||
|
||||
/datum/status_effect/wraith_spectacles/on_apply()
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
apply_eye_damage(H)
|
||||
|
||||
/datum/status_effect/wraith_spectacles/tick()
|
||||
if(!ishuman(owner))
|
||||
qdel(src)
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/glasses_right = istype(H.glasses, /obj/item/clothing/glasses/wraith_spectacles)
|
||||
var/obj/item/clothing/glasses/wraith_spectacles/WS = H.glasses
|
||||
if(glasses_right && !WS.up && !ratvar_awakens)
|
||||
apply_eye_damage(H)
|
||||
else
|
||||
if(ratvar_awakens)
|
||||
H.cure_nearsighted()
|
||||
H.cure_blind()
|
||||
H.adjust_eye_damage(-eye_damage_done)
|
||||
eye_damage_done = 0
|
||||
else if(prob(50) && eye_damage_done)
|
||||
H.adjust_eye_damage(-1)
|
||||
eye_damage_done--
|
||||
if(!eye_damage_done)
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
|
||||
if(H.disabilities & BLIND)
|
||||
return
|
||||
H.adjust_eye_damage(1)
|
||||
eye_damage_done++
|
||||
if(eye_damage_done >= 20)
|
||||
H.adjust_blurriness(2)
|
||||
if(eye_damage_done >= nearsight_breakpoint)
|
||||
if(H.become_nearsighted())
|
||||
H << "<span class='nzcrentr'>Your vision doubles, then trebles. Darkness begins to close in. You can't keep this up!</span>"
|
||||
if(eye_damage_done >= blind_breakpoint)
|
||||
if(H.become_blind())
|
||||
H << "<span class='nzcrentr_large'>A piercing white light floods your vision. Suddenly, all goes dark!</span>"
|
||||
if(prob(min(20, 5 + eye_damage_done)))
|
||||
H << "<span class='nzcrentr_small'><i>Your eyes continue to burn.</i></span>"
|
||||
@@ -1,595 +0,0 @@
|
||||
////////////////////////
|
||||
// CLOCKWORK MACHINES //
|
||||
////////////////////////
|
||||
//not-actually-machines
|
||||
|
||||
/obj/structure/clockwork/powered
|
||||
var/obj/machinery/power/apc/target_apc
|
||||
var/active = FALSE
|
||||
var/needs_power = TRUE
|
||||
var/active_icon = null //icon_state while process() is being called
|
||||
var/inactive_icon = null //icon_state while process() isn't being called
|
||||
|
||||
/obj/structure/clockwork/powered/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/powered = total_accessable_power()
|
||||
user << "<span class='[powered ? "brass":"alloy"]'>It has access to [powered == INFINITY ? "INFINITY":"[powered]"]W of power.</span>"
|
||||
|
||||
/obj/structure/clockwork/powered/Destroy()
|
||||
SSfastprocess.processing -= src
|
||||
SSobj.processing -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/powered/process()
|
||||
var/powered = total_accessable_power()
|
||||
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
|
||||
|
||||
/obj/structure/clockwork/powered/proc/toggle(fast_process, mob/living/user)
|
||||
if(user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] [active ? "dis" : "en"]ables [src].</span>", "<span class='brass'>You [active ? "dis" : "en"]able [src].</span>")
|
||||
active = !active
|
||||
if(active)
|
||||
icon_state = active_icon
|
||||
if(fast_process)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
icon_state = inactive_icon
|
||||
if(fast_process)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/proc/total_accessable_power() //how much power we have and can use
|
||||
if(!needs_power || ratvar_awakens)
|
||||
return INFINITY //oh yeah we've got power why'd you ask
|
||||
|
||||
var/power = 0
|
||||
power += accessable_apc_power()
|
||||
power += accessable_sigil_power()
|
||||
return power
|
||||
|
||||
/obj/structure/clockwork/powered/proc/accessable_apc_power()
|
||||
var/power = 0
|
||||
var/area/A = get_area(src)
|
||||
var/area/targetAPCA
|
||||
for(var/obj/machinery/power/apc/APC in apcs_list)
|
||||
var/area/APCA = get_area(APC)
|
||||
if(APCA == A)
|
||||
target_apc = APC
|
||||
if(target_apc)
|
||||
targetAPCA = get_area(target_apc)
|
||||
if(targetAPCA != A)
|
||||
target_apc = null
|
||||
else if(target_apc.cell)
|
||||
var/apccharge = target_apc.cell.charge
|
||||
if(apccharge >= 50)
|
||||
power += apccharge
|
||||
return power
|
||||
|
||||
/obj/structure/clockwork/powered/proc/accessable_sigil_power()
|
||||
var/power = 0
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
|
||||
power += T.power_charge
|
||||
return power
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power
|
||||
if(!needs_power || ratvar_awakens)
|
||||
return 1
|
||||
if(amount <= 0)
|
||||
return 0
|
||||
var/power = total_accessable_power()
|
||||
if(!power || power < amount)
|
||||
return 0
|
||||
return use_power(amount)
|
||||
|
||||
/obj/structure/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it
|
||||
var/sigilpower = accessable_sigil_power()
|
||||
var/list/sigils_in_range = list()
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
|
||||
sigils_in_range |= T
|
||||
while(sigilpower && amount >= 50)
|
||||
for(var/S in sigils_in_range)
|
||||
var/obj/effect/clockwork/sigil/transmission/T = S
|
||||
if(amount >= 50 && T.modify_charge(50))
|
||||
sigilpower -= 50
|
||||
amount -= 50
|
||||
var/apcpower = accessable_apc_power()
|
||||
while(apcpower >= 50 && amount >= 50)
|
||||
if(target_apc.cell.use(50))
|
||||
apcpower -= 50
|
||||
amount -= 50
|
||||
target_apc.update()
|
||||
target_apc.update_icon()
|
||||
else
|
||||
apcpower = 0
|
||||
if(amount)
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
/obj/structure/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils
|
||||
if(amount <= 0)
|
||||
return 0
|
||||
var/list/sigils_in_range = list()
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
|
||||
sigils_in_range |= T
|
||||
if(!sigils_in_range.len)
|
||||
return 0
|
||||
while(amount >= 50)
|
||||
for(var/S in sigils_in_range)
|
||||
var/obj/effect/clockwork/sigil/transmission/T = S
|
||||
if(amount >= 50 && T.modify_charge(-50))
|
||||
amount -= 50
|
||||
return 1
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor //Mending motor: A prism that consumes replicant alloy to repair nearby mechanical servants at a quick rate.
|
||||
name = "mending motor"
|
||||
desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
|
||||
clockwork_desc = "A powerful prism that rapidly repairs nearby mechanical servants and clockwork structures."
|
||||
icon_state = "mending_motor_inactive"
|
||||
active_icon = "mending_motor"
|
||||
inactive_icon = "mending_motor_inactive"
|
||||
construction_value = 20
|
||||
max_health = 150
|
||||
health = 150
|
||||
break_message = "<span class='warning'>The prism collapses with a heavy thud!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards, /obj/item/clockwork/component/vanguard_cogwheel)
|
||||
var/stored_alloy = 0 //2500W = 1 alloy = 100 liquified alloy
|
||||
var/max_alloy = 25000
|
||||
var/mob_cost = 200
|
||||
var/structure_cost = 250
|
||||
var/cyborg_cost = 300
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/prefilled
|
||||
stored_alloy = 2500 //starts with 1 replicant alloy/100 liquified alloy
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/total_accessable_power()
|
||||
. = ..()
|
||||
if(. != INFINITY)
|
||||
. += accessable_alloy_power()
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/proc/accessable_alloy_power()
|
||||
return stored_alloy
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/use_power(amount)
|
||||
var/alloypower = accessable_alloy_power()
|
||||
while(alloypower >= 50 && amount >= 50)
|
||||
stored_alloy -= 50
|
||||
alloypower -= 50
|
||||
amount -= 50
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='alloy'>It contains [stored_alloy*0.04]/[max_alloy*0.04] units of liquified alloy, which is equivalent to [stored_alloy]W/[max_alloy]W of power.</span>"
|
||||
user << "<span class='inathneq_small'>It requires [mob_cost]W to heal clockwork mobs, [structure_cost]W for clockwork structures, and [cyborg_cost]W for cyborgs.</span>"
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/process()
|
||||
if(..() < mob_cost)
|
||||
visible_message("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
|
||||
toggle()
|
||||
return
|
||||
for(var/atom/movable/M in range(5, src))
|
||||
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
var/mob/living/simple_animal/hostile/clockwork/W = M
|
||||
var/fatigued = FALSE
|
||||
if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder))
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/E = M
|
||||
if(E.fatigue)
|
||||
fatigued = TRUE
|
||||
if((!fatigued && W.health == W.maxHealth) || W.stat)
|
||||
continue
|
||||
if(!try_use_power(mob_cost))
|
||||
break
|
||||
W.adjustHealth(-15)
|
||||
else if(istype(M, /obj/structure/clockwork))
|
||||
var/obj/structure/clockwork/C = M
|
||||
if(C.health == C.max_health)
|
||||
continue
|
||||
if(!try_use_power(structure_cost))
|
||||
break
|
||||
C.health = min(C.health + 15, C.max_health)
|
||||
else if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
|
||||
continue
|
||||
if(!try_use_power(cyborg_cost))
|
||||
break
|
||||
S.adjustBruteLoss(-15)
|
||||
S.adjustFireLoss(-15)
|
||||
return 1
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
if(total_accessable_power() < mob_cost)
|
||||
user << "<span class='warning'>[src] needs more power or replicant alloy to function!</span>"
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/clockwork/powered/mending_motor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user))
|
||||
if(stored_alloy + 2500 > max_alloy)
|
||||
user << "<span class='warning'>[src] is too full to accept any more alloy!</span>"
|
||||
return 0
|
||||
user.whisper("Genafzhgr vagb jngre.")
|
||||
user.visible_message("<span class='notice'>[user] liquifies [I] and pours it onto [src].</span>", \
|
||||
"<span class='notice'>You liquify [src] and pour it onto [src], transferring the alloy into its reserves.</span>")
|
||||
stored_alloy = stored_alloy + 2500
|
||||
user.drop_item()
|
||||
qdel(I)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/mania_motor //Mania motor: A pair of antenna that, while active, cause braindamage and hallucinations in nearby human mobs.
|
||||
name = "mania motor"
|
||||
desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion."
|
||||
clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing hallucinations and brain damage as long as it remains powered."
|
||||
icon_state = "mania_motor_inactive"
|
||||
active_icon = "mania_motor"
|
||||
inactive_icon = "mania_motor_inactive"
|
||||
construction_value = 20
|
||||
max_health = 80
|
||||
health = 80
|
||||
break_message = "<span class='warning'>The antenna break off, leaving a pile of shards!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards, /obj/item/clockwork/component/guvax_capacitor/antennae)
|
||||
var/mania_cost = 150
|
||||
var/convert_attempt_cost = 150
|
||||
var/convert_cost = 300
|
||||
|
||||
var/mania_messages = list("\"Tb ahgf.\"", "\"Gnxr n penpx ng penml.\"", "\"Znxr n ovq sbe vafnavgl.\"", "\"Trg xbbxl.\"", "\"Zbir gbjneqf znavn.\"", "\"Orpbzr orjvyqrerq.\"", "\"Jnk jvyq.\"", \
|
||||
"\"Tb ebhaq gur oraq.\"", "\"Ynaq va yhanpl.\"", "\"Gel qrzragvn.\"", "\"Fgevir gb trg n fperj ybbfr.\"")
|
||||
var/compel_messages = list("\"Pbzr pybfre.\"", "\"Nccebnpu gur genafzvggre.\"", "\"Gbhpu gur nagraanr.\"", "\"V nyjnlf unir gb qrny jvgu vqvbgf. Zbir gbjneqf gur znavn zbgbe.\"", \
|
||||
"\"Nqinapr sbejneq naq cynpr lbhe urnq orgjrra gur nagraanr - gun'g'f nyy vg'f tbbq sbe.\"", "\"Vs lbh jrer fznegre, lbh'q or bire urer nyernql.\"", "\"Zbir SBEJNEQ, lbh sbby.\"")
|
||||
var/convert_messages = list("\"Lbh jba'g qb. Tb gb fyrrc juvyr V gryy gur'fr avgjvgf ubj gb pbaireg lbh.\"", "\"Lbh ner vafhssvpvrag. V zhfg vafgehpg gur'fr vqvbgf va gur neg-bs pbairefvba.\"", \
|
||||
"\"Bu-bs pbhefr, fbzrbar jr pna'g pbaireg. Gur'fr freinagf ner sbbyf.\"", "\"Ubj uneq vf vg gb hfr n Fvtvy, naljnl? Nyy vg gnxrf vf qenttvat fbzrbar bagb vg.\"", \
|
||||
"\"Ubj qb gur'l snvy gb hfr n Fvtvy-bs Npprffvba, naljnl?\"", "\"Jul vf vg gun'g nyy freinagf ner guv'f varcg?\"", "\"Vg'f dhvgr yvxryl lbh'yy or fghpx urer sbe n juvyr.\"")
|
||||
var/close_messages = list("\"Jryy, lbh pna'g ernpu gur zbgbe sebz GUR'ER, lbh zbeba.\"", "\"Vagrerfgvat ybpngvba. V'q cersre vs lbh jrag fbzrjurer lbh pbhyq NPGHNYYL GBHPU GUR NAGRAANR!\"", \
|
||||
"\"Nznmvat. Lbh fbzrubj znantrq gb jrqtr lbhefrys fbzrjurer lbh pna'g npghnyyl ernpu gur zbgbe sebz.\"", "\"Fhpu n fubj-bs vqvbpl vf hacnenyyryrq. Creuncf V fubhyq chg lbh ba qvfcynl?\"", \
|
||||
"\"Qvq lbh qb guv'f ba checbfr? V pna'g vzntvar lbh qbvat fb nppvqragnyyl. Bu, jnvg, V pna.\"", "\"Ubj vf vg gun'g fhpu fzneg perngherf pna fgvyy qb fbzrguv'at NF FGHCVQ NF GUV'F!\"")
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/mania_motor/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='sevtug_small'>It requires [mania_cost]W to run, and [convert_attempt_cost + convert_cost]W to convert humans adjecent to it.</span>"
|
||||
|
||||
/obj/structure/clockwork/powered/mania_motor/process()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!..())
|
||||
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
|
||||
playsound(T, 'sound/effects/screech.ogg', 40, 1)
|
||||
toggle(0)
|
||||
return
|
||||
if(try_use_power(mania_cost))
|
||||
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
|
||||
for(var/mob/living/carbon/human/H in view(1, src))
|
||||
if(H.Adjacent(src) && try_use_power(convert_attempt_cost))
|
||||
if(is_eligible_servant(H) && try_use_power(convert_cost))
|
||||
H << "<span class='sevtug'>\"Lbh ner zvar-naq-uvf, abj.\"</span>"
|
||||
H.playsound_local(T, hum, 80, 1)
|
||||
add_servant_of_ratvar(H)
|
||||
else if(!H.stat)
|
||||
if(H.getBrainLoss() >= H.maxHealth)
|
||||
H.Paralyse(5)
|
||||
H << "<span class='sevtug'>[pick(convert_messages)]</span>"
|
||||
else
|
||||
H.adjustBrainLoss(100)
|
||||
H.visible_message("<span class='warning'>[H] reaches out and touches [src].</span>", "<span class='sevtug'>You touch [src] involuntarily.</span>")
|
||||
else
|
||||
visible_message("<span class='warning'>[src]'s antennae fizzle quietly.</span>")
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
for(var/mob/living/carbon/human/H in range(10, src))
|
||||
if(!is_servant_of_ratvar(H) && !H.null_rod_check() && H.stat == CONSCIOUS)
|
||||
var/distance = get_dist(T, get_turf(H))
|
||||
var/falloff_distance = min((110) - distance * 10, 80)
|
||||
var/sound_distance = falloff_distance * 0.5
|
||||
var/targetbrainloss = H.getBrainLoss()
|
||||
var/targethallu = H.hallucination
|
||||
var/targetdruggy = H.druggy
|
||||
if(distance >= 4 && prob(falloff_distance))
|
||||
H << "<span class='sevtug_small'>[pick(mania_messages)]</span>"
|
||||
H.playsound_local(T, hum, sound_distance, 1)
|
||||
switch(distance)
|
||||
if(2 to 3)
|
||||
if(prob(falloff_distance))
|
||||
if(prob(falloff_distance))
|
||||
H << "<span class='sevtug_small'>[pick(mania_messages)]</span>"
|
||||
else
|
||||
H << "<span class='sevtug'>[pick(compel_messages)]</span>"
|
||||
if(targetbrainloss <= 50)
|
||||
H.adjustBrainLoss(50 - targetbrainloss) //got too close had brain eaten
|
||||
if(targetdruggy <= 150)
|
||||
H.adjust_drugginess(11)
|
||||
if(targethallu <= 150)
|
||||
H.hallucination += 11
|
||||
if(4 to 5)
|
||||
if(targetbrainloss <= 50)
|
||||
H.adjustBrainLoss(3)
|
||||
if(targetdruggy <= 120)
|
||||
H.adjust_drugginess(9)
|
||||
if(targethallu <= 120)
|
||||
H.hallucination += 9
|
||||
if(6 to 7)
|
||||
if(targetbrainloss <= 30)
|
||||
H.adjustBrainLoss(2)
|
||||
if(prob(falloff_distance) && targetdruggy <= 90)
|
||||
H.adjust_drugginess(7)
|
||||
else if(targethallu <= 90)
|
||||
H.hallucination += 7
|
||||
if(8 to 9)
|
||||
if(H.getBrainLoss() <= 10)
|
||||
H.adjustBrainLoss(1)
|
||||
if(prob(falloff_distance) && targetdruggy <= 60)
|
||||
H.adjust_drugginess(5)
|
||||
else if(targethallu <= 60)
|
||||
H.hallucination += 5
|
||||
if(10 to INFINITY)
|
||||
if(prob(falloff_distance) && targetdruggy <= 30)
|
||||
H.adjust_drugginess(3)
|
||||
else if(targethallu <= 30)
|
||||
H.hallucination += 3
|
||||
else //if it's a distance of 1 and they can't see it/aren't adjacent or they're on top of it(how'd they get on top of it and still trigger this???)
|
||||
if(targetbrainloss <= 99)
|
||||
if(prob(falloff_distance))
|
||||
if(prob(falloff_distance))
|
||||
H << "<span class='sevtug'>[pick(compel_messages)]</span>"
|
||||
else if(prob(falloff_distance))
|
||||
H << "<span class='sevtug'>[pick(close_messages)]</span>"
|
||||
else
|
||||
H << "<span class='sevtug_small'>[pick(mania_messages)]</span>"
|
||||
H.adjustBrainLoss(99 - targetbrainloss)
|
||||
if(targetdruggy <= 200)
|
||||
H.adjust_drugginess(15)
|
||||
if(targethallu <= 200)
|
||||
H.hallucination += 15
|
||||
|
||||
if(is_servant_of_ratvar(H) && (H.getBrainLoss() || H.hallucination || H.druggy)) //not an else so that newly converted servants are healed of the damage it inflicts
|
||||
H.adjustBrainLoss(-H.getBrainLoss()) //heals servants of braindamage, hallucination, and druggy
|
||||
H.hallucination = 0
|
||||
H.adjust_drugginess(-H.druggy)
|
||||
else
|
||||
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
|
||||
playsound(src, 'sound/effects/screech.ogg', 40, 1)
|
||||
toggle(0)
|
||||
|
||||
/obj/structure/clockwork/powered/mania_motor/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
if(!total_accessable_power() >= mania_cost)
|
||||
user << "<span class='warning'>[src] needs more power to function!</span>"
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/interdiction_lens //Interdiction lens: A powerful artifact that constantly disrupts electronics but, if it fails to find something to disrupt, turns off.
|
||||
name = "interdiction lens"
|
||||
desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers."
|
||||
clockwork_desc = "A powerful totem that constantly disrupts nearby electronics and funnels power into nearby Sigils of Transmission."
|
||||
icon_state = "interdiction_lens"
|
||||
construction_value = 25
|
||||
active_icon = "interdiction_lens_active"
|
||||
inactive_icon = "interdiction_lens"
|
||||
break_message = "<span class='warning'>The lens flares a blinding violet before shattering!</span>"
|
||||
break_sound = 'sound/effects/Glassbr3.ogg'
|
||||
var/recharging = 0 //world.time when the lens was last used
|
||||
var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes
|
||||
var/disabled = FALSE //if it's actually usable
|
||||
var/interdiction_range = 14 //how large an area it drains and disables in
|
||||
var/disrupt_cost = 100 //how much power to use when disabling an object
|
||||
|
||||
/obj/structure/clockwork/powered/interdiction_lens/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='[recharging > world.time ? "nezbere_small":"brass"]'>Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \
|
||||
: "vibrates in place and thrums with power"].</span>"
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='nezbere_small'>It requires [disrupt_cost]W of power for each nearby disruptable electronic.</span>"
|
||||
user << "<span class='nezbere_small'>If it fails to both drain any power and disrupt any electronics, it will disable itself for [round(recharge_time/600, 1)] minutes.</span>"
|
||||
|
||||
/obj/structure/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user)
|
||||
..()
|
||||
if(active)
|
||||
set_light(4,2)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/clockwork/powered/interdiction_lens/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
if(disabled)
|
||||
user << "<span class='warning'>As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back.</span>"
|
||||
return 0
|
||||
if(!total_accessable_power() >= disrupt_cost)
|
||||
user << "<span class='warning'>[src] needs more power to function!</span>"
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/clockwork/powered/interdiction_lens/process()
|
||||
if(recharging > world.time)
|
||||
return
|
||||
if(disabled)
|
||||
visible_message("<span class='warning'>The writhing tendrils return to the gemstone, which begins to glow with power!</span>")
|
||||
flick("interdiction_lens_recharged", src)
|
||||
disabled = FALSE
|
||||
toggle(0)
|
||||
else
|
||||
var/successfulprocess = FALSE
|
||||
var/power_drained = 0
|
||||
var/list/atoms_to_test = list()
|
||||
for(var/A in spiral_range_turfs(interdiction_range, src))
|
||||
var/turf/T = A
|
||||
for(var/M in T)
|
||||
atoms_to_test |= M
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
for(var/M in atoms_to_test)
|
||||
if(istype(M, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/A = M
|
||||
if(A.cell && A.cell.charge)
|
||||
successfulprocess = TRUE
|
||||
playsound(A, "sparks", 50, 1)
|
||||
flick("apc-spark", A)
|
||||
power_drained += min(A.cell.charge, 100)
|
||||
A.cell.charge = max(0, A.cell.charge - 100)
|
||||
if(!A.cell.charge && !A.shorted)
|
||||
A.shorted = 1
|
||||
A.visible_message("<span class='warning'>The [A.name]'s screen blurs with static.</span>")
|
||||
A.update()
|
||||
A.update_icon()
|
||||
else if(istype(M, /obj/machinery/power/smes))
|
||||
var/obj/machinery/power/smes/S = M
|
||||
if(S.charge)
|
||||
successfulprocess = TRUE
|
||||
power_drained += min(S.charge, 500)
|
||||
S.charge = max(0, S.charge - 50000) //SMES units contain too much power and could run an interdiction lens basically forever, or provide power forever
|
||||
if(!S.charge && !S.panel_open)
|
||||
S.panel_open = TRUE
|
||||
S.icon_state = "[initial(S.icon_state)]-o"
|
||||
var/datum/effect_system/spark_spread/spks = new(get_turf(S))
|
||||
spks.set_up(10, 0, get_turf(S))
|
||||
spks.start()
|
||||
S.visible_message("<span class='warning'>[S]'s panel flies open with a flurry of sparks.</span>")
|
||||
S.update_icon()
|
||||
else if(isrobot(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
if(!is_servant_of_ratvar(R) && R.cell && R.cell.charge)
|
||||
successfulprocess = TRUE
|
||||
power_drained += min(R.cell.charge, 200)
|
||||
R.cell.charge = max(0, R.cell.charge - 200)
|
||||
R << "<span class='warning'>ERROR: Power loss detected!</span>"
|
||||
var/datum/effect_system/spark_spread/spks = new(get_turf(R))
|
||||
spks.set_up(3, 0, get_turf(R))
|
||||
spks.start()
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(!return_power(power_drained) || power_drained < 50) //failed to return power drained or too little power to return
|
||||
successfulprocess = FALSE
|
||||
if(try_use_power(disrupt_cost) && total_accessable_power() >= disrupt_cost) //if we can disable at least one object
|
||||
playsound(src, 'sound/items/PSHOOM.ogg', 50, 1, interdiction_range-7, 1)
|
||||
for(var/M in atoms_to_test)
|
||||
if(istype(M, /obj/machinery/light)) //cosmetic light flickering
|
||||
var/obj/machinery/light/L = M
|
||||
if(L.on)
|
||||
playsound(L, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
L.flicker(3)
|
||||
else if(istype(M, /obj/machinery/camera))
|
||||
var/obj/machinery/camera/C = M
|
||||
if(C.isEmpProof() || !C.status)
|
||||
continue
|
||||
successfulprocess = TRUE
|
||||
if(C.emped)
|
||||
continue
|
||||
if(!try_use_power(disrupt_cost))
|
||||
break
|
||||
C.emp_act(1)
|
||||
else if(istype(M, /obj/item/device/radio))
|
||||
var/obj/item/device/radio/O = M
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
if(!try_use_power(disrupt_cost))
|
||||
break
|
||||
O.emp_act(1)
|
||||
else if(isliving(M) || istype(M, /obj/structure/closet) || istype(M, /obj/item/weapon/storage)) //other things may have radios in them but we don't care
|
||||
var/atom/movable/A = M
|
||||
for(var/obj/item/device/radio/O in A.GetAllContents())
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
if(!try_use_power(disrupt_cost))
|
||||
break
|
||||
O.emp_act(1)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(!successfulprocess)
|
||||
visible_message("<span class='warning'>The gemstone suddenly turns horribly dark, writhing tendrils covering it!</span>")
|
||||
recharging = world.time + recharge_time
|
||||
flick("interdiction_lens_discharged", src)
|
||||
icon_state = "interdiction_lens_inactive"
|
||||
set_light(2,1)
|
||||
disabled = TRUE
|
||||
|
||||
|
||||
|
||||
/obj/structure/clockwork/powered/clockwork_obelisk
|
||||
name = "clockwork obelisk"
|
||||
desc = "A large brass obelisk hanging in midair."
|
||||
clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk."
|
||||
icon_state = "obelisk_inactive"
|
||||
active_icon = "obelisk"
|
||||
inactive_icon = "obelisk_inactive"
|
||||
construction_value = 20
|
||||
max_health = 200
|
||||
health = 200
|
||||
break_message = "<span class='warning'>The obelisk falls to the ground, undamaged!</span>"
|
||||
debris = list(/obj/item/clockwork/component/hierophant_ansible/obelisk)
|
||||
var/hierophant_cost = 50 //how much it costs to broadcast with large text
|
||||
var/gateway_cost = 2000 //how much it costs to open a gateway
|
||||
var/gateway_active = FALSE
|
||||
|
||||
/obj/structure/clockwork/powered/clockwork_obelisk/New()
|
||||
..()
|
||||
toggle(1)
|
||||
|
||||
/obj/structure/clockwork/powered/clockwork_obelisk/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='nzcrentr_small'>It requires [hierophant_cost]W to broadcast over the Hierophant Network, and [gateway_cost]W to open a Spatial Gateway.</span>"
|
||||
|
||||
/obj/structure/clockwork/powered/clockwork_obelisk/process()
|
||||
if(locate(/obj/effect/clockwork/spatial_gateway) in loc)
|
||||
icon_state = active_icon
|
||||
density = 0
|
||||
gateway_active = TRUE
|
||||
else
|
||||
icon_state = inactive_icon
|
||||
density = 1
|
||||
gateway_active = FALSE
|
||||
|
||||
/obj/structure/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user) || !total_accessable_power() >= hierophant_cost)
|
||||
user << "<span class='warning'>You place your hand on the obelisk, but it doesn't react.</span>"
|
||||
return
|
||||
var/choice = alert(user,"You place your hand on the obelisk...",,"Hierophant Broadcast","Spatial Gateway","Cancel")
|
||||
switch(choice)
|
||||
if("Hierophant Broadcast")
|
||||
if(gateway_active)
|
||||
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
|
||||
return
|
||||
var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "")
|
||||
if(!input || !user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(gateway_active)
|
||||
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
|
||||
return
|
||||
if(!try_use_power(hierophant_cost))
|
||||
user << "<span class='warning'>The obelisk lacks the power to broadcast!</span>"
|
||||
return
|
||||
clockwork_say(user, "Uvrebcunag Oebnqpnfg, npgvingr!")
|
||||
send_hierophant_message(user, input, "big_brass", "large_brass")
|
||||
if("Spatial Gateway")
|
||||
if(gateway_active)
|
||||
user << "<span class='warning'>The obelisk is already sustaining a gateway!</span>"
|
||||
return
|
||||
if(!try_use_power(gateway_cost))
|
||||
user << "<span class='warning'>The obelisk lacks the power to open a gateway!</span>"
|
||||
return
|
||||
if(procure_gateway(user, 100, 5, 1))
|
||||
clockwork_say(user, "Fcnpvny Tngrjnl, npgvingr!")
|
||||
else
|
||||
return_power(gateway_cost)
|
||||
if("Cancel")
|
||||
return
|
||||
@@ -1,579 +1,51 @@
|
||||
|
||||
//The base for clockwork mobs
|
||||
/mob/living/simple_animal/hostile/clockwork
|
||||
faction = list("ratvar")
|
||||
gender = NEUTER
|
||||
icon = 'icons/mob/clockwork_mobs.dmi'
|
||||
unique_name = 1
|
||||
minbodytemp = 0
|
||||
unsuitable_atmos_damage = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) //Robotic
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
languages_spoken = RATVAR
|
||||
languages_understood = HUMAN|RATVAR
|
||||
healable = FALSE
|
||||
del_on_death = TRUE
|
||||
speak_emote = list("clanks", "clinks", "clunks", "clangs")
|
||||
verb_ask = "requests"
|
||||
verb_exclaim = "proclaims"
|
||||
verb_yell = "harangues"
|
||||
bubble_icon = "clock"
|
||||
death_sound = 'sound/magic/clockwork/anima_fragment_death.ogg'
|
||||
var/playstyle_string = "<span class='heavy_brass'>You are a bug, yell at whoever spawned you!</span>"
|
||||
var/obj/item/clockwork/slab/internalslab //an internal slab for running scripture
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/New()
|
||||
..()
|
||||
internalslab = new/obj/item/clockwork/slab/internal(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/Destroy()
|
||||
qdel(internalslab)
|
||||
internalslab = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/get_spans()
|
||||
return ..() | SPAN_ROBOT
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/Login()
|
||||
..()
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
src << playstyle_string
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment //Anima fragment: Low health and high melee damage, but slows down when struck. Created by inserting a soul vessel into an empty fragment.
|
||||
name = "anima fragment"
|
||||
desc = "An ominous humanoid shell with a spinning cogwheel as its head, lifted by a jet of blazing red flame."
|
||||
icon_state = "anime_fragment"
|
||||
health = 90
|
||||
maxHealth = 90
|
||||
speed = -1
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attacktext = "crushes"
|
||||
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
|
||||
loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment)
|
||||
weather_immunities = list("lava")
|
||||
flying = 1
|
||||
playstyle_string = "<span class='heavy_brass'>You are an anima fragment</span><b>, a clockwork creation of Ratvar. As a fragment, you have low health, do decent damage, and move at \
|
||||
extreme speed in addition to being immune to extreme temperatures and pressures. Taking damage will temporarily slow you down, however. \n Your goal is to serve the Justiciar and his servants \
|
||||
in any way you can. You yourself are one of these servants, and will be able to utilize anything they can, assuming it doesn't require opposable thumbs.</b>"
|
||||
var/movement_delay_time //how long the fragment is slowed after being hit
|
||||
/mob/living/simple_animal/hostile/clockwork/ratvar_act()
|
||||
fully_heal(TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/New()
|
||||
..()
|
||||
set_light(2,1)
|
||||
if(prob(1))
|
||||
name = "anime fragment"
|
||||
real_name = name
|
||||
desc = "I-it's not like I want to show you the light of the Justiciar or anything, B-BAKA!"
|
||||
/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0)
|
||||
return 0 //ouch, my metal-unlikely-to-be-damaged-by-electricity-body
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Stat()
|
||||
..()
|
||||
if(statpanel("Status") && movement_delay_time > world.time && !ratvar_awakens)
|
||||
stat(null, "Movement delay(seconds): [max(round((movement_delay_time - world.time)*0.1, 0.1), 0)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/death(gibbed)
|
||||
visible_message("<span class='warning'>[src]'s flame jets cut out as it falls to the floor with a tremendous crash.</span>", \
|
||||
"<span class='userdanger'>Your gears seize up. Your flame jets flicker out. Your soul vessel belches smoke as you helplessly crash down.</span>")
|
||||
..(TRUE)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/movement_delay()
|
||||
. = ..()
|
||||
if(movement_delay_time > world.time && !ratvar_awakens)
|
||||
. += min((movement_delay_time - world.time) * 0.1, 10) //the more delay we have, the slower we go
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/adjustHealth(amount)
|
||||
. = ..()
|
||||
if(!ratvar_awakens && amount > 0) //if ratvar is up we ignore movement delay
|
||||
if(movement_delay_time > world.time)
|
||||
movement_delay_time = movement_delay_time + amount*3
|
||||
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/msg = "<span class='brass'>*---------*\nThis is \icon[src] \a <b>[src]</b>!\n"
|
||||
msg += "[desc]\n"
|
||||
if(health < maxHealth)
|
||||
msg += "<span class='warning'>"
|
||||
if(health >= maxHealth/2)
|
||||
msg += "[t_He] look[t_s] slightly dented.\n"
|
||||
else
|
||||
movement_delay_time = world.time + amount*3
|
||||
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
|
||||
msg += "</span>"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/updatehealth()
|
||||
..()
|
||||
if(health == maxHealth)
|
||||
speed = initial(speed)
|
||||
else
|
||||
speed = 0 //slow down if damaged at all
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder //Clockwork marauder: Slow but with high damage, resides inside of a servant. Created via the Memory Allocation scripture.
|
||||
name = "clockwork marauder"
|
||||
desc = "A stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
|
||||
icon_state = "clockwork_marauder"
|
||||
health = 300 //Health is very high, and under most cases it will take enough fatigue to be forced to recall first
|
||||
maxHealth = 300
|
||||
speed = 1
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
environment_smash = 1
|
||||
weather_immunities = list("lava")
|
||||
flying = 1
|
||||
loot = list(/obj/item/clockwork/component/replicant_alloy/fallen_armor)
|
||||
var/true_name = "Meme Master 69" //Required to call forth the marauder
|
||||
var/list/possible_true_names = list("Xaven", "Melange", "Ravan", "Kel", "Rama", "Geke", "Peris", "Vestra", "Skiwa") //All fairly short and easy to pronounce
|
||||
var/fatigue = 0 //Essentially what determines the marauder's power
|
||||
var/fatigue_recall_threshold = 100 //In variable form due to changed effects when Ratvar awakens
|
||||
var/mob/living/host //The mob that the marauder is living inside of
|
||||
var/recovering = FALSE //If the marauder is recovering from a large amount of fatigue
|
||||
var/blockchance = 15 //chance to block melee attacks entirely
|
||||
var/counterchance = 30 //chance to counterattack after blocking
|
||||
var/combattimer = 50 //after 5 seconds of not being hit ot attacking we count as 'out of combat' and lose block/counter chance
|
||||
playstyle_string = "<span class='sevtug'>You are a clockwork marauder</span><b>, a living extension of Sevtug's will. As a marauder, you are somewhat slow, but may block melee attacks \
|
||||
and have a chance to also counter blocked melee attacks for extra damage, in addition to being immune to extreme temperatures and pressures. \
|
||||
Your primary goal is to serve the creature that you are now a part of. You can use <span class='sevtug_small'><i>:b</i></span> to communicate silently with your master, \
|
||||
but can only exit if your master calls your true name or if they are exceptionally damaged. \
|
||||
\n\n\
|
||||
Taking damage and remaining outside of your master will cause <i>fatigue</i>, which hinders your movement speed and attacks, in addition to forcing you back into your master if it grows \
|
||||
too high. As a final note, you should probably avoid harming any fellow servants of Ratvar.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/New()
|
||||
..()
|
||||
combattimer = 0
|
||||
true_name = pick(possible_true_names)
|
||||
set_light(2,1)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
if(combattimer < world.time)
|
||||
blockchance = max(blockchance - 5, initial(blockchance))
|
||||
counterchance = max(counterchance - 10, initial(counterchance))
|
||||
if(is_in_host())
|
||||
if(!ratvar_awakens && host.stat == DEAD)
|
||||
death()
|
||||
return
|
||||
adjust_fatigue(-1.5)
|
||||
if(ratvar_awakens)
|
||||
adjustHealth(-5.5)
|
||||
else
|
||||
adjustHealth(-0.5)
|
||||
if(!fatigue && recovering)
|
||||
src << "<span class='userdanger'>Your strength has returned. You can once again come forward!</span>"
|
||||
host << "<span class='userdanger'>Your marauder is now strong enough to come forward again!</span>"
|
||||
recovering = FALSE
|
||||
else
|
||||
if(ratvar_awakens)
|
||||
adjustHealth(-2)
|
||||
else if(host) //If Ratvar is alive, marauders both don't take fatigue loss and move at fast speed
|
||||
if(host.stat == DEAD)
|
||||
death()
|
||||
return
|
||||
if(z && host.z && z == host.z)
|
||||
switch(get_dist(get_turf(src), get_turf(host)))
|
||||
if(2 to 4)
|
||||
adjust_fatigue(1)
|
||||
if(5)
|
||||
adjust_fatigue(3)
|
||||
if(6 to INFINITY)
|
||||
adjust_fatigue(10)
|
||||
src << "<span class='userdanger'>You're too far from your host and rapidly taking fatigue damage!</span>"
|
||||
else //right next to or on top of host
|
||||
adjust_fatigue(-1)
|
||||
else //well then, you're not even in the same zlevel
|
||||
adjust_fatigue(10)
|
||||
src << "<span class='userdanger'>You're too far from your host and rapidly taking fatigue damage!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
//DAMAGE and FATIGUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/update_fatigue()
|
||||
if(!ratvar_awakens && host && host.stat == DEAD)
|
||||
death()
|
||||
return
|
||||
if(ratvar_awakens)
|
||||
speed = 0
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attacktext = "devastates"
|
||||
else
|
||||
switch((fatigue/fatigue_recall_threshold) * 100)
|
||||
if(0 to 10) //Bonuses to speed and damage at normal fatigue levels
|
||||
speed = 0
|
||||
melee_damage_lower = 13
|
||||
melee_damage_upper = 13
|
||||
attacktext = "viciously slashes"
|
||||
if(10 to 25)
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = initial(melee_damage_lower)
|
||||
melee_damage_upper = initial(melee_damage_upper)
|
||||
attacktext = initial(attacktext)
|
||||
if(25 to 50) //Damage decrease, but not speed
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = 7
|
||||
melee_damage_upper = 7
|
||||
attacktext = "lightly slashes"
|
||||
if(50 to 75) //Speed decrease
|
||||
speed = 2
|
||||
melee_damage_lower = 7
|
||||
melee_damage_upper = 7
|
||||
attacktext = "lightly slashes"
|
||||
if(75 to 99) //Massive speed decrease and weak melee attacks
|
||||
speed = 3
|
||||
melee_damage_lower = 4
|
||||
melee_damage_upper = 4
|
||||
attacktext = "weakly slashes"
|
||||
if(99 to 100) //we are at maximum fatigue, we're either useless or recalling
|
||||
if(host)
|
||||
src << "<span class='userdanger'>The fatigue becomes too much!</span>"
|
||||
src << "<span class='userdanger'>You retreat to [host] - you will have to wait before being deployed again.</span>"
|
||||
host << "<span class='userdanger'>[true_name] is too fatigued to fight - you will need to wait until they are strong enough.</span>"
|
||||
recovering = TRUE
|
||||
return_to_host()
|
||||
else
|
||||
speed = 4
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 1
|
||||
attacktext = "taps"
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/death(gibbed)
|
||||
emerge_from_host(0, 1)
|
||||
visible_message("<span class='warning'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
"<span class='userdanger'>Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.</span>")
|
||||
..()
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Fatigue: [fatigue]/[fatigue_recall_threshold]")
|
||||
stat(null, "Current True Name: [true_name]")
|
||||
stat(null, "Host: [host ? host : "NONE"]")
|
||||
if(host)
|
||||
var/resulthealth
|
||||
resulthealth = round((abs(config.health_threshold_dead - host.health) / abs(config.health_threshold_dead - host.maxHealth)) * 100)
|
||||
stat(null, "Host Health: [resulthealth]%")
|
||||
if(ratvar_awakens)
|
||||
stat(null, "You are [recovering ? "un" : ""]able to deploy!")
|
||||
else
|
||||
if(resulthealth > 60)
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "can deploy on hearing your True Name"]!")
|
||||
else
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "can deploy to protect your host"]!")
|
||||
if(ratvar_awakens)
|
||||
stat(null, "Block Chance: 80%")
|
||||
stat(null, "Counter Chance: 80%")
|
||||
else
|
||||
stat(null, "Block Chance: [blockchance]%")
|
||||
stat(null, "Counter Chance: [counterchance]%")
|
||||
stat(null, "You do [melee_damage_upper] damage on melee attacks.")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/adjustHealth(amount) //Fatigue damage
|
||||
var/fatiguedamage = adjust_fatigue(amount)
|
||||
if(amount > 0)
|
||||
combattimer = world.time + initial(combattimer)
|
||||
for(var/mob/living/L in view(2, src))
|
||||
if(istype(L.l_hand, /obj/item/weapon/nullrod) || istype(L.r_hand, /obj/item/weapon/nullrod)) //hand-held holy weapons increase the damage it takes
|
||||
src << "<span class='userdanger'>The presence of a brandished holy artifact weakens your armor!</span>"
|
||||
amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage
|
||||
break
|
||||
return ..() + fatiguedamage
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/adjust_fatigue(amount) //Adds or removes the given amount of fatigue
|
||||
if(status_flags & GODMODE)
|
||||
return 0
|
||||
fatigue = Clamp(fatigue + amount, 0, fatigue_recall_threshold)
|
||||
update_fatigue()
|
||||
return amount
|
||||
|
||||
//ATTACKING, BLOCKING, and COUNTERING
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/AttackingTarget()
|
||||
if(is_in_host())
|
||||
return 0
|
||||
combattimer = world.time + initial(combattimer)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/Proj)
|
||||
if(ratvar_awakens && blockOrCounter(null, Proj))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
|
||||
if(ratvar_awakens && blockOrCounter(null, AM))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder) || !blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_hand(mob/living/carbon/human/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/nullrod) || !blockOrCounter(user, I))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/blockOrCounter(mob/target, atom/textobject)
|
||||
if(ratvar_awakens) //if ratvar has woken, we block nearly everything at a very high chance
|
||||
blockchance = 80
|
||||
counterchance = 80
|
||||
if(prob(blockchance))
|
||||
. = TRUE
|
||||
if(target)
|
||||
target.do_attack_animation(src)
|
||||
target.changeNext_move(CLICK_CD_MELEE)
|
||||
blockchance = initial(blockchance)
|
||||
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 10, 1, 0, 1) //clang
|
||||
visible_message("<span class='boldannounce'>[src] blocks [target && istype(textobject, /obj/item) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>", \
|
||||
"<span class='userdanger'>You block [target && istype(textobject, /obj/item) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>")
|
||||
if(target && prob(counterchance))
|
||||
counterchance = initial(counterchance)
|
||||
var/previousattacktext = attacktext
|
||||
attacktext = "counters"
|
||||
target.attack_animal(src)
|
||||
attacktext = previousattacktext
|
||||
else
|
||||
counterchance = min(counterchance + initial(counterchance), 100)
|
||||
else
|
||||
blockchance = min(blockchance + initial(blockchance), 100)
|
||||
|
||||
//COMMUNICATION and EMERGENCE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
|
||||
..()
|
||||
if(findtext(message, true_name) && is_in_host()) //Called or revealed by hearing their true name
|
||||
if(speaker == host)
|
||||
emerge_from_host(1)
|
||||
else
|
||||
src << "<span class='boldannounce'>You hear your true name and partially emerge before you can stop yourself!</span>"
|
||||
host.visible_message("<span class='warning'>[host]'s skin flashes crimson!</span>", "<span class='boldannounce'>Your marauder instinctively reacts to its true name!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/say(message, message_mode)
|
||||
if(host && (is_in_host() || message_mode == MODE_BINARY))
|
||||
marauder_comms(message)
|
||||
return 1
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/marauder_comms(message)
|
||||
if(host)
|
||||
message = "<span class='sevtug'>Marauder [true_name]:</span> <span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
src << message
|
||||
host << message
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
M << "[link] [message]"
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/proc/talk_with_marauder() //hosts communicate via a verb, marauders just use :b
|
||||
set name = "Linked Minds"
|
||||
set desc = "Silently communicates with your marauder."
|
||||
set category = "Clockwork"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/marauder
|
||||
|
||||
if(!marauder)
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/marauder/C in living_mob_list)
|
||||
if(C.host == src)
|
||||
marauder = C
|
||||
if(!marauder) //Double-check afterwards
|
||||
src << "<span class='warning'>You aren't hosting any marauders!</span>"
|
||||
verbs -= /mob/living/proc/talk_with_marauder
|
||||
return 0
|
||||
var/message = stripped_input(src, "Enter a message to tell your marauder.", "Telepathy")// as null|anything
|
||||
if(!src || !message)
|
||||
return 0
|
||||
if(!marauder)
|
||||
usr << "<span class='warning'>Your marauder seems to have vanished!</span>"
|
||||
return 0
|
||||
message = "<span class='heavy_brass'>Servant [findtextEx(name, real_name) ? "[name]" : "[real_name] (as [name])"]:</span> <span class='brass'>\"[message]\"</span>" //Processed output
|
||||
src << message
|
||||
marauder << message
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
M << "[link] [message]"
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/verb/change_true_name()
|
||||
set name = "Change True Name (One-Use)"
|
||||
set desc = "Changes your true name, used to be called forth."
|
||||
set category = "Marauder"
|
||||
|
||||
verbs -= /mob/living/simple_animal/hostile/clockwork/marauder/verb/change_true_name
|
||||
var/new_name = stripped_input(usr, "Enter a new true name (10-character limit).", "Change True Name","", 11)
|
||||
if(!usr)
|
||||
return 0
|
||||
if(!new_name)
|
||||
usr << "<span class='notice'>You decide against changing your true name for now.</span>"
|
||||
verbs += /mob/living/simple_animal/hostile/clockwork/marauder/verb/change_true_name //If they decide against it, let them have another opportunity
|
||||
return 0
|
||||
true_name = new_name
|
||||
usr << "<span class='heavy_brass'>You have changed your true name to </span><span class='sevtug'>\"[new_name]\"</span><span class='heavy_brass'>!</span>"
|
||||
if(host)
|
||||
host << "<span class='heavy_brass'>Your clockwork marauder has changed their true name to </span><span class='sevtug'>\"[new_name]\"</span><span class='heavy_brass'>!</span>"
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/verb/return_to_host()
|
||||
set name = "Return to Host"
|
||||
set desc = "Recalls yourself to your host, assuming you aren't already there."
|
||||
set category = "Marauder"
|
||||
|
||||
if(is_in_host())
|
||||
return 0
|
||||
if(!host)
|
||||
src << "<span class='warning'>You don't have a host!</span>"
|
||||
verbs -= /mob/living/simple_animal/hostile/clockwork/marauder/verb/return_to_host
|
||||
return 0
|
||||
host.visible_message("<span class='warning'>[host]'s skin flashes crimson!</span>", "<span class='heavy_brass'>You feel [true_name]'s consciousness settle in your mind.</span>")
|
||||
visible_message("<span class='warning'>[src] suddenly disappears!</span>", "<span class='heavy_brass'>You return to [host].</span>")
|
||||
forceMove(host)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/verb/try_emerge()
|
||||
set name = "Attempt to Emerge from Host"
|
||||
set desc = "Attempts to emerge from your host, likely to only work if your host is very heavily damaged."
|
||||
set category = "Marauder"
|
||||
|
||||
if(!host)
|
||||
src << "<span class='warning'>You don't have a host!</span>"
|
||||
verbs -= /mob/living/simple_animal/hostile/clockwork/marauder/verb/try_emerge
|
||||
return 0
|
||||
var/resulthealth
|
||||
resulthealth = round((abs(config.health_threshold_dead - host.health) / abs(config.health_threshold_dead - host.maxHealth)) * 100)
|
||||
if(!ratvar_awakens && host.stat != DEAD && resulthealth > 60) //if above 20 health, fails
|
||||
src << "<span class='warning'>Your host must be at 60% or less health to emerge like this!</span>"
|
||||
return
|
||||
return emerge_from_host(0)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/emerge_from_host(hostchosen, force) //Notice that this is a proc rather than a verb - marauders can NOT exit at will, but they CAN return
|
||||
if(!is_in_host())
|
||||
return 0
|
||||
if(!force && recovering)
|
||||
if(hostchosen)
|
||||
host << "<span class='heavy_brass'>[true_name] is too weak to come forth!</span>"
|
||||
else
|
||||
host << "<span class='heavy_brass'>[true_name] tries to emerge to protect you, but it's too weak!</span>"
|
||||
src << "<span class='userdanger'>You try to come forth, but you're too weak!</span>"
|
||||
return 0
|
||||
if(hostchosen) //marauder approved
|
||||
host << "<span class='heavy_brass'>Your words echo with power as [true_name] emerges from your body!</span>"
|
||||
else
|
||||
host << "<span class='heavy_brass'>[true_name] emerges from your body to protect you!</span>"
|
||||
forceMove(get_turf(host))
|
||||
visible_message("<span class='warning'>[host]'s skin glows red as [name] emerges from their body!</span>", "<span class='brass'>You exit the safety of [host]'s body!</span>")
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/is_in_host() //Checks if the marauder is inside of their host
|
||||
return host && loc == host
|
||||
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/reclaimer
|
||||
name = "clockwork reclaimer"
|
||||
desc = "A tiny clockwork arachnid with a single cogwheel spinning quickly in its head. Its legs blur, too fast to be seen clearly."
|
||||
icon_state = "clockwork_reclaimer"
|
||||
health = 50
|
||||
maxHealth = 50
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attacktext = "slams into"
|
||||
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
|
||||
ventcrawler = 2
|
||||
playstyle_string = "<span class='heavy_brass'>You are a clockwork reclaimer</span><b>, a harbringer of the Justiciar's light. You can crawl through vents to move more swiftly. Your \
|
||||
goal: purge all untruths and honor Ratvar. You may alt-click a valid target to break yourself apart and convert the target to a servant of Ratvar.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/reclaimer/New()
|
||||
..()
|
||||
if(prob(1))
|
||||
real_name = "jehovah's witness"
|
||||
name = real_name
|
||||
spawn(1)
|
||||
if(mind)
|
||||
mind.special_role = null
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
src << playstyle_string
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/reclaimer/Life()
|
||||
..()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/L = loc
|
||||
if(L.stat || !L.client)
|
||||
disengage()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/reclaimer/death()
|
||||
..(1)
|
||||
visible_message("<span class='warning'>[src] bursts into deadly shrapnel!</span>")
|
||||
for(var/mob/living/carbon/C in range(2, src))
|
||||
C.adjustBruteLoss(rand(3, 5))
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/reclaimer/AltClickOn(atom/movable/A)
|
||||
if(!ishuman(A))
|
||||
return ..()
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(is_servant_of_ratvar(H) || H.stat || (H.mind && !H.client))
|
||||
src << "<span class='warning'>[H] isn't a valid target! Valid targets are conscious non-servants.</span>"
|
||||
return 0
|
||||
if(get_dist(src, H) > 3)
|
||||
src << "<span class='warning'>You need to be closer to dominate [H]!</span>"
|
||||
return 0
|
||||
visible_message("<span class='warning'>[src] rockets with blinding speed towards [H]!</span>", "<span class='heavy_brass'>You leap with blinding speed towards [H]'s head!</span>")
|
||||
for(var/i = 9, i > 0, i -= 3)
|
||||
pixel_y += i
|
||||
sleep(1)
|
||||
icon_state = "[initial(icon_state)]_charging"
|
||||
while(loc != H.loc)
|
||||
if(!H)
|
||||
icon_state = initial(icon_state)
|
||||
return 0
|
||||
sleep(1)
|
||||
forceMove(get_step(src, get_dir(src, H)))
|
||||
if(H.head)
|
||||
H.visible_message("<span class='warning'>[src] tears apart [H]'s [H.name]!</span>")
|
||||
H.unEquip(H.head)
|
||||
qdel(H.head)
|
||||
H.visible_message("<span class='warning'>[src] latches onto [H]'s head and digs its claws in!</span>", "<span class='userdanger'>[src] leaps onto your head and impales its claws deep!</span>")
|
||||
add_servant_of_ratvar(H)
|
||||
H.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork/reclaimer(null), slot_head)
|
||||
loc = H
|
||||
icon_state = initial(icon_state)
|
||||
status_flags += GODMODE
|
||||
src << "<span class='userdanger'>ASSIMILATION SUCCESSFUL.</span>"
|
||||
H << "<span class='userdanger'>ASSIMILATION SUCCESSFUL.</span>"
|
||||
clockwork_say(H, rot13("ASSIMILATION SUCCESSFUL."))
|
||||
if(!H.mind)
|
||||
mind.transfer_to(H)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/reclaimer/verb/disengage()
|
||||
set name = "Disgengage From Host"
|
||||
set desc = "Jumps off of your host if you have one, freeing their mind but allowing you movement."
|
||||
set category = "Clockwork"
|
||||
|
||||
if(!ishuman(usr.loc))
|
||||
usr << "<span class='warning'>You have no host! Alt-click on a non-servant to enslave them.</span>"
|
||||
return
|
||||
var/mob/living/carbon/human/L = usr.loc
|
||||
usr.loc = get_turf(L)
|
||||
pixel_y = initial(pixel_y)
|
||||
usr.visible_message("<span class='warning'>[usr] jumps off of [L]'s head!</span>", "<span class='notice'>You disengage from your host.</span>")
|
||||
usr.status_flags -= GODMODE
|
||||
remove_servant_of_ratvar(L)
|
||||
L.unEquip(L.head)
|
||||
qdel(L.head)
|
||||
|
||||
|
||||
|
||||
/mob/living/mind_control_holder
|
||||
name = "imprisoned mind"
|
||||
desc = "A helpless mind, imprisoned in its own body."
|
||||
stat = 0
|
||||
status_flags = GODMODE
|
||||
|
||||
/mob/living/mind_control_holder/say()
|
||||
return 0
|
||||
user << msg
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//Anima fragment: Low health and high melee damage, but slows down when struck. Created by inserting a soul vessel into an empty fragment.
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment
|
||||
name = "anima fragment"
|
||||
desc = "An ominous humanoid shell with a spinning cogwheel as its head, lifted by a jet of blazing red flame."
|
||||
icon_state = "anime_fragment"
|
||||
health = 90
|
||||
maxHealth = 90
|
||||
speed = -1
|
||||
melee_damage_lower = 18
|
||||
melee_damage_upper = 18
|
||||
attacktext = "crushes"
|
||||
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
|
||||
loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment)
|
||||
weather_immunities = list("lava")
|
||||
movement_type = FLYING
|
||||
playstyle_string = "<span class='heavy_brass'>You are an anima fragment</span><b>, a clockwork creation of Ratvar. As a fragment, you have low health, do decent damage, and move at \
|
||||
extreme speed in addition to being immune to extreme temperatures and pressures. Taking damage will temporarily slow you down, however. \n Your goal is to serve the Justiciar and his servants \
|
||||
in any way you can. You yourself are one of these servants, and will be able to utilize anything they can, assuming it doesn't require opposable thumbs.</b>"
|
||||
var/movement_delay_time //how long the fragment is slowed after being hit
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/New()
|
||||
..()
|
||||
SetLuminosity(2,1)
|
||||
if(prob(1))
|
||||
name = "anime fragment"
|
||||
desc = "I-it's not like I want to show you the light of the Justiciar or anything, B-BAKA!"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Stat()
|
||||
..()
|
||||
if(statpanel("Status") && movement_delay_time > world.time && !ratvar_awakens)
|
||||
stat(null, "Movement delay(seconds): [max(round((movement_delay_time - world.time)*0.1, 0.1), 0)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/death(gibbed)
|
||||
visible_message("<span class='warning'>[src]'s flame jets cut out as it falls to the floor with a tremendous crash.</span>", \
|
||||
"<span class='userdanger'>Your gears seize up. Your flame jets flicker out. Your soul vessel belches smoke as you helplessly crash down.</span>")
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/emp_act(severity)
|
||||
if(movement_delay_time > world.time)
|
||||
movement_delay_time = movement_delay_time + (50/severity)
|
||||
else
|
||||
movement_delay_time = world.time + (50/severity)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/movement_delay()
|
||||
. = ..()
|
||||
if(movement_delay_time > world.time && !ratvar_awakens)
|
||||
. += min((movement_delay_time - world.time) * 0.1, 10) //the more delay we have, the slower we go
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/adjustHealth(amount)
|
||||
. = ..()
|
||||
if(!ratvar_awakens && amount > 0) //if ratvar is up we ignore movement delay
|
||||
if(movement_delay_time > world.time)
|
||||
movement_delay_time = movement_delay_time + amount*2.5
|
||||
else
|
||||
movement_delay_time = world.time + amount*2.5
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/updatehealth()
|
||||
..()
|
||||
if(health == maxHealth)
|
||||
speed = initial(speed)
|
||||
else
|
||||
speed = 0 //slow down if damaged at all
|
||||
@@ -0,0 +1,428 @@
|
||||
//Clockwork marauder: Slow but with high damage, resides inside of a servant. Created via the Memory Allocation scripture.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder
|
||||
name = "clockwork marauder"
|
||||
desc = "A stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
|
||||
icon_state = "clockwork_marauder"
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
speed = 1
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 12
|
||||
melee_damage_upper = 12
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
weather_immunities = list("lava")
|
||||
movement_type = FLYING
|
||||
loot = list(/obj/item/clockwork/component/replicant_alloy/fallen_armor)
|
||||
var/true_name = "Meme Master 69" //Required to call forth the marauder
|
||||
var/global/list/possible_true_names = list("Servant", "Warden", "Serf", "Page", "Usher", "Knave", "Vassal", "Escort")
|
||||
var/mob/living/host //The mob that the marauder is living inside of
|
||||
var/recovering = FALSE //If the marauder is recovering from recalling
|
||||
var/blockchance = 17 //chance to block attacks entirely
|
||||
var/counterchance = 30 //chance to counterattack after blocking
|
||||
var/static/list/damage_heal_order = list(OXY, BURN, BRUTE, TOX) //we heal our host's damage in this order
|
||||
playstyle_string = "<span class='sevtug'>You are a clockwork marauder</span><b>, a living extension of Sevtug's will. As a marauder, you are somewhat slow, but may block attacks, \
|
||||
and have a chance to also counter blocked melee attacks for extra damage, in addition to being immune to extreme temperatures and pressures. \
|
||||
Your primary goal is to serve the creature that you are now a part of. You can use <span class='sevtug_small'><i>:b</i></span> to communicate silently with your master, \
|
||||
but can only exit if your master calls your true name or if they are exceptionally damaged. \
|
||||
\n\n\
|
||||
Stay near your host to protect and heal them; being too far from your host will rapidly cause you massive damage. Recall to your host if you are too weak and believe you cannot continue \
|
||||
fighting safely. As a final note, you should probably avoid harming any fellow servants of Ratvar.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/New()
|
||||
..()
|
||||
true_name = pick(possible_true_names)
|
||||
SetLuminosity(2,1)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
if(is_in_host())
|
||||
if(!is_servant_of_ratvar(host))
|
||||
emerge_from_host(FALSE, TRUE)
|
||||
unbind_from_host()
|
||||
return
|
||||
if(!ratvar_awakens && host.stat == DEAD)
|
||||
death()
|
||||
return
|
||||
if(ratvar_awakens)
|
||||
adjustHealth(-50)
|
||||
else
|
||||
adjustHealth(-10)
|
||||
if(!recovering)
|
||||
heal_host() //also heal our host if inside of them and we aren't recovering
|
||||
else if(health == maxHealth)
|
||||
src << "<span class='userdanger'>Your strength has returned. You can once again come forward!</span>"
|
||||
host << "<span class='userdanger'>Your marauder is now strong enough to come forward again!</span>"
|
||||
recovering = FALSE
|
||||
else
|
||||
if(ratvar_awakens) //If Ratvar is alive, marauders don't need a host and are downright impossible to kill
|
||||
adjustHealth(-5)
|
||||
heal_host()
|
||||
else if(host)
|
||||
if(!is_servant_of_ratvar(host))
|
||||
unbind_from_host()
|
||||
return
|
||||
if(host.stat == DEAD)
|
||||
adjustHealth(50)
|
||||
src << "<span class='userdanger'>Your host is dead!</span>"
|
||||
return
|
||||
if(z && host.z && z == host.z)
|
||||
switch(get_dist(get_turf(src), get_turf(host)))
|
||||
if(2)
|
||||
adjustHealth(-1)
|
||||
if(3)
|
||||
//EQUILIBRIUM
|
||||
if(4)
|
||||
adjustHealth(1)
|
||||
if(5)
|
||||
adjustHealth(3)
|
||||
if(6)
|
||||
adjustHealth(6)
|
||||
if(7)
|
||||
adjustHealth(9)
|
||||
if(8 to INFINITY)
|
||||
adjustHealth(15)
|
||||
src << "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>"
|
||||
else //right next to or on top of host
|
||||
adjustHealth(-2)
|
||||
heal_host() //gradually heal host if nearby and host is very weak
|
||||
else //well then, you're not even in the same zlevel
|
||||
adjustHealth(15)
|
||||
src << "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/death(gibbed)
|
||||
emerge_from_host(FALSE, TRUE)
|
||||
unbind_from_host()
|
||||
visible_message("<span class='warning'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
"<span class='userdanger'>Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.</span>")
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Current True Name: [true_name]")
|
||||
stat(null, "Host: [host ? host : "NONE"]")
|
||||
if(host)
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
stat(null, "Host Health: [resulthealth]%")
|
||||
if(ratvar_awakens)
|
||||
stat(null, "You are [recovering ? "un" : ""]able to deploy!")
|
||||
else
|
||||
if(resulthealth > MARAUDER_EMERGE_THRESHOLD)
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy on hearing your True Name"]!")
|
||||
else
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy to protect your host"]!")
|
||||
stat(null, "You do [melee_damage_upper] damage on melee attacks.")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/bind_to_host(mob/living/new_host)
|
||||
if(!new_host)
|
||||
return FALSE
|
||||
host = new_host
|
||||
var/datum/action/innate/summon_marauder/SM = new()
|
||||
SM.linked_marauder = src
|
||||
SM.Grant(host)
|
||||
var/datum/action/innate/linked_minds/LM = new()
|
||||
LM.linked_marauder = src
|
||||
LM.Grant(host)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/unbind_from_host()
|
||||
if(host)
|
||||
for(var/datum/action/innate/summon_marauder/SM in host.actions)
|
||||
qdel(SM)
|
||||
for(var/datum/action/innate/linked_minds/LM in host.actions)
|
||||
qdel(LM)
|
||||
host = null
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//DAMAGE and FATIGUE
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/heal_host()
|
||||
if(!host)
|
||||
return
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
if(ratvar_awakens || resulthealth <= MARAUDER_EMERGE_THRESHOLD)
|
||||
new /obj/effect/overlay/temp/heal(host.loc, "#AF0AAF")
|
||||
host.heal_ordered_damage(4, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(amount > 0)
|
||||
for(var/mob/living/L in view(2, src))
|
||||
if(L.is_holding_item_of_type(/obj/item/weapon/nullrod))
|
||||
src << "<span class='userdanger'>The presence of a brandished holy artifact weakens your armor!</span>"
|
||||
amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage
|
||||
break
|
||||
. = ..()
|
||||
if(src && updating_health)
|
||||
update_health_hud()
|
||||
update_stats()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/update_health_hud()
|
||||
if(hud_used && hud_used.healths)
|
||||
if(istype(hud_used, /datum/hud/marauder))
|
||||
var/datum/hud/marauder/M = hud_used
|
||||
var/resulthealth
|
||||
if(host)
|
||||
if(iscarbon(host))
|
||||
resulthealth = "[round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)]%"
|
||||
else
|
||||
resulthealth = "[round((host.health / host.maxHealth) * 100, 0.5)]%"
|
||||
else
|
||||
resulthealth = "NONE"
|
||||
M.hosthealth.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>HOST<br>[resulthealth]</font></div>"
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>[round((health / maxHealth) * 100, 0.5)]%</font>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/update_stats()
|
||||
if(ratvar_awakens)
|
||||
speed = 0
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attacktext = "devastates"
|
||||
else
|
||||
var/healthpercent = (health/maxHealth) * 100
|
||||
switch(healthpercent)
|
||||
if(100 to 70) //Bonuses to speed and damage at high health
|
||||
speed = 0
|
||||
melee_damage_lower = 16
|
||||
melee_damage_upper = 16
|
||||
attacktext = "viciously slashes"
|
||||
if(70 to 40)
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = initial(melee_damage_lower)
|
||||
melee_damage_upper = initial(melee_damage_upper)
|
||||
attacktext = initial(attacktext)
|
||||
if(40 to 30) //Damage decrease, but not speed
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attacktext = "lightly slashes"
|
||||
if(30 to 20) //Speed decrease
|
||||
speed = 2
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 8
|
||||
attacktext = "lightly slashes"
|
||||
if(20 to 10) //Massive speed decrease and weak melee attacks
|
||||
speed = 3
|
||||
melee_damage_lower = 6
|
||||
melee_damage_upper = 6
|
||||
attacktext = "weakly slashes"
|
||||
if(10 to 0) //We are super weak and going to die
|
||||
speed = 4
|
||||
melee_damage_lower = 4
|
||||
melee_damage_upper = 4
|
||||
attacktext = "taps"
|
||||
|
||||
//ATTACKING, BLOCKING, and COUNTERING
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/AttackingTarget()
|
||||
if(is_in_host())
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/Proj)
|
||||
if(blockOrCounter(null, Proj))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
|
||||
if(blockOrCounter(null, AM))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder) || !blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_hand(mob/living/carbon/human/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/nullrod) || !blockOrCounter(user, I))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/blockOrCounter(mob/target, atom/textobject)
|
||||
if(ratvar_awakens) //if ratvar has woken, we block nearly everything at a very high chance
|
||||
blockchance = 90
|
||||
counterchance = 90
|
||||
if(prob(blockchance))
|
||||
. = TRUE
|
||||
if(target)
|
||||
target.do_attack_animation(src)
|
||||
target.changeNext_move(CLICK_CD_MELEE)
|
||||
blockchance = initial(blockchance)
|
||||
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 30, 1, 0, 1) //clang
|
||||
visible_message("<span class='boldannounce'>[src] blocks [target && istype(textobject, /obj/item) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>", \
|
||||
"<span class='userdanger'>You block [target && istype(textobject, /obj/item) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>")
|
||||
if(target && Adjacent(target))
|
||||
if(prob(counterchance))
|
||||
counterchance = initial(counterchance)
|
||||
var/previousattacktext = attacktext
|
||||
attacktext = "counters"
|
||||
target.attack_animal(src)
|
||||
attacktext = previousattacktext
|
||||
else
|
||||
counterchance = min(counterchance + initial(counterchance), 100)
|
||||
else
|
||||
blockchance = min(blockchance + initial(blockchance), 100)
|
||||
if(ratvar_awakens)
|
||||
blockchance = 90
|
||||
counterchance = 90
|
||||
|
||||
//COMMUNICATION and EMERGENCE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/handle_inherent_channels(message, message_mode)
|
||||
if(host && (is_in_host() || message_mode == MODE_BINARY))
|
||||
marauder_comms(message)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/marauder_comms(message)
|
||||
var/name_part = "<span class='sevtug'>[src] ([true_name])</span>"
|
||||
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
src << "[name_part]<span class='sevtug_small'>:</span> [message]"
|
||||
host << "[name_part]<span class='sevtug_small'>:</span> [message]"
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
M << "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[findtextEx(host.name, host.real_name) ? "[host.name]" : "[host.real_name] (as [host.name])"]</span><span class='sevtug_small'>):</span> [message] "
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/return_to_host()
|
||||
if(is_in_host())
|
||||
return FALSE
|
||||
if(!host)
|
||||
src << "<span class='warning'>You don't have a host!</span>"
|
||||
return FALSE
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
host.visible_message("<span class='warning'>[host]'s skin flashes crimson!</span>", "<span class='sevtug'>You feel [true_name]'s consciousness settle in your mind.</span>")
|
||||
visible_message("<span class='warning'>[src] suddenly disappears!</span>", "<span class='sevtug'>You return to [host].</span>")
|
||||
forceMove(host)
|
||||
if(resulthealth > MARAUDER_EMERGE_THRESHOLD && health != maxHealth)
|
||||
recovering = TRUE
|
||||
src << "<span class='userdanger'>You have weakened and will need to recover before manifesting again!</span>"
|
||||
host << "<span class='sevtug'>[true_name] has weakened and will need to recover before manifesting again!</span>"
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/try_emerge()
|
||||
if(!host)
|
||||
src << "<span class='warning'>You don't have a host!</span>"
|
||||
return FALSE
|
||||
if(!ratvar_awakens)
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
if(host.stat != DEAD && resulthealth > MARAUDER_EMERGE_THRESHOLD) //if above 20 health, fails
|
||||
src << "<span class='warning'>Your host must be at [MARAUDER_EMERGE_THRESHOLD]% or less health to emerge like this!</span>"
|
||||
return FALSE
|
||||
return emerge_from_host(FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/emerge_from_host(hostchosen, force) //Notice that this is a proc rather than a verb - marauders can NOT exit at will, but they CAN return
|
||||
if(!is_in_host())
|
||||
return FALSE
|
||||
if(!force && recovering)
|
||||
if(hostchosen)
|
||||
host << "<span class='sevtug'>[true_name] is too weak to come forth!</span>"
|
||||
else
|
||||
host << "<span class='sevtug'>[true_name] tries to emerge to protect you, but it's too weak!</span>"
|
||||
src << "<span class='userdanger'>You try to come forth, but you're too weak!</span>"
|
||||
return FALSE
|
||||
if(!force)
|
||||
if(hostchosen) //marauder approved
|
||||
host << "<span class='sevtug'>Your words echo with power as [true_name] emerges from your body!</span>"
|
||||
else
|
||||
host << "<span class='sevtug'>[true_name] emerges from your body to protect you!</span>"
|
||||
forceMove(host.loc)
|
||||
visible_message("<span class='warning'>[host]'s skin glows red as [name] emerges from their body!</span>", "<span class='sevtug_small'>You exit the safety of [host]'s body!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/get_alt_name()
|
||||
return " ([text2ratvar(true_name)])"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/is_in_host() //Checks if the marauder is inside of their host
|
||||
return host && loc == host
|
||||
|
||||
//HOST ACTIONS
|
||||
|
||||
//Summon Marauder action: Calls forth or recalls your marauder
|
||||
/datum/action/innate/summon_marauder
|
||||
name = "Force Marauder to Emerge/Recall"
|
||||
desc = "Allows you to force your clockwork marauder to emerge or recall as required."
|
||||
button_icon_state = "clockwork_marauder"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/linked_marauder
|
||||
var/static/list/defend_phrases = list("Defend me", "Come forth", "Assist me", "Protect me", "Give aid", "Help me")
|
||||
var/static/list/return_phrases = list("Return", "Return to me", "Your job is done", "You have served", "Come back", "Retreat")
|
||||
|
||||
/datum/action/innate/summon_marauder/IsAvailable()
|
||||
if(!linked_marauder)
|
||||
return FALSE
|
||||
if(isliving(owner))
|
||||
var/mob/living/L = owner
|
||||
if(!L.can_speak_vocal())
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/summon_marauder/Activate()
|
||||
if(linked_marauder.is_in_host())
|
||||
clockwork_say(owner, text2ratvar("[pick(defend_phrases)], [linked_marauder.true_name]!"))
|
||||
linked_marauder.emerge_from_host(TRUE)
|
||||
else
|
||||
clockwork_say(owner, text2ratvar("[pick(return_phrases)], [linked_marauder.true_name]!"))
|
||||
linked_marauder.return_to_host()
|
||||
return TRUE
|
||||
|
||||
//Linked Minds action: talks to your marauder
|
||||
/datum/action/innate/linked_minds
|
||||
name = "Linked Minds"
|
||||
desc = "Allows you to silently communicate with your marauder."
|
||||
button_icon_state = "linked_minds"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/linked_marauder
|
||||
|
||||
/datum/action/innate/linked_minds/IsAvailable()
|
||||
if(!linked_marauder)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/linked_minds/Activate()
|
||||
var/message = stripped_input(owner, "Enter a message to tell your marauder.", "Telepathy")
|
||||
if(!owner || !message)
|
||||
return FALSE
|
||||
if(!linked_marauder)
|
||||
owner << "<span class='warning'>Your marauder seems to have been destroyed!</span>"
|
||||
return FALSE
|
||||
var/name_part = "<span class='sevtug'>Servant [findtextEx(owner.name, owner.real_name) ? "[owner.name]" : "[owner.real_name] (as [owner.name])"]</span>"
|
||||
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
owner << "[name_part]<span class='sevtug_small'>:</span> [message]"
|
||||
linked_marauder << "[name_part]<span class='sevtug_small'>:</span> [message]"
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
M << "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[linked_marauder][linked_marauder.get_alt_name()]</span><span class='sevtug_small'>):</span> [message]"
|
||||
return TRUE
|
||||
@@ -1,326 +0,0 @@
|
||||
/obj/structure/clockwork/massive //For objects that are typically very large
|
||||
name = "massive construct"
|
||||
desc = "A very large construction."
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
density = FALSE
|
||||
burn_state = LAVA_PROOF
|
||||
|
||||
/obj/structure/clockwork/massive/New()
|
||||
..()
|
||||
poi_list += src
|
||||
|
||||
/obj/structure/clockwork/massive/Destroy()
|
||||
poi_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway //The gateway to Reebe, from which Ratvar emerges
|
||||
name = "Gateway to the Celestial Derelict"
|
||||
desc = "A massive, thrumming rip in spacetime."
|
||||
clockwork_desc = "A portal to the Celestial Derelict. Massive and intimidating, it is the only thing that can both transport Ratvar and withstand the massive amount of energy he emits."
|
||||
health = 500
|
||||
max_health = 500
|
||||
mouse_opacity = 2
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "nothing"
|
||||
density = TRUE
|
||||
can_be_repaired = FALSE
|
||||
var/progress_in_seconds = 0 //Once this reaches GATEWAY_RATVAR_ARRIVAL, it's game over
|
||||
var/purpose_fulfilled = FALSE
|
||||
var/first_sound_played = FALSE
|
||||
var/second_sound_played = FALSE
|
||||
var/third_sound_played = FALSE
|
||||
var/obj/effect/clockwork/gateway_glow/glow
|
||||
var/obj/effect/countdown/clockworkgate/countdown
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/New()
|
||||
..()
|
||||
glow = new(get_turf(src))
|
||||
countdown = new(src)
|
||||
countdown.start()
|
||||
SSshuttle.emergencyNoEscape = TRUE
|
||||
START_PROCESSING(SSobj, src)
|
||||
var/area/gate_area = get_area(src)
|
||||
for(var/M in mob_list)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M))
|
||||
M << "<span class='large_brass'><b>A gateway to the Celestial Derelict has been created in [gate_area.map_name]!</b></span>"
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/Destroy()
|
||||
SSshuttle.emergencyNoEscape = FALSE
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
|
||||
SSshuttle.emergency.mode = SHUTTLE_DOCKED
|
||||
SSshuttle.emergency.timer = world.time
|
||||
if(!purpose_fulfilled)
|
||||
priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(!purpose_fulfilled)
|
||||
var/area/gate_area = get_area(src)
|
||||
for(var/M in mob_list)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M))
|
||||
M << "<span class='large_brass'><b>A gateway to the Celestial Derelict has fallen at [gate_area.map_name]!</b></span>"
|
||||
world << sound(null, 0, channel = 8)
|
||||
qdel(glow)
|
||||
glow = null
|
||||
qdel(countdown)
|
||||
countdown = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/destroyed()
|
||||
countdown.stop()
|
||||
visible_message("<span class='userdanger'>The [src] begins to pulse uncontrollably... you might want to run!</span>")
|
||||
world << sound('sound/effects/clockcult_gateway_disrupted.ogg', 0, channel = 8, volume = 50)
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_disrupted"
|
||||
takes_damage = FALSE
|
||||
sleep(27)
|
||||
explosion(src, 1, 3, 8, 8)
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/proc/make_glow()
|
||||
if(!glow)
|
||||
glow = new(get_turf(src))
|
||||
glow.linked_gate = src
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/ex_act(severity)
|
||||
return 0 //Nice try, Toxins!
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/process()
|
||||
if(!progress_in_seconds || prob(5))
|
||||
for(var/M in mob_list)
|
||||
M << "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>"
|
||||
if(!health)
|
||||
return 0
|
||||
progress_in_seconds += GATEWAY_SUMMON_RATE
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
if(!first_sound_played)
|
||||
world << sound('sound/effects/clockcult_gateway_charging.ogg', 1, channel = 8, volume = 50)
|
||||
first_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_charging"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
if(!second_sound_played)
|
||||
world << sound('sound/effects/clockcult_gateway_active.ogg', 1, channel = 8, volume = 50)
|
||||
second_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_active"
|
||||
if(GATEWAY_RATVAR_COMING to GATEWAY_RATVAR_ARRIVAL)
|
||||
if(!third_sound_played)
|
||||
world << sound('sound/effects/clockcult_gateway_closing.ogg', 1, channel = 8, volume = 50)
|
||||
third_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_closing"
|
||||
if(GATEWAY_RATVAR_ARRIVAL to INFINITY)
|
||||
if(!purpose_fulfilled)
|
||||
countdown.stop()
|
||||
takes_damage = FALSE
|
||||
purpose_fulfilled = TRUE
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 1.5, alpha = 255, time = 126)
|
||||
world << sound('sound/effects/ratvar_rises.ogg', 0, channel = 8) //End the sounds
|
||||
sleep(131)
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
|
||||
sleep(5)
|
||||
new/obj/structure/clockwork/massive/ratvar(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/clockwork/massive/celestial_gateway/examine(mob/user)
|
||||
icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon
|
||||
..()
|
||||
icon_state = initial(icon_state)
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/arrival_text = "IMMINENT"
|
||||
if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0)
|
||||
arrival_text = "[round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE * 0.5), 0), 1)]"
|
||||
user << "<span class='big'><b>Seconds until Ratvar's arrival:</b> [arrival_text]s</span>"
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
user << "<span class='heavy_brass'>It's still opening.</span>"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
user << "<span class='heavy_brass'>It's reached the Celestial Derelict and is drawing power from it.</span>"
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
user << "<span class='heavy_brass'>Ratvar is coming through the gateway!</span>"
|
||||
else
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
user << "<span class='warning'>It's a swirling mass of blackness.</span>"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
user << "<span class='warning'>It seems to be leading somewhere.</span>"
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
user << "<span class='warning'><b>Something is coming through!</b></span>"
|
||||
|
||||
/obj/effect/clockwork/gateway_glow //the actual appearance of the Gateway to the Celestial Derelict; an object so the edges of the gate can be clicked through.
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "clockwork_gateway_charging"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
mouse_opacity = 0
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
var/obj/structure/clockwork/massive/celestial_gateway/linked_gate
|
||||
|
||||
/obj/effect/clockwork/gateway_glow/Destroy()
|
||||
if(linked_gate)
|
||||
linked_gate.glow = null
|
||||
linked_gate = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/gateway_glow/examine(mob/user)
|
||||
if(linked_gate)
|
||||
linked_gate.examine(user)
|
||||
|
||||
/obj/effect/clockwork/gateway_glow/ex_act(severity, target)
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar
|
||||
name = "Ratvar, the Clockwork Justiciar"
|
||||
desc = "<span class='userdanger'>What is what is what are what real what is all a lie all a lie it's all a lie why how can what is</span>"
|
||||
clockwork_desc = "<span class='large_brass'><b><i>Ratvar, the Clockwork Justiciar, your master eternal.</i></b></span>"
|
||||
icon = 'icons/effects/512x512.dmi'
|
||||
icon_state = "ratvar"
|
||||
pixel_x = -235
|
||||
pixel_y = -248
|
||||
takes_damage = FALSE
|
||||
var/atom/prey //Whatever Ratvar is chasing
|
||||
var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE
|
||||
var/proselytize_range = 10
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/New()
|
||||
..()
|
||||
ratvar_awakens = TRUE
|
||||
for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects)
|
||||
R.update_force()
|
||||
START_PROCESSING(SSobj, src)
|
||||
world << "<span class='heavy_brass'><font size=6>\"BAPR NTNVA ZL YVTUG FUNYY FUVAR NPEBFF GUVF CNGURGVP ERNYZ!!\"</font></span>"
|
||||
world << 'sound/effects/ratvar_reveal.ogg'
|
||||
var/image/alert_overlay = image('icons/effects/clockwork_effects.dmi', "ratvar_alert")
|
||||
var/area/A = get_area(src)
|
||||
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
|
||||
addtimer(SSshuttle.emergency, "request", 50, FALSE, null, 0.3)
|
||||
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/Destroy()
|
||||
ratvar_awakens = FALSE
|
||||
for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects)
|
||||
R.update_force()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
world << "<span class='heavy_brass'><font size=6>\"NO! I will not... be...</font> <font size=5>banished...</font> <font size=4>again...\"</font></span>"
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O)
|
||||
var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Cogscarab", "Reclaimer", "No")
|
||||
if(alertresult == "No" || !O)
|
||||
return 0
|
||||
var/mob/living/simple_animal/R
|
||||
if(alertresult == "Cogscarab")
|
||||
R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src))
|
||||
R.visible_message("<span class='heavy_brass'>[R] forms, and its eyes blink open, glowing bright red!</span>")
|
||||
else
|
||||
R = new/mob/living/simple_animal/hostile/clockwork/reclaimer(get_turf(src))
|
||||
R.visible_message("<span class='heavy_brass'>[R] forms, and it emits a faint hum!</span>")
|
||||
R.key = O.key
|
||||
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/Bump(atom/A)
|
||||
forceMove(get_turf(A))
|
||||
A.ratvar_act()
|
||||
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/Process_Spacemove()
|
||||
return clashing
|
||||
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/process()
|
||||
if(clashing) //I'm a bit occupied right now, thanks
|
||||
return
|
||||
for(var/atom/A in range(proselytize_range, src))
|
||||
A.ratvar_act()
|
||||
var/dir_to_step_in = pick(cardinal)
|
||||
if(!prey)
|
||||
for(var/obj/singularity/narsie/N in poi_list)
|
||||
if(N.z == z)
|
||||
prey = N
|
||||
break
|
||||
if(!prey) //In case there's a Nar-Sie
|
||||
var/list/meals = list()
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(L.z == z && !is_servant_of_ratvar(L) && L.mind)
|
||||
meals += L
|
||||
if(meals.len)
|
||||
prey = pick(meals)
|
||||
prey << "<span class='heavy_brass'><font size=5>\"You will do.\"</font></span>\n\
|
||||
<span class='userdanger'>Something very large and very malevolent begins lumbering its way towards you...</span>"
|
||||
prey << 'sound/effects/ratvar_reveal.ogg'
|
||||
else
|
||||
if(prob(10) || is_servant_of_ratvar(prey) || prey.z != z)
|
||||
prey << "<span class='heavy_brass'><font size=5>\"How dull. Leave me.\"</font></span>\n\
|
||||
<span class='userdanger'>You feel tremendous relief as a set of horrible eyes loses sight of you...</span>"
|
||||
prey = null
|
||||
else
|
||||
dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target
|
||||
step(src, dir_to_step_in)
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/narsie_act()
|
||||
if(clashing)
|
||||
return 0
|
||||
clashing = TRUE
|
||||
world << "<span class='heavy_brass'><font size=5>\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"</font></span>"
|
||||
world << "<span class='cult'><font size=5>\"<b>Ratvar?! How?!</b>\"</font></span>"
|
||||
for(var/obj/singularity/narsie/N in range(15, src))
|
||||
if(N.clashing)
|
||||
continue
|
||||
N.clashing = TRUE
|
||||
clash_of_the_titans(N) //IT'S TIME FOR THE BATTLE OF THE AGES
|
||||
break
|
||||
return 1
|
||||
|
||||
/obj/structure/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
|
||||
var/winner = "Undeclared"
|
||||
var/base_victory_chance = 0
|
||||
while(TRUE)
|
||||
world << 'sound/magic/clockwork/ratvar_attack.ogg'
|
||||
sleep(5.2)
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.client)
|
||||
M.client.color = rgb(150, 100, 0)
|
||||
spawn(1)
|
||||
M.client.color = initial(M.client.color)
|
||||
shake_camera(M, 4, 3)
|
||||
var/r_success_modifier = (ticker.mode.servants_of_ratvar.len * 2) //2% for each cultist
|
||||
var/n_success_modifier = (ticker.mode.cult.len * 2)
|
||||
for(var/mob/living/simple_animal/hostile/construct/harvester/C in player_list)
|
||||
n_success_modifier += 2
|
||||
if(prob(base_victory_chance + r_success_modifier))
|
||||
winner = "Ratvar"
|
||||
break
|
||||
sleep(rand(2,5))
|
||||
world << 'sound/magic/clockwork/narsie_attack.ogg'
|
||||
sleep(7.4)
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.client)
|
||||
M.client.color = rgb(200, 0, 0)
|
||||
spawn(1)
|
||||
M.client.color = initial(M.client.color)
|
||||
shake_camera(M, 4, 3)
|
||||
if(prob(base_victory_chance + n_success_modifier))
|
||||
winner = "Nar-Sie"
|
||||
break
|
||||
base_victory_chance++ //The clash has a higher chance of resolving each time both gods attack one another
|
||||
switch(winner)
|
||||
if("Ratvar")
|
||||
world << "<span class='heavy_brass'><font size=5>\"[pick("DIE! DIE! DIE!", "REEEEEEEEE!", "FILTH!!!", "SUFFER!!!", "EBG SBE PRAGHEVRF NF V UNIR!!")]\"</font></span>" //nar-sie get out
|
||||
world << "<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>"
|
||||
world << 'sound/magic/clockwork/anima_fragment_attack.ogg'
|
||||
world << 'sound/magic/demon_dies.ogg'
|
||||
clashing = FALSE
|
||||
qdel(narsie)
|
||||
return 1
|
||||
if("Nar-Sie")
|
||||
world << "<span class='cult'><font size=5>\"<b>[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]</b>\"</font></span>" //Broken English
|
||||
world << 'sound/magic/demon_attack1.ogg'
|
||||
world << 'sound/magic/clockwork/anima_fragment_death.ogg'
|
||||
narsie.clashing = FALSE
|
||||
qdel(src)
|
||||
return 1
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,314 @@
|
||||
//////////////////
|
||||
// APPLICATIONS //
|
||||
//////////////////
|
||||
|
||||
//Sigil of Accession: Creates a sigil of accession, which is like a sigil of submission, but can convert any number of non-implanted targets and up to one implanted target.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_accession
|
||||
descname = "Trap, Permanent Conversion"
|
||||
name = "Sigil of Accession"
|
||||
desc = "Places a luminous sigil much like a Sigil of Submission, but it will remain even after successfully converting a non-implanted target. \
|
||||
It will penetrate mindshield implants once before disappearing."
|
||||
invocations = list("Divinity, enslave...", "...all who trespass here!")
|
||||
channel_time = 70
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/submission/accession
|
||||
prevent_path = /obj/effect/clockwork/sigil/submission
|
||||
creator_message = "<span class='brass'>A luminous sigil appears below you. All non-servants to cross it will be enslaved after a brief time if they do not move.</span>"
|
||||
usage_tip = "It will remain after converting a target, unless that target has a mindshield implant, which it will break to convert them, but consume itself in the process."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Accession, which can convert a mindshielded non-Servant that remains on it."
|
||||
|
||||
|
||||
//Fellowship Armory: Arms the invoker and nearby servants with Ratvarian armor.
|
||||
/datum/clockwork_scripture/fellowship_armory
|
||||
descname = "Area Servant Armor"
|
||||
name = "Fellowship Armory"
|
||||
desc = "Equips the invoker and all visible Servants with Ratvarian armor. This armor provides high melee resistance but a weakness to lasers. \
|
||||
It grows faster to invoke with more adjacent Servants."
|
||||
invocations = list("Shield us...", "...with the...", "... fragments of Engine!")
|
||||
channel_time = 100
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
usage_tip = "This scripture will replace all weaker armor worn by affected Servants."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Attempts to armor all nearby Servants with powerful Ratvarian armor."
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork)) //don't replace this ever
|
||||
var/static/list/better_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
|
||||
|
||||
/datum/clockwork_scripture/fellowship_armory/run_scripture()
|
||||
for(var/mob/living/L in orange(1, invoker))
|
||||
if(is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal())
|
||||
channel_time = max(channel_time - 10, 0)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/fellowship_armory/scripture_effects()
|
||||
var/affected = 0
|
||||
for(var/mob/living/L in view(7, get_turf(invoker)))
|
||||
if(L.stat == DEAD || !is_servant_of_ratvar(L))
|
||||
continue
|
||||
var/do_message = 0
|
||||
var/obj/item/I = L.get_item_by_slot(slot_wear_suit)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
|
||||
I = L.get_item_by_slot(slot_head)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
|
||||
I = L.get_item_by_slot(slot_gloves)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
|
||||
I = L.get_item_by_slot(slot_shoes)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
|
||||
if(do_message)
|
||||
L.visible_message("<span class='warning'>Strange armor appears on [L]!</span>", "<span class='heavy_brass'>A bright shimmer runs down your body, equipping you with Ratvarian armor.</span>")
|
||||
playsound(L, 'sound/magic/clockwork/fellowship_armory.ogg', 15*do_message, 1) //get sound loudness based on how much we equipped
|
||||
affected++
|
||||
return affected
|
||||
|
||||
/datum/clockwork_scripture/fellowship_armory/proc/remove_item_if_better(obj/item/I, mob/user)
|
||||
if(!I)
|
||||
return TRUE
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
return FALSE
|
||||
if(!ratvar_awakens && is_type_in_typecache(I, better_armor_typecache))
|
||||
return FALSE
|
||||
return user.dropItemToGround(I)
|
||||
|
||||
//Memory Allocation: Finds a willing ghost and makes them into a clockwork marauders for the invoker.
|
||||
/datum/clockwork_scripture/memory_allocation
|
||||
descname = "Guardian"
|
||||
name = "Memory Allocation"
|
||||
desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilant fighter that lives within you, able to be \
|
||||
called forth by Speaking its True Name or if you become exceptionally low on health.<br>\
|
||||
If it remains close to you, you will gradually regain health up to a low amount, but it will die if it goes too far from you."
|
||||
invocations = list("Fright's will...", "...call forth...")
|
||||
channel_time = 100
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 2)
|
||||
usage_tip = "Marauders are useful as personal bodyguards and frontline warriors."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 3
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/check_special_requirements()
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in all_clockwork_mobs)
|
||||
if(M.host == invoker)
|
||||
invoker << "<span class='warning'>You can only house one marauder at a time!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/scripture_effects()
|
||||
return create_marauder()
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/proc/create_marauder()
|
||||
invoker.visible_message("<span class='warning'>A purple tendril appears from [invoker]'s [slab.name] and impales itself in [invoker.p_their()] forehead!</span>", \
|
||||
"<span class='sevtug'>A tendril flies from [slab] into your forehead. You begin waiting while it painfully rearranges your thought pattern...</span>")
|
||||
invoker.notransform = TRUE //Vulnerable during the process
|
||||
slab.busy = "Thought Modification in progress"
|
||||
if(!do_after(invoker, 50, target = invoker))
|
||||
invoker.visible_message("<span class='warning'>The tendril, covered in blood, retracts from [invoker]'s head and back into the [slab.name]!</span>", \
|
||||
"<span class='userdanger'>Total agony overcomes you as the tendril is forced out early!</span>")
|
||||
invoker.notransform = FALSE
|
||||
invoker.Stun(5)
|
||||
invoker.Weaken(5)
|
||||
invoker.apply_damage(10, BRUTE, "head")
|
||||
slab.busy = null
|
||||
return FALSE
|
||||
clockwork_say(invoker, text2ratvar("...the mind made..."))
|
||||
invoker.notransform = FALSE
|
||||
slab.busy = "Marauder Selection in progress"
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
invoker << "<span class='warning'>The tendril shivers slightly as it selects a marauder...</span>"
|
||||
var/list/marauder_candidates = pollCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50)
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
if(!marauder_candidates.len)
|
||||
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
|
||||
"<span class='warning'>The tendril was unsuccessful! Perhaps you should try again another time.</span>")
|
||||
return FALSE
|
||||
clockwork_say(invoker, text2ratvar("...sword and shield!"))
|
||||
var/mob/dead/observer/theghost = pick(marauder_candidates)
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/M = new(invoker)
|
||||
M.key = theghost.key
|
||||
M.bind_to_host(invoker)
|
||||
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
|
||||
"<span class='sevtug'>[M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" action button.</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
//Anima Fragment: Creates an empty anima fragment, which produces an anima fragment that moves at extreme speed and does high damage.
|
||||
/datum/clockwork_scripture/create_object/anima_fragment
|
||||
descname = "Fast Soul Vessel Shell"
|
||||
name = "Anima Fragment"
|
||||
desc = "Creates a large shell fitted for soul vessels. Adding an active soul vessel to it results in a powerful construct with decent health, notable melee power, \
|
||||
and exceptional speed, though taking damage will temporarily slow it down."
|
||||
invocations = list("Call forth...", "...the soldiers of Armorer.")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 2)
|
||||
object_path = /obj/structure/destructible/clockwork/shell/fragment
|
||||
creator_message = "<span class='brass'>You form an anima fragment, a powerful soul vessel receptable.</span>"
|
||||
observer_message = "<span class='warning'>The slab disgorges a puddle of black metal that expands and forms into a strange shell!</span>"
|
||||
usage_tip = "Useless without a soul vessel and should not be created without one."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Fragment Shell, which produces an Anima Fragment when filled with a Soul Vessel."
|
||||
|
||||
|
||||
//Sigil of Transmission: Creates a sigil of transmission that can store power for clockwork structures.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transmission
|
||||
descname = "Structure Battery"
|
||||
name = "Sigil of Transmission"
|
||||
desc = "Scribes a sigil beneath the invoker which stores power to power clockwork structures."
|
||||
invocations = list("Divinity...", "...power our creations!")
|
||||
channel_time = 70
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 2)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transmission
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures adjecent to it.</span>"
|
||||
usage_tip = "Cyborgs can charge from this sigil by remaining over it for 5 seconds."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transmission, which stores power for clockwork structures."
|
||||
|
||||
|
||||
//Interdiction Lens: Creates a powerful totem that disables radios and cameras and drains power into nearby sigils of transmission.
|
||||
/datum/clockwork_scripture/create_object/interdiction_lens
|
||||
descname = "Structure, Disables Machinery"
|
||||
name = "Interdiction Lens"
|
||||
desc = "Creates a clockwork totem that sabotages nearby machinery and funnels drained power into nearby Sigils of Transmission or the area's APC."
|
||||
invocations = list("May this totem...", "...shroud the false suns!")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 3, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/interdiction_lens
|
||||
creator_message = "<span class='brass'>You form an interdiction lens, which disrupts cameras and radios and drains power.</span>"
|
||||
observer_message = "<span class='warning'>A brass totem rises from the ground, a purple gem appearing in its center!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "If it fails to funnel power into a nearby Sigil of Transmission or the area's APC and fails to disable even one thing, it will disable itself for two minutes."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates an Interdiction Lens, which drains power into nearby Sigils of Transmission."
|
||||
|
||||
|
||||
//Mending Motor: Creates a prism that will quickly heal mechanical servants/clockwork structures and consume power or replicant alloy.
|
||||
/datum/clockwork_scripture/create_object/mending_motor
|
||||
descname = "Structure, Repairs Other Structures"
|
||||
name = "Mending Motor"
|
||||
desc = "Creates a mechanized prism that will rapidly repair damage to clockwork creatures, converted cyborgs, and clockwork structures. Requires power to function."
|
||||
invocations = list("May this prism...", "...mend our dents and scratches!")
|
||||
channel_time = 80
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/mending_motor
|
||||
creator_message = "<span class='brass'>You form a mending motor, which will consume power to mend constructs and structures.</span>"
|
||||
observer_message = "<span class='warning'>An onyx prism forms in midair and sprouts tendrils to support itself!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "Powerful healing but power use is somewhat inefficient, though much better than a proselytizer."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Mending Motor, which rapidly repairs constructs and structures at a power cost."
|
||||
|
||||
|
||||
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
|
||||
/datum/clockwork_scripture/create_object/mania_motor
|
||||
descname = "Structure, Area Denial"
|
||||
name = "Mania Motor"
|
||||
desc = "Creates a mania motor which will cause brain damage and hallucinations in nearby non-servant humans. It will also try to convert humans directly adjecent to the motor."
|
||||
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
|
||||
channel_time = 80
|
||||
consumed_components = list(GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
|
||||
creator_message = "<span class='brass'>You form a mania motor which will cause brain damage and hallucinations in nearby humans while active.</span>"
|
||||
observer_message = "<span class='warning'>A two-pronged machine rises from the ground!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "Eligible human servants next to the motor will be converted at an additional power cost. It will also cure hallucinations and brain damage in nearby servants."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Mania Motor, which can convert adjacent non-Servants with power."
|
||||
|
||||
|
||||
//Tinkerer's Daemon: Creates an efficient machine that rapidly produces components at a power cost.
|
||||
/datum/clockwork_scripture/create_object/tinkerers_daemon
|
||||
descname = "Structure, Component Generator"
|
||||
name = "Tinkerer's Daemon"
|
||||
desc = "Creates a tinkerer's daemon which can rapidly collect components. It will only function if it has sufficient power, is outnumbered by servants by a ratio of 5:1, and there is at least one existing cache."
|
||||
invocations = list("May this generator...", "...collect Engine parts that yet hold greatness!")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 3)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/tinkerers_daemon
|
||||
creator_message = "<span class='brass'>You form a tinkerer's daemon which can rapidly collect components at a power cost.</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "Vital to your success!"
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Tinkerer's Daemon, which can rapidly collect components for power."
|
||||
|
||||
/datum/clockwork_scripture/create_object/tinkerers_daemon/check_special_requirements()
|
||||
var/servants = 0
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
if(servants * 0.2 < clockwork_daemons)
|
||||
invoker << "<span class='nezbere'>\"Daemons are already disabled, making more of them would be a waste.\"</span>"
|
||||
return FALSE
|
||||
if(servants * 0.2 < clockwork_daemons+1)
|
||||
invoker << "<span class='nezbere'>\"This daemon would be useless, friend.\"</span>"
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost.
|
||||
/datum/clockwork_scripture/create_object/clockwork_obelisk
|
||||
descname = "Structure, Teleportation Hub"
|
||||
name = "Clockwork Obelisk"
|
||||
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living servant or clockwork obelisk."
|
||||
invocations = list("May this obelisk...", "...take us to all places!")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 3)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
|
||||
creator_message = "<span class='brass'>You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways.</span>"
|
||||
observer_message = "<span class='warning'>A brass obelisk appears handing in midair!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks recieve double duration and uses."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
|
||||
@@ -0,0 +1,42 @@
|
||||
/////////////////
|
||||
// CYBORG ONLY //
|
||||
/////////////////
|
||||
|
||||
//Linked Vanguard: grants Vanguard to the invoker and a target
|
||||
/datum/clockwork_scripture/ranged_ability/linked_vanguard
|
||||
name = "Linked Vanguard"
|
||||
invocations = list("Shield us...", "...from darkness!")
|
||||
channel_time = 30
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
quickbind_desc = "Allows you to grant a Servant and yourself stun immunity, as the Vanguard scripture.<br><b>Click your slab to disable.</b>"
|
||||
slab_icon = "vanguard"
|
||||
ranged_type = /obj/effect/proc_holder/slab/vanguard
|
||||
ranged_message = "<span class='inathneq_small'><i>You charge the clockwork slab with defensive strength.</i>\n\
|
||||
<b>Left-click a fellow Servant or yourself to grant Vanguard!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 50
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/linked_vanguard/check_special_requirements()
|
||||
if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
|
||||
invoker << "<span class='warning'>You are already shielded by a Vanguard!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//Judicial Marker: places a judicial marker at a target location
|
||||
/datum/clockwork_scripture/ranged_ability/judicial_marker
|
||||
name = "Judicial Marker"
|
||||
invocations = list("May heathens...", "...kneel under our force!")
|
||||
channel_time = 30
|
||||
primary_component = BELLIGERENT_EYE
|
||||
quickbind_desc = "Allows you to place a Judicial Marker to stun and damage a target location.<br><b>Click your slab to disable.</b>"
|
||||
slab_icon = "judicial"
|
||||
ranged_type = /obj/effect/proc_holder/slab/judicial
|
||||
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with judicial force.</i>\n\
|
||||
<b>Left-click a target to place a Judicial Marker!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 50
|
||||
|
||||
//Volt Void, but with a different quickbind desc
|
||||
/datum/clockwork_scripture/channeled/volt_void/cyborg
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations using your own power. Failing to fire causes backlash.<br><b>Maximum 4 chants.</b>"
|
||||
tier = SCRIPTURE_PERIPHERAL
|
||||
@@ -0,0 +1,316 @@
|
||||
/////////////
|
||||
// DRIVERS //
|
||||
/////////////
|
||||
|
||||
//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned.
|
||||
/datum/clockwork_scripture/channeled/belligerent
|
||||
descname = "Channeled, Area Slowdown"
|
||||
name = "Belligerent"
|
||||
desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds."
|
||||
chant_invocations = list("Punish their blindness!", "Take time, make slow!")
|
||||
chant_amount = 15
|
||||
chant_interval = 20
|
||||
channel_time = 20
|
||||
usage_tip = "Useful for crowd control in a populated area and disrupting mass movement."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.<br><b>Maximum 15 chants.</b>"
|
||||
var/noncultist_damage = 2 //damage per chant to noncultists
|
||||
var/cultist_damage = 8 //damage per chant to non-walking cultists
|
||||
|
||||
/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number)
|
||||
for(var/mob/living/carbon/C in hearers(7, invoker))
|
||||
var/number_legs = C.get_num_legs()
|
||||
if(!is_servant_of_ratvar(C) && !C.null_rod_check() && number_legs) //you have legs right
|
||||
C.apply_damage(noncultist_damage * 0.5, BURN, "l_leg")
|
||||
C.apply_damage(noncultist_damage * 0.5, BURN, "r_leg")
|
||||
if(C.m_intent != MOVE_INTENT_WALK)
|
||||
if(!iscultist(C))
|
||||
C << "<span class='warning'>Your leg[number_legs > 1 ? "s shiver":" shivers"] with pain!</span>"
|
||||
else //Cultists take extra burn damage
|
||||
C << "<span class='warning'>Your leg[number_legs > 1 ? "s burn":" burns"] with pain!</span>"
|
||||
C.apply_damage(cultist_damage * 0.5, BURN, "l_leg")
|
||||
C.apply_damage(cultist_damage * 0.5, BURN, "r_leg")
|
||||
C.toggle_move_intent()
|
||||
return TRUE
|
||||
|
||||
|
||||
//Judicial Visor: Creates a judicial visor, which can smite an area.
|
||||
/datum/clockwork_scripture/create_object/judicial_visor
|
||||
descname = "Delayed Area Stun Glasses"
|
||||
name = "Judicial Visor"
|
||||
desc = "Forms a visor that, when worn, will grant the ability to smite an area, stunning, muting, and damaging non-Servants. \
|
||||
Cultists of Nar-Sie will be set on fire, though they will be stunned for half the time."
|
||||
invocations = list("Grant me the flames of Engine!")
|
||||
channel_time = 10
|
||||
consumed_components = list(BELLIGERENT_EYE = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clothing/glasses/judicial_visor
|
||||
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting the unworthy.</span>"
|
||||
usage_tip = "The visor has a thirty-second cooldown once used, and the marker it creates has a delay of 3 seconds before exploding."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Judicial Visor, which can create a Judicial Marker at an area, stunning, muting, and damaging non-Servants after a delay."
|
||||
|
||||
|
||||
//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
|
||||
/datum/clockwork_scripture/vanguard
|
||||
descname = "Self Stun Immunity"
|
||||
name = "Vanguard"
|
||||
desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is stunned for the equivalent of 25% of all stuns they absorbed. \
|
||||
Excessive absorption will cause unconsciousness."
|
||||
invocations = list("Shield me...", "...from darkness!")
|
||||
channel_time = 30
|
||||
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 3
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled."
|
||||
|
||||
/datum/clockwork_scripture/vanguard/check_special_requirements()
|
||||
if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
|
||||
invoker << "<span class='warning'>You are already shielded by a Vanguard!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/vanguard/scripture_effects()
|
||||
invoker.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Sentinel's Compromise: Allows the invoker to select a nearby servant and convert their brute, burn, and oxygen damage into half as much toxin damage.
|
||||
/datum/clockwork_scripture/ranged_ability/sentinels_compromise
|
||||
descname = "Convert Brute/Burn/Oxygen to Half Toxin"
|
||||
name = "Sentinel's Compromise"
|
||||
desc = "Charges your slab with healing power, allowing you to convert all of a target Servant's brute, burn, and oxygen damage to half as much toxin damage."
|
||||
invocations = list("Mend the wounds of...", "...my inferior flesh.")
|
||||
channel_time = 30
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1)
|
||||
usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to convert a Servant's brute, burn, and oxygen damage to half toxin damage.<br><b>Click your slab to disable.</b>"
|
||||
slab_icon = "compromise"
|
||||
ranged_type = /obj/effect/proc_holder/slab/compromise
|
||||
ranged_message = "<span class='inathneq_small'><i>You charge the clockwork slab with healing power.</i>\n\
|
||||
<b>Left-click a fellow Servant or yourself to heal!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
|
||||
|
||||
//Geis: Grants a short-range binding that will immediately start chanting on binding a valid target.
|
||||
/datum/clockwork_scripture/ranged_ability/geis_prep
|
||||
descname = "Melee Convert Attack"
|
||||
name = "Geis"
|
||||
desc = "Charges your slab with divine energy, allowing you to bind a nearby heretic for conversion. This is very obvious and will make your slab visible in-hand."
|
||||
invocations = list("Divinity, grant...", "...me strength...", "...to enlighten...", "...the heathen!")
|
||||
whispered = TRUE
|
||||
channel_time = 20
|
||||
usage_tip = "Is melee range and does not penetrate mindshield implants. Much more efficient than a Sigil of Submission at low Servant amounts."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to bind and start converting an adjacent target non-Servant.<br><b>Click your slab to disable.</b>"
|
||||
slab_icon = "geis"
|
||||
ranged_type = /obj/effect/proc_holder/slab/geis
|
||||
ranged_message = "<span class='sevtug_small'><i>You charge the clockwork slab with divine energy.</i>\n\
|
||||
<b>Left-click a target within melee range to convert!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 100
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/geis_prep/run_scripture()
|
||||
var/servants = 0
|
||||
if(!ratvar_awakens)
|
||||
for(var/mob/living/M in all_clockwork_mobs)
|
||||
if(ishuman(M) || issilicon(M))
|
||||
servants++
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
whispered = FALSE
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
channel_time = min(channel_time + servants*3, 50)
|
||||
return ..()
|
||||
|
||||
//The scripture that does the converting.
|
||||
/datum/clockwork_scripture/geis
|
||||
name = "Geis Conversion"
|
||||
invocations = list("Enlighten this heathen!", "All are insects before Engine!", "Purge all untruths and honor Engine.")
|
||||
channel_time = 49
|
||||
tier = SCRIPTURE_PERIPHERAL
|
||||
var/mob/living/target
|
||||
var/obj/structure/destructible/clockwork/geis_binding/binding
|
||||
|
||||
/datum/clockwork_scripture/geis/Destroy()
|
||||
if(binding && !qdeleted(binding))
|
||||
qdel(binding)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/geis/can_recite()
|
||||
if(!target)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/geis/run_scripture()
|
||||
var/servants = 0
|
||||
if(!ratvar_awakens)
|
||||
for(var/mob/living/M in all_clockwork_mobs)
|
||||
if(ishuman(M) || issilicon(M))
|
||||
servants++
|
||||
if(target.buckled)
|
||||
target.buckled.unbuckle_mob(target, TRUE)
|
||||
binding = new(get_turf(target))
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
channel_time = min(channel_time + servants*7, 120)
|
||||
binding.can_resist = TRUE
|
||||
binding.setDir(target.dir)
|
||||
binding.buckle_mob(target, TRUE)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/geis/check_special_requirements()
|
||||
return target && binding && target.buckled == binding && !is_servant_of_ratvar(target) && target.stat != DEAD
|
||||
|
||||
/datum/clockwork_scripture/geis/scripture_effects()
|
||||
return add_servant_of_ratvar(target)
|
||||
|
||||
|
||||
//Taunting Tirade: Channeled for up to five times over thirty seconds. Confuses non-servants that can hear it and allows movement for a brief time after each chant.
|
||||
/datum/clockwork_scripture/channeled/taunting_tirade
|
||||
descname = "Channeled, Mobile Area Confusion"
|
||||
name = "Taunting Tirade"
|
||||
desc = "Weakens, confuses and dizzies all nearby non-servants with a short invocation, then allows movement for five seconds. Chanted every second for up to thirty seconds."
|
||||
chant_invocations = list("Hostiles on my back!", "Enemies on my trail!", "Gonna try and shake my tail.", "Bogeys on my six!")
|
||||
chant_amount = 5
|
||||
chant_interval = 10
|
||||
consumed_components = list(GEIS_CAPACITOR = 1)
|
||||
usage_tip = "Useful for fleeing attackers, as few will be able to follow someone using this scripture."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Weakens, confuses, and dizzies nearby non-servants, then allows some movement.<br><b>Maximum 5 chants.</b>"
|
||||
var/flee_time = 47 //allow fleeing for 5 seconds
|
||||
var/grace_period = 3 //very short grace period so you don't have to stop immediately
|
||||
var/datum/progressbar/progbar
|
||||
|
||||
/datum/clockwork_scripture/channeled/taunting_tirade/chant_effects(chant_number)
|
||||
for(var/mob/living/L in hearers(7, invoker))
|
||||
if(!is_servant_of_ratvar(L) && !L.null_rod_check())
|
||||
L.confused = min(L.confused + 20, 100)
|
||||
L.dizziness = min(L.dizziness + 20, 100)
|
||||
L.Weaken(1)
|
||||
invoker.visible_message("<span class='warning'>[invoker] is suddenly covered with a thin layer of purple smoke!</span>")
|
||||
var/invoker_old_color = invoker.color
|
||||
invoker.color = list("#AF0AAF", "#AF0AAF", "#AF0AAF", rgb(0,0,0))
|
||||
animate(invoker, color = invoker_old_color, time = flee_time+grace_period)
|
||||
addtimer(CALLBACK(invoker, /atom/proc/update_atom_colour), flee_time+grace_period)
|
||||
if(chant_number != chant_amount) //if this is the last chant, we don't have a movement period because the chant is over
|
||||
var/endtime = world.time + flee_time
|
||||
var/starttime = world.time
|
||||
progbar = new(invoker, flee_time, invoker)
|
||||
progbar.bar.color = list("#AF0AAF", "#AF0AAF", "#AF0AAF", rgb(0,0,0))
|
||||
animate(progbar.bar, color = initial(progbar.bar.color), time = flee_time+grace_period)
|
||||
while(world.time < endtime && can_recite())
|
||||
sleep(1)
|
||||
progbar.update(world.time - starttime)
|
||||
qdel(progbar)
|
||||
if(can_recite())
|
||||
sleep(grace_period)
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/taunting_tirade/chant_end_effects()
|
||||
qdel(progbar)
|
||||
|
||||
|
||||
//Replicant: Creates a new clockwork slab.
|
||||
/datum/clockwork_scripture/create_object/replicant
|
||||
descname = "New Clockwork Slab"
|
||||
name = "Replicant"
|
||||
desc = "Creates a new clockwork slab."
|
||||
invocations = list("Metal, become greater!")
|
||||
channel_time = 10
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/slab
|
||||
creator_message = "<span class='brass'>You copy a piece of replicant alloy and command it into a new slab.</span>"
|
||||
usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a new Clockwork Slab."
|
||||
|
||||
|
||||
//Tinkerer's Cache: Creates a tinkerer's cache, allowing global component storage.
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache
|
||||
descname = "Necessary Structure, Shares Components"
|
||||
name = "Tinkerer's Cache"
|
||||
desc = "Forms a cache that can store an infinite amount of components. All caches are linked and will provide components to slabs."
|
||||
invocations = list("Constructing...", "...a cache!")
|
||||
channel_time = 50
|
||||
consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
|
||||
object_path = /obj/structure/destructible/clockwork/cache
|
||||
creator_message = "<span class='brass'>You form a tinkerer's cache, which is capable of storing components, which will automatically be used by slabs.</span>"
|
||||
observer_message = "<span class='warning'>A hollow brass spire rises and begins to blaze!</span>"
|
||||
usage_tip = "Slabs will draw components from the global cache after the slab's own repositories, making caches very efficient."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Tinkerer's Cache, which stores components globally for slab access."
|
||||
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache/creation_update()
|
||||
var/cache_cost_increase = min(round(clockwork_caches*0.25), 5)
|
||||
consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
|
||||
for(var/i in consumed_components)
|
||||
if(i != REPLICANT_ALLOY)
|
||||
consumed_components[i] += cache_cost_increase
|
||||
|
||||
|
||||
//Wraith Spectacles: Creates a pair of wraith spectacles, which grant xray vision but damage vision slowly.
|
||||
/datum/clockwork_scripture/create_object/wraith_spectacles
|
||||
descname = "Xray Vision Glasses"
|
||||
name = "Wraith Spectacles"
|
||||
desc = "Fabricates a pair of glasses that provides true sight but quickly damage vision, eventually causing blindness if worn for too long."
|
||||
invocations = list("Show the truth of this world to me!")
|
||||
channel_time = 10
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clothing/glasses/wraith_spectacles
|
||||
creator_message = "<span class='brass'>You form a pair of wraith spectacles, which will grant true sight when worn.</span>"
|
||||
usage_tip = "\"True sight\" means that you are able to see through walls and in darkness."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
|
||||
|
||||
|
||||
//Sigil of Transgression: Creates a sigil of transgression, which stuns the first nonservant to cross it.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transgression
|
||||
descname = "Trap, Stunning"
|
||||
name = "Sigil of Transgression"
|
||||
desc = "Wards a tile with a sigil. The next person to cross the sigil will be smitten and unable to move. Nar-Sian cultists are stunned altogether."
|
||||
invocations = list("Divinity, dazzle...", "...those who tresspass here!")
|
||||
channel_time = 50
|
||||
consumed_components = list(HIEROPHANT_ANSIBLE = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transgression
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. The next non-servant to cross it will be immobilized.</span>"
|
||||
usage_tip = "The sigil, while fairly powerful in its stun, does not induce muteness in its victim."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transgression, which will stun the first non-Servant to cross it."
|
||||
@@ -0,0 +1,57 @@
|
||||
///////////////
|
||||
// JUDGEMENT //
|
||||
///////////////
|
||||
|
||||
//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, either summoning ratvar or proselytizing everything.
|
||||
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar
|
||||
descname = "Structure, Win Condition"
|
||||
name = "Ark of the Clockwork Justiciar"
|
||||
desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict.\n\
|
||||
This gateway will either call forth Ratvar from his exile if that is the task He has set you, or proselytize the entire station if it is not."
|
||||
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
|
||||
"THE TIME HAS COME FOR OUR MASTER TO BREAK THE CHAINS OF EXILE!!", \
|
||||
"LEND US YOUR AID! ENGINE COMES!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 10, VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 10, REPLICANT_ALLOY = 10, HIEROPHANT_ANSIBLE = 10)
|
||||
invokers_required = 5
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
|
||||
as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
|
||||
tier = SCRIPTURE_JUDGEMENT
|
||||
sort_priority = 1
|
||||
|
||||
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/New()
|
||||
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
|
||||
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
|
||||
"THIS STATION WILL BE A BEACON OF HOPE IN THE DARKNESS OF SPACE!!", \
|
||||
"HELP US MAKE THIS SHOW ENGINE'S GLORY!!")
|
||||
..()
|
||||
|
||||
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/check_special_requirements()
|
||||
if(!slab.no_cost)
|
||||
if(ratvar_awakens)
|
||||
invoker << "<span class='big_brass'>\"I am already here, idiot.\"</span>"
|
||||
return FALSE
|
||||
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in all_clockwork_objects)
|
||||
var/area/gate_area = get_area(G)
|
||||
invoker << "<span class='userdanger'>There is already a gateway at [gate_area.map_name]!</span>"
|
||||
return FALSE
|
||||
var/area/A = get_area(invoker)
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!T || T.z != ZLEVEL_STATION || istype(A, /area/shuttle) || !A.blob_allowed)
|
||||
invoker << "<span class='warning'>You must be on the station to activate the Ark!</span>"
|
||||
return FALSE
|
||||
if(clockwork_gateway_activated)
|
||||
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
|
||||
invoker << "<span class='nezbere'>\"Look upon his works. Is it not glorious?\"</span>"
|
||||
else
|
||||
invoker << "<span class='warning'>Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects()
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(T)
|
||||
new/obj/structure/destructible/clockwork/massive/celestial_gateway(T)
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -0,0 +1,227 @@
|
||||
//////////////
|
||||
// REVENANT //
|
||||
//////////////
|
||||
|
||||
//Invoke Inath-neq, the Resonant Cogwheel: Grants invulnerability and stun immunity to everyone nearby for 15 seconds.
|
||||
/datum/clockwork_scripture/invoke_inathneq
|
||||
descname = "Area Invulnerability"
|
||||
name = "Invoke Inath-neq, the Resonant Cogwheel"
|
||||
desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all servants in range for fifteen seconds."
|
||||
invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!")
|
||||
channel_time = 100
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 3)
|
||||
usage_tip = "Those affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 2
|
||||
|
||||
/datum/clockwork_scripture/invoke_inathneq/check_special_requirements()
|
||||
if(!slab.no_cost && clockwork_generals_invoked["inath-neq"] > world.time)
|
||||
invoker << "<span class='inathneq'>\"[text2ratvar("I cannot lend you my aid yet, champion. Please be careful.")]\"</span>\n\
|
||||
<span class='warning'>Inath-neq has already been invoked recently! You must wait several minutes before calling upon the Resonant Cogwheel.</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_inathneq/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/inathneq(get_turf(invoker))
|
||||
hierophant_message("<span class='inathneq_large'>[text2ratvar("Vanguard: \"I lend you my aid, champions! Let glory guide your blows!")]\"</span>", FALSE, invoker)
|
||||
clockwork_generals_invoked["inath-neq"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
if(invoker.real_name == "Lucio")
|
||||
clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!"))
|
||||
for(var/mob/living/L in range(7, invoker))
|
||||
if(!is_servant_of_ratvar(L) || L.stat == DEAD)
|
||||
continue
|
||||
L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Sevtug, the Formless Pariah: Causes massive global hallucinations, braindamage, confusion, and dizziness to all humans on the same zlevel.
|
||||
/datum/clockwork_scripture/invoke_sevtug
|
||||
descname = "Global Hallucination"
|
||||
name = "Invoke Sevtug, the Formless Pariah"
|
||||
desc = "Taps the limitless power of Sevtug, one of Ratvar's four generals. The mental manipulation ability of the Pariah allows its wielder to cause mass hallucinations and confusion \
|
||||
for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects."
|
||||
invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 6, HIEROPHANT_ANSIBLE = 3)
|
||||
usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
sort_priority = 3
|
||||
primary_component = GEIS_CAPACITOR
|
||||
invokers_required = 3
|
||||
multiple_invokers_used = TRUE
|
||||
var/static/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \
|
||||
"\"Really, this is almost boring.\"", "\"None of these minds have anything interesting in them.\"", "\"Maybe I can instill a little bit of terror in this one.\"", \
|
||||
"\"What a waste of my power.\"", "\"I'm sure I could just control these minds instead, but they never ask.\"")
|
||||
|
||||
/datum/clockwork_scripture/invoke_sevtug/check_special_requirements()
|
||||
if(!slab.no_cost && clockwork_generals_invoked["sevtug"] > world.time)
|
||||
invoker << "<span class='sevtug'>\"[text2ratvar("Is it really so hard - even for a simpleton like you - to grasp the concept of waiting?")]\"</span>\n\
|
||||
<span class='warning'>Sevtug has already been invoked recently! You must wait several minutes before calling upon the Formless Pariah.</span>"
|
||||
return FALSE
|
||||
if(!slab.no_cost && ratvar_awakens)
|
||||
invoker << "<span class='sevtug'>\"[text2ratvar("Do you really think anything I can do right now will compare to Engine's power?")]\"</span>\n\
|
||||
<span class='warning'>Sevtug will not grant his power while Ratvar's dwarfs his own!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_sevtug/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/sevtug(get_turf(invoker))
|
||||
hierophant_message("<span class='sevtug_large'>[text2ratvar("Fright: \"I heed your call, idiots. Get going and use this chance while it lasts!")]\"</span>", FALSE, invoker)
|
||||
clockwork_generals_invoked["sevtug"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
|
||||
var/turf/T = get_turf(invoker)
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
if(H.z == invoker.z && !is_servant_of_ratvar(H))
|
||||
var/distance = 0
|
||||
distance += get_dist(T, get_turf(H))
|
||||
var/visualsdistance = max(150 - distance, 5)
|
||||
var/minordistance = max(200 - distance*2, 5)
|
||||
var/majordistance = max(150 - distance*3, 5)
|
||||
if(H.null_rod_check())
|
||||
H << "<span class='sevtug'>[text2ratvar("Oh, a void weapon. How annoying, I may as well not bother.")]</span>\n\
|
||||
<span class='warning'>Your holy weapon glows a faint orange, defending your mind!</span>"
|
||||
continue
|
||||
else if(H.isloyal())
|
||||
visualsdistance = round(visualsdistance * 0.5) //half effect for shielded targets
|
||||
minordistance = round(minordistance * 0.5)
|
||||
majordistance = round(majordistance * 0.5)
|
||||
H << "<span class='sevtug'>[text2ratvar("Oh, look, a mindshield. Cute, I suppose I'll humor it.")]</span>"
|
||||
else if(prob(visualsdistance))
|
||||
H << "<span class='sevtug'>[text2ratvar(pick(mindbreaksayings))]</span>"
|
||||
H.playsound_local(T, hum, visualsdistance, 1)
|
||||
flash_color(H, flash_color="#AF0AAF", flash_time=visualsdistance*10)
|
||||
H.dizziness = minordistance + H.dizziness
|
||||
H.hallucination = minordistance + H.hallucination
|
||||
H.confused = majordistance + H.confused
|
||||
H.setBrainLoss(majordistance + H.getBrainLoss())
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Nezbere, the Brass Eidolon: Invokes Nezbere, bolstering the strength of many clockwork items for one minute.
|
||||
/datum/clockwork_scripture/invoke_nezbere
|
||||
descname = "Global Structure Buff"
|
||||
name = "Invoke Nezbere, the Brass Eidolon"
|
||||
desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \
|
||||
clockwork proselytizers will charge very rapidly."
|
||||
invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 6)
|
||||
usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \
|
||||
and interdiction lenses, mending motors, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 4
|
||||
invokers_required = 3
|
||||
multiple_invokers_used = TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nezbere/check_special_requirements()
|
||||
if(!slab.no_cost && clockwork_generals_invoked["nezbere"] > world.time)
|
||||
invoker << "<span class='nezbere'>\"[text2ratvar("Not just yet, friend. Patience is a virtue.")]\"</span>\n\
|
||||
<span class='warning'>Nezbere has already been invoked recently! You must wait several minutes before calling upon the Brass Eidolon.</span>"
|
||||
return FALSE
|
||||
if(!slab.no_cost && ratvar_awakens)
|
||||
invoker << "<span class='nezbere'>\"[text2ratvar("Our master is here already. You do not require my help, friend.")]\"</span>\n\
|
||||
<span class='warning'>Nezbere will not grant his power while Ratvar's dwarfs his own!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nezbere/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/nezbere(get_turf(invoker))
|
||||
hierophant_message("<span class='nezbere_large'>[text2ratvar("Armorer: \"I heed your call, champions. May your artifacts bring ruin upon the heathens that oppose our master!")]\"</span>", FALSE, invoker)
|
||||
clockwork_generals_invoked["nezbere"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects) //Ocular wardens have increased damage and radius
|
||||
W.damage_per_tick = 5
|
||||
W.sight_range = 5
|
||||
for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects) //Proselytizers no longer require power
|
||||
P.charge_rate = 1250
|
||||
for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects) //Powered clockwork structures no longer need power
|
||||
M.needs_power = FALSE
|
||||
if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon)) //Daemons produce components twice as quickly
|
||||
var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M
|
||||
D.production_time = 0
|
||||
D.production_cooldown *= 0.5
|
||||
spawn(600)
|
||||
for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects)
|
||||
if(W.damage_per_tick == 5)
|
||||
W.damage_per_tick = initial(W.damage_per_tick)
|
||||
if(W.sight_range == 5)
|
||||
W.sight_range = initial(W.sight_range)
|
||||
for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects)
|
||||
if(P.charge_rate == 1250)
|
||||
P.charge_rate = initial(P.charge_rate)
|
||||
for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects)
|
||||
M.needs_power = initial(M.needs_power)
|
||||
if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon))
|
||||
var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M
|
||||
D.production_cooldown = initial(D.production_cooldown)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Nzcrentr, the Eternal Thunderbolt: Imbues an immense amount of energy into the invoker. After several seconds, everyone near the invoker will be hit with a devastating lightning blast.
|
||||
/datum/clockwork_scripture/invoke_nzcrentr
|
||||
descname = "Area Lightning Blast"
|
||||
name = "Invoke Nzcrentr, the Eternal Thunderbolt"
|
||||
desc = "Taps the limitless power of Nzcrentr, one of Ratvar's four generals. The immense energy Nzcrentr wields will allow you to imbue a tiny fraction of it into your body. After several \
|
||||
seconds, anyone near you will be struck by a devastating lightning bolt."
|
||||
invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!")
|
||||
channel_time = 100
|
||||
consumed_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 6)
|
||||
usage_tip = "Struck targets will also be knocked down for about sixteen seconds."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 5
|
||||
|
||||
/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements()
|
||||
if(!slab.no_cost && clockwork_generals_invoked["nzcrentr"] > world.time)
|
||||
invoker << "<span class='nzcrentr'>\"[text2ratvar("The boss says you have to wait. Hey, do you think he would mind if I killed you? ...He would? Ok.")]\"</span>\n\
|
||||
<span class='warning'>Nzcrentr has already been invoked recently! You must wait several minutes before calling upon the Eternal Thunderbolt.</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nzcrentr/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/nzcrentr(get_turf(invoker))
|
||||
clockwork_generals_invoked["nzcrentr"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
hierophant_message("<span class='nzcrentr_large'>[text2ratvar("Amperage: \"[invoker.real_name] has called forth my power. Hope [invoker.p_they()] [invoker.p_do()] not shatter under it!")]\"</span>", FALSE, invoker)
|
||||
invoker.visible_message("<span class='warning'>[invoker] begins to radiate a blinding light!</span>", \
|
||||
"<span class='nzcrentr'>\"[text2ratvar("The boss says it's okay to do this. Don't blame me if you die from it.")]\"</span>\n \
|
||||
<span class='userdanger'>You feel limitless power surging through you!</span>")
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
sleep(2)
|
||||
playsound(invoker, 'sound/magic/lightning_chargeup.ogg', 100, 0)
|
||||
var/oldcolor = invoker.color
|
||||
animate(invoker, color = list(rgb(255, 255, 255), rgb(255, 255, 255), rgb(255, 255, 255), rgb(0,0,0)), time = 88) //Gradual advancement to extreme brightness
|
||||
sleep(88)
|
||||
if(invoker)
|
||||
invoker.visible_message("<span class='warning'>Massive bolts of energy emerge from across [invoker]'s body!</span>", \
|
||||
"<span class='nzcrentr'>\"[text2ratvar("I told you you wouldn't be able to handle it.")]\"</span>\n \
|
||||
<span class='userdanger'>TOO... MUCH! CAN'T... TAKE IT!</span>")
|
||||
playsound(invoker, 'sound/magic/lightningbolt.ogg', 100, 0)
|
||||
if(invoker.stat == CONSCIOUS)
|
||||
animate(invoker, color = oldcolor, time = 10)
|
||||
addtimer(CALLBACK(invoker, /atom/proc/update_atom_colour), 10)
|
||||
for(var/mob/living/L in view(7, invoker))
|
||||
if(is_servant_of_ratvar(L) || L.null_rod_check())
|
||||
continue
|
||||
invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10)
|
||||
var/randdamage = rand(40, 60)
|
||||
if(iscarbon(L))
|
||||
L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage)
|
||||
else
|
||||
L.adjustFireLoss(randdamage)
|
||||
L.visible_message(
|
||||
"<span class='danger'>[L] was shocked by Nzcrentr's power!</span>", \
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>" \
|
||||
)
|
||||
L.Weaken(8)
|
||||
playsound(L, 'sound/magic/LightningShock.ogg', 50, 1)
|
||||
else
|
||||
playsound(invoker, 'sound/magic/Disintegrate.ogg', 50, 1)
|
||||
invoker.gib()
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
@@ -0,0 +1,308 @@
|
||||
/////////////
|
||||
// SCRIPTS //
|
||||
/////////////
|
||||
|
||||
//Ocular Warden: Creates an ocular warden, which defends a small area near it.
|
||||
/datum/clockwork_scripture/create_object/ocular_warden
|
||||
descname = "Structure, Turret"
|
||||
name = "Ocular Warden"
|
||||
desc = "Forms an automatic short-range turret that deals low sustained damage to the unenlightened in its range."
|
||||
invocations = list("Guardians...", "...of the Engine...", "...defend us!")
|
||||
channel_time = 120
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, REPLICANT_ALLOY = 1)
|
||||
object_path = /obj/structure/destructible/clockwork/ocular_warden
|
||||
creator_message = "<span class='brass'>You form an ocular warden, which will focus its searing gaze upon nearby unenlightened.</span>"
|
||||
observer_message = "<span class='warning'>A brass eye takes shape and slowly rises into the air, its red iris glaring!</span>"
|
||||
usage_tip = "Although powerful, the warden is very fragile and should optimally be placed behind barricades."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
space_allowed = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates an Ocular Warden, which will automatically attack nearby unrestrained non-Servants that can see it."
|
||||
|
||||
/datum/clockwork_scripture/create_object/ocular_warden/check_special_requirements()
|
||||
for(var/obj/structure/destructible/clockwork/ocular_warden/W in range(3, invoker))
|
||||
invoker << "<span class='neovgre'>You sense another ocular warden too near this location. Placing another this close would cause them to fight.</span>" //fluff message
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
//Cogscarab: Creates an empty cogscarab shell, which produces a cogscarab dedicated to maintaining and defending the cult.
|
||||
/datum/clockwork_scripture/create_object/cogscarab
|
||||
descname = "Constructor Soul Vessel Shell"
|
||||
name = "Cogscarab"
|
||||
desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer."
|
||||
invocations = list("Call forth...", "...the workers of Armorer.")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
object_path = /obj/structure/destructible/clockwork/shell/cogscarab
|
||||
creator_message = "<span class='brass'>You form a cogscarab, a constructor soul vessel receptacle.</span>"
|
||||
observer_message = "<span class='warning'>The slab disgorges a puddle of black metal that contracts and forms into a strange shell!</span>"
|
||||
usage_tip = "Useless without a soul vessel and should not be created without one."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Cogscarab Shell, which produces a Cogscarab when filled with a Soul Vessel."
|
||||
|
||||
|
||||
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix
|
||||
descname = "Trap, Damage to Healing"
|
||||
name = "Vitality Matrix"
|
||||
desc = "Scribes a sigil beneath the invoker which drains life from any living non-Servants that cross it. Servants that cross it, however, will be healed based on how much Vitality all \
|
||||
Matrices have drained from non-Servants. Dead Servants can be revived by this sigil if there is vitality equal to the target Servant's non-oxygen damage."
|
||||
invocations = list("Divinity...", "...steal their life...", "...for these shells!")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/vitality
|
||||
creator_message = "<span class='brass'>A vitality matrix appears below you. It will drain life from non-Servants and heal Servants that cross it.</span>"
|
||||
usage_tip = "The sigil will be consumed upon reviving a Servant."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 3
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Vitality Matrix, which drains non-Servants on it to heal Servants that cross it."
|
||||
|
||||
|
||||
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_submission
|
||||
descname = "Trap, Conversion"
|
||||
name = "Sigil of Submission"
|
||||
desc = "Places a luminous sigil that will enslave any valid beings standing on it after a time."
|
||||
invocations = list("Divinity, enlighten...", "...those who trespass here!")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/submission
|
||||
creator_message = "<span class='brass'>A luminous sigil appears below you. The next non-servant to cross it will be enslaved after a brief time if they do not move.</span>"
|
||||
usage_tip = "This is not a primary conversion method - use Geis for that. It is advantageous as a trap, however, as it will transmit the name of the newly-converted."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Submission, which will convert one non-Servant that remains on it."
|
||||
|
||||
|
||||
//Soul Vessel: Creates a soul vessel, which can seek a ghost or be used on the uncovered head of a dead or dying human to take their brain.
|
||||
/datum/clockwork_scripture/create_object/soul_vessel
|
||||
descname = "Clockwork Posibrain"
|
||||
name = "Soul Vessel"
|
||||
desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar."
|
||||
invocations = list("Herd the souls of...", "...the blasphemous damned!")
|
||||
channel_time = 30
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/device/mmi/posibrain/soul_vessel
|
||||
creator_message = "<span class='brass'>You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness.</span>"
|
||||
usage_tip = "The vessel can be used as a teleport target for Spatial Gateway, though it is generally better-used by placing it in a shell or cyborg body."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Soul Vessel, which can be placed in construct shells and cyborg bodies once filled."
|
||||
|
||||
|
||||
//Clockwork Proselytizer: Creates a clockwork proselytizer, used to convert objects and repair clockwork structures.
|
||||
/datum/clockwork_scripture/create_object/clockwork_proselytizer
|
||||
descname = "Converts Objects to Ratvarian"
|
||||
name = "Clockwork Proselytizer"
|
||||
desc = "Forms a device that, when used on certain objects, converts them into their Ratvarian equivalents. It requires power to function."
|
||||
invocations = list("With this device...", "...his presence shall be made known.")
|
||||
channel_time = 20
|
||||
consumed_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/clockwork_proselytizer/preloaded
|
||||
creator_message = "<span class='brass'>You form a clockwork proselytizer.</span>"
|
||||
usage_tip = "Clockwork Walls cause nearby tinkerer's caches to generate components passively, making them a vital tool. Clockwork Floors heal toxin damage in Servants standing on them."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Clockwork Proselytizer, which can convert various objects to Ratvarian variants."
|
||||
|
||||
|
||||
//Function Call: Grants the invoker the ability to call forth a Ratvarian spear that deals significant damage to silicons.
|
||||
/datum/clockwork_scripture/function_call
|
||||
descname = "Permanent Summonable Spear"
|
||||
name = "Function Call"
|
||||
desc = "Grants the invoker the ability to call forth a powerful Ratvarian spear every three minutes. The spear will deal significant damage to Nar-Sie's dogs and silicon lifeforms, but will \
|
||||
vanish three minutes after being summoned."
|
||||
invocations = list("Grant me...", "...the might of brass!")
|
||||
channel_time = 20
|
||||
consumed_components = list(REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
whispered = TRUE
|
||||
usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and stun them, but break the spear."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 8
|
||||
|
||||
/datum/clockwork_scripture/function_call/check_special_requirements()
|
||||
for(var/datum/action/innate/function_call/F in invoker.actions)
|
||||
invoker << "<span class='warning'>You have already bound a Ratvarian spear to yourself!</span>"
|
||||
return FALSE
|
||||
return invoker.can_hold_items()
|
||||
|
||||
/datum/clockwork_scripture/function_call/scripture_effects()
|
||||
invoker.visible_message("<span class='warning'>A shimmer of yellow light infuses [invoker]!</span>", \
|
||||
"<span class='brass'>You bind a Ratvarian spear to yourself. Use the \"Function Call\" action button to call it forth.</span>")
|
||||
var/datum/action/innate/function_call/F = new()
|
||||
F.Grant(invoker)
|
||||
return TRUE
|
||||
|
||||
//Function Call action: Calls forth a Ratvarian spear once every 3 minutes.
|
||||
/datum/action/innate/function_call
|
||||
name = "Function Call"
|
||||
desc = "Allows you to summon a Ratvarian spear to fight enemies."
|
||||
button_icon_state = "ratvarian_spear"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/cooldown = 0
|
||||
var/base_cooldown = 1800
|
||||
|
||||
/datum/action/innate/function_call/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner) || cooldown > world.time)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/function_call/Activate()
|
||||
if(!owner.get_empty_held_indexes())
|
||||
usr << "<span class='warning'>You need an empty hand to call forth your spear!</span>"
|
||||
return FALSE
|
||||
owner.visible_message("<span class='warning'>A strange spear materializes in [owner]'s hands!</span>", "<span class='brass'>You call forth your spear!</span>")
|
||||
var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr))
|
||||
owner.put_in_hands(R)
|
||||
if(!ratvar_awakens)
|
||||
R.clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons, though it won't last for long."
|
||||
owner << "<span class='warning'>Your spear begins to break down in this plane of existence. You can't use it for long!</span>"
|
||||
R.timerid = addtimer(CALLBACK(R, /obj/item/clockwork/ratvarian_spear.proc/break_spear), base_cooldown, TIMER_STOPPABLE)
|
||||
cooldown = base_cooldown + world.time
|
||||
owner.update_action_buttons_icon()
|
||||
addtimer(CALLBACK(src, .proc/update_actions), base_cooldown)
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/function_call/proc/update_actions()
|
||||
if(owner)
|
||||
owner.update_action_buttons_icon()
|
||||
|
||||
|
||||
//Spatial Gateway: Allows the invoker to teleport themselves and any nearby allies to a conscious servant or clockwork obelisk.
|
||||
/datum/clockwork_scripture/spatial_gateway
|
||||
descname = "Teleport Gate"
|
||||
name = "Spatial Gateway"
|
||||
desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \
|
||||
Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration."
|
||||
invocations = list("Spatial Gateway...", "...activate!")
|
||||
channel_time = 80
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
/datum/clockwork_scripture/spatial_gateway/check_special_requirements()
|
||||
if(!isturf(invoker.loc))
|
||||
invoker << "<span class='warning'>You must not be inside an object to use this scripture!</span>"
|
||||
return FALSE
|
||||
var/other_servants = 0
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(is_servant_of_ratvar(L) && !L.stat && L != invoker)
|
||||
other_servants++
|
||||
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects)
|
||||
other_servants++
|
||||
if(!other_servants)
|
||||
invoker << "<span class='warning'>There are no other servants or clockwork obelisks!</span>"
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/spatial_gateway/scripture_effects()
|
||||
var/portal_uses = 0
|
||||
var/duration = 0
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
portal_uses++
|
||||
duration += 40 //4 seconds
|
||||
if(ratvar_awakens)
|
||||
portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
|
||||
//Volt Void: Channeled for up to five times over ten seconds to fire up to five rays of energy at target locations.
|
||||
/datum/clockwork_scripture/channeled/volt_void
|
||||
descname = "Channeled, Targeted Energy Blasts"
|
||||
name = "Volt Void" //Alternative name: "On all levels but physical, I am a power sink"
|
||||
desc = "Allows you to fire energy rays at target locations; more power consumed causes more damage. Channeled every fifth of a second for a maximum of ten seconds."
|
||||
channel_time = 30
|
||||
invocations = list("Amperage...", "...grant me your power!")
|
||||
chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!")
|
||||
chant_amount = 4
|
||||
chant_interval = 5
|
||||
consumed_components = list(GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations. Failing to fire causes backlash.<br><b>Maximum 4 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
"Boss says </span><span class='heavy_brass'>\"Click something, you idiot!\"</span><span class='nzcrentr'>.", "Stop wasting components if you can't aim.")
|
||||
|
||||
/datum/clockwork_scripture/channeled/volt_void/chant_effects(chant_number)
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/ranged_ability/volt_ray/ray = new
|
||||
ray.slab = slab
|
||||
ray.invoker = invoker
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!ray.run_scripture() && slab && invoker)
|
||||
if(can_recite() && T == get_turf(invoker))
|
||||
if(!ratvar_awakens)
|
||||
var/obj/structure/destructible/clockwork/powered/volt_checker/VC = new/obj/structure/destructible/clockwork/powered/volt_checker(get_turf(invoker))
|
||||
var/multiplier = 0.5
|
||||
var/usable_power = min(Floor(VC.total_accessable_power() * 0.2, MIN_CLOCKCULT_POWER), 1000)
|
||||
if(VC.try_use_power(usable_power))
|
||||
multiplier += (usable_power * 0.0005) //at maximum power, should be 1 multiplier
|
||||
qdel(VC)
|
||||
if(iscyborg(invoker))
|
||||
var/mob/living/silicon/robot/C = invoker
|
||||
if(C.cell)
|
||||
var/prev_power = usable_power //we don't want to increase the multiplier past 1
|
||||
usable_power = min(Floor(C.cell.charge * 0.2, MIN_CLOCKCULT_POWER), 1000) - prev_power
|
||||
if(usable_power > 0 && C.cell.use(usable_power))
|
||||
multiplier += (usable_power * 0.0005)
|
||||
var/obj/effect/overlay/temp/ratvar/volt_hit/VH = new /obj/effect/overlay/temp/ratvar/volt_hit(get_turf(invoker), null, multiplier)
|
||||
invoker.visible_message("<span class='warning'>[invoker] is struck by [invoker.p_their()] own [VH.name]!</span>", "<span class='userdanger'>You're struck by your own [VH.name]!</span>")
|
||||
invoker.adjustFireLoss(VH.damage) //you have to fail all five blasts to die to this
|
||||
playsound(invoker, 'sound/machines/defib_zap.ogg', VH.damage, 1, -1)
|
||||
invoker << "<span class='nzcrentr'>\"[text2ratvar(pick(nzcrentr_insults))]\"</span>"
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/ebeam/volt_ray
|
||||
name = "volt_ray"
|
||||
layer = LYING_MOB_LAYER
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/volt_ray
|
||||
name = "Volt Ray"
|
||||
slab_icon = "volt"
|
||||
allow_mobility = FALSE
|
||||
ranged_type = /obj/effect/proc_holder/slab/volt
|
||||
ranged_message = "<span class='nzcrentr_small'><i>You charge the clockwork slab with shocking might.</i>\n\
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/volt_checker
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
@@ -0,0 +1,295 @@
|
||||
//The base clockwork structure. Can have an alternate desc and will show up in the list of clockwork objects.
|
||||
/obj/structure/destructible/clockwork
|
||||
name = "meme structure"
|
||||
desc = "Some frog or something, the fuck?"
|
||||
var/clockwork_desc //Shown to servants when they examine
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "rare_pepe"
|
||||
var/unanchored_icon //icon for when this structure is unanchored, doubles as the var for if it can be unanchored
|
||||
anchored = 1
|
||||
density = 1
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/repair_amount = 4 //how much a proselytizer can repair each cycle
|
||||
var/can_be_repaired = TRUE //if a proselytizer can repair it at all
|
||||
break_message = "<span class='warning'>The frog isn't a meme after all!</span>" //The message shown when a structure breaks
|
||||
break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 2, \
|
||||
/obj/item/clockwork/alloy_shards/small = 3) //Parts left behind when a structure breaks
|
||||
var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station
|
||||
|
||||
/obj/structure/destructible/clockwork/New()
|
||||
..()
|
||||
change_construction_value(construction_value)
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/structure/destructible/clockwork/Destroy()
|
||||
change_construction_value(-construction_value)
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/ratvar_act()
|
||||
obj_integrity = max_integrity
|
||||
|
||||
/obj/structure/destructible/clockwork/narsie_act()
|
||||
if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist
|
||||
var/previouscolor = color
|
||||
color = "#960000"
|
||||
animate(src, color = previouscolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
|
||||
/obj/structure/destructible/clockwork/examine(mob/user)
|
||||
var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user)
|
||||
if(can_see_clockwork && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
if(unanchored_icon)
|
||||
user << "<span class='notice'>[src] is [anchored ? "":"not "]secured to the floor.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/examine_status(mob/user)
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/t_It = p_they(TRUE)
|
||||
var/t_is = p_are()
|
||||
var/heavily_damaged = FALSE
|
||||
var/healthpercent = (obj_integrity/max_integrity) * 100
|
||||
if(healthpercent < 50)
|
||||
heavily_damaged = TRUE
|
||||
return "<span class='[heavily_damaged ? "alloy":"brass"]'>[t_It] [t_is] at <b>[obj_integrity]/[max_integrity]</b> integrity[heavily_damaged ? "!":"."]</span>"
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/hulk_damage()
|
||||
return 20
|
||||
|
||||
/obj/structure/destructible/clockwork/proc/get_efficiency_mod(increasing)
|
||||
if(ratvar_awakens)
|
||||
if(increasing)
|
||||
return 0.5
|
||||
return 2
|
||||
. = max(sqrt(obj_integrity/max(max_integrity, 1)), 0.5)
|
||||
if(increasing)
|
||||
. *= min(max_integrity/max(obj_integrity, 1), 4)
|
||||
. = round(., 0.01)
|
||||
|
||||
/obj/structure/destructible/clockwork/can_be_unfasten_wrench(mob/user)
|
||||
if(anchored && obj_integrity <= round(max_integrity * 0.25, 1))
|
||||
user << "<span class='warning'>[src] is too damaged to unsecure!</span>"
|
||||
return FAILED_UNFASTEN
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_ai(mob/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
attack_hand(user)
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_animal(mob/living/simple_animal/M)
|
||||
if(is_servant_of_ratvar(M))
|
||||
attack_hand(M)
|
||||
return FALSE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params)
|
||||
if(is_servant_of_ratvar(user) && istype(I, /obj/item/weapon/wrench) && unanchored_icon)
|
||||
if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN)
|
||||
update_anchored(user, TRUE)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/proc/update_anchored(mob/user, do_damage)
|
||||
if(anchored)
|
||||
icon_state = initial(icon_state)
|
||||
else
|
||||
icon_state = unanchored_icon
|
||||
if(do_damage)
|
||||
playsound(src, break_sound, 10 * get_efficiency_mod(TRUE), 1)
|
||||
take_damage(round(max_integrity * 0.25, 1), BRUTE)
|
||||
user << "<span class='warning'>As you unsecure [src] from the floor, you see cracks appear in its surface!</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/emp_act(severity)
|
||||
if(anchored && unanchored_icon)
|
||||
anchored = FALSE
|
||||
update_anchored(null, obj_integrity > max_integrity * 0.25)
|
||||
new /obj/effect/overlay/temp/emp(loc)
|
||||
|
||||
|
||||
//for the ark and Ratvar
|
||||
/obj/structure/destructible/clockwork/massive
|
||||
name = "massive construct"
|
||||
desc = "A very large construction."
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
density = FALSE
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/New()
|
||||
..()
|
||||
poi_list += src
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/Destroy()
|
||||
poi_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/singularity_pull(S, current_size)
|
||||
return
|
||||
|
||||
|
||||
//the base clockwork machinery, which is not actually machines, but happens to use power
|
||||
/obj/structure/destructible/clockwork/powered
|
||||
var/obj/machinery/power/apc/target_apc
|
||||
var/active = FALSE
|
||||
var/needs_power = TRUE
|
||||
var/active_icon = null //icon_state while process() is being called
|
||||
var/inactive_icon = null //icon_state while process() isn't being called
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/powered = total_accessable_power()
|
||||
var/sigil_number = LAZYLEN(check_apc_and_sigils())
|
||||
user << "<span class='[powered ? "brass":"alloy"]'>It has access to <b>[powered == INFINITY ? "INFINITY":"[powered]"]W</b> of power, \
|
||||
and <b>[sigil_number]</b> Sigil[sigil_number == 1 ? "":"s"] of Transmission [sigil_number == 1 ? "is":"are"] in range.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/Destroy()
|
||||
SSfastprocess.processing -= src
|
||||
SSobj.processing -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/process()
|
||||
var/powered = total_accessable_power()
|
||||
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user)
|
||||
if(active)
|
||||
user << "<span class='warning'>[src] needs to be disabled before it can be unsecured!</span>"
|
||||
return FAILED_UNFASTEN
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user)
|
||||
if(user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return FALSE
|
||||
if(!anchored && !active)
|
||||
user << "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>"
|
||||
return FALSE
|
||||
visible_message("<span class='notice'>[user] [active ? "dis" : "en"]ables [src].</span>", "<span class='brass'>You [active ? "dis" : "en"]able [src].</span>")
|
||||
active = !active
|
||||
if(active)
|
||||
icon_state = active_icon
|
||||
if(fast_process)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
icon_state = inactive_icon
|
||||
if(fast_process)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/forced_disable(bad_effects)
|
||||
if(active)
|
||||
toggle()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/emp_act(severity)
|
||||
if(forced_disable(TRUE))
|
||||
new /obj/effect/overlay/temp/emp(loc)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/total_accessable_power() //how much power we have and can use
|
||||
if(!needs_power || ratvar_awakens)
|
||||
return INFINITY //oh yeah we've got power why'd you ask
|
||||
|
||||
var/power = 0
|
||||
power += accessable_apc_power()
|
||||
power += accessable_sigil_power()
|
||||
return power
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/accessable_apc_power()
|
||||
var/power = 0
|
||||
var/area/A = get_area(src)
|
||||
var/area/targetAPCA
|
||||
for(var/obj/machinery/power/apc/APC in apcs_list)
|
||||
var/area/APCA = get_area(APC)
|
||||
if(APCA == A)
|
||||
target_apc = APC
|
||||
if(target_apc)
|
||||
targetAPCA = get_area(target_apc)
|
||||
if(targetAPCA != A)
|
||||
target_apc = null
|
||||
else if(target_apc.cell)
|
||||
var/apccharge = target_apc.cell.charge
|
||||
if(apccharge >= MIN_CLOCKCULT_POWER)
|
||||
power += apccharge
|
||||
return power
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/accessable_sigil_power()
|
||||
var/power = 0
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
|
||||
power += T.power_charge
|
||||
return power
|
||||
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power
|
||||
if(!needs_power || ratvar_awakens)
|
||||
return 1
|
||||
if(amount <= 0)
|
||||
return FALSE
|
||||
var/power = total_accessable_power()
|
||||
if(!power || power < amount)
|
||||
return FALSE
|
||||
return use_power(amount)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it
|
||||
var/sigilpower = accessable_sigil_power()
|
||||
var/list/sigils_in_range = list()
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
|
||||
sigils_in_range += T
|
||||
while(sigilpower && amount >= MIN_CLOCKCULT_POWER)
|
||||
for(var/S in sigils_in_range)
|
||||
var/obj/effect/clockwork/sigil/transmission/T = S
|
||||
if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(MIN_CLOCKCULT_POWER))
|
||||
sigilpower -= MIN_CLOCKCULT_POWER
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
var/apcpower = accessable_apc_power()
|
||||
while(apcpower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER)
|
||||
if(target_apc.cell.use(MIN_CLOCKCULT_POWER))
|
||||
apcpower -= MIN_CLOCKCULT_POWER
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
target_apc.charging = 1
|
||||
target_apc.chargemode = TRUE
|
||||
target_apc.update()
|
||||
target_apc.update_icon()
|
||||
target_apc.updateUsrDialog()
|
||||
else
|
||||
apcpower = 0
|
||||
if(amount)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils or if there are no sigils, to the APC
|
||||
if(amount <= 0)
|
||||
return FALSE
|
||||
var/list/sigils_in_range = check_apc_and_sigils()
|
||||
if(!istype(sigils_in_range))
|
||||
return FALSE
|
||||
if(sigils_in_range.len)
|
||||
while(amount >= MIN_CLOCKCULT_POWER)
|
||||
for(var/S in sigils_in_range)
|
||||
var/obj/effect/clockwork/sigil/transmission/T = S
|
||||
if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(-MIN_CLOCKCULT_POWER))
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
if(target_apc && target_apc.cell && target_apc.cell.give(amount))
|
||||
target_apc.charging = 1
|
||||
target_apc.chargemode = TRUE
|
||||
target_apc.update()
|
||||
target_apc.update_icon()
|
||||
target_apc.updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/check_apc_and_sigils() //checks for sigils and an APC, returning FALSE if it finds neither, and a list of sigils otherwise
|
||||
. = list()
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
|
||||
. += T
|
||||
var/list/L = .
|
||||
if(!L.len && (!target_apc || !target_apc.cell))
|
||||
return FALSE
|
||||
@@ -1,955 +0,0 @@
|
||||
//////////////////////////
|
||||
// CLOCKWORK STRUCTURES //
|
||||
//////////////////////////
|
||||
|
||||
/obj/structure/clockwork
|
||||
name = "meme structure"
|
||||
desc = "Some frog or something, the fuck?"
|
||||
var/clockwork_desc //Shown to servants when they examine
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "rare_pepe"
|
||||
anchored = 1
|
||||
density = 1
|
||||
opacity = 0
|
||||
layer = BELOW_OBJ_LAYER
|
||||
var/max_health = 100 //All clockwork structures have health that can be removed via attacks
|
||||
var/health = 100
|
||||
var/repair_amount = 5 //how much a proselytizer can repair each cycle
|
||||
var/can_be_repaired = TRUE //if a proselytizer can repair it at all
|
||||
var/takes_damage = TRUE //If the structure can be damaged
|
||||
var/break_message = "<span class='warning'>The frog isn't a meme after all!</span>" //The message shown when a structure breaks
|
||||
var/break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
|
||||
var/list/debris = list(/obj/item/clockwork/alloy_shards) //Parts left behind when a structure breaks
|
||||
var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station
|
||||
|
||||
/obj/structure/clockwork/New()
|
||||
..()
|
||||
clockwork_construction_value += construction_value
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/structure/clockwork/Destroy()
|
||||
clockwork_construction_value -= construction_value
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/proc/destroyed()
|
||||
if(!takes_damage)
|
||||
return 0
|
||||
for(var/I in debris)
|
||||
new I (get_turf(src))
|
||||
visible_message(break_message)
|
||||
playsound(src, break_sound, 50, 1)
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
/obj/structure/clockwork/burn()
|
||||
SSobj.burning -= src
|
||||
if(takes_damage)
|
||||
playsound(src, 'sound/items/Welder.ogg', 100, 1)
|
||||
visible_message("<span class='warning'>[src] is warped by the heat!</span>")
|
||||
take_damage(rand(50, 100), BURN)
|
||||
|
||||
/obj/structure/clockwork/proc/take_damage(amount, damage_type)
|
||||
if(!amount || !damage_type || !damage_type in list(BRUTE, BURN))
|
||||
return 0
|
||||
if(takes_damage)
|
||||
health = max(0, health - amount)
|
||||
if(!health)
|
||||
destroyed()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/structure/clockwork/narsie_act()
|
||||
if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist
|
||||
var/previouscolor = color
|
||||
color = "#960000"
|
||||
animate(src, color = previouscolor, time = 8)
|
||||
|
||||
/obj/structure/clockwork/ex_act(severity)
|
||||
var/damage = 0
|
||||
switch(severity)
|
||||
if(1)
|
||||
damage = max_health //100% max health lost
|
||||
if(2)
|
||||
damage = max_health * rand(0.5, 0.7) //50-70% max health lost
|
||||
if(3)
|
||||
damage = max_health * rand(0.1, 0.3) //10-30% max health lost
|
||||
if(damage)
|
||||
take_damage(damage, BRUTE)
|
||||
|
||||
/obj/structure/clockwork/examine(mob/user)
|
||||
var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user)
|
||||
if(can_see_clockwork && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
if(takes_damage)
|
||||
var/servant_message = "It is at <b>[health]/[max_health]</b> integrity"
|
||||
var/other_message = "It seems pristine and undamaged"
|
||||
var/heavily_damaged = FALSE
|
||||
var/healthpercent = (health/max_health) * 100
|
||||
if(healthpercent >= 100)
|
||||
other_message = "It seems pristine and undamaged"
|
||||
else if(healthpercent >= 50)
|
||||
other_message = "It looks slightly dented"
|
||||
else if(healthpercent >= 25)
|
||||
other_message = "It appears heavily damaged"
|
||||
heavily_damaged = TRUE
|
||||
else if(healthpercent >= 0)
|
||||
other_message = "It's falling apart"
|
||||
heavily_damaged = TRUE
|
||||
user << "<span class='[heavily_damaged ? "alloy":"brass"]'>[can_see_clockwork ? "[servant_message]":"[other_message]"][heavily_damaged ? "!":"."]</span>"
|
||||
|
||||
/obj/structure/clockwork/bullet_act(obj/item/projectile/P)
|
||||
. = ..()
|
||||
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>")
|
||||
playsound(src, P.hitsound, 50, 1)
|
||||
take_damage(P.damage, P.damage_type)
|
||||
|
||||
/obj/structure/clockwork/proc/attack_generic(mob/user, damage = 0, damage_type = BRUTE) //used by attack_alien, attack_animal, and attack_slime
|
||||
user.do_attack_animation(src)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.visible_message("<span class='danger'>[user] smashes into [src]!</span>")
|
||||
take_damage(damage, damage_type)
|
||||
|
||||
/obj/structure/clockwork/attack_alien(mob/living/user)
|
||||
playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1)
|
||||
attack_generic(user, 15)
|
||||
|
||||
/obj/structure/clockwork/attack_animal(mob/living/simple_animal/M)
|
||||
if(!M.melee_damage_upper)
|
||||
return
|
||||
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
|
||||
attack_generic(M, M.melee_damage_upper, M.melee_damage_type)
|
||||
|
||||
/obj/structure/clockwork/attack_slime(mob/living/simple_animal/slime/user)
|
||||
if(!user.is_adult)
|
||||
return
|
||||
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
|
||||
attack_generic(user, rand(10, 15))
|
||||
|
||||
/obj/structure/clockwork/attacked_by(obj/item/I, mob/living/user)
|
||||
. = ..()
|
||||
if(I.force && takes_damage)
|
||||
playsound(src, I.hitsound, 50, 1)
|
||||
take_damage(I.force, I.damtype)
|
||||
|
||||
/obj/structure/clockwork/mech_melee_attack(obj/mecha/M)
|
||||
if(..())
|
||||
playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
|
||||
take_damage(M.force, M.damtype)
|
||||
|
||||
/obj/structure/clockwork/cache //Tinkerer's cache: Stores components for later use.
|
||||
name = "tinkerer's cache"
|
||||
desc = "A large brass spire with a flaming hole in its center."
|
||||
clockwork_desc = "A brass container capable of storing a large amount of components.\n\
|
||||
Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
|
||||
icon_state = "tinkerers_cache"
|
||||
construction_value = 10
|
||||
break_message = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
|
||||
max_health = 80
|
||||
health = 80
|
||||
var/wall_generation_cooldown
|
||||
var/wall_found = FALSE //if we've found a wall and finished our windup delay
|
||||
|
||||
/obj/structure/clockwork/cache/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
clockwork_caches++
|
||||
set_light(2,1)
|
||||
|
||||
/obj/structure/clockwork/cache/Destroy()
|
||||
clockwork_caches--
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/cache/destroyed()
|
||||
if(takes_damage)
|
||||
for(var/I in src)
|
||||
var/atom/movable/A = I
|
||||
A.forceMove(get_turf(src)) //drop any daemons we have
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/cache/process()
|
||||
for(var/turf/closed/wall/clockwork/C in orange(1, src))
|
||||
if(!wall_found)
|
||||
wall_found = TRUE
|
||||
wall_generation_cooldown = world.time + CACHE_PRODUCTION_TIME
|
||||
visible_message("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
|
||||
break
|
||||
if(wall_generation_cooldown <= world.time)
|
||||
wall_generation_cooldown = world.time + CACHE_PRODUCTION_TIME
|
||||
generate_cache_component()
|
||||
playsound(C, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
|
||||
visible_message("<span class='warning'>Something clunks around inside of [src]...</span>")
|
||||
break
|
||||
|
||||
/obj/structure/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return ..()
|
||||
if(istype(I, /obj/item/clockwork/component))
|
||||
var/obj/item/clockwork/component/C = I
|
||||
clockwork_component_cache[C.component_id]++
|
||||
user << "<span class='notice'>You add [C] to [src].</span>"
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab))
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
clockwork_component_cache["belligerent_eye"] += S.stored_components["belligerent_eye"]
|
||||
clockwork_component_cache["vanguard_cogwheel"] += S.stored_components["vanguard_cogwheel"]
|
||||
clockwork_component_cache["guvax_capacitor"] += S.stored_components["guvax_capacitor"]
|
||||
clockwork_component_cache["replicant_alloy"] += S.stored_components["replicant_alloy"]
|
||||
clockwork_component_cache["hierophant_ansible"] += S.stored_components["hierophant_ansible"]
|
||||
S.stored_components["belligerent_eye"] = 0
|
||||
S.stored_components["vanguard_cogwheel"] = 0
|
||||
S.stored_components["guvax_capacitor"] = 0
|
||||
S.stored_components["replicant_alloy"] = 0
|
||||
S.stored_components["hierophant_ansible"] = 0
|
||||
user.visible_message("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/daemon_shell))
|
||||
var/component_type
|
||||
switch(alert(user, "Will this daemon produce a specific type of component or produce randomly?.", , "Specific Type", "Random Component"))
|
||||
if("Specific Type")
|
||||
switch(input(user, "Choose a component type.", name) as null|anything in list("Belligerent Eyes", "Vanguard Cogwheels", "Guvax Capacitors", "Replicant Alloys", "Hierophant Ansibles"))
|
||||
if("Belligerent Eyes")
|
||||
component_type = "belligerent_eye"
|
||||
if("Vanguard Cogwheels")
|
||||
component_type = "vanguard_cogwheel"
|
||||
if("Guvax Capacitors")
|
||||
component_type = "guvax_capacitor"
|
||||
if("Replicant Alloys")
|
||||
component_type = "replicant_alloy"
|
||||
if("Hierophant Ansibles")
|
||||
component_type = "hierophant_ansibles"
|
||||
if(!user || !user.canUseTopic(src) || !user.canUseTopic(I))
|
||||
return 0
|
||||
var/obj/item/clockwork/tinkerers_daemon/D = new(src)
|
||||
D.cache = src
|
||||
D.specific_component = component_type
|
||||
user.visible_message("<span class='notice'>[user] spins the cogwheel on [I] and puts it into [src].</span>", \
|
||||
"<span class='notice'>You activate the daemon and put it into [src]. It will now produce a component every twenty seconds.</span>")
|
||||
user.drop_item()
|
||||
qdel(I)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/cache/attack_hand(mob/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return 0
|
||||
var/list/possible_components = list()
|
||||
if(clockwork_component_cache["belligerent_eye"])
|
||||
possible_components += "Belligerent Eye"
|
||||
if(clockwork_component_cache["vanguard_cogwheel"])
|
||||
possible_components += "Vanguard Cogwheel"
|
||||
if(clockwork_component_cache["guvax_capacitor"])
|
||||
possible_components += "Guvax Capacitor"
|
||||
if(clockwork_component_cache["replicant_alloy"])
|
||||
possible_components += "Replicant Alloy"
|
||||
if(clockwork_component_cache["hierophant_ansible"])
|
||||
possible_components += "Hierophant Ansible"
|
||||
if(!possible_components.len)
|
||||
user << "<span class='warning'>[src] is empty!</span>"
|
||||
return 0
|
||||
var/component_to_withdraw = input(user, "Choose a component to withdraw.", name) as null|anything in possible_components
|
||||
if(!user || !user.canUseTopic(src) || !component_to_withdraw)
|
||||
return 0
|
||||
var/obj/item/clockwork/component/the_component
|
||||
switch(component_to_withdraw)
|
||||
if("Belligerent Eye")
|
||||
if(clockwork_component_cache["belligerent_eye"])
|
||||
the_component = new/obj/item/clockwork/component/belligerent_eye(get_turf(src))
|
||||
clockwork_component_cache["belligerent_eye"]--
|
||||
if("Vanguard Cogwheel")
|
||||
if(clockwork_component_cache["vanguard_cogwheel"])
|
||||
the_component = new/obj/item/clockwork/component/vanguard_cogwheel(get_turf(src))
|
||||
clockwork_component_cache["vanguard_cogwheel"]--
|
||||
if("Guvax Capacitor")
|
||||
if(clockwork_component_cache["guvax_capacitor"])
|
||||
the_component = new/obj/item/clockwork/component/guvax_capacitor(get_turf(src))
|
||||
clockwork_component_cache["guvax_capacitor"]--
|
||||
if("Replicant Alloy")
|
||||
if(clockwork_component_cache["replicant_alloy"])
|
||||
the_component = new/obj/item/clockwork/component/replicant_alloy(get_turf(src))
|
||||
clockwork_component_cache["replicant_alloy"]--
|
||||
if("Hierophant Ansible")
|
||||
if(clockwork_component_cache["hierophant_ansible"])
|
||||
the_component = new/obj/item/clockwork/component/hierophant_ansible(get_turf(src))
|
||||
clockwork_component_cache["hierophant_ansible"]--
|
||||
if(the_component)
|
||||
user.visible_message("<span class='notice'>[user] withdraws [the_component] from [src].</span>", "<span class='notice'>You withdraw [the_component] from [src].</span>")
|
||||
user.put_in_hands(the_component)
|
||||
return 1
|
||||
|
||||
/obj/structure/clockwork/cache/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<b>Stored components:</b>"
|
||||
user << "<span class='neovgre_small'><i>Belligerent Eyes:</i> [clockwork_component_cache["belligerent_eye"]]</span>"
|
||||
user << "<span class='inathneq_small'><i>Vanguard Cogwheels:</i> [clockwork_component_cache["vanguard_cogwheel"]]</span>"
|
||||
user << "<span class='sevtug_small'><i>Guvax Capacitors:</i> [clockwork_component_cache["guvax_capacitor"]]</span>"
|
||||
user << "<span class='nezbere_small'><i>Replicant Alloys:</i> [clockwork_component_cache["replicant_alloy"]]</span>"
|
||||
user << "<span class='nzcrentr_small'><i>Hierophant Ansibles:</i> [clockwork_component_cache["hierophant_ansible"]]</span>"
|
||||
|
||||
|
||||
/obj/structure/clockwork/ocular_warden //Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with.
|
||||
name = "ocular warden"
|
||||
desc = "A large brass eye with tendrils trailing below it and a wide red iris."
|
||||
clockwork_desc = "A stalwart turret that will deal sustained damage to any non-faithful it sees."
|
||||
icon_state = "ocular_warden"
|
||||
health = 25
|
||||
max_health = 25
|
||||
construction_value = 15
|
||||
layer = HIGH_OBJ_LAYER
|
||||
break_message = "<span class='warning'>The warden's eye gives a glare of utter hate before falling dark!</span>"
|
||||
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye)
|
||||
burn_state = LAVA_PROOF
|
||||
var/damage_per_tick = 3
|
||||
var/sight_range = 3
|
||||
var/mob/living/target
|
||||
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
|
||||
|
||||
/obj/structure/clockwork/ocular_warden/New()
|
||||
..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/structure/clockwork/ocular_warden/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/ocular_warden/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='brass'>[target ? "<b>It's fixated on [target]!</b>" : "Its gaze is wandering aimlessly."]</span>"
|
||||
|
||||
/obj/structure/clockwork/ocular_warden/process()
|
||||
var/list/validtargets = acquire_nearby_targets()
|
||||
if(ratvar_awakens && (damage_per_tick == initial(damage_per_tick) || sight_range == initial(sight_range))) //Massive buff if Ratvar has returned
|
||||
damage_per_tick = 10
|
||||
sight_range = 5
|
||||
if(target)
|
||||
if(!(target in validtargets))
|
||||
lose_target()
|
||||
else
|
||||
if(!target.null_rod_check())
|
||||
target.adjustFireLoss(!iscultist(target) ? damage_per_tick : damage_per_tick * 2) //Nar-Sian cultists take additional damage
|
||||
if(ratvar_awakens && target)
|
||||
target.adjust_fire_stacks(damage_per_tick)
|
||||
target.IgniteMob()
|
||||
setDir(get_dir(get_turf(src), get_turf(target)))
|
||||
if(!target)
|
||||
if(validtargets.len)
|
||||
target = pick(validtargets)
|
||||
visible_message("<span class='warning'>[src] swivels to face [target]!</span>")
|
||||
target << "<span class='heavy_brass'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [ratvar_awakens ? "melts you alive" : "burns you"]!</span>"
|
||||
if(target.null_rod_check() && !ratvar_awakens)
|
||||
target << "<span class='warning'>Your artifact glows hotly against you, protecting you from the warden's gaze!</span>"
|
||||
else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes
|
||||
if(prob(50))
|
||||
visible_message("<span class='notice'>[src][pick(idle_messages)]</span>")
|
||||
else
|
||||
setDir(pick(cardinal))//Random rotation
|
||||
|
||||
/obj/structure/clockwork/ocular_warden/proc/acquire_nearby_targets()
|
||||
. = list()
|
||||
for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind
|
||||
if(!is_servant_of_ratvar(L) && !L.stat && L.mind && !(L.disabilities & BLIND) && !L.null_rod_check())
|
||||
. += L
|
||||
|
||||
/obj/structure/clockwork/ocular_warden/proc/lose_target()
|
||||
if(!target)
|
||||
return 0
|
||||
target = null
|
||||
visible_message("<span class='warning'>[src] settles and seems almost disappointed.</span>")
|
||||
return 1
|
||||
|
||||
|
||||
/obj/structure/clockwork/shell
|
||||
construction_value = 0
|
||||
anchored = 0
|
||||
density = 0
|
||||
takes_damage = FALSE
|
||||
burn_state = LAVA_PROOF
|
||||
var/mobtype = /mob/living/simple_animal/hostile/clockwork
|
||||
var/spawn_message = " is an error and you should yell at whoever spawned this shell."
|
||||
|
||||
/obj/structure/clockwork/shell/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
..()
|
||||
return 0
|
||||
var/obj/item/device/mmi/posibrain/soul_vessel/S = I
|
||||
if(!S.brainmob)
|
||||
user << "<span class='warning'>[S] hasn't trapped a spirit! Turn it on first.</span>"
|
||||
return 0
|
||||
if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind))
|
||||
user << "<span class='warning'>[S]'s trapped spirit appears inactive!</span>"
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] places [S] in [src], where it fuses to the shell.</span>", "<span class='brass'>You place [S] in [src], fusing it to the shell.</span>")
|
||||
var/mob/living/simple_animal/A = new mobtype(get_turf(src))
|
||||
A.visible_message("<span class='brass'>[src][spawn_message]</span>")
|
||||
S.brainmob.mind.transfer_to(A)
|
||||
add_servant_of_ratvar(A, TRUE)
|
||||
user.drop_item()
|
||||
qdel(S)
|
||||
qdel(src)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/shell/cogscarab
|
||||
name = "cogscarab shell"
|
||||
desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism."
|
||||
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer."
|
||||
icon_state = "clockdrone_shell"
|
||||
mobtype = /mob/living/simple_animal/drone/cogscarab
|
||||
spawn_message = "'s eyes blink open, glowing bright red."
|
||||
|
||||
/obj/structure/clockwork/shell/fragment //Anima fragment: Useless on its own, but can accept an active soul vessel to create a powerful construct.
|
||||
name = "fragment shell"
|
||||
desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power."
|
||||
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct."
|
||||
icon_state = "anime_fragment"
|
||||
mobtype = /mob/living/simple_animal/hostile/clockwork/fragment
|
||||
spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire."
|
||||
|
||||
|
||||
/obj/structure/clockwork/wall_gear
|
||||
name = "massive gear"
|
||||
icon_state = "wall_gear"
|
||||
climbable = TRUE
|
||||
max_health = 50
|
||||
health = 50
|
||||
desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it."
|
||||
clockwork_desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, just climb over it, or proselytize it into replicant alloy."
|
||||
break_message = "<span class='warning'>The gear breaks apart into shards of alloy!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards)
|
||||
|
||||
/obj/structure/clockwork/wall_gear/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/wrench))
|
||||
default_unfasten_wrench(user, I, 10)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/clockwork/wall_gear/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='notice'>[src] is [anchored ? "secured to the floor":"mobile, and not secured"].</span>"
|
||||
|
||||
///////////////////////
|
||||
// CLOCKWORK EFFECTS //
|
||||
///////////////////////
|
||||
|
||||
/obj/effect/clockwork
|
||||
name = "meme machine"
|
||||
desc = "Still don't know what it is."
|
||||
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "ratvars_flame"
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
burn_state = LAVA_PROOF
|
||||
|
||||
/obj/effect/clockwork/New()
|
||||
..()
|
||||
all_clockwork_objects += src
|
||||
|
||||
/obj/effect/clockwork/Destroy()
|
||||
all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker //Judicial marker: Created by the judicial visor. After three seconds, stuns any non-servants nearby and damages Nar-Sian cultists.
|
||||
name = "judicial marker"
|
||||
desc = "You get the feeling that you shouldn't be standing here."
|
||||
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_MOB_LAYER
|
||||
var/mob/user
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/New(loc, caster)
|
||||
..()
|
||||
user = caster
|
||||
playsound(src, 'sound/magic/MAGIC_MISSILE.ogg', 50, 1, 1, 1)
|
||||
flick("judicial_marker", src)
|
||||
addtimer(src, "burstanim", 16, FALSE)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/proc/burstanim()
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
flick("judicial_explosion", src)
|
||||
addtimer(src, "judicialblast", 13, FALSE)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/proc/judicialblast()
|
||||
var/targetsjudged = 0
|
||||
playsound(src, 'sound/effects/explosionfar.ogg', 100, 1, 1, 1)
|
||||
for(var/mob/living/L in range(1, src))
|
||||
if(is_servant_of_ratvar(L))
|
||||
continue
|
||||
if(L.null_rod_check())
|
||||
var/obj/item/I = L.null_rod_check()
|
||||
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
continue
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
|
||||
L.Weaken(8)
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='heavy_brass'>\"Keep an eye out, filth.\"</span>\n<span class='userdanger'>A burst of heat crushes you against the ground!</span>")
|
||||
L.Weaken(4) //half the stun, but sets cultists on fire
|
||||
L.adjust_fire_stacks(2)
|
||||
L.IgniteMob()
|
||||
targetsjudged++
|
||||
L.adjustBruteLoss(10)
|
||||
user << "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[!targetsjudged || targetsjudged > 1 ? "s":""].</b></span>"
|
||||
QDEL_IN(src, 3) //so the animation completes properly
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/ex_act(severity)
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway //Spatial gateway: A usually one-way rift to another location.
|
||||
name = "spatial gateway"
|
||||
desc = "A gently thrumming tear in reality."
|
||||
clockwork_desc = "A gateway in reality."
|
||||
icon_state = "spatial_gateway"
|
||||
density = 1
|
||||
var/sender = TRUE //If this gateway is made for sending, not receiving
|
||||
var/both_ways = FALSE
|
||||
var/lifetime = 25 //How many deciseconds this portal will last
|
||||
var/uses = 1 //How many objects or mobs can go through the portal
|
||||
var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/New()
|
||||
..()
|
||||
spawn(1)
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return 0
|
||||
if(both_ways)
|
||||
clockwork_desc = "A gateway in reality. It can both send and receive objects."
|
||||
else
|
||||
clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects."
|
||||
QDEL_IN(src, lifetime)
|
||||
|
||||
//set up a gateway with another gateway
|
||||
/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way)
|
||||
if(!gatewayB || !set_duration || !uses)
|
||||
return 0
|
||||
linked_gateway = gatewayB
|
||||
gatewayB.linked_gateway = src
|
||||
if(two_way)
|
||||
both_ways = TRUE
|
||||
gatewayB.both_ways = TRUE
|
||||
else
|
||||
sender = TRUE
|
||||
gatewayB.sender = FALSE
|
||||
gatewayB.density = FALSE
|
||||
lifetime = set_duration
|
||||
gatewayB.lifetime = set_duration
|
||||
uses = set_uses
|
||||
gatewayB.uses = set_uses
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='brass'>It has [uses] uses remaining.</span>"
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user)
|
||||
if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
|
||||
var/mob/living/L = user.pulling
|
||||
if(L.buckled || L.anchored || L.has_buckled_mobs())
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] shoves [L] into [src]!</span>", "<span class='danger'>You shove [L] into [src]!</span>")
|
||||
user.stop_pulling()
|
||||
pass_through_gateway(L)
|
||||
return 1
|
||||
if(!user.canUseTopic(src))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] climbs through [src]!</span>", "<span class='danger'>You brace yourself and step through [src]...</span>")
|
||||
pass_through_gateway(user)
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/weapon/nullrod))
|
||||
user.visible_message("<span class='warning'>[user] dispels [src] with [I]!</span>", "<span class='danger'>You close [src] with [I]!</span>")
|
||||
qdel(linked_gateway)
|
||||
qdel(src)
|
||||
return 1
|
||||
if(istype(I, /obj/item/clockwork/slab))
|
||||
user << "<span class='heavy_brass'>\"I don't think you want to drop your slab into that\".\n\"If you really want to, try throwing it.\"</span>"
|
||||
return 1
|
||||
if(user.drop_item())
|
||||
user.visible_message("<span class='warning'>[user] drops [I] into [src]!</span>", "<span class='danger'>You drop [I] into [src]!</span>")
|
||||
pass_through_gateway(I)
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Bumped(atom/A)
|
||||
..()
|
||||
if(isliving(A) || istype(A, /obj/item))
|
||||
pass_through_gateway(A)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A)
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return 0
|
||||
if(!sender)
|
||||
visible_message("<span class='warning'>[A] bounces off of [src]!</span>")
|
||||
return 0
|
||||
if(!uses)
|
||||
return 0
|
||||
if(isliving(A))
|
||||
var/mob/living/user = A
|
||||
user << "<span class='warning'><b>You pass through [src] and appear elsewhere!</b></span>"
|
||||
linked_gateway.visible_message("<span class='warning'>A shape appears in [linked_gateway] before emerging!</span>")
|
||||
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
transform = matrix() * 1.5
|
||||
animate(src, transform = matrix() / 1.5, time = 10)
|
||||
linked_gateway.transform = matrix() * 1.5
|
||||
animate(linked_gateway, transform = matrix() / 1.5, time = 10)
|
||||
A.forceMove(get_turf(linked_gateway))
|
||||
uses = max(0, uses - 1)
|
||||
linked_gateway.uses = max(0, linked_gateway.uses - 1)
|
||||
spawn(10)
|
||||
if(!uses)
|
||||
qdel(src)
|
||||
qdel(linked_gateway)
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/general_marker
|
||||
name = "general marker"
|
||||
desc = "Some big guy. For you."
|
||||
clockwork_desc = "One of Ratvar's generals."
|
||||
alpha = 200
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
|
||||
/obj/effect/clockwork/general_marker/New()
|
||||
..()
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
animate(src, alpha = 0, time = 10)
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/obj/effect/clockwork/general_marker/nezbere
|
||||
name = "Nezbere, the Brass Eidolon"
|
||||
desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you."
|
||||
clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain."
|
||||
icon = 'icons/effects/340x428.dmi'
|
||||
icon_state = "nezbere"
|
||||
pixel_x = -154
|
||||
pixel_y = -198
|
||||
|
||||
/obj/effect/clockwork/general_marker/sevtug
|
||||
name = "Sevtug, the Formless Pariah"
|
||||
desc = "A sinister cloud of purple energy. Looking at it gives you a headache."
|
||||
clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies."
|
||||
icon = 'icons/effects/211x247.dmi'
|
||||
icon_state = "sevtug"
|
||||
pixel_x = -89
|
||||
pixel_y = -107
|
||||
|
||||
/obj/effect/clockwork/general_marker/nzcrentr
|
||||
name = "Nzcrentr, the Forgotten Arbiter"
|
||||
desc = "A terrifying war machine crackling with limitless energy."
|
||||
clockwork_desc = "One of Ratvar's four generals. Nzcrentr is the result of Neovgre - Nezbere's finest war machine, commandeerable only be a mortal - fusing with its pilot and driving her \
|
||||
insane. Nzcrentr seeks out any and all sentient life to slaughter it for sport."
|
||||
icon = 'icons/effects/254x361.dmi'
|
||||
icon_state = "nzcrentr"
|
||||
pixel_x = -111
|
||||
pixel_y = -164
|
||||
|
||||
/obj/effect/clockwork/general_marker/inathneq
|
||||
name = "Inath-Neq, the Resonant Cogwheel"
|
||||
desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring."
|
||||
clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-Neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \
|
||||
their prowess. After a lost battle with Nar-Sian cultists, Inath-Neq was struck down and stated in her dying breath, \
|
||||
\"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-Neq an eternal body and \
|
||||
merged her soul with those of the Cogs slain with her on the battlefield."
|
||||
icon = 'icons/effects/187x381.dmi'
|
||||
icon_state = "inath-neq"
|
||||
pixel_x = -77
|
||||
pixel_y = -174
|
||||
|
||||
|
||||
/obj/effect/clockwork/sigil //Sigils: Rune-like markings on the ground with various effects.
|
||||
name = "sigil"
|
||||
desc = "A strange set of markings drawn on the ground."
|
||||
clockwork_desc = "A sigil of some purpose."
|
||||
icon_state = "sigil"
|
||||
layer = LOW_OBJ_LAYER
|
||||
alpha = 50
|
||||
burn_state = FIRE_PROOF
|
||||
burntime = 1
|
||||
var/affects_servants = FALSE
|
||||
var/stat_affected = CONSCIOUS
|
||||
|
||||
/obj/effect/clockwork/sigil/attack_hand(mob/user)
|
||||
if(iscarbon(user) && !user.stat && (!is_servant_of_ratvar(user) || (is_servant_of_ratvar(user) && user.a_intent == "harm")))
|
||||
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/sigil/Crossed(atom/movable/AM)
|
||||
..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat <= stat_affected)
|
||||
if((!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && affects_servants)) && L.mind)
|
||||
if(L.null_rod_check())
|
||||
var/obj/item/I = L.null_rod_check()
|
||||
L.visible_message("<span class='warning'>[L]'s [I.name] protects them from [src]'s effects!</span>", "<span class='userdanger'>Your [I.name] protects you!</span>")
|
||||
return
|
||||
sigil_effects(L)
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L)
|
||||
|
||||
/obj/effect/clockwork/sigil/transgression //Sigil of Transgression: Stuns and flashes the first non-servant to walk on it. Nar-Sian cultists are damaged and knocked down for about twice the stun
|
||||
name = "dull sigil"
|
||||
desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
clockwork_desc = "A sigil that will stun the first non-servant to cross it. Nar-Sie's dogs will be knocked down."
|
||||
icon_state = "sigildull"
|
||||
color = "#FAE48C"
|
||||
|
||||
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
|
||||
var/target_flashed = L.flash_eyes()
|
||||
for(var/mob/living/M in viewers(5, src))
|
||||
if(!is_servant_of_ratvar(M) && M != L)
|
||||
M.flash_eyes()
|
||||
if(iscultist(L))
|
||||
L << "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>"
|
||||
L.adjustBruteLoss(10)
|
||||
L.Weaken(4)
|
||||
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
|
||||
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
|
||||
L.Stun(3)
|
||||
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/transgression, get_turf(src))
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/sigil/submission //Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards.
|
||||
name = "ominous sigil"
|
||||
desc = "A luminous golden sigil. Something about it really bothers you."
|
||||
clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for five seconds."
|
||||
icon_state = "sigilsubmission"
|
||||
color = "#FAE48C"
|
||||
alpha = 125
|
||||
stat_affected = UNCONSCIOUS
|
||||
var/convert_time = 50
|
||||
var/glow_light = 2 //soft light
|
||||
var/glow_falloff = 1
|
||||
var/delete_on_finish = TRUE
|
||||
var/sigil_name = "Sigil of Submission"
|
||||
var/glow_type
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/New()
|
||||
..()
|
||||
set_light(glow_light,glow_falloff)
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L)
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>")
|
||||
animate(src, color = "#AF0AAF", time = convert_time)
|
||||
var/obj/effect/overlay/temp/ratvar/sigil/glow
|
||||
if(glow_type)
|
||||
glow = PoolOrNew(glow_type, get_turf(src))
|
||||
animate(glow, alpha = 255, time = convert_time)
|
||||
var/I = 0
|
||||
while(I < convert_time && get_turf(L) == get_turf(src))
|
||||
I++
|
||||
sleep(1)
|
||||
if(get_turf(L) != get_turf(src))
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
animate(src, color = initial(color), time = 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
return 0
|
||||
post_channel(L)
|
||||
if(is_eligible_servant(L))
|
||||
L << "<span class='heavy_brass'>\"You belong to me now.\"</span>"
|
||||
add_servant_of_ratvar(L)
|
||||
L.Weaken(3) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
L.Stun(3)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 5
|
||||
var/message = "[sigil_name] in [get_area(src)] <span class='sevtug'>[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]</span>"
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, L)
|
||||
M << "[link] <span class='heavy_brass'>[message] [L.real_name]!</span>"
|
||||
else if(is_servant_of_ratvar(M))
|
||||
if(M == L)
|
||||
M << "<span class='heavy_brass'>[message] you!</span>"
|
||||
else
|
||||
M << "<span class='heavy_brass'>[message] [L.real_name]!</span>"
|
||||
if(delete_on_finish)
|
||||
qdel(src)
|
||||
else
|
||||
animate(src, color = initial(color), time = 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/accession //Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards.
|
||||
name = "terrifying sigil"
|
||||
desc = "A luminous brassy sigil. Something about it makes you want to flee."
|
||||
clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for five seconds. \n\
|
||||
It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets."
|
||||
icon_state = "sigiltransgression"
|
||||
color = "#A97F1B"
|
||||
alpha = 200
|
||||
glow_light = 4 //bright light
|
||||
glow_falloff = 3
|
||||
delete_on_finish = FALSE
|
||||
sigil_name = "Sigil of Accession"
|
||||
glow_type = /obj/effect/overlay/temp/ratvar/sigil/accession
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L)
|
||||
if(isloyal(L))
|
||||
delete_on_finish = TRUE
|
||||
L.visible_message("<span class='warning'>[L] visibly trembles!</span>", \
|
||||
"<span class='sevtug'>Lbh jvyy or zvar-naq-uvf. Guvf chal gevaxrg jvyy abg fgbc zr.</span>")
|
||||
for(var/obj/item/weapon/implant/mindshield/M in L)
|
||||
if(M.implanted)
|
||||
qdel(M)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission
|
||||
name = "suspicious sigil"
|
||||
desc = "A glowing orange sigil. The air around it feels staticky."
|
||||
clockwork_desc = "A sigil that will serve as a battery for clockwork structures. Use Volt Void while standing on it to charge it."
|
||||
icon_state = "sigiltransmission"
|
||||
color = "#EC8A2D"
|
||||
alpha = 50
|
||||
var/power_charge = 2500 //starts with 2500W by default
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='[power_charge ? "brass":"alloy"]'>It is storing [power_charge]W of power.</span>"
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
|
||||
if(power_charge)
|
||||
L << "<span class='brass'>You feel a slight, static shock.</span>"
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/New()
|
||||
..()
|
||||
alpha = min(initial(alpha) + power_charge*0.02, 255)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
|
||||
if(power_charge - amount < 0)
|
||||
return 0
|
||||
power_charge -= amount
|
||||
alpha = min(initial(alpha) + power_charge*0.02, 255)
|
||||
return 1
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality
|
||||
name = "comforting sigil"
|
||||
desc = "A faint blue sigil. Looking at it makes you feel protected."
|
||||
clockwork_desc = "A sigil that will drain non-servants that remain on it. Servants that remain on it will be healed if it has any vitality drained."
|
||||
icon_state = "sigilvitality"
|
||||
color = "#123456"
|
||||
alpha = 75
|
||||
affects_servants = TRUE
|
||||
stat_affected = DEAD
|
||||
var/vitality = 0
|
||||
var/base_revive_cost = 20
|
||||
var/sigil_active = FALSE
|
||||
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='[vitality ? "inathneq_small":"alloy"]'>It is storing [vitality] units of vitality.</span>"
|
||||
user << "<span class='inathneq_small'>It requires at least [base_revive_cost] units of vitality to revive dead servants, in addition to any damage the servant has.</span>"
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
|
||||
if(L.suiciding || sigil_active || !is_servant_of_ratvar(L) && L.stat == DEAD)
|
||||
return 0
|
||||
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
|
||||
animate(src, alpha = 255, time = 10)
|
||||
sleep(10)
|
||||
sigil_active = TRUE
|
||||
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
|
||||
while(L && (!is_servant_of_ratvar(L) && L.stat != DEAD || (is_servant_of_ratvar(L) && vitality)) && get_turf(L) == get_turf(src))
|
||||
if(animation_number >= 4)
|
||||
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src))
|
||||
animation_number = 0
|
||||
animation_number++
|
||||
if(!is_servant_of_ratvar(L))
|
||||
var/vitality_drained = L.adjustToxLoss(1.5)
|
||||
if(vitality_drained)
|
||||
vitality += vitality_drained
|
||||
else
|
||||
break
|
||||
else
|
||||
var/clone_to_heal = L.getCloneLoss()
|
||||
var/tox_to_heal = L.getToxLoss()
|
||||
var/burn_to_heal = L.getFireLoss()
|
||||
var/brute_to_heal = L.getBruteLoss()
|
||||
var/oxy_to_heal = L.getOxyLoss()
|
||||
var/total_damage = clone_to_heal + tox_to_heal + burn_to_heal + brute_to_heal + oxy_to_heal
|
||||
if(L.stat == DEAD)
|
||||
var/revival_cost = base_revive_cost + total_damage - oxy_to_heal //ignores oxygen damage
|
||||
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
|
||||
if(ghost)
|
||||
if(vitality >= revival_cost)
|
||||
ghost.reenter_corpse()
|
||||
L.revive(1, 1)
|
||||
playsound(L, 'sound/magic/Staff_Healing.ogg', 50, 1)
|
||||
L.visible_message("<span class='warning'>[L] suddenly gets back up, their mouth dripping blue ichor!</span>", "<span class='inathneq'>\"Lbh jvyy or bxnl, puvyq.\"</span>")
|
||||
vitality -= revival_cost
|
||||
break
|
||||
else
|
||||
break
|
||||
if(!total_damage)
|
||||
break
|
||||
var/vitality_for_cycle = min(vitality, 3)
|
||||
|
||||
if(clone_to_heal && vitality_for_cycle)
|
||||
var/healing = min(vitality_for_cycle, clone_to_heal)
|
||||
vitality_for_cycle -= healing
|
||||
L.adjustCloneLoss(-healing)
|
||||
vitality -= healing
|
||||
|
||||
if(tox_to_heal && vitality_for_cycle)
|
||||
var/healing = min(vitality_for_cycle, tox_to_heal)
|
||||
vitality_for_cycle -= healing
|
||||
L.adjustToxLoss(-healing)
|
||||
vitality -= healing
|
||||
|
||||
if(burn_to_heal && vitality_for_cycle)
|
||||
var/healing = min(vitality_for_cycle, burn_to_heal)
|
||||
vitality_for_cycle -= healing
|
||||
L.adjustFireLoss(-healing)
|
||||
vitality -= healing
|
||||
|
||||
if(brute_to_heal && vitality_for_cycle)
|
||||
var/healing = min(vitality_for_cycle, brute_to_heal)
|
||||
vitality_for_cycle -= healing
|
||||
L.adjustBruteLoss(-healing)
|
||||
vitality -= healing
|
||||
|
||||
if(oxy_to_heal && vitality_for_cycle)
|
||||
var/healing = min(vitality_for_cycle, oxy_to_heal)
|
||||
vitality_for_cycle -= healing
|
||||
L.adjustOxyLoss(-healing)
|
||||
vitality -= healing
|
||||
sleep(2)
|
||||
|
||||
animation_number = initial(animation_number)
|
||||
sigil_active = FALSE
|
||||
animate(src, alpha = initial(alpha), time = 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
@@ -0,0 +1,255 @@
|
||||
//The gateway to Reebe, from which Ratvar emerges.
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway
|
||||
name = "Gateway to the Celestial Derelict"
|
||||
desc = "A massive, thrumming rip in spacetime."
|
||||
clockwork_desc = "A portal to the Celestial Derelict. Massive and intimidating, it is the only thing that can both transport Ratvar and withstand the massive amount of energy he emits."
|
||||
obj_integrity = 500
|
||||
max_integrity = 500
|
||||
mouse_opacity = 2
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "nothing"
|
||||
density = FALSE
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
|
||||
can_be_repaired = FALSE
|
||||
var/progress_in_seconds = 0 //Once this reaches GATEWAY_RATVAR_ARRIVAL, it's game over
|
||||
var/purpose_fulfilled = FALSE
|
||||
var/first_sound_played = FALSE
|
||||
var/second_sound_played = FALSE
|
||||
var/third_sound_played = FALSE
|
||||
var/ratvar_portal = TRUE //if the gateway actually summons ratvar or just produces a hugeass conversion burst
|
||||
var/obj/effect/clockwork/overlay/gateway_glow/glow
|
||||
var/obj/effect/countdown/clockworkgate/countdown
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/New()
|
||||
..()
|
||||
INVOKE_ASYNC(src, .proc/spawn_animation)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/spawn_animation()
|
||||
var/turf/T = get_turf(src)
|
||||
var/objective_is_gateway = (ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY)
|
||||
new/obj/effect/clockwork/general_marker/inathneq(T)
|
||||
if(objective_is_gateway)
|
||||
hierophant_message("<span class='inathneq'>\"[text2ratvar("Engine, come forth and show your servants your mercy")]!\"</span>")
|
||||
else
|
||||
hierophant_message("<span class='inathneq'>\"[text2ratvar("We will show all the mercy of Engine")]!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 30, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/sevtug(T)
|
||||
if(objective_is_gateway)
|
||||
hierophant_message("<span class='sevtug'>\"[text2ratvar("Engine, come forth and show this station your decorating skills")]!\"</span>")
|
||||
else
|
||||
hierophant_message("<span class='sevtug'>\"[text2ratvar("We will show all Engine's decorating skills")]!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 45, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/nezbere(T)
|
||||
if(objective_is_gateway)
|
||||
hierophant_message("<span class='nezbere'>\"[text2ratvar("Engine, come forth and shine your light across this realm")]!!\"</span>")
|
||||
else
|
||||
hierophant_message("<span class='nezbere'>\"[text2ratvar("We will show all Engine's light")]!!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 60, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/nzcrentr(T)
|
||||
if(objective_is_gateway)
|
||||
hierophant_message("<span class='nzcrentr'>\"[text2ratvar("Engine, come forth")].\"</span>")
|
||||
else
|
||||
hierophant_message("<span class='nzcrentr'>\"[text2ratvar("We will show all Engine's power")].\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0)
|
||||
sleep(10)
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0)
|
||||
var/list/open_turfs = list()
|
||||
for(var/turf/open/OT in orange(1, T))
|
||||
if(!is_blocked_turf(OT, TRUE))
|
||||
open_turfs |= OT
|
||||
if(open_turfs.len)
|
||||
for(var/mob/living/L in T)
|
||||
L.forceMove(pick(open_turfs))
|
||||
resistance_flags &= ~INDESTRUCTIBLE
|
||||
density = TRUE
|
||||
invisibility = 0
|
||||
glow = new(get_turf(src))
|
||||
countdown = new(src)
|
||||
countdown.start()
|
||||
var/area/gate_area = get_area(src)
|
||||
hierophant_message("<span class='large_brass'><b>A gateway to the Celestial Derelict has been created in [gate_area.map_name]!</b></span>", FALSE, src)
|
||||
if(!objective_is_gateway)
|
||||
ratvar_portal = FALSE
|
||||
hierophant_message("<span class='big_brass'>This newly constructed gateway will not free Ratvar, \
|
||||
and will instead simply proselytize and convert everything and everyone on the station.</span>", TRUE)
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
if(!purpose_fulfilled)
|
||||
var/area/gate_area = get_area(src)
|
||||
hierophant_message("<span class='large_brass'><b>A gateway to the Celestial Derelict has fallen at [gate_area.map_name]!</b></span>")
|
||||
send_to_playing_players(sound(null, 0, channel = 8))
|
||||
var/was_stranded = SSshuttle.emergency.mode == SHUTTLE_STRANDED
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
if(!was_stranded && !purpose_fulfilled && second_sound_played)
|
||||
priority_announce("Massive energy anomaly no longer on short-range scanners.","Anomaly Alert")
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
glow = null
|
||||
if(countdown)
|
||||
qdel(countdown)
|
||||
countdown = null
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/deconstruct(disassembled = TRUE)
|
||||
if(!(flags & NODECONSTRUCT))
|
||||
if(!disassembled)
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
countdown.stop()
|
||||
visible_message("<span class='userdanger'>The [src] begins to pulse uncontrollably... you might want to run!</span>")
|
||||
send_to_playing_players(sound('sound/effects/clockcult_gateway_disrupted.ogg', 0, channel = 8, volume = 50))
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_disrupted"
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
sleep(27)
|
||||
explosion(src, 1, 3, 8, 8)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/make_glow()
|
||||
if(!glow)
|
||||
glow = new /obj/effect/clockwork/overlay/gateway_glow(get_turf(src))
|
||||
glow.linked = src
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/ex_act(severity)
|
||||
var/damage = max((obj_integrity * 0.70) / severity, 100) //requires multiple bombs to take down
|
||||
take_damage(damage, BRUTE, "bomb", 0)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/get_arrival_text(s_on_time)
|
||||
. = "IMMINENT"
|
||||
if(!obj_integrity)
|
||||
. = "DETONATING"
|
||||
else if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0)
|
||||
. = "[round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE), 0), 1)][s_on_time ? "S":""]"
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/examine(mob/user)
|
||||
icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon
|
||||
..()
|
||||
icon_state = initial(icon_state)
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='big'><b>Seconds until [ratvar_portal ? "Ratvar's arrival":"Proselytization"]:</b> [get_arrival_text(TRUE)]</span>"
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
user << "<span class='heavy_brass'>It's still opening.</span>"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
user << "<span class='heavy_brass'>It's reached the Celestial Derelict and is drawing power from it.</span>"
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
user << "<span class='heavy_brass'>[ratvar_portal ? "Ratvar is coming through the gateway":"The gateway is glowing with massed power"]!</span>"
|
||||
else
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
user << "<span class='warning'>It's a swirling mass of blackness.</span>"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
user << "<span class='warning'>It seems to be leading somewhere.</span>"
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
user << "<span class='boldwarning'>[ratvar_portal ? "Something is coming through":"It's glowing brightly"]!</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/process()
|
||||
if(!progress_in_seconds || prob(7))
|
||||
for(var/M in player_list)
|
||||
if(M && !isnewplayer(M))
|
||||
M << "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>"
|
||||
if(!obj_integrity)
|
||||
return 0
|
||||
var/convert_dist = 1 + (round(Floor(progress_in_seconds, 15) * 0.067))
|
||||
for(var/t in RANGE_TURFS(convert_dist, loc))
|
||||
var/turf/T = t
|
||||
if(!T)
|
||||
continue
|
||||
if(get_dist(T, src) < 2)
|
||||
if(iswallturf(T))
|
||||
var/turf/closed/wall/W = T
|
||||
W.dismantle_wall()
|
||||
else if(t && (isclosedturf(T) || !is_blocked_turf(T)))
|
||||
T.ChangeTurf(/turf/open/floor/clockwork)
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x, y)
|
||||
if(dist < convert_dist)
|
||||
T.ratvar_act(FALSE, TRUE, 3)
|
||||
for(var/obj/O in orange(1, src))
|
||||
if(!O.pulledby && !istype(O, /obj/effect) && O.density)
|
||||
if(!step_away(O, src, 2) || get_dist(O, src) < 2)
|
||||
O.take_damage(50, BURN, "bomb")
|
||||
O.update_icon()
|
||||
progress_in_seconds += GATEWAY_SUMMON_RATE
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
if(!first_sound_played)
|
||||
send_to_playing_players(sound('sound/effects/clockcult_gateway_charging.ogg', 1, channel = 8, volume = 30))
|
||||
first_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_charging"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
if(!second_sound_played)
|
||||
var/area/gate_area = get_area(src)
|
||||
priority_announce("Massive energy anomaly detected on short-range scanners. Location: [gate_area.map_name].", "Anomaly Alert")
|
||||
send_to_playing_players(sound('sound/effects/clockcult_gateway_active.ogg', 1, channel = 8, volume = 35))
|
||||
second_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_active"
|
||||
if(GATEWAY_RATVAR_COMING to GATEWAY_RATVAR_ARRIVAL)
|
||||
if(!third_sound_played)
|
||||
send_to_playing_players(sound('sound/effects/clockcult_gateway_closing.ogg', 1, channel = 8, volume = 40))
|
||||
third_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_closing"
|
||||
if(GATEWAY_RATVAR_ARRIVAL to INFINITY)
|
||||
if(!purpose_fulfilled)
|
||||
countdown.stop()
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
purpose_fulfilled = TRUE
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 1.5, alpha = 255, time = 125)
|
||||
send_to_playing_players(sound('sound/effects/ratvar_rises.ogg', 0, channel = 8)) //End the sounds
|
||||
sleep(125)
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
|
||||
var/turf/startpoint = get_turf(src)
|
||||
QDEL_IN(src, 3)
|
||||
clockwork_gateway_activated = TRUE
|
||||
if(ratvar_portal)
|
||||
sleep(3)
|
||||
new/obj/structure/destructible/clockwork/massive/ratvar(startpoint)
|
||||
else
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 0) //call the shuttle immediately
|
||||
sleep(3)
|
||||
send_to_playing_players("<span class='ratvar'>\"[text2ratvar("Behold")]!\"</span>\n<span class='inathneq_large'>\"[text2ratvar("See Engine's mercy")]!\"</span>\n\
|
||||
<span class='sevtug_large'>\"[text2ratvar("Observe Engine's design skills")]!\"</span>\n<span class='nezbere_large'>\"[text2ratvar("Behold Engine's light")]!!\"</span>\n\
|
||||
<span class='nzcrentr_large'>\"[text2ratvar("Gaze upon Engine's power")]!\"</span>")
|
||||
send_to_playing_players('sound/magic/clockwork/invoke_general.ogg')
|
||||
var/x0 = startpoint.x
|
||||
var/y0 = startpoint.y
|
||||
for(var/I in spiral_range_turfs(255, startpoint))
|
||||
var/turf/T = I
|
||||
if(!T)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
||||
if(dist < 100)
|
||||
dist = TRUE
|
||||
else
|
||||
dist = FALSE
|
||||
T.ratvar_act(dist)
|
||||
CHECK_TICK
|
||||
for(var/mob/living/silicon/robot/R in silicon_mobs)
|
||||
if(R && R.stat != DEAD && !is_servant_of_ratvar(R))
|
||||
add_servant_of_ratvar(R)
|
||||
for(var/i in ai_list)
|
||||
var/mob/living/silicon/ai/A = i
|
||||
if(A && A.stat != DEAD && !is_servant_of_ratvar(A))
|
||||
add_servant_of_ratvar(A)
|
||||
for(var/I in all_clockwork_mobs)
|
||||
var/mob/M = I
|
||||
if(M.stat == CONSCIOUS)
|
||||
clockwork_say(M, text2ratvar(pick("Purge all untruths and honor Engine!", "All glory to Engine's light!", "Engine's power is unmatched!")))
|
||||
|
||||
//the actual appearance of the Gateway to the Celestial Derelict; an object so the edges of the gate can be clicked through.
|
||||
/obj/effect/clockwork/overlay/gateway_glow
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "clockwork_gateway_charging"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_OPEN_DOOR_LAYER
|
||||
@@ -0,0 +1,48 @@
|
||||
//Useless on their own, these shells can create powerful constructs.
|
||||
/obj/structure/destructible/clockwork/shell
|
||||
construction_value = 0
|
||||
anchored = 0
|
||||
density = 0
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/mobtype = /mob/living/simple_animal/hostile/clockwork
|
||||
var/spawn_message = " is an error and you should yell at whoever spawned this shell."
|
||||
|
||||
/obj/structure/destructible/clockwork/shell/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
..()
|
||||
return 0
|
||||
var/obj/item/device/mmi/posibrain/soul_vessel/S = I
|
||||
if(!S.brainmob)
|
||||
user << "<span class='warning'>[S] is inactive! Turn it on or capture a mind first.</span>"
|
||||
return 0
|
||||
if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind))
|
||||
user << "<span class='warning'>[S]'s trapped consciousness appears inactive!</span>"
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] places [S] in [src], where it fuses to the shell.</span>", "<span class='brass'>You place [S] in [src], fusing it to the shell.</span>")
|
||||
var/mob/living/simple_animal/A = new mobtype(get_turf(src))
|
||||
A.visible_message("<span class='brass'>[src][spawn_message]</span>")
|
||||
S.brainmob.mind.transfer_to(A)
|
||||
A.fully_replace_character_name(null, "[findtext(A.name, initial(A.name)) ? "[initial(A.name)]":"[A.name]"] ([S.brainmob.name])")
|
||||
user.drop_item()
|
||||
qdel(S)
|
||||
qdel(src)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/shell/cogscarab
|
||||
name = "cogscarab shell"
|
||||
desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism."
|
||||
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer."
|
||||
icon_state = "clockdrone_shell"
|
||||
mobtype = /mob/living/simple_animal/drone/cogscarab
|
||||
spawn_message = "'s eyes blink open, glowing bright red."
|
||||
|
||||
/obj/structure/destructible/clockwork/shell/fragment
|
||||
name = "fragment shell"
|
||||
desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power."
|
||||
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct."
|
||||
icon_state = "anime_fragment"
|
||||
mobtype = /mob/living/simple_animal/hostile/clockwork/fragment
|
||||
spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire."
|
||||
@@ -0,0 +1,95 @@
|
||||
//Clockwork Obelisk: Can broadcast a message at a small power cost or outright open a spatial gateway at a massive power cost.
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk
|
||||
name = "clockwork obelisk"
|
||||
desc = "A large brass obelisk hanging in midair."
|
||||
clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk."
|
||||
icon_state = "obelisk_inactive"
|
||||
active_icon = "obelisk"
|
||||
inactive_icon = "obelisk_inactive"
|
||||
unanchored_icon = "obelisk_unwrenched"
|
||||
construction_value = 20
|
||||
max_integrity = 150
|
||||
obj_integrity = 150
|
||||
break_message = "<span class='warning'>The obelisk falls to the ground, undamaged!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
|
||||
/obj/item/clockwork/component/hierophant_ansible/obelisk = 1)
|
||||
var/hierophant_cost = MIN_CLOCKCULT_POWER //how much it costs to broadcast with large text
|
||||
var/gateway_cost = 2000 //how much it costs to open a gateway
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/New()
|
||||
..()
|
||||
toggle(1)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='nzcrentr_small'>It requires <b>[hierophant_cost]W</b> to broadcast over the Hierophant Network, and <b>[gateway_cost]W</b> to open a Spatial Gateway.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user)
|
||||
if(active)
|
||||
user << "<span class='warning'>[src] is currently sustaining a gateway!</span>"
|
||||
return FAILED_UNFASTEN
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/forced_disable(bad_effects)
|
||||
var/affected = 0
|
||||
for(var/obj/effect/clockwork/spatial_gateway/SG in loc)
|
||||
SG.ex_act(1)
|
||||
affected++
|
||||
if(bad_effects)
|
||||
affected += try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
return affected
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user) || total_accessable_power() < hierophant_cost || !anchored)
|
||||
user << "<span class='warning'>You place your hand on the obelisk, but it doesn't react.</span>"
|
||||
return
|
||||
var/choice = alert(user,"You place your hand on the obelisk...",,"Hierophant Broadcast","Spatial Gateway","Cancel")
|
||||
switch(choice)
|
||||
if("Hierophant Broadcast")
|
||||
if(active)
|
||||
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
|
||||
return
|
||||
if(!user.can_speak_vocal())
|
||||
user << "<span class='warning'>You cannot speak through the obelisk!</span>"
|
||||
return
|
||||
var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "")
|
||||
if(!is_servant_of_ratvar(user) || !input || !user.canUseTopic(src, !issilicon(user)))
|
||||
return
|
||||
if(active)
|
||||
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
|
||||
return
|
||||
if(!try_use_power(hierophant_cost))
|
||||
user << "<span class='warning'>The obelisk lacks the power to broadcast!</span>"
|
||||
return
|
||||
if(!user.can_speak_vocal())
|
||||
user << "<span class='warning'>You cannot speak through the obelisk!</span>"
|
||||
return
|
||||
clockwork_say(user, text2ratvar("Hierophant Broadcast, activate! [html_decode(input)]"))
|
||||
titled_hierophant_message(user, input, "big_brass", "large_brass")
|
||||
if("Spatial Gateway")
|
||||
if(active)
|
||||
user << "<span class='warning'>The obelisk is already sustaining a gateway!</span>"
|
||||
return
|
||||
if(!try_use_power(gateway_cost))
|
||||
user << "<span class='warning'>The obelisk lacks the power to open a gateway!</span>"
|
||||
return
|
||||
if(!user.can_speak_vocal())
|
||||
user << "<span class='warning'>You need to be able to speak to open a gateway!</span>"
|
||||
return
|
||||
if(procure_gateway(user, round(100 * get_efficiency_mod(), 1), round(5 * get_efficiency_mod(), 1), 1) && !active)
|
||||
clockwork_say(user, text2ratvar("Spatial Gateway, activate!"))
|
||||
else
|
||||
return_power(gateway_cost)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/process()
|
||||
if(!anchored)
|
||||
return
|
||||
if(locate(/obj/effect/clockwork/spatial_gateway) in loc)
|
||||
icon_state = active_icon
|
||||
density = 0
|
||||
active = TRUE
|
||||
else
|
||||
icon_state = inactive_icon
|
||||
density = 1
|
||||
active = FALSE
|
||||
@@ -0,0 +1,130 @@
|
||||
//Used by the Geis scripture to hold its target in place
|
||||
/obj/structure/destructible/clockwork/geis_binding
|
||||
name = "glowing ring"
|
||||
desc = "A flickering, glowing purple ring around a target."
|
||||
clockwork_desc = "A binding ring around a target, preventing them from taking action while they're being converted."
|
||||
max_integrity = 25
|
||||
obj_integrity = 25
|
||||
density = 0
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "geisbinding_full"
|
||||
break_message = null
|
||||
break_sound = 'sound/magic/Repulse.ogg'
|
||||
debris = list()
|
||||
can_buckle = TRUE
|
||||
buckle_lying = 0
|
||||
buckle_prevents_pull = TRUE
|
||||
var/resisting = FALSE
|
||||
var/can_resist = FALSE
|
||||
var/mob_layer = MOB_LAYER
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/examine(mob/user)
|
||||
icon_state = "geisbinding_full"
|
||||
..()
|
||||
icon_state = "geisbinding"
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/attack_hand(mob/living/user)
|
||||
return
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/emp_act(severity)
|
||||
new /obj/effect/overlay/temp/emp(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/post_buckle_mob(mob/living/M)
|
||||
..()
|
||||
if(M.buckled == src)
|
||||
desc = "A flickering, glowing purple ring around [M]."
|
||||
clockwork_desc = "A binding ring around [M], preventing [M.p_them()] from taking action while [M.p_theyre()] being converted."
|
||||
icon_state = "geisbinding"
|
||||
mob_layer = M.layer
|
||||
layer = M.layer - 0.01
|
||||
var/image/GB = new('icons/effects/clockwork_effects.dmi', src, "geisbinding_top", M.layer + 0.01)
|
||||
add_overlay(GB)
|
||||
for(var/obj/item/I in M.held_items)
|
||||
M.dropItemToGround(I)
|
||||
for(var/i in M.get_empty_held_indexes())
|
||||
var/obj/item/geis_binding/B = new(M)
|
||||
M.put_in_hands(B, i)
|
||||
M.regenerate_icons()
|
||||
M.visible_message("<span class='warning'>A [name] appears around [M]!</span>", \
|
||||
"<span class='warning'>A [name] appears around you!</span>[can_resist ? "\n<span class='userdanger'>Resist!</span>":""]")
|
||||
if(!can_resist)
|
||||
repair_and_interrupt()
|
||||
else
|
||||
var/obj/effect/overlay/temp/ratvar/geis_binding/G = new /obj/effect/overlay/temp/ratvar/geis_binding(M.loc)
|
||||
var/obj/effect/overlay/temp/ratvar/geis_binding/T = new /obj/effect/overlay/temp/ratvar/geis_binding/top(M.loc)
|
||||
G.layer = mob_layer - 0.01
|
||||
T.layer = mob_layer + 0.01
|
||||
G.alpha = alpha
|
||||
T.alpha = alpha
|
||||
animate(G, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT)
|
||||
animate(T, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT)
|
||||
M.visible_message("<span class='warning'>[src] snaps into glowing pieces and dissipates!</span>")
|
||||
for(var/obj/item/geis_binding/GB in M.held_items)
|
||||
M.dropItemToGround(GB, TRUE)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/relaymove(mob/user, direction)
|
||||
if(isliving(user) && can_resist)
|
||||
var/mob/living/L = user
|
||||
L.resist()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
if(.)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/update_icon()
|
||||
alpha = min(initial(alpha) + ((obj_integrity - max_integrity) * 5), 255)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/proc/repair_and_interrupt()
|
||||
obj_integrity = max_integrity
|
||||
update_icon()
|
||||
for(var/m in buckled_mobs)
|
||||
var/mob/living/L = m
|
||||
if(L)
|
||||
L.Stun(1, 1, 1)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 4
|
||||
visible_message("<span class='sevtug'>[src] flares brightly!</span>")
|
||||
var/obj/effect/overlay/temp/ratvar/geis_binding/G1 = new /obj/effect/overlay/temp/ratvar/geis_binding(loc)
|
||||
var/obj/effect/overlay/temp/ratvar/geis_binding/G2 = new /obj/effect/overlay/temp/ratvar/geis_binding(loc)
|
||||
var/obj/effect/overlay/temp/ratvar/geis_binding/T1 = new /obj/effect/overlay/temp/ratvar/geis_binding/top(loc)
|
||||
var/obj/effect/overlay/temp/ratvar/geis_binding/T2 = new /obj/effect/overlay/temp/ratvar/geis_binding/top(loc)
|
||||
G1.layer = mob_layer - 0.01
|
||||
G2.layer = mob_layer - 0.01
|
||||
T1.layer = mob_layer + 0.01
|
||||
T2.layer = mob_layer + 0.01
|
||||
animate(G1, pixel_y = pixel_y + 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
animate(G2, pixel_y = pixel_y - 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
animate(T1, pixel_y = pixel_y + 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
animate(T2, pixel_y = pixel_y - 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
|
||||
if(buckled_mob == user)
|
||||
if(!resisting && can_resist)
|
||||
resisting = TRUE
|
||||
user.visible_message("<span class='warning'>[user] starts struggling against [src]...</span>", "<span class='userdanger'>You start breaking out of [src]...</span>")
|
||||
while(do_after(user, 10, target = src) && resisting && obj_integrity)
|
||||
if(obj_integrity - 5 <= 0)
|
||||
user.visible_message("<span class='warning'>[user] breaks [src]!</span>", "<span class='userdanger'>You break [src]!</span>")
|
||||
take_damage(5)
|
||||
return user
|
||||
take_damage(5)
|
||||
resisting = FALSE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/geis_binding
|
||||
name = "glowing ring"
|
||||
desc = "A flickering ring preventing you from holding items."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "geisbinding_full"
|
||||
flags = NODROP|ABSTRACT|DROPDEL
|
||||
|
||||
/obj/item/geis_binding/pre_attackby(atom/target, mob/living/user, params)
|
||||
user.resist()
|
||||
return FALSE
|
||||
@@ -0,0 +1,123 @@
|
||||
//Interdiction Lens: A powerful artifact that constantly disrupts electronics and drains power but, if it fails to find something to disrupt, turns off.
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens
|
||||
name = "interdiction lens"
|
||||
desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers."
|
||||
clockwork_desc = "A powerful totem that constantly drains nearby electronics and funnels the power drained into nearby Sigils of Transmission or the area's APC."
|
||||
icon_state = "interdiction_lens"
|
||||
construction_value = 20
|
||||
active_icon = "interdiction_lens_active"
|
||||
inactive_icon = "interdiction_lens"
|
||||
unanchored_icon = "interdiction_lens_unwrenched"
|
||||
break_message = "<span class='warning'>The lens flares a blinding violet before shattering!</span>"
|
||||
break_sound = 'sound/effects/Glassbr3.ogg'
|
||||
var/recharging = 0 //world.time when the lens was last used
|
||||
var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes
|
||||
var/disabled = FALSE //if it's actually usable
|
||||
var/interdiction_range = 14 //how large an area it drains and disables in
|
||||
var/static/list/rage_messages = list("...", "Disgusting.", "Die.", "Foul.", "Worthless.", "Mortal.", "Unfit.", "Weak.", "Fragile.", "Useless.", "Leave my sight!")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='[recharging > world.time ? "neovgre_small":"brass"]'>Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \
|
||||
: "vibrates in place and thrums with power"].</span>"
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='neovgre_small'>If it fails to drain any electronics or has nothing to return power to, it will disable itself for <b>[round(recharge_time/600, 1)]</b> minutes.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
if(active)
|
||||
SetLuminosity(4, 2)
|
||||
else
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY))
|
||||
if(disabled)
|
||||
user << "<span class='warning'>As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back.</span>"
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/forced_disable(bad_effects)
|
||||
if(disabled)
|
||||
return FALSE
|
||||
if(!active)
|
||||
toggle(0)
|
||||
visible_message("<span class='warning'>The gemstone suddenly turns horribly dark, writhing tendrils covering it!</span>")
|
||||
recharging = world.time + recharge_time
|
||||
flick("interdiction_lens_discharged", src)
|
||||
icon_state = "interdiction_lens_inactive"
|
||||
SetLuminosity(2,1)
|
||||
disabled = TRUE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/process()
|
||||
. = ..()
|
||||
if(recharging > world.time)
|
||||
return
|
||||
if(disabled)
|
||||
visible_message("<span class='warning'>The writhing tendrils return to the gemstone, which begins to glow with power!</span>")
|
||||
flick("interdiction_lens_recharged", src)
|
||||
disabled = FALSE
|
||||
toggle(0)
|
||||
else
|
||||
if(!check_apc_and_sigils())
|
||||
forced_disable()
|
||||
return
|
||||
var/successfulprocess = FALSE
|
||||
var/power_drained = 0
|
||||
var/list/atoms_to_test = list()
|
||||
for(var/A in spiral_range_turfs(interdiction_range, src))
|
||||
var/turf/T = A
|
||||
for(var/M in T)
|
||||
atoms_to_test |= M
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
var/unconverted_ai = FALSE
|
||||
var/efficiency = get_efficiency_mod()
|
||||
var/rage_modifier = get_efficiency_mod(TRUE)
|
||||
|
||||
for(var/i in ai_list)
|
||||
var/mob/living/silicon/ai/AI = i
|
||||
if(AI && AI.stat != DEAD && !is_servant_of_ratvar(AI))
|
||||
unconverted_ai = TRUE
|
||||
|
||||
for(var/M in atoms_to_test)
|
||||
var/atom/movable/A = M
|
||||
if(!A || qdeleted(A) || A == target_apc)
|
||||
continue
|
||||
power_drained += Floor(A.power_drain(TRUE) * efficiency, MIN_CLOCKCULT_POWER)
|
||||
|
||||
if(prob(1 * rage_modifier))
|
||||
A << "<span class='neovgre'>\"[text2ratvar(pick(rage_messages))]\"</span>"
|
||||
|
||||
if(prob(100 * (efficiency * efficiency)))
|
||||
if(istype(A, /obj/machinery/camera) && unconverted_ai)
|
||||
var/obj/machinery/camera/C = A
|
||||
if(C.isEmpProof() || !C.status)
|
||||
continue
|
||||
successfulprocess = TRUE
|
||||
if(C.emped)
|
||||
continue
|
||||
C.emp_act(1)
|
||||
else if(istype(A, /obj/item/device/radio))
|
||||
var/obj/item/device/radio/O = A
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
O.emp_act(1)
|
||||
else if((isliving(A) && !is_servant_of_ratvar(A)) || istype(A, /obj/structure/closet) || istype(A, /obj/item/weapon/storage)) //other things may have radios in them but we don't care
|
||||
for(var/obj/item/device/radio/O in A.GetAllContents())
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
O.emp_act(1)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(power_drained && power_drained >= MIN_CLOCKCULT_POWER && return_power(power_drained))
|
||||
successfulprocess = TRUE
|
||||
playsound(src, 'sound/items/PSHOOM.ogg', 50 * efficiency, 1, interdiction_range-7, 1)
|
||||
|
||||
if(!successfulprocess)
|
||||
forced_disable()
|
||||
@@ -0,0 +1,151 @@
|
||||
//Mania Motor: A pair of antenna that, while active, cause braindamage and hallucinations in nearby human mobs.
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor
|
||||
name = "mania motor"
|
||||
desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion."
|
||||
clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing hallucinations and brain damage as long as it remains powered."
|
||||
icon_state = "mania_motor_inactive"
|
||||
active_icon = "mania_motor"
|
||||
inactive_icon = "mania_motor_inactive"
|
||||
unanchored_icon = "mania_motor_unwrenched"
|
||||
construction_value = 20
|
||||
max_integrity = 80
|
||||
obj_integrity = 80
|
||||
break_message = "<span class='warning'>The antenna break off, leaving a pile of shards!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/alloy_shards/small = 3, \
|
||||
/obj/item/clockwork/component/geis_capacitor/antennae = 1)
|
||||
var/mania_cost = 200
|
||||
var/convert_attempt_cost = 500
|
||||
var/convert_cost = 500
|
||||
var/static/list/mania_messages = list("Go nuts.", "Take a crack at crazy.", "Make a bid for insanity.", "Get kooky.", "Move towards mania.", "Become bewildered.", "Wax wild.", \
|
||||
"Go round the bend.", "Land in lunacy.", "Try dementia.", "Strive to get a screw loose.")
|
||||
var/static/list/compel_messages = list("Come closer.", "Approach the transmitter.", "Touch the antennae.", "I always have to deal with idiots. Move towards the mania motor.", \
|
||||
"Advance forward and place your head between the antennae - that's all it's good for.", "If you were smarter, you'd be over here already.", "Move FORWARD, you fool.")
|
||||
var/static/list/convert_messages = list("You won't do. Go to sleep while I tell these nitwits how to convert you.", "You are insufficient. I must instruct these idiots in the art of conversion.", \
|
||||
"Oh of course, someone we can't convert. These servants are fools.", "How hard is it to use a Sigil, anyway? All it takes is dragging someone onto it.", \
|
||||
"How do they fail to use a Sigil of Accession, anyway?", "Why is it that all servants are this inept?", "It's quite likely you'll be stuck here for a while.")
|
||||
var/static/list/close_messages = list("Well, you can't reach the motor from THERE, you moron.", "Interesting location. I'd prefer if you went somewhere you could ACTUALLY TOUCH THE ANTENNAE!", \
|
||||
"Amazing. You somehow managed to wedge yourself somewhere you can't actually reach the motor from.", "Such a show of idiocy is unparalleled. Perhaps I should put you on display?", \
|
||||
"Did you do this on purpose? I can't imagine you doing so accidentally. Oh, wait, I can.", "How is it that such smart creatures can still do something AS STUPID AS THIS!")
|
||||
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='sevtug_small'>It requires <b>[mania_cost]W</b> to run, and <b>[convert_attempt_cost + convert_cost]W</b> to convert humans adjecent to it.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
|
||||
playsound(src, 'sound/effects/screech.ogg', 40, 1)
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
|
||||
if(!total_accessable_power() >= mania_cost)
|
||||
user << "<span class='warning'>[src] needs more power to function!</span>"
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
if(active)
|
||||
SetLuminosity(2, 1)
|
||||
else
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/process()
|
||||
if(try_use_power(mania_cost))
|
||||
var/turf/T = get_turf(src)
|
||||
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
|
||||
var/efficiency = get_efficiency_mod()
|
||||
for(var/mob/living/carbon/human/H in view(1, src))
|
||||
if(is_servant_of_ratvar(H) || H.null_rod_check())
|
||||
continue
|
||||
if(H.Adjacent(src) && try_use_power(convert_attempt_cost))
|
||||
if(is_eligible_servant(H) && try_use_power(convert_cost))
|
||||
H << "<span class='sevtug'>\"[text2ratvar("You are mine and his, now.")]\"</span>"
|
||||
H.playsound_local(T, hum, 80, 1)
|
||||
add_servant_of_ratvar(H)
|
||||
H.Paralyse(5)
|
||||
else if(!H.stat)
|
||||
if(H.getBrainLoss() >= 100)
|
||||
H.Paralyse(5)
|
||||
H << "<span class='sevtug'>\"[text2ratvar(pick(convert_messages))]\"</span>"
|
||||
else
|
||||
H.adjustBrainLoss(100 * efficiency)
|
||||
H.visible_message("<span class='warning'>[H] reaches out and touches [src].</span>", "<span class='sevtug'>You touch [src] involuntarily.</span>")
|
||||
else
|
||||
visible_message("<span class='warning'>[src]'s antennae fizzle quietly.</span>")
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
for(var/mob/living/carbon/human/H in range(10, src))
|
||||
if(is_servant_of_ratvar(H))
|
||||
if(H.getBrainLoss() || H.hallucination || H.druggy || H.dizziness || H.confused)
|
||||
H.adjustBrainLoss(-H.getBrainLoss()) //heals servants of braindamage, hallucination, druggy, dizziness, and confusion
|
||||
H.hallucination = 0
|
||||
H.adjust_drugginess(-H.druggy)
|
||||
H.dizziness = 0
|
||||
H.confused = 0
|
||||
else if(!H.null_rod_check() && H.stat == CONSCIOUS)
|
||||
var/distance = get_dist(T, get_turf(H))
|
||||
var/falloff_distance = min((110) - distance * 10, 80)
|
||||
var/sound_distance = falloff_distance * 0.5
|
||||
var/targetbrainloss = H.getBrainLoss()
|
||||
if(distance >= 4 && prob(falloff_distance * 0.5))
|
||||
H << "<span class='sevtug_small'>\"[text2ratvar(pick(mania_messages))]\"</span>"
|
||||
H.playsound_local(T, hum, sound_distance, 1)
|
||||
switch(distance)
|
||||
if(2 to 3)
|
||||
if(prob(falloff_distance * 0.5))
|
||||
if(prob(falloff_distance))
|
||||
H << "<span class='sevtug_small'>\"[text2ratvar(pick(mania_messages))]\"</span>"
|
||||
else
|
||||
H << "<span class='sevtug'>\"[text2ratvar(pick(compel_messages))]\"</span>"
|
||||
if(targetbrainloss <= 50)
|
||||
H.adjustBrainLoss((50 * efficiency) - targetbrainloss) //got too close had brain eaten
|
||||
H.adjust_drugginess(Clamp(7 * efficiency, 0, 100 - H.druggy))
|
||||
H.hallucination = min(H.hallucination + (7 * efficiency), 100)
|
||||
H.dizziness = min(H.dizziness + (3 * efficiency), 45)
|
||||
H.confused = min(H.confused + (3 * efficiency), 45)
|
||||
if(4 to 5)
|
||||
if(targetbrainloss <= 50)
|
||||
H.adjustBrainLoss(1 * efficiency)
|
||||
H.adjust_drugginess(Clamp(5 * efficiency, 0, 80 - H.druggy))
|
||||
H.hallucination = min(H.hallucination + (5 * efficiency), 80)
|
||||
H.dizziness = min(H.dizziness + (2 * efficiency), 30)
|
||||
H.confused = min(H.confused + (2 * efficiency), 30)
|
||||
if(6 to 7)
|
||||
if(targetbrainloss <= 30)
|
||||
H.adjustBrainLoss(1 * efficiency)
|
||||
H.adjust_drugginess(Clamp(2 * efficiency, 0, 60 - H.druggy))
|
||||
H.hallucination = min(H.hallucination + (2 * efficiency), 60)
|
||||
H.dizziness = min(H.dizziness + (2 * efficiency), 15)
|
||||
H.confused = min(H.confused + (2 * efficiency), 15)
|
||||
if(8 to 9)
|
||||
if(targetbrainloss <= 10)
|
||||
H.adjustBrainLoss(1 * efficiency)
|
||||
H.adjust_drugginess(Clamp(2 * efficiency, 0, 40 - H.druggy))
|
||||
H.hallucination = min(H.hallucination + (2 * efficiency), 40)
|
||||
if(10 to INFINITY)
|
||||
H.adjust_drugginess(Clamp(2 * efficiency, 0, 20 - H.druggy))
|
||||
H.hallucination = min(H.hallucination + (2 * efficiency), 20)
|
||||
else //if it's a distance of 1 and they can't see it/aren't adjacent or they're on top of it(how'd they get on top of it and still trigger this???)
|
||||
if(prob(falloff_distance * 0.5))
|
||||
if(prob(falloff_distance))
|
||||
H << "<span class='sevtug'>\"[text2ratvar(pick(compel_messages))]\"</span>"
|
||||
else if(prob(falloff_distance * 0.5))
|
||||
H << "<span class='sevtug'>\"[text2ratvar(pick(close_messages))]\"</span>"
|
||||
else
|
||||
H << "<span class='sevtug_small'>\"[text2ratvar(pick(mania_messages))]\"</span>"
|
||||
if(targetbrainloss <= 99)
|
||||
H.adjustBrainLoss((99 * efficiency) - targetbrainloss)
|
||||
H.adjust_drugginess(Clamp(10 * efficiency, 0, 150 - H.druggy))
|
||||
H.hallucination = min(H.hallucination + (10 * efficiency), 150)
|
||||
H.dizziness = min(H.dizziness + (5 * efficiency), 60)
|
||||
H.confused = min(H.confused + (5 * efficiency), 60)
|
||||
|
||||
else
|
||||
forced_disable(FALSE)
|
||||
@@ -0,0 +1,107 @@
|
||||
//Mending Motor: A prism that consumes replicant alloy or power to repair nearby mechanical servants at a quick rate.
|
||||
/obj/structure/destructible/clockwork/powered/mending_motor
|
||||
name = "mending motor"
|
||||
desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
|
||||
clockwork_desc = "A powerful prism that rapidly repairs nearby mechanical servants and clockwork structures."
|
||||
icon_state = "mending_motor_inactive"
|
||||
active_icon = "mending_motor"
|
||||
inactive_icon = "mending_motor_inactive"
|
||||
unanchored_icon = "mending_motor_unwrenched"
|
||||
construction_value = 20
|
||||
max_integrity = 125
|
||||
obj_integrity = 125
|
||||
break_message = "<span class='warning'>The prism collapses with a heavy thud!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 5, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 1, \
|
||||
/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/component/vanguard_cogwheel = 1)
|
||||
var/heal_attempts = 4
|
||||
var/heal_cost = MIN_CLOCKCULT_POWER*2
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
|
||||
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
|
||||
"Ah, child, it's okay now.")
|
||||
var/static/list/heal_failure_messages = list("Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
|
||||
"If you die, you will be remembered.")
|
||||
var/static/list/mending_motor_typecache = typecacheof(list(
|
||||
/obj/structure/destructible/clockwork,
|
||||
/obj/machinery/door/airlock/clockwork,
|
||||
/obj/machinery/door/window/clockwork,
|
||||
/obj/structure/window/reinforced/clockwork,
|
||||
/obj/structure/table/reinforced/brass))
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mending_motor/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
user << "<span class='inathneq_small'>It requires at least <b>[heal_cost]W</b> to attempt to repair clockwork mobs, structures, or converted silicons.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mending_motor/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(heal_cost)
|
||||
visible_message("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mending_motor/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
|
||||
if(total_accessable_power() < MIN_CLOCKCULT_POWER)
|
||||
user << "<span class='warning'>[src] needs more power to function!</span>"
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mending_motor/process()
|
||||
var/efficiency = get_efficiency_mod()
|
||||
for(var/atom/movable/M in range(7, src))
|
||||
var/turf/T
|
||||
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
T = get_turf(M)
|
||||
var/mob/living/simple_animal/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD)
|
||||
continue
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
if(try_use_power(heal_cost))
|
||||
S.adjustHealth(-(8 * efficiency))
|
||||
new /obj/effect/overlay/temp/heal(T, "#1E8CE1")
|
||||
else
|
||||
S << "<span class='inathneq'>\"[text2ratvar(pick(heal_failure_messages))]\"</span>"
|
||||
break
|
||||
else
|
||||
S << "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>"
|
||||
break
|
||||
else if(is_type_in_typecache(M, mending_motor_typecache))
|
||||
T = get_turf(M)
|
||||
var/obj/structure/destructible/clockwork/C = M
|
||||
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
|
||||
continue
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(C.obj_integrity < C.max_integrity)
|
||||
if(try_use_power(heal_cost))
|
||||
C.obj_integrity = min(C.obj_integrity + (8 * efficiency), C.max_integrity)
|
||||
if(C == src)
|
||||
efficiency = get_efficiency_mod()
|
||||
C.update_icon()
|
||||
new /obj/effect/overlay/temp/heal(T, "#1E8CE1")
|
||||
else
|
||||
break
|
||||
else
|
||||
break
|
||||
else if(issilicon(M))
|
||||
T = get_turf(M)
|
||||
var/mob/living/silicon/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
|
||||
continue
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
if(try_use_power(heal_cost))
|
||||
S.heal_ordered_damage(8 * efficiency, damage_heal_order)
|
||||
new /obj/effect/overlay/temp/heal(T, "#1E8CE1")
|
||||
else
|
||||
S << "<span class='inathneq'>\"[text2ratvar(pick(heal_failure_messages))]\"</span>"
|
||||
break
|
||||
else
|
||||
S << "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>"
|
||||
break
|
||||
. = ..()
|
||||
if(. < heal_cost)
|
||||
forced_disable(FALSE)
|
||||
@@ -0,0 +1,128 @@
|
||||
//Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with.
|
||||
/obj/structure/destructible/clockwork/ocular_warden
|
||||
name = "ocular warden"
|
||||
desc = "A large brass eye with tendrils trailing below it and a wide red iris."
|
||||
clockwork_desc = "A fragile turret that will deal sustained damage to any non-faithful it sees."
|
||||
icon_state = "ocular_warden"
|
||||
unanchored_icon = "ocular_warden_unwrenched"
|
||||
obj_integrity = 25
|
||||
max_integrity = 25
|
||||
construction_value = 15
|
||||
layer = WALL_OBJ_LAYER
|
||||
break_message = "<span class='warning'>The warden's eye gives a glare of utter hate before falling dark!</span>"
|
||||
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1)
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/damage_per_tick = 2.7
|
||||
var/sight_range = 3
|
||||
var/atom/movable/target
|
||||
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/New()
|
||||
..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='brass'>[target ? "<b>It's fixated on [target]!</b>" : "Its gaze is wandering aimlessly."]</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/hulk_damage()
|
||||
return 25
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user)
|
||||
if(anchored)
|
||||
if(obj_integrity <= max_integrity * 0.25)
|
||||
user << "<span class='warning'>[src] is too damaged to unsecure!</span>"
|
||||
return FAILED_UNFASTEN
|
||||
else
|
||||
for(var/obj/structure/destructible/clockwork/ocular_warden/W in orange(3, src))
|
||||
user << "<span class='neovgre'>You sense another ocular warden too near this location. Activating this one this close would cause them to fight.</span>"
|
||||
return FAILED_UNFASTEN
|
||||
return SUCCESSFUL_UNFASTEN
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/ratvar_act()
|
||||
..()
|
||||
if(ratvar_awakens)
|
||||
damage_per_tick = 10
|
||||
sight_range = 6
|
||||
else
|
||||
damage_per_tick = initial(damage_per_tick)
|
||||
sight_range = initial(sight_range)
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/process()
|
||||
if(!anchored)
|
||||
lose_target()
|
||||
return
|
||||
var/list/validtargets = acquire_nearby_targets()
|
||||
if(target)
|
||||
if(!(target in validtargets))
|
||||
lose_target()
|
||||
else
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!L.null_rod_check())
|
||||
if(isrevenant(L))
|
||||
var/mob/living/simple_animal/revenant/R = L
|
||||
if(R.revealed)
|
||||
R.unreveal_time += 2
|
||||
else
|
||||
R.reveal(10)
|
||||
if(prob(50))
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot1.ogg',50,1)
|
||||
else
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot2.ogg',50,1)
|
||||
L.adjustFireLoss((!iscultist(L) ? damage_per_tick : damage_per_tick * 2) * get_efficiency_mod()) //Nar-Sian cultists take additional damage
|
||||
if(ratvar_awakens && L)
|
||||
L.adjust_fire_stacks(damage_per_tick)
|
||||
L.IgniteMob()
|
||||
else if(istype(target,/obj/mecha))
|
||||
var/obj/mecha/M = target
|
||||
M.take_damage(damage_per_tick * get_efficiency_mod(), BURN, "melee", 1, get_dir(src, M))
|
||||
|
||||
new /obj/effect/overlay/temp/ratvar/ocular_warden(get_turf(target))
|
||||
|
||||
setDir(get_dir(get_turf(src), get_turf(target)))
|
||||
if(!target)
|
||||
if(validtargets.len)
|
||||
target = pick(validtargets)
|
||||
playsound(src,'sound/machines/clockcult/ocularwarden-target.ogg',50,1)
|
||||
visible_message("<span class='warning'>[src] swivels to face [target]!</span>")
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
L << "<span class='heavy_brass'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [ratvar_awakens ? "melts you alive" : "burns you"]!</span>"
|
||||
else if(istype(target,/obj/mecha))
|
||||
var/obj/mecha/M = target
|
||||
M.occupant << "<span class='heavy_brass'>\"I SEE YOU!\"</span>" //heeeellooooooo, person in mech.
|
||||
else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes
|
||||
if(prob(50))
|
||||
visible_message("<span class='notice'>[src][pick(idle_messages)]</span>")
|
||||
else
|
||||
setDir(pick(cardinal))//Random rotation
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets()
|
||||
. = list()
|
||||
for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind
|
||||
var/obj/item/weapon/storage/book/bible/B = L.bible_check()
|
||||
if(B)
|
||||
if(!(B.resistance_flags & ON_FIRE))
|
||||
L << "<span class='warning'>Your [B.name] bursts into flames!</span>"
|
||||
for(var/obj/item/weapon/storage/book/bible/BI in L.GetAllContents())
|
||||
if(!(BI.resistance_flags & ON_FIRE))
|
||||
BI.fire_act()
|
||||
else if(!is_servant_of_ratvar(L) && !L.stat && L.mind && !L.restrained() && !(L.buckled && (L.lying || istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding))) && \
|
||||
!(L.disabilities & BLIND) && !L.null_rod_check())
|
||||
. += L
|
||||
for(var/N in mechas_list)
|
||||
var/obj/mecha/M = N
|
||||
if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant) && (M in view(sight_range, src)))
|
||||
. += M
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/proc/lose_target()
|
||||
if(!target)
|
||||
return 0
|
||||
target = null
|
||||
visible_message("<span class='warning'>[src] settles and seems almost disappointed.</span>")
|
||||
return 1
|
||||
@@ -0,0 +1,145 @@
|
||||
//Ratvar himself. Impossible to damage by most standard means, He will dominate the station and all upon it.
|
||||
/obj/structure/destructible/clockwork/massive/ratvar
|
||||
name = "Ratvar, the Clockwork Justiciar"
|
||||
desc = "<span class='userdanger'>What is what is what are what real what is all a lie all a lie it's all a lie why how can what is</span>"
|
||||
clockwork_desc = "<span class='large_brass'><b><i>Ratvar, the Clockwork Justiciar, your master eternal.</i></b></span>"
|
||||
icon = 'icons/effects/512x512.dmi'
|
||||
icon_state = "ratvar"
|
||||
pixel_x = -235
|
||||
pixel_y = -248
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
appearance_flags = 0
|
||||
var/atom/prey //Whatever Ratvar is chasing
|
||||
var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE
|
||||
var/proselytize_range = 10
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/New()
|
||||
..()
|
||||
ratvar_awakens++
|
||||
for(var/obj/O in all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
START_PROCESSING(SSobj, src)
|
||||
send_to_playing_players("<span class='ratvar'>\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"</span>")
|
||||
send_to_playing_players('sound/effects/ratvar_reveal.ogg')
|
||||
var/image/alert_overlay = image('icons/effects/clockwork_effects.dmi', "ratvar_alert")
|
||||
var/area/A = get_area(src)
|
||||
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
|
||||
addtimer(CALLBACK(SSshuttle.emergency, /obj/docking_port/mobile/emergency..proc/request, null, 0.1), 50)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Destroy()
|
||||
ratvar_awakens--
|
||||
for(var/obj/O in all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=6>\"NO! I will not... be...</font> <font size=5>banished...</font> <font size=4>again...\"</font></span>")
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O)
|
||||
var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Yes", "No")
|
||||
if(alertresult == "No" || !O)
|
||||
return 0
|
||||
var/mob/living/simple_animal/drone/cogscarab/ratvar/R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src))
|
||||
R.visible_message("<span class='heavy_brass'>[R] forms, and its eyes blink open, glowing bright red!</span>")
|
||||
R.key = O.key
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Bump(atom/A)
|
||||
var/turf/T = get_turf(A)
|
||||
forceMove(T)
|
||||
T.ratvar_act()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Process_Spacemove()
|
||||
return clashing
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/process()
|
||||
if(clashing) //I'm a bit occupied right now, thanks
|
||||
return
|
||||
for(var/I in circlerangeturfs(src, proselytize_range))
|
||||
var/turf/T = I
|
||||
T.ratvar_act()
|
||||
for(var/I in circleviewturfs(src, round(proselytize_range * 0.5)))
|
||||
var/turf/T = I
|
||||
T.ratvar_act(1)
|
||||
var/dir_to_step_in = pick(cardinal)
|
||||
if(!prey)
|
||||
for(var/obj/singularity/narsie/N in poi_list)
|
||||
if(N.z == z)
|
||||
prey = N
|
||||
break
|
||||
if(!prey) //In case there's a Nar-Sie
|
||||
var/list/meals = list()
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(L.z == z && !is_servant_of_ratvar(L) && L.mind)
|
||||
meals += L
|
||||
if(meals.len)
|
||||
prey = pick(meals)
|
||||
prey << "<span class='heavy_brass'><font size=5>\"You will do.\"</font></span>\n\
|
||||
<span class='userdanger'>Something very large and very malevolent begins lumbering its way towards you...</span>"
|
||||
prey << 'sound/effects/ratvar_reveal.ogg'
|
||||
else
|
||||
if(prob(10) || is_servant_of_ratvar(prey) || prey.z != z)
|
||||
prey << "<span class='heavy_brass'><font size=5>\"How dull. Leave me.\"</font></span>\n\
|
||||
<span class='userdanger'>You feel tremendous relief as a set of horrible eyes loses sight of you...</span>"
|
||||
prey = null
|
||||
else
|
||||
dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target
|
||||
step(src, dir_to_step_in)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/narsie_act()
|
||||
if(clashing)
|
||||
return FALSE
|
||||
clashing = TRUE
|
||||
world << "<span class='heavy_brass'><font size=5>\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"</font></span>"
|
||||
world << "<span class='cult'><font size=5>\"<b>Ratvar?! How?!</b>\"</font></span>"
|
||||
for(var/obj/singularity/narsie/N in range(15, src))
|
||||
if(N.clashing)
|
||||
continue
|
||||
N.clashing = TRUE
|
||||
clash_of_the_titans(N) //IT'S TIME FOR THE BATTLE OF THE AGES
|
||||
break
|
||||
return TRUE
|
||||
|
||||
//Put me in Reebe, will you? Ratvar has found and is going to fucking murder Nar-Sie
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
|
||||
var/winner = "Undeclared"
|
||||
var/base_victory_chance = 1
|
||||
while(src && narsie)
|
||||
send_to_playing_players('sound/magic/clockwork/ratvar_attack.ogg')
|
||||
sleep(5.2)
|
||||
for(var/mob/M in mob_list)
|
||||
if(!isnewplayer(M))
|
||||
flash_color(M, flash_color="#966400", flash_time=1)
|
||||
shake_camera(M, 4, 3)
|
||||
var/ratvar_chance = min(ticker.mode.servants_of_ratvar.len, 50)
|
||||
var/narsie_chance = ticker.mode.cult.len
|
||||
for(var/mob/living/simple_animal/hostile/construct/harvester/C in player_list)
|
||||
narsie_chance++
|
||||
ratvar_chance = rand(base_victory_chance, ratvar_chance)
|
||||
narsie_chance = rand(base_victory_chance, min(narsie_chance, 50))
|
||||
if(ratvar_chance > narsie_chance)
|
||||
winner = "Ratvar"
|
||||
break
|
||||
sleep(rand(2,5))
|
||||
send_to_playing_players('sound/magic/clockwork/narsie_attack.ogg')
|
||||
sleep(7.4)
|
||||
for(var/mob/M in mob_list)
|
||||
if(!isnewplayer(M))
|
||||
flash_color(M, flash_color="#C80000", flash_time=1)
|
||||
shake_camera(M, 4, 3)
|
||||
if(narsie_chance > ratvar_chance)
|
||||
winner = "Nar-Sie"
|
||||
break
|
||||
base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another
|
||||
switch(winner)
|
||||
if("Ratvar")
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE! DIE! DIE!", "FILTH!!!", "SUFFER!!!", text2ratvar("ROT FOR CENTURIES AS I HAVE!!"))]\"</font></span>\n\
|
||||
<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>") //nar-sie get out
|
||||
send_to_playing_players('sound/magic/clockwork/anima_fragment_attack.ogg')
|
||||
send_to_playing_players('sound/magic/demon_dies.ogg')
|
||||
clashing = FALSE
|
||||
qdel(narsie)
|
||||
if("Nar-Sie")
|
||||
send_to_playing_players("<span class='cult'><font size=5>\"<b>[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]</b>\"</font></span>") //Broken English
|
||||
send_to_playing_players('sound/magic/demon_attack1.ogg')
|
||||
send_to_playing_players('sound/magic/clockwork/anima_fragment_death.ogg')
|
||||
narsie.clashing = FALSE
|
||||
qdel(src)
|
||||
@@ -0,0 +1,101 @@
|
||||
//Tinkerer's cache: Stores components for later use.
|
||||
/obj/structure/destructible/clockwork/cache
|
||||
name = "tinkerer's cache"
|
||||
desc = "A large brass spire with a flaming hole in its center."
|
||||
clockwork_desc = "A brass container capable of storing a large amount of components.\n\
|
||||
Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
|
||||
icon_state = "tinkerers_cache"
|
||||
unanchored_icon = "tinkerers_cache_unwrenched"
|
||||
construction_value = 10
|
||||
break_message = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
|
||||
max_integrity = 80
|
||||
obj_integrity = 80
|
||||
var/wall_generation_cooldown
|
||||
var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
clockwork_caches++
|
||||
update_slab_info()
|
||||
SetLuminosity(2,1)
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/Destroy()
|
||||
clockwork_caches--
|
||||
update_slab_info()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(linkedwall)
|
||||
linkedwall.linkedcache = null
|
||||
linkedwall = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/process()
|
||||
if(!anchored)
|
||||
if(linkedwall)
|
||||
linkedwall.linkedcache = null
|
||||
linkedwall = null
|
||||
return
|
||||
for(var/turf/closed/wall/clockwork/C in range(4, src))
|
||||
if(!C.linkedcache && !linkedwall)
|
||||
C.linkedcache = src
|
||||
linkedwall = C
|
||||
wall_generation_cooldown = world.time + (CACHE_PRODUCTION_TIME * get_efficiency_mod(TRUE))
|
||||
visible_message("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
|
||||
break
|
||||
if(linkedwall && wall_generation_cooldown <= world.time)
|
||||
wall_generation_cooldown = world.time + (CACHE_PRODUCTION_TIME * get_efficiency_mod(TRUE))
|
||||
var/component_id = generate_cache_component(null, src)
|
||||
playsound(linkedwall, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
|
||||
visible_message("<span class='[get_component_span(component_id)]'>Something</span><span class='warning'> cl[pick("ank", "ink", "unk", "ang")]s around inside of [src]...</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return ..()
|
||||
if(istype(I, /obj/item/clockwork/component))
|
||||
var/obj/item/clockwork/component/C = I
|
||||
if(!anchored)
|
||||
user << "<span class='warning'>[src] needs to be secured to place [C] into it!</span>"
|
||||
else
|
||||
clockwork_component_cache[C.component_id]++
|
||||
update_slab_info()
|
||||
user << "<span class='notice'>You add [C] to [src].</span>"
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab))
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
if(!anchored)
|
||||
user << "<span class='warning'>[src] needs to be secured to offload your slab's components into it!</span>"
|
||||
else
|
||||
for(var/i in S.stored_components)
|
||||
clockwork_component_cache[i] += S.stored_components[i]
|
||||
S.stored_components[i] = 0
|
||||
update_slab_info()
|
||||
user.visible_message("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/attack_hand(mob/living/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(linkedwall)
|
||||
if(wall_generation_cooldown > world.time)
|
||||
user << "<span class='alloy'>[src] will produce a component in <b>[(world.time - wall_generation_cooldown) * 0.1]</b> seconds.</span>"
|
||||
else
|
||||
user << "<span class='brass'>[src] is about to produce a component!</span>"
|
||||
else if(anchored)
|
||||
user << "<span class='alloy'>[src] is unlinked! Construct a Clockwork Wall nearby to generate components!</span>"
|
||||
else
|
||||
user << "<span class='alloy'>[src] needs to be secured to generate components!</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(linkedwall)
|
||||
user << "<span class='brass'>It is linked to a Clockwork Wall and will generate a component every <b>[round((CACHE_PRODUCTION_TIME * 0.1) * get_efficiency_mod(TRUE), 0.1)]</b> seconds!</span>"
|
||||
else
|
||||
user << "<span class='alloy'>It is unlinked! Construct a Clockwork Wall nearby to generate components!</span>"
|
||||
user << "<b>Stored components:</b>"
|
||||
for(var/i in clockwork_component_cache)
|
||||
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[clockwork_component_cache[i]]</b></span>"
|
||||
@@ -0,0 +1,165 @@
|
||||
//Tinkerer's Daemon: A machine that rapidly produces components at a power cost.
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon
|
||||
name = "tinkerer's daemon"
|
||||
desc = "A strange machine with three small brass obelisks attached to it."
|
||||
clockwork_desc = "An efficient machine that can rapidly produce components at a small power cost. It will only function if outnumbered by servants at a rate to 5:1."
|
||||
icon_state = "tinkerers_daemon"
|
||||
active_icon = "tinkerers_daemon"
|
||||
inactive_icon = "tinkerers_daemon"
|
||||
unanchored_icon = "tinkerers_daemon_unwrenched"
|
||||
max_integrity = 100
|
||||
obj_integrity = 100
|
||||
construction_value = 20
|
||||
break_message = "<span class='warning'>The daemon shatters into millions of pieces!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 2, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 4, \
|
||||
/obj/item/clockwork/alloy_shards/small = 6)
|
||||
var/image/daemon_glow
|
||||
var/image/component_glow
|
||||
var/component_id_to_produce
|
||||
var/production_time = 0 //last time we produced a component
|
||||
var/production_cooldown = 120
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/New()
|
||||
..()
|
||||
clockwork_daemons++
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/Destroy()
|
||||
clockwork_daemons--
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(active)
|
||||
if(component_id_to_produce)
|
||||
user << "<span class='[get_component_span(component_id_to_produce)]_small'>It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != REPLICANT_ALLOY ? "s":""].</span>"
|
||||
else
|
||||
user << "<span class='brass'>It is currently producing random components.</span>"
|
||||
user << "<span class='nezbere_small'>It will produce a component every <b>[round((production_cooldown*0.1) * get_efficiency_mod(TRUE), 0.1)]</b> seconds and requires at least the following power for each component type:</span>"
|
||||
for(var/i in clockwork_component_cache)
|
||||
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)]:</i> <b>[get_component_cost(i)]W</b> <i>([clockwork_component_cache[i]] exist[clockwork_component_cache[i] == 1 ? "s" : ""])</i></span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
visible_message("<span class='warning'>[src] shuts down with a horrible grinding noise!</span>")
|
||||
playsound(src, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, 1)
|
||||
else
|
||||
visible_message("<span class='warning'>[src] shuts down!</span>")
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
user << "<span class='warning'>You place your hand on the daemon, but nothing happens.</span>"
|
||||
return
|
||||
if(active)
|
||||
toggle(0, user)
|
||||
else
|
||||
if(!anchored)
|
||||
user << "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>"
|
||||
return FALSE
|
||||
var/servants = 0
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
if(servants * 0.2 < clockwork_daemons)
|
||||
user << "<span class='nezbere'>\"There are too few servants for this daemon to work.\"</span>"
|
||||
return
|
||||
if(!clockwork_caches)
|
||||
user << "<span class='nezbere'>\"You require a cache for this daemon to operate. Get to it.\"</span>"
|
||||
return
|
||||
var/min_power_usable = 0
|
||||
for(var/i in clockwork_component_cache)
|
||||
if(!min_power_usable)
|
||||
min_power_usable = get_component_cost(i)
|
||||
else
|
||||
min_power_usable = min(min_power_usable, get_component_cost(i))
|
||||
if(total_accessable_power() < min_power_usable)
|
||||
user << "<span class='nezbere'>\"You need more power to activate this daemon, friend.\"</span>"
|
||||
return
|
||||
var/choice = alert(user,"Activate Daemon...",,"Specific Component","Random Component","Cancel")
|
||||
switch(choice)
|
||||
if("Specific Component")
|
||||
var/list/components = list()
|
||||
for(var/i in clockwork_component_cache)
|
||||
components["[get_component_name(i)] ([get_component_cost(i)]W)"] = i
|
||||
var/input_component = input(user, "Choose a component type.", name) as null|anything in components
|
||||
component_id_to_produce = components[input_component]
|
||||
servants = 0
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
if(!is_servant_of_ratvar(user) || !user.canUseTopic(src, !issilicon(user), NO_DEXTERY) || active || !clockwork_caches || servants * 0.2 < clockwork_daemons)
|
||||
return
|
||||
if(!component_id_to_produce)
|
||||
user << "<span class='warning'>You decide not to select a component and activate the daemon.</span>"
|
||||
return
|
||||
if(total_accessable_power() < get_component_cost(component_id_to_produce))
|
||||
user << "<span class='warning'>There is too little power to produce this type of component!</span>"
|
||||
return
|
||||
toggle(0, user)
|
||||
if("Random Component")
|
||||
component_id_to_produce = null
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
if(active)
|
||||
var/component_color = get_component_color(component_id_to_produce)
|
||||
if(!daemon_glow)
|
||||
daemon_glow = new('icons/obj/clockwork_objects.dmi', "tinkerglow")
|
||||
daemon_glow.color = component_color
|
||||
add_overlay(daemon_glow)
|
||||
if(!component_glow)
|
||||
component_glow = new('icons/obj/clockwork_objects.dmi', "t_[component_id_to_produce ? component_id_to_produce :"random_component"]")
|
||||
else
|
||||
component_glow.icon_state = "t_[component_id_to_produce ? component_id_to_produce :"random_component"]"
|
||||
component_glow.color = component_color
|
||||
add_overlay(component_glow)
|
||||
production_time = world.time + production_cooldown //don't immediately produce when turned on after being off
|
||||
SetLuminosity(2, 1)
|
||||
else
|
||||
cut_overlays()
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/proc/get_component_cost(id)
|
||||
return max(MIN_CLOCKCULT_POWER*2, (MIN_CLOCKCULT_POWER*2) * (1 + round(clockwork_component_cache[id] * 0.2)))
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/process()
|
||||
var/servants = 0
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
. = ..()
|
||||
var/min_power_usable = 0
|
||||
if(!component_id_to_produce)
|
||||
for(var/i in clockwork_component_cache)
|
||||
if(!min_power_usable)
|
||||
min_power_usable = get_component_cost(i)
|
||||
else
|
||||
min_power_usable = min(min_power_usable, get_component_cost(i))
|
||||
else
|
||||
min_power_usable = get_component_cost(component_id_to_produce)
|
||||
if(!clockwork_caches || servants * 0.2 < clockwork_daemons || . < min_power_usable) //if we don't have enough to produce the lowest or what we chose to produce, cancel out
|
||||
forced_disable(FALSE)
|
||||
return
|
||||
if(production_time <= world.time)
|
||||
var/component_to_generate = component_id_to_produce
|
||||
if(!component_to_generate)
|
||||
component_to_generate = get_weighted_component_id() //more likely to generate components that we have less of
|
||||
if(!try_use_power(get_component_cost(component_to_generate)))
|
||||
component_to_generate = null
|
||||
if(!component_id_to_produce)
|
||||
for(var/i in clockwork_component_cache)
|
||||
if(try_use_power(get_component_cost(i))) //if we fail but are producing random, try and get a different component to produce
|
||||
component_to_generate = i
|
||||
break
|
||||
if(component_to_generate)
|
||||
generate_cache_component(component_to_generate, src)
|
||||
production_time = world.time + (production_cooldown * get_efficiency_mod(TRUE)) //go on cooldown
|
||||
visible_message("<span class='warning'>[src] hums as it produces a </span><span class='[get_component_span(component_to_generate)]'>component</span><span class='warning'>.</span>")
|
||||
else
|
||||
forced_disable(FALSE) //we shouldn't actually ever get here, as we should cancel out way before this
|
||||
@@ -0,0 +1,76 @@
|
||||
//A massive gear, effectively a girder for clocks.
|
||||
/obj/structure/destructible/clockwork/wall_gear
|
||||
name = "massive gear"
|
||||
icon_state = "wall_gear"
|
||||
unanchored_icon = "wall_gear"
|
||||
climbable = TRUE
|
||||
max_integrity = 100
|
||||
obj_integrity = 100
|
||||
layer = BELOW_OBJ_LAYER
|
||||
construction_value = 3
|
||||
desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it."
|
||||
break_message = "<span class='warning'>The gear breaks apart into shards of alloy!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 4, \
|
||||
/obj/item/clockwork/alloy_shards/small = 2) //slightly more debris than the default, totals 26 alloy
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/displaced
|
||||
anchored = FALSE
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/New()
|
||||
..()
|
||||
new /obj/effect/overlay/temp/ratvar/gear(get_turf(src))
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/emp_act(severity)
|
||||
return
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/wrench))
|
||||
default_unfasten_wrench(user, I, 10)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/weapon/screwdriver))
|
||||
if(anchored)
|
||||
user << "<span class='warning'>[src] needs to be unsecured to disassemble it!</span>"
|
||||
else
|
||||
playsound(src, I.usesound, 100, 1)
|
||||
user.visible_message("<span class='warning'>[user] starts to disassemble [src].</span>", "<span class='notice'>You start to disassemble [src]...</span>")
|
||||
if(do_after(user, 30*I.toolspeed, target = src) && !anchored)
|
||||
user << "<span class='notice'>You disassemble [src].</span>"
|
||||
deconstruct(TRUE)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/stack/tile/brass))
|
||||
var/obj/item/stack/tile/brass/W = I
|
||||
if(W.get_amount() < 1)
|
||||
user << "<span class='warning'>You need one brass sheet to do this!</span>"
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(iswallturf(T))
|
||||
user << "<span class='warning'>There is already a wall present!</span>"
|
||||
return
|
||||
if(!isfloorturf(T))
|
||||
user << "<span class='warning'>A floor must be present to build a [anchored ? "false ":""]wall!</span>"
|
||||
return
|
||||
if(locate(/obj/structure/falsewall) in T.contents)
|
||||
user << "<span class='warning'>There is already a false wall present!</span>"
|
||||
return
|
||||
user << "<span class='notice'>You start adding [W] to [src]...</span>"
|
||||
if(do_after(user, 20, target = src))
|
||||
var/brass_floor = FALSE
|
||||
if(istype(T, /turf/open/floor/clockwork)) //if the floor is already brass, costs less to make(conservation of masssssss)
|
||||
brass_floor = TRUE
|
||||
if(W.use(2 - brass_floor))
|
||||
if(anchored)
|
||||
T.ChangeTurf(/turf/closed/wall/clockwork)
|
||||
else
|
||||
T.ChangeTurf(/turf/open/floor/clockwork)
|
||||
new /obj/structure/falsewall/brass(T)
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='warning'>You need more brass to make a [anchored ? "false ":""]wall!</span>"
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/deconstruct(disassembled = TRUE)
|
||||
if(!(flags & NODECONSTRUCT) && disassembled)
|
||||
new /obj/item/stack/tile/brass(loc, 3)
|
||||
return ..()
|
||||
@@ -1,178 +0,0 @@
|
||||
//sends messages via hierophant
|
||||
/proc/send_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant")
|
||||
if(!user || !message || !ticker || !ticker.mode)
|
||||
return 0
|
||||
var/parsed_message = "<span class='[name_span]'>[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: </span><span class='[message_span]'>\"[message]\"</span>"
|
||||
for(var/M in mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
M << "[link] [parsed_message]"
|
||||
else if(is_servant_of_ratvar(M))
|
||||
M << parsed_message
|
||||
return 1
|
||||
|
||||
//Function Call action: Calls forth a Ratvarian spear.
|
||||
/datum/action/innate/function_call
|
||||
name = "Function Call"
|
||||
button_icon_state = "ratvarian_spear"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/innate/function_call/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/function_call/Activate()
|
||||
if(owner.l_hand && owner.r_hand)
|
||||
usr << "<span class='warning'>You need an empty to hand to call forth your spear!</span>"
|
||||
return 0
|
||||
owner.visible_message("<span class='warning'>A strange spear materializes in [usr]'s hands!</span>", "<span class='brass'>You call forth your spear!</span>")
|
||||
var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr))
|
||||
owner.put_in_hands(R)
|
||||
for(var/datum/action/innate/function_call/F in owner.actions) //Removes any bound Ratvarian spears
|
||||
qdel(F)
|
||||
return 1
|
||||
|
||||
//allows a mob to select a target to gate to
|
||||
/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way)
|
||||
var/list/possible_targets = list()
|
||||
var/list/teleportnames = list()
|
||||
var/list/duplicatenamecount = list()
|
||||
|
||||
for(var/obj/structure/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects)
|
||||
if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX)) //don't list obelisks that we're next to
|
||||
var/area/A = get_area(O)
|
||||
var/locname = initial(A.name)
|
||||
var/resultkey = "[locname] [O.name]"
|
||||
if(resultkey in teleportnames) //why the fuck did you put two obelisks in the same area
|
||||
duplicatenamecount[resultkey]++
|
||||
resultkey = "[resultkey] ([duplicatenamecount[resultkey]])"
|
||||
else
|
||||
teleportnames.Add(resultkey)
|
||||
duplicatenamecount[resultkey] = 1
|
||||
possible_targets[resultkey] = O
|
||||
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && L != invoker && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons
|
||||
var/resultkey = "[L.name] ([L.real_name])"
|
||||
if(resultkey in teleportnames)
|
||||
duplicatenamecount[resultkey]++
|
||||
resultkey = "[resultkey] ([duplicatenamecount[resultkey]])"
|
||||
else
|
||||
teleportnames.Add(resultkey)
|
||||
duplicatenamecount[resultkey] = 1
|
||||
possible_targets[resultkey] = L
|
||||
|
||||
if(!possible_targets.len)
|
||||
invoker << "<span class='warning'>There are no other eligible targets for a Spatial Gateway!</span>"
|
||||
return 0
|
||||
var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets
|
||||
var/atom/movable/target = possible_targets[input_target_key]
|
||||
if(!target || !invoker.canUseTopic(src, BE_CLOSE))
|
||||
return 0
|
||||
var/istargetobelisk = istype(target, /obj/structure/clockwork/powered/clockwork_obelisk)
|
||||
if(istargetobelisk)
|
||||
gateway_uses *= 2
|
||||
time_duration *= 2
|
||||
invoker.visible_message("<span class='warning'>The air in front of [invoker] ripples before suddenly tearing open!</span>", \
|
||||
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
|
||||
var/obj/effect/clockwork/spatial_gateway/S1 = new(istype(src, /obj/structure/clockwork/powered/clockwork_obelisk) ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
|
||||
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
|
||||
|
||||
//Set up the portals now that they've spawned
|
||||
S1.setup_gateway(S2, time_duration, gateway_uses, two_way)
|
||||
S2.visible_message("<span class='warning'>The air in front of [target] ripples before suddenly tearing open!</span>")
|
||||
return 1
|
||||
|
||||
/proc/scripture_unlock_check(scripture_tier) //check if the selected scripture tier is unlocked
|
||||
var/servants = 0
|
||||
var/unconverted_ai_exists = FALSE
|
||||
for(var/mob/living/M in living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
for(var/mob/living/silicon/ai/ai in living_mob_list)
|
||||
if(!is_servant_of_ratvar(ai) && ai.client)
|
||||
unconverted_ai_exists = TRUE
|
||||
switch(scripture_tier)
|
||||
if(SCRIPTURE_DRIVER)
|
||||
return 1
|
||||
if(SCRIPTURE_SCRIPT)
|
||||
if(servants >= 5 && clockwork_caches)
|
||||
return 1 //5 or more non-brain servants and any number of clockwork caches
|
||||
if(SCRIPTURE_APPLICATION)
|
||||
if(servants >= 8 && clockwork_caches >= 3 && clockwork_construction_value >= 75)
|
||||
return 1 //8 or more non-brain servants, 3+ clockwork caches, and at least 75 CV
|
||||
if(SCRIPTURE_REVENANT)
|
||||
if(servants >= 10 && clockwork_caches >= 4 && clockwork_construction_value >= 150)
|
||||
return 1 //10 or more non-brain servants, 4+ clockwork caches, and at least 150 CV
|
||||
if(SCRIPTURE_JUDGEMENT)
|
||||
if(servants >= 12 && clockwork_caches >= 5 && clockwork_construction_value >= 250 && !unconverted_ai_exists)
|
||||
return 1 //12 or more non-brain servants, 5+ clockwork caches, at least 250 CV, and there are no living, non-servant ais
|
||||
return 0
|
||||
|
||||
/proc/generate_cache_component(specific_component_id) //generates a component in the global component cache, either random based on lowest or a specific component
|
||||
if(specific_component_id)
|
||||
clockwork_component_cache[specific_component_id]++
|
||||
else
|
||||
var/component_to_generate = get_weighted_component_id()
|
||||
clockwork_component_cache[component_to_generate]++
|
||||
|
||||
/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab) //returns a chosen component id based on the lowest amount of that component
|
||||
if(storage_slab)
|
||||
return pickweight(list("belligerent_eye" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["belligerent_eye"] + storage_slab.stored_components["belligerent_eye"]), 1), \
|
||||
"vanguard_cogwheel" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["vanguard_cogwheel"] + storage_slab.stored_components["vanguard_cogwheel"]), 1), \
|
||||
"guvax_capacitor" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["guvax_capacitor"] + storage_slab.stored_components["guvax_capacitor"]), 1), \
|
||||
"replicant_alloy" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["replicant_alloy"] + storage_slab.stored_components["replicant_alloy"]), 1), \
|
||||
"hierophant_ansible" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["hierophant_ansible"] + storage_slab.stored_components["hierophant_ansible"]), 1)))
|
||||
|
||||
return pickweight(list("belligerent_eye" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["belligerent_eye"], 1), \
|
||||
"vanguard_cogwheel" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["vanguard_cogwheel"], 1), \
|
||||
"guvax_capacitor" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["guvax_capacitor"], 1), \
|
||||
"replicant_alloy" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["replicant_alloy"], 1), \
|
||||
"hierophant_ansible" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["hierophant_ansible"], 1)))
|
||||
|
||||
/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE)
|
||||
// When servants invoke ratvar's power, they speak in ways that non
|
||||
// servants do not comprehend.
|
||||
// Our ratvarian chants are stored in their ratvar forms
|
||||
|
||||
var/list/spans = list(SPAN_ROBOT)
|
||||
|
||||
var/old_languages_spoken = AM.languages_spoken
|
||||
AM.languages_spoken = HUMAN //anyone who can understand HUMAN will hear weird shitty ratvar speak, otherwise it'll get starred out
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(!whisper)
|
||||
L.say(message, "clock", spans)
|
||||
else
|
||||
L.whisper(message)
|
||||
else
|
||||
AM.say(message)
|
||||
AM.languages_spoken = old_languages_spoken
|
||||
|
||||
/*
|
||||
|
||||
The Ratvarian Language
|
||||
|
||||
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from
|
||||
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult).
|
||||
|
||||
While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is
|
||||
actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached.
|
||||
This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated
|
||||
sentence thirteen places ahead changes it right back to plain English.
|
||||
|
||||
There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have apostrophes, hyphens, and spaces, making the plain
|
||||
English translation apparent but disjoined (for instance, "Oru`byq zl-cbjre!" translates directly to "Beh'old my-power!") although this can be ignored without impacting overall quality. When
|
||||
translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Oru`byq zl-cbjre!" into "Behold my power!" after removing the
|
||||
abnormal spacing, hyphens, and grave accents.
|
||||
|
||||
List of nuances:
|
||||
|
||||
- Any time the word "of" occurs, it is linked to the previous word by a hyphen. If it is the first word, nothing is done. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.")
|
||||
- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun.
|
||||
- The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-Neq (Vangu-Ard), although these words can be used in proper context if one is
|
||||
not referring to the four generals and simply using the words themselves.
|
||||
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user