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 @@
Electronics
@@ -115,7 +120,7 @@ " 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"