diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index c1ef5370..86a020c8 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -614,7 +614,7 @@
"alP" = (/obj/machinery/light/small{dir = 8},/obj/machinery/button/door{desc = "A remote control switch for the medbay foyer."; id = "outerbrig"; name = "Brig Exterior Doors Control"; normaldoorcontrol = 1; pixel_x = -26; pixel_y = -5; req_access_txt = "63"},/obj/machinery/button/door{desc = "A remote control switch for the medbay foyer."; id = "innerbrig"; name = "Brig Interior Doors Control"; normaldoorcontrol = 1; pixel_x = -26; pixel_y = 5; req_access_txt = "63"},/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel/dark,/area/security/brig)
"alQ" = (/obj/structure/chair/office/dark{dir = 4},/turf/open/floor/plasteel/dark,/area/security/brig)
"alR" = (/obj/structure/table/reinforced,/obj/machinery/door/poddoor/shutters/preopen{id = "briggate"; name = "security shutters"},/obj/machinery/door/window/eastright{name = "Brig Desk"; req_access_txt = "2"},/obj/item/restraints/handcuffs,/obj/item/radio/off,/turf/open/floor/plasteel/dark,/area/security/brig)
-"alS" = (/obj/effect/turf_decal/tile/blue{dir = 4},/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/structure/medkit_cabinet{pixel_y = 27},/obj/effect/turf_decal/loading_area{name = "steel pannel"; icon_state = "steel_panel"; dir = 10},/turf/open/floor/plasteel,/area/hallway/primary/central)
+"alS" = (/obj/machinery/door/airlock/public/glass{dir = 4; name = "Cryogenics "},/obj/structure/cable{icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/open/floor/plasteel,/area/crew_quarters/cryopod)
"alT" = (/obj/structure/closet/secure_closet/brig{id = "Cell 4"; name = "Cell 4 Locker"},/turf/open/floor/plasteel,/area/security/brig)
"alU" = (/obj/machinery/atmospherics/components/unary/vent_scrubber/on{dir = 1},/turf/open/floor/plasteel,/area/security/brig)
"alV" = (/obj/structure/bed,/obj/item/bedsheet,/obj/item/radio/intercom{desc = "Talk through this. It looks like it has been modified to not broadcast."; dir = 2; name = "Prison Intercom (General)"; pixel_x = 25; pixel_y = -2; prison_radio = 1},/turf/open/floor/plasteel,/area/security/brig)
@@ -1520,7 +1520,7 @@
"aDl" = (/obj/machinery/cryopod{dir = 4},/turf/open/floor/carpet,/area/crew_quarters/cryopod)
"aDm" = (/obj/machinery/atmospherics/components/unary/vent_scrubber/on{dir = 4},/turf/open/floor/carpet,/area/crew_quarters/cryopod)
"aDn" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/open/floor/carpet,/area/crew_quarters/cryopod)
-"aDo" = (/obj/machinery/door/airlock/public/glass{name = "Cryogenics "},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/door/firedoor,/obj/machinery/door/firedoor,/turf/open/floor/plasteel,/area/crew_quarters/cryopod)
+"aDo" = (/obj/machinery/door/airlock/public/glass{dir = 4; name = "Cryogenics "},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/door/firedoor,/obj/machinery/door/firedoor,/turf/open/floor/plasteel,/area/crew_quarters/cryopod)
"aDp" = (/obj/machinery/atmospherics/pipe/manifold4w/scrubbers/hidden,/obj/effect/turf_decal/tile/neutral,/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/machinery/camera{c_tag = "Dormitory South"; dir = 8},/turf/open/floor/plasteel,/area/crew_quarters/dorms)
"aDq" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/closed/wall,/area/crew_quarters/toilet)
"aDr" = (/obj/structure/sink{dir = 8; pixel_x = -12; pixel_y = 2},/obj/structure/sink{dir = 8; pixel_x = -12; pixel_y = 2},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/structure/cable{icon_state = "2-4"},/obj/effect/turf_decal/loading_area{dir = 8; icon_state = "drain"; name = "drain"},/turf/open/floor/plasteel/freezer,/area/crew_quarters/toilet)
@@ -1588,7 +1588,7 @@
"aEB" = (/obj/machinery/light/small{dir = 8},/turf/open/floor/plasteel/dark,/area/ai_monitored/storage/eva)
"aEC" = (/obj/structure/cable{icon_state = "2-4"},/turf/open/floor/carpet,/area/crew_quarters/cryopod)
"aED" = (/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/carpet,/area/crew_quarters/cryopod)
-"aEE" = (/obj/machinery/door/airlock/public/glass{name = "Cryogenics "},/obj/structure/cable{icon_state = "4-8"},/obj/machinery/door/firedoor,/turf/open/floor/plasteel,/area/crew_quarters/cryopod)
+"aEE" = (/obj/effect/turf_decal/tile/blue{dir = 4},/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/structure/medkit_cabinet{pixel_y = 27},/turf/open/floor/plasteel,/area/hallway/primary/central)
"aEF" = (/obj/machinery/atmospherics/pipe/manifold/supply/hidden{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/plasteel,/area/crew_quarters/dorms)
"aEG" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/effect/turf_decal/tile/neutral,/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/plasteel,/area/crew_quarters/dorms)
"aEH" = (/obj/machinery/door/airlock{dir = 4; name = "Unisex Restrooms"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/plasteel/freezer,/area/crew_quarters/toilet)
@@ -1881,7 +1881,7 @@
"aKi" = (/obj/effect/turf_decal/tile/red,/obj/effect/turf_decal/tile/blue{dir = 8},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/turf/open/floor/plasteel,/area/crew_quarters/theatre)
"aKj" = (/obj/effect/turf_decal/tile/red,/obj/effect/turf_decal/tile/blue{dir = 8},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/open/floor/plasteel,/area/crew_quarters/theatre)
"aKk" = (/obj/effect/turf_decal/tile/red,/obj/effect/turf_decal/tile/blue{dir = 8},/obj/structure/cable{icon_state = "1-2"},/obj/machinery/vending/autodrobe,/turf/open/floor/plasteel,/area/crew_quarters/theatre)
-"aKl" = (/obj/effect/turf_decal/loading_area{name = "steel pannel"; icon_state = "steel_panel"; dir = 10},/turf/open/floor/plasteel,/area/hallway/primary/central)
+"aKl" = (/obj/effect/turf_decal/loading_area{dir = 2; icon_state = "drain"; name = "drain"},/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/plasteel,/area/hallway/primary/central)
"aKm" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/effect/turf_decal/bot{dir = 2},/obj/structure/cable{icon_state = "1-2"},/turf/closed/wall,/area/maintenance/starboard/fore)
"aKn" = (/obj/structure/table/reinforced,/obj/item/storage/secure/briefcase,/obj/item/storage/box/PDAs{pixel_x = 4; pixel_y = 4},/obj/item/storage/box/ids,/turf/open/floor/plasteel,/area/bridge)
"aKo" = (/obj/machinery/light{dir = 1; pixel_y = 16},/turf/open/floor/wood,/area/crew_quarters/bar)
@@ -2544,7 +2544,6 @@
"aWV" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 5},/turf/open/floor/carpet,/area/chapel/main)
"aWW" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/open/floor/carpet,/area/chapel/main)
"aWX" = (/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{dir = 1},/turf/open/floor/carpet,/area/chapel/main)
-"aWY" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/public/glass{dir = 4; name = "Chapel"},/turf/open/floor/carpet,/area/chapel/main)
"aWZ" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/effect/turf_decal/tile/red{dir = 8},/turf/open/floor/plasteel/white/corner{dir = 1},/area/hallway/secondary/exit)
"aXa" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/open/floor/plasteel,/area/hallway/secondary/exit)
"aXb" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/effect/landmark/event_spawn,/turf/open/floor/plasteel,/area/hallway/secondary/exit)
@@ -7059,20 +7058,20 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauSaAaauSaAbaxyayUaAcaAdaAeaAfayUaxyaAbayUauSaAgaAhalzaAiaAjaAkaAkaAkaAlazcaAmaAnaAoaApaAqaAraAmazcaAsaAtaAuaAvaAvaAvaAvaAvaAwarYaxSaadaAxaAxaAyaAxaAzaAxaAxaadaxYaxZayaaCXaABaACaADaCYayaaAEaAFaAGaAHaAIaAJaAKaALaAMaANaAOaAPayoayoayoaAQazwanbaARahfafmaASaASaASaASaASaATatuazFazFazFazFazFazFaAUaAVaAWazFaqGaqGaqGaqGaJgaJhaltayJaqKaqKaqKaqKaqKayJaltaltamIamIamIaltaAYayKaAZaBaayKamIarPaltamIasNaltamIamIaltarPasOaltamIamIaltaBbamIaxnayMaqTarUarUarUarUarUarUarUarUarUarVarVarVarVarVaadaoBaoBaoBaoBaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUaBcayUayUayUayUayUayUaBcayUaaaauSaBdazbaBeaBfaBgaBeaBeaBeaBhazcaAmaBiaBjaBkaBlaBmaAmazcaBnaBoaBnaBnaBnaBnaBnaBnaBpaBnaBqaaaaAxaBraBsaBtaBuaBvaAxaaaaxYaxZayaaCXaBwaBxaByaCYayaaqsaBzaydaBAaBBaBCaBDaBEaAPaBFaBGayoayoaBHayoaAQazwanbazxahfafmaASaBIaBJaBKaBLayuatuazFaBMaBNaBOaBOazFaBSaBPaAWazFaBQaZMaBRaqGaAXauJaltaBVaBWaBWaBWaBWaBWaBXaltaltaBYaBZaCaaltaltayKaCbaCcayKaCdaCealtaltaltaltaltaltaCfaCgaChaCiaCiaCiaCjaCkaClaCmaCnaCoaCpaCqaCraCsaCtaCuaCvaCwaCwaCwaadaadaadaadaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauSayWaCxaBeaCyaCzaCAaCBaCCaCDazcaAmaCEaCFaCGaCFaCFaAmazcaCHaCIaCJaCKaCLaCMaCNaCOaCPaCQaBqaadaAxaCRaCSaCTaCUaCVaAxaadaxYaxZayaaCZaDabiybizbiAayaaqsaDbaydaDcaDdaDeayoaDfaDgaDhaDiaDjaAQayqaDkayqazwanbazxahfafmaASaDlaDmaDnaDoasxaDpaDqaDraDsaDtaDtaDuaDvaDwaDBaDxaBUaDyaDzaDAaDCaDDaltaHwaltaHwaltaHwaltaHwaltaltaBYaDEaDFaDGaDHayKaDIaDJayKarPamIaltaaaaltaDKaDLaDLaDMaDNaDOaDOaDOaDOaDOaDPaDQaDRaDSaDTaDTaDTaDUaVqaDWaDXaDYaDZaEaaEbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayWaEcaBeaEdaEeaEfaEgaEhaEiazcaEjaCFaCFaCFaCFaCFaCFaEkaElaCIaElaEmaElaElaElaElaCPaElaBqaaaaAxaEnaEoaEoaEpaEqaAxaaaaxYaxZayaaEraEsaEtaEuaEvayaaqsaEwaydaydaDiaExaEyaEzaEAaydaydayoayoayqaEBayqazwanbazxahfafmaASaDlaECaEDaEEaEFaEGaEHaEIaEJaEKaEKaEKaEKaEKaELazFaEMaEOaFHaqGaHCaHDaltaltaltaltaltaltaltaltaltaltaltaltaltaEPaltayKaEQaERaESaETaEUaEVaEWaEVaEXaEYaDOaEZaFaaFbaFbaFbaFbaFcaFdaFeaFcaFcaFcaFcaFcaFcaFcaFfaFgaFhaCwaCwaCwaadaadaadaadaadaadaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayWaEcaBeaEdaEeaEfaEgaEhaEiazcaEjaCFaCFaCFaCFaCFaCFaEkaElaCIaElaEmaElaElaElaElaCPaElaBqaaaaAxaEnaEoaEoaEpaEqaAxaaaaxYaxZayaaEraEsaEtaEuaEvayaaqsaEwaydaydaDiaExaEyaEzaEAaydaydayoayoayqaEBayqazwanbazxahfafmaASaDlaECaEDalSaEFaEGaEHaEIaEJaEKaEKaEKaEKaEKaELazFaEMaEOaFHaqGaHCaHDaltaltaltaltaltaltaltaltaltaltaltaltaltaEPaltayKaEQaERaESaETaEUaEVaEWaEVaEXaEYaDOaEZaFaaFbaFbaFbaFbaFcaFdaFeaFcaFcaFcaFcaFcaFcaFcaFfaFgaFhaCwaCwaCwaadaadaadaadaadaadaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayWaFiaBeaFjaFkaFlaFmaFnaFoazcaFpaCFaCFaCFaCFaCFaFqazcaFraFsaFtaFuaElaElaElaFvaFwaFxaBqaadaAxaFyaFzaFAaFBaFCaAxaadaxYaFDayaaFEaFFaEtaFGaENayaaqsaFIayqaFJayoaFKaFLaFMayoaFNayqaFOaFPayqaFLayqaFQaoNaFRahfafmaASaDlaFSaFTaFUattatuazFaFVaFWazFaFXazFaFZazFaFYaZMaZMaWIaGbaGcaGeaGfaGgaHHaGiaGiaGjaGkaHyaHzaGkaGlaGmaGkaGkaGnaGiaGoaGpaCnaGqaGraGsaGtaGuaGtaGvaGwaFbaGxaGyaFbaGzaGAaGBaFcaGCaGDaFcaGEaGFaGGaGHaGIaGJaGKaGLaGMaGNaGOaGPaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoBaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaGQayUayWaGRaBeaBeaGSaGTaGUaGTaBeazcazcazcazcaGVaCFaGWaGXazcaGYaCIaElaElaElaGZaElaElaCPaHaaBqaaaaAxaAxaHbaHcaHbaAxaAxaaaaxYaxZayaaHdaHeaHfaHgaHhayaaqsaHiayqaHjayoaHkaFLaHlayoaHmayqaAQaAQayqaHnayqaHoaHpaHqahfanDaASaASaASaASaASaHraHsazFaHtaHuazFaHvazFaHxazFaGdaGhaHJaGhaHAaHGbiBbiCaHEaHFaHIaHIaIYaIZaJcaKmaHIaHKaHLaHMaxpaxpaxpaHNaHOaHPaHQaHRamIaHSaHSaHSaHTaHUaFbaHVaHWaHXaHYaHZaIaaFcaIbaIcaFcaIdaIeaIfaIgaGIaIhaFfaFgaDYaIiaIjaGPaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayWaxBaIkaIlaImaIlaInaxBaIoaIpaIqaIrazcaIsaCFaCFaItazcaIuaCIaElaIvaIwaIxaIyaIzaIAaIBaBqaaaaadaaaaICaIDaICaaaaadaaaaxYaxZayaaIEaIFaIGaFGaIHayaaqsapyayqaIIayoaFLaFLaFLaIJaIKayqaaaaaaaILaIMaINaIOaIPaIQaIRaISaILaaaaaaaITaIUaIVaIWazFaIXaHuaHuaHuaHuaHuazFaJaaJbaJdaJeaJdaJdaNtaPQbiDaBTaBTaJfaKhaKiaKjaKkaJiaJiaJjaJkaJlaJiaJmaHSaHSaJnaHTaHSaHSaHSaJoaJpaHTaHUaFbaJqaJraJsaJtaJuaJvaFcaJwaJxaJyaJzaJAaJBaJCaJDaIhaFfaJEaDYaGNaJFaGPaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayWaxBaJGaJHaJIaJHaJJaJHaJHaJHaJKaxBazcaJLaJMaJLazcazcaJNaJOaJNaBnaBnaBnaBnaJNaJPaJQaBqaJRaJSaJSaJTaJUaJVaJSaJSaJWaxYaJXayaaJYayaaJZaKaaKbayaarjaoJayqayqayqaAQaKcaAQayqayqayqaILaILaILaKdaIPaIPaIPaIPaIPaKeaILaILaILaITaKfaIVaKgazFaLMazFazFazFazFazFaJdaGaaKsbiEaKtbgUaKoaMcaLQaLcaLTaBTaKpaKraKraKjaLSaJiaLUaKuaKvaKwaJiaKxaKyaKzaKAaKBaKCaKDaKEaKFaKGaHTaHUaFbaKHaKIaKJaJtaJuaKKaFcaKLaKMaKNaKOaKPaKQaKRaFcaFcaKSaFgaDYaIiaIjaGPaaaaadaadaadaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauSaKTaxBaKUaKVaKWaKXaKYaKZaweaLaaLbaxBaLjaLdaLeaLeaLfaLeaLeaLgaLeaLeaLeaLeaLeaLeaLhaLiaLqaLkaLlaLmaLmaLnaLmaLmaLmaLmaLoaLpaLxaLraLmaLsaLmaLtaMWaLuaLvaLwaLRalSaIRaIRaIRaLNaLPaLPbiFaLPaLPaLAaLBaLCaLDaLEaLFaLGaLPaLPbiFaLHaLIaLJaLKaPJbcXaNKbiGaLPbiHbiIaOCaLVaKsaLWaWHaLXaLYaOvaNjaNlaNnaBTaLZaMaaMbaNkaNmaJiaMdaKuaMeaMfaJiaJiaMgaMhaMiaMjaMkaMlaMmaMnaMoaHTaHUaFbaMpaMpaMqaMraMpaMpaFcaMsaMtaFcaMuaKRaKRaKRaFcaMvaMwaMxaDYaCwaCwaCwaMyaMyaMyaMzaMzaMzaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayVayUayUayUayUayUayUayVayUaaaauSaBdaMAaKUaMBaMCaMDaMEaMFaweaMGaLbaMHaIkaLdaMIaMJaMKaMLaMLaMMaLeaLeaLeaLeaLeaLeaLeaLiaLeaLdaMNaLeaLeaMOaMPaMQaMQaMQaMRaMSaMQaMTaMQaMUaMQaMVaOnaMXaMYaMZaIPaKlaIPaIPaIPaIPaIPaIPaLzaIPaIPaNaaNbaNcaNdaNeaNfaNgaIPaIPaLzaIPaNhaIPaIPaIPaIPaIPaIPaIPaNiaIPaOCaNoaNpaNqaNraStaNsbiJaOwaOxaOyaBTaNuaOuaOuaHBaOzaJiaNvaKuaNwaNxaNyaJiaHSaHSaNzaHSaHSaHSaNAaNBaNAaHTaHUaFbaNCaMpaMpaNDaMpaNEaFcaFcaFcaFcaFcaFcaFcaNFaFcaFfaFfaFgaDYaNGaNHaCwaNIaNJaRkaNLaNMaMzaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauSaKTaxBaKUaKVaKWaKXaKYaKZaweaLaaLbaxBaLjaLdaLeaLeaLfaLeaLeaLgaLeaLeaLeaLeaLeaLeaLhaLiaLqaLkaLlaLmaLmaLnaLmaLmaLmaLmaLoaLpaLxaLraLmaLsaLmaLtaMWaLuaLvaLwaLRaEEaIRaIRaIRaLNaLPaLPbiFaLPaLPaLAaLBaLCaLDaLEaLFaLGaLPaLPbiFaLHaLIaLJaLKaPJbcXaNKbiGaLPbiHbiIaOCaLVaKsaLWaWHaLXaLYaOvaNjaNlaNnaBTaLZaMaaMbaNkaNmaJiaMdaKuaMeaMfaJiaJiaMgaMhaMiaMjaMkaMlaMmaMnaMoaHTaHUaFbaMpaMpaMqaMraMpaMpaFcaMsaMtaFcaMuaKRaKRaKRaFcaMvaMwaMxaDYaCwaCwaCwaMyaMyaMyaMzaMzaMzaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayVayUayUayUayUayUayUayVayUaaaauSaBdaMAaKUaMBaMCaMDaMEaMFaweaMGaLbaMHaIkaLdaMIaMJaMKaMLaMLaMMaLeaLeaLeaLeaLeaLeaLeaLiaLeaLdaMNaLeaLeaMOaMPaMQaMQaMQaMRaMSaMQaMTaMQaMUaMQaMVaOnaMXaMYaMZaIPaIPaIPaIPaIPaIPaIPaIPaLzaIPaIPaNaaNbaNcaNdaNeaNfaNgaIPaIPaLzaIPaNhaIPaIPaIPaIPaIPaIPaIPaNiaIPaOCaNoaNpaNqaNraStaNsbiJaOwaOxaOyaBTaNuaOuaOuaHBaOzaJiaNvaKuaNwaNxaNyaJiaHSaHSaNzaHSaHSaHSaNAaNBaNAaHTaHUaFbaNCaMpaMpaNDaMpaNEaFcaFcaFcaFcaFcaFcaFcaNFaFcaFfaFfaFgaDYaNGaNHaCwaNIaNJaRkaNLaNMaMzaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauSaAaauSayUaxyayUaNNaNOaNPaNQayUaxyayUayUauSayWaxBaKUaNRaNSaMDaMEaMFaweaNTaLbaxBaIkaLdaLeaNUaNVaNVaNVaNWaNXaNYaNVaNZaNVaNVaNVaOaaNVaObaNVaNVaNVaOcaOdaOeaOfaOfaOfaOgaOhaOiaOjaOkaOlaOmaWUaOoaOpaIPaOqaOqaOqaOraOqaOqaOqaOqaOsaOqaOqaOqaOqaOqaOqaOtaOqaOqaOqaOqaPPaOqaOqaOqaOqaOqaOqaOtaOqaIPaIPaIPaJdaPLaStaStaStaStaRiaMcaLQaPOaNnaBTaBTaPKaBTaBTaBTaJiaOAaOBaODaWFaOEaJiaHSaOFaOGaOHaOIaOHaOHaOJaOKaHTaHUaFbaOLaOLaOMaONaOOaOOaOPaFbaOQaORaOSaCwaFfaGNaOTaFfaFfaOUaOVaCwaOWaCwaOXaOYaOZaPaaPbaMzaMzaMzaMzaMzaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaweawfaweayUaBcayUayWaxBaxBayXayUaBcayUaPcaPdaPeaxBaKUaPfaPgaKXaPhaKZaweaPiaLbaxBaPjaPjaPjaPkaPlaPlaPlaPlaPlaPlaPmaPnaPlaPoaPlaPlaPlaPpaPqaPraPqaPsaPtaPuaLeaLeaPvaPwaPxaLeaPyaPzaLeaPAaPAaPMaRgaRmaILaILaILaILaILaILaILaILaPCaPDaPEaPFaPEaPEaPEaPGaPEaPHaPEaPIaPCaILaILaILaILaILaILaILaILaPMaTSaUTaJdaVjaRiaRiaRiaRiaKsaMcaLQaRjaKsaRsaKsaKsaVnaJiaRnaJiaJiaPRaJkaJiaJiaJiaJiaOHaPSaPTaPTaPTaPTaPUaOHaHTaHUaFbaPVaMpaOMaONaMpaMpaPWaFbaPXaPYaPZaCwaFfaIiaQaaQbaQbaQcaQdaQeaQfaCwaQgaQhaQiaQjaQjaQkaQlaQlaQmaQlaQnaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoBaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaQoaaaaaaaaaaxwaXfaxyaxzaQpaxBaQqaPeaxBaxBaQraQqaxBaQpaPeaxBaxBaxBaQsaQtaQuaQvaQwaQxaQxaQyaQzaxBaPjaQAaPjaQBaPlaQCbiKaQEaQFaQGaQDaQHaQIaQJaQKaQLaQMaPpaQNaQOaQPaPsaQQaPuaPuaQRaPuaPuaPAaPAaQSaQTaPAaPAaPAaQUbiLbbeaILaaaaaaaaaaaaaaaaaaaaaaPCaKnaQVaQWaQXaQYaQZaRaaRbaRcaRdaReaPCaaaaaaaaaaaaaaaaaaaaaaILaIOaIPaIPbiMaKsaKsaKsaRlaKsaKsaRfaSfaRjaKsaSraKsaKsaKsbaEaSBaRoaRpaRqaRraRtaRuaSuaJiaOHaRvaVsbiNbiNbiOaRxaOHaHTaRyaFbaRzaRzaOMaONaRAaRAaRBaFbaFbaRCaFbaCwaRDaGNaOTaREaRFaOUaOVaCwaCwaCwaMzaRGaRHaMzaMzaMzaMzaMzaMzaMzaRIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaweaRJawgaRKaRLaRLaRLaRLaRLaRLaRLaRLaRKaRLaRMaxBaxBaIkaxBaRNaROaxBaRPaxBaRQaRRaRSaPjaRTaPjaQBaPlaRUaQDaQDaQDaQDaQDaQHaQDaQDaQDaQDaQMaPpaRVaQOaQOaPsaQQaPuaRWaRXaRXaRYaPAaRZaSaaSbaScaSdaSeaIPbiLbbeaILaaaaaaaaaaaaaPCaPCaPCaPCaSgaShaSiaSjaSkaSlaSmaSnaSoaSpaSvaPCaPCaPCaPCaaaaaaaaaaaaaILaIOaIPaIPaSqaKsaKsaSsaStaSwbiPaSzaSAaRjaSsaTTaSwaKsaTUaJiaWKaSCaSDaSEaSFaSGaSHaSBaSIaSJaSKbiQaSLaSMbiRaSNaOHaHTaHUaFbaMpaMpaOMaONaRAaRAaMpaSOaSPaMpaSQaCwaKSaSRaSSaREaREaSTaSUaSVaCwaSWaSXaQhaQiaQjaQjaSYaQlaQlaQlaQlaSZaTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaauSauSauSauSayUayUayUayUayUayUayUayUauSauSaweaIkaTbaTcaTcaTdaTcaTcaTcaTcaTeaTcaTcaPjaRTaTfaTgaPlaThaQDaTiaTjaTkaTlaTmaTnaToaQDaQDaTpaPpaTqaTraTsaPsaQQaPuaTtaTuaTvaTwaPAaTxaTyaSbaTzaTAaSeaIPaPBbbeaILaILaTBaPCaPCaPCaTCaTDaTEaTFaTGaTHaTIaTJaTHaTKaTHaTLaTMaTNaTOaTPaTQaPCaPCaPCaTBaILaILaLzaLzbbfaJdaKsaKsaSsaVmaSwbiSaWIaTVaKqaSsbiTaSwaKsaKsaVoaSBaSBaWJaTXaTYaTZaUaaSBaUbaUcaUdbiQaUeaUfbiRaUgaUhaHTaHUaFbaUiaUiaOMaONaUjaMpaMpaUkaMpaUlaUmaCwaUnaUoaUpaREaREaUqaUraFfaCwaUsaQjaQhaQiaQjaPbaMzaMzaMzaMzaMzaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUaAcazaaUtaTcaUuaUvaUwaUxaUwaUyaUzaUwaTcaRTaRTaUAaUBaPlaUCaUDaUEaUFaUGaUHaUIaUJaUKaULaUMaQMaPpaPpaPpaPpaPsaQQaPuaPuaPuaPuaPuaPAaUNaUOaUPaTzaUQaSeaIPaIPaLyaIRaIRaURaUSaZQaPCaUUaUVaUWaUXaUYaUXaUZaVaaVbaVcaVdaVeaVfaVdaVgaVhaViaPCaZRaUSaVkaVlaIRaIOaIPaxxaJdaSyaKsaSsbiUaSwaKsaZMaZMaKsaSsaStaSwaKsaKsaVoaSBaSBbgZbiVaVpaVpaUaaWLaJiaVraUdbiWbiXbiXbiYaUgaVtaHTaVuaFbaFbaFbaOMaONaVvaVwaMpaVxaVyaKJaVzaCwaFfaSRaSSaREaREaVAaSUaVBaCwaVCaQjaQhaQiaQjaPbaMzaZNaZOaZPaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVDayUayUayWaxBaTcaVEaVFaVGaUuaVHaVIaUzaUwaTcaVJaVKaVLaPjaPlaVMaVNaVOaVPaVQaVQaVRaVQaVQaVQaVSaVTaPlaVUaVVaVWaVXaVYaVZaWaaWbaWcaWdaWdaWdaWdaWdaWdaWdaWdbbVaIPaIPaIPaIPaWeaWfaWgaWhaWiaWjaWkaWlaWmaWnaWoaWpaWqaWraWsaWtaWuaWvaWkaWwaWxaWyaWzaWAaWBaWCaWDaWEaIPaIPbbXbiZaKsaKsaKsaKsbjaaZMaZMaKsaSsaStaSwaKsaKsaVoaSBaSBaSBaSBaSBaSBaUaaYoaJiaOHaUdaRwaRwaRwaRwaUgaOHaHTaWMaWNaWOaWPaWQaWRaWSaWSaWTaOMaOMaOMaOMaWYaREaREaREaREaREaWVaWWaWXaYIaWZaXaaXbaXcaPaaXdaMzaZPaZOaZOaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaVDayUayUayWaxBaTcaVEaVFaVGaUuaVHaVIaUzaUwaTcaVJaVKaVLaPjaPlaVMaVNaVOaVPaVQaVQaVRaVQaVQaVQaVSaVTaPlaVUaVVaVWaVXaVYaVZaWaaWbaWcaWdaWdaWdaWdaWdaWdaWdaWdbbVaIPaIPaIPaIPaWeaWfaWgaWhaWiaWjaWkaWlaWmaWnaWoaWpaWqaWraWsaWtaWuaWvaWkaWwaWxaWyaWzaWAaWBaWCaWDaWEaIPaIPbbXbiZaKsaKsaKsaKsbjaaZMaZMaKsaSsaStaSwaKsaKsaVoaSBaSBaSBaSBaSBaSBaUaaYoaJiaOHaUdaRwaRwaRwaRwaUgaOHaHTaWMaWNaWOaWPaWQaWRaWSaWSaWTaOMaOMaOMaOMbegaREaREaREaREaREaWVaWWaWXaYIaWZaXaaXbaXcaPaaXdaMzaZPaZOaZOaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaXeaXgaxybhaaxBaxBaTcaXhaXiaXjaXkaXkaXlaXmaXnaTcaXoaRTaVLaXpaXpaXpaXqaXraXpaXsaXtaXuaXvaXwaXwaXxaXyaPlaXzaXAaXBaXCaXDaXEaXBaXFaXGaXGaXHaXIaXJaXKaXLaXMaWdbbVaIPaXNaXOaXPaXQaXRaXSaPCaXTaXUaXVaXWaXXaXYaXYaXZaYaaYbaYcaYdaYeaYfaXVaYgaXTaPCaXSaXRaYhaYiaXOaYjaIPaIPbebbbXbiZaKsaKsaKsaKsaKsaKsaKsaRlbjbaKsaKsaKsaJiaYpaYqaSBaSBaYraSBaYXbhyaJiaYsaYtaRwaYuaYuaYvaYtaYwaYxaYyaYzaYzaYAaYBaYCaOMaOMaYDaOMaOMaOMaOMbegaYEaYFaYFaYFaYFaYFaYGaYHbjsaYJaYKaYLaYMaQjaYNaMzbjhaZOaZNaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUayUayUayWaYOaYPaYQaYRaYSaYSaYSaYSaYTaUuaTcaYUaYVaVLaXpaYWbaKaYYaYZaXpaZaaZbaZcaPlaZdaZeaZfaZgaPlaZhaZiaZjaZkaZjaZlaZmaZnaWdaZoaZpaZpaZqaZraZsaZtaWdbbYaLzaZuaZvaZvaZvaZvaZvaZvaZwaZxaZyaXXaXZaZzaZAaZAaZBaZAaZAaZCaYbaYeaZDaZEaZFaZDaZDaZDaZDaZDaZDbjiaIPaIPbgTbjjbbXbiZbjkaSwbjlaKsaKsaKsaWGaKsaKsbjmaYkaJibjnaJiaZSaYlaZTaZTaJiaJiaJiaZUaRwaRwaZVaZWaZXaZYaZWaHTaZZbaababaFbbacbadbaeaVwaMpbafaUkaVwbagaCwbahaFfbaiaREaREbaiaFfbajaCwbakbalbamaQiaQjaPbaMzaMzaMzaMzaMzaMzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayUbanaPebaoaTcaUwaVFaUwaUubapaUwbaqaUwaTcbarbasbataXpaXpaXpbaubavaXpaZbbawaZbaPlaZdaZeaZfaZgaPlaZhaZibaxbayaZjbazaZmaZnaWdbaAaZpaZpaZGbaBaZpbaDbbxaIPaIPbbZaZvbaFbaGbaHbaIbaJbcebaLbaMbaNbaOaZAaZAbaPbaQbaPaZAaZAbaRbaSbaCbaTbaUbaXbaYbbzbaVbaWaZDbjoaIPaIPbgTbgTbjpbbXaJdaJdaJdbbbaSqbbbaJdbbcaJdaJdaJdaJibcbbdZbbdbbdbbdbbdbcfbdHaJiaZWbbgbbgaZWbaabaabaabaaaHTaZZbaababaFbaFbaFbbbhaFbbbhaFbbbhaFbaFbaCwaCwbbibbibbibbibbibbiaCwaCwbbjaQjbbkaQiaQjaQjbblaQlaQlaQlaQlaSZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@@ -7095,7 +7094,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabqFbnFbnFbnFbhYbnFbnFbnFbzpbzpbzpbzpbzqbzrbzrbzpbzpbzsbztbzubzvbxWbzwbzxbzybzzbxWbzAbpAbbeaTBaTBbobbobbobbobbobbzBbobaILaILaILbtSbzCbzDbzEbtYaILaILaILbsHbsHbsHbsHbsHbsHbsHbsHbsHbzFaIPbzGbxabxabzHbzIbxabxabxabzJbyubzKbyubzLbzMbzNbzObzPbzQbzLbhcbyCbvVbzRbzSbzTbzUbzVbzWbzXbzUbzUbzYbzZbAabAbbAcbAcbAcbAcbAdbAcbAcbAcbAebAebAfbAgbAhbAhbtrbAibtsbxybsabsbbsAbAmbAnbAobApbsebsebAqbAqbAqbsebArbsebxFbhIbAsbzmbAtblYaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaabzpbAubAvbAwbAxbAybAzbzrbAAbABbACbADbxXbAEbAFbAGbAHbxWbzAbpAaIPaLPbAIbAJbAKaLPbiFbALbAMbANaWDaWDaWDbAObAPbAQbARbASaIPaIPaIPaIPaLOaIPaLzbATaIPaIPbAUaIPbAVaIPbAWbxabAXbAYbAZbBabBbbxabBcbyubBdbyubzLbzMbzMbBebBfbBgbzLbhcbBhbvVbuBbBibBjbBkbBlbBmbBnbBobBpbrGbrGbBqbBrbAcbBsbBtbBubBvbBwbBxbAcbBybBzbBAbBBbBCbAhbtrbAibBDbBEbsBbsVbtPbBIbBJbBKbApbBLbBLbBLbBLbBLbBLbBLbsebxFbhIbBMbBNbBOblYaadaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoBaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaabzrbBPbBQbBRbBSbBTbBUbBVbBWbBXbBYbBZbCabCbbAGbCcbCdbxWbzAbCeaIPaIPaIPaIPaIPaIPbCfaIPbpAaIPaIPaIPaIPaIPbCgbChbCiaIPaIPaIPaIPaIPaIPaIPaLzaIPaIPaIPaIPaNhbAVbCjbjDbxabCkbClbCmbCnbCobxabCpbyubyvbCqbxabCrbCsbCtbCubCvbxabhcbyCbvVbvVbvVbvVbvVbrGbrGbrGbrGbrGbrGbCwbCxbCybAcbCzbCAbCBbCCbCDbCEbAcbCFbCGbCHbCIbCJbAhbtrbCKbCLbCMbtQbyybyybyZbzabzbbApbBLbBLbCSbCTbBLbBLbBLbsebxFbhIbCUbzmbCVblYaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabzpbCWbCXbCYbCZbDabDbbDcbDdbDebDfbDdbDgbDhbDibDjbDkbxWbDlbDmbDnbfQbDnbDobDnbDnbDpbDnbDqbfQbDrbDsbfQbDtbDubDvbDwbDxbDybDzbDAbDAbDBbDAbDCbDDbDAbDEbDFbDGbDHbfQbDIbxabDJbDKbDLbxbbxbbxabxbbDMbxbbxabxabxabxabxabxabxabxabhcbhcbDNbDObDPbwZbDQbDRbAjbAkbAlbBFbDRbDWbDXbDYbAcbBsbDZbEabEbbEcbEdbAcbEebEfbEgbEhbEibAhbtrbEjbEkbxzbBGbBHbCNbCObCPbCQbApbBLbBLbBLbErbBLbBLbBLbsebEsbEtbEubzmbznblYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabzpbCWbCXbCYbCZbDabDbbDcbDdbDebDfbDdbDgbDhbDibDjbDkbxWbDlbDmbDnaKlbDnbDobDnbDnbDpbDnbDqbfQbDrbDsbfQbDtbDubDvbDwbDxbDybDzbDAbDAbDBbDAbDCbDDbDAbDEbDFbDGbDHbfQbDIbxabDJbDKbDLbxbbxbbxabxbbDMbxbbxabxabxabxabxabxabxabxabhcbhcbDNbDObDPbwZbDQbDRbAjbAkbAlbBFbDRbDWbDXbDYbAcbBsbDZbEabEbbEcbEdbAcbEebEfbEgbEhbEibAhbtrbEjbEkbxzbBGbBHbCNbCObCPbCQbApbBLbBLbBLbErbBLbBLbBLbsebEsbEtbEubzmbznblYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabzpbzpbzrbzrbzrbzrbzpbzpbEvbEwbACaTRbxWbxWbxWbxWbxWbxWbExbEyaITaITaITaITbEzbEzbEzbEzbEzbEzbEzbEzbEzbEzbEAaHpbEBbECbECbECbECbECbEDbECbECbECbECbEEbEFbEEaIUaKfbEGbxabEHbEIbEJbEKbELbxabEMbyubENbEObEPbEQbERbESbETbEUbEOblDbhcbhcbhcbhcbhcbsWbEVbCRbDSbCRbDTbDRbEZbCxbFabFabFabFabFabFabFabFabFabFbbFbbFbbFbbFbbFbbFcbFdbFebxzbxzbxzbxzbxzbxzbxzbApbsebsebsebsebsebsebsebsebxFbhIbFfbFgblYblYaadaadaadaaeaaeaaeaaeaaeaaeaaeaaeaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabFhaaaaaaaaaaadaaaaaabzsbFibFjbFkbFlbFlbFmbFnbFobFpbFqbFrbEyaaaaaaaadaaabEzbFsbFtbFubFvbFwbFxbFybFzbEzbFAbFBbFCbECbFDbFEbFFbFGbFHbFIbFJbFKbFLbFMbFNbEEbEEbEEbEEbxabFObFPbFQbFRbFSbFTbFUbFVbFWbFXbFVbFVbFVbFYbyubFZbGabGbbGcbGcbGdbGebGfbGgbEVbDUbDVbElbEmbDRbEZbCxbFabGlbGlbGlbGmbGlbGlbGlbFabGnbGnbGobGnbGnbFbbGpbGqbGrbGsbGtbGubGvbGwbGxbGybGzbGAbGBbGCbGDbGEbGFbGGbGGbGHbGIbGtbGtblYaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaabzsbzsbGJbGKbGLbDdbGMbGNbGObGObGPbGQbGRbGSaadbGTbGUbGVbGWbGXbFzbGYbFzbGZbFzbFzbFzbEzbHabHbbHcbECbHdbHebHfbHgbHhbHibHjbECbECbHkbHlbHmbHnbHobHpbHqbHrbHsbHtbHubHvbHwbHxbHybHzbHAbHBbHCbyubyubyubHDbjEbjEbjEbjEbjEbHEbHFbwYbEVbEnbEobCRbEpbDRbEZbCxbFabGlbGlbGlbGlbGlbGlbGlbFabHJbHKbHLbHMbHNbHObHPbHQbGrbHRbHSbHTbHTbHTbHTbHTbHTbHUbHVbHWbGDblYbHXbHYbHZbHZbIabIbbIcbGtatJaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadbIdbIebIdaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 8aab6175..8acc1d8f 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -185,6 +185,12 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
//We will round to this value in damage calculations.
#define DAMAGE_PRECISION 0.1
+//bullet_act() return values
+#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
+#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
+#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
+
//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25)
#define TOTAL_MASS_TINY_ITEM 1.25
#define TOTAL_MASS_SMALL_ITEM 2.5
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 83d603df..5bcee19f 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -1,10 +1,16 @@
// simple is_type and similar inline helpers
+#if DM_VERSION < 513
#define islist(L) (istype(L, /list))
+#endif
#define in_range(source, user) (get_dist(source, user) <= 1 && (get_step(source, 0)?:z) == (get_step(user, 0)?:z))
+#if DM_VERSION < 513
#define ismovableatom(A) (istype(A, /atom/movable))
+#else
+#define ismovableatom(A) ismovable(A)
+#endif
#define isatom(A) (isloc(A))
diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm
index 2ba50123..cabc67f6 100644
--- a/code/__DEFINES/logging.dm
+++ b/code/__DEFINES/logging.dm
@@ -35,6 +35,7 @@
#define LOG_GAME (1 << 12)
#define LOG_ADMIN_PRIVATE (1 << 13)
#define LOG_ASAY (1 << 14)
+#define LOG_CLONING (1 << 15)
//Individual logging panel pages
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK)
@@ -47,3 +48,4 @@
#define LOGSRC_CLIENT "Client"
#define LOGSRC_MOB "Mob"
+
diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index 86245940..0edb4239 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -100,6 +100,11 @@
#define NUKE_ON_TIMING 2
#define NUKE_ON_EXPLODING 3
+//cloning defines. These are flags.
+#define CLONING_SUCCESS (1<<0)
+#define CLONING_DELETE_RECORD (1<<1)
+
//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
#define PLANT_GENE_REMOVABLE (1<<0)
#define PLANT_GENE_EXTRACTABLE (1<<1)
+
diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm
index d344f7f0..402c3dc1 100644
--- a/code/__DEFINES/maths.dm
+++ b/code/__DEFINES/maths.dm
@@ -30,7 +30,11 @@
// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
+#if DM_VERSION < 513
#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
+#else
+#define CLAMP(CLVALUE,CLMIN,CLMAX) clamp(CLVALUE,CLMIN,CLMAX)
+#endif
// Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive
#define WRAP(val, min, max) ( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) )
@@ -39,7 +43,11 @@
#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
// Tangent
+#if DM_VERSION < 513
#define TAN(x) (sin(x) / cos(x))
+#else
+#define TAN(x) tan(x)
+#endif
// Cotangent
#define COT(x) (1 / TAN(x))
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 98d630b7..bb6fab9f 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -476,7 +476,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define PDAIMG(what) {""}
//Filters
-#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"border"=4,"color"="#04080FAA")
+#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"color"="#04080FAA")
#define EYE_BLUR(size) list("type"="blur", "size"=size)
#define GRAVITY_MOTION_BLUR list("type"="motion_blur","x"=0,"y"=0)
diff --git a/code/__DEFINES/reactions.dm b/code/__DEFINES/reactions.dm
index 99ff5ec3..00ac9b84 100644
--- a/code/__DEFINES/reactions.dm
+++ b/code/__DEFINES/reactions.dm
@@ -24,9 +24,9 @@
#define REACTION_OPPRESSION_THRESHOLD 5
#define NOBLIUM_FORMATION_ENERGY 2e9 //1 Mole of Noblium takes the planck energy to condense.
//Research point amounts
-#define NOBLIUM_RESEARCH_AMOUNT 1000
-#define BZ_RESEARCH_AMOUNT 150
-#define MIASMA_RESEARCH_AMOUNT 160
+#define NOBLIUM_RESEARCH_AMOUNT 100
+#define BZ_RESEARCH_AMOUNT 15
+#define MIASMA_RESEARCH_AMOUNT 16
#define STIMULUM_RESEARCH_AMOUNT 50
//Plasma fusion properties
#define FUSION_ENERGY_THRESHOLD 3e9 //Amount of energy it takes to start a fusion reaction
diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm
index ae5df258..8bfe6216 100644
--- a/code/__DEFINES/typeids.dm
+++ b/code/__DEFINES/typeids.dm
@@ -2,7 +2,7 @@
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
-#define GET_TYPEID(ref) ( ( (lentext(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, lentext(ref)-6) ) )
+#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 99cb6c54..812ced8d 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -514,7 +514,7 @@
used_key_list[input_key] = 1
return input_key
-#if DM_VERSION > 512
+#if DM_VERSION > 513
#error Remie said that lummox was adding a way to get a lists
#error contents via list.values, if that is true remove this
#error otherwise, update the version and bug lummox
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index ac17df57..b6b4efa0 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -58,6 +58,10 @@
if (CONFIG_GET(flag/log_game))
WRITE_LOG(GLOB.world_game_log, "GAME: [text]")
+/proc/log_cloning(text, mob/initiator)
+ if(CONFIG_GET(flag/log_cloning))
+ WRITE_LOG(GLOB.world_cloning_log, "CLONING: [text]")
+
/proc/log_access(text)
if (CONFIG_GET(flag/log_access))
WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]")
@@ -261,3 +265,4 @@
return "([AREACOORD(T)])"
else if(A.loc)
return "(UNKNOWN (?, ?, ?))"
+
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index 351411ce..402f0c76 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -305,9 +305,9 @@
//is in the other string at the same spot (assuming it is not a replace char).
//This is used for fingerprints
var/newtext = text
- if(lentext(text) != lentext(compare))
+ if(length(text) != length(compare))
return 0
- for(var/i = 1, i < lentext(text), i++)
+ for(var/i = 1, i < length(text), i++)
var/a = copytext(text,i,i+1)
var/b = copytext(compare,i,i+1)
//if it isn't both the same letter, or if they are both the replacement character
@@ -327,7 +327,7 @@
if(!text || !character)
return 0
var/count = 0
- for(var/i = 1, i <= lentext(text), i++)
+ for(var/i = 1, i <= length(text), i++)
var/a = copytext(text,i,i+1)
if(a == character)
count++
@@ -608,8 +608,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
continue
var/buffer = ""
var/early_culling = TRUE
- for(var/pos = 1, pos <= lentext(string), pos++)
- var/let = copytext(string, pos, (pos + 1) % lentext(string))
+ for(var/pos = 1, pos <= length(string), pos++)
+ var/let = copytext(string, pos, (pos + 1) % length(string))
if(early_culling && !findtext(let,GLOB.is_alphanumeric))
continue
early_culling = FALSE
@@ -617,9 +617,9 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
if(!findtext(buffer,GLOB.is_alphanumeric))
continue
var/punctbuffer = ""
- var/cutoff = lentext(buffer)
- for(var/pos = lentext(buffer), pos >= 0, pos--)
- var/let = copytext(buffer, pos, (pos + 1) % lentext(buffer))
+ var/cutoff = length(buffer)
+ for(var/pos = length(buffer), pos >= 0, pos--)
+ var/let = copytext(buffer, pos, (pos + 1) % length(buffer))
if(findtext(let,GLOB.is_alphanumeric))
break
if(findtext(let,GLOB.is_punctuation))
@@ -629,8 +629,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
var/exclaim = FALSE
var/question = FALSE
var/periods = 0
- for(var/pos = lentext(punctbuffer), pos >= 0, pos--)
- var/punct = copytext(punctbuffer, pos, (pos + 1) % lentext(punctbuffer))
+ for(var/pos = length(punctbuffer), pos >= 0, pos--)
+ var/punct = copytext(punctbuffer, pos, (pos + 1) % length(punctbuffer))
if(!exclaim && findtext(punct,"!"))
exclaim = TRUE
if(!question && findtext(punct,"?"))
@@ -652,7 +652,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
buffer = copytext(buffer, 1, cutoff) + punctbuffer
if(!findtext(buffer,GLOB.is_alphanumeric))
continue
- if(!buffer || lentext(buffer) > 280 || lentext(buffer) <= cullshort || buffer in accepted)
+ if(!buffer || length(buffer) > 280 || length(buffer) <= cullshort || buffer in accepted)
continue
accepted += buffer
diff --git a/code/__HELPERS/text_vr.dm b/code/__HELPERS/text_vr.dm
index 64e13ef6..9be806fc 100644
--- a/code/__HELPERS/text_vr.dm
+++ b/code/__HELPERS/text_vr.dm
@@ -9,8 +9,8 @@
return t
proc/TextPreview(var/string,var/len=40)
- if(lentext(string) <= len)
- if(!lentext(string))
+ if(length(string) <= len)
+ if(!length(string))
return "\[...\]"
else
return string
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 7e078184..1f8db38f 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -451,10 +451,15 @@ Turf and target are separate in case you want to teleport some distance from a t
var/y = min(world.maxy, max(1, A.y + dy))
return locate(x,y,A.z)
+#if DM_VERSION > 513
+#warn if you're getting this warning it means 513 is stable
+#warn and you should remove this tidbit
+#endif
+#if DM_VERSION < 513
/proc/arctan(x)
var/y=arcsin(x/sqrt(1+x*x))
return y
-
+#endif
/*
Gets all contents of contents and returns them all in a list.
*/
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index deffd25b..bf4ff55f 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -26,6 +26,8 @@ GLOBAL_VAR(query_debug_log)
GLOBAL_PROTECT(query_debug_log)
GLOBAL_VAR(world_job_debug_log)
GLOBAL_PROTECT(world_job_debug_log)
+GLOBAL_VAR(world_cloning_log)
+GLOBAL_PROTECT(world_cloning_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 1f6e4623..3f767433 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -39,6 +39,8 @@
/datum/config_entry/flag/log_game // log game events
+/datum/config_entry/flag/log_cloning // log cloning actions.
+
/datum/config_entry/flag/log_vote // log voting
/datum/config_entry/flag/log_whisper // log client whisper
@@ -76,6 +78,16 @@
config_entry_value = 600
min_val = 0
+/datum/config_entry/number/vote_autotransfer_initial //length of time before the first autotransfer vote is called (deciseconds, default 2 hours)
+ config_entry_value = 72000
+ integer = FALSE
+ min_val = 0
+
+/datum/config_entry/number/vote_autotransfer_interval //length of time to wait before subsequent autotransfer votes (deciseconds, default 30 minutes)
+ config_entry_value = 18000
+ integer = FALSE
+ min_val = 0
+
/datum/config_entry/flag/default_no_vote // vote does not default to nochange/norestart
/datum/config_entry/flag/no_dead_vote // dead people can't vote
@@ -419,3 +431,4 @@
/datum/config_entry/flag/log_pictures
/datum/config_entry/flag/picture_logging_camera
+
diff --git a/code/controllers/subsystem/autotransfer.dm b/code/controllers/subsystem/autotransfer.dm
new file mode 100644
index 00000000..d6ae7140
--- /dev/null
+++ b/code/controllers/subsystem/autotransfer.dm
@@ -0,0 +1,17 @@
+SUBSYSTEM_DEF(autotransfer)
+ name = "Autotransfer Vote"
+ flags = SS_KEEP_TIMING | SS_BACKGROUND
+ wait = 1 MINUTES
+
+ var/starttime
+ var/targettime
+
+/datum/controller/subsystem/autotransfer/Initialize(timeofday)
+ starttime = world.time
+ targettime = starttime + CONFIG_GET(number/vote_autotransfer_initial)
+ return ..()
+
+/datum/controller/subsystem/autotransfer/fire()
+ if (world.time > targettime)
+ SSvote.initiate_vote("transfer",null) //TODO figure out how to not use null as the user
+ targettime = targettime + CONFIG_GET(number/vote_autotransfer_interval)
\ No newline at end of file
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index f2469e8f..dffb0439 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -205,8 +205,6 @@ SUBSYSTEM_DEF(ticker)
mode.process(wait * 0.1)
check_queue()
check_maprotate()
- scripture_states = scripture_unlock_alert(scripture_states)
- SSshuttle.autoEnd()
if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending)
current_state = GAME_STATE_FINISHED
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 79bc9dbe..f5c91f14 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -76,6 +76,21 @@ SUBSYSTEM_DEF(vote)
choices[GLOB.master_mode] += non_voters.len
if(choices[GLOB.master_mode] >= greatest_votes)
greatest_votes = choices[GLOB.master_mode]
+ else if(mode == "transfer") // austation begin -- Crew autotransfer vote
+ var/factor = 1
+ switch(world.time / (1 MINUTES ))
+ if(0 to 60)
+ factor = 0.5
+ if(61 to 120)
+ factor = 0.8
+ if(121 to 240)
+ factor = 1
+ if(241 to 300)
+ factor = 1.2
+ else
+ factor = 1.4
+ choices["Initiate Crew Transfer"] += round(non_voters.len * factor) // austation end
+
//get all options with that many votes and return them in a list
. = list()
if(greatest_votes)
@@ -152,6 +167,13 @@ SUBSYSTEM_DEF(vote)
log_admin("The map has been voted for and will change to: [VM.map_name]")
if(SSmapping.changemap(config.maplist[.]))
to_chat(world, "The map vote has chosen [VM.map_name] for next round!")
+ if("transfer") // austation begin -- Crew autotransfer vote
+ if(. == "Initiate Crew Transfer")
+ //TODO find a cleaner way to do this
+ SSshuttle.requestEvac(null,"Crew transfer requested.")
+ var/obj/machinery/computer/communications/C = locate() in GLOB.machines
+ if(C)
+ C.post_status("shuttle") // austation end
if(restart)
var/active_admins = 0
for(var/client/C in GLOB.admins)
@@ -200,6 +222,7 @@ SUBSYSTEM_DEF(vote)
to_chat(usr, "A vote was initiated recently, you must wait [DisplayTimeText(next_allowed_time-world.time)] before a new vote can be started!")
return 0
+ SEND_SOUND(world, sound('sound/misc/notice2.ogg'))
reset()
obfuscated = hideresults //CIT CHANGE - adds obfuscated votes
switch(vote_type)
@@ -211,6 +234,8 @@ SUBSYSTEM_DEF(vote)
choices.Add(config.maplist)
for(var/i in choices)//this is necessary because otherwise we'll end up with a bunch of /datum/map_config's as the default vote value instead of 0 as intended
choices[i] = 0
+ if("transfer") // austation begin -- Crew autotranfer vote
+ choices.Add("Initiate Crew Transfer","Continue Playing") // austation end
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
choices.Add("secret", "extended")
if("custom")
@@ -225,7 +250,7 @@ SUBSYSTEM_DEF(vote)
else
return 0
mode = vote_type
- initiator = initiator_key
+ initiator = initiator_key ? initiator_key : "the Server" // austation -- Crew autotransfer vote
started_time = world.time
var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == "custom")
diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm
index 838a1b57..f0333072 100644
--- a/code/datums/components/caltrop.dm
+++ b/code/datums/components/caltrop.dm
@@ -37,9 +37,9 @@
if(O.status == BODYPART_ROBOTIC)
return
- var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
+ var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
- if(!(flags & CALTROP_BYPASS_SHOES) && (H.shoes || feetCover))
+ if(!(flags & CALTROP_BYPASS_SHOES) && feetCover)
return
if((H.movement_type & FLYING) || H.buckled)
diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm
index fd25f972..c4bf893c 100644
--- a/code/datums/components/footstep.dm
+++ b/code/datums/components/footstep.dm
@@ -89,19 +89,19 @@
return
if(ishuman(LM)) //for proper humans, they're special
var/mob/living/carbon/human/H = LM
- var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
+ var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
return
- if(H.shoes || feetCover) //are we wearing shoes
+ if(feetCover) //are we wearing shoes
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
- if((!H.shoes && !feetCover)) //are we NOT wearing shoes
+ if(!feetCover) //are we NOT wearing shoes
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index e6f33680..466a5406 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -371,7 +371,7 @@
updateappearance(icon_update=0)
if(LAZYLEN(mutation_index))
- dna.mutation_index = mutation_index
+ dna.mutation_index = mutation_index.Copy()
domutcheck()
if(mrace || newfeatures || ui)
@@ -616,4 +616,4 @@
else
gib()
else
- set_species(/datum/species/dullahan)
\ No newline at end of file
+ set_species(/datum/species/dullahan)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index f633b5cf..5dd0b34d 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -62,6 +62,9 @@
var/unconvertable = FALSE
var/late_joiner = FALSE
+ var/last_death = 0
+
+
var/force_escaped = FALSE // Set by Into The Sunset command of the shuttle manipulator
var/list/learned_recipes //List of learned recipe TYPES.
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 9e8756bb..78953609 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -598,6 +598,14 @@
/atom/proc/multitool_act(mob/living/user, obj/item/I)
return
+///Check if the multitool has an item in it's data buffer
+/atom/proc/multitool_check_buffer(user, obj/item/I, silent = FALSE)
+ if(!istype(I, /obj/item/multitool))
+ if(user && !silent)
+ to_chat(user, "[I] has no data buffer!")
+ return FALSE
+ return TRUE
+
/atom/proc/screwdriver_act(mob/living/user, obj/item/I)
SEND_SIGNAL(src, COMSIG_ATOM_SCREWDRIVER_ACT, user, I)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 5b7eff2b..a70c1068 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -19,7 +19,7 @@
circuit = /obj/item/circuitboard/machine/clonepod
var/heal_level //The clone is released once its health reaches this level.
- var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine.
+ var/obj/machinery/computer/cloning/connected //So we remember the connected clone machine.
var/mess = FALSE //Need to clean out it if it's full of exploded clone.
var/attempting = FALSE //One clone attempt at a time thanks
var/speed_coeff
@@ -53,7 +53,10 @@
update_icon()
/obj/machinery/clonepod/Destroy()
+ var/mob/living/mob_occupant = occupant
go_out()
+ if(mob_occupant)
+ log_cloning("[key_name(mob_occupant)] ejected from [src] at [AREACOORD(src)] due to Destroy().")
QDEL_NULL(radio)
QDEL_NULL(countdown)
if(connected)
@@ -74,6 +77,23 @@
if(heal_level > 100)
heal_level = 100
+/obj/machinery/clonepod/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ user.examinate(src)
+
+/obj/machinery/clonepod/attack_ai(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/clonepod/examine(mob/user)
+ . = ..()
+ . += "The linking device can be scanned with a multitool."
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Cloning speed at [speed_coeff*50]%.
Predicted amount of cellular damage: [100-heal_level]%."
+ if(efficiency > 5)
+ . += "Pod has been upgraded to support autoprocessing and apply beneficial mutations."
+
//The return of data disks?? Just for transferring between genetics machine/cloning machine.
//TO-DO: Make the genetics machine accept them.
/obj/item/disk/data
@@ -102,7 +122,7 @@
//Clonepod
/obj/machinery/clonepod/examine(mob/user)
- ..()
+ . = ..()
var/mob/living/mob_occupant = occupant
if(mess)
to_chat(user, "It's filled with blood and viscera. You swear you can see it moving...")
@@ -129,44 +149,54 @@
return examine(user)
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, datum/species/mrace, list/features, factions, list/quirks)
+/obj/machinery/clonepod/proc/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks, empty)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
- clonemind = locate(mindref) in SSticker.minds
- if(!istype(clonemind)) //not a mind
- return FALSE
- if(!QDELETED(clonemind.current))
- if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
+
+ if(!empty) //Doesn't matter if we're just making a copy
+ clonemind = locate(mindref) in SSticker.minds
+ if(!istype(clonemind)) //not a mind
return FALSE
- if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
+ if(clonemind.last_death != last_death) //The soul has advanced, the record has not.
return FALSE
- if(clonemind.active) //somebody is using that mind
- if( ckey(clonemind.key)!=ckey )
+ if(!QDELETED(clonemind.current))
+ if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
+ return NONE
+ if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
+ return NONE
+ if(!clonemind.active)
+ // get_ghost() will fail if they're unable to reenter their body
+ var/mob/dead/observer/G = clonemind.get_ghost()
+ if(!G)
+ return NONE
+ if(G.suiciding) // The ghost came from a body that is suiciding.
+ return NONE
+ if(clonemind.damnation_type) //Can't clone the damned.
+ INVOKE_ASYNC(src, .proc/horrifyingsound)
+ mess = TRUE
+ icon_state = "pod_g"
+ update_icon()
return FALSE
- else
- // get_ghost() will fail if they're unable to reenter their body
- var/mob/dead/observer/G = clonemind.get_ghost()
- if(!G)
- return FALSE
- if(G.suiciding) // The ghost came from a body that is suiciding.
- return FALSE
- if(clonemind.damnation_type) //Can't clone the damned.
- INVOKE_ASYNC(src, .proc/horrifyingsound)
- mess = TRUE
- update_icon()
- return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
- H.hardset_dna(ui, mutation_index, H.real_name, null, mrace, features)
+ H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
- if(prob(50 - efficiency*10)) //Chance to give a bad mutation.
- H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) //100% bad mutation. Can be cured with mutadone.
+ if(!HAS_TRAIT(H, TRAIT_RADIMMUNE))//dont apply mutations if the species is Mutation proof.
+ if(efficiency > 2)
+ var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
+ H.dna.remove_mutation_group(unclean_mutations)
+ if(efficiency > 5 && prob(20))
+ H.easy_randmut(POSITIVE)
+ if(efficiency < 3 && prob(50))
+ var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
+ if(ismob(M))
+ H = M
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
occupant = H
@@ -184,15 +214,16 @@
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
- clonemind.transfer_to(H)
+ if(!empty)
+ clonemind.transfer_to(H)
- if(grab_ghost_when == CLONER_FRESH_CLONE)
- H.grab_ghost()
- to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
+ if(grab_ghost_when == CLONER_FRESH_CLONE)
+ H.grab_ghost()
+ to_chat(H, "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?")
- if(grab_ghost_when == CLONER_MATURE_CLONE)
- H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
- to_chat(H.get_ghost(TRUE), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.")
+ if(grab_ghost_when == CLONER_MATURE_CLONE)
+ H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
+ to_chat(H.get_ghost(TRUE), "Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.")
if(H)
H.faction |= factions
@@ -206,7 +237,7 @@
H.suiciding = FALSE
attempting = FALSE
- return TRUE
+ return CLONING_SUCCESS
//Grow clones to maturity then kick them out. FREELOADERS
/obj/machinery/clonepod/process()
@@ -215,16 +246,20 @@
if(!is_operational()) //Autoeject if power is lost
if(mob_occupant)
go_out()
+ log_cloning("[key_name(mob_occupant)] ejected from [src] at [AREACOORD(src)] due to power loss.")
+
mob_occupant.apply_vore_prefs()
+
connected_message("Clone Ejected: Loss of power.")
else if(mob_occupant && (mob_occupant.loc == src))
- if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
+ if(mob_occupant && (mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
connected_message("Clone Rejected: Deceased.")
if(internal_radio)
SPEAK("The cloning has been \
aborted due to unrecoverable tissue failure.")
go_out()
+ log_cloning("[key_name(mob_occupant)] ejected from [src] at [AREACOORD(src)] after suiciding.")
mob_occupant.apply_vore_prefs()
else if(mob_occupant.cloneloss > (100 - heal_level))
@@ -272,10 +307,13 @@
BP.attach_limb(mob_occupant)
go_out()
+ log_cloning("[key_name(mob_occupant)] completed cloning cycle in [src] at [AREACOORD(src)].")
mob_occupant.apply_vore_prefs()
else if (!mob_occupant || mob_occupant.loc != src)
occupant = null
+ if (!mess && !panel_open)
+ icon_state = "pod_0"
use_power(200)
update_icon()
@@ -290,6 +328,8 @@
return
if(istype(W, /obj/item/multitool))
+ if(!multitool_check_buffer(user, W))
+ return
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/computer/cloning))
@@ -316,10 +356,13 @@
to_chat(user, "Error: Pod has no occupant.")
return
else
+ add_fingerprint(user)
connected_message("Emergency Ejection")
SPEAK("An emergency ejection of the current clone has occurred. Survival not guaranteed.")
to_chat(user, "You force an emergency ejection. ")
go_out()
+ log_cloning("[key_name(user)] manually ejected [key_name(mob_occupant)] from [src] at [AREACOORD(src)].")
+ log_combat(user, mob_occupant, "ejected", W, "from [src]")
mob_occupant.apply_vore_prefs()
else
return ..()
@@ -329,6 +372,9 @@
return
to_chat(user, "You corrupt the genetic compiler.")
malfunction()
+ add_fingerprint(user)
+ log_cloning("[key_name(user)] emagged [src] at [AREACOORD(src)], causing it to malfunction.")
+ log_combat(user, src, "emagged", null, occupant ? "[occupant] inside, killing them via malfunction." : null)
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(message)
@@ -381,6 +427,7 @@
unattached_flesh.Cut()
occupant = null
+ clonemind = null
/obj/machinery/clonepod/proc/malfunction()
var/mob/living/mob_occupant = occupant
@@ -391,13 +438,14 @@
mess = TRUE
maim_clone(mob_occupant) //Remove every bit that's grown back so far to drop later, also destroys bits that haven't grown yet
update_icon()
- if(mob_occupant.mind != clonemind)
+ if(clonemind && mob_occupant.mind != clonemind)
clonemind.transfer_to(mob_occupant)
mob_occupant.grab_ghost() // We really just want to make you suffer.
flash_color(mob_occupant, flash_color="#960000", flash_time=100)
to_chat(mob_occupant, "Agony blazes across your consciousness as your body is torn apart.
Is this what dying is like? Yes it is.")
playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
SEND_SOUND(mob_occupant, sound('sound/hallucinations/veryfar_noise.ogg',0,1,50))
+ log_cloning("[key_name(mob_occupant)] destroyed within [src] at [AREACOORD(src)] due to malfunction.")
QDEL_IN(mob_occupant, 40)
/obj/machinery/clonepod/relaymove(mob/user)
@@ -416,11 +464,14 @@
SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of, ERROR: John Doe, prematurely." ,0))
mob_occupant.apply_vore_prefs()
go_out()
+ log_cloning("[key_name(mob_occupant)] ejected from [src] at [AREACOORD(src)] due to EMP pulse.")
/obj/machinery/clonepod/ex_act(severity, target)
..()
- if(!QDELETED(src))
+ if(!QDELETED(src) && occupant)
+ var/mob/living/mob_occupant = occupant
go_out()
+ log_cloning("[key_name(mob_occupant)] ejected from [src] at [AREACOORD(src)] due to explosion.")
/obj/machinery/clonepod/handle_atom_del(atom/A)
if(A == occupant)
@@ -436,7 +487,9 @@
/obj/machinery/clonepod/deconstruct(disassembled = TRUE)
if(occupant)
+ var/mob/living/mob_occupant = occupant
go_out()
+ log_cloning("[key_name(mob_occupant)] ejected from [src] at [AREACOORD(src)] due to deconstruction.")
..()
/obj/machinery/clonepod/proc/maim_clone(mob/living/carbon/human/H)
@@ -552,3 +605,4 @@
#undef CLONE_INITIAL_DAMAGE
#undef SPEAK
#undef MINIMUM_HEAL_LEVEL
+
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 43582e39..ad563635 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -31,6 +31,7 @@
/obj/machinery/computer/camera_advanced/syndie
icon_keyboard = "syndie_key"
+ circuit = /obj/item/circuitboard/computer/advanced_camera
/obj/machinery/computer/camera_advanced/proc/CreateEye()
eyeobj = new()
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index eceb6042..dede5724 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -7,25 +7,24 @@
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
- var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
+ var/obj/machinery/dna_scannernew/scanner //Linked scanner. For scanning.
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
var/scantemp = "Ready to Scan"
var/menu = 1 //Which menu screen to display
+ var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
+
var/loading = 0 // Nice loading text
var/autoprocess = 0
- var/list/records = list()
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/cloning/Initialize()
. = ..()
updatemodules(TRUE)
- var/obj/item/circuitboard/computer/cloning/board = circuit
- records = board.records
/obj/machinery/computer/cloning/Destroy()
@@ -39,7 +38,7 @@
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
- if(pod.occupant && pod.clonemind == mind)
+ if(pod.occupant && mind && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
@@ -60,6 +59,9 @@
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
+/proc/grow_clone_from_record(obj/machinery/clonepod/pod, datum/data/record/R, empty)
+ return pod.growclone(R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mindref"], R.fields["last_death"], R.fields["blood_type"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], empty)
+
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
@@ -68,16 +70,19 @@
scan_occupant(scanner.occupant)
for(var/datum/data/record/R in records)
- var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"])
+ var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mindref"])
if(!pod)
return
if(pod.occupant)
- continue //how though?
+ continue
- if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"]))
+ var/result = grow_clone_from_record(pod, R)
+ if(result & CLONING_SUCCESS)
temp = "[R.fields["name"]] => Cloning cycle in progress..."
+ log_cloning("Cloning of [key_name(R.fields["mindref"])] automatically started via autoprocess - [src] at [AREACOORD(src)]. Pod: [pod] at [AREACOORD(pod)].")
+ if(result & CLONING_DELETE_RECORD)
records -= R
/obj/machinery/computer/cloning/proc/updatemodules(findfirstcloner)
@@ -132,7 +137,9 @@
to_chat(user, "You insert [W].")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
src.updateUsrDialog()
- else if(istype(W, /obj/item/multitool))
+ else if(W.tool_behaviour == TOOL_MULTITOOL)
+ if(!multitool_check_buffer(user, W))
+ return
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
@@ -201,6 +208,7 @@
if(scanner_occupant)
dat += "Start Scan"
+ dat += "Body-Only Scan"
dat += "
[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]"
else
dat += "Start Scan"
@@ -228,8 +236,11 @@
if (!src.active_record)
dat += "Record not found."
else
- dat += "
[src.active_record.fields["name"]]
"
- dat += "Scan ID [src.active_record.fields["id"]] Clone
"
+ var/body_only = active_record.fields["body_only"]
+ dat += "[active_record.fields["name"]][body_only ? " - BODY-ONLY" : ""]
"
+ dat += "Scan ID [active_record.fields["id"]] \
+ [!body_only ? "Clone" : "" ]\
+ Empty Clone
"
var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
@@ -239,7 +250,14 @@
dat += "Unable to locate Health Implant.
"
dat += "Unique Identifier:
[src.active_record.fields["UI"]]
"
- dat += "Structural Enzymes:
[src.active_record.fields["SE"]]
"
+ dat += "Structural Enzymes:
"
+ for(var/key in active_record.fields["SE"])
+ if(key != RACEMUT)
+ var/val = active_record.fields["SE"][key]
+ var/alias = GLOB.all_mutations[key].alias
+ dat +="[alias]: [val]
"
+
+ dat += "
"
if(diskette && diskette.fields)
dat += ""
@@ -296,18 +314,13 @@
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
-
+ var/body_only = href_list["body_only"]
loading = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
- spawn(20)
- src.scan_occupant(scanner.occupant)
-
- loading = 0
- src.updateUsrDialog()
- playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
+ addtimer(CALLBACK(src, .proc/do_scan, usr, body_only), 2 SECONDS)
//No locking an open scanner.
@@ -323,34 +336,42 @@
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
- if(!active_record.fields["ckey"])
- records -= active_record
- active_record = null
- src.temp = "
Record Corrupt"
- else
- src.menu = 3
+ menu = 3
else
- src.temp = "Record missing."
+ temp = "Record missing."
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
- src.temp = "Delete record?"
- src.menu = 4
- playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
+ var/has_access = FALSE
+ if(ishuman(usr))
+ var/mob/living/carbon/human/user = usr
+ var/obj/item/card/id/C = user.get_idcard(TRUE)
+ if(C)
+ if(check_access(C))
+ has_access = TRUE
+ if(active_record.fields["body_only"]) //Body-only scans are not as important and can be deleted freely
+ has_access = TRUE
+ if(has_access)
+ temp = "Delete record?"
+ menu = 4
+ playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
+ else
+ temp = "Access Denied"
+ menu = 2
+ playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (src.menu == 4)
var/obj/item/card/id/C = usr.get_active_held_item()
if (istype(C)||istype(C, /obj/item/pda))
if(src.check_access(C))
+ log_cloning("[key_name(usr)] deleted [key_name(active_record.fields["mindref"])]'s cloning records from [src] at [AREACOORD(src)].")
src.temp = "[src.active_record.fields["name"]] => Record deleted."
src.records.Remove(active_record)
active_record = null
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.menu = 2
- var/obj/item/circuitboard/computer/cloning/board = circuit
- board.records = records
else
src.temp = "
Access Denied."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
@@ -400,9 +421,14 @@
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
+ var/empty = href_list["empty"]
//Look for that player! They better be dead!
if(C)
+ if(C.fields["body_only"] && !empty)
+ temp = "
Cannot initiate regular cloning with body-only scans."
+ playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
var/obj/machinery/clonepod/pod = GetAvailablePod()
+ var/success = FALSE
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "
No Clonepods detected."
@@ -410,20 +436,33 @@
else if(!pod)
temp = "
No Clonepods available."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
- else if(!CONFIG_GET(flag/revival_cloning))
+ else if(!CONFIG_GET(flag/revival_cloning) && !empty)
temp = "
Unable to initiate cloning cycle."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "
Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
- else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"]))
- temp = "[C.fields["name"]] =>
Cloning cycle in progress..."
- playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
- records.Remove(C)
- if(active_record == C)
- active_record = null
- menu = 1
else
+ var/result = grow_clone_from_record(pod, C, empty)
+ if(result & CLONING_SUCCESS)
+ temp = "[C.fields["name"]] =>
Cloning cycle in progress..."
+ playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
+ records.Remove(C)
+ if(active_record == C)
+ active_record = null
+ menu = 1
+ success = TRUE
+ if(!empty)
+ log_cloning("[key_name(usr)] initiated cloning of [key_name(C.fields["mindref"])] via [src] at [AREACOORD(src)]. Pod: [pod] at [AREACOORD(pod)].")
+ else
+ log_cloning("[key_name(usr)] initiated EMPTY cloning of [key_name(C.fields["mindref"])] via [src] at [AREACOORD(src)]. Pod: [pod] at [AREACOORD(pod)].")
+ if(result & CLONING_DELETE_RECORD)
+ if(active_record == C)
+ active_record = null
+ menu = 1
+ records -= C
+
+ if(!success)
temp = "[C.fields["name"]] =>
Initialisation failure."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
@@ -439,21 +478,31 @@
src.updateUsrDialog()
return
-/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
+/obj/machinery/computer/cloning/proc/do_scan(mob/user, body_only)
+ scan_occupant(scanner.occupant, user, body_only)
+
+ loading = FALSE
+ updateUsrDialog()
+ playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
+
+/obj/machinery/computer/cloning/proc/scan_occupant(occupant, mob/M, body_only)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
+
+ // Do not use unless you know what they are.
+ var/mob/living/carbon/C = mob_occupant
+ var/mob/living/brain/B = mob_occupant
+
if(ishuman(mob_occupant))
- var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
- var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "
Unable to locate valid genetic data."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
- if(mob_occupant.suiciding || mob_occupant.hellbound)
+ if(!body_only && (mob_occupant.suiciding || mob_occupant.hellbound))
scantemp = "
Subject's brain is not responding to scanning stimuli."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
@@ -461,14 +510,14 @@
scantemp = "
Subject no longer contains the fundamental materials required to create a living clone."
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
- if ((!mob_occupant.ckey) || (!mob_occupant.client))
+ if (!body_only && isnull(mob_occupant.mind))
scantemp = "
Mental interface failure."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
- if (find_record("ckey", mob_occupant.ckey, records))
- scantemp = "
Subject already in database."
- playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
- return
+// if (find_record("ckey", mob_occupant.ckey, records))
+// scantemp = "
Subject already in database."
+// playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
+// return
var/datum/data/record/R = new()
if(dna.species)
@@ -481,7 +530,7 @@
var/datum/species/rando_race = pick(GLOB.roundstart_races)
R.fields["mrace"] = rando_race.type
- R.fields["ckey"] = mob_occupant.ckey
+ //R.fields["ckey"] = mob_occupant.ckey
R.fields["name"] = mob_occupant.real_name
R.fields["id"] = copytext(md5(mob_occupant.real_name), 2, 6)
R.fields["UE"] = dna.unique_enzymes
@@ -495,21 +544,32 @@
var/datum/quirk/T = V
R.fields["quirks"][T.type] = T.clone_data()
- if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
- R.fields["mind"] = "[REF(mob_occupant.mind)]"
+ R.fields["mindref"] = "[REF(mob_occupant.mind)]"
+ R.fields["last_death"] = mob_occupant.stat == DEAD ? mob_occupant.mind.last_death : -1
+ R.fields["body_only"] = body_only
- //Add an implant if needed
- var/obj/item/implant/health/imp
- for(var/obj/item/implant/health/HI in mob_occupant.implants)
- imp = HI
- break
- if(!imp)
- imp = new /obj/item/implant/health(mob_occupant)
- imp.implant(mob_occupant)
- R.fields["imp"] = "[REF(imp)]"
+ if(!body_only)
+ //Add an implant if needed
+ var/obj/item/implant/health/imp
+ for(var/obj/item/implant/health/HI in mob_occupant.implants)
+ imp = HI
+ break
+ if(!imp)
+ imp = new /obj/item/implant/health(mob_occupant)
+ imp.implant(mob_occupant)
+ R.fields["imp"] = "[REF(imp)]"
+ var/datum/data/record/old_record = find_record("mindref", REF(mob_occupant.mind), records)
+ if(body_only)
+ old_record = find_record("UE", dna.unique_enzymes, records) //Body-only records cannot be identified by mind, so we use the DNA
+ if(old_record && ((old_record.fields["UI"] != dna.uni_identity) || (!old_record.fields["body_only"]))) //Never overwrite a mind-and-body record if it exists
+ old_record = null
+ if(old_record)
+ records -= old_record
+ scantemp = "Record updated."
+ else
+ scantemp = "Subject successfully scanned."
src.records += R
- var/obj/item/circuitboard/computer/cloning/board = circuit
- board.records = records
- scantemp = "Subject successfully scanned."
+ log_cloning("[M ? key_name(M) : "Autoprocess"] added the [body_only ? "body-only " : ""]record of [key_name(mob_occupant)] to [src] at [AREACOORD(src)].")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
+
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 23c8bd35..20fc831c 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -332,6 +332,7 @@
C.bleed(DOOR_CRUSH_DAMAGE)
else
L.add_splatter_floor(location)
+
for(var/obj/mecha/M in get_turf(src))
M.take_damage(DOOR_CRUSH_DAMAGE)
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
index ffe66e68..d5388035 100644
--- a/code/game/machinery/exp_cloner.dm
+++ b/code/game/machinery/exp_cloner.dm
@@ -9,7 +9,7 @@
internal_radio = FALSE
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/experimental/growclone(ckey, clonename, ui, se, datum/species/mrace, list/features, factions)
+/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance)
if(panel_open)
return FALSE
if(mess || attempting)
@@ -20,7 +20,7 @@
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
- H.hardset_dna(ui, se, H.real_name, null, mrace, features)
+ H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
if(efficiency > 2)
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
@@ -292,6 +292,7 @@
temp = "
Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
- pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, clone_species, dna.features, mob_occupant.faction)
+ pod.growclone(mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] =>
Cloning data sent to pod."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
+
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index c37c607a..6bf9930e 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -515,7 +515,7 @@ GLOBAL_LIST_EMPTY(allCasters)
if(href_list["set_channel_name"])
channel_name = stripped_input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "", MAX_NAME_LEN)
while (findtext(channel_name," ") == 1)
- channel_name = copytext(channel_name,2,lentext(channel_name)+1)
+ channel_name = copytext(channel_name,2,length(channel_name)+1)
updateUsrDialog()
else if(href_list["set_channel_lock"])
c_locked = !c_locked
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index 877e320a..675c8bce 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -243,7 +243,7 @@
else
line1 = "CARGO"
line2 = SSshuttle.supply.getTimerStr()
- if(lentext(line2) > CHARS_PER_LINE)
+ if(length(line2) > CHARS_PER_LINE)
line2 = "Error"
update_display(line1, line2)
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index 9ffd40b1..a2222fa2 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -461,3 +461,56 @@
//NC.mergeConnectedNetworksOnTurf()
last_piece = NC
return 1
+
+//Dunno where else to put this so shrug
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade
+ name = "Ripley MK-II Conversion Kit"
+ desc = "A pressurized canopy attachment kit for an Autonomous Power Loader Unit \"Ripley\" MK-I mecha, to convert it to the slower, but space-worthy MK-II design. This kit cannot be removed, once applied."
+ icon_state = "ripleyupgrade"
+
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/can_attach(obj/mecha/working/ripley/M)
+ if(M.type != /obj/mecha/working/ripley)
+ to_chat(loc, "
This conversion kit can only be applied to APLU MK-I models.")
+ return FALSE
+ if(M.cargo.len)
+ to_chat(loc, "
[M]'s cargo hold must be empty before this conversion kit can be applied.")
+ return FALSE
+ if(!M.maint_access) //non-removable upgrade, so lets make sure the pilot or owner has their say.
+ to_chat(loc, "
[M] must have maintenance protocols active in order to allow this conversion kit.")
+ return FALSE
+ if(M.occupant) //We're actualy making a new mech and swapping things over, it might get weird if players are involved
+ to_chat(loc, "
[M] must be unoccupied before this conversion kit can be applied.")
+ return FALSE
+ if(!M.cell) //Turns out things break if the cell is missing
+ to_chat(loc, "
The conversion process requires a cell installed.")
+ return FALSE
+ return TRUE
+
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade/attach(obj/mecha/M)
+ var/obj/mecha/working/ripley/mkii/N = new /obj/mecha/working/ripley/mkii(get_turf(M),1)
+ if(!N)
+ return
+ QDEL_NULL(N.cell)
+ if (M.cell)
+ N.cell = M.cell
+ M.cell.forceMove(N)
+ M.cell = null
+ N.step_energy_drain = M.step_energy_drain //For the scanning module
+ N.armor = N.armor.setRating(energy = M.armor["energy"]) //for the capacitor
+ for(var/obj/item/mecha_parts/E in M.contents)
+// if(istype(E, /obj/item/mecha_parts/concealed_weapon_bay)) //why is the bay not just a variable change who did this
+// E.forceMove(N)
+ for(var/obj/item/mecha_parts/mecha_equipment/E in M.equipment) //Move the equipment over...
+ E.detach()
+ E.attach(N)
+ M.equipment -= E
+ N.dna_lock = M.dna_lock
+ N.maint_access = M.maint_access
+ N.strafe = M.strafe
+ N.obj_integrity = M.obj_integrity //This is not a repair tool
+ if (M.name != "\improper APLU MK-I \"Ripley\"")
+ N.name = M.name
+ M.wreckage = 0
+ qdel(M)
+ playsound(get_turf(N),'sound/items/ratchet.ogg',50,1)
+ return
\ No newline at end of file
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 9fd16a57..46beb3a6 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -18,7 +18,9 @@
var/list/queue = list()
var/processing_queue = 0
var/screen = "main"
+ var/link_on_init = TRUE
var/temp
+ var/datum/component/remote_materials/rmat
var/list/part_sets = list(
"Cyborg",
"Ripley",
@@ -33,13 +35,11 @@
"Misc"
)
-/obj/machinery/mecha_part_fabricator/Initialize()
- var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
- list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE), 0,
- TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
- materials.precise_insertion = TRUE
- stored_research = new
- return ..()
+/obj/machinery/mecha_part_fabricator/Initialize(mapload)
+ stored_research = new
+ rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init)
+ RefreshParts() //Recalculating local material sizes if the fab isn't linked
+ return ..()
/obj/machinery/mecha_part_fabricator/RefreshParts()
var/T = 0
@@ -47,8 +47,7 @@
//maximum stocking amount (default 300000, 600000 at T4)
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
T += M.rating
- GET_COMPONENT(materials, /datum/component/material_container)
- materials.max_amount = (200000 + (T*50000))
+ rmat.set_local_size((200000 + (T*50000)))
//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
T = 1.15
@@ -62,6 +61,12 @@
T += Ml.rating
time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01)
+/obj/machinery/mecha_part_fabricator/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "
The status display reads: Storing up to [rmat.local_size] material units.
Material consumption at [component_coeff*100]%.
Build time reduced by [100-time_coeff*100]%."
+
+
/obj/machinery/mecha_part_fabricator/emag_act()
if(obj_flags & EMAGGED)
@@ -104,16 +109,22 @@
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
var/output
- GET_COMPONENT(materials, /datum/component/material_container)
- for(var/mat_id in materials.materials)
- var/datum/material/M = materials.materials[mat_id]
- output += "[M.name]: [M.amount] cm³"
- if(M.amount >= MINERAL_MATERIAL_AMOUNT)
- output += "- Remove \[1\]"
- if(M.amount >= (MINERAL_MATERIAL_AMOUNT * 10))
- output += " | \[10\]"
- output += " | \[All\]"
- output += "
"
+ var/datum/component/material_container/materials = rmat.mat_container
+
+ if(materials)
+ for(var/mat_id in materials.materials)
+ var/datum/material/M = mat_id
+ var/amount = materials.materials[mat_id]
+ var/ref = REF(M)
+ output += "[M.name]: [amount] cm³"
+ if(amount >= MINERAL_MATERIAL_AMOUNT)
+ output += "- Remove \[1\]"
+ if(amount >= (MINERAL_MATERIAL_AMOUNT * 10))
+ output += " | \[10\]"
+ output += " | \[50\]"
+ output += "
"
+ else
+ output += "No material storage connected, please contact the quartermaster.
"
return output
/obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D)
@@ -125,18 +136,29 @@
/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D)
if(D.reagents_list.len) // No reagents storage - no reagent designs.
return FALSE
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = rmat.mat_container
if(materials.has_materials(get_resources_w_coeff(D)))
return TRUE
return FALSE
/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D)
- being_built = D
- desc = "It's building \a [initial(D.name)]."
var/list/res_coef = get_resources_w_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = rmat.mat_container
+ if (!materials)
+ say("No access to material storage, please contact the quartermaster.")
+ return FALSE
+ if (rmat.on_hold())
+ say("Mineral access is on hold, please contact the quartermaster.")
+ return FALSE
+ if(!check_resources(D))
+ say("Not enough resources. Queue processing stopped.")
+ return FALSE
+ being_built = D
+ desc = "It's building \a [initial(D.name)]."
materials.use_amount(res_coef)
+ rmat.silo_log(src, "built", -1, "[D.name]", res_coef)
+
add_overlay("fab-active")
use_power = ACTIVE_POWER_USE
updateUsrDialog()
@@ -191,13 +213,10 @@
while(D)
if(stat&(NOPOWER|BROKEN))
return FALSE
- if(!check_resources(D))
- say("Not enough resources. Queue processing stopped.")
- temp = {"Not enough resources to build next part.
- Try again | Return"}
+ if(build_part(D))
+ remove_from_queue(1)
+ else
return FALSE
- remove_from_queue(1)
- build_part(D)
D = listgetindex(queue, 1)
say("Queue processing finished successfully.")
@@ -379,16 +398,32 @@
break
if(href_list["remove_mat"] && href_list["material"])
- GET_COMPONENT(materials, /datum/component/material_container)
- materials.retrieve_sheets(text2num(href_list["remove_mat"]), href_list["material"])
+ var/datum/material/Mat = locate(href_list["material"])
+ eject_sheets(Mat, text2num(href_list["remove_mat"]))
updateUsrDialog()
return
-/obj/machinery/mecha_part_fabricator/on_deconstruction()
- GET_COMPONENT(materials, /datum/component/material_container)
- materials.retrieve_all()
- ..()
+/obj/machinery/mecha_part_fabricator/proc/do_process_queue()
+ if(processing_queue || being_built)
+ return FALSE
+ processing_queue = 1
+ process_queue()
+ processing_queue = 0
+
+/obj/machinery/mecha_part_fabricator/proc/eject_sheets(eject_sheet, eject_amt)
+ var/datum/component/material_container/mat_container = rmat.mat_container
+ if (!mat_container)
+ say("No access to material storage, please contact the quartermaster.")
+ return 0
+ if (rmat.on_hold())
+ say("Mineral access is on hold, please contact the quartermaster.")
+ return 0
+ var/count = mat_container.retrieve_sheets(text2num(eject_amt), eject_sheet, drop_location())
+ var/list/matlist = list()
+ matlist[eject_sheet] = text2num(eject_amt)
+ rmat.silo_log(src, "ejected", -count, "sheets", matlist)
+ return count
/obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
var/stack_name = material2name(id_inserted)
@@ -417,3 +452,6 @@
return FALSE
return TRUE
+
+/obj/machinery/mecha_part_fabricator/maint
+ link_on_init = FALSE
\ No newline at end of file
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 2d182516..b357e96d 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -69,6 +69,12 @@
var/melee_cooldown = 10
var/melee_can_hit = 1
+ var/silicon_pilot = FALSE //set to true if an AI or MMI is piloting.
+
+ var/enter_delay = 40 //Time taken to enter the mech
+ var/enclosed = TRUE //Set to false for open-cockpit mechs
+ var/silicon_icon_state = null //if the mech has a different icon when piloted by an AI or MMI
+
//Action datums
var/datum/action/innate/mecha/mech_eject/eject_action = new
var/datum/action/innate/mecha/mech_toggle_internals/internals_action = new
@@ -116,7 +122,8 @@
icon_state += "-open"
add_radio()
add_cabin()
- add_airtank()
+ if (enclosed)
+ add_airtank()
spark_system.set_up(2, 0, src)
spark_system.attach(src)
smoke_system.set_up(3, src)
@@ -133,6 +140,11 @@
diag_hud_set_mechcell()
diag_hud_set_mechstat()
+/obj/mecha/update_icon()
+ if (silicon_pilot && silicon_icon_state)
+ icon_state = silicon_icon_state
+ . = ..()
+
/obj/mecha/get_cell()
return cell
@@ -273,6 +285,11 @@
to_chat(user, "It's equipped with:")
for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
to_chat(user, "[icon2html(ME, user)] \A [ME].")
+ if(!enclosed)
+ if(silicon_pilot)
+ to_chat(user, "[src] appears to be piloting itself...")
+ else if(occupant && occupant != user) //!silicon_pilot implied
+ to_chat(user, "You can see [occupant] inside.")
//processing internal damage, temperature, air regulation, alert updates, lights power use.
/obj/mecha/process()
@@ -392,13 +409,19 @@
diag_hud_set_mechcell()
diag_hud_set_mechstat()
+/obj/mecha/fire_act() //Check if we should ignite the pilot of an open-canopy mech
+ if (occupant && !enclosed && !silicon_pilot)
+ if (occupant.fire_stacks < 5)
+ occupant.fire_stacks += 1
+ occupant.IgniteMob()
+
/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits.
return
/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
if(speaker == occupant)
- if(radio.broadcasting)
+ if(radio?.broadcasting)
radio.talk_into(speaker, text, , spans, message_language)
//flick speech bubble
var/list/speech_bubble_recipients = list()
@@ -474,7 +497,7 @@
. = ..()
if(.)
events.fireEvent("onMove",get_turf(src))
- if (internal_tank.disconnect()) // Something moved us and broke connection
+ if (internal_tank?.disconnect()) // Something moved us and broke connection
occupant_message("Air port connection teared off!")
log_message("Lost connection to gas port.")
@@ -500,7 +523,7 @@
user.forceMove(get_turf(src))
to_chat(user, "You climb out from [src].")
return 0
- if(internal_tank.connected_port)
+ if(internal_tank?.connected_port)
if(world.time - last_message > 20)
occupant_message("Unable to move while connected to the air system port!")
last_message = world.time
@@ -688,6 +711,7 @@
AI.disconnect_shell()
RemoveActions(AI, TRUE)
occupant = null
+ silicon_pilot = FALSE
AI.forceMove(card)
card.AI = AI
AI.controlled_mech = null
@@ -729,7 +753,9 @@
AI.ai_restore_power()
AI.forceMove(src)
occupant = AI
+ silicon_pilot = TRUE
icon_state = initial(icon_state)
+ update_icon()
playsound(src, 'sound/machines/windowdoor.ogg', 50, 1)
if(!internal_damage)
SEND_SOUND(occupant, sound('sound/mecha/nominal.ogg',volume=50))
@@ -832,7 +858,7 @@
visible_message("[user] starts to climb into [name].")
- if(do_after(user, 40, target = src))
+ if(do_after(user, enter_delay, target = src))
if(obj_integrity <= 0)
to_chat(user, "You cannot get in the [name], it has been destroyed!")
else if(occupant)
@@ -905,6 +931,7 @@
var/mob/living/brainmob = mmi_as_oc.brainmob
mmi_as_oc.mecha = src
occupant = brainmob
+ silicon_pilot = TRUE
brainmob.forceMove(src) //should allow relaymove
brainmob.reset_perspective(src)
brainmob.remote_control = src
@@ -946,6 +973,7 @@
RemoveActions(occupant)
occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced.
occupant = null
+ silicon_pilot = FALSE
return
else
if(!AI.linked_core)
@@ -963,6 +991,7 @@
return
var/mob/living/L = occupant
occupant = null //we need it null when forceMove calls Exited().
+ silicon_pilot = FALSE
if(mob_container.forceMove(newloc))//ejecting mob container
log_message("[mob_container] moved out.")
L << browse(null, "window=exosuit")
diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm
index 7b00e208..307e8d1b 100644
--- a/code/game/mecha/mecha_actions.dm
+++ b/code/game/mecha/mecha_actions.dm
@@ -3,7 +3,8 @@
/obj/mecha/proc/GrantActions(mob/living/user, human_occupant = 0)
if(human_occupant)
eject_action.Grant(user, src)
- internals_action.Grant(user, src)
+ if(enclosed)
+ internals_action.Grant(user, src)
cycle_action.Grant(user, src)
lights_action.Grant(user, src)
stats_action.Grant(user, src)
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 5b7becb5..0c87ca84 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -171,36 +171,29 @@
list(
"key" = TOOL_WRENCH,
"back_key" = TOOL_CROWBAR,
- "desc" = "Internal armor is installed."
+ "desc" = "Outer plating is installed."
),
//17
list(
"key" = TOOL_WELDER,
"back_key" = TOOL_WRENCH,
- "desc" = "Internal armor is wrenched."
+ "desc" = "Outer Plating is wrenched."
),
//18
list(
- "key" = /obj/item/stack/sheet/plasteel,
- "amount" = 5,
+ "key" = /obj/item/stack/rods,
+ "amount" = 10,
"back_key" = TOOL_WELDER,
- "desc" = "Internal armor is welded."
+ "desc" = "Outer Plating is welded."
),
//19
- list(
- "key" = TOOL_WRENCH,
- "back_key" = TOOL_CROWBAR,
- "desc" = "External armor is installed."
- ),
-
- //20
list(
"key" = TOOL_WELDER,
- "back_key" = TOOL_WRENCH,
- "desc" = "External armor is wrenched."
+ "back_key" = TOOL_WIRECUTTER,
+ "desc" = "Cockpit wire screen is installed."
),
)
diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm
index 0188419f..37395dd4 100644
--- a/code/game/mecha/mecha_control_console.dm
+++ b/code/game/mecha/mecha_control_console.dm
@@ -76,7 +76,7 @@
var/answer = {"Name: [M.name]
Integrity: [M.obj_integrity/M.max_integrity*100]%
Cell charge: [isnull(cell_charge)?"Not found":"[M.cell.percent()]%"]
-Airtank: [M.return_pressure()]kPa
+Airtank: [M.internal_tank?"[round(M.return_pressure(), 0.01)]":"Not Equipped"] kPa
Pilot: [M.occupant||"None"]
Location: [get_area(M)||"Unknown"]
Active equipment: [M.selected||"None"] "}
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index b7d59c6a..74981f35 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -114,6 +114,9 @@
/obj/mecha/bullet_act(obj/item/projectile/Proj) //wrapper
+ if (!enclosed && occupant && !silicon_pilot) //allows bullets to hit the pilot of open-canopy mechs
+ occupant.bullet_act(Proj) //If the sides are open, the occupant can be hit
+ return BULLET_ACT_HIT
log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).", color="red")
. = ..()
diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm
index 0bab48da..f087c67f 100644
--- a/code/game/mecha/mecha_topic.dm
+++ b/code/game/mecha/mecha_topic.dm
@@ -71,19 +71,24 @@
/obj/mecha/proc/get_stats_part()
var/integrity = obj_integrity/max_integrity*100
var/cell_charge = get_charge()
- var/datum/gas_mixture/int_tank_air = internal_tank.return_air()
- var/tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
- var/tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
- var/cabin_pressure = round(return_pressure(),0.01)
+ var/datum/gas_mixture/int_tank_air = 0
+ var/tank_pressure = 0
+ var/tank_temperature = 0
+ var/cabin_pressure = 0
+ if (internal_tank)
+ int_tank_air = internal_tank.return_air()
+ tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
+ tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
+ cabin_pressure = round(return_pressure(),0.01)
. = {"[report_internal_damage()]
[integrity<30?"DAMAGE LEVEL CRITICAL
":null]
Integrity: [integrity]%
Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
- Air source: [use_internal_tank?"Internal Airtank":"Environment"]
- Airtank pressure: [tank_pressure]kPa
- Airtank temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
- Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
+ Air source: [internal_tank?"[use_internal_tank?"Internal Airtank":"Environment"]":"Environment"]
+ Airtank pressure: [internal_tank?"[tank_pressure]kPa":"N/A"]
+ Airtank temperature: [internal_tank?"[tank_temperature]°K|[tank_temperature - T0C]°C":"N/A"]
+ Cabin pressure: [internal_tank?"[cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa":"N/A"]
+ Cabin temperature: [internal_tank?"[return_temperature()]°K|[return_temperature() - T0C]°C":"N/A"]
[dna_lock?"DNA-locked:
[dna_lock] \[Reset\]
":""]
[thrusters_action.owner ? "Thrusters: [thrusters_active ? "Enabled" : "Disabled"]
" : ""]
[defense_action.owner ? "Defence Mode: [defence_mode ? "Enabled" : "Disabled"]
" : ""]
@@ -100,14 +105,14 @@
@@ -115,7 +120,7 @@
[add_req_access?"L":"Unl"]ock ID upload panel
[maint_access?"Forbid":"Permit"] maintenance protocols
-
[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port
+ [internal_tank?"
[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port":""]
DNA-lock
View internal log
Change exosuit name
diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm
index eb88c254..652c9f31 100644
--- a/code/game/mecha/mecha_wreckage.dm
+++ b/code/game/mecha/mecha_wreckage.dm
@@ -161,6 +161,22 @@
welder_salvage += part
parts -= part
+/obj/structure/mecha_wreckage/ripley/mkii
+ name = "\improper Ripley MK-II wreckage"
+ icon_state = "ripleymkii-broken"
+
+/obj/structure/mecha_wreckage/ripley/mkii/Initialize()
+ . = ..()
+ var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso,
+ /obj/item/mecha_parts/part/ripley_left_arm,
+ /obj/item/mecha_parts/part/ripley_right_arm,
+ /obj/item/mecha_parts/part/ripley_left_leg,
+ /obj/item/mecha_parts/part/ripley_right_leg)
+ for(var/i = 0; i < 2; i++)
+ if(parts.len && prob(40))
+ var/part = pick(parts)
+ welder_salvage += part
+ parts -= part
/obj/structure/mecha_wreckage/ripley/firefighter
name = "\improper Firefighter wreckage"
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index dea5ca58..6b89c920 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -1,10 +1,11 @@
/obj/mecha/working/ripley
- desc = "Autonomous Power Loader Unit. This newer model is refitted with powerful armour against the dangers of planetary mining."
- name = "\improper APLU \"Ripley\""
+ desc = "Autonomous Power Loader Unit MK-I. Designed primarily around heavy lifting, the Ripley can be outfitted with utility equipment to fill a number of roles."
+ name = "\improper APLU MK-I \"Ripley\""
icon_state = "ripley"
- step_in = 3 //Move speed, lower is faster.
- var/fast_pressure_step_in = 2
- var/slow_pressure_step_in = 3
+ silicon_icon_state = "ripley-empty"
+ step_in = 1.5 //Move speed, lower is faster.
+ var/fast_pressure_step_in = 1.5 //step_in while in low pressure conditions
+ var/slow_pressure_step_in = 2.0 //step_in while in normal pressure conditions
max_temperature = 20000
max_integrity = 200
lights_power = 8
@@ -15,6 +16,9 @@
var/list/cargo = new
var/cargo_capacity = 15
var/hides = 0
+ enclosed = FALSE //Normal ripley has an open cockpit design
+ enter_delay = 10 //can enter in a quarter of the time of other mechs
+ opacity = FALSE //Ripley has a window
/obj/mecha/working/ripley/Move()
. = ..()
@@ -55,18 +59,38 @@
else
add_overlay(occupant ? "ripley-g-full" : "ripley-g-full-open")
+/obj/mecha/working/ripley/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null)
+ if (!enclosed)
+ possible_int_damage -= (MECHA_INT_TEMP_CONTROL + MECHA_INT_TANK_BREACH) //if we don't even have an air tank, these two doesn't make a ton of sense.
+ . = ..()
+
+
/obj/mecha/working/ripley/Initialize()
. = ..()
AddComponent(/datum/component/armor_plate,3,/obj/item/stack/sheet/animalhide/goliath_hide,list("melee" = 10, "bullet" = 5, "laser" = 5))
+/obj/mecha/working/ripley/mkii
+ desc = "Autonomous Power Loader Unit MK-II. This prototype Ripley is refitted with a pressurized cabin, trading its prior speed for atmospheric protection"
+ name = "\improper APLU MK-II \"Ripley\""
+ icon_state = "ripleymkii"
+ fast_pressure_step_in = 2 //step_in while in low pressure conditions
+ slow_pressure_step_in = 4 //step_in while in normal pressure conditions
+ step_in = 4
+ armor = list("melee" = 40, "bullet" = 20, "laser" = 10, "energy" = 20, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
+ wreckage = /obj/structure/mecha_wreckage/ripley/mkii
+ enclosed = TRUE
+ enter_delay = 40
+ silicon_icon_state = null
+ opacity = TRUE
/obj/mecha/working/ripley/firefighter
- desc = "Autonomous Power Loader Unit. This model is refitted with additional thermal protection."
- name = "\improper APLU \"Firefighter\""
+ desc = "Autonomous Power Loader Unit MK-III. This model is refitted with a pressurized cabin and additional thermal protection."
+ name = "\improper APLU MK-III \"Firefighter\""
icon_state = "firefighter"
step_in = 4
- fast_pressure_step_in = 2
- slow_pressure_step_in = 4
+ fast_pressure_step_in = 2 //step_in while in low pressure conditions
+ slow_pressure_step_in = 4 //step_in while in normal pressure conditions
+ step_in = 4
max_temperature = 65000
max_integrity = 250
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
@@ -74,6 +98,10 @@
armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
max_equip = 5 // More armor, less tools
wreckage = /obj/structure/mecha_wreckage/ripley/firefighter
+ enclosed = TRUE
+ enter_delay = 40
+ silicon_icon_state = null
+ opacity = TRUE
/obj/mecha/working/ripley/deathripley
@@ -81,11 +109,17 @@
name = "\improper DEATH-RIPLEY"
icon_state = "deathripley"
armor = list("melee" = 40, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- slow_pressure_step_in = 3
+ fast_pressure_step_in = 2 //step_in while in low pressure conditions
+ slow_pressure_step_in = 4 //step_in while in normal pressure conditions
+ step_in = 4
opacity=0
lights_power = 7
wreckage = /obj/structure/mecha_wreckage/ripley/deathripley
step_energy_drain = 0
+ enclosed = TRUE
+ enter_delay = 40
+ silicon_icon_state = null
+ opacity = TRUE
/obj/mecha/working/ripley/deathripley/Initialize()
. = ..()
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 73f9d265..a43f956c 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -861,3 +861,201 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(reagents && reagents.total_volume)
hand_reagents()
+
+///////////////
+/////BONGS/////
+///////////////
+
+/obj/item/bong
+ name = "bong"
+ desc = "A water bong used for smoking dried plants."
+ icon = 'icons/obj/bongs.dmi'
+ icon_state = null
+ item_state = null
+ w_class = WEIGHT_CLASS_NORMAL
+ light_color = "#FFCC66"
+ var/icon_off = "bong"
+ var/icon_on = "bong_lit"
+ var/chem_volume = 100
+ var/last_used_time //for cooldown
+ var/firecharges = 0 //used for counting how many hits can be taken before the flame goes out
+ var/list/list_reagents = list() //For the base reagents bongs could get
+
+
+/obj/item/bong/Initialize()
+ . = ..()
+ create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
+ reagents.add_reagent_list(list_reagents)
+ icon_state = icon_off
+
+/obj/item/bong/attackby(obj/item/O, mob/user, params)
+ . = ..()
+ //If we're using a dried plant..
+ if(istype(O,/obj/item/reagent_containers/food/snacks))
+ var/obj/item/reagent_containers/food/snacks/DP = O
+ if (DP.dry)
+ //Nothing if our bong is full
+ if (reagents.holder_full())
+ user.show_message("
The bowl is full!", 1)
+ return
+
+ //Transfer reagents and remove the plant
+ user.show_message("
You stuff the [DP] into the [src]'s bowl.", 1)
+ DP.reagents.trans_to(src, 100)
+ qdel(DP)
+ return
+ else
+ user.show_message("
[DP] must be dried first!", 1)
+ return
+
+ if (O.heat > 500)
+ if (reagents && reagents.total_volume) //if there's stuff in the bong
+ var/lighting_text = O.ignition_effect(src, user)
+ if(lighting_text)
+ //Logic regarding igniting it on
+ if (firecharges == 0)
+ user.show_message("
You light the [src] with the [O]!", 1)
+ bongturnon()
+ else
+ user.show_message("
You rekindle [src]'s flame with the [O]!", 1)
+
+ firecharges = 1
+ return
+ else
+ user.show_message("
There's nothing to light up in the bowl.", 1)
+ return
+
+/obj/item/bong/CtrlShiftClick(mob/user) //empty reagents on alt click
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if (reagents && reagents.total_volume)
+ user.show_message("
You empty the [src].", 1)
+ reagents.clear_reagents()
+ if(firecharges)
+ firecharges = 0
+ bongturnoff()
+ else
+ user.show_message("
The [src] is already empty.", 1)
+
+/obj/item/bong/AltClick(mob/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if(firecharges)
+ firecharges = 0
+ bongturnoff()
+ user.show_message("
You quench the flame.", 1)
+
+/obj/item/bong/examine(mob/user)
+ ..()
+ if(!reagents.total_volume)
+ to_chat(user, "
The bowl is empty.")
+ else if (reagents.total_volume > 80)
+ to_chat(user, "
The bowl is filled to the brim.")
+ else if (reagents.total_volume > 40)
+ to_chat(user, "
The bowl has plenty weed in it.")
+ else
+ to_chat(user, "
The bowl has some weed in it.")
+
+ to_chat(user, "
Ctrl+Shift-click to empty.")
+ to_chat(user, "
Alt-click to extinguish.")
+
+/obj/item/bong/ignition_effect(atom/A, mob/user)
+ if(firecharges)
+ . = "
[user] lights [A] off of the [src]."
+ else
+ . = ""
+
+/obj/item/bong/attack(mob/living/carbon/M, mob/living/carbon/user, obj/target)
+ //if it's lit up, some stuff in the bowl and the user is a target, and we're not on cooldown
+ if (!reagents)
+ return
+
+ if (M ==! user)
+ return
+
+ if(user.is_mouth_covered(head_only = 1))
+ to_chat(user, "
Remove your headgear first.")
+ return
+
+ if(user.is_mouth_covered(mask_only = 1))
+ to_chat(user, "
Remove your mask first.")
+ return
+
+ if (!reagents.total_volume)
+ to_chat(user, "
There's nothing in the bowl.")
+ return
+
+ if (!firecharges)
+ to_chat(user, "
You have to light it up first.")
+ return
+
+ if (last_used_time + 30 < world.time)
+ var/hit_strength
+ var/noise
+ var/hittext = ""
+ //if the intent is help then you take a small hit, else a big one
+ if (user.a_intent == INTENT_HARM)
+ hit_strength = 2
+ noise = 100
+ hittext = "big hit"
+ else
+ hit_strength = 1
+ noise = 70
+ hittext = "hit"
+ //bubbling sound
+ playsound(user.loc,'sound/effects/bonghit.ogg', noise, 1)
+
+ last_used_time = world.time
+
+ //message
+ user.visible_message("
[user] begins to take a "+ hittext +" from the [src]!", \
+ "
You begin to take a "+ hittext +" from [src].")
+
+ //we take a hit here, after an uninterrupted delay
+ if(do_after(user, 25, target = user))
+ if (reagents && reagents.total_volume)
+ var/fraction = 12 * hit_strength
+
+ var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
+ s.set_up(reagents, hit_strength, 18, user.loc)
+ s.start()
+
+ reagents.reaction(user, INGEST, fraction)
+ if(!reagents.trans_to(user, fraction))
+ reagents.remove_any(fraction)
+
+ if (hit_strength == 2 && prob(15))
+ user.emote("cough")
+ user.adjustOxyLoss(15)
+
+ //playsound(user.loc, 'sound/effects/smoke.ogg', 10, 1, -3)
+
+ user.visible_message("
[user] takes a "+ hittext +" from the [src]!", \
+ "
You take a "+ hittext +" from [src].")
+
+ firecharges = firecharges - 1
+ if (firecharges == 0)
+ bongturnoff()
+ if (!reagents.total_volume)
+ firecharges = 0
+ bongturnoff()
+
+
+
+/obj/item/bong/proc/bongturnon()
+ icon_state = icon_on
+ set_light(3, 0.8)
+
+/obj/item/bong/proc/bongturnoff()
+ icon_state = icon_off
+ set_light(0, 0.0)
+
+
+
+/obj/item/bong/coconut
+ name = "coconut bong"
+ icon_off = "coconut_bong"
+ icon_on = "coconut_bong_lit"
+ desc = "A water bong used for smoking dried plants. This one's made out of a coconut and some bamboo"
\ No newline at end of file
diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm
index 7d2ffe0a..afbf2630 100644
--- a/code/game/objects/items/circuitboards/computer_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm
@@ -14,6 +14,10 @@
name = "Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security
+/obj/item/circuitboard/computer/advanced_camera
+ name = "Advanced Camera Console (Computer Board)"
+ build_path = /obj/machinery/computer/camera_advanced/syndie
+
/obj/item/circuitboard/computer/xenobiology
name = "circuit board (Xenobiology Console)"
build_path = /obj/machinery/computer/camera_advanced/xenobio
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index 143d77bc..a1ee1d1d 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -54,6 +54,21 @@
else
return ..()
+/obj/item/kitchen/fork/plastic
+ name = "plastic fork"
+ desc = "Really takes you back to highschool lunch."
+ icon_state = "plastic_fork"
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ grind_results = list(/datum/material/plastic=80)
+ var/break_chance = 25
+
+/obj/item/kitchen/fork/plastic/afterattack(mob/living/carbon/user)
+ .=..()
+ if(prob(break_chance))
+ user.visible_message("
[user]'s fork snaps into tiny pieces in their hand.")
+ qdel(src)
/obj/item/kitchen/knife
name = "kitchen knife"
@@ -89,6 +104,26 @@
"
[user] is slitting [user.p_their()] stomach open with the [src.name]! It looks like [user.p_theyre()] trying to commit seppuku."))
return (BRUTELOSS)
+/obj/item/kitchen/knife/plastic
+ name = "plastic knife"
+ icon_state = "plastic_knife"
+ item_state = "knife"
+ desc = "A very safe, barely sharp knife made of plastic. Good for cutting food and not much else."
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ throw_range = 5
+ grind_results = list(/datum/material/plastic = 100)
+ attack_verb = list("prodded", "whiffed","scratched", "poked")
+ sharpness = IS_SHARP
+ var/break_chance = 25
+
+/obj/item/kitchen/knife/plastic/afterattack(mob/living/carbon/user)
+ .=..()
+ if(prob(break_chance))
+ user.visible_message("
[user]'s knife snaps into tiny pieces in their hand.")
+ qdel(src)
+
/obj/item/kitchen/knife/ritual
name = "ritual knife"
desc = "The unearthly energies that once powered this blade are now dormant."
@@ -175,6 +210,22 @@
return BRUTELOSS
/* Trays moved to /obj/item/storage/bag */
+/obj/item/kitchen/spoon/plastic
+ name = "plastic spoon"
+ desc = "Just be careful your food doesn't melt the spoon first."
+ icon_state = "plastic_spoon"
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ grind_results = list(/datum/material/plastic=120)
+ var/break_chance = 25
+
+/obj/item/kitchen/knife/plastic/afterattack(mob/living/carbon/user)
+ .=..()
+ if(prob(break_chance))
+ user.visible_message("
[user]'s spoon snaps into tiny pieces in their hand.")
+ qdel(src)
+
/obj/item/kitchen/knife/scimitar
name = "Scimitar knife"
desc = "A knife used to cleanly butcher. Its razor-sharp edge has been honed for butchering, but has been poorly maintained over the years."
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 83b14a1a..2a5e7e4a 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -39,6 +39,9 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
/obj/item/stack/sheet/glass/fifty
amount = 50
+/obj/item/stack/sheet/glass/five
+ amount = 5
+
/obj/item/stack/sheet/glass/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.glass_recipes
return ..()
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 46c0d473..cc8e6a6f 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -55,6 +55,9 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
/obj/item/stack/sheet/mineral/sandstone/thirty
amount = 30
+/obj/item/stack/sheet/mineral/sandstone/twelve
+ amount = 12
+
/*
* Sandbags
*/
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 068468b7..6736c0dd 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -235,6 +235,34 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
/obj/item/stack/sheet/mineral/wood/fifty
amount = 50
+/*
+ * Bamboo
+ */
+
+GLOBAL_LIST_INIT(bamboo_recipes, list ( \
+ new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 10, time = 160, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 70), \
+ ))
+
+/obj/item/stack/sheet/mineral/bamboo
+ name = "bamboo cuttings"
+ desc = "Finely cut bamboo sticks."
+ singular_name = "cut bamboo"
+ icon_state = "sheet-bamboo"
+ item_state = "sheet-bamboo"
+ icon = 'icons/obj/stack_objects.dmi'
+ sheettype = "bamboo"
+ throwforce = 15
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
+ resistance_flags = FLAMMABLE
+ merge_type = /obj/item/stack/sheet/mineral/bamboo
+ grind_results = list("carbon" = 5)
+
+/obj/item/stack/sheet/mineral/bamboo/Initialize(mapload, new_amount, merge = TRUE)
+ recipes = GLOB.bamboo_recipes
+ return ..()
+
+
/*
* Cloth
*/
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index b98c4f79..6d010369 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -73,6 +73,15 @@
turf_type = /turf/open/floor/grass
resistance_flags = FLAMMABLE
+//Fairygrass
+/obj/item/stack/tile/fairygrass
+ name = "fairygrass tile"
+ singular_name = "fairygrass floor tile"
+ desc = "A patch of odd, glowing blue grass."
+ icon_state = "tile_fairygrass"
+ item_state = "tile-fairygrass"
+ turf_type = /turf/open/floor/grass/fairy
+ resistance_flags = FLAMMABLE
//Wood
/obj/item/stack/tile/wood
diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm
index 0f3bfbeb..4c85e746 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -104,12 +104,12 @@
playing = FALSE
hearing_mobs = null
return
- if(!lentext(note))
+ if(!length(note))
continue
var/cur_note = text2ascii(note) - 96
if(cur_note < 1 || cur_note > 7)
continue
- for(var/i=2 to lentext(note))
+ for(var/i=2 to length(note))
var/ni = copytext(note,i,i+1)
if(!text2num(ni))
if(ni == "#" || ni == "b" || ni == "n")
@@ -209,7 +209,7 @@
lines.Cut(MUSIC_MAXLINES + 1)
var/linenum = 1
for(var/l in lines)
- if(lentext(l) > MUSIC_MAXLINECHARS)
+ if(length(l) > MUSIC_MAXLINECHARS)
to_chat(usr, "Line [linenum] too long!")
lines.Remove(l)
else
@@ -236,11 +236,11 @@
if(!in_range(instrumentObj, usr))
return
- if(lentext(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
+ if(length(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
if(cont == "no")
break
- while(lentext(t) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
+ while(length(t) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
ParseSong(t)
else if(href_list["help"])
@@ -272,7 +272,7 @@
return
if(lines.len > MUSIC_MAXLINES)
return
- if(lentext(newline) > MUSIC_MAXLINECHARS)
+ if(length(newline) > MUSIC_MAXLINECHARS)
newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
lines.Add(newline)
@@ -287,7 +287,7 @@
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
if(!content || !in_range(instrumentObj, usr))
return
- if(lentext(content) > MUSIC_MAXLINECHARS)
+ if(length(content) > MUSIC_MAXLINECHARS)
content = copytext(content, 1, MUSIC_MAXLINECHARS)
if(num > lines.len || num < 1)
return
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index ed6e2790..0128eeda 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -96,6 +96,15 @@
if(..())
return
+/turf/open/floor/grass/fairy //like grass but fae-er
+ name = "fairygrass patch"
+ desc = "Something about this grass makes you want to frolic. Or get high."
+ icon_state = "fairygrass"
+ floor_tile = /obj/item/stack/tile/fairygrass
+ light_range = 2
+ light_power = 0.50
+ light_color = "#33CCFF"
+
/turf/open/floor/grass/snow
gender = PLURAL
name = "snow"
diff --git a/code/game/world.dm b/code/game/world.dm
index d3491903..958ef849 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -100,6 +100,7 @@ GLOBAL_VAR(restart_counter)
GLOB.picture_log_directory = "data/picture_logs/[override_dir]"
GLOB.world_game_log = "[GLOB.log_directory]/game.log"
+ GLOB.world_cloning_log = "[GLOB.log_directory]/cloning.log"
GLOB.world_attack_log = "[GLOB.log_directory]/attack.log"
GLOB.world_pda_log = "[GLOB.log_directory]/pda.log"
GLOB.world_telecomms_log = "[GLOB.log_directory]/telecomms.log"
@@ -302,3 +303,4 @@ GLOBAL_VAR(restart_counter)
maxz++
SSmobs.MaxZChanged()
SSidlenpcpool.MaxZChanged()
+
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index c427b277..62cb66f9 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2152,7 +2152,7 @@
return
src.admincaster_feed_channel.channel_name = stripped_input(usr, "Provide a Feed Channel Name.", "Network Channel Handler", "")
while (findtext(src.admincaster_feed_channel.channel_name," ") == 1)
- src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,lentext(src.admincaster_feed_channel.channel_name)+1)
+ src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,length(src.admincaster_feed_channel.channel_name)+1)
src.access_news_network()
else if(href_list["ac_set_channel_lock"])
@@ -2194,7 +2194,7 @@
return
src.admincaster_feed_message.body = adminscrub(input(usr, "Write your Feed story.", "Network Channel Handler", ""))
while (findtext(src.admincaster_feed_message.returnBody(-1)," ") == 1)
- src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.returnBody(-1),2,lentext(src.admincaster_feed_message.returnBody(-1))+1)
+ src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.returnBody(-1),2,length(src.admincaster_feed_message.returnBody(-1))+1)
src.access_news_network()
else if(href_list["ac_submit_new_message"])
@@ -2255,7 +2255,7 @@
return
src.admincaster_wanted_message.criminal = adminscrub(input(usr, "Provide the name of the Wanted person.", "Network Security Handler", ""))
while(findtext(src.admincaster_wanted_message.criminal," ") == 1)
- src.admincaster_wanted_message.criminal = copytext(admincaster_wanted_message.criminal,2,lentext(admincaster_wanted_message.criminal)+1)
+ src.admincaster_wanted_message.criminal = copytext(admincaster_wanted_message.criminal,2,length(admincaster_wanted_message.criminal)+1)
src.access_news_network()
else if(href_list["ac_set_wanted_desc"])
@@ -2263,7 +2263,7 @@
return
src.admincaster_wanted_message.body = adminscrub(input(usr, "Provide the a description of the Wanted person and any other details you deem important.", "Network Security Handler", ""))
while (findtext(src.admincaster_wanted_message.body," ") == 1)
- src.admincaster_wanted_message.body = copytext(src.admincaster_wanted_message.body,2,lentext(src.admincaster_wanted_message.body)+1)
+ src.admincaster_wanted_message.body = copytext(src.admincaster_wanted_message.body,2,length(src.admincaster_wanted_message.body)+1)
src.access_news_network()
else if(href_list["ac_submit_wanted"])
diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm
index 40c2cdba..6ddc75c7 100644
--- a/code/modules/admin/verbs/modifyvariables.dm
+++ b/code/modules/admin/verbs/modifyvariables.dm
@@ -307,11 +307,11 @@ GLOBAL_PROTECT(VVpixelmovement)
// the type with the base type removed from the begaining
var/fancytype = types[D.type]
if (findtext(fancytype, types[type]))
- fancytype = copytext(fancytype, lentext(types[type])+1)
- var/shorttype = copytext("[D.type]", lentext("[type]")+1)
- if (lentext(shorttype) > lentext(fancytype))
+ fancytype = copytext(fancytype, length(types[type])+1)
+ var/shorttype = copytext("[D.type]", length("[type]")+1)
+ if (length(shorttype) > length(fancytype))
shorttype = fancytype
- if (!lentext(shorttype))
+ if (!length(shorttype))
shorttype = "/"
.["[D]([shorttype])[REF(D)]#[i]"] = D
@@ -534,7 +534,7 @@ GLOBAL_PROTECT(VVpixelmovement)
if (prompt != "Continue")
return FALSE
return TRUE
-
+
/client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0)
if(!check_rights(R_VAREDIT))
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index fa28da74..6f85668b 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -82,7 +82,7 @@
crate_type = /obj/structure/closet/crate/internals
/datum/supply_pack/emergency/radiatione_emergency
- name = "Emergenc Radiation Protection Crate"
+ name = "Emergency Radiation Protection Crate"
desc = "Survive the Nuclear Apocalypse and Supermatter Engine alike with two sets of Radiation suits. Each set contains a helmet, suit, and Geiger counter. We'll even throw in a few pill bottles that are able to handles radiation and the affects of the poisoning."
cost = 2500
contains = list(/obj/item/clothing/head/radiation,
@@ -293,7 +293,7 @@
/datum/supply_pack/medical/anitvirus
name = "Virus Containment Crate"
- desc = "Viro let out a death plague Mk II again? Someone didnt wash there hands? Old plagues born anew? Well this crate is for you! Hope you cure it before it brakes out of the station... This crate needs medical access to open and has two bio suits, a box of needles and beakers, five spaceacillin needles, and a medibot."
+ desc = "Viro let out a death plague Mk II again? Someone didnt wash their hands? Old plagues born anew? Well this crate is for you! Hope you cure it before it breaks out of the station... This crate needs medical access to open and has two bio suits, a box of needles and beakers, five spaceacillin needles, and a medibot."
cost = 3000
access = ACCESS_MEDICAL
contains = list(/mob/living/simple_animal/bot/medbot,
@@ -311,6 +311,56 @@
crate_name = "virus containment unit crate"
crate_type = /obj/structure/closet/crate/secure/plasma
+
+/datum/supply_pack/emergency/medicalemergency
+ name = "Emergency Medical Supplies"
+ desc = "Emergency supplies for a front-line medic. Contains two boxes of body bags, a medical HUD, a defib unit, medical belt, toxin bottles, epipens, and several types of medical kits."
+ cost = 6600
+ contains = list(/obj/item/storage/box/bodybags,
+ /obj/item/storage/box/bodybags,
+ /obj/item/clothing/glasses/hud/health,
+ /obj/item/defibrillator/loaded,
+ /obj/item/storage/belt/medical,
+ /obj/item/storage/firstaid/toxin,
+ /obj/item/storage/firstaid/o2,
+ /obj/item/storage/firstaid/brute,
+ /obj/item/storage/firstaid/fire,
+ /obj/item/reagent_containers/glass/bottle/toxin,
+ /obj/item/reagent_containers/glass/bottle/toxin,
+ /obj/item/storage/box/medipens)
+ crate_name = "medical emergency crate"
+ crate_type = /obj/structure/closet/crate/medical
+
+/datum/supply_pack/emergency/medemergencylite
+ name = "Emergency Medical Supplies (Lite)"
+ desc = "A less than optimal, but still effective, set of tools for emergency care. Contains a box of bodybags, a medical HUD, healing sprays, charcoal, some gauze, and some spare medipens."
+ cost = 2800
+ contains = list(/obj/item/storage/box/bodybags,
+ /obj/item/stack/medical/gauze,
+ /obj/item/clothing/glasses/hud/health,
+ /obj/item/reagent_containers/medspray/styptic,
+ /obj/item/reagent_containers/medspray/silver_sulf,
+ /obj/item/reagent_containers/medspray/synthflesh,
+ /obj/item/reagent_containers/glass/bottle/charcoal,
+ /obj/item/reagent_containers/glass/bottle/charcoal,
+ /obj/item/reagent_containers/hypospray/medipen,
+ /obj/item/reagent_containers/hypospray/medipen,
+ /obj/item/reagent_containers/hypospray/medipen)
+ crate_name = "medical emergency crate (lite)"
+ crate_type = /obj/structure/closet/crate/medical
+
+/datum/supply_pack/emergency/mre
+ name = "MRE supply kit (emergency rations)"
+ desc = "The lights are out. Oxygen's running low. You've run out of food except space weevils. Don't let this be you! Order our NT branded MRE kits today! This pack contains 5 MRE packs with a randomized menu and an oxygen tank."
+ cost = 2000
+ contains = list(/obj/item/storage/box/mre/menu1/safe,
+ /obj/item/storage/box/mre/menu1/safe,
+ /obj/item/storage/box/mre/menu2/safe,
+ /obj/item/storage/box/mre/menu2/safe,
+ /obj/item/storage/box/mre/menu3,
+ /obj/item/storage/box/mre/menu4/safe)
+ crate_name = "MRE crate (emergency rations)"
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Security ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -813,7 +863,7 @@
/datum/supply_pack/engineering/industrialrcd
name = "Industrial RCD"
- desc = "A industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Dose not contain spare ammo for the industrial RCD or any other RCD modles."
+ desc = "A industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Does not contain spare ammo for the industrial RCD or any other RCD modles."
cost = 4500
access = ACCESS_CE
contains = list(/obj/item/construction/rcd/industrial)
@@ -860,6 +910,18 @@
crate_name = "power cell crate"
crate_type = /obj/structure/closet/crate/engineering/electrical
+/datum/supply_pack/engineering/powertools
+ name = "Power Tools Crate"
+ desc = "Setting up the aux base? Working out in space? Maybe you just hate doing things by hand. Grab some power tools and slash your workload in half! Contains a hardhat, hazard vest, Hand Drill, and Jaws of Life"
+ cost = 6500
+ access = ACCESS_ENGINE
+ contains = list(/obj/item/clothing/head/hardhat,
+ /obj/item/clothing/suit/hazardvest,
+ /obj/item/screwdriver/power,
+ /obj/item/crowbar/power)
+ crate_name = "power tools crate"
+ crate_type = /obj/structure/closet/crate/secure/engineering
+
/datum/supply_pack/engineering/shuttle_engine
name = "Shuttle Engine Crate"
desc = "Through advanced bluespace-shenanigans, our engineers have managed to fit an entire shuttle engine into one tiny little crate. Requires CE access to open."
@@ -1282,6 +1344,16 @@
group = "Medical"
crate_type = /obj/structure/closet/crate/medical
+/datum/supply_pack/medical/bodybags
+ name = "Bodybags"
+ desc = "For when the bodies hit the floor. Contains 4 boxes of bodybags."
+ cost = 1200
+ contains = list(/obj/item/storage/box/bodybags,
+ /obj/item/storage/box/bodybags,
+ /obj/item/storage/box/bodybags,
+ /obj/item/storage/box/bodybags,)
+ crate_name = "bodybag crate"
+
/datum/supply_pack/medical/firstaidbruises
name = "Bruise Treatment Kit Crate"
desc = "Contains three first aid kits focused on healing bruises and broken bones."
@@ -1343,7 +1415,7 @@
/datum/supply_pack/science/adv_surgery_tools
name = "Med-Co Advanced surgery tools"
- desc = "A full set of Med-Co advanced surgery tools, this crate also comes with a spay of synth flesh as well as a can of . Requires Surgery access to open."
+ desc = "A full set of Med-Co advanced surgery tools, this crate both a can of synthflesh and a can of sterilizine. Requires Surgery access to open."
cost = 5000
access = ACCESS_SURGERY
contains = list(/obj/item/storage/belt/medical/surgery_belt_adv,
@@ -1494,6 +1566,37 @@
group = "Science"
crate_type = /obj/structure/closet/crate/science
+/datum/supply_pack/science/aliens
+ name = "Advanced Alien Alloy Crate Crate"
+ desc = "Hello brothers from the stars!!! Our fellow brethren have made contact at long last and gave us gifts man! They really did build the prymi- Connection Error- Bro we’ll send you a sheet of advanced alien alloy."
+ cost = 15000
+ contraband = TRUE
+ DropPodOnly = TRUE
+ contains = list(/obj/item/stack/sheet/mineral/abductor)
+ crate_name = "alien bro alloy crate"
+
+/datum/supply_pack/science/beakers
+ name = "Chemistry Beakers Crate"
+ desc = "Glassware for any chemistry lab! Contains four small beakers, three large, two plastic, and one metamaterial. As well as three droppers and two pairs of latex gloves."
+ cost = 2000
+ contains = list(/obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/reagent_containers/glass/beaker/plastic,
+ /obj/item/reagent_containers/glass/beaker/plastic,
+ /obj/item/reagent_containers/glass/beaker/meta,
+ /obj/item/reagent_containers/glass/beaker/noreact,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/clothing/gloves/color/latex,
+ /obj/item/clothing/gloves/color/latex)
+ crate_name = "chemistry beaker crate"
+
/datum/supply_pack/science/robotics/mecha_odysseus
name = "Circuit Crate (Odysseus)"
desc = "Ever wanted to build your own giant medical robot? Well, now you can! Contains the Odysseus main control board and Odysseus peripherals board. Requires Robotics access to open."
@@ -1525,6 +1628,15 @@
/obj/item/integrated_electronics/wirer)
crate_name = "circuitry starter pack crate"
+/datum/supply_pack/science/nitrilegloves
+ name = "Nitrile Gloves Crate"
+ desc = "Handling toxic chemicals? Well worry not, keep your flesh intact with some nitrile made gloves! Contains three pairs of nitrile gloves."
+ cost = 1500
+ contains = list(/obj/item/clothing/gloves/color/latex/nitrile,
+ /obj/item/clothing/gloves/color/latex/nitrile,
+ /obj/item/clothing/gloves/color/latex/nitrile)
+ crate_name = "nitrile gloves crate"
+
/datum/supply_pack/science/plasma
name = "Plasma Assembly Crate"
desc = "Everything you need to burn something to the ground, this contains three plasma assembly sets. Each set contains a plasma tank, igniter, proximity sensor, and timer! Warranty void if exposed to high temperatures. Requires Toxins access to open."
@@ -1572,10 +1684,19 @@
crate_name = "shield generators crate"
crate_type = /obj/structure/closet/crate/secure/science
+/datum/supply_pack/science/slime
+ name = "Slime Core Crate"
+ desc = "Ran out of slimes? No problem, contains one gray slime core. Requires Xenobio access to open."
+ cost = 1000
+ access = ACCESS_XENOBIOLOGY
+ contains = list(/obj/item/slime_extract/grey)
+ crate_name = "slime core crate"
+ crate_type = /obj/structure/closet/crate/secure/science
+
/datum/supply_pack/science/tablets
name = "Tablet Crate"
desc = "What's a computer? Contains five cargo tablets."
- cost = 5000
+ cost = 3000
contains = list(/obj/item/modular_computer/tablet/preset/cargo,
/obj/item/modular_computer/tablet/preset/cargo,
/obj/item/modular_computer/tablet/preset/cargo,
@@ -1622,6 +1743,20 @@
crate_name = "advanced lighting crate"
crate_type = /obj/structure/closet/crate/secure
+/datum/supply_pack/service/janitor/advanced
+ name = "Advanced Sanitation Crate"
+ desc = "Contains all the essentials for an advanced spacefaring cleanup crew. This kit includes a trashbag of holding, an advanced mop, a bottle of space cleaner, a floor buffer, and a holosign projector."
+ cost = 5000
+ access = ACCESS_JANITOR
+ contains = list(/obj/item/storage/bag/trash/bluespace,
+ /obj/item/reagent_containers/spray/cleaner,
+ /obj/item/mop/advanced,
+ /obj/item/lightreplacer,
+ /obj/item/janiupgrade,
+ /obj/item/holosign_creator)
+ crate_name = "advanced santation crate"
+ crate_type = /obj/structure/closet/crate/secure
+
/datum/supply_pack/service/cargo_supples
name = "Cargo Supplies Crate"
desc = "Sold everything that wasn't bolted down? You can get right back to work with this crate containing stamps, an export scanner, destination tagger, hand labeler and some package wrapping."
@@ -1658,6 +1793,65 @@
crate_name = "ice cream vat crate"
crate_type = /obj/structure/closet/crate
+/datum/supply_pack/service/buildabar
+ name = "Build a Bar Crate"
+ desc = "Looking to set up your own little safe haven? Maintenance bar too much of a bummer to work on? Maybe you just want to set up shop right in front of the bartender. Whatever your reasons, get a jump-start on this with this handy kit. Contains circuitboards for bar equipment, some parts, and some basic bartending supplies. (Batteries not Included)"
+ cost = 3750
+ contains = list(/obj/item/storage/box/drinkingglasses,
+ /obj/item/storage/box/drinkingglasses,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/capacitor,
+ /obj/item/stock_parts/capacitor,
+ /obj/item/stack/sheet/metal/ten,
+ /obj/item/stack/sheet/metal/five,
+ /obj/item/stack/sheet/glass/five,
+ /obj/item/stack/cable_coil/random,
+ /obj/item/reagent_containers/rag,
+ /obj/item/book/manual/wiki/barman_recipes,
+ /obj/item/book/granter/action/drink_fling,
+ /obj/item/reagent_containers/food/drinks/shaker,
+ /obj/item/clothing/under/waiter,
+ /obj/item/clothing/under/rank/bartender,
+ /obj/item/clothing/under/rank/bartender/skirt,
+ /obj/item/clothing/accessory/waistcoat,
+ /obj/item/circuitboard/machine/chem_dispenser/drinks/beer,
+ /obj/item/circuitboard/machine/chem_dispenser/drinks,
+ /obj/item/circuitboard/machine/dish_drive)
+ crate_name = "build a bar crate"
+
+/datum/supply_pack/service/maintgarden
+ name = "Maintenance Garden Crate"
+ desc = "Set up your own tiny paradise with do-it-yourself botany kit. Contains sandstone for dirt plots, pest spray, ammonia, a portable seed generator, basic botanical tools, and some seeds to start off with."
+ cost = 2350
+ contains = list(/obj/item/storage/bag/plants/portaseeder,
+ /obj/item/reagent_containers/spray/pestspray,
+ /obj/item/stack/sheet/mineral/sandstone/twelve,
+ /obj/item/reagent_containers/glass/bucket,
+ /obj/item/reagent_containers/glass/bottle/ammonia,
+ /obj/item/reagent_containers/glass/bottle/ammonia,
+ /obj/item/hatchet,
+ /obj/item/cultivator,
+ /obj/item/plant_analyzer,
+ /obj/item/flashlight,
+ /obj/item/seeds/carrot,
+ /obj/item/seeds/carrot,
+ /obj/item/seeds/tower,
+ /obj/item/seeds/tower,
+ /obj/item/seeds/watermelon,
+ /obj/item/seeds/watermelon,
+ /obj/item/seeds/grass,
+ /obj/item/seeds/grass)
+ crate_name = "maint garden crate"
+ crate_type = /obj/structure/closet/crate/hydroponics
+
/datum/supply_pack/service/janitor
name = "Janitorial Supplies Crate"
desc = "Fight back against dirt and grime with Nanotrasen's Janitorial Essentials(tm)! Contains three buckets, caution signs, and cleaner grenades. Also has a single mop, spray cleaner, rag, NT soap and a trash bag."
@@ -1974,6 +2168,25 @@
/obj/item/reagent_containers/food/snacks/grown/banana)
crate_name = "food crate"
+/datum/supply_pack/organic/fiestatortilla
+ name = "Fiesta Crate"
+ desc = "Spice up the kitchen with this fiesta themed food order! Contains 8 tortilla based food items, as well as a sombrero, moustache, and cloak!"
+ cost = 2750
+ contains = list(/obj/item/clothing/head/sombrero,
+ /obj/item/clothing/suit/hooded/cloak/david,
+ /obj/item/clothing/mask/fakemoustache,
+ /obj/item/reagent_containers/food/snacks/taco,
+ /obj/item/reagent_containers/food/snacks/taco,
+ /obj/item/reagent_containers/food/snacks/taco/plain,
+ /obj/item/reagent_containers/food/snacks/taco/plain,
+ /obj/item/reagent_containers/food/snacks/enchiladas,
+ /obj/item/reagent_containers/food/snacks/enchiladas,
+ /obj/item/reagent_containers/food/snacks/carneburrito,
+ /obj/item/reagent_containers/food/snacks/cheesyburrito,
+ /obj/item/reagent_containers/glass/bottle/capsaicin,
+ /obj/item/reagent_containers/glass/bottle/capsaicin)
+ crate_name = "fiesta crate"
+
/datum/supply_pack/organic/cream_piee
name = "High-yield Clown-grade Cream Pie Crate"
desc = "Designed by Aussec's Advanced Warfare Research Division, these high-yield, Clown-grade cream pies are powered by a synergy of performance and efficiency. Guaranteed to provide maximum results."
@@ -1985,8 +2198,8 @@
crate_type = /obj/structure/closet/crate/secure
/datum/supply_pack/organic/hunting
- name = "Huntting gear"
- desc = "Even in space, we can fine prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a huntting shotgun. "
+ name = "Hunting gear"
+ desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. "
cost = 3500
contraband = TRUE
contains = list(/obj/item/clothing/head/flatcap,
@@ -2000,6 +2213,42 @@
crate_name = "sporting crate"
crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
+/datum/supply_pack/organic/fakemeat
+ name = "Meat Crate"
+ desc = "Run outta meat already? Keep the lizards content with this freezer filled with cruelty-free chemically compounded meat! Contains 4 slabs of meat product, and two slabs of *carp*."
+ cost = 1700
+ contains = list(/obj/item/reagent_containers/food/snacks/meat/slab/meatproduct,
+ /obj/item/reagent_containers/food/snacks/meat/slab/meatproduct,
+ /obj/item/reagent_containers/food/snacks/meat/slab/meatproduct,
+ /obj/item/reagent_containers/food/snacks/meat/slab/meatproduct,
+ /obj/item/reagent_containers/food/snacks/carpmeat/imitation,
+ /obj/item/reagent_containers/food/snacks/carpmeat/imitation)
+ crate_name = "meaty crate"
+ crate_type = /obj/structure/closet/crate/freezer
+
+/datum/supply_pack/organic/monkeydripmeat
+ name = "*Meat* Crate"
+ desc = "Need some meat? With this do-it-yourself kit you'll be swimming in it! Contains a monkey cube, an IV drip, and some cryoxadone!"
+ cost = 2150
+ contraband = TRUE
+ contains = list(/obj/item/reagent_containers/food/snacks/monkeycube,
+ /obj/item/restraints/handcuffs/cable,
+ /obj/machinery/iv_drip,
+ /obj/item/reagent_containers/glass/beaker/cryoxadone,
+ /obj/item/reagent_containers/glass/beaker/cryoxadone)
+ crate_name = "monkey meat crate"
+
+/datum/supply_pack/organic/mixedboxes
+ name = "Mixed Ingredient Boxes"
+ desc = "Get overwhelmed with inspiration by ordering these boxes of surprise ingredients! Get four boxes filled with an assortment of products!"
+ cost = 2300
+ contains = list(/obj/item/storage/box/ingredients/wildcard,
+ /obj/item/storage/box/ingredients/wildcard,
+ /obj/item/storage/box/ingredients/wildcard,
+ /obj/item/storage/box/ingredients/wildcard)
+ crate_name = "wildcard food crate"
+ crate_type = /obj/structure/closet/crate/freezer
+
/datum/supply_pack/organic/hydroponics
name = "Hydroponics Crate"
desc = "Supplies for growing a great garden! Contains two bottles of ammonia, two Plant-B-Gone spray bottles, a hatchet, cultivator, plant analyzer, as well as a pair of leather gloves and a botanist's apron."
@@ -2124,6 +2373,21 @@
crate_name = "valentine crate"
crate_type = /obj/structure/closet/crate/secure
+/datum/supply_pack/organic/strangeseeds
+ name = "Strange Seeds Crate"
+ desc = "After our chemical waste mysteriously disappeared we've discovered many strange and interesting species of plants, and they're yours for the taking! Contains 8 packs of strange seeds."
+ cost = 4500
+ contains = list(/obj/item/seeds/random,
+ /obj/item/seeds/random,
+ /obj/item/seeds/random,
+ /obj/item/seeds/random,
+ /obj/item/seeds/random,
+ /obj/item/seeds/random,
+ /obj/item/seeds/random,
+ /obj/item/seeds/random)
+ crate_name = "strange seeds crate"
+ crate_type = /obj/structure/closet/crate/hydroponics
+
/datum/supply_pack/organic/exoticseeds
name = "Exotic Seeds Crate"
desc = "Any entrepreneuring botanist's dream. Contains twelve different seeds, including three replica-pod seeds and two mystery seeds!"
@@ -2276,6 +2540,18 @@
/mob/living/simple_animal/hostile/retaliate/poison/snake)
crate_name = "snake crate"
+/datum/supply_pack/critter/mouse
+ name = "Mouse Crate"
+ desc = "Good for snakes and lizards of all ages. Contains ~12 feeder mice."
+ cost = 2000
+ contains = list(/mob/living/simple_animal/mouse,)
+ crate_name = "mouse crate"
+
+/datum/supply_pack/critter/mouse/generate()
+ . = ..()
+ for(var/i in 1 to 11)
+ new /mob/living/simple_animal/mouse(.)
+
/datum/supply_pack/critter/secbat
name = "Security Bat Crate"
desc = "Contains five security bats, perfect to Bat-up any security officer."
@@ -2648,7 +2924,10 @@
name = "Kinkmate construction kit"
cost = 2000
contraband = TRUE
- contains = list(/obj/item/vending_refill/kink, /obj/item/circuitboard/machine/kinkmate)
+ contains = list(/obj/item/vending_refill/kink,
+ /obj/item/vending_refill/kink,
+ /obj/item/vending_refill/kink,
+ /obj/item/circuitboard/machine/kinkmate)
crate_name = "Kinkmate construction kit"
//////////////////////////////////////////////////////////////////////////////
@@ -2687,6 +2966,51 @@
crate_name = "captain pen"
crate_type = /obj/structure/closet/crate/secure/weapon //It is a combat pen
+/datum/supply_pack/misc/exoticfootwear
+ name = "Exotic Footwear Crate"
+ desc = "Popularised by lizards and exotic dancers, the footwear included in this shipment is sure to give your feet the breathing room they deserve. Sweet Kicks Inc. is not responsible for any damage, distress, or @r0u$a1 caused by this shipment."
+ cost = 3000
+ contains = list(/obj/item/clothing/shoes/wraps,
+ /obj/item/clothing/shoes/wraps,
+ /obj/item/clothing/shoes/wraps/silver,
+ /obj/item/clothing/shoes/wraps/silver,
+ /obj/item/clothing/shoes/wraps/red,
+ /obj/item/clothing/shoes/wraps/red,
+ /obj/item/clothing/shoes/wraps/blue,
+ /obj/item/clothing/shoes/wraps/blue,
+ /obj/item/clothing/shoes/clown_shoes,
+ /obj/item/clothing/shoes/kindleKicks)
+ crate_name = "footie crate"
+
+/datum/supply_pack/misc/randombedsheets
+ name = "Bedsheet Crate (R)"
+ desc = "Snuggle up in some sweet sheets with this assorted bedsheet crate. Each set comes with eight random bedsheets for your slumbering pleasure!"
+ cost = 2000
+ contains = list(/obj/item/bedsheet/random,
+ /obj/item/bedsheet/random,
+ /obj/item/bedsheet/random,
+ /obj/item/bedsheet/random,
+ /obj/item/bedsheet/random,
+ /obj/item/bedsheet/random,
+ /obj/item/bedsheet/random,
+ /obj/item/bedsheet/random) //I'm lazy, and I copy paste stuff.
+ crate_name = "random bedsheet crate"
+
+/datum/supply_pack/misc/coloredsheets
+ name = "Bedsheet Crate (C)"
+ desc = "Give your night life a splash of color with this crate filled with bedsheets! Contains a total of nine different-colored sheets."
+ cost = 1250
+ contains = list(/obj/item/bedsheet/blue,
+ /obj/item/bedsheet/green,
+ /obj/item/bedsheet/orange,
+ /obj/item/bedsheet/purple,
+ /obj/item/bedsheet/red,
+ /obj/item/bedsheet/yellow,
+ /obj/item/bedsheet/brown,
+ /obj/item/bedsheet/black,
+ /obj/item/bedsheet/rainbow)
+ crate_name = "colored bedsheet crate"
+
/datum/supply_pack/misc/bicycle
name = "Bicycle"
desc = "Nanotrasen reminds all employees to never toy with powers outside their control."
@@ -2722,6 +3046,36 @@
/obj/item/book/random/triple)
crate_type = /obj/structure/closet/crate/wooden
+/datum/supply_pack/misc/cbtpack
+ name = "CBT Equipment"
+ desc = "(*!&@#CBT is a special term coined by high ranking syndicate operatives for a special form of information extraction. While the training required to use this shipment is highly classified, the distribution of it's contents are not. In addition to this crates unusual contents, we have added a bar of soap.#@*$"
+ hidden = TRUE
+ cost = 2400
+ contains = list(/mob/living/simple_animal/chicken,
+ /obj/item/toy/beach_ball/holoball,
+ /obj/item/melee/baton/cattleprod,
+ /obj/item/soap/syndie)
+ crate_name = "cbt crate"
+ crate_type = /obj/structure/closet/crate/large
+
+/datum/supply_pack/misc/casinocrate
+ name = "Casino Crate"
+ desc = "Start up your own grand casino with this crate filled with slot machine and arcade boards!"
+ cost = 3000
+ contains = list(/obj/item/circuitboard/computer/arcade/battle,
+ /obj/item/circuitboard/computer/arcade/battle,
+ /obj/item/circuitboard/computer/arcade/orion_trail,
+ /obj/item/circuitboard/computer/arcade/orion_trail,
+ /obj/item/circuitboard/computer/arcade/minesweeper,
+ /obj/item/circuitboard/computer/arcade/minesweeper,
+ /obj/item/circuitboard/computer/slot_machine,
+ /obj/item/circuitboard/computer/slot_machine,
+ /obj/item/circuitboard/computer/slot_machine,
+ /obj/item/circuitboard/computer/slot_machine,
+ /obj/item/circuitboard/computer/slot_machine,
+ /obj/item/circuitboard/computer/slot_machine)
+ crate_name = "casino crate"
+
/datum/supply_pack/misc/paper
name = "Bureaucracy Crate"
desc = "High stacks of papers on your desk Are a big problem - make it Pea-sized with these bureaucratic supplies! Contains five pens, some camera film, hand labeler supplies, a paper bin, three folders, two clipboards and two stamps as well as a briefcase."//that was too forced
@@ -2804,11 +3158,13 @@
/datum/supply_pack/misc/lewd
name = "Lewd Crate" // OwO
- desc = "Psss want to have a good time with your sluts? Well I got what you want maid clothing, dildos, collars and more!"
+ desc = "Psss want to have a good time with your sluts? Well I got what you want! Maid clothing, dildos, collars and more!"
cost = 5000
contraband = TRUE
contains = list(/obj/item/dildo/custom,
/obj/item/dildo/custom,
+ /obj/item/circuitboard/machine/kinkmate,
+ /obj/item/vending_refill/kink,
/obj/item/vending_refill/kink,
/obj/item/vending_refill/kink,
/obj/item/clothing/under/maid,
@@ -2859,6 +3215,33 @@
/obj/item/autosurgeon/womb)
crate_name = "promiscuous organs"
+/datum/supply_pack/misc/shower
+ name = "Shower Supplies"
+ desc = "Everyone needs a bit of R&R. Make sure you get can get yours by ordering this crate filled with towels, rubber duckies, and some soap!"
+ cost = 1000
+ contains = list(/obj/item/reagent_containers/rag/towel,
+ /obj/item/reagent_containers/rag/towel,
+ /obj/item/reagent_containers/rag/towel,
+ /obj/item/reagent_containers/rag/towel,
+ /obj/item/reagent_containers/rag/towel,
+ /obj/item/reagent_containers/rag/towel,
+ /obj/item/bikehorn/rubberducky,
+ /obj/item/bikehorn/rubberducky,
+ /obj/item/soap/nanotrasen)
+ crate_name = "shower crate"
+
+/datum/supply_pack/misc/spacehermitstarter
+ name = "Space Hermit Starter Pack"
+ desc = "So sick of the station you wish to leave and never come back? Or perhaps you need to find a place of solitutde and privacy? Jumping out of an external airlock may just be the solution for you! But not before you buy this crate - contains a mining hardsuit, a proto-kinetic accelerator, GPS, luxury bluespace shelter aswell as a deluxe bluespace shelter.(Jetpack not included)"
+ cost = 5000
+ contraband = TRUE
+ contains = list(/obj/item/clothing/suit/space/hardsuit/mining,
+ /obj/item/gun/energy/kinetic_accelerator,
+ /obj/item/survivalcapsule/deluxe,
+ /obj/item/survivalcapsule/luxury,
+ /obj/item/gps)
+ crate_name = "space hermit crate"
+
/datum/supply_pack/misc/toner
name = "Toner Crate"
desc = "Spent too much ink printing butt pictures? Fret not, with these six toner refills, you'll be printing butts 'till the cows come home!'"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index d992df6f..906207c0 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -357,8 +357,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
"
dat += "Flavor Text"
dat += "Set Examine Text "
- if(lentext(features["flavor_text"]) <= 40)
- if(!lentext(features["flavor_text"]))
+ if(length(features["flavor_text"]) <= 40)
+ if(!length(features["flavor_text"]))
dat += "\[...\]"
else
dat += "[features["flavor_text"]]"
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 4659de3e..1fe70f47 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -69,7 +69,7 @@
/obj/item/clothing/shoes/clown_shoes
desc = "The prankster's standard-issue clowning shoes. Damn, they're huge!"
name = "clown shoes"
- icon_state = "clown"
+ icon_state = "clown_shoes"
item_state = "clown_shoes"
slowdown = SHOES_SLOWDOWN+1
item_color = "clown"
@@ -312,3 +312,24 @@
set_light(0)
lightCycle = 0
active = FALSE
+
+/obj/item/clothing/shoes/wraps
+ name = "gilded leg wraps"
+ desc = "Ankle coverings. These ones have a golden design."
+ icon_state = "gildedcuffs"
+ body_parts_covered = FALSE
+
+/obj/item/clothing/shoes/wraps/silver
+ name = "silver leg wraps"
+ desc = "Ankle coverings. Not made of real silver."
+ icon_state = "silvergildedcuffs"
+
+/obj/item/clothing/shoes/wraps/red
+ name = "red leg wraps"
+ desc = "Ankle coverings. Show off your style with these shiny red ones!"
+ icon_state = "redcuffs"
+
+/obj/item/clothing/shoes/wraps/blue
+ name = "blue leg wraps"
+ desc = "Ankle coverings. Hang ten, brother."
+ icon_state = "bluecuffs"
\ No newline at end of file
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 2811168f..7fe2b758 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -636,11 +636,24 @@
/datum/crafting_recipe/wheelchair
name = "Wheelchair"
result = /obj/vehicle/ridden/wheelchair
- reqs = list(/obj/item/stack/sheet/plasteel = 2,
+ reqs = list(/obj/item/stack/sheet/metal = 10,
/obj/item/stack/rods = 8)
time = 100
category = CAT_MISC
+/datum/crafting_recipe/motorized_wheelchair
+ name = "Motorized Wheelchair"
+ result = /obj/vehicle/ridden/wheelchair/motorized
+ reqs = list(/obj/item/stack/sheet/metal = 10,
+ /obj/item/stack/rods = 8,
+ /obj/item/stock_parts/manipulator = 2,
+ /obj/item/stock_parts/capacitor = 1)
+ parts = list(/obj/item/stock_parts/manipulator = 2,
+ /obj/item/stock_parts/capacitor = 1)
+ tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH)
+ time = 200
+ category = CAT_MISC
+
/datum/crafting_recipe/rcl
name = "Makeshift Rapid Cable Layer"
result = /obj/item/twohanded/rcl/ghetto
@@ -963,3 +976,11 @@
time = 60
always_availible = TRUE
category = CAT_CLOTHING
+
+/datum/crafting_recipe/coconut_bong
+ name = "Coconut Bong"
+ result = /obj/item/bong/coconut
+ reqs = list(/obj/item/stack/sheet/mineral/bamboo = 2,
+ /obj/item/reagent_containers/food/snacks/grown/coconut = 1)
+ time = 70
+ category = CAT_MISC
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index b8f937d8..a61063dc 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -14,6 +14,7 @@
volume = 50
resistance_flags = NONE
var/isGlass = TRUE //Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it
+ splashable = TRUE
/obj/item/reagent_containers/food/drinks/on_reagent_change(changetype)
if (gulp_size < 5)
@@ -104,6 +105,7 @@
/obj/item/reagent_containers/food/drinks/throw_impact(atom/target, datum/thrownthing/throwinfo)
. = ..()
if(!.) //if the bottle wasn't caught
+ SplashReagents(target)
smash(target, throwinfo.thrower, TRUE)
/obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE)
diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
index 7c44857b..a74f73ed 100644
--- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm
+++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm
@@ -794,4 +794,25 @@
name = "Red Queen"
id = "red_queen"
results = list("red_queen" = 10)
- required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1)
\ No newline at end of file
+ required_reagents = list("tea" = 6, "mercury" = 2, "blackpepper" = 1, "growthserum" = 1)
+
+/datum/chemical_reaction/gunfire
+ name = "Gunfire"
+ id = "gunfire"
+ results = list("gunfire" = 4)
+ required_reagents = list("rum" = 1, "tea" = 3)
+ mix_message = "A loud popping begins to fill the air as the drink is mixed."
+
+/datum/chemical_reaction/hellfire
+ name = "Hellfire"
+ id = "hellfire"
+ results = list("hellfire" = 5)
+ required_reagents = list("rum" = 1, "beer" = 1, "ice" = 1, "capsaicin" = 1, "limejuice" = 1)
+ mix_message = "The liquid begins to churn as it changes to an amber orange and catches on fire."
+
+/datum/chemical_reaction/sins_delight
+ name = "Sins Delight"
+ id = "sins_delight"
+ results = list("sins_delight" = 5)
+ required_reagents = list("demonsblood" = 2, "triple_sec" = 1, "martini" = 1, "changelingsting" = 1)
+ mix_message = "The liquid starts swirling, before forming a pink cloud that dissipates in the air."
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
index e26d15db..391a37d5 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
@@ -69,8 +69,9 @@
/datum/crafting_recipe/food/birthdaycake
name = "Birthday cake"
reqs = list(
- /obj/item/clothing/head/hardhat/cakehat = 1,
- /obj/item/reagent_containers/food/snacks/store/cake/plain = 1
+ /obj/item/reagent_containers/food/snacks/store/cake/plain = 1,
+ /obj/item/candle = 1,
+ /datum/reagent/consumable/sugar = 5,
)
result = /obj/item/reagent_containers/food/snacks/store/cake/birthday
subcategory = CAT_CAKE
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index 39b1908c..8695bf2c 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -240,7 +240,7 @@
dat += " |
"
else
dat += "No trait-related genes detected in sample.
"
- if(can_insert && istype(disk.gene, /datum/plant_gene/trait))
+ if(can_insert && istype(disk.gene, /datum/plant_gene/trait) && !seed.is_gene_forbidden(disk.gene))
dat += "
Insert: [disk.gene.get_name()]"
dat += "
"
else
diff --git a/code/modules/hydroponics/grown/berries.dm b/code/modules/hydroponics/grown/berries.dm
index e9ad49ee..a16ce949 100644
--- a/code/modules/hydroponics/grown/berries.dm
+++ b/code/modules/hydroponics/grown/berries.dm
@@ -90,7 +90,7 @@
lifespan = 30
endurance = 25
mutatelist = list()
- genes = list(/datum/plant_gene/trait/glow/berry , /datum/plant_gene/trait/noreact, /datum/plant_gene/trait/repeated_harvest)
+ genes = list(/datum/plant_gene/trait/glow/white , /datum/plant_gene/trait/noreact, /datum/plant_gene/trait/repeated_harvest)
reagents_add = list("uranium" = 0.25, "iodine" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
rarity = 20
@@ -121,8 +121,9 @@
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
icon_grow = "cherry-grow"
icon_dead = "cherry-dead"
+ icon_harvest = "cherry-harvest"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- mutatelist = list(/obj/item/seeds/cherry/blue)
+ mutatelist = list(/obj/item/seeds/cherry/blue, /obj/item/seeds/cherry/bulb)
reagents_add = list("nutriment" = 0.07, "sugar" = 0.07)
/obj/item/reagent_containers/food/snacks/grown/cherries
@@ -162,6 +163,31 @@
tastes = list("blue cherry" = 1)
wine_power = 50
+//Cherry Bulbs
+/obj/item/seeds/cherry/bulb
+ name = "pack of cherry bulb pits"
+ desc = "The glowy kind of cherries."
+ icon_state = "seed-cherrybulb"
+ species = "cherrybulb"
+ plantname = "Cherry Bulb Tree"
+ product = /obj/item/reagent_containers/food/snacks/grown/cherrybulbs
+ genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/pink)
+ mutatelist = list()
+ reagents_add = list("nutriment" = 0.07, "sugar" = 0.07)
+ rarity = 10
+
+/obj/item/reagent_containers/food/snacks/grown/cherrybulbs
+ seed = /obj/item/seeds/cherry/bulb
+ name = "cherry bulbs"
+ desc = "They're like little Space Christmas lights!"
+ icon_state = "cherry_bulb"
+ filling_color = "#FF0000"
+ bitesize_mod = 2
+ foodtype = FRUIT
+ grind_results = list(/datum/reagent/consumable/cherryjelly = 0)
+ tastes = list("cherry" = 1)
+ wine_power = 50
+
// Grapes
/obj/item/seeds/grape
name = "pack of grape seeds"
@@ -224,6 +250,10 @@
species = "strawberry"
plantname = "Strawberry Vine"
product = /obj/item/reagent_containers/food/snacks/grown/strawberry
+ growthstages = 6
+ growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
+ icon_grow = "strawberry-grow"
+ icon_dead = "berry-dead"
reagents_add = list("vitamin" = 0.07, "nutriment" = 0.1, "sugar" = 0.2)
mutatelist = list()
diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm
index 97b30aec..5209c090 100644
--- a/code/modules/hydroponics/grown/citrus.dm
+++ b/code/modules/hydroponics/grown/citrus.dm
@@ -49,7 +49,7 @@
icon_grow = "lime-grow"
icon_dead = "lime-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- mutatelist = list(/obj/item/seeds/lime)
+ mutatelist = list(/obj/item/seeds/lime, /obj/item/seeds/orange_3d)
reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05)
/obj/item/reagent_containers/food/snacks/grown/citrus/orange
@@ -61,6 +61,42 @@
juice_results = list("orangejuice" = 0)
distill_reagent = "triple_sec"
+//3D Orange
+/obj/item/seeds/orange_3d
+ name = "pack of extradimensional orange seeds"
+ desc = "Polygonal seeds."
+ icon_state = "seed-orange"
+ species = "orange"
+ plantname = "Extradimensional Orange Tree"
+ product = /obj/item/reagent_containers/food/snacks/grown/citrus/orange
+ lifespan = 60
+ endurance = 50
+ yield = 5
+ potency = 20
+ growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
+ icon_grow = "lime-grow"
+ icon_dead = "lime-dead"
+ genes = list(/datum/plant_gene/trait/repeated_harvest)
+ reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05, "haloperidol" = 0.15)
+
+/obj/item/reagent_containers/food/snacks/grown/citrus/orange_3d
+ seed = /obj/item/seeds/orange
+ name = "extradminesional orange"
+ desc = "You can hardly wrap your head around this thing."
+ icon_state = "orang"
+ filling_color = "#FFA500"
+ juice_results = list("orangejuice" = 0)
+ distill_reagent = "triple_sec"
+ tastes = list("polygons" = 1, "oranges" = 1)
+
+/obj/item/reagent_containers/food/snacks/grown/citrus/orange_3d/pickup(mob/user)
+ . = ..()
+ icon_state = "orange"
+
+/obj/item/reagent_containers/food/snacks/grown/citrus/orange_3d/dropped(mob/user)
+ . = ..()
+ icon_state = "orang"
+
// Lemon
/obj/item/seeds/lemon
name = "pack of lemon seeds"
diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm
index 9661f38d..705c7562 100644
--- a/code/modules/hydroponics/grown/flowers.dm
+++ b/code/modules/hydroponics/grown/flowers.dm
@@ -183,6 +183,7 @@
icon_grow = "moonflower-grow"
icon_dead = "sunflower-dead"
product = /obj/item/reagent_containers/food/snacks/grown/moonflower
+ genes = list(/datum/plant_gene/trait/glow/purple)
mutatelist = list()
reagents_add = list("moonshine" = 0.2, "vitamin" = 0.02, "nutriment" = 0.02)
rarity = 15
@@ -293,8 +294,8 @@
/obj/item/seeds/bee_balm/honey
name = "pack of Honey Balm seeds"
desc = "These seeds grow into Honey Balms."
- icon_state = "seed-bee_balmalt"
- species = "seed-bee_balm_alt"
+ icon_state = "seed-bee_balm_alt"
+ species = "bee_balmalt"
plantname = "Honey Balm Pods"
product = /obj/item/reagent_containers/food/snacks/grown/bee_balm/honey
endurance = 1
diff --git a/code/modules/hydroponics/grown/grass_carpet.dm b/code/modules/hydroponics/grown/grass_carpet.dm
index 1a1c2ac0..08ce71ad 100644
--- a/code/modules/hydroponics/grown/grass_carpet.dm
+++ b/code/modules/hydroponics/grown/grass_carpet.dm
@@ -15,7 +15,7 @@
icon_grow = "grass-grow"
icon_dead = "grass-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- mutatelist = list(/obj/item/seeds/grass/carpet)
+ mutatelist = list(/obj/item/seeds/grass/carpet, /obj/item/seeds/grass/fairy)
reagents_add = list("nutriment" = 0.02, "hydrogen" = 0.05)
/obj/item/reagent_containers/food/snacks/grown/grass
@@ -40,6 +40,27 @@
new stacktype(user.drop_location(), grassAmt)
qdel(src)
+//Fairygrass
+/obj/item/seeds/grass/fairy
+ name = "pack of fairygrass seeds"
+ desc = "These seeds grow into a more mystical grass."
+ icon_state = "seed-fairygrass"
+ species = "fairygrass"
+ plantname = "Fairygrass"
+ product = /obj/item/reagent_containers/food/snacks/grown/grass/fairy
+ icon_grow = "fairygrass-grow"
+ icon_dead = "fairygrass-dead"
+ genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/blue)
+ reagents_add = list("nutriment" = 0.02, "hydrogen" = 0.05, "space_drugs" = 0.15)
+
+/obj/item/reagent_containers/food/snacks/grown/grass/fairy
+ seed = /obj/item/seeds/grass/fairy
+ name = "fairygrass"
+ desc = "Blue, glowing, and smells fainly of mushrooms."
+ icon_state = "fairygrassclump"
+ filling_color = "#3399ff"
+ stacktype = /obj/item/stack/tile/fairygrass
+
// Carpet
/obj/item/seeds/grass/carpet
name = "pack of carpet seeds"
diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm
index 29691c32..f74a763b 100644
--- a/code/modules/hydroponics/grown/melon.dm
+++ b/code/modules/hydroponics/grown/melon.dm
@@ -44,6 +44,7 @@
species = "holymelon"
plantname = "Holy Melon Vines"
product = /obj/item/reagent_containers/food/snacks/grown/holymelon
+ genes = list(/datum/plant_gene/trait/glow/yellow)
mutatelist = list()
reagents_add = list("holywater" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
rarity = 20
diff --git a/code/modules/hydroponics/grown/misc.dm b/code/modules/hydroponics/grown/misc.dm
index 641a5edc..879f71cd 100644
--- a/code/modules/hydroponics/grown/misc.dm
+++ b/code/modules/hydroponics/grown/misc.dm
@@ -142,6 +142,7 @@
yield = 4
growthstages = 3
reagents_add = list("sugar" = 0.25)
+ mutatelist = list(/obj/item/seeds/bamboo)
/obj/item/reagent_containers/food/snacks/grown/sugarcane
seed = /obj/item/seeds/sugarcane
@@ -239,3 +240,282 @@
product = /obj/item/reagent_containers/food/snacks/grown/ash_flora/cactus_fruit
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
growthstages = 2
+
+// Coconut
+/obj/item/seeds/coconut
+ name = "pack of coconut seeds"
+ desc = "They're seeds that grow into coconut palm trees."
+ icon_state = "seed-coconut"
+ species = "coconut"
+ plantname = "Coconut Palm Tree"
+ product = /obj/item/reagent_containers/food/snacks/grown/coconut
+ lifespan = 50
+ endurance = 30
+ potency = 35
+ growing_icon = 'icons/obj/hydroponics/growing.dmi'
+ icon_dead = "coconut-dead"
+ genes = list(/datum/plant_gene/trait/repeated_harvest)
+ forbiddengenes = list(/datum/plant_gene/trait/squash, /datum/plant_gene/trait/stinging)
+ reagents_add = list("coconutmilk" = 0.3)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut
+ seed = /obj/item/seeds/coconut
+ name = "coconut"
+ desc = "Hard shell of a nut containing delicious milk inside. Perhaps try using something sharp?"
+ icon_state = "coconut"
+ item_state = "coconut"
+ possible_transfer_amounts = list(5, 10, 15, 20, 25, 30, 50)
+ spillable = FALSE
+ resistance_flags = ACID_PROOF
+ volume = 150 //so it won't cut reagents despite having the capacity for them
+ w_class = WEIGHT_CLASS_SMALL
+ force = 5
+ throwforce = 5
+ hitsound = 'sound/weapons/klonk.ogg'
+ attack_verb = list("klonked", "donked", "bonked")
+ var/opened = FALSE
+ var/carved = FALSE
+ var/chopped = FALSE
+ var/straw = FALSE
+ var/fused = FALSE
+ var/fusedactive = FALSE
+ var/defused = FALSE
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/Initialize(mapload, obj/item/seeds/new_seed)
+ . = ..()
+ var/newvolume
+ newvolume = 50 + round(seed.potency,10)
+ if (seed.get_gene(/datum/plant_gene/trait/maxchem))
+ newvolume = newvolume + 50
+ volume = newvolume
+ reagents.maximum_volume = newvolume
+ reagents.update_total()
+
+ transform *= TRANSFORM_USING_VARIABLE(40, 100) + 0.5 //temporary fix for size?
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/attack_self(mob/user)
+ if (opened == TRUE)
+ if(possible_transfer_amounts.len)
+ var/i=0
+ for(var/A in possible_transfer_amounts)
+ i++
+ if(A == amount_per_transfer_from_this)
+ if(i
[src]'s transfer amount is now [amount_per_transfer_from_this] units.")
+ return
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/attackby(obj/item/W, mob/user, params)
+ //DEFUSING NADE LOGIC
+ if (W.tool_behaviour == TOOL_WIRECUTTER && fused == TRUE)
+ user.show_message("You cut the fuse!", 1)
+ playsound(user, W.hitsound, 50, 1, -1)
+ icon_state = "coconut_carved"
+ desc = "A coconut. This one's got a hole in it."
+ name = "coconut"
+ defused = TRUE
+ fused = FALSE
+ fusedactive = FALSE
+ if(!seed.get_gene(/datum/plant_gene/trait/glow))
+ set_light(0, 0.0)
+ return
+ //IGNITING NADE LOGIC
+ if(fusedactive == FALSE && fused == TRUE)
+ var/lighting_text = W.ignition_effect(src, user)
+ if(lighting_text)
+ user.visible_message("[user] ignites [src]'s fuse!", "You ignite the [src]'s fuse!")
+ fusedactive = TRUE
+ defused = FALSE
+ playsound(src, 'sound/effects/fuse.ogg', 100, 0)
+ message_admins("[ADMIN_LOOKUPFLW(user)] ignited a coconut bomb for detonation at [ADMIN_VERBOSEJMP(user)] "+ pretty_string_from_reagent_list(reagents.reagent_list))
+ log_game("[key_name(user)] primed a coconut grenade for detonation at [AREACOORD(user)].")
+ addtimer(CALLBACK(src, .proc/prime), 5 SECONDS)
+ icon_state = "coconut_grenade_active"
+ desc = "RUN!"
+ if(!seed.get_gene(/datum/plant_gene/trait/glow))
+ light_color = "#FFCC66" //for the fuse
+ set_light(3, 0.8)
+ return
+
+ //ADDING A FUSE, NADE LOGIC
+ if (istype(W,/obj/item/stack/sheet/cloth) || istype(W,/obj/item/stack/sheet/durathread))
+ if (carved == TRUE && straw == FALSE && fused == FALSE)
+ user.show_message("You add a fuse to the coconut!", 1)
+ W.use(1)
+ fused = TRUE
+ icon_state = "coconut_grenade"
+ desc = "A makeshift bomb made out of a coconut. You estimate the fuse is long enough for 5 seconds."
+ name = "coconut bomb"
+ return
+ //ADDING STRAW LOGIC
+ if (istype(W,/obj/item/stack/sheet/mineral/bamboo) && opened == TRUE && straw == FALSE && fused == FALSE)
+ user.show_message("You add a bamboo straw to the coconut!", 1)
+ straw = TRUE
+ W.use(1)
+ icon_state += "_straw"
+ desc = "You can already feel like you're on a tropical vacation."
+ //OPENING THE NUT LOGIC
+ if (carved == FALSE && chopped == FALSE)
+ if(W.tool_behaviour == TOOL_SCREWDRIVER)
+ user.show_message("You make a hole in the coconut!", 1)
+ carved = TRUE
+ opened = TRUE
+ reagent_flags = OPENCONTAINER
+ ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
+ icon_state = "coconut_carved"
+ desc = "A coconut. This one's got a hole in it."
+ playsound(user, W.hitsound, 50, 1, -1)
+ return
+ else if(W.sharpness)
+ user.show_message("You slice the coconut open!", 1)
+ chopped = TRUE
+ opened = TRUE
+ reagent_flags = OPENCONTAINER
+ ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
+ spillable = TRUE
+ icon_state = "coconut_chopped"
+ desc = "A coconut. This one's sliced open, with all its delicious contents for your eyes to savour."
+ playsound(user, W.hitsound, 50, 1, -1)
+ return
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/attack(mob/living/M, mob/user, obj/target)
+ if(M && user.a_intent == INTENT_HARM && spillable == FALSE)
+ var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at
+ if (affecting == BODY_ZONE_HEAD && prob(15))
+ //smash the nut open
+ var/armor_block = min(90, M.run_armor_check(affecting, "melee", null, null,armour_penetration)) // For normal attack damage
+ M.apply_damage(force, BRUTE, affecting, armor_block)
+
+ //Sound
+ playsound(user, hitsound, 100, 1, -1)
+
+ //Attack logs
+ log_combat(user, M, "attacked", src)
+
+ //Display an attack message.
+ if(M != user)
+ M.visible_message("[user] has cracked open a [src.name] on [M]'s head!", \
+ "[user] has cracked open a [src.name] on [M]'s head!")
+ else
+ user.visible_message("[M] cracks open a [src.name] on their [M.p_them()] head!", \
+ "[M] cracks open a [src.name] on [M.p_their()] head!")
+
+ //The coconut breaks open so splash its reagents
+ spillable = TRUE
+ SplashReagents(M)
+
+ //Lastly we remove the nut
+ qdel(src)
+ else
+ . = ..()
+ return
+
+ if(fusedactive)
+ return
+
+ if(opened == FALSE)
+ return
+
+ if(!canconsume(M, user))
+ return
+
+ if(!reagents || !reagents.total_volume)
+ to_chat(user, "[src] is empty!")
+ return
+
+ if(istype(M))
+ if(user.a_intent == INTENT_HARM && spillable == TRUE)
+ var/R
+ M.visible_message("[user] splashes the contents of [src] onto [M]!", \
+ "[user] splashes the contents of [src] onto [M]!")
+ if(reagents)
+ for(var/datum/reagent/A in reagents.reagent_list)
+ R += A.id + " ("
+ R += num2text(A.volume) + "),"
+ if(isturf(target) && reagents.reagent_list.len && thrownby)
+ log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]")
+ message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] at [ADMIN_VERBOSEJMP(target)].")
+ reagents.reaction(M, TOUCH)
+ log_combat(user, M, "splashed", R)
+ reagents.clear_reagents()
+ else
+ if(M != user)
+ M.visible_message("[user] attempts to feed something to [M].", \
+ "[user] attempts to feed something to you.")
+ if(!do_mob(user, M))
+ return
+ if(!reagents || !reagents.total_volume)
+ return // The drink might be empty after the delay, such as by spam-feeding
+ M.visible_message("[user] feeds something to [M].", "[user] feeds something to you.")
+ log_combat(user, M, "fed", reagents.log_list())
+ else
+ to_chat(user, "You swallow a gulp of [src].")
+ var/fraction = min(5/reagents.total_volume, 1)
+ reagents.reaction(M, INGEST, fraction)
+ addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5), 5)
+ playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/afterattack(obj/target, mob/user, proximity)
+ . = ..()
+ if(fusedactive)
+ return
+
+ if((!proximity) || !check_allowed_items(target,target_self=1))
+ return
+
+ if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
+ if(!reagents.total_volume)
+ to_chat(user, "[src] is empty!")
+ return
+
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
+ return
+
+ var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
+ to_chat(user, "You transfer [trans] unit\s of the solution to [target].")
+
+ else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
+ if(!target.reagents.total_volume)
+ to_chat(user, "[target] is empty and can't be refilled!")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
+ return
+
+ var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
+ to_chat(user, "You fill [src] with [trans] unit\s of the contents of [target].")
+
+ else if(reagents.total_volume)
+ if(user.a_intent == INTENT_HARM && spillable == TRUE)
+ user.visible_message("[user] splashes the contents of [src] onto [target]!", \
+ "You splash the contents of [src] onto [target].")
+ reagents.reaction(target, TOUCH)
+ reagents.clear_reagents()
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/dropped(mob/user)
+ . = ..()
+ transform *= TRANSFORM_USING_VARIABLE(40, 100) + 0.5 //temporary fix for size?
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/proc/prime()
+ if (!defused)
+ var/turf/T = get_turf(src)
+ reagents.chem_temp = 1000
+ //Disable seperated contents when the grenade primes
+ if (seed.get_gene(/datum/plant_gene/trait/noreact))
+ DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
+ reagents.handle_reactions()
+ log_game("Coconut bomb detonation at [AREACOORD(T)], location [loc]")
+ qdel(src)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/ex_act(severity)
+ qdel(src)
+
+/obj/item/reagent_containers/food/snacks/grown/coconut/deconstruct(disassembled = TRUE)
+ if(!disassembled && fused)
+ prime()
+ if(!QDELETED(src))
+ qdel(src)
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index 23f178ed..6df0f0cd 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -98,6 +98,49 @@
/obj/item/grown/log/steel/CheckAccepted(obj/item/I)
return FALSE
+/obj/item/seeds/bamboo
+ name = "pack of bamboo seeds"
+ desc = "A plant known for its flexible and resistant logs."
+ icon_state = "seed-bamboo"
+ species = "bamboo"
+ plantname = "Bamboo"
+ product = /obj/item/grown/log/bamboo
+ lifespan = 80
+ endurance = 70
+ maturation = 15
+ production = 2
+ yield = 5
+ potency = 50
+ growthstages = 2
+ growing_icon = 'icons/obj/hydroponics/growing.dmi'
+ icon_dead = "bamboo-dead"
+ genes = list(/datum/plant_gene/trait/repeated_harvest)
+
+/obj/item/grown/log/bamboo
+ seed = /obj/item/seeds/bamboo
+ name = "bamboo log"
+ desc = "A long and resistant bamboo log."
+ icon_state = "bamboo"
+ plank_type = /obj/item/stack/sheet/mineral/bamboo
+ plank_name = "bamboo sticks"
+
+/obj/item/grown/log/bamboo/CheckAccepted(obj/item/I)
+ return FALSE
+
+/obj/structure/punji_sticks
+ name = "punji sticks"
+ desc = "Don't step on this."
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "punji"
+ resistance_flags = FLAMMABLE
+ max_integrity = 30
+ density = FALSE
+ anchored = TRUE
+
+/obj/structure/punji_sticks/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/caltrop, 20, 30, 100, CALTROP_BYPASS_SHOES)
+
/////////BONFIRES//////////
/obj/structure/bonfire
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index 53e94c73..536cfe68 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -301,14 +301,39 @@
/datum/plant_gene/trait/glow/shadow/glow_power(obj/item/seeds/S)
return -max(S.potency*(rate*0.2), 0.2)
-/datum/plant_gene/trait/glow/red
- name = "Red Electrical Glow"
- glow_color = LIGHT_COLOR_RED
+//Colored versions of bioluminescence.
+datum/plant_gene/trait/glow/white
+ name = "White Bioluminescence"
+ glow_color = "#FFFFFF"
-/datum/plant_gene/trait/glow/berry
- name = "Strong Bioluminescence"
- rate = 0.05
- glow_color = null
+/datum/plant_gene/trait/glow/red
+ name = "Red Bioluminescence"
+ glow_color = "#FF3333"
+
+/datum/plant_gene/trait/glow/yellow
+ //not the disgusting glowshroom yellow hopefully
+ name = "Yellow Bioluminescence"
+ glow_color = "#FFFF66"
+
+/datum/plant_gene/trait/glow/green
+ //oh no, now i'm radioactive
+ name = "Green Bioluminescence"
+ glow_color = "#99FF99"
+
+/datum/plant_gene/trait/glow/blue
+ //the best one
+ name = "Blue Bioluminescence"
+ glow_color = "#6699FF"
+
+/datum/plant_gene/trait/glow/purple
+ //did you know that notepad++ doesnt think bioluminescence is a word
+ name = "Purple Bioluminescence"
+ glow_color = "#D966FF"
+
+/datum/plant_gene/trait/glow/pink
+ //gay tide station pride
+ name = "Pink Bioluminescence"
+ glow_color = "#FFB3DA"
/datum/plant_gene/trait/teleport
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index f7f831a8..ab9668a3 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -26,6 +26,7 @@
var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
var/list/mutatelist = list() // The type of plants that this plant can mutate into.
var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
+ var/list/forbiddengenes = list() // Plant genes that the seed may be forbidden from having.
var/list/reagents_add = list()
// A list of reagents to add to product.
// Format: "reagent_id" = potency multiplier
@@ -90,6 +91,10 @@
/obj/item/seeds/proc/get_gene(typepath)
return (locate(typepath) in genes)
+obj/item/seeds/proc/is_gene_forbidden(typepath)
+ return (locate(typepath) in forbiddengenes)
+
+
/obj/item/seeds/proc/reagents_from_genes()
reagents_add = list()
for(var/datum/plant_gene/reagent/R in genes)
@@ -390,7 +395,7 @@
for(var/i in 1 to amount_random_traits)
var/random_trait = pick((subtypesof(/datum/plant_gene/trait)-typesof(/datum/plant_gene/trait/plant_type)))
var/datum/plant_gene/trait/T = new random_trait
- if(T.can_add(src))
+ if(T.can_add(src) && !is_gene_forbidden(T))
genes += T
else
qdel(T)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index fefa032e..0e2e50c2 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -231,7 +231,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
var/r_val
var/b_val
var/g_val
- var/color_format = lentext(input_color)
+ var/color_format = length(input_color)
if(color_format == 3)
r_val = hex2num(copytext(input_color, 1, 2))*16
g_val = hex2num(copytext(input_color, 2, 3))*16
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 7232944b..f6793aa2 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -781,7 +781,7 @@
broken_plural = TRUE
else
var/holder = broken[1] //our one and only element
- if(holder[lentext(holder)] == "s")
+ if(holder[length(holder)] == "s")
broken_plural = TRUE
//Put the items in that list into a string of text
for(var/B in broken)
@@ -793,7 +793,7 @@
damaged_plural = TRUE
else
var/holder = damaged[1]
- if(holder[lentext(holder)] == "s")
+ if(holder[length(holder)] == "s")
damaged_plural = TRUE
for(var/D in damaged)
damaged_message += D
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 68995702..b1095b12 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -94,6 +94,10 @@
var/ignorelistcleanuptimer = 1 // This ticks up every automated action, at 300 we clean the ignore list
var/robot_arm = /obj/item/bodypart/r_arm/robot
+ var/commissioned = FALSE // Will other (noncommissioned) bots salute this bot?
+ var/can_salute = TRUE
+ var/salute_delay = 60 SECONDS
+
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST) //Diagnostic HUD views
/mob/living/simple_animal/bot/proc/get_mode()
@@ -244,6 +248,14 @@
if(!on || client)
return
+ if(!commissioned && can_salute)
+ for(var/mob/living/simple_animal/bot/B in get_hearers_in_view(5, get_turf(src)))
+ if(B.commissioned)
+ visible_message("[src] performs an elaborate salute for [B]!")
+ can_salute = FALSE
+ addtimer(VARSET_CALLBACK(src, can_salute, TRUE), salute_delay)
+ break
+
switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
if(BOT_RESPONDING) //Called by the AI.
call_mode()
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index e09eb138..bd53e824 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -14,13 +14,14 @@
model = "Cleanbot"
bot_core_type = /obj/machinery/bot_core/cleanbot
window_id = "autoclean"
- window_name = "Automatic Station Cleaner v1.2"
+ window_name = "Automatic Station Cleaner v1.4"
pass_flags = PASSMOB
path_image_color = "#993299"
var/blood = 1
var/trash = 0
var/pests = 0
+ var/drawn = 0
var/list/target_types
var/obj/effect/decal/cleanable/target
@@ -32,14 +33,81 @@
var/next_dest
var/next_dest_loc
+ var/obj/item/weapon
+ var/weapon_orig_force = 0
+ var/chosen_name
+
+ var/list/stolen_valor
+
+ var/static/list/officers = list("Captain", "Head of Personnel", "Head of Security")
+ var/static/list/command = list("Captain" = "Cpt.","Head of Personnel" = "Lt.")
+ var/static/list/security = list("Head of Security" = "Maj.", "Warden" = "Sgt.", "Detective" = "Det.", "Security Officer" = "Officer")
+ var/static/list/engineering = list("Chief Engineer" = "Chief Engineer", "Station Engineer" = "Engineer", "Atmospherics Technician" = "Technician")
+ var/static/list/medical = list("Chief Medical Officer" = "C.M.O.", "Medical Doctor" = "M.D.", "Chemist" = "Pharm.D.")
+ var/static/list/research = list("Research Director" = "Ph.D.", "Roboticist" = "M.S.", "Scientist" = "B.S.")
+ var/static/list/legal = list("Lawyer" = "Esq.")
+
+ var/list/prefixes
+ var/list/suffixes
+
+
+/mob/living/simple_animal/bot/cleanbot/proc/deputize(obj/item/W, mob/user)
+ if(in_range(src, user))
+ to_chat(user, "You attach \the [W] to \the [src].")
+ user.transferItemToLoc(W, src)
+ weapon = W
+ weapon_orig_force = weapon.force
+ if(!emagged)
+ weapon.force = weapon.force / 2
+ add_overlay(image(icon=weapon.lefthand_file,icon_state=weapon.item_state))
+
+/mob/living/simple_animal/bot/cleanbot/proc/update_titles()
+ var/working_title = ""
+
+ for(var/pref in prefixes)
+ for(var/title in pref)
+ if(title in stolen_valor)
+ working_title += pref[title] + " "
+ if(title in officers)
+ commissioned = TRUE
+ break
+
+ working_title += chosen_name
+
+ for(var/suf in suffixes)
+ for(var/title in suf)
+ if(title in stolen_valor)
+ working_title += " " + suf[title]
+ break
+
+ name = working_title
+
+/mob/living/simple_animal/bot/cleanbot/examine(mob/user)
+ . = ..()
+ if(weapon)
+ . += " Is that \a [weapon] taped to it...?"
+
/mob/living/simple_animal/bot/cleanbot/Initialize()
. = ..()
+
+ chosen_name = name
get_targets()
icon_state = "cleanbot[on]"
var/datum/job/janitor/J = new/datum/job/janitor
access_card.access += J.get_access()
prev_access = access_card.access
+ stolen_valor = list()
+
+ prefixes = list(command, security, engineering)
+ suffixes = list(research, medical, legal)
+
+/mob/living/simple_animal/bot/cleanbot/Destroy()
+ if(weapon)
+ var/atom/Tsec = drop_location()
+ weapon.force = weapon_orig_force
+ drop_part(weapon, Tsec)
+ return ..()
/mob/living/simple_animal/bot/cleanbot/turn_on()
..()
@@ -53,6 +121,8 @@
/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
+ if(weapon && emagged == 2)
+ weapon.force = weapon_orig_force
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
target = null
oldloc = null
@@ -62,6 +132,22 @@
text_dehack = "[name]'s software has been reset!"
text_dehack_fail = "[name] does not seem to respond to your repair code!"
+/mob/living/simple_animal/bot/cleanbot/Crossed(atom/movable/AM)
+ . = ..()
+
+ zone_selected = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ if(weapon && has_gravity() && ismob(AM))
+ var/mob/living/carbon/C = AM
+ if(!istype(C))
+ return
+
+ if(!(C.job in stolen_valor))
+ stolen_valor += C.job
+ update_titles()
+
+ weapon.attack(C, src)
+ C.Knockdown(20)
+
/mob/living/simple_animal/bot/cleanbot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda))
if(bot_core.allowed(user) && !open && !emagged)
@@ -74,12 +160,19 @@
to_chat(user, "Please close the access panel before locking it.")
else
to_chat(user, "\The [src] doesn't seem to respect your authority.")
+ else if(istype(W, /obj/item/kitchen/knife) && user.a_intent != INTENT_HARM)
+ to_chat(user, "You start attaching \the [W] to \the [src]...")
+ if(do_after(user, 25, target = src))
+ deputize(W, user)
else
return ..()
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
..()
+
if(emagged == 2)
+ if(weapon)
+ weapon.force = weapon_orig_force
if(user)
to_chat(user, "[src] buzzes and beeps.")
@@ -132,6 +225,9 @@
if(!target && trash) //Then for trash.
target = scan(/obj/item/trash)
+ if(!target && trash) //Search for dead mices.
+ target = scan(/obj/item/reagent_containers/food/snacks/deadmouse)
+
if(!target && auto_patrol) //Search for cleanables it can see.
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
start_patrol()
@@ -177,7 +273,6 @@
/obj/effect/decal/cleanable/oil,
/obj/effect/decal/cleanable/vomit,
/obj/effect/decal/cleanable/robot_debris,
- /obj/effect/decal/cleanable/crayon,
/obj/effect/decal/cleanable/molten_object,
/obj/effect/decal/cleanable/tomato_smudge,
/obj/effect/decal/cleanable/egg_smudge,
@@ -199,33 +294,37 @@
target_types += /mob/living/simple_animal/cockroach
target_types += /mob/living/simple_animal/mouse
+ if(drawn)
+ target_types += /obj/effect/decal/cleanable/crayon
+
if(trash)
target_types += /obj/item/trash
+ target_types += /obj/item/reagent_containers/food/snacks/deadmouse
target_types = typecacheof(target_types)
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
- if(istype(A, /obj/effect/decal/cleanable))
- anchored = TRUE
+ if(is_cleanable(A))
icon_state = "cleanbot-c"
- visible_message("[src] begins to clean up [A].")
mode = BOT_CLEANING
- spawn(50)
- if(mode == BOT_CLEANING)
- if(A && isturf(A.loc))
- var/atom/movable/AM = A
- if(istype(AM, /obj/effect/decal/cleanable))
- for(var/obj/effect/decal/cleanable/C in A.loc)
- qdel(C)
- anchored = FALSE
- target = null
- mode = BOT_IDLE
- icon_state = "cleanbot[on]"
+ var/turf/T = get_turf(A)
+ if(do_after(src, 1, target = T))
+ SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
+ visible_message("[src] cleans \the [T].")
+ for(var/atom/dirtything in T)
+ if(is_cleanable(dirtything))
+ qdel(dirtything)
+
+ target = null
+
+ mode = BOT_IDLE
+ icon_state = "cleanbot[on]"
else if(istype(A, /obj/item) || istype(A, /obj/effect/decal/remains))
visible_message("[src] sprays hydrofluoric acid at [A]!")
- playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
+ playsound(src, 'sound/effects/spray2.ogg', 50, TRUE, -6)
A.acid_act(75, 10)
+ target = null
else if(istype(A, /mob/living/simple_animal/cockroach) || istype(A, /mob/living/simple_animal/mouse))
var/mob/living/simple_animal/M = target
if(!M.stat)
@@ -245,7 +344,7 @@
"MY ONLY MISSION IS TO CLEANSE THE WORLD OF EVIL.", "EXTERMINATING PESTS.")
say(phrase)
victim.emote("scream")
- playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
+ playsound(src.loc, 'sound/effects/spray2.ogg', 50, TRUE, -6)
victim.acid_act(5, 100)
else if(A == src) // Wets floors and spawns foam randomly
if(prob(75))
@@ -277,7 +376,6 @@
/obj/machinery/bot_core/cleanbot
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS)
-
/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
var/dat
dat += hack(user)
@@ -289,6 +387,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"})
if(!locked || issilicon(user)|| IsAdminGhost(user))
dat += "
Clean Blood: [blood ? "Yes" : "No"]"
dat += "
Clean Trash: [trash ? "Yes" : "No"]"
+ dat += "
Clean Graffiti: [drawn ? "Yes" : "No"]"
dat += "
Exterminate Pests: [pests ? "Yes" : "No"]"
dat += "
Patrol Station: [auto_patrol ? "Yes" : "No"]"
return dat
@@ -304,5 +403,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"})
pests = !pests
if("trash")
trash = !trash
+ if("drawn")
+ drawn = !drawn
get_targets()
update_controls()
diff --git a/code/modules/mob/living/taste.dm b/code/modules/mob/living/taste.dm
index e4d1aa94..f48fb528 100644
--- a/code/modules/mob/living/taste.dm
+++ b/code/modules/mob/living/taste.dm
@@ -3,6 +3,8 @@
/mob/living
var/last_taste_time
var/last_taste_text
+ var/last_ph_taste_time
+ var/last_ph_taste_number
/mob/living/proc/get_taste_sensitivity()
return DEFAULT_TASTE_SENSITIVITY
@@ -49,14 +51,30 @@
say("The pH is appropriately [round(from.pH, 1)].")
return
if (!HAS_TRAIT(src, TRAIT_AGEUSIA)) //I'll let you get away with not having 1 damage.
- switch(from.pH)
- if(11.5 to INFINITY)
- to_chat(src, "You taste a strong alkaline flavour!")
- if(8.5 to 11.5)
- to_chat(src, "You taste a sort of soapy tone in the mixture.")
- if(2.5 to 5.5)
- to_chat(src, "You taste a sort of acid tone in the mixture.")
- if(-INFINITY to 2.5)
- to_chat(src, "You taste a strong acidic flavour!")
+ if(last_ph_taste_time + 50 < world.time)
+ var/ph_taste_number
+ switch(from.pH)
+ if(11.5 to INFINITY)
+ ph_taste_number = 1
+ if(8.5 to 11.5)
+ ph_taste_number = 2
+ if(2.5 to 5.5)
+ ph_taste_number = 3
+ if(-INFINITY to 2.5)
+ ph_taste_number = 4
+
+ if(ph_taste_number != last_ph_taste_number || last_ph_taste_time + 200 < world.time)
+ if (ph_taste_number == 1)
+ to_chat(src, "You taste a strong alkaline flavour!")
+ if (ph_taste_number == 2)
+ to_chat(src, "You taste a sort of soapy tone in the mixture.")
+ if (ph_taste_number == 3)
+ to_chat(src, "You taste a sort of acid tone in the mixture.")
+ if (ph_taste_number == 4)
+ to_chat(src, "You taste a strong acidic flavour!")
+
+ last_ph_taste_time = world.time
+ last_ph_taste_number = ph_taste_number
+
#undef DEFAULT_TASTE_SENSITIVITY
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 83eca8b8..3a3dacee 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -67,8 +67,8 @@
/proc/slur(n,var/strength=50)
strength = min(strength,50)
var/phrase = html_decode(n)
- var/leng = lentext(phrase)
- var/counter=lentext(phrase)
+ var/leng = length(phrase)
+ var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
@@ -102,8 +102,8 @@
/proc/cultslur(n) // Inflicted on victims of a stun talisman
var/phrase = html_decode(n)
- var/leng = lentext(phrase)
- var/counter=lentext(phrase)
+ var/leng = length(phrase)
+ var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 1fc97c31..4bbeef70 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -25,7 +25,7 @@
if(flavor_text && flavor_text != "")
// We are decoding and then encoding to not only get correct amount of characters, but also to prevent partial escaping characters being shown.
var/msg = html_decode(replacetext(flavor_text, "\n", " "))
- if(lentext(msg) <= 40)
+ if(length(msg) <= 40)
return "[html_encode(msg)]"
else
return "[html_encode(copytext(msg, 1, 37))]... More..."
diff --git a/code/modules/projectiles/guns/misc/syringe_gun.dm b/code/modules/projectiles/guns/misc/syringe_gun.dm
index c9e8f2f2..3e4b800b 100644
--- a/code/modules/projectiles/guns/misc/syringe_gun.dm
+++ b/code/modules/projectiles/guns/misc/syringe_gun.dm
@@ -122,3 +122,19 @@
else
to_chat(user, "You can't put the [A] into \the [src]!")
return FALSE
+
+/obj/item/gun/syringe/blowgun
+ name = "blowgun"
+ desc = "Fire syringes at a short distance."
+ icon_state = "blowgun"
+ item_state = "blowgun"
+ fire_sound = 'sound/weapons/grenadelaunch.ogg'
+
+/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+ visible_message("[user] starts aiming with a blowgun!")
+ if(do_after(user, 25, target = src))
+ var/shot
+ shot = ..()
+ if (shot == TRUE)
+ user.adjustStaminaLoss(15)
+ user.adjustOxyLoss(15)
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 2445bd29..a3194cee 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -2227,3 +2227,48 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = flavor
if(holder.my_atom)
holder.my_atom.on_reagent_change()
+
+/datum/reagent/consumable/ethanol/gunfire
+ name = "Gunfire"
+ id = "gunfire"
+ description = "A drink that tastes like tiny explosions."
+ color = "#e4830d"
+ boozepwr = 40
+ quality = DRINK_GOOD
+ taste_description = "tiny explosions"
+ glass_icon_state = "gunfire"
+ glass_name = "Gunfire"
+ glass_desc = "It pops constantly as you look at it, giving off tiny sparks."
+
+/datum/reagent/consumable/ethanol/hellfire/on_mob_life(mob/living/carbon/M)
+ if (prob(3))
+ to_chat(M,"You feel the gunfire pop in your mouth.")
+ return ..()
+
+/datum/reagent/consumable/ethanol/hellfire
+ name = "Hellfire"
+ id = "hellfire"
+ description = "A nice drink that isn't quite as hot as it looks."
+ color = "#fb2203"
+ boozepwr = 60
+ quality = DRINK_VERYGOOD
+ taste_description = "cold flames that lick at the top of your mouth"
+ glass_icon_state = "hellfire"
+ glass_name = "Hellfire"
+ glass_desc = "An amber colored drink that isn't quite as hot as it looks."
+
+/datum/reagent/consumable/ethanol/hellfire/on_mob_life(mob/living/carbon/M)
+ M.adjust_bodytemperature(30 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL + 30)
+ return ..()
+
+/datum/reagent/consumable/ethanol/sins_delight
+ name = "Sin's Delight"
+ id = "sins_delight"
+ description = "The drink smells like the seven sins."
+ color = "#330000"
+ boozepwr = 66
+ quality = DRINK_FANTASTIC
+ taste_description = "sin"
+ glass_icon_state = "sins_delight"
+ glass_name = "Sin's Delight"
+ glass_desc = "You can smell the seven sins rolling off the top of the glass."
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index bfefc073..b4e61faa 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -242,6 +242,23 @@
. = 1
..()
+/datum/reagent/consumable/coconutmilk
+ name = "Coconut Milk"
+ id = "coconutmilk"
+ description = "A transparent white liquid extracted from coconuts. Rich in taste."
+ color = "#DFDFDF" // rgb: 223, 223, 223
+ taste_description = "sweet milk"
+ quality = DRINK_GOOD
+ glass_icon_state = "glass_white"
+ glass_name = "glass of coconut milk"
+ glass_desc = "White and nutritious goodness!"
+
+/datum/reagent/consumable/coconutmilk/on_mob_life(mob/living/carbon/M)
+ if(M.getBruteLoss() && prob(20))
+ M.heal_bodypart_damage(2,0, 0)
+ . = 1
+ ..()
+
/datum/reagent/consumable/cream
name = "Cream"
id = "cream"
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 5d30fb77..93a8f1f5 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -17,6 +17,7 @@
var/spillable = FALSE
var/beaker_weakness_bitflag = NONE//Bitflag!
var/container_HP = 2
+ var/splashable = FALSE
/obj/item/reagent_containers/Initialize(mapload, vol)
. = ..()
@@ -92,7 +93,7 @@
transform = initial(transform)
/obj/item/reagent_containers/proc/SplashReagents(atom/target, thrown = FALSE)
- if(!reagents || !reagents.total_volume || !spillable)
+ if(!reagents || !reagents.total_volume || !(splashable ? splashable : spillable))
return
if(ismob(target) && target.reagents)
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
index 273ff526..6f6fb0c8 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm
@@ -21,6 +21,32 @@
build_path = /obj/item/kitchen/fork
category = list("initial","Dinnerware")
+/datum/design/plastic_fork
+ name = "Plastic Fork"
+ id = "plastic_fork"
+ build_type = AUTOLATHE | PROTOLATHE
+ materials = list(MAT_PLASTIC = 80)
+ build_path = /obj/item/kitchen/fork/plastic
+ category = list("initial", "Tool Designs", "Dinnerware")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
+/datum/design/plastic_spoon
+ name = "Plastic Spoon"
+ id = "plastic_spoon"
+ build_type = AUTOLATHE | PROTOLATHE
+ materials = list(MAT_PLASTIC = 120)
+ build_path = /obj/item/kitchen/spoon/plastic
+ category = list("initial", "Tool Designs", "Dinnerware")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
+/datum/design/plastic_knife
+ name = "Plastic Knife"
+ id = "plastic_knife"
+ build_type = AUTOLATHE | PROTOLATHE
+ materials = list(MAT_PLASTIC = 100)
+ build_path = /obj/item/kitchen/knife/plastic
+ category = list("initial", "Tool Designs","Dinnerware")
+
/datum/design/tray
name = "Tray"
id = "tray"
diff --git a/code/modules/research/designs/comp_board_designs/comp_board_designs_sec.dm b/code/modules/research/designs/comp_board_designs/comp_board_designs_sec.dm
index 0e93481f..29321886 100644
--- a/code/modules/research/designs/comp_board_designs/comp_board_designs_sec.dm
+++ b/code/modules/research/designs/comp_board_designs/comp_board_designs_sec.dm
@@ -41,3 +41,11 @@
build_path = /obj/item/circuitboard/computer/card
category = list("Computer Boards")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_ENGINEERING //Honestly should have a bridge techfab for this sometime.
+
+/datum/design/board/advanced_camera
+ name = "Computer Design (Advanced Camera Console)"
+ desc = "Allows for the construction of circuit boards used to build advanced camera consoles."
+ id = "advanced_camera"
+ build_path = /obj/item/circuitboard/computer/advanced_camera
+ category = list("Computer Boards")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 841a8897..4659d322 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -476,6 +476,15 @@
category = list("Phazon")
//Exosuit Equipment
+/datum/design/ripleyupgrade
+ name = "Ripley MK-1 to MK-II conversion kit"
+ id = "ripleyupgrade"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_equipment/ripleyupgrade
+ materials = list(MAT_METAL=10000,MAT_PLASMA=10000)
+ construction_time = 100
+ category = list("Exosuit Equipment")
+
/datum/design/mech_hydraulic_clamp
name = "Exosuit Engineering Equipment (Hydraulic Clamp)"
id = "mech_hydraulic_clamp"
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 5a8fc03d..b24b0cff 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -906,3 +906,16 @@
build_path = /obj/item/bodypart/r_arm/robot/surplus_upgraded
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+
+
+/datum/design/adv_dis_hypo
+ name = "Disposable Hypospray MK.II"
+ desc = "A cheaply made hypospray"
+ id = "disposable_hypospray"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 100, MAT_PLASTIC = 500)
+ construction_time = 40
+ build_path = /obj/item/hypospray/mkii/disposable
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
\ No newline at end of file
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 2f51b33e..afede110 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -11,7 +11,8 @@
design_ids = list("basic_matter_bin", "basic_cell", "basic_scanning", "basic_capacitor", "basic_micro_laser", "micro_mani",
"destructive_analyzer", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab",
"space_heater", "xlarge_beaker", "sec_rshot", "sec_bshot", "sec_slug", "sec_Islug", "sec_dart", "sec_38", "sec_38lethal",
- "rglass","plasteel","plastitanium","plasmaglass","plasmareinforcedglass","titaniumglass","plastitaniumglass","chem_pack","medkit_cabinet")
+ "rglass","plasteel","plastitanium","plasmaglass","plasmareinforcedglass","titaniumglass","plastitaniumglass","chem_pack","medkit_cabinet",
+ "disposable_hypospray","plastic_knife","plastic_fork","plastic_spoon")
/datum/techweb_node/mmi
id = "mmi"
@@ -34,7 +35,7 @@
display_name = "Mechanical Exosuits"
description = "Mechanized exosuits that are several magnitudes stronger and more powerful than the average human."
design_ids = list("mecha_tracking", "mechacontrol", "mechapower", "mech_recharger", "ripley_chassis", "firefighter_chassis", "ripley_torso", "ripley_left_arm", "ripley_right_arm", "ripley_left_leg", "ripley_right_leg",
- "ripley_main", "ripley_peri", "mech_hydraulic_clamp")
+ "ripley_main", "ripley_peri", "ripleyupgrade", "mech_hydraulic_clamp")
/datum/techweb_node/mech_tools
id = "mech_tools"
@@ -1052,7 +1053,7 @@
display_name = "Illegal Technology"
description = "Dangerous research used to create dangerous objects."
prereq_ids = list("adv_engi", "adv_weaponry", "explosive_weapons")
- design_ids = list("decloner", "borg_syndicate_module", "suppressor", "largecrossbow", "donksofttoyvendor")
+ design_ids = list("decloner", "borg_syndicate_module", "suppressor", "largecrossbow", "donksofttoyvendor", "advanced_camera")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
export_price = 5000
hidden = TRUE
diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm
new file mode 100644
index 00000000..873ae7ac
--- /dev/null
+++ b/code/modules/vehicles/motorized_wheelchair.dm
@@ -0,0 +1,168 @@
+/obj/vehicle/ridden/wheelchair/motorized
+ name = "motorized wheelchair"
+ desc = "A chair with big wheels. It seems to have a motor in it."
+ max_integrity = 150
+ var/speed = 2
+ var/power_efficiency = 1
+ var/power_usage = 100
+ var/panel_open = FALSE
+ var/list/required_parts = list(/obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/capacitor)
+ var/obj/item/stock_parts/cell/power_cell
+
+/obj/vehicle/ridden/wheelchair/motorized/CheckParts(list/parts_list)
+ ..()
+ refresh_parts()
+
+/obj/vehicle/ridden/wheelchair/motorized/proc/refresh_parts()
+ speed = 1 // Should never be under 1
+ for(var/obj/item/stock_parts/manipulator/M in contents)
+ speed += M.rating
+ for(var/obj/item/stock_parts/capacitor/C in contents)
+ power_efficiency = C.rating
+ var/datum/component/riding/D = GetComponent(/datum/component/riding)
+ D.vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * delay_multiplier) / speed
+
+/obj/vehicle/ridden/wheelchair/motorized/obj_destruction(damage_flag)
+ var/turf/T = get_turf(src)
+ for(var/atom/movable/A in contents)
+ A.forceMove(T)
+ //if(isliving(A))
+ // var/mob/living/L = A
+ // L.update_mobility()
+ ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/driver_move(mob/living/user, direction)
+ if(istype(user))
+ if(!canmove)
+ return FALSE
+ if(!power_cell)
+ to_chat(user, "There seems to be no cell installed in [src].")
+ canmove = FALSE
+ addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
+ return FALSE
+ if(power_cell.charge < power_usage / max(power_efficiency, 1))
+ to_chat(user, "The display on [src] blinks 'Out of Power'.")
+ canmove = FALSE
+ addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
+ return FALSE
+ if(user.get_num_arms() < arms_required)
+ to_chat(user, "You don't have enough arms to operate the motor controller!")
+ canmove = FALSE
+ addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
+ return FALSE
+ power_cell.use(power_usage / max(power_efficiency, 1))
+ return ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/set_move_delay(mob/living/user)
+ return
+
+/obj/vehicle/ridden/wheelchair/motorized/post_buckle_mob(mob/living/user)
+ . = ..()
+ density = TRUE
+
+/obj/vehicle/ridden/wheelchair/motorized/post_unbuckle_mob()
+ . = ..()
+ density = FALSE
+
+/obj/vehicle/ridden/wheelchair/motorized/attack_hand(mob/living/user)
+ if(power_cell && panel_open)
+ power_cell.update_icon()
+ user.put_in_hands(power_cell)
+ power_cell = null
+ to_chat(user, "You remove the power cell from [src].")
+ return
+ return ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/attackby(obj/item/I, mob/user, params)
+ if(I.tool_behaviour == TOOL_SCREWDRIVER)
+ I.play_tool_sound(src)
+ panel_open = !panel_open
+ user.visible_message("[user] [panel_open ? "opens" : "closes"] the maintenance panel on [src].", "You [panel_open ? "open" : "close"] the maintenance panel.")
+ return
+ if(panel_open)
+ if(istype(I, /obj/item/stock_parts/cell))
+ if(power_cell)
+ to_chat(user, "There is a power cell already installed.")
+ else
+ I.forceMove(src)
+ power_cell = I
+ to_chat(user, "You install the [I].")
+ refresh_parts()
+ return
+ if(istype(I, /obj/item/stock_parts))
+ var/obj/item/stock_parts/B = I
+ var/P
+ for(var/obj/item/stock_parts/A in contents)
+ for(var/D in required_parts)
+ if(ispath(A.type, D))
+ P = D
+ break
+ if(istype(B, P) && istype(A, P))
+ if(B.get_part_rating() > A.get_part_rating())
+ B.forceMove(src)
+ user.put_in_hands(A)
+ user.visible_message("[user] replaces [A] with [B] in [src].", "You replace [A] with [B].")
+ break
+ refresh_parts()
+ return
+ return ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/wrench_act(mob/living/user, obj/item/I)
+ to_chat(user, "You begin to detach the wheels...")
+ if(I.use_tool(src, user, 40, volume=50))
+ to_chat(user, "You detach the wheels and deconstruct the chair.")
+ new /obj/item/stack/rods(drop_location(), 8)
+ new /obj/item/stack/sheet/metal(drop_location(), 10)
+ var/turf/T = get_turf(src)
+ for(var/atom/movable/A in contents)
+ A.forceMove(T)
+ //if(isliving(A))
+ // var/mob/living/L = A
+ // L.update_mobility()
+ qdel(src)
+ return TRUE
+
+/obj/vehicle/ridden/wheelchair/motorized/examine(mob/user)
+ . = ..()
+ if((obj_flags & EMAGGED) && panel_open)
+ . += "There is a bomb under the maintenance panel."
+ . += "There is a small screen on it, [(in_range(user, src) || isobserver(user)) ? "[power_cell ? "it reads:" : "but it is dark."]" : "but you can't see it from here."]"
+ if(!power_cell || (!in_range(user, src) && !isobserver(user)))
+ return
+ . += "Speed: [speed]"
+ . += "Energy efficiency: [power_efficiency]"
+ . += "Power: [power_cell.charge] out of [power_cell.maxcharge]"
+
+/obj/vehicle/ridden/wheelchair/motorized/Bump(atom/movable/M)
+ . = ..()
+ // Here is the shitty emag functionality.
+ if(obj_flags & EMAGGED && (istype(M, /turf/closed) || isliving(M)))
+ explosion(src, -1, 1, 3, 2, 0)
+ visible_message("[src] explodes!!")
+ return
+ // If the speed is higher than delay_multiplier throw the person on the wheelchair away
+ if(M.density && speed > delay_multiplier && has_buckled_mobs())
+ var/mob/living/H = buckled_mobs[1]
+ var/atom/throw_target = get_edge_target_turf(H, pick(GLOB.cardinals))
+ unbuckle_mob(H)
+ H.throw_at(throw_target, 2, 3)
+ H.Knockdown(100)
+ H.adjustStaminaLoss(40)
+ if(isliving(M))
+ var/mob/living/D = M
+ throw_target = get_edge_target_turf(D, pick(GLOB.cardinals))
+ D.throw_at(throw_target, 2, 3)
+ D.Knockdown(80)
+ D.adjustStaminaLoss(35)
+ visible_message("[src] crashes into [M], sending [H] and [D] flying!")
+ else
+ visible_message("[src] crashes into [M], sending [H] flying!")
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
+
+/obj/vehicle/ridden/wheelchair/motorized/emag_act(mob/user)
+ if((obj_flags & EMAGGED) || !panel_open)
+ return
+ to_chat(user, "A bomb appears in [src], what the fuck?")
+ obj_flags |= EMAGGED
diff --git a/code/modules/vehicles/wheelchair.dm b/code/modules/vehicles/wheelchair.dm
index 137242c5..2eb1a2ad 100644
--- a/code/modules/vehicles/wheelchair.dm
+++ b/code/modules/vehicles/wheelchair.dm
@@ -1,4 +1,4 @@
-/obj/vehicle/ridden/wheelchair //ported from Hippiestation (by Jujumatic) Then ported by Fermis from tg!
+/obj/vehicle/ridden/wheelchair //ported from Hippiestation (by Jujumatic)
name = "wheelchair"
desc = "A chair with big wheels. It looks like you can move in this on your own."
icon = 'icons/obj/vehicles.dmi'
@@ -9,7 +9,8 @@
legs_required = 0 //You'll probably be using this if you don't have legs
canmove = TRUE
density = FALSE //Thought I couldn't fix this one easily, phew
- arms_required = 1
+ // Run speed delay is multiplied with this for vehicle move delay.
+ var/delay_multiplier = 6.7
/obj/vehicle/ridden/wheelchair/Initialize()
. = ..()
@@ -42,16 +43,19 @@
canmove = FALSE
addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
return FALSE
- var/datum/component/riding/D = GetComponent(/datum/component/riding)
- //1.5 (movespeed as of this change) multiplied by 6.7 gets ABOUT 10 (rounded), the old constant for the wheelchair that gets divided by how many arms they have
- //if that made no sense this simply makes the wheelchair speed change along with movement speed delay
- D.vehicle_move_delay = round((CONFIG_GET(number/movedelay/run_delay) * 4) / min(user.get_num_arms(), 2), world.tick_lag)
+ set_move_delay(user)
return ..()
+/obj/vehicle/ridden/wheelchair/proc/set_move_delay(mob/living/user)
+ var/datum/component/riding/D = GetComponent(/datum/component/riding)
+ //1.5 (movespeed as of this change) multiplied by 6.7 gets ABOUT 10 (rounded), the old constant for the wheelchair that gets divided by how many arms they have
+ //if that made no sense this simply makes the wheelchair speed change along with movement speed delay
+ D.vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * delay_multiplier) / min(user.get_num_arms(), 2)
+
/obj/vehicle/ridden/wheelchair/Moved()
. = ..()
cut_overlays()
- playsound(src, 'sound/effects/roll.ogg', 75, 1)
+ playsound(src, 'sound/effects/roll.ogg', 75, TRUE)
if(has_buckled_mobs())
handle_rotation_overlayed()
@@ -69,6 +73,7 @@
handle_rotation(newdir)
/obj/vehicle/ridden/wheelchair/wrench_act(mob/living/user, obj/item/I) //Attackby should stop it attacking the wheelchair after moving away during decon
+ ..()
to_chat(user, "You begin to detach the wheels...")
if(I.use_tool(src, user, 40, volume=50))
to_chat(user, "You detach the wheels and deconstruct the chair.")
diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm
index 0569b9f1..d48da5b1 100644
--- a/code/modules/vending/megaseed.dm
+++ b/code/modules/vending/megaseed.dm
@@ -14,6 +14,7 @@
/obj/item/seeds/chanter = 3,
/obj/item/seeds/chili = 3,
/obj/item/seeds/cocoapod = 3,
+ /obj/item/seeds/coconut = 3,
/obj/item/seeds/coffee = 3,
/obj/item/seeds/cotton = 3,
/obj/item/seeds/corn = 3,
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index 5076744a..b5ddff5f 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -131,6 +131,7 @@
/obj/item/clothing/mask/bandana/skull = 2)
premium = list(/obj/item/radio/headset/headset_rob = 2) //Cit change
contraband = list(/obj/item/clothing/suit/hooded/techpriest = 2)
+ contraband = list(/obj/item/organ/tongue/robot = 2)
refill_canister = /obj/item/vending_refill/wardrobe/robo_wardrobe
/obj/item/vending_refill/wardrobe/robo_wardrobe
diff --git a/config/config.txt b/config/config.txt
index 5dda144c..a6820cef 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -146,6 +146,9 @@ LOG_MANIFEST
## Enable logging pictures
# LOG_PICTURES
+## log cloning actions
+LOG_CLONING
+
##Log camera pictures - Must have picture logging enabled
PICTURE_LOGGING_CAMERA
@@ -176,6 +179,12 @@ VOTE_DELAY 6000
## time period (deciseconds) which voting session will last (default 1 minute)
VOTE_PERIOD 600
+## autovote initial delay (deciseconds) before first automatic transfer vote call (default 120 minutes)
+VOTE_AUTOTRANSFER_INITIAL 72000
+
+##autovote delay (deciseconds) before sequential automatic transfer votes are called (default 30 minutes)
+VOTE_AUTOTRANSFER_INTERVAL 18000
+
## prevents dead players from voting or starting votes
# NO_DEAD_VOTE
diff --git a/icons/mecha/mech_construction.dmi b/icons/mecha/mech_construction.dmi
index cdb07215..d7f0f3e0 100644
Binary files a/icons/mecha/mech_construction.dmi and b/icons/mecha/mech_construction.dmi differ
diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi
index 4b09f791..291abf96 100644
Binary files a/icons/mecha/mecha.dmi and b/icons/mecha/mecha.dmi differ
diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi
index 02c79848..af1324c0 100644
Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ
diff --git a/icons/mob/feet.dmi b/icons/mob/feet.dmi
index e7598f35..78464f6c 100644
Binary files a/icons/mob/feet.dmi and b/icons/mob/feet.dmi differ
diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi
index fb800d7d..3df9fe5f 100644
Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi
index 8978d172..ea185c5a 100644
Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi
index 3f8a876d..1d380e34 100644
Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ
diff --git a/icons/obj/bongs.dmi b/icons/obj/bongs.dmi
new file mode 100644
index 00000000..406cce38
Binary files /dev/null and b/icons/obj/bongs.dmi differ
diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi
index a042f30e..95335bc9 100644
Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index 7822cdb8..6c0f7c30 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index 0ac8ccf5..588f58e5 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/hydroponics/equipment.dmi b/icons/obj/hydroponics/equipment.dmi
index dd4d1e1f..37adf547 100644
Binary files a/icons/obj/hydroponics/equipment.dmi and b/icons/obj/hydroponics/equipment.dmi differ
diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi
index e7dee229..7dc253eb 100644
Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ
diff --git a/icons/obj/hydroponics/growing_fruits.dmi b/icons/obj/hydroponics/growing_fruits.dmi
index 32d7fc53..9c0aa7ec 100644
Binary files a/icons/obj/hydroponics/growing_fruits.dmi and b/icons/obj/hydroponics/growing_fruits.dmi differ
diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi
index b59e23ef..7ba91fe5 100644
Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ
diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi
index c0f97be5..c653f54b 100644
Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ
diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi
index 42255471..ac3f7f9f 100644
Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ
diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi
index 7fa9f24a..f8271e11 100644
Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ
diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi
index 3aa6912d..c8c2202a 100644
Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 04384bc8..71339f5f 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
index f4af8a40..58bf4fb2 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
@@ -43,6 +43,9 @@
icon_state = "hemiknot"
name = "Knotted Hemi"
+/datum/sprite_accessory/penis/thick
+ icon_state = "thick"
+ name = "thick"
////////////////////////
// Taur cocks go here //
diff --git a/modular_citadel/code/modules/client/loadout/shoes.dm b/modular_citadel/code/modules/client/loadout/shoes.dm
index 95675cca..7baa8eff 100644
--- a/modular_citadel/code/modules/client/loadout/shoes.dm
+++ b/modular_citadel/code/modules/client/loadout/shoes.dm
@@ -37,3 +37,23 @@
name = "White shoes"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/white
+
+/datum/gear/gildedcuffs
+ name = "Gilded leg wraps"
+ category = SLOT_SHOES
+ path= /obj/item/clothing/shoes/wraps
+
+/datum/gear/silvercuffs
+ name = "Silver leg wraps"
+ category = SLOT_SHOES
+ path= /obj/item/clothing/shoes/wraps/silver
+
+/datum/gear/redcuffs
+ name = "Red leg wraps"
+ category = SLOT_SHOES
+ path= /obj/item/clothing/shoes/wraps/red
+
+/datum/gear/bluecuffs
+ name = "Blue leg wraps"
+ category = SLOT_SHOES
+ path= /obj/item/clothing/shoes/wraps/blue
diff --git a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
index 6cd9e1ba..de334f31 100644
--- a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
+++ b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
@@ -34,6 +34,7 @@
var/inject_self = SELF_INJECT
var/quickload = FALSE
var/penetrates = FALSE
+ var/reloadable = TRUE
/obj/item/hypospray/mkii/brute
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/bicaridine
@@ -53,6 +54,16 @@
/obj/item/hypospray/mkii/enlarge
spawnwithvial = FALSE
+//A vial-loaded hypospray. Cartridge-based!
+/obj/item/hypospray/mkii/disposable
+ name = "disposable hypospray mk.II"
+ icon = 'modular_citadel/icons/obj/hypospraymkii.dmi'
+ icon_state = "hypo2"
+ desc = "A cheaply made knock off verson of the MKII hypospray. You cannot remove a hypovial from it making it nonreusable."
+ w_class = WEIGHT_CLASS_TINY
+ spawnwithvial = FALSE
+ reloadable = FALSE
+
/obj/item/hypospray/mkii/CMO
name = "hypospray mk.II deluxe"
allowed_containers = list(/obj/item/reagent_containers/glass/bottle/vial/tiny, /obj/item/reagent_containers/glass/bottle/vial/small, /obj/item/reagent_containers/glass/bottle/vial/large)
@@ -96,21 +107,24 @@
/obj/item/hypospray/mkii/examine(mob/user)
. = ..()
- to_chat(user, "[vial] has [vial.reagents.total_volume]u remaining.")
to_chat(user, "[src] is set to [mode ? "Inject" : "Spray"] contents on application.")
/obj/item/hypospray/mkii/proc/unload_hypo(obj/item/I, mob/user)
- if((istype(I, /obj/item/reagent_containers/glass/bottle/vial)))
- var/obj/item/reagent_containers/glass/bottle/vial/V = I
- V.forceMove(user.loc)
- user.put_in_hands(V)
- to_chat(user, "You remove [vial] from [src].")
- vial = null
- update_icon()
- playsound(loc, 'sound/weapons/empty.ogg', 50, 1)
+ if (reloadable == TRUE)
+ if((istype(I, /obj/item/reagent_containers/glass/bottle/vial)))
+ var/obj/item/reagent_containers/glass/bottle/vial/V = I
+ V.forceMove(user.loc)
+ user.put_in_hands(V)
+ to_chat(user, "You remove [vial] from [src].")
+ vial = null
+ update_icon()
+ playsound(loc, 'sound/weapons/empty.ogg', 50, 1)
+ else
+ to_chat(user, "This hypo isn't loaded!")
+ return
else
- to_chat(user, "This hypo isn't loaded!")
- return
+ if((istype(I, /obj/item/reagent_containers/glass/bottle/vial)))
+ to_chat(user, "You cannot remove [vial] from [src] without destroying both.")
/obj/item/hypospray/mkii/attackby(obj/item/I, mob/living/user)
if((istype(I, /obj/item/reagent_containers/glass/bottle/vial) && vial != null))
diff --git a/modular_citadel/icons/mob/digishoes.dmi b/modular_citadel/icons/mob/digishoes.dmi
index a499db62..3d568863 100644
Binary files a/modular_citadel/icons/mob/digishoes.dmi and b/modular_citadel/icons/mob/digishoes.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/penis.dmi b/modular_citadel/icons/obj/genitals/penis.dmi
index 517758b2..5118b094 100644
Binary files a/modular_citadel/icons/obj/genitals/penis.dmi and b/modular_citadel/icons/obj/genitals/penis.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/penis_onmob.dmi b/modular_citadel/icons/obj/genitals/penis_onmob.dmi
index 361001a4..6ad0628d 100644
Binary files a/modular_citadel/icons/obj/genitals/penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/penis_onmob.dmi differ
diff --git a/sound/effects/bonghit.ogg b/sound/effects/bonghit.ogg
new file mode 100644
index 00000000..45a0dec1
Binary files /dev/null and b/sound/effects/bonghit.ogg differ
diff --git a/sound/weapons/klonk.ogg b/sound/weapons/klonk.ogg
new file mode 100644
index 00000000..471f3ad8
Binary files /dev/null and b/sound/weapons/klonk.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 1679844e..41677a1b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -229,6 +229,7 @@
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\augury.dm"
+#include "code\controllers\subsystem\autotransfer.dm"
#include "code\controllers\subsystem\blackbox.dm"
#include "code\controllers\subsystem\communications.dm"
#include "code\controllers\subsystem\dbcore.dm"
@@ -2760,6 +2761,7 @@
#include "code\modules\surgery\advanced\bioware\nerve_splicing.dm"
#include "code\modules\surgery\advanced\bioware\vein_threading.dm"
#include "code\modules\surgery\bodyparts\bodyparts.dm"
+#include "code\modules\surgery\bodyparts\broken.dm"
#include "code\modules\surgery\bodyparts\dismemberment.dm"
#include "code\modules\surgery\bodyparts\head.dm"
#include "code\modules\surgery\bodyparts\helpers.dm"
@@ -2811,6 +2813,7 @@
#include "code\modules\vehicles\atv.dm"
#include "code\modules\vehicles\bicycle.dm"
#include "code\modules\vehicles\lavaboat.dm"
+#include "code\modules\vehicles\motorized_wheelchair.dm"
#include "code\modules\vehicles\pimpin_ride.dm"
#include "code\modules\vehicles\ridden.dm"
#include "code\modules\vehicles\scooter.dm"
@@ -2877,7 +2880,7 @@
#include "modular_citadel\code\_onclick\hud\stamina.dm"
#include "modular_citadel\code\controllers\configuration\entries\general.dm"
#include "modular_citadel\code\controllers\subsystem\job.dm"
-#include "modular_citadel\code\controllers\subsystem\shuttle.dm"
+//#include "modular_citadel\code\controllers\subsystem\shuttle.dm"
#include "modular_citadel\code\datums\components\material_container.dm"
#include "modular_citadel\code\datums\components\phantomthief.dm"
#include "modular_citadel\code\datums\components\souldeath.dm"