diff --git a/_maps/interiors/apc_cloner.dmm b/_maps/interiors/apc_cloner.dmm new file mode 100644 index 00000000000..15214e40b46 --- /dev/null +++ b/_maps/interiors/apc_cloner.dmm @@ -0,0 +1,194 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/interior/apc/nineteen, +/area/interior/apc) +"b" = ( +/obj/structure/bed/chair/driver_gunner_seat{ + pixel_x = -3; + pixel_y = -5 + }, +/turf/open/interior/apc/eleven, +/area/interior/apc) +"c" = ( +/obj/machinery/computer/cloning_console/vats{ + dir = 2; + layer = 2.99; + pixel_x = 8 + }, +/turf/open/interior/apc/nine, +/area/interior/apc) +"d" = ( +/turf/closed/interior/apc/twenty, +/area/interior/apc) +"e" = ( +/turf/closed/interior/apc/two, +/area/interior/apc) +"g" = ( +/turf/closed/interior/apc/five, +/area/interior/apc) +"h" = ( +/turf/closed/interior/apc/twelve, +/area/interior/apc) +"l" = ( +/turf/closed/interior/apc/twentyseven, +/area/interior/apc) +"m" = ( +/obj/structure/gun_breech/secondary, +/obj/machinery/gibber/apc, +/turf/open/interior/apc/twentytwo, +/area/interior/apc) +"n" = ( +/turf/open/interior/apc/ten, +/area/interior/apc) +"o" = ( +/turf/open/interior/apc/sixteen, +/area/interior/apc) +"p" = ( +/turf/closed/interior/apc/thirteen, +/area/interior/apc) +"s" = ( +/turf/open/interior/apc/eight, +/area/interior/apc) +"t" = ( +/obj/machinery/cloning/vats/apc/south{ + pixel_y = -16 + }, +/turf/closed/interior/apc/two, +/area/interior/apc) +"B" = ( +/obj/machinery/telecomms/relay/preset/telecomms/onboard/nondense, +/turf/closed/interior/apc/six, +/area/interior/apc) +"C" = ( +/turf/closed/interior/tank/door, +/area/interior/apc) +"D" = ( +/turf/open/interior/apc/fifteen, +/area/interior/apc) +"F" = ( +/obj/machinery/quick_vendor/beginner{ + pixel_x = 28 + }, +/turf/closed/interior/apc/thirteen, +/area/interior/apc) +"H" = ( +/obj/machinery/cloning/vats/apc/south{ + pixel_y = -16 + }, +/turf/closed/interior/apc/four, +/area/interior/apc) +"I" = ( +/turf/closed/interior/apc/twentythree, +/area/interior/apc) +"J" = ( +/turf/open/interior/apc/fourteen, +/area/interior/apc) +"L" = ( +/turf/closed/interior/apc/twentyeight, +/area/interior/apc) +"P" = ( +/turf/closed/interior/apc/twentyfour, +/area/interior/apc) +"R" = ( +/obj/machinery/cloning/vats/apc{ + dir = 1; + pixel_y = 16 + }, +/turf/closed/interior/apc/twentyseven, +/area/interior/apc) +"S" = ( +/turf/closed/interior/apc/seventeen, +/area/interior/apc) +"T" = ( +/obj/machinery/computer/cloning_console/vats{ + dir = 1; + pixel_x = 8 + }, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"U" = ( +/obj/machinery/cloning/vats/apc/south{ + pixel_y = -16 + }, +/turf/closed/interior/apc/three, +/area/interior/apc) +"W" = ( +/obj/structure/ammo_rack/secondary{ + pixel_y = -13 + }, +/turf/closed/interior/apc/two, +/area/interior/apc) +"Y" = ( +/turf/closed/interior/apc/one, +/area/interior/apc) +"Z" = ( +/obj/structure/bed/chair/loader_seat{ + pixel_y = -5 + }, +/obj/structure/periscope/apc, +/turf/open/interior/apc/twentynine, +/area/interior/apc) + +(1,1,1) = {" +Y +C +F +p +a +"} +(2,1,1) = {" +e +s +J +T +R +"} +(3,1,1) = {" +t +c +D +T +R +"} +(4,1,1) = {" +t +c +D +T +R +"} +(5,1,1) = {" +U +c +D +T +R +"} +(6,1,1) = {" +H +c +D +Z +l +"} +(7,1,1) = {" +W +n +o +m +l +"} +(8,1,1) = {" +g +b +S +I +d +"} +(9,1,1) = {" +B +h +P +P +L +"} diff --git a/_maps/interiors/apc_medical.dmm b/_maps/interiors/apc_medical.dmm new file mode 100644 index 00000000000..f604f5c8a7d --- /dev/null +++ b/_maps/interiors/apc_medical.dmm @@ -0,0 +1,180 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/interior/apc/nineteen, +/area/interior/apc) +"b" = ( +/obj/structure/bed/chair/driver_gunner_seat{ + pixel_x = -3; + pixel_y = -5 + }, +/turf/open/interior/apc/eleven, +/area/interior/apc) +"c" = ( +/turf/open/interior/apc/nine, +/area/interior/apc) +"d" = ( +/turf/closed/interior/apc/twenty, +/area/interior/apc) +"e" = ( +/turf/closed/interior/apc/two, +/area/interior/apc) +"g" = ( +/turf/closed/interior/apc/five, +/area/interior/apc) +"h" = ( +/turf/closed/interior/apc/twelve, +/area/interior/apc) +"k" = ( +/obj/machinery/optable, +/obj/item/tank/anesthetic, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"l" = ( +/turf/closed/interior/apc/twentyseven, +/area/interior/apc) +"m" = ( +/obj/structure/gun_breech/secondary, +/turf/open/interior/apc/twentytwo, +/area/interior/apc) +"n" = ( +/turf/open/interior/apc/ten, +/area/interior/apc) +"o" = ( +/turf/open/interior/apc/sixteen, +/area/interior/apc) +"p" = ( +/turf/closed/interior/apc/thirteen, +/area/interior/apc) +"s" = ( +/turf/open/interior/apc/eight, +/area/interior/apc) +"t" = ( +/obj/structure/bed/chair/dropship/doublewide/left, +/obj/structure/bed/chair/dropship/doublewide/right, +/turf/open/interior/apc/nine, +/area/interior/apc) +"B" = ( +/turf/closed/interior/apc/six, +/area/interior/apc) +"C" = ( +/turf/closed/interior/tank/door, +/area/interior/apc) +"D" = ( +/turf/open/interior/apc/fifteen, +/area/interior/apc) +"F" = ( +/obj/machinery/vending/MarineMed, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"H" = ( +/turf/closed/interior/apc/four, +/area/interior/apc) +"I" = ( +/turf/closed/interior/apc/twentythree, +/area/interior/apc) +"J" = ( +/turf/open/interior/apc/fourteen, +/area/interior/apc) +"L" = ( +/turf/closed/interior/apc/twentyeight, +/area/interior/apc) +"O" = ( +/obj/structure/bed/chair/dropship/doublewide/left, +/obj/structure/bed/chair/dropship/doublewide/right, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"P" = ( +/turf/closed/interior/apc/twentyfour, +/area/interior/apc) +"S" = ( +/turf/closed/interior/apc/seventeen, +/area/interior/apc) +"T" = ( +/obj/structure/bed/chair/comfy{ + dir = 8 + }, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"U" = ( +/turf/closed/interior/apc/three, +/area/interior/apc) +"W" = ( +/obj/structure/ammo_rack/secondary{ + pixel_y = -13 + }, +/turf/closed/interior/apc/two, +/area/interior/apc) +"Y" = ( +/turf/closed/interior/apc/one, +/area/interior/apc) +"Z" = ( +/obj/structure/bed/chair/loader_seat{ + pixel_y = -5 + }, +/obj/structure/periscope/apc, +/turf/open/interior/apc/twentynine, +/area/interior/apc) + +(1,1,1) = {" +Y +C +p +p +a +"} +(2,1,1) = {" +e +s +J +F +l +"} +(3,1,1) = {" +e +c +D +k +l +"} +(4,1,1) = {" +e +t +D +T +l +"} +(5,1,1) = {" +U +t +D +O +l +"} +(6,1,1) = {" +H +t +D +Z +l +"} +(7,1,1) = {" +W +n +o +m +l +"} +(8,1,1) = {" +g +b +S +I +d +"} +(9,1,1) = {" +B +h +P +P +L +"} diff --git a/_maps/interiors/apc_transport.dmm b/_maps/interiors/apc_transport.dmm new file mode 100644 index 00000000000..cbf99ba2341 --- /dev/null +++ b/_maps/interiors/apc_transport.dmm @@ -0,0 +1,171 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/closed/interior/apc/nineteen, +/area/interior/apc) +"b" = ( +/turf/closed/interior/apc/four, +/area/interior/apc) +"c" = ( +/obj/structure/ammo_rack/secondary{ + pixel_y = -13 + }, +/turf/closed/interior/apc/two, +/area/interior/apc) +"f" = ( +/turf/closed/interior/apc/twentyfour, +/area/interior/apc) +"g" = ( +/turf/closed/interior/apc/six, +/area/interior/apc) +"j" = ( +/turf/closed/interior/apc/twentythree, +/area/interior/apc) +"l" = ( +/turf/closed/interior/apc/five, +/area/interior/apc) +"m" = ( +/obj/structure/periscope/apc, +/obj/structure/bed/chair/loader_seat{ + pixel_y = -5 + }, +/turf/open/interior/apc/nine, +/area/interior/apc) +"n" = ( +/obj/structure/bed/chair/dropship/doublewide/left, +/obj/structure/bed/chair/dropship/doublewide/right, +/turf/open/interior/apc/eight, +/area/interior/apc) +"p" = ( +/turf/closed/interior/apc/twelve, +/area/interior/apc) +"q" = ( +/turf/closed/interior/apc/three, +/area/interior/apc) +"r" = ( +/obj/structure/bed/chair/dropship/doublewide/left, +/obj/structure/bed/chair/dropship/doublewide/right, +/turf/open/interior/apc/nine, +/area/interior/apc) +"s" = ( +/obj/structure/periscope/apc, +/obj/structure/bed/chair/loader_seat{ + pixel_y = -5 + }, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"u" = ( +/obj/structure/gun_breech/secondary, +/turf/open/interior/apc/twentytwo, +/area/interior/apc) +"x" = ( +/turf/closed/interior/apc/twentyseven, +/area/interior/apc) +"y" = ( +/turf/closed/interior/apc/two, +/area/interior/apc) +"z" = ( +/turf/closed/interior/tank/door, +/area/interior/apc) +"B" = ( +/turf/closed/interior/apc/one, +/area/interior/apc) +"C" = ( +/obj/structure/bed/chair/driver_gunner_seat{ + pixel_x = -3; + pixel_y = -5 + }, +/turf/open/interior/apc/eleven, +/area/interior/apc) +"E" = ( +/turf/open/interior/apc/fourteen, +/area/interior/apc) +"F" = ( +/turf/closed/interior/apc/thirteen, +/area/interior/apc) +"G" = ( +/turf/closed/interior/apc/twentyeight, +/area/interior/apc) +"I" = ( +/turf/open/interior/apc/sixteen, +/area/interior/apc) +"J" = ( +/obj/structure/bed/chair/dropship/doublewide/left, +/obj/structure/bed/chair/dropship/doublewide/right, +/turf/open/interior/apc/twentynine, +/area/interior/apc) +"L" = ( +/turf/closed/interior/apc/seventeen, +/area/interior/apc) +"M" = ( +/turf/open/interior/apc/ten, +/area/interior/apc) +"R" = ( +/turf/closed/interior/apc/twenty, +/area/interior/apc) +"T" = ( +/turf/open/interior/apc/fifteen, +/area/interior/apc) + +(1,1,1) = {" +B +F +z +F +a +"} +(2,1,1) = {" +y +n +E +J +x +"} +(3,1,1) = {" +y +r +T +J +x +"} +(4,1,1) = {" +y +r +T +J +x +"} +(5,1,1) = {" +q +r +T +J +x +"} +(6,1,1) = {" +b +m +T +s +x +"} +(7,1,1) = {" +c +M +I +u +x +"} +(8,1,1) = {" +l +C +L +j +R +"} +(9,1,1) = {" +g +p +f +f +G +"} diff --git a/_maps/interiors/tank.dmm b/_maps/interiors/tank.dmm new file mode 100644 index 00000000000..e0dc236f120 --- /dev/null +++ b/_maps/interiors/tank.dmm @@ -0,0 +1,157 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/open/space/basic, +/area/interior/tank) +"b" = ( +/turf/closed/interior/tank/door, +/area/interior/tank) +"d" = ( +/obj/structure/bed/chair/vehicle_driver_seat{ + pixel_x = 11; + pixel_y = -6 + }, +/turf/open/interior/tank/twentytwo, +/area/interior/tank) +"f" = ( +/obj/machinery/telecomms/relay/preset/telecomms/onboard/nondense, +/turf/closed/interior/tank/twentyone, +/area/interior/tank) +"h" = ( +/turf/closed/interior/tank/five, +/area/interior/tank) +"j" = ( +/turf/closed/interior/tank/one, +/area/interior/tank) +"k" = ( +/turf/closed/interior/tank/twenty, +/area/interior/tank) +"l" = ( +/turf/open/interior/tank/nine, +/area/interior/tank) +"n" = ( +/turf/closed/interior/tank/eighteen, +/area/interior/tank) +"r" = ( +/turf/closed/interior/tank/twentythree, +/area/interior/tank) +"s" = ( +/turf/open/interior/tank/sixteen, +/area/interior/tank) +"t" = ( +/turf/closed/interior/tank/twentyfour, +/area/interior/tank) +"u" = ( +/obj/structure/gun_breech{ + pixel_x = -13; + pixel_y = -4 + }, +/turf/closed/interior/tank/seventeen, +/area/interior/tank) +"v" = ( +/obj/structure/bed/chair/loader_seat{ + pixel_y = -5 + }, +/obj/structure/periscope, +/turf/open/interior/tank/fifteen, +/area/interior/tank) +"w" = ( +/turf/closed/interior/tank/twentyseven, +/area/interior/tank) +"x" = ( +/turf/open/interior/tank/eight, +/area/interior/tank) +"z" = ( +/turf/closed/interior/tank/nineteen, +/area/interior/tank) +"A" = ( +/obj/structure/ammo_rack/primary{ + pixel_x = 1; + pixel_y = -10 + }, +/turf/closed/interior/tank/four, +/area/interior/tank) +"D" = ( +/turf/closed/interior/tank/twentyeight, +/area/interior/tank) +"E" = ( +/turf/closed/interior/tank/twelve, +/area/interior/tank) +"H" = ( +/turf/closed/interior/tank/twentyfive, +/area/interior/tank) +"I" = ( +/turf/closed/interior/tank/thirteen, +/area/interior/tank) +"M" = ( +/turf/closed/interior/tank/twentysix, +/area/interior/tank) +"N" = ( +/turf/open/interior/tank/ten, +/area/interior/tank) +"S" = ( +/obj/structure/bed/chair/vehicle_gunner_seat{ + pixel_x = -3; + pixel_y = -5 + }, +/turf/open/interior/tank/eleven, +/area/interior/tank) +"V" = ( +/obj/structure/ammo_rack/secondary{ + pixel_x = 11; + pixel_y = -18 + }, +/turf/closed/interior/tank/two, +/area/interior/tank) +"X" = ( +/turf/closed/interior/tank/six, +/area/interior/tank) +"Y" = ( +/obj/structure/gun_breech/secondary, +/turf/open/interior/tank/fourteen, +/area/interior/tank) +"Z" = ( +/turf/closed/interior/tank/three, +/area/interior/tank) + +(1,1,1) = {" +j +b +I +z +a +"} +(2,1,1) = {" +V +x +Y +k +a +"} +(3,1,1) = {" +Z +l +v +f +H +"} +(4,1,1) = {" +A +N +s +d +M +"} +(5,1,1) = {" +h +S +u +r +w +"} +(6,1,1) = {" +X +E +n +t +D +"} diff --git a/_maps/map_files/Arachne/TGS_Arachne.dmm b/_maps/map_files/Arachne/TGS_Arachne.dmm index ef0e2bf67fe..2c3e943e8f0 100644 --- a/_maps/map_files/Arachne/TGS_Arachne.dmm +++ b/_maps/map_files/Arachne/TGS_Arachne.dmm @@ -5474,7 +5474,7 @@ /obj/structure/bed/chair/office/dark{ dir = 1 }, -/obj/effect/landmark/start/job/pilotofficer, +/obj/effect/landmark/start/job/transportofficer, /turf/open/floor/wood, /area/mainship/living/pilotbunks) "eMo" = ( diff --git a/_maps/map_files/Campaign maps/orion_2/orionoutpost_2.dmm b/_maps/map_files/Campaign maps/orion_2/orionoutpost_2.dmm index d8b45142d7a..d0bcbaf7c8f 100644 --- a/_maps/map_files/Campaign maps/orion_2/orionoutpost_2.dmm +++ b/_maps/map_files/Campaign maps/orion_2/orionoutpost_2.dmm @@ -2863,7 +2863,7 @@ /area/orion_outpost/ground/underground/caveN) "nJ" = ( /obj/item/ammo_magazine/tank/ltb_cannon, -/obj/item/ammo_magazine/tank/ltaaap_minigun, +/obj/item/ammo_magazine/tank/ltaap_chaingun, /turf/open/floor/mainship/black{ dir = 8 }, @@ -6740,7 +6740,7 @@ /area/orion_outpost/ground/outpostcent) "Gr" = ( /obj/item/ammo_magazine/tank/ltb_cannon, -/obj/item/ammo_magazine/tank/ltaaap_minigun, +/obj/item/ammo_magazine/tank/ltaap_chaingun, /turf/open/floor/mainship/black/full, /area/orion_outpost/surface/building/ammodepot) "Gs" = ( diff --git a/_maps/map_files/Orion_Military_Outpost/orionoutpost.dmm b/_maps/map_files/Orion_Military_Outpost/orionoutpost.dmm index fabdf14b4cb..7a9abd31d51 100644 --- a/_maps/map_files/Orion_Military_Outpost/orionoutpost.dmm +++ b/_maps/map_files/Orion_Military_Outpost/orionoutpost.dmm @@ -2640,7 +2640,7 @@ /area/orion_outpost/ground/outpostsw) "nJ" = ( /obj/item/ammo_magazine/tank/ltb_cannon, -/obj/item/ammo_magazine/tank/ltaaap_minigun, +/obj/item/ammo_magazine/tank/ltaap_chaingun, /turf/open/floor/mainship/black{ dir = 8 }, @@ -6262,7 +6262,7 @@ /area/orion_outpost/ground/outpostcent) "Gr" = ( /obj/item/ammo_magazine/tank/ltb_cannon, -/obj/item/ammo_magazine/tank/ltaaap_minigun, +/obj/item/ammo_magazine/tank/ltaap_chaingun, /turf/open/floor/mainship/black/full, /area/orion_outpost/surface/building/ammodepot) "Gs" = ( diff --git a/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm b/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm index 309d2fa5d40..3cfdf883871 100644 --- a/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm +++ b/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm @@ -9338,7 +9338,7 @@ "lPM" = ( /obj/structure/bed, /obj/item/bedsheet/red, -/obj/effect/landmark/start/job/pilotofficer, +/obj/effect/landmark/start/job/transportofficer, /turf/open/floor/wood, /area/mainship/living/pilotbunks) "lPY" = ( diff --git a/_maps/map_files/Sulaco/TGS_Sulaco.dmm b/_maps/map_files/Sulaco/TGS_Sulaco.dmm index ec8ca33333c..8e1c4600efb 100644 --- a/_maps/map_files/Sulaco/TGS_Sulaco.dmm +++ b/_maps/map_files/Sulaco/TGS_Sulaco.dmm @@ -24023,7 +24023,6 @@ "tUA" = ( /obj/structure/bed/bunkbed, /obj/effect/landmark/start/job/pilotofficer, -/obj/effect/landmark/start/job/pilotofficer, /turf/open/floor/prison, /area/mainship/living/pilotbunks) "tVZ" = ( @@ -25840,6 +25839,10 @@ }, /turf/open/floor/prison/sterilewhite, /area/sulaco/cryosleep) +"wlD" = ( +/obj/effect/landmark/start/job/transportofficer, +/turf/open/floor/prison, +/area/mainship/living/pilotbunks) "wlT" = ( /obj/effect/turf_decal/warning_stripes/thin{ dir = 8 @@ -66275,7 +66278,7 @@ pWS hxN oLM ujq -aZw +wlD aZw tUA aXN diff --git a/_maps/map_files/Theseus/TGS_Theseus.dmm b/_maps/map_files/Theseus/TGS_Theseus.dmm index 20fa789152b..31d9b7f0131 100644 --- a/_maps/map_files/Theseus/TGS_Theseus.dmm +++ b/_maps/map_files/Theseus/TGS_Theseus.dmm @@ -10486,6 +10486,12 @@ /obj/effect/ai_node, /turf/open/floor/plating/plating_catwalk, /area/mainship/hallways/port_hallway) +"gXv" = ( +/obj/structure/bed, +/obj/item/bedsheet/brown, +/obj/effect/landmark/start/job/transportofficer, +/turf/open/floor/wood, +/area/mainship/living/pilotbunks) "gXD" = ( /obj/machinery/door/firedoor/mainship{ dir = 2 @@ -44351,7 +44357,7 @@ srL nKK lzj cZJ -stM +gXv lzj fZA aVk diff --git a/_maps/map_files/debugdalus/tgs_debugdalus.dmm b/_maps/map_files/debugdalus/tgs_debugdalus.dmm index abe6c9e0103..b3744cb0eed 100644 --- a/_maps/map_files/debugdalus/tgs_debugdalus.dmm +++ b/_maps/map_files/debugdalus/tgs_debugdalus.dmm @@ -305,12 +305,6 @@ /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) "abo" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/open/floor/mainship, -/area/mainship/hallways/exoarmor) -"abp" = ( /obj/structure/rack, /obj/item/tool/weldingtool, /obj/item/tool/weldpack, @@ -320,7 +314,7 @@ /obj/item/clothing/glasses/welding, /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) -"abq" = ( +"abp" = ( /obj/structure/rack, /obj/item/storage/backpack/marine/engineerpack, /obj/item/tool/weldingtool, @@ -330,10 +324,14 @@ /obj/item/clothing/glasses/welding, /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) -"abr" = ( +"abq" = ( /obj/structure/closet/secure_closet/engineering_welding, /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) +"abr" = ( +/obj/machinery/vending/engivend, +/turf/open/floor/mainship, +/area/mainship/hallways/exoarmor) "abs" = ( /obj/machinery/vending/tool, /turf/open/floor/mainship, @@ -442,6 +440,9 @@ dir = 1 }, /obj/structure/cable, +/obj/structure/rack, +/obj/item/stack/sheet/glass/phoronrglass, +/obj/item/stack/sheet/glass/phoronrglass, /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) "abU" = ( @@ -629,7 +630,7 @@ "acX" = ( /obj/item/storage/box/crate/sentry, /obj/structure/rack, -/obj/item/stack/sheet/glass{ +/obj/item/stack/sheet/glass/glass{ amount = 50; pixel_x = 3; pixel_y = 3 @@ -1192,18 +1193,6 @@ /obj/machinery/computer/crew, /turf/open/floor/mainship, /area/mainship/command/cic) -"afC" = ( -/obj/effect/attach_point/weapon/dropship2{ - dir = 8 - }, -/turf/open/floor/plating, -/area/mainship/hallways/hangar) -"afD" = ( -/obj/effect/attach_point/weapon/dropship2{ - dir = 4 - }, -/turf/open/floor/plating, -/area/mainship/hallways/hangar) "afE" = ( /obj/machinery/computer/ordercomp, /obj/structure/cable, @@ -1769,9 +1758,7 @@ /turf/open/floor/mainship, /area/mainship/medical/lower_medical) "aie" = ( -/obj/machinery/bodyscanner{ - dir = 8 - }, +/obj/machinery/bodyscanner, /turf/open/floor/mainship, /area/mainship/medical/lower_medical) "aif" = ( @@ -2264,6 +2251,16 @@ /obj/structure/window/framed/mainship, /turf/open/floor/plating, /area/mainship/command/telecomms) +"ayb" = ( +/obj/structure/cable, +/obj/machinery/landinglight/alamo{ + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "azU" = ( /turf/open/floor/mainship, /area/mainship/command/cic) @@ -2310,6 +2307,10 @@ "bOu" = ( /turf/open/floor/plating, /area/mainship/hallways/hangar) +"bXE" = ( +/obj/structure/ship_ammo/cas/bomb/fourhundred, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "bXN" = ( /obj/structure/cable, /obj/structure/closet/secure_closet/medical_doctor, @@ -2321,6 +2322,13 @@ }, /turf/open/floor/mainship, /area/mainship/squads/general) +"cXg" = ( +/obj/machinery/door/poddoor/railing{ + dir = 2; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "djH" = ( /obj/vehicle/ridden/powerloader, /obj/machinery/landinglight/cas, @@ -2337,10 +2345,18 @@ "dwY" = ( /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"dLM" = ( +/obj/structure/closet/secure_closet/engineering_personal, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "dPu" = ( /obj/machinery/vending/cargo_supply, /turf/open/floor/mainship, /area/mainship/squads/req) +"dTa" = ( +/obj/machinery/robotic_cradle, +/turf/open/floor/mainship, +/area/mainship/medical/lower_medical) "dZo" = ( /obj/structure/cable, /turf/open/floor/mainship, @@ -2420,8 +2436,28 @@ /obj/structure/ship_rail_gun, /turf/open/floor/mainship, /area/mainship/shipboard/weapon_room) +"gtH" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/quick_vendor/beginner, +/turf/open/floor/mainship, +/area/mainship/squads/general) "gOE" = ( /obj/machinery/light, +/obj/structure/rack, +/obj/item/stack/sheet/glass/reinforced{ + amount = 50 + }, +/obj/item/stack/sheet/glass/reinforced{ + amount = 50 + }, /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) "gUp" = ( @@ -2446,11 +2482,24 @@ }, /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"hSf" = ( +/obj/structure/rack, +/obj/item/stack/sheet/plasteel/large_stack, +/obj/item/stack/sheet/plasteel/large_stack, +/turf/open/floor/mainship, +/area/mainship/hallways/exoarmor) "ieJ" = ( /obj/structure/table/mainship, /obj/item/pizzabox/margherita, /turf/open/floor/mainship, /area/mainship/living/cryo_cells) +"iiS" = ( +/obj/structure/cable, +/obj/structure/rack, +/obj/item/stack/sheet/metal/large_stack, +/obj/item/stack/sheet/metal/large_stack, +/turf/open/floor/mainship, +/area/mainship/hallways/exoarmor) "ivw" = ( /obj/machinery/landinglight/alamo{ dir = 8 @@ -2477,6 +2526,13 @@ /obj/structure/cable, /turf/open/floor/mainship, /area/mainship/shipboard/weapon_room) +"jxZ" = ( +/obj/machinery/door/poddoor/railing{ + dir = 8; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "jPH" = ( /obj/machinery/bot/cleanbot, /turf/open/floor/mainship, @@ -2506,8 +2562,20 @@ dir = 1 }, /obj/structure/cable, +/obj/structure/rack, +/obj/item/stack/sheet/wood/large_stack, +/obj/item/stack/sheet/wood/large_stack, /turf/open/floor/mainship, /area/mainship/hallways/exoarmor) +"kEg" = ( +/obj/machinery/door/poddoor/railing{ + id = "vehicle_elevator_railing" + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "kEy" = ( /obj/machinery/light{ dir = 4 @@ -2518,6 +2586,15 @@ }, /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"kQa" = ( +/obj/machinery/light, +/obj/structure/dropship_equipment/cas/weapon/bomb_pod, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) +"kVr" = ( +/obj/machinery/gear/vehicle, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "lcb" = ( /obj/structure/cable, /obj/machinery/camera/autoname/mainship, @@ -2533,6 +2610,14 @@ }, /turf/open/floor/mainship, /area/mainship/medical/medical_science) +"leQ" = ( +/obj/structure/rack, +/obj/item/stack/sheet/glass/glass/large_stack, +/obj/item/stack/sheet/glass/glass/large_stack, +/obj/item/stack/sheet/glass/reinforced, +/obj/item/stack/sheet/glass/reinforced, +/turf/open/floor/mainship, +/area/mainship/hallways/exoarmor) "ljg" = ( /obj/effect/turf_decal/warning_stripes/box/small, /obj/effect/turf_decal/warning_stripes/box/small{ @@ -2570,6 +2655,10 @@ }, /turf/open/floor/mainship, /area/mainship/squads/req) +"lGu" = ( +/obj/machinery/tank_part_fabricator, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "lGz" = ( /obj/structure/closet/secure_closet/engineering_welding, /obj/machinery/camera/autoname/mainship{ @@ -2582,6 +2671,14 @@ /obj/structure/cable, /turf/open/floor/mainship, /area/mainship/medical/lower_medical) +"mfs" = ( +/obj/machinery/door/poddoor/railing{ + dir = 1; + id = "vehicle_elevator_railing" + }, +/obj/machinery/light, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "mlP" = ( /obj/machinery/vending/nanomed, /obj/structure/cable, @@ -2602,6 +2699,10 @@ /obj/machinery/cic_maptable, /turf/open/floor/mainship, /area/mainship/command/cic) +"nRd" = ( +/obj/structure/ship_ammo/cas/bomblet, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "oNT" = ( /obj/machinery/light{ dir = 1 @@ -2620,6 +2721,14 @@ }, /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"oQd" = ( +/obj/structure/cable, +/obj/effect/ai_node, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "qko" = ( /obj/machinery/camera/autoname/mainship, /turf/open/floor/mainship, @@ -2682,6 +2791,9 @@ /obj/machinery/landinglight/tadpole, /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"qWN" = ( +/turf/open/floor/mainship/empty, +/area/mainship/hallways/hangar) "rmh" = ( /obj/structure/cable, /obj/machinery/landinglight/alamo{ @@ -2712,6 +2824,10 @@ "rDw" = ( /turf/open/floor/mainship, /area/mainship/command/telecomms) +"rMD" = ( +/obj/machinery/vending/tool, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "rPl" = ( /obj/machinery/landinglight/tadpole{ dir = 8 @@ -2729,6 +2845,10 @@ }, /turf/open/floor/mainship, /area/mainship/command/cic) +"skH" = ( +/obj/structure/closet/secure_closet/engineering_welding, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "soy" = ( /obj/structure/cable, /obj/machinery/camera/autoname/mainship{ @@ -2739,6 +2859,13 @@ }, /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"sru" = ( +/obj/structure/table/mainship, +/obj/machinery/light{ + dir = 1 + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "syF" = ( /obj/structure/cable, /obj/machinery/landinglight/alamo{ @@ -2750,6 +2877,25 @@ /obj/machinery/floodlight/landing/hq, /turf/open/floor/mainship, /area/mainship/hallways/hangar) +"sDt" = ( +/obj/docking_port/stationary/supply/vehicle, +/turf/open/floor/mainship/empty, +/area/mainship/hallways/hangar) +"sPD" = ( +/obj/machinery/landinglight/alamo{ + dir = 8 + }, +/obj/machinery/landinglight/cas{ + dir = 4 + }, +/obj/machinery/light/floor{ + dir = 8 + }, +/obj/machinery/light/floor{ + dir = 4 + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "tae" = ( /obj/machinery/camera/autoname/mainship{ dir = 4 @@ -2772,6 +2918,10 @@ /obj/structure/cable, /turf/open/floor/mainship, /area/mainship/engineering/engineering_workshop) +"ttO" = ( +/obj/structure/dropship_equipment/cas/weapon/bomblet_pod, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "tQD" = ( /obj/machinery/light, /turf/open/floor/mainship, @@ -2814,6 +2964,13 @@ /obj/machinery/computer/orbital_cannon_console, /turf/open/floor/mainship, /area/mainship/shipboard/weapon_room) +"uyq" = ( +/obj/machinery/door/poddoor/railing{ + dir = 1; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "vsI" = ( /obj/structure/table/mainship, /obj/item/storage/donut_box, @@ -2853,6 +3010,12 @@ /obj/effect/turf_decal/warning_stripes/box/small, /turf/open/floor/mainship, /area/mainship/squads/general) +"wlt" = ( +/obj/machinery/door/poddoor/railing{ + id = "vehicle_elevator_railing" + }, +/turf/open/floor/mainship, +/area/mainship/hallways/hangar) "wpk" = ( /obj/structure/ship_ammo/cas/minirocket, /obj/machinery/light{ @@ -2885,6 +3048,12 @@ /obj/vehicle/unmanned/droid/scout, /turf/open/floor/mech_bay_recharge_floor, /area/mainship/command/telecomms) +"xiw" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/mainship, +/area/mainship/hallways/exoarmor) "xot" = ( /obj/structure/cable, /obj/effect/ai_node, @@ -3126,16 +3295,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +bgb +bgb +bgb +bgb +bgb +bgb +bgb +bgb +bgb aaa aaa aaa @@ -3186,16 +3355,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +lGu +kVr +wlt +kEg +wlt +wlt +wlt +kVr +bgb aaa aaa aaa @@ -3246,16 +3415,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +dwY +cXg +qWN +qWN +qWN +qWN +qWN +uyq +bgb aaa aaa aaa @@ -3306,16 +3475,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +dwY +cXg +qWN +qWN +qWN +qWN +qWN +uyq +bgb aaa aaa aaa @@ -3366,16 +3535,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +sru +cXg +qWN +qWN +sDt +qWN +qWN +mfs +bgb aaa aaa aaa @@ -3426,16 +3595,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +skH +cXg +qWN +qWN +qWN +qWN +qWN +uyq +bgb aaa aaa aaa @@ -3486,16 +3655,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +rMD +cXg +qWN +qWN +qWN +qWN +qWN +uyq +bgb aaa aaa aaa @@ -3546,16 +3715,16 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bgb +dLM +kVr +jxZ +jxZ +jxZ +jxZ +jxZ +kVr +bgb aaa aaa aaa @@ -3610,9 +3779,9 @@ bgb bgb bgb bgb -bgb -bgb -bgb +dwY +dwY +dwY bgb bgb bgb @@ -3669,9 +3838,9 @@ oQb dwY dwY dwY +oQb dwY dwY -oQb dwY dwY dwY @@ -3977,7 +4146,7 @@ xBy ldZ bgb rmt -dwY +bXE dwY dwY dwY @@ -4037,7 +4206,7 @@ ljw dwY bgb acJ -dwY +nRd dwY dwY dwY @@ -4104,7 +4273,7 @@ gUp dwY dwY dwY -dwY +ttO aji agd agt @@ -4164,7 +4333,7 @@ afg dwY dwY dwY -ldZ +kQa aji aji aji @@ -4215,7 +4384,7 @@ rPl rPl dwY dwY -acI +oQd syF syF syF @@ -4226,7 +4395,7 @@ syF syF syF syF -syF +ayb adG syF syF @@ -4786,7 +4955,7 @@ ahy ahy dZo aie -ahy +dTa ahy ajT ahg @@ -4944,7 +5113,7 @@ ecg tWe ivw ivw -ivw +sPD ivw ivw adU @@ -4954,7 +5123,7 @@ ivw ivw ivw ivw -ivw +sPD ivw ivw ahh @@ -5009,7 +5178,7 @@ bOu bOu bOu bOu -afC +bOu bOu bOu bOu @@ -5107,7 +5276,7 @@ aal vsI aab wqS -qxC +gtH aaA aaS qxC @@ -5609,7 +5778,7 @@ bOu bOu bOu bOu -afD +bOu bOu bOu bOu @@ -5891,9 +6060,9 @@ aaa aaa aea abn -xTV -xTV -xTV +xiw +leQ +hSf aea acn adA @@ -6013,7 +6182,7 @@ aea abo xTV xTV -abU +iiS aea aco acu diff --git a/_maps/map_files/slumbridge/slumbridge.dmm b/_maps/map_files/slumbridge/slumbridge.dmm index 8cd121860b2..76618408d74 100644 --- a/_maps/map_files/slumbridge/slumbridge.dmm +++ b/_maps/map_files/slumbridge/slumbridge.dmm @@ -9303,7 +9303,7 @@ /turf/open/floor/tile/yellow/full, /area/slumbridge/inside/engi/central) "hey" = ( -/obj/item/ammo_magazine/tank/ltaaap_minigun, +/obj/item/ammo_magazine/tank/ltaap_chaingun, /obj/structure/cable, /turf/open/floor/plating, /area/slumbridge/inside/sombase/east) @@ -15956,16 +15956,6 @@ /obj/structure/prop/mainship/holobarrier/passthrough, /turf/open/floor/plating/fake_space, /area/slumbridge/outside/northwest) -"lRh" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/flasher/portable, -/obj/machinery/atmospherics/pipe/simple/green/hidden{ - dir = 4 - }, -/turf/open/floor/prison/darkred{ - dir = 1 - }, -/area/slumbridge/inside/prison/outerringnorth) "lRi" = ( /turf/open/floor/plating/ground/snow/layer2{ dir = 10 diff --git a/_maps/shuttles/minidropship_factorio.dmm b/_maps/shuttles/minidropship_factorio.dmm index ba0f82638ee..02e7df7403c 100644 --- a/_maps/shuttles/minidropship_factorio.dmm +++ b/_maps/shuttles/minidropship_factorio.dmm @@ -72,9 +72,7 @@ /turf/open/floor/plating/plating_catwalk, /area/shuttle/minidropship) "w" = ( -/obj/machinery/camera/autoname/mainship{ - pixel_y = 16 - }, +/obj/machinery/camera/autoname/mainship/dropship_two, /turf/open/floor/mainship/mono, /area/shuttle/minidropship) "x" = ( diff --git a/_maps/shuttles/minidropship_food.dmm b/_maps/shuttles/minidropship_food.dmm index fa49947f571..5edd5a0fca5 100644 --- a/_maps/shuttles/minidropship_food.dmm +++ b/_maps/shuttles/minidropship_food.dmm @@ -7,7 +7,7 @@ /area/shuttle/minidropship) "c" = ( /obj/machinery/computer/camera_advanced/shuttle_docker/minidropship, -/obj/machinery/camera/autoname/mainship, +/obj/machinery/camera/autoname/mainship/dropship_two, /turf/open/floor/iron/white/textured_half, /area/shuttle/minidropship) "d" = ( diff --git a/_maps/shuttles/minidropship_mobile_bar.dmm b/_maps/shuttles/minidropship_mobile_bar.dmm index deaa0030965..6f15eb67c53 100644 --- a/_maps/shuttles/minidropship_mobile_bar.dmm +++ b/_maps/shuttles/minidropship_mobile_bar.dmm @@ -280,10 +280,10 @@ /area/shuttle/minidropship) "S" = ( /obj/machinery/computer/camera_advanced/shuttle_docker/minidropship, -/obj/machinery/camera/autoname/mainship, /obj/structure/barricade/metal{ dir = 1 }, +/obj/machinery/camera/autoname/mainship/dropship_two, /turf/open/floor/carpet/side{ dir = 1 }, diff --git a/_maps/shuttles/minidropship_standard.dmm b/_maps/shuttles/minidropship_standard.dmm index 9f47352a0ad..c1550db2b7b 100644 --- a/_maps/shuttles/minidropship_standard.dmm +++ b/_maps/shuttles/minidropship_standard.dmm @@ -88,7 +88,7 @@ /area/shuttle/minidropship) "u" = ( /obj/machinery/computer/camera_advanced/shuttle_docker/minidropship, -/obj/machinery/camera/autoname/mainship, +/obj/machinery/camera/autoname/mainship/dropship_two, /turf/open/floor/plating/plating_catwalk, /area/shuttle/minidropship) "v" = ( diff --git a/_maps/shuttles/minidropship_umbilical.dmm b/_maps/shuttles/minidropship_umbilical.dmm index 5a832d0a50f..c7787ac4aa9 100644 --- a/_maps/shuttles/minidropship_umbilical.dmm +++ b/_maps/shuttles/minidropship_umbilical.dmm @@ -42,9 +42,8 @@ dir = 8 }, /obj/effect/turf_decal/tile/transparent/dark_blue/full, -/obj/machinery/camera/autoname/mainship{ - dir = 8; - pixel_x = 14 +/obj/machinery/camera/autoname/mainship/dropship_two{ + dir = 8 }, /turf/open/floor/mainship/mono, /area/shuttle/minidropship) diff --git a/_maps/shuttles/vehicle_supply.dmm b/_maps/shuttles/vehicle_supply.dmm new file mode 100644 index 00000000000..b5765882876 --- /dev/null +++ b/_maps/shuttles/vehicle_supply.dmm @@ -0,0 +1,116 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"b" = ( +/turf/open/floor/plating, +/area/shuttle/vehicle_supply) +"c" = ( +/obj/docking_port/mobile/supply/vehicle, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"f" = ( +/obj/machinery/door/poddoor/railing{ + id = "vehicle_elevator_railing" + }, +/obj/machinery/door/poddoor/railing{ + dir = 2; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"l" = ( +/obj/machinery/door/poddoor/railing{ + dir = 8; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"C" = ( +/obj/machinery/door/poddoor/railing{ + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"E" = ( +/obj/machinery/door/poddoor/railing{ + dir = 2; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"I" = ( +/obj/machinery/door/poddoor/railing{ + dir = 1; + id = "vehicle_elevator_railing" + }, +/obj/machinery/door/poddoor/railing{ + dir = 8; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"K" = ( +/obj/machinery/door/poddoor/railing{ + dir = 1; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"M" = ( +/obj/machinery/door/poddoor/railing{ + dir = 8; + id = "vehicle_elevator_railing" + }, +/obj/machinery/door/poddoor/railing{ + dir = 2; + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) +"Q" = ( +/obj/machinery/door/poddoor/railing{ + dir = 1; + id = "vehicle_elevator_railing" + }, +/obj/machinery/door/poddoor/railing{ + id = "vehicle_elevator_railing" + }, +/turf/open/floor/plating/plating_catwalk, +/area/shuttle/vehicle_supply) + +(1,1,1) = {" +I +l +l +l +M +"} +(2,1,1) = {" +K +b +a +b +E +"} +(3,1,1) = {" +K +a +c +a +E +"} +(4,1,1) = {" +K +b +a +b +E +"} +(5,1,1) = {" +Q +C +C +C +f +"} diff --git a/code/__DEFINES/_subsystems.dm b/code/__DEFINES/_subsystems.dm index 6c25cd62616..c1d6e34e37b 100644 --- a/code/__DEFINES/_subsystems.dm +++ b/code/__DEFINES/_subsystems.dm @@ -80,6 +80,7 @@ #define INIT_ORDER_DBCORE 25 #define INIT_ORDER_SERVER_MAINT 23 #define INIT_ORDER_INPUT 21 +#define INIT_ORDER_VIS 20 #define INIT_ORDER_SOUNDS 19 #define INIT_ORDER_INSTRUMENTS 17 #define INIT_ORDER_GREYSCALE 16 @@ -125,6 +126,7 @@ #define FIRE_PRIORITY_AMBIENCE 10 #define FIRE_PRIORITY_WEED 11 #define FIRE_PRIORITY_GARBAGE 15 +#define FIRE_PRIORITY_VIS 15 #define FIRE_PRIORITY_MINIMAPS 17 #define FIRE_PRIORITY_DIRECTION 19 #define FIRE_PRIORITY_SPAWNING 20 diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index 5fca2c8b79e..09eee9b76bb 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -27,6 +27,8 @@ GLOBAL_LIST_EMPTY(all_req_one_access) #define ACCESS_MARINE_WO 45 #define ACCESS_MARINE_RO 46 #define ACCESS_MARINE_MECH 47 +#define ACCESS_MARINE_TADPOLE 48 +#define ACCESS_MARINE_ARMORED 49 #define ACCESS_MARINE_REMOTEBUILD 60 @@ -58,13 +60,13 @@ GLOBAL_LIST_EMPTY(all_req_one_access) #define PAYGRADES_ENLISTED list("C","CMN","E1","E2","E3", "E3E","E4","E5","E6","E7","E8","E9","PO3","PO2","PO1") //Just marines -#define ALL_MARINE_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_COMMANDER, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_MECH, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_MARINE_REMOTEBUILD) +#define ALL_MARINE_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_COMMANDER, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE, ACCESS_MARINE_MECH, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_MARINE_REMOTEBUILD) //Literally everything -#define ALL_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_MECH, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_NT_PMC_GREEN, ACCESS_NT_PMC_ORANGE, ACCESS_NT_PMC_RED, ACCESS_NT_PMC_BLACK, ACCESS_NT_PMC_WHITE, ACCESS_NT_CORPORATE, ACCESS_ILLEGAL_PIRATE, ACCESS_MARINE_REMOTEBUILD) +#define ALL_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE, ACCESS_MARINE_MECH, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_NT_PMC_GREEN, ACCESS_NT_PMC_ORANGE, ACCESS_NT_PMC_RED, ACCESS_NT_PMC_BLACK, ACCESS_NT_PMC_WHITE, ACCESS_NT_CORPORATE, ACCESS_ILLEGAL_PIRATE, ACCESS_MARINE_REMOTEBUILD) //PMC menk -#define ALL_PMC_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_NT_PMC_GREEN, ACCESS_NT_PMC_ORANGE, ACCESS_NT_PMC_RED, ACCESS_NT_PMC_BLACK, ACCESS_NT_PMC_WHITE, ACCESS_NT_CORPORATE, ACCESS_MARINE_REMOTEBUILD) +#define ALL_PMC_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_NT_PMC_GREEN, ACCESS_NT_PMC_ORANGE, ACCESS_NT_PMC_RED, ACCESS_NT_PMC_BLACK, ACCESS_NT_PMC_WHITE, ACCESS_NT_CORPORATE, ACCESS_MARINE_REMOTEBUILD) //Removes PMC and Marine IFF -#define ALL_ANTAGONIST_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_MECH, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_NT_PMC_GREEN, ACCESS_NT_PMC_ORANGE, ACCESS_NT_PMC_RED, ACCESS_NT_PMC_BLACK, ACCESS_NT_PMC_WHITE, ACCESS_NT_CORPORATE, ACCESS_ILLEGAL_PIRATE, ACCESS_MARINE_REMOTEBUILD) +#define ALL_ANTAGONIST_ACCESS list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_BRIG, ACCESS_MARINE_ARMORY, ACCESS_MARINE_WO, ACCESS_MARINE_CMO, ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_MEDBAY, ACCESS_MARINE_PREP, ACCESS_MARINE_MEDPREP, ACCESS_MARINE_ENGPREP,ACCESS_MARINE_SMARTPREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA, ACCESS_MARINE_CHEMISTRY, ACCESS_MARINE_RESEARCH, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE, ACCESS_MARINE_MECH, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_ENGINEERING, ACCESS_CIVILIAN_LOGISTICS, ACCESS_NT_PMC_GREEN, ACCESS_NT_PMC_ORANGE, ACCESS_NT_PMC_RED, ACCESS_NT_PMC_BLACK, ACCESS_NT_PMC_WHITE, ACCESS_NT_CORPORATE, ACCESS_ILLEGAL_PIRATE, ACCESS_MARINE_REMOTEBUILD) diff --git a/code/__DEFINES/apc_defines.dm b/code/__DEFINES/apc_defines.dm new file mode 100644 index 00000000000..53d27679e07 --- /dev/null +++ b/code/__DEFINES/apc_defines.dm @@ -0,0 +1,81 @@ + +#define APC_WIRE_IDSCAN (1<<0) +#define APC_WIRE_MAIN_POWER1 (1<<1) +#define APC_WIRE_MAIN_POWER2 (1<<2) +#define APC_WIRE_AI_CONTROL (1<<3) + +#define APC_RESET_EMP 5 + +// APC electronics status: +/// There are no electronics in the APC. +#define APC_ELECTRONICS_MISSING 0 +/// The electronics are installed but not secured. +#define APC_ELECTRONICS_INSTALLED 1 +/// The electronics are installed and secured. +#define APC_ELECTRONICS_SECURED 2 + +// APC cover status: +/// The APCs cover is closed. +#define APC_COVER_CLOSED 0 +/// The APCs cover is open. +#define APC_COVER_OPENED 1 +/// The APCs cover is missing. +#define APC_COVER_REMOVED 2 + +// APC charging status: +/// The APC is not charging. +#define APC_NOT_CHARGING 0 +/// The APC is charging. +#define APC_CHARGING 1 +/// The APC is fully charged. +#define APC_FULLY_CHARGED 2 + +#define APC_EXTERNAL_POWER_NONE 0 +#define APC_EXTERNAL_POWER_LOW 1 +#define APC_EXTERNAL_POWER_GOOD 2 + +// APC channel status: +/// The APCs power channel is manually set off. +#define APC_CHANNEL_OFF 0 +/// The APCs power channel is automatically off. +#define APC_CHANNEL_AUTO_OFF 1 +/// The APCs power channel is manually set on. +#define APC_CHANNEL_ON 2 +/// The APCs power channel is automatically on. +#define APC_CHANNEL_AUTO_ON 3 + +#define APC_CHANNEL_IS_ON(channel) (channel >= APC_CHANNEL_ON) + +// update_state +// Bitshifts: (If you change the status values to be something other than an int or able to exceed 3 you will need to change these too) +/// The bit shift for the APCs cover status. +#define UPSTATE_COVER_SHIFT (0) + /// The bitflag representing the APCs cover being open for icon purposes. + #define UPSTATE_OPENED1 (APC_COVER_OPENED << UPSTATE_COVER_SHIFT) + /// The bitflag representing the APCs cover being missing for icon purposes. + #define UPSTATE_OPENED2 (APC_COVER_REMOVED << UPSTATE_COVER_SHIFT) + +// Bitflags: +/// The APC is broken or damaged. +#define UPSTATE_BROKE (1<<2) +/// The APC is undergoing maintenance. +#define UPSTATE_MAINT (1<<3) +/// The APCs wires are exposed. +#define UPSTATE_WIREEXP (1<<4) + +// update_overlay +// Bitflags: +/// Bitflag indicating that the APCs operating status overlay should be shown. +#define UPOVERLAY_OPERATING (1<<0) +/// Bitflag indicating that the APCs locked status overlay should be shown. +#define UPOVERLAY_LOCKED (1<<1) + +// Bitshifts: (If you change the status values to be something other than an int or able to exceed 3 you will need to change these too) +/// Bit shift for the charging status of the APC. +#define UPOVERLAY_CHARGING_SHIFT (2) +/// Bit shift for the equipment status of the APC. +#define UPOVERLAY_EQUIPMENT_SHIFT (4) +/// Bit shift for the lighting channel status of the APC. +#define UPOVERLAY_LIGHTING_SHIFT (6) +/// Bit shift for the environment channel status of the APC. +#define UPOVERLAY_ENVIRON_SHIFT (8) diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 4055a462ebd..6633b1f43b7 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -52,6 +52,9 @@ #define COOLDOWN_TRY_TTS "cooldown_try_tts" #define COOLDOWN_EVACUATION "evacuation" #define COOLDOWN_SENTIENT_HUGGER "sentient_hugger" +#define COOLDOWN_EVASION_ACTIVATION "cooldown_evasion_activation" +#define COOLDOWN_TANK_SWIVEL "tank_turret_swivel" +#define COOLDOWN_ARMORED_HORN "cooldown_armored_horn" //Mecha cooldowns #define COOLDOWN_MECHA "mecha" @@ -63,6 +66,7 @@ #define COOLDOWN_MECHA_SKYFALL "mecha_skyfall" #define COOLDOWN_MECHA_MISSILE_STRIKE "mecha_missile_strike" +#define COOLDOWN_VEHICLE_CRUSHSOUND "cooldown_vehicle_crushsound" //// COOLDOWN SYSTEMS /* * We have 2 cooldown systems: timer cooldowns (divided between stoppable and regular) and world.time cooldowns. diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 83dec12ede0..3d596d510ed 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -229,10 +229,32 @@ ///from base of atom/get_mechanics_info(): (/mob) #define COMSIG_ATOM_GET_MECHANICS_INFO "atom_mechanics_info" #define COMPONENT_MECHANICS_CHANGE (1<<0) -#define COMSIG_ATOM_UPDATE_ICON "atom_update_icon" //from base of atom/update_icon(): () - #define COMSIG_ATOM_NO_UPDATE_ICON_STATE (1<<0) - #define COMSIG_ATOM_NO_UPDATE_OVERLAYS (1<<1) -#define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays" //from base of atom/update_overlays(): (list/new_overlays) + +///from base of [/atom/proc/update_appearance]: (updates) +#define COMSIG_ATOM_UPDATE_APPEARANCE "atom_update_appearance" + /// If returned from [COMSIG_ATOM_UPDATE_APPEARANCE] it prevents the atom from updating its name. + #define COMSIG_ATOM_NO_UPDATE_NAME UPDATE_NAME + /// If returned from [COMSIG_ATOM_UPDATE_APPEARANCE] it prevents the atom from updating its desc. + #define COMSIG_ATOM_NO_UPDATE_DESC UPDATE_DESC + /// If returned from [COMSIG_ATOM_UPDATE_APPEARANCE] it prevents the atom from updating its icon. + #define COMSIG_ATOM_NO_UPDATE_ICON UPDATE_ICON +///from base of [/atom/proc/update_name]: (updates) +#define COMSIG_ATOM_UPDATE_NAME "atom_update_name" +///from base of [/atom/proc/update_desc]: (updates) +#define COMSIG_ATOM_UPDATE_DESC "atom_update_desc" +///from base of [/atom/update_icon]: () +#define COMSIG_ATOM_UPDATE_ICON "atom_update_icon" + /// If returned from [COMSIG_ATOM_UPDATE_ICON] it prevents the atom from updating its icon state. + #define COMSIG_ATOM_NO_UPDATE_ICON_STATE UPDATE_ICON_STATE + /// If returned from [COMSIG_ATOM_UPDATE_ICON] it prevents the atom from updating its overlays. + #define COMSIG_ATOM_NO_UPDATE_OVERLAYS UPDATE_OVERLAYS +///from base of [atom/update_icon_state]: () +#define COMSIG_ATOM_UPDATE_ICON_STATE "atom_update_icon_state" +///from base of [/atom/update_overlays]: (list/new_overlays) +#define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays" +///from base of [/atom/update_icon]: (signalOut, did_anything) +#define COMSIG_ATOM_UPDATED_ICON "atom_updated_icon" + #define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target) #define COMSIG_ATOM_SET_LIGHT "atom_set_light" //from base of atom/set_light(): (l_range, l_power, l_color) #define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" //from base of atom/bullet_act(): (/obj/projectile) @@ -275,6 +297,8 @@ #define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force) #define COMPONENT_MOVABLE_BUCKLE_STOPPED (1<<0) #define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force) +///from /obj/vehicle/sealed/proc/driver_move +#define COMSIG_VEHICLE_MOVE "vehicle_move" ///from /obj/vehicle/proc/driver_move, caught by the riding component to check and execute the driver trying to drive the vehicle #define COMSIG_RIDDEN_DRIVER_MOVE "driver_move" #define COMPONENT_DRIVER_BLOCK_MOVE (1<<0) @@ -421,6 +445,8 @@ #define COMSIG_MECH_FIRE "mech_fire" #define COMSIG_MECH_STOP_FIRE "mech_stop_fire" +#define COMSIG_ARMORED_FIRE "armored_fire" +#define COMSIG_ARMORED_STOP_FIRE "armored_stop_fire" // /obj/item/clothing signals #define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): () @@ -943,6 +969,7 @@ #define COMSIG_KB_ATTACKORDER "keybind_attackorder" #define COMSIG_KB_DEFENDORDER "keybind_defendorder" #define COMSIG_KB_RETREATORDER "keybind_retreatorder" +#define COMSIG_KB_VEHICLEHONK "keybind_vehiclehonk" // human modules signals for keybindings #define COMSIG_KB_VALI_CONFIGURE "keybinding_vali_configure" diff --git a/code/__DEFINES/dropship_equipment.dm b/code/__DEFINES/dropship_equipment.dm index 49cb471d38f..b13f432068f 100644 --- a/code/__DEFINES/dropship_equipment.dm +++ b/code/__DEFINES/dropship_equipment.dm @@ -17,6 +17,8 @@ #define CAS_MISSILE 3 #define CAS_30MM 4 #define RAILGUN_AMMO 5 +#define CAS_BOMBLET 6 +#define CAS_BOMB 7 //Ammo impact type defines #define CAS_AMMO_EXPLOSIVE 1//Uses explosive ammo. Missiles/bombs, etc. diff --git a/code/__DEFINES/equipment.dm b/code/__DEFINES/equipment.dm index 250d7559763..32845ad2064 100644 --- a/code/__DEFINES/equipment.dm +++ b/code/__DEFINES/equipment.dm @@ -22,6 +22,8 @@ #define PASS_AIR (1<<9) ///Mobs can walk freely between turfs with walkover flagged objects #define PASS_WALKOVER (1<<10) +///when jumping, mobs can pass onto tanks +#define PASS_TANK (1<<11) #define PASSABLE (PASS_THROW|PASS_PROJECTILE|PASS_AIR) #define HOVERING (PASS_LOW_STRUCTURE|PASS_MOB|PASS_DEFENSIVE_STRUCTURE|PASS_FIRE) @@ -64,29 +66,50 @@ //bitflags that were previously under flags_atom, these only apply to items. //clothing specific stuff uses flags_inventory. //flags_item -#define NOBLUDGEON (1<<0) // when an item has this it produces no "X has been hit by Y with Z" message with the default handler -#define DELONDROP (1<<1) // Deletes on drop instead of falling on the floor. -#define TWOHANDED (1<<2) // The item is twohanded. -#define WIELDED (1<<3) // The item is wielded with both hands. -#define ITEM_ABSTRACT (1<<4) //The item is abstract (grab, powerloader_clamp, etc) -#define DOES_NOT_NEED_HANDS (1<<5) //Dont need hands to use it -#define SYNTH_RESTRICTED (1<<6) //Prevents synths from wearing items with this flag -#define IMPEDE_JETPACK (1<<7) //Reduce the range of jetpack -#define CAN_BUMP_ATTACK (1<<8) //Item triggers bump attack -#define IS_DEPLOYABLE (1<<9) //Item can be deployed into a machine +/// when an item has this it produces no "X has been hit by Y with Z" message with the default handler +#define NOBLUDGEON (1<<0) +/// Deletes on drop instead of falling on the floor. +#define DELONDROP (1<<1) +/// The item is twohanded. +#define TWOHANDED (1<<2) +/// The item is wielded with both hands. +#define WIELDED (1<<3) +///The item is abstract (grab, powerloader_clamp, etc) +#define ITEM_ABSTRACT (1<<4) +///Dont need hands to use it +#define DOES_NOT_NEED_HANDS (1<<5) +///Prevents synths from wearing items with this flag +#define SYNTH_RESTRICTED (1<<6) +///Reduce the range of jetpack +#define IMPEDE_JETPACK (1<<7) +///Item triggers bump attack +#define CAN_BUMP_ATTACK (1<<8) +///Item can be deployed into a machine +#define IS_DEPLOYABLE (1<<9) +///Item deploys on initialize #define DEPLOY_ON_INITIALIZE (1<<10) -#define IS_DEPLOYED (1<<11) //If this is on an item, said item is currently deployed -#define DEPLOYED_NO_PICKUP (1<<12) //Disables deployed item pickup -#define DEPLOYED_NO_ROTATE (1<<13) //Disables deployed item rotation abilities to rotate. -#define DEPLOYED_NO_ROTATE_ANCHORED (1<<14) //Disables deployed item rotation if anchored. -#define DEPLOYED_WRENCH_DISASSEMBLE (1<<15) //If this is on an item, the item can only be disassembled using a wrench once deployed. -#define DEPLOYED_ANCHORED_FIRING_ONLY (1<<16) //Disables firing deployable if it is not anchored. -#define FULLY_WIELDED (1<<17) //If the item is properly wielded. Used for guns +///If this is on an item, said item is currently deployed +#define IS_DEPLOYED (1<<11) +///Disables deployed item pickup +#define DEPLOYED_NO_PICKUP (1<<12) +///Disables deployed item rotation abilities to rotate. +#define DEPLOYED_NO_ROTATE (1<<13) +///Disables deployed item rotation if anchored. +#define DEPLOYED_NO_ROTATE_ANCHORED (1<<14) +///If this is on an item, the item can only be disassembled using a wrench once deployed. +#define DEPLOYED_WRENCH_DISASSEMBLE (1<<15) +///Disables firing deployable if it is not anchored. +#define DEPLOYED_ANCHORED_FIRING_ONLY (1<<16) +///If the item is properly wielded. Used for guns +#define FULLY_WIELDED (1<<17) ///If a holster has underlay sprites #define HAS_UNDERLAY (1<<18) ///is this item equipped into an inventory slot or hand of a mob? #define IN_INVENTORY (1<<19) +///ITEM_PREDATOR #define ITEM_PREDATOR (1<<20) +///This item is used for autobalance calculations or excluded, such as valhalla items +#define AUTOBALANCE_CHECK (1<<21) //flags_storage ///If a storage container can be restocked into a vendor diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 79addbd1b66..3eff083c0ee 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -24,3 +24,19 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define DF_USE_TAG (1<<0) #define DF_VAR_EDITED (1<<1) #define DF_ISPROCESSING (1<<2) + +// Update flags for [/atom/proc/update_appearance] +/// Update the atom's name +#define UPDATE_NAME (1<<0) +/// Update the atom's desc +#define UPDATE_DESC (1<<1) +/// Update the atom's icon state +#define UPDATE_ICON_STATE (1<<2) +/// Update the atom's overlays +#define UPDATE_OVERLAYS (1<<3) +/// Update the atom's icon +#define UPDATE_ICON (UPDATE_ICON_STATE|UPDATE_OVERLAYS) + +//alternate appearance flags +#define AA_TARGET_SEE_APPEARANCE (1<<0) +#define AA_MATCH_TARGET_OVERLAYS (1<<1) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 308bdd47271..d63ab0aef12 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -243,6 +243,10 @@ #define ismecha(A) (istype(A, /obj/vehicle/sealed/mecha)) +#define isarmoredvehicle(A) (istype(A, /obj/vehicle/sealed/armored)) + +#define ishitbox(A) (istype(A, /obj/hitbox)) + #define isorgan(A) (istype(A, /datum/limb)) #define isidcard(A) (istype(A, /obj/item/card/id)) diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm index 2eb28e5ef9b..873e6c46db8 100644 --- a/code/__DEFINES/jobs.dm +++ b/code/__DEFINES/jobs.dm @@ -12,6 +12,7 @@ #define JOB_DISPLAY_ORDER_CORPORATE_LIAISON 8 #define JOB_DISPLAY_ORDER_SYNTHETIC 9 #define JOB_DISPLAY_ORDER_AI 10 +#define JOB_DISPLAY_ORDER_TRANSPORT_OFFICER 11 #define JOB_DISPLAY_ORDER_CHIEF_ENGINEER 13 #define JOB_DISPLAY_ORDER_SHIP_TECH 14 #define JOB_DISPLAY_ORDER_REQUISITIONS_OFFICER 15 @@ -47,8 +48,11 @@ #define EXECUTIVE_OFFICER "Executive Officer" //Currently disabled. #define FIELD_COMMANDER "Field Commander" #define STAFF_OFFICER "Staff Officer" +#define TRANSPORT_OFFICER "Transport Officer" #define PILOT_OFFICER "Pilot Officer" #define MECH_PILOT "Mech Pilot" +#define ASSAULT_CREWMAN "Assault Crewman" +#define TRANSPORT_CREWMAN "Transport Crewman" #define REQUISITIONS_OFFICER "Requisitions Officer" #define CHIEF_SHIP_ENGINEER "Chief Ship Engineer" #define CHIEF_MEDICAL_OFFICER "Chief Medical Officer" @@ -106,14 +110,14 @@ #define ROLE_FALLEN(role) ("Fallen " + ##role) GLOBAL_LIST_EMPTY(jobs_command) -GLOBAL_LIST_INIT(jobs_officers, list(CAPTAIN, FIELD_COMMANDER, STAFF_OFFICER, PILOT_OFFICER, MECH_PILOT, CORPORATE_LIAISON, SYNTHETIC, SILICON_AI, SQUAD_LEADER, CHIEF_MEDICAL_OFFICER, CHIEF_SHIP_ENGINEER, REQUISITIONS_OFFICER)) +GLOBAL_LIST_INIT(jobs_officers, list(CAPTAIN, FIELD_COMMANDER, STAFF_OFFICER, PILOT_OFFICER, TRANSPORT_OFFICER, MECH_PILOT, ASSAULT_CREWMAN, TRANSPORT_CREWMAN, CORPORATE_LIAISON, SYNTHETIC, SILICON_AI)) GLOBAL_LIST_INIT(jobs_support, list(PILOT_OFFICER, MECH_PILOT, REQUISITIONS_OFFICER, SYNTHETIC, SILICON_AI)) GLOBAL_LIST_INIT(jobs_engineering, list(CHIEF_SHIP_ENGINEER, SHIP_TECH, SQUAD_ENGINEER)) GLOBAL_LIST_INIT(jobs_requisitions, list(REQUISITIONS_OFFICER)) GLOBAL_LIST_INIT(jobs_medical, list(CHIEF_MEDICAL_OFFICER, MEDICAL_DOCTOR, MEDICAL_RESEARCHER, SQUAD_CORPSMAN)) GLOBAL_LIST_INIT(jobs_marines, list(SQUAD_LEADER, SQUAD_SMARTGUNNER, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_MARINE)) GLOBAL_LIST_INIT(jobs_som, list(SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_CORPSMAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER, SOM_STAFF_OFFICER, SOM_COMMANDER)) -GLOBAL_LIST_INIT(jobs_regular_all, list(CAPTAIN, FIELD_COMMANDER, STAFF_OFFICER, PILOT_OFFICER, MECH_PILOT, REQUISITIONS_OFFICER, CHIEF_SHIP_ENGINEER, \ +GLOBAL_LIST_INIT(jobs_regular_all, list(CAPTAIN, FIELD_COMMANDER, STAFF_OFFICER, PILOT_OFFICER, TRANSPORT_OFFICER, MECH_PILOT, REQUISITIONS_OFFICER, CHIEF_SHIP_ENGINEER, \ CHIEF_MEDICAL_OFFICER, SYNTHETIC, SILICON_AI, CORPORATE_LIAISON, SHIP_TECH, \ MEDICAL_DOCTOR, MEDICAL_RESEARCHER, SQUAD_LEADER, SQUAD_SMARTGUNNER, SQUAD_CORPSMAN, SQUAD_ENGINEER, SQUAD_MARINE, \ SOM_SQUAD_MARINE, SOM_SQUAD_VETERAN, SOM_SQUAD_ENGINEER, SOM_SQUAD_CORPSMAN, SOM_SQUAD_LEADER, SOM_FIELD_COMMANDER, SOM_STAFF_OFFICER, SOM_COMMANDER)) @@ -162,6 +166,7 @@ GLOBAL_LIST_INIT(jobs_fallen_marine, typecacheof(list(/datum/job/fallen/marine), #define SMARTIE_POINTS_HIGH 3 #define SYNTH_POINTS_REGULAR 1 #define MECH_POINTS_REGULAR 1 +#define ARMORED_VEHICLE_POINTS_REGULAR 1 #define VETERAN_POINTS_REGULAR 1 diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 8d62d64dbe7..ec81f0ee8ba 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -135,7 +135,7 @@ ///for platform corner structures #define ABOVE_MOB_PLATFORM_LAYER 4.11 -#define TANK_BARREL_LAYER 4.2 +#define ABOVE_MOB_PROP_LAYER 4.2 #define TANK_TURRET_LAYER 4.27 diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index 574fc8f03b1..e7fc83bf0b0 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -50,37 +50,6 @@ #define NSDIRFLIP(d) (d^(NORTH|SOUTH)) #define EWDIRFLIP(d) (d^(EAST|WEST)) -//update_state -#define UPSTATE_OPENED1 (1<<0) -#define UPSTATE_OPENED2 (1<<1) -#define UPSTATE_MAINT (1<<2) -#define UPSTATE_BROKE (1<<3) -#define UPSTATE_WIREEXP (1<<4) -#define UPSTATE_ALLGOOD (1<<5) - -//update_overlay -#define APC_UPOVERLAY_CHARGEING0 (1<<0) -#define APC_UPOVERLAY_CHARGEING1 (1<<1) -#define APC_UPOVERLAY_CHARGEING2 (1<<2) -#define APC_UPOVERLAY_EQUIPMENT0 (1<<3) -#define APC_UPOVERLAY_EQUIPMENT1 (1<<4) -#define APC_UPOVERLAY_EQUIPMENT2 (1<<5) -#define APC_UPOVERLAY_LIGHTING0 (1<<6) -#define APC_UPOVERLAY_LIGHTING1 (1<<7) -#define APC_UPOVERLAY_LIGHTING2 (1<<8) -#define APC_UPOVERLAY_ENVIRON0 (1<<9) -#define APC_UPOVERLAY_ENVIRON1 (1<<10) -#define APC_UPOVERLAY_ENVIRON2 (1<<11) -#define APC_UPOVERLAY_LOCKED (1<<12) -#define APC_UPOVERLAY_OPERATING (1<<13) -#define APC_UPOVERLAY_CELL_IN (1<<14) -#define APC_UPOVERLAY_BLUESCREEN (1<<15) - -#define APC_WIRE_IDSCAN (1<<0) -#define APC_WIRE_MAIN_POWER1 (1<<1) -#define APC_WIRE_MAIN_POWER2 (1<<2) -#define APC_WIRE_AI_CONTROL (1<<3) - #define MACHINE_NOT_ELECTRIFIED 0 #define MACHINE_ELECTRIFIED_PERMANENT -1 #define MACHINE_DEFAULT_ELECTRIFY_TIME 30 diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm index 36bd0cbff24..a7dbf5411a2 100644 --- a/code/__DEFINES/mecha.dm +++ b/code/__DEFINES/mecha.dm @@ -95,6 +95,8 @@ ///degree of cone in front of which mech is allowed to fire at #define MECH_FIRE_CONE_ALLOWED 120 +///degree of cone in front of which armored vehicles are allowed to fire at +#define ARMORED_FIRE_CONE_ALLOWED 110 /** * greyscale mech shenanigans */ diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index b0830a04967..c4569316720 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -25,6 +25,11 @@ #define DIRT_TYPE_SNOW 3 #define DIRT_TYPE_LAVALAND 4 +///How many variations of bullethole patterns there are +#define BULLETHOLE_STATES 10 +///Maximum possible bullet holes in a closed turf +#define BULLETHOLE_MAX 24 + //wet floors #define FLOOR_WET_WATER 1 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 4b906e025e8..59358d33a2a 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -4,6 +4,12 @@ #define AI_VOX //Mob movement define + +///Speed mod for walk intent +#define MOB_WALK_MOVE_MOD 4 +///Speed mod for run intent +#define MOB_RUN_MOVE_MOD 3 +///Move mod for going diagonally #define DIAG_MOVEMENT_ADDED_DELAY_MULTIPLIER 1.6 @@ -873,6 +879,15 @@ GLOBAL_LIST_INIT(human_body_parts, list(BODY_ZONE_HEAD, ///Combat robot species #define SPECIES_COMBAT_ROBOT "species_combat_robot" +///Nextmove delay after performing an interaction with a grab on something +#define GRAB_SLAM_DELAY 0.7 SECONDS +///Default damage for slamming a mob against an object +#define BASE_OBJ_SLAM_DAMAGE 10 +///Default damage for slamming a mob against a wall +#define BASE_WALL_SLAM_DAMAGE 15 +///Default damage for slamming a mob against another mob +#define BASE_MOB_SLAM_DAMAGE 8 + #define IS_YAUTJA (1<<6) #define MOTH_WINGS_LAYER 28 diff --git a/code/__DEFINES/movement.dm b/code/__DEFINES/movement.dm index 31345b34104..cbb6a9d8941 100644 --- a/code/__DEFINES/movement.dm +++ b/code/__DEFINES/movement.dm @@ -1,16 +1,25 @@ //The minimum for glide_size to be clamped to. //If you want more classic style "delay" movement while still retaining the smoothness improvements at higher framerates, set this to 8 -#define MIN_GLIDE_SIZE 0 +#define MIN_GLIDE_SIZE 3 //The maximum for glide_size to be clamped to. //This shouldn't be higher than the icon size, and generally you shouldn't be changing this, but it's here just in case. #define MAX_GLIDE_SIZE 32 -#define DELAY_TO_GLIDE_SIZE(delay) (round((clamp(((32 / max(delay / world.tick_lag, 1)) * (1 - (SStime_track.time_dilation_current / 100)) * (CONFIG_GET(number/glide_size_mod) * 0.01)), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE)), 0.1)) +/// Compensating for time dilation +GLOBAL_VAR_INIT(glide_size_multiplier, 1) -#define DELAY_TO_GLIDE_SIZE_STATIC(delay) (round(clamp((32 / (delay || 1)) * (CONFIG_GET(number/glide_size_mod) * 0.01), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE), 0.1)) +///Broken down, here's what this does: +/// divides the world icon_size (32) by delay divided by ticklag to get the number of pixels something should be moving each tick. +/// The division result is given a min value of 1 to prevent obscenely slow glide sizes from being set +/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave. +/// The whole result is then clamped to within the range above. +/// Not very readable but it works +#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE)) + +///Similar to DELAY_TO_GLIDE_SIZE, except without the clamping, and it supports piping in an unrelated scalar +#define MOVEMENT_ADJUSTED_GLIDE_SIZE(delay, movement_disparity) (32 / ((delay) / world.tick_lag) * movement_disparity * GLOB.glide_size_multiplier) -//Old behavior, client related. Currently unused. -#define DELAY_TO_GLIDE_SIZE_OLD(source, delay) (round(source.tick_lag ? ((32 / max(delay, source.tick_lag)) * source.tick_lag) : 0, 0.1)) +#define DELAY_TO_GLIDE_SIZE_STATIC(delay) (round(clamp((32 / (delay || 1)) * (CONFIG_GET(number/glide_size_mod) * 0.01), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE), 0.1)) #define GLIDE_MOD_PULLED (1<<0) #define GLIDE_MOD_BUCKLED (1<<0) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index a6c1d7acca6..fe8f881952c 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -4,7 +4,6 @@ #define CAN_BE_HIT (1<<1) //can this be bludgeoned by items? #define PROJ_IGNORE_DENSITY (1<<2) // If non-dense structures can still get hit by projectiles #define LIGHT_CAN_BE_SHUT (1<<3) // Is sensible to nightfall ability, and its light will be turned off -#define AUTOBALANCE_CHECK (1<<4) //If this item is used for autobalance calculations or excluded, such as valhalla items //Fire and Acid stuff, for resistance_flags #define INDESTRUCTIBLE (1<<0) //doesn't take damage diff --git a/code/__DEFINES/overlays.dm b/code/__DEFINES/overlays.dm index a4488cea619..b95a460168f 100644 --- a/code/__DEFINES/overlays.dm +++ b/code/__DEFINES/overlays.dm @@ -15,7 +15,6 @@ /// Performs any operations that ought to run after an appearance change #define POST_OVERLAY_CHANGE(changed_on) \ - /* TODO port alternate appearances already if(alternate_appearances) { \ for(var/I in changed_on.alternate_appearances){\ var/datum/atom_hud/alternate_appearance/AA = changed_on.alternate_appearances[I];\ @@ -24,4 +23,3 @@ }\ } \ } - */ diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index 80e3d57b1c9..29efec972eb 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -113,4 +113,5 @@ #define SHUTTLE_DISTRESS "distress" #define SHUTTLE_ESCAPE_POD "escape_pod" #define SHUTTLE_SUPPLY "supply" +#define SHUTTLE_VEHICLE_SUPPLY "vehicle_supply" diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm index c1431fd69f9..33d03067ff4 100644 --- a/code/__DEFINES/skills.dm +++ b/code/__DEFINES/skills.dm @@ -154,8 +154,10 @@ #define SKILL_PILOT_TRAINED 1 //Pilot //multitile and mech vehicle skills -#define SKILL_LARGE_VEHICLE_DEFAULT 0 -#define SKILL_LARGE_VEHICLE_TRAINED 1 +#define SKILL_LARGE_VEHICLE_DEFAULT 0 //nothing +#define SKILL_LARGE_VEHICLE_TRAINED 1 //loader +#define SKILL_LARGE_VEHICLE_EXPERIENCED 2 //transport crew +#define SKILL_LARGE_VEHICLE_VETERAN 3 //mech pilot and assault crew //stamina skill - you do cardio, right? //buff stamina related things diff --git a/code/__DEFINES/stat_tracking.dm b/code/__DEFINES/stat_tracking.dm index d7d207469d8..f0635c95529 100644 --- a/code/__DEFINES/stat_tracking.dm +++ b/code/__DEFINES/stat_tracking.dm @@ -8,10 +8,7 @@ #define STAT_LOG_ENTRY(entrylist, entryname) \ var/list/STAT_ENTRY = entrylist[entryname] || (entrylist[entryname] = new /list(STAT_ENTRY_LENGTH));\ STAT_ENTRY[STAT_ENTRY_TIME] += STAT_TIME;\ - var/STAT_INCR_AMOUNT = min(1, 2**round((STAT_ENTRY[STAT_ENTRY_COUNT] || 0)/SHORT_REAL_LIMIT));\ - if (STAT_INCR_AMOUNT == 1 || prob(100/STAT_INCR_AMOUNT)) {\ - STAT_ENTRY[STAT_ENTRY_COUNT] += STAT_INCR_AMOUNT;\ - };\ + STAT_ENTRY[STAT_ENTRY_COUNT] += 1; diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index ad40c277181..ef98bccb3b4 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -158,8 +158,20 @@ #define TRAIT_HEAVY_STEP "heavy_step" ///indicates this mob was spawned by a corpse spawner #define TRAIT_MAPSPAWNED "mapspawned" -///banish +///Banished from the hive by the ruler #define TRAIT_BANISHED "banished" +///Mindmelded with another mob +#define TRAIT_MINDMELDED "mindmelded" +///You swing axe good +#define TRAIT_AXE_EXPERT "axe_expert" +///You swing sword good +#define TRAIT_SWORD_EXPERT "sword_expert" +///Pain reduction light +#define TRAIT_LIGHT_PAIN_RESIST "light_pain_resist" +///Pain reduction medium +#define TRAIT_MEDIUM_PAIN_RESIST "medium_pain_resist" +///is currently riding an armored vehicle +#define TRAIT_TANK_DESANT "tank_desant" /// Prevents usage of manipulation appendages (picking, holding or using items, manipulating storage). #define TRAIT_HANDS_BLOCKED "handsblocked" @@ -233,6 +245,8 @@ //this mech is melee core boosted #define TRAIT_MELEE_CORE "melee_core" +///stops tanks from being able to ram this mob +#define TRAIT_STOPS_TANK_COLLISION "stops_tanks" //added to escaped humans #define TRAIT_HAS_ESCAPED "escaped_marine" diff --git a/code/__DEFINES/vehicles.dm b/code/__DEFINES/vehicles.dm index bca10c69284..642607dc7ae 100644 --- a/code/__DEFINES/vehicles.dm +++ b/code/__DEFINES/vehicles.dm @@ -45,3 +45,16 @@ // For fireman carries, the carrying human needs an arm #define CARRIER_NEEDS_ARM (1<<4) + +//Armored vehicle defines +#define ARMORED_HAS_UNDERLAY (1<<0) +#define ARMORED_HAS_MAP_VARIANTS (1<<2) +#define ARMORED_HAS_PRIMARY_WEAPON (1<<3) +#define ARMORED_HAS_SECONDARY_WEAPON (1<<4) +#define ARMORED_LIGHTS_ON (1<<5) +#define ARMORED_HAS_HEADLIGHTS (1<<6) +#define ARMORED_PURCHASABLE_ASSAULT (1<<7) +#define ARMORED_PURCHASABLE_TRANSPORT (1<<8) + +#define MODULE_PRIMARY (1<<0) +#define MODULE_SECONDARY (1<<1) diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index a351e6f7499..3c89dff29a0 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -52,7 +52,7 @@ . = ..() -/mob/oranges_ear/Move() +/mob/oranges_ear/Move(atom/newloc, direction, glide_size_override) SHOULD_CALL_PARENT(FALSE) stack_trace("SOMEHOW A /mob/oranges_ear MOVED") return FALSE diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 6f52ce99735..883657d2a6b 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -177,7 +177,6 @@ return WEST return NORTH|WEST - //returns the north-zero clockwise angle in degrees, given a direction /proc/dir2angle(D) switch(D) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index bcc049e0372..9793cefe1bc 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -158,6 +158,18 @@ if(293 to 337) return NORTHWEST +///Returns one of the 4 cardinal directions based on an angle +/proc/angle_to_cardinal_dir(angle) + switch(angle) + if(316 to 360, 0 to 45) + return NORTH + if(46 to 135) + return EAST + if(136 to 225) + return SOUTH + if(226 to 315) + return WEST + ///returns degrees between two angles /proc/get_between_angles(degree_one, degree_two) var/angle = abs(degree_one - degree_two) % 360 @@ -594,9 +606,7 @@ /proc/get_cardinal_dir(atom/A, atom/B) - var/dx = abs(B.x - A.x) - var/dy = abs(B.y - A.y) - return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12) + return angle_to_cardinal_dir(Get_Angle(get_turf(A), get_turf(B))) /// If given a diagonal dir, return a corresponding cardinal dir. East/west preferred /proc/closest_cardinal_dir(dir) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 01168c7f697..1c51b1245ed 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -144,7 +144,8 @@ GLOBAL_LIST_INIT(bitfields, list( "PASS_THROW" = PASS_THROW, "PASS_PROJECTILE" = PASS_PROJECTILE, "PASS_AIR" = PASS_AIR, - "PASS_WALKOVER" = PASS_WALKOVER + "PASS_WALKOVER" = PASS_WALKOVER, + "PASS_TANK" = PASS_TANK, ), "pass_flags" = list( "PASS_LOW_STRUCTURE" = PASS_LOW_STRUCTURE, @@ -157,7 +158,8 @@ GLOBAL_LIST_INIT(bitfields, list( "PASS_THROW" = PASS_THROW, "PASS_PROJECTILE" = PASS_PROJECTILE, "PASS_AIR" = PASS_AIR, - "PASS_WALKOVER" = PASS_WALKOVER + "PASS_WALKOVER" = PASS_WALKOVER, + "PASS_TANK" = PASS_TANK, ), "status_flags" = list( "CANSTUN" = CANSTUN, @@ -171,7 +173,7 @@ GLOBAL_LIST_INIT(bitfields, list( "TK_USER" = TK_USER, "CANUNCONSCIOUS" = CANUNCONSCIOUS, "CANCONFUSE" = CANCONFUSE, - "INCORPOREAL" = INCORPOREAL + "INCORPOREAL" = INCORPOREAL, ), "muted" = list( "MUTE_IC" = MUTE_IC, @@ -302,30 +304,13 @@ GLOBAL_LIST_INIT(bitfields, list( "HAND_RIGHT" = HAND_RIGHT ), "update_overlay" = list( - "APC_UPOVERLAY_CHARGEING0" = APC_UPOVERLAY_CHARGEING0, - "APC_UPOVERLAY_CHARGEING1" = APC_UPOVERLAY_CHARGEING1, - "APC_UPOVERLAY_CHARGEING2" = APC_UPOVERLAY_CHARGEING2, - "APC_UPOVERLAY_EQUIPMENT0" = APC_UPOVERLAY_EQUIPMENT0, - "APC_UPOVERLAY_EQUIPMENT1" = APC_UPOVERLAY_EQUIPMENT1, - "APC_UPOVERLAY_EQUIPMENT2" = APC_UPOVERLAY_EQUIPMENT2, - "APC_UPOVERLAY_LIGHTING0" = APC_UPOVERLAY_LIGHTING0, - "APC_UPOVERLAY_LIGHTING1" = APC_UPOVERLAY_LIGHTING1, - "APC_UPOVERLAY_LIGHTING2" = APC_UPOVERLAY_LIGHTING2, - "APC_UPOVERLAY_ENVIRON0" = APC_UPOVERLAY_ENVIRON0, - "APC_UPOVERLAY_ENVIRON1" = APC_UPOVERLAY_ENVIRON1, - "APC_UPOVERLAY_ENVIRON2" = APC_UPOVERLAY_ENVIRON2, - "APC_UPOVERLAY_LOCKED" = APC_UPOVERLAY_LOCKED, - "APC_UPOVERLAY_OPERATING" = APC_UPOVERLAY_OPERATING, - "APC_UPOVERLAY_CELL_IN" = APC_UPOVERLAY_CELL_IN, - "APC_UPOVERLAY_BLUESCREEN" = APC_UPOVERLAY_BLUESCREEN + "UPOVERLAY_OPERATING" = UPOVERLAY_OPERATING, + "UPOVERLAY_LOCKED" = UPOVERLAY_LOCKED, ), "update_state" = list( - "UPSTATE_OPENED1" = UPSTATE_OPENED1, - "UPSTATE_OPENED2" = UPSTATE_OPENED2, - "UPSTATE_MAINT" = UPSTATE_MAINT, "UPSTATE_BROKE" = UPSTATE_BROKE, + "UPSTATE_MAINT" = UPSTATE_MAINT, "UPSTATE_WIREEXP" = UPSTATE_WIREEXP, - "UPSTATE_ALLGOOD" = UPSTATE_ALLGOOD ), "apcwires" = list( "APC_WIRE_IDSCAN" = APC_WIRE_IDSCAN, diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 89b9f2963d3..0bcaaaa93f0 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -29,6 +29,7 @@ GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtype GLOBAL_LIST_EMPTY(alive_living_list) //all alive /mob/living, including clientless. GLOBAL_LIST_EMPTY(offered_mob_list) //all /mobs offered by admins GLOBAL_LIST_EMPTY(ai_list) +GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for each AI_* status define GLOBAL_LIST_EMPTY(living_cameras) GLOBAL_LIST_EMPTY(aiEyes) diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index b4c341ddf5f..b22f15555f2 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -102,6 +102,8 @@ //Multitile special cases. /obj/vehicle/Adjacent(atom/neighbor) + if(hitbox) + return hitbox.Adjacent(neighbor) if(bound_width > 32 || bound_height > 32) for(var/turf/myloc AS in locs) if(myloc.Adjacent(neighbor, target = neighbor, mover = src)) @@ -115,6 +117,12 @@ return TRUE return FALSE +/obj/hitbox/Adjacent(atom/neighbor, atom/target, atom/movable/mover) + for(var/turf/T AS in locs) + if(T.Adjacent(neighbor, neighbor, mover)) + return TRUE + return FALSE + /mob/living/silicon/decoy/Adjacent(atom/neighbor) for(var/turf/myloc AS in locs) diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 4785d51b105..807f7b822c3 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -122,47 +122,47 @@ var/atom/movable/screen/using //AI core - using = new /atom/movable/screen/ai/aicore() + using = new /atom/movable/screen/ai/aicore(null, src) using.screen_loc = ui_ai_core static_inventory += using //Camera list - using = new /atom/movable/screen/ai/camera_list() + using = new /atom/movable/screen/ai/camera_list(null, src) using.screen_loc = ui_ai_camera_list static_inventory += using //Track - using = new /atom/movable/screen/ai/camera_track() + using = new /atom/movable/screen/ai/camera_track(null, src) using.screen_loc = ui_ai_track_with_camera static_inventory += using //VOX - using = new /atom/movable/screen/ai/announcement() + using = new /atom/movable/screen/ai/announcement(null, src) using.screen_loc = ui_ai_announcement static_inventory += using //VOX Help - using = new /atom/movable/screen/ai/announcement_help() + using = new /atom/movable/screen/ai/announcement_help(null, src) using.screen_loc = ui_ai_announcement_help static_inventory += using //Camera light - using = new /atom/movable/screen/ai/camera_light() + using = new /atom/movable/screen/ai/camera_light(null, src) using.screen_loc = ui_ai_camera_light static_inventory += using //Multicamera mode - using = new /atom/movable/screen/ai/multicam() + using = new /atom/movable/screen/ai/multicam(null, src) using.screen_loc = ui_ai_multicam static_inventory += using //Add multicamera camera - using = new /atom/movable/screen/ai/add_multicam() + using = new /atom/movable/screen/ai/add_multicam(null, src) using.screen_loc = ui_ai_add_multicam static_inventory += using //bioscan - using = new /atom/movable/screen/ai/bioscan() + using = new /atom/movable/screen/ai/bioscan(null, src) using.screen_loc = ui_ai_bioscan static_inventory += using diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 6ba4e208684..edc135b7d84 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -46,11 +46,11 @@ . = ..() var/atom/movable/screen/using - using = new /atom/movable/screen/ghost/follow_ghosts() + using = new /atom/movable/screen/ghost/follow_ghosts(null, src) using.screen_loc = ui_ghost_slot2 static_inventory += using - using = new /atom/movable/screen/ghost/reenter_corpse() + using = new /atom/movable/screen/ghost/reenter_corpse(null, src) using.screen_loc = ui_ghost_slot3 static_inventory += using diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 47c134ebf35..0fd0cb8fa5c 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -35,7 +35,7 @@ var/atom/movable/screen/toggle_firemode var/atom/movable/screen/unique_action - var/atom/movable/screen/zone_sel + var/atom/movable/screen/zone_sel/zone_sel var/atom/movable/screen/pull_icon var/atom/movable/screen/throw_icon var/atom/movable/screen/rest_icon diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index ce706a95f75..9984877bd36 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -5,8 +5,6 @@ layer = ABOVE_HUD_LAYER /atom/movable/screen/human/equip/Click() - if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech - return TRUE SEND_SIGNAL(usr, COMSIG_CLICK_QUICKEQUIP) @@ -30,7 +28,7 @@ var/has_hidden_gear for(var/gear_slot in hud_data.gear) - inv_box = new /atom/movable/screen/inventory() + inv_box = new /atom/movable/screen/inventory(null, src) inv_box.icon = ui_style inv_box.color = ui_color inv_box.alpha = ui_alpha @@ -48,7 +46,7 @@ static_inventory += inv_box if(has_hidden_gear) - using = new /atom/movable/screen/toggle_inv() + using = new /atom/movable/screen/toggle_inv(null, src) using.icon = ui_style using.color = ui_color using.alpha = ui_alpha @@ -57,7 +55,7 @@ // Draw the attack intent dialogue. if(hud_data.has_a_intent) - using = new /atom/movable/screen/act_intent/corner() + using = new /atom/movable/screen/act_intent/corner(null, src) using.icon_state = owner.a_intent using.alpha = ui_alpha static_inventory += using @@ -66,7 +64,7 @@ if(hud_data.has_m_intent) - using = new /atom/movable/screen/mov_intent() + using = new /atom/movable/screen/mov_intent(null, src) using.icon = ui_style using.icon_state = (owner.m_intent == MOVE_INTENT_RUN ? "running" : "walking") using.color = ui_color @@ -75,7 +73,7 @@ move_intent = using if(hud_data.has_drop) - using = new /atom/movable/screen/drop() + using = new /atom/movable/screen/drop(null, src) using.icon = ui_style using.color = ui_color using.alpha = ui_alpha @@ -83,105 +81,97 @@ if(hud_data.has_hands) - using = new /atom/movable/screen/human/equip + using = new /atom/movable/screen/human/equip(null, src) using.icon = ui_style using.plane = ABOVE_HUD_PLANE using.color = ui_color using.alpha = ui_alpha static_inventory += using - inv_box = new /atom/movable/screen/inventory/hand/right() + inv_box = new /atom/movable/screen/inventory/hand/right(null, src) inv_box.icon = ui_style - if(owner && !owner.hand) //This being 0 or null means the right hand is in use - inv_box.add_overlay("hand_active") inv_box.slot_id = SLOT_R_HAND inv_box.color = ui_color inv_box.alpha = ui_alpha + inv_box.update_icon() r_hand_hud_object = inv_box static_inventory += inv_box - inv_box = new /atom/movable/screen/inventory/hand() + inv_box = new /atom/movable/screen/inventory/hand/left(null, src) inv_box.setDir(EAST) inv_box.icon = ui_style - if(owner?.hand) //This being 1 means the left hand is in use - inv_box.add_overlay("hand_active") inv_box.slot_id = SLOT_L_HAND inv_box.color = ui_color inv_box.alpha = ui_alpha + inv_box.update_icon() l_hand_hud_object = inv_box static_inventory += inv_box - using = new /atom/movable/screen/swap_hand/human() + using = new /atom/movable/screen/swap_hand/human(null, src) using.icon = ui_style using.color = ui_color using.alpha = ui_alpha static_inventory += using - using = new /atom/movable/screen/swap_hand/right() + using = new /atom/movable/screen/swap_hand/right(null, src) using.icon = ui_style using.color = ui_color using.alpha = ui_alpha static_inventory += using if(hud_data.has_resist) - using = new /atom/movable/screen/resist() + using = new /atom/movable/screen/resist(null, src) using.icon = ui_style using.color = ui_color using.alpha = ui_alpha hotkeybuttons += using if(hud_data.has_throw) - throw_icon = new /atom/movable/screen/throw_catch() + throw_icon = new /atom/movable/screen/throw_catch(null, src) throw_icon.icon = ui_style throw_icon.color = ui_color throw_icon.alpha = ui_alpha hotkeybuttons += throw_icon - pull_icon = new /atom/movable/screen/pull() + pull_icon = new /atom/movable/screen/pull(null, src) pull_icon.icon = ui_style - pull_icon.update_icon(owner) + pull_icon.update_icon() hotkeybuttons += pull_icon if(hud_data.has_warnings) - oxygen_icon = new /atom/movable/screen/oxygen() - infodisplay += oxygen_icon - - fire_icon = new /atom/movable/screen/fire() + fire_icon = new /atom/movable/screen/fire(null, src) infodisplay += fire_icon - healths = new /atom/movable/screen/healths() + healths = new /atom/movable/screen/healths(null, src) infodisplay += healths - staminas = new + staminas = new /atom/movable/screen/stamina_hud(null, src) infodisplay += staminas if(hud_data.has_bodytemp) - bodytemp_icon = new /atom/movable/screen/bodytemp() + bodytemp_icon = new /atom/movable/screen/bodytemp(null, src) infodisplay += bodytemp_icon if(hud_data.has_nutrition) - nutrition_icon = new /atom/movable/screen() - nutrition_icon.icon_state = "nutrition0" - nutrition_icon.name = "nutrition" - nutrition_icon.screen_loc = ui_nutrition + nutrition_icon = new /atom/movable/screen/nutrition(null, src) infodisplay += nutrition_icon - rest_icon = new /atom/movable/screen/rest() + rest_icon = new /atom/movable/screen/rest(null, src) rest_icon.icon = ui_style rest_icon.color = ui_color rest_icon.alpha = ui_alpha - rest_icon.update_icon(owner) + rest_icon.update_icon() static_inventory += rest_icon //squad leader locator - SL_locator = new /atom/movable/screen/SL_locator + SL_locator = new /atom/movable/screen/SL_locator(null, src) infodisplay += SL_locator - zone_sel = new /atom/movable/screen/zone_sel() + zone_sel = new /atom/movable/screen/zone_sel(null, src) zone_sel.icon = ui_style zone_sel.color = ui_color zone_sel.alpha = ui_alpha - zone_sel.update_icon(owner) + zone_sel.set_selected_zone(BODY_ZONE_CHEST, owner) static_inventory += zone_sel diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm index 55c108e6e67..8e2b8525b8a 100644 --- a/code/_onclick/hud/parallax.dm +++ b/code/_onclick/hud/parallax.dm @@ -7,12 +7,12 @@ if(!length(C.parallax_layers_cached)) C.parallax_layers_cached = list() - C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, C.view) - C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_2(null, C.view) - C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/planet(null, C.view) + C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_1(null, src, C.view) + C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_2(null, src, C.view) + C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/planet(null, src, C.view) if(SSparallax.random_layer) - C.parallax_layers_cached += new SSparallax.random_layer - C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_3(null, C.view) + C.parallax_layers_cached += new SSparallax.random_layer(null, src, C.view) + C.parallax_layers_cached += new /atom/movable/screen/parallax_layer/layer_3(null, src, C.view) C.parallax_layers = C.parallax_layers_cached.Copy() @@ -238,7 +238,7 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT -/atom/movable/screen/parallax_layer/Initialize(mapload, view) +/atom/movable/screen/parallax_layer/Initialize(mapload, datum/hud/hud_owner, view) . = ..() if (!view) view = world.view @@ -289,7 +289,7 @@ /atom/movable/screen/parallax_layer/random/space_gas icon_state = "space_gas" -/atom/movable/screen/parallax_layer/random/space_gas/Initialize(mapload, view) +/atom/movable/screen/parallax_layer/random/space_gas/Initialize(mapload, datum/hud/hud_owner, view) . = ..() src.add_atom_colour(SSparallax.random_parallax_color, ADMIN_COLOUR_PRIORITY) diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/picture_in_picture.dm index e5f96dbf3b5..3f47c2d6bb2 100644 --- a/code/_onclick/hud/picture_in_picture.dm +++ b/code/_onclick/hud/picture_in_picture.dm @@ -15,7 +15,7 @@ var/const/max_dimensions = 10 -/atom/movable/screen/movable/pic_in_pic/Initialize(mapload) +/atom/movable/screen/movable/pic_in_pic/Initialize(mapload, datum/hud/hud_owner) . = ..() make_backgrounds() @@ -60,7 +60,7 @@ add_overlay(move_tab) if(!button_x) - button_x = new /atom/movable/screen/component_button(null, src) + button_x = new /atom/movable/screen/component_button(null, null, src) var/mutable_appearance/MA = new /mutable_appearance() MA.name = "close" MA.icon = 'icons/misc/pic_in_pic.dmi' @@ -73,7 +73,7 @@ vis_contents += button_x if(!button_expand) - button_expand = new /atom/movable/screen/component_button(null, src) + button_expand = new /atom/movable/screen/component_button(null, null, src) var/mutable_appearance/MA = new /mutable_appearance() MA.name = "expand" MA.icon = 'icons/misc/pic_in_pic.dmi' @@ -86,7 +86,7 @@ vis_contents += button_expand if(!button_shrink) - button_shrink = new /atom/movable/screen/component_button(null, src) + button_shrink = new /atom/movable/screen/component_button(null, null, src) var/mutable_appearance/MA = new /mutable_appearance() MA.name = "shrink" MA.icon = 'icons/misc/pic_in_pic.dmi' diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index 94a0e95b7a8..9822401ebea 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -125,7 +125,7 @@ GLOBAL_LIST_EMPTY(radial_menus) if(length(elements) < max_elements) var/elements_to_add = max_elements - length(elements) for(var/i in 1 to elements_to_add) //Create all elements - var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice + var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice() new_element.tooltips = use_tooltips new_element.parent = src elements += new_element diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm index 4b629451493..1c85b345fa5 100644 --- a/code/_onclick/hud/rendering/plane_master.dm +++ b/code/_onclick/hud/rendering/plane_master.dm @@ -45,7 +45,7 @@ appearance_flags = PLANE_MASTER render_relay_plane = RENDER_PLANE_GAME -/atom/movable/screen/plane_master/openspace/Initialize(mapload) +/atom/movable/screen/plane_master/openspace/Initialize(mapload, datum/hud/hud_owner) . = ..() add_filter("first_stage_openspace", 1, drop_shadow_filter(color = "#04080FAA", size = -10)) add_filter("second_stage_openspace", 2, drop_shadow_filter(color = "#04080FAA", size = -15)) @@ -118,7 +118,7 @@ mymob.overlay_fullscreen("lighting_backdrop", /atom/movable/screen/fullscreen/lighting_backdrop/backplane) mymob.overlay_fullscreen("lighting_backdrop_lit_secondary", /atom/movable/screen/fullscreen/lighting_backdrop/lit_secondary) -/atom/movable/screen/plane_master/lighting/Initialize(mapload) +/atom/movable/screen/plane_master/lighting/Initialize(mapload, datum/hud/hud_owner) . = ..() add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE)) add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)) @@ -133,7 +133,7 @@ render_target = EMISSIVE_RENDER_TARGET render_relay_plane = null -/atom/movable/screen/plane_master/emissive/Initialize(mapload) +/atom/movable/screen/plane_master/emissive/Initialize(mapload, datum/hud/hud_owner) . = ..() add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix)) diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm index d3e67e40f65..b4b45b512f9 100644 --- a/code/_onclick/hud/rendering/render_plate.dm +++ b/code/_onclick/hud/rendering/render_plate.dm @@ -40,7 +40,7 @@ plane = RENDER_PLANE_GAME render_relay_plane = RENDER_PLANE_MASTER -/atom/movable/screen/plane_master/rendering_plate/game_world/Initialize(mapload) +/atom/movable/screen/plane_master/rendering_plate/game_world/Initialize(mapload, datum/hud/hud_owner) . = ..() add_filter("displacer", 1, displacement_map_filter(render_source = GRAVITY_PULSE_RENDER_TARGET, size = 10)) diff --git a/code/_onclick/hud/screen_objects/screen_objects.dm b/code/_onclick/hud/screen_objects/screen_objects.dm index 33a4cbd4420..3be0ca2e982 100644 --- a/code/_onclick/hud/screen_objects/screen_objects.dm +++ b/code/_onclick/hud/screen_objects/screen_objects.dm @@ -23,6 +23,11 @@ */ var/del_on_map_removal = TRUE +/atom/movable/screen/Initialize(mapload, datum/hud/hud_owner) + . = ..() + if(hud_owner && istype(hud_owner)) + hud = hud_owner + /atom/movable/screen/Destroy() master = null hud = null @@ -80,9 +85,6 @@ if(isobserver(usr) || usr.incapacitated(TRUE)) return TRUE - if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech/tank - return TRUE - //If there is an item in the slot you are clicking on, this will relay the click to the item within the slot var/atom/item_in_slot = usr.get_item_by_slot(slot_id) if(item_in_slot) @@ -94,15 +96,20 @@ return TRUE /atom/movable/screen/inventory/hand + ///The tag used by this hand, used for activate_hand() + var/hand_tag = "" + +/atom/movable/screen/inventory/hand/left name = "l_hand" icon_state = "hand_l" screen_loc = ui_lhand - var/hand_tag = "l" + hand_tag = "l" -/atom/movable/screen/inventory/hand/update_icon(active = FALSE) - cut_overlays() - if(active) - add_overlay("hand_active") +/atom/movable/screen/inventory/hand/left/update_overlays() + . = ..() + if(!hud?.mymob?.hand) + return + . += "hand_active" /atom/movable/screen/inventory/hand/Click(location, control, params) . = ..() @@ -116,6 +123,12 @@ screen_loc = ui_rhand hand_tag = "r" +/atom/movable/screen/inventory/hand/right/update_overlays() + . = ..() + if(!hud?.mymob || hud.mymob.hand) + return + . += "hand_active" + /atom/movable/screen/close name = "close" layer = ABOVE_HUD_LAYER @@ -168,11 +181,12 @@ usr.toggle_move_intent() -/atom/movable/screen/mov_intent/update_icon(mob/user) - if(!user) +/atom/movable/screen/mov_intent/update_icon_state() + . = ..() + if(!hud?.mymob) return - switch(user.m_intent) + switch(hud.mymob.m_intent) if(MOVE_INTENT_RUN) icon_state = "running" if(MOVE_INTENT_WALK) @@ -193,10 +207,11 @@ var/mob/living/L = usr L.lay_down() -/atom/movable/screen/rest/update_icon(mob/mymob) - if(!isliving(mymob)) +/atom/movable/screen/rest/update_icon_state() + . = ..() + if(!isliving(hud?.mymob)) return - var/mob/living/L = mymob + var/mob/living/L = hud?.mymob icon_state = "act_rest[L.resting ? "0" : ""]" /atom/movable/screen/pull @@ -212,10 +227,11 @@ usr.stop_pulling() -/atom/movable/screen/pull/update_icon(mob/user) - if(!user) +/atom/movable/screen/pull/update_icon_state() + . = ..() + if(!hud?.mymob) return - if(user.pulling) + if(hud.mymob.pulling) icon_state = "pull" else icon_state = "pull0" @@ -370,19 +386,19 @@ return BODY_ZONE_PRECISE_EYES return BODY_ZONE_HEAD -/atom/movable/screen/zone_sel/proc/set_selected_zone(choice, mob/user) +/atom/movable/screen/zone_sel/proc/set_selected_zone(choice = BODY_ZONE_CHEST, mob/user) if(isobserver(user)) return if(choice != selecting) selecting = choice - update_icon(user) + user.zone_selected = selecting + update_icon() return TRUE -/atom/movable/screen/zone_sel/update_icon(mob/user) - cut_overlays() - add_overlay(mutable_appearance('icons/mob/screen/zone_sel.dmi', "[z_prefix][selecting]")) - user.zone_selected = selecting +/atom/movable/screen/zone_sel/update_overlays() + . = ..() + . += mutable_appearance('icons/mob/screen/zone_sel.dmi', "[z_prefix][selecting]") /atom/movable/screen/zone_sel/alien icon = 'icons/mob/screen/alien.dmi' @@ -404,10 +420,25 @@ /atom/movable/screen/stamina_hud icon = 'icons/mob/screen/health.dmi' name = "stamina" - icon_state = "staminaloss0" + icon_state = "stamloss-14" screen_loc = UI_STAMINA mouse_opacity = MOUSE_OPACITY_ICON +/atom/movable/screen/stamina_hud/update_icon_state() + . = ..() + if(!ishuman(hud?.mymob)) + return + var/mob/living/carbon/human/mymob_human = hud.mymob + if(mymob_human.stat == DEAD) + icon_state = "stamloss200" + return + var/relative_stamloss = mymob_human.getStaminaLoss() + if(relative_stamloss < 0 && mymob_human.max_stamina) + relative_stamloss = round(((relative_stamloss * 14) / mymob_human.max_stamina), 1) + else + relative_stamloss = round(((relative_stamloss * 7) / (mymob_human.maxHealth * 2)), 1) + icon_state = "stamloss[relative_stamloss]" + /atom/movable/screen/stamina_hud/Click(location, control, params) if(!isliving(usr)) return @@ -421,7 +452,7 @@ /atom/movable/screen/component_button var/atom/movable/screen/parent -/atom/movable/screen/component_button/Initialize(mapload, atom/movable/screen/parent) +/atom/movable/screen/component_button/Initialize(mapload, datum/hud/hud_owner, atom/movable/screen/parent) . = ..() src.parent = parent @@ -501,18 +532,97 @@ icon_state = "temp0" screen_loc = ui_temp +/atom/movable/screen/bodytemp/update_icon_state() + . = ..() + if(!ishuman(hud?.mymob)) + return + var/mob/living/carbon/human/human_mymob = hud.mymob + if(!human_mymob.species) + switch(human_mymob.bodytemperature) //310.055 optimal body temp + if(370 to INFINITY) + icon_state = "temp4" + if(350 to 370) + icon_state = "temp3" + if(335 to 350) + icon_state = "temp2" + if(320 to 335) + icon_state = "temp1" + if(300 to 320) + icon_state = "temp0" + if(295 to 300) + icon_state = "temp-1" + if(280 to 295) + icon_state = "temp-2" + if(260 to 280) + icon_state = "temp-3" + else + icon_state = "temp-4" + return -/atom/movable/screen/oxygen - name = "oxygen" - icon_state = "oxy0" - screen_loc = ui_oxygen + var/temp_step + if(human_mymob.bodytemperature >= human_mymob.species.body_temperature) + temp_step = (human_mymob.species.heat_level_1 - human_mymob.species.body_temperature) / 4 + + if(human_mymob.bodytemperature >= human_mymob.species.heat_level_1) + icon_state = "temp4" + else if(human_mymob.bodytemperature >= human_mymob.species.body_temperature + temp_step * 3) + icon_state = "temp3" + else if(human_mymob.bodytemperature >= human_mymob.species.body_temperature + temp_step * 2) + icon_state = "temp2" + else if(human_mymob.bodytemperature >= human_mymob.species.body_temperature + temp_step * 1) + icon_state = "temp1" + else + icon_state = "temp0" + return + + if(human_mymob.bodytemperature < human_mymob.species.body_temperature) + temp_step = (human_mymob.species.body_temperature - human_mymob.species.cold_level_1)/4 + + if(human_mymob.bodytemperature <= human_mymob.species.cold_level_1) + icon_state = "temp-4" + else if(human_mymob.bodytemperature <= human_mymob.species.body_temperature - temp_step * 3) + icon_state = "temp-3" + else if(human_mymob.bodytemperature <= human_mymob.species.body_temperature - temp_step * 2) + icon_state = "temp-2" + else if(human_mymob.bodytemperature <= human_mymob.species.body_temperature - temp_step * 1) + icon_state = "temp-1" + else + icon_state = "temp0" +/atom/movable/screen/nutrition + name = "nutrition" + icon_state = "nutrition1" + screen_loc = ui_nutrition + +/atom/movable/screen/nutrition/update_icon_state() + . = ..() + if(!ishuman(hud?.mymob)) + return + var/mob/living/carbon/human/human_mymob = hud.mymob + switch(human_mymob.nutrition) + if(NUTRITION_OVERFED to INFINITY) + icon_state = "nutrition0" + if(NUTRITION_HUNGRY to NUTRITION_OVERFED) //Not-hungry. + icon_state = "nutrition1" //Empty icon. + if(NUTRITION_STARVING to NUTRITION_HUNGRY) + icon_state = "nutrition3" + else + icon_state = "nutrition4" /atom/movable/screen/fire - name = "fire" + name = "body temperature" icon_state = "fire0" screen_loc = ui_fire +/atom/movable/screen/fire/update_icon_state() + . = ..() + if(!ishuman(hud?.mymob)) + return + var/mob/living/carbon/human/human_mymob = hud.mymob + if(human_mymob.fire_alert) + icon_state = "fire[human_mymob.fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. + else + icon_state = "fire0" /atom/movable/screen/toggle_inv name = "toggle" @@ -550,7 +660,7 @@ ///List of possible screen locs var/static/list/ammo_screen_loc_list = list(ui_ammo1, ui_ammo2, ui_ammo3, ui_ammo4) -/atom/movable/screen/ammo/Initialize(mapload) +/atom/movable/screen/ammo/Initialize(mapload, datum/hud/hud_owner) . = ..() flash_holder = new flash_holder.icon_state = "frame" @@ -646,7 +756,7 @@ deltimer(del_timer) qdel(src) -/atom/movable/screen/arrow/Initialize(mapload) //Self-deletes +/atom/movable/screen/arrow/Initialize(mapload, datum/hud/hud_owner) //Self-deletes . = ..() START_PROCESSING(SSprocessing, src) del_timer = addtimer(CALLBACK(src, PROC_REF(kill_arrow)), duration, TIMER_STOPPABLE) diff --git a/code/_onclick/hud/screen_objects/text_objects.dm b/code/_onclick/hud/screen_objects/text_objects.dm index f717461f715..3ef7cb80696 100644 --- a/code/_onclick/hud/screen_objects/text_objects.dm +++ b/code/_onclick/hud/screen_objects/text_objects.dm @@ -25,6 +25,7 @@ /atom/movable/screen/text/screen_timer/Initialize( mapload, + datum/hud/hud_owner, list/mobs, timer, text, diff --git a/code/_onclick/hud/xeno/hivemind.dm b/code/_onclick/hud/xeno/hivemind.dm index 1bc7fa6bc12..5d8b0b0ccf2 100644 --- a/code/_onclick/hud/xeno/hivemind.dm +++ b/code/_onclick/hud/xeno/hivemind.dm @@ -2,18 +2,18 @@ ..() var/atom/movable/screen/using - using = new /atom/movable/screen/alien/nightvision() + using = new /atom/movable/screen/alien/nightvision(null, src) using.alpha = ui_alpha infodisplay += using - alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay() + alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay(null, src) alien_plasma_display.alpha = ui_alpha infodisplay += alien_plasma_display - healths = new /atom/movable/screen/healths/alien() + healths = new /atom/movable/screen/healths/alien(null, src) healths.alpha = ui_alpha infodisplay += healths - locate_leader = new /atom/movable/screen/alien/queen_locator() + locate_leader = new /atom/movable/screen/alien/queen_locator(null, src) locate_leader.alpha = ui_alpha infodisplay += locate_leader diff --git a/code/_onclick/hud/xeno/larva.dm b/code/_onclick/hud/xeno/larva.dm index 793b6452470..20eea825453 100644 --- a/code/_onclick/hud/xeno/larva.dm +++ b/code/_onclick/hud/xeno/larva.dm @@ -2,13 +2,13 @@ ..() var/atom/movable/screen/using - using = new /atom/movable/screen/mov_intent/alien() + using = new /atom/movable/screen/mov_intent/alien(null, src) using.alpha = ui_alpha using.icon_state = (owner.m_intent == MOVE_INTENT_RUN ? "running" : "walking") static_inventory += using move_intent = using - using = new /atom/movable/screen/alien/nightvision() + using = new /atom/movable/screen/alien/nightvision(null, src) using.alpha = ui_alpha infodisplay += using @@ -16,10 +16,10 @@ alien_evolve_display.alpha = ui_alpha infodisplay += alien_evolve_display - healths = new /atom/movable/screen/healths/alien/larva() + healths = new /atom/movable/screen/healths/alien/larva(null, src) healths.alpha = ui_alpha infodisplay += healths - locate_leader = new /atom/movable/screen/alien/queen_locator() + locate_leader = new /atom/movable/screen/alien/queen_locator(null, src) locate_leader.alpha = ui_alpha infodisplay += locate_leader diff --git a/code/_onclick/hud/xeno/xeno.dm b/code/_onclick/hud/xeno/xeno.dm index e9e8e3cf77e..07d8954d0c4 100644 --- a/code/_onclick/hud/xeno/xeno.dm +++ b/code/_onclick/hud/xeno/xeno.dm @@ -67,76 +67,74 @@ var/atom/movable/screen/using var/atom/movable/screen/inventory/inv_box - using = new /atom/movable/screen/act_intent/corner() + using = new /atom/movable/screen/act_intent/corner(null, src) using.alpha = ui_alpha using.icon_state = owner.a_intent static_inventory += using action_intent = using - using = new /atom/movable/screen/mov_intent/alien() + using = new /atom/movable/screen/mov_intent/alien(null, src) using.alpha = ui_alpha using.icon_state = (owner.m_intent == MOVE_INTENT_RUN ? "running" : "walking") static_inventory += using move_intent = using - using = new /atom/movable/screen/drop() + using = new /atom/movable/screen/drop(null, src) using.icon = 'icons/mob/screen/alien.dmi' using.alpha = ui_alpha static_inventory += using - inv_box = new /atom/movable/screen/inventory/hand/right() + inv_box = new /atom/movable/screen/inventory/hand/right(null, src) inv_box.icon = 'icons/mob/screen/alien.dmi' using.alpha = ui_alpha - if(owner && !owner.hand) //This being 0 or null means the right hand is in use - using.add_overlay("hand_active") inv_box.slot_id = SLOT_R_HAND + inv_box.update_icon() r_hand_hud_object = inv_box static_inventory += inv_box - inv_box = new /atom/movable/screen/inventory/hand() + inv_box = new /atom/movable/screen/inventory/hand/left(null, src) inv_box.icon = 'icons/mob/screen/alien.dmi' using.alpha = ui_alpha - if(owner?.hand) //This being 1 means the left hand is in use - inv_box.add_overlay("hand_active") inv_box.slot_id = SLOT_L_HAND + inv_box.update_icon() l_hand_hud_object = inv_box static_inventory += inv_box - using = new /atom/movable/screen/swap_hand() + using = new /atom/movable/screen/swap_hand(null, src) using.icon = 'icons/mob/screen/alien.dmi' using.alpha = ui_alpha static_inventory += using - using = new /atom/movable/screen/swap_hand/right() + using = new /atom/movable/screen/swap_hand/right(null, src) using.icon = 'icons/mob/screen/alien.dmi' using.alpha = ui_alpha static_inventory += using - using = new /atom/movable/screen/resist() + using = new /atom/movable/screen/resist(null, src) using.icon = 'icons/mob/screen/alien.dmi' using.screen_loc = ui_above_movement using.alpha = ui_alpha hotkeybuttons += using - throw_icon = new /atom/movable/screen/throw_catch() + throw_icon = new /atom/movable/screen/throw_catch(null, src) throw_icon.icon = 'icons/mob/screen/alien.dmi' throw_icon.alpha = ui_alpha hotkeybuttons += throw_icon - healths = new /atom/movable/screen/healths/alien() + healths = new /atom/movable/screen/healths/alien(null, src) healths.alpha = ui_alpha infodisplay += healths - using = new /atom/movable/screen/alien/nightvision() + using = new /atom/movable/screen/alien/nightvision(null, src) using.alpha = ui_alpha infodisplay += using - alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay() + alien_plasma_display = new /atom/movable/screen/alien/plasmadisplay(null, src) alien_plasma_display.alpha = ui_alpha infodisplay += alien_plasma_display - locate_leader = new /atom/movable/screen/alien/queen_locator() + locate_leader = new /atom/movable/screen/alien/queen_locator(null, src) locate_leader.alpha = ui_alpha infodisplay += locate_leader @@ -148,15 +146,15 @@ alien_sunder_display.alpha = ui_alpha infodisplay += alien_sunder_display - pull_icon = new /atom/movable/screen/pull() + pull_icon = new /atom/movable/screen/pull(null, src) pull_icon.icon = 'icons/mob/screen/alien.dmi' pull_icon.screen_loc = ui_above_movement pull_icon.alpha = ui_alpha - pull_icon.update_icon(owner) + pull_icon.update_icon() hotkeybuttons += pull_icon - zone_sel = new /atom/movable/screen/zone_sel/alien() - zone_sel.update_icon(owner) + zone_sel = new /atom/movable/screen/zone_sel/alien(null, src) + zone_sel.update_icon() static_inventory += zone_sel /datum/hud/alien/persistent_inventory_update() diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 873b0dcda3f..a1c787e25c0 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -51,6 +51,10 @@ add_fingerprint(user, "attackby", I) if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACKBY, I, user, params) & COMPONENT_NO_AFTERATTACK) return TRUE + //not fully portet from tg + if(isgrabitem(I) && grab_interact(I, user)) + user.changeNext_move(GRAB_SLAM_DELAY) + return TRUE return FALSE diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index 84cb76ea451..94bae47b3ae 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -206,16 +206,15 @@ Redefine as needed. return new /obj/effect/temp_visual/telekinesis(get_turf(focus)) - -/obj/item/tk_grab/update_icon() - cut_overlays() +/obj/item/tk_grab/update_overlays() + . = ..() if(!focus) return var/old_layer = focus.layer var/old_plane = focus.plane focus.layer = layer+0.01 focus.plane = ABOVE_HUD_PLANE - add_overlay(focus) //this is kind of ick, but it's better than using icon() + . += focus focus.layer = old_layer focus.plane = old_plane diff --git a/code/controllers/subsystem/minimaps.dm b/code/controllers/subsystem/minimaps.dm index 2916771fdc7..53e8b588871 100644 --- a/code/controllers/subsystem/minimaps.dm +++ b/code/controllers/subsystem/minimaps.dm @@ -353,7 +353,7 @@ SUBSYSTEM_DEF(minimaps) var/hash = "[zlevel]-[flags]" if(hashed_minimaps[hash]) return hashed_minimaps[hash] - var/atom/movable/screen/minimap/map = new(null, zlevel, flags) + var/atom/movable/screen/minimap/map = new(null, null, zlevel, flags) if (!map.icon) //Don't wanna save an unusable minimap for a z-level. CRASH("Empty and unusable minimap generated for '[zlevel]-[flags]'") //Can be caused by atoms calling this proc before minimap subsystem initializing. hashed_minimaps[hash] = map @@ -381,7 +381,7 @@ SUBSYSTEM_DEF(minimaps) ///assoc list of mob choices by clicking on coords. only exists fleetingly for the wait loop in [/proc/get_coords_from_click] var/list/mob/choices_by_mob -/atom/movable/screen/minimap/Initialize(mapload, target, flags) +/atom/movable/screen/minimap/Initialize(mapload, datum/hud/hud_owner, target, flags) . = ..() if(!SSminimaps.minimaps_by_z["[target]"]) return diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm index 4814b696a84..b1c381934d6 100644 --- a/code/controllers/subsystem/time_track.dm +++ b/code/controllers/subsystem/time_track.dm @@ -1,6 +1,6 @@ SUBSYSTEM_DEF(time_track) name = "Time Tracking" - wait = 600 + wait = 100 flags = SS_NO_INIT runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT @@ -30,6 +30,7 @@ SUBSYSTEM_DEF(time_track) time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current) time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast) time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg) + GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime) else first_run = FALSE diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm new file mode 100644 index 00000000000..1afe1c62100 --- /dev/null +++ b/code/controllers/subsystem/vis_overlays.dm @@ -0,0 +1,77 @@ +SUBSYSTEM_DEF(vis_overlays) + name = "Vis contents overlays" + wait = 1 MINUTES + priority = FIRE_PRIORITY_VIS + init_order = INIT_ORDER_VIS + + var/list/vis_overlay_cache + var/list/currentrun + +/datum/controller/subsystem/vis_overlays/Initialize() + vis_overlay_cache = list() + return SS_INIT_SUCCESS + +/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE) + if(!resumed) + currentrun = vis_overlay_cache.Copy() + var/list/current_run = currentrun + + while(current_run.len) + var/key = current_run[current_run.len] + var/obj/effect/overlay/vis/overlay = current_run[key] + current_run.len-- + if(!overlay.unused && !length(overlay.vis_locs)) + overlay.unused = world.time + else if(overlay.unused && overlay.unused + overlay.cache_expiration < world.time) + vis_overlay_cache -= key + qdel(overlay) + if(MC_TICK_CHECK) + return + +//the "thing" var can be anything with vis_contents which includes images - in the future someone should totally allow vis overlays to be passed in as an arg instead of all this bullshit +/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE) + var/obj/effect/overlay/vis/overlay + if(!unique) + . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]" + overlay = vis_overlay_cache[.] + if(!overlay) + overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) + vis_overlay_cache[.] = overlay + else + overlay.unused = 0 + else + overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) + overlay.cache_expiration = -1 + var/cache_id = "[text_ref(overlay)]@{[world.time]}" + vis_overlay_cache[cache_id] = overlay + . = overlay + thing.vis_contents += overlay + + if(!isatom(thing)) // Automatic rotation is not supported on non atoms + return overlay + + if(!thing.managed_vis_overlays) + thing.managed_vis_overlays = list(overlay) + else + thing.managed_vis_overlays += overlay + return overlay + +/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags) + var/obj/effect/overlay/vis/overlay = new + overlay.icon = icon + overlay.icon_state = iconstate + overlay.layer = layer + overlay.plane = plane + overlay.dir = dir + overlay.alpha = alpha + overlay.appearance_flags |= add_appearance_flags + return overlay + + +/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays) + thing.vis_contents -= overlays + if(!isatom(thing)) + return + thing.managed_vis_overlays -= overlays + if(!length(thing.managed_vis_overlays)) + thing.managed_vis_overlays = null diff --git a/code/datums/callback.dm b/code/datums/callback.dm index ef07f584120..af8ec8de82e 100644 --- a/code/datums/callback.dm +++ b/code/datums/callback.dm @@ -231,5 +231,3 @@ else datum.vars[var_name] = var_value -/proc/___callbacknew(typepath, arguments) - new typepath(arglist(arguments)) diff --git a/code/datums/components/autofire.dm b/code/datums/components/autofire.dm index 527f1838bf0..b06b8f85fb3 100644 --- a/code/datums/components/autofire.dm +++ b/code/datums/components/autofire.dm @@ -32,8 +32,8 @@ RegisterSignal(parent, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, PROC_REF(modify_burst_shots_to_fire)) RegisterSignal(parent, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, PROC_REF(modify_burstfire_shot_delay)) RegisterSignal(parent, COMSIG_GUN_AUTO_BURST_SHOT_DELAY_MODIFIED, PROC_REF(modify_autoburstfire_shot_delay)) - RegisterSignals(parent, list(COMSIG_GUN_FIRE, COMSIG_XENO_FIRE, COMSIG_MECH_FIRE), PROC_REF(initiate_shot)) - RegisterSignals(parent, list(COMSIG_GUN_STOP_FIRE, COMSIG_XENO_STOP_FIRE, COMSIG_MECH_STOP_FIRE), PROC_REF(stop_firing)) + RegisterSignals(parent, list(COMSIG_GUN_FIRE, COMSIG_XENO_FIRE, COMSIG_MECH_FIRE, COMSIG_ARMORED_FIRE), PROC_REF(initiate_shot)) + RegisterSignals(parent, list(COMSIG_GUN_STOP_FIRE, COMSIG_XENO_STOP_FIRE, COMSIG_MECH_STOP_FIRE, COMSIG_ARMORED_STOP_FIRE), PROC_REF(stop_firing)) auto_fire_shot_delay = _auto_fire_shot_delay burstfire_shot_delay = _burstfire_shot_delay diff --git a/code/datums/components/deployable_item.dm b/code/datums/components/deployable_item.dm index b811cc176ef..daeb48b80d4 100644 --- a/code/datums/components/deployable_item.dm +++ b/code/datums/components/deployable_item.dm @@ -110,7 +110,7 @@ if(item_to_deploy?.reagents?.total_volume) item_to_deploy.reagents.trans_to(deployed_machine, item_to_deploy.reagents.total_volume) - deployed_machine.update_icon_state() + deployed_machine.update_appearance() if(user) item_to_deploy.balloon_alert(user, "Deployed!") @@ -167,4 +167,4 @@ deployed_machine.clear_internal_item() QDEL_NULL(deployed_machine) - undeployed_item.update_icon_state() + undeployed_item.update_appearance() diff --git a/code/datums/components/jump.dm b/code/datums/components/jump.dm index 7fa5d0c983c..5eeb7eb6ffb 100644 --- a/code/datums/components/jump.dm +++ b/code/datums/components/jump.dm @@ -37,7 +37,7 @@ set_vars(_jump_duration, _jump_cooldown, _stamina_cost, _jump_height, _jump_sound, _jump_flags, _jumper_allow_pass_flags) ///Actually sets the jump vars -/datum/component/jump/proc/set_vars(_jump_duration = 0.5 SECONDS, _jump_cooldown = 1 SECONDS, _stamina_cost = 8, _jump_height = 16, _jump_sound = null, _jump_flags = JUMP_SHADOW, _jumper_allow_pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE) +/datum/component/jump/proc/set_vars(_jump_duration = 0.5 SECONDS, _jump_cooldown = 1 SECONDS, _stamina_cost = 8, _jump_height = 16, _jump_sound = null, _jump_flags = JUMP_SHADOW, _jumper_allow_pass_flags = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK) jump_duration = _jump_duration jump_cooldown = _jump_cooldown stamina_cost = _stamina_cost diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 61088ed923e..117b982b2d5 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -49,6 +49,8 @@ return COMPONENT_INCOMPATIBLE handle_specials() + var/atom/movable/movable_parent = parent + riding_mob.set_glide_size(movable_parent.glide_size) riding_mob.updating_glide_size = FALSE ride_check_flags |= args_to_flags(check_loc, lying_buckle, hands_needed, target_hands_needed)//buckle_mob_flags vehicle_moved() @@ -115,8 +117,7 @@ var/atom/movable/movable_parent = parent if (isnull(dir)) dir = movable_parent.dir - for (var/m in movable_parent.buckled_mobs) - var/mob/buckled_mob = m + for(var/mob/buckled_mob AS in movable_parent.buckled_mobs) ride_check(buckled_mob) if(QDELETED(src)) return // runtimed with piggy's without this, look into this more @@ -203,9 +204,14 @@ return TRUE /// Every time the driver tries to move, this is called to see if they can actually drive and move the vehicle (via relaymove) -/datum/component/riding/proc/driver_move(atom/movable/movable_parent, mob/living/user, direction) +/datum/component/riding/proc/driver_move(atom/movable/movable_parent, mob/living/user, direction, glide_size_override) SIGNAL_HANDLER - return + SHOULD_CALL_PARENT(TRUE) + movable_parent.set_glide_size(glide_size_override ? glide_size_override : DELAY_TO_GLIDE_SIZE(vehicle_move_delay)) + +/// Calculates the additional delay to moving +/datum/component/riding/proc/calculate_additional_delay(mob/living/user) + return 0 /// So we can check all occupants when we bump a door to see if anyone has access /datum/component/riding/proc/vehicle_bump(atom/movable/movable_parent, obj/machinery/door/possible_bumped_door) diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index 5b4ce5fc796..c6b718be36c 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -68,7 +68,7 @@ former_rider.log_message("is no longer riding [living_parent]", LOG_ATTACK, color="pink") return ..() -/datum/component/riding/creature/driver_move(atom/movable/movable_parent, mob/living/user, direction) +/datum/component/riding/creature/driver_move(atom/movable/movable_parent, mob/living/user, direction, glide_size_override) if(!COOLDOWN_CHECK(src, vehicle_move_cooldown)) return COMPONENT_DRIVER_BLOCK_MOVE if(!keycheck(user)) @@ -76,11 +76,12 @@ var/obj/item/key = keytype to_chat(user, "You need a [initial(key.name)] to ride [movable_parent]!") return COMPONENT_DRIVER_BLOCK_MOVE - var/mob/living/living_parent = parent - var/turf/next = get_step(living_parent, direction) - step(living_parent, direction) - last_move_diagonal = ((direction & (direction - 1)) && (living_parent.loc == next)) - COOLDOWN_START(src, vehicle_move_cooldown, (last_move_diagonal? 2 : 1) * vehicle_move_delay) + last_move_diagonal = ISDIAGONALDIR(direction) + var/new_delay = (last_move_diagonal ? DIAG_MOVEMENT_ADDED_DELAY_MULTIPLIER : 1) * vehicle_move_delay + glide_size_override = DELAY_TO_GLIDE_SIZE(new_delay) + . = ..() + step(movable_parent, direction) + COOLDOWN_START(src, vehicle_move_cooldown, new_delay) /// Yeets the rider off, used for animals and cyborgs, redefined for humans who shove their piggyback rider off /datum/component/riding/creature/proc/force_dismount(mob/living/rider, gentle = FALSE) diff --git a/code/datums/components/riding/riding_vehicle.dm b/code/datums/components/riding/riding_vehicle.dm index cbb18cee8b1..0843e28427f 100644 --- a/code/datums/components/riding/riding_vehicle.dm +++ b/code/datums/components/riding/riding_vehicle.dm @@ -9,7 +9,7 @@ . = ..() RegisterSignal(parent, COMSIG_RIDDEN_DRIVER_MOVE, PROC_REF(driver_move)) -/datum/component/riding/vehicle/driver_move(atom/movable/movable_parent, mob/living/user, direction) +/datum/component/riding/vehicle/driver_move(atom/movable/movable_parent, mob/living/user, direction, glide_size_override) if(!COOLDOWN_CHECK(src, vehicle_move_cooldown)) return COMPONENT_DRIVER_BLOCK_MOVE var/obj/vehicle/vehicle_parent = parent @@ -53,10 +53,14 @@ COOLDOWN_START(src, message_cooldown, 5 SECONDS) return COMPONENT_DRIVER_BLOCK_MOVE - handle_ride(user, direction) + last_move_diagonal = ISDIAGONALDIR(direction) + var/new_delay = (last_move_diagonal ? DIAG_MOVEMENT_ADDED_DELAY_MULTIPLIER : 1) * vehicle_move_delay + calculate_additional_delay(user) + glide_size_override = DELAY_TO_GLIDE_SIZE(new_delay) + . = ..() + handle_ride(user, direction, new_delay) /// This handles the actual movement for vehicles once [/datum/component/riding/vehicle/proc/driver_move] has given us the green light -/datum/component/riding/vehicle/proc/handle_ride(mob/user, direction) +/datum/component/riding/vehicle/proc/handle_ride(mob/living/user, direction, cooldown_duration) var/atom/movable/movable_parent = parent var/turf/next = get_step(movable_parent, direction) @@ -69,15 +73,14 @@ if(!isturf(movable_parent.loc)) return + //movable_parent.Move(next, direction, glide_size_override) step(movable_parent, direction) - last_move_diagonal = ((direction & (direction - 1)) && (movable_parent.loc == next)) - COOLDOWN_START(src, vehicle_move_cooldown, (last_move_diagonal? 2 : 1) * vehicle_move_delay) + COOLDOWN_START(src, vehicle_move_cooldown, cooldown_duration) if(QDELETED(src)) return handle_vehicle_layer(movable_parent.dir) handle_vehicle_offsets(movable_parent.dir) - return TRUE /datum/component/riding/vehicle/atv keytype = /obj/item/key/atv @@ -116,6 +119,44 @@ vehicle_move_delay = 0 ride_check_flags = RIDER_NEEDS_ARMS +/datum/component/riding/vehicle/wheelchair/driver_move(atom/movable/movable_parent, mob/living/user, direction, glide_size_override) + if(!iscarbon(user)) + return COMPONENT_DRIVER_BLOCK_MOVE + var/mob/living/carbon/carbon_user = user + + var/datum/limb/left_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_R_HAND) + var/datum/limb/right_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_L_HAND) + var/working_hands = 2 + + if(!left_hand?.is_usable() || user.get_item_for_held_index(1)) + working_hands-- + if(!right_hand?.is_usable() || user.get_item_for_held_index(2)) + working_hands-- + if(!working_hands) + to_chat(user, span_warning("You have no arms to propel [movable_parent]!")) + return COMPONENT_DRIVER_BLOCK_MOVE // No hands to drive your chair? Tough luck! + return ..() + +/datum/component/riding/vehicle/wheelchair/calculate_additional_delay(mob/living/user) + if(!iscarbon(user)) + return 0 + var/mob/living/carbon/carbon_user = user + + var/datum/limb/left_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_R_HAND) + var/datum/limb/right_hand = carbon_user.get_limb(BODY_ZONE_PRECISE_L_HAND) + var/delay_to_add = 0 + + if(!left_hand?.is_usable() || user.get_item_for_held_index(1)) + delay_to_add += vehicle_move_delay * 0.5 //harder to move a wheelchair with a single hand + else if(left_hand?.is_broken()) + delay_to_add = vehicle_move_delay * 0.33 + if(!right_hand?.is_usable() || user.get_item_for_held_index(2)) + delay_to_add += vehicle_move_delay * 0.5 + else if(right_hand.is_broken()) + delay_to_add = vehicle_move_delay * 0.33 + + return delay_to_add + /datum/component/riding/vehicle/wheelchair/handle_specials() . = ..() set_vehicle_dir_layer(SOUTH, OBJ_LAYER) @@ -123,6 +164,9 @@ set_vehicle_dir_layer(EAST, OBJ_LAYER) set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/vehicle/wheelchair/weaponized + vehicle_move_delay = 5 + /datum/component/riding/vehicle/motorbike vehicle_move_delay = 2 ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER diff --git a/code/datums/elements/connect_loc.dm b/code/datums/elements/connect_loc.dm index c373adafffe..7693fb0febd 100644 --- a/code/datums/elements/connect_loc.dm +++ b/code/datums/elements/connect_loc.dm @@ -19,7 +19,7 @@ /datum/element/connect_loc/Detach(atom/movable/listener) . = ..() - unregister_signals(listener, listener.loc) + unregister_signals(listener, listener.loc, listener.locs) UnregisterSignal(listener, COMSIG_MOVABLE_MOVED) /datum/element/connect_loc/proc/update_signals(atom/movable/listener) @@ -29,16 +29,25 @@ for (var/signal in connections) //override=TRUE because more than one connect_loc element instance tracked object can be on the same loc - listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE) + if(length(listener.locs) < 2) //this is kinda funny but a multitile object could be inside something + listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE) + continue + for(var/turf/turf AS in listener.locs) + listener.RegisterSignal(turf, signal, connections[signal], override=TRUE) -/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc) + +/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc, list/turf/old_locs) if(isnull(old_loc)) return for (var/signal in connections) - listener.UnregisterSignal(old_loc, signal) + if(length(old_locs) < 2) + listener.UnregisterSignal(old_loc, signal) + continue + for(var/turf/turf AS in old_locs) + listener.UnregisterSignal(turf, signal) -/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc) +/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc, movement_dir, forced, list/turf/old_locs) SIGNAL_HANDLER - unregister_signals(listener, old_loc) + unregister_signals(listener, old_loc, old_locs) update_signals(listener) diff --git a/code/datums/gamemodes/campaign/missions/base_rescue.dm b/code/datums/gamemodes/campaign/missions/base_rescue.dm index 4cba8278dd5..f4bcf9c14e0 100644 --- a/code/datums/gamemodes/campaign/missions/base_rescue.dm +++ b/code/datums/gamemodes/campaign/missions/base_rescue.dm @@ -139,6 +139,7 @@ return ..() /obj/structure/weapon_x_pod/update_icon_state() + . = ..() if(occupant) icon_state = initial(icon_state) else diff --git a/code/datums/gamemodes/distress.dm b/code/datums/gamemodes/distress.dm index f470623e1a5..54ba20cdce7 100644 --- a/code/datums/gamemodes/distress.dm +++ b/code/datums/gamemodes/distress.dm @@ -9,7 +9,8 @@ /datum/job/terragov/command/captain = 1, /datum/job/terragov/command/fieldcommander = 1, /datum/job/terragov/command/staffofficer = 4, - /datum/job/terragov/command/pilot = 2, + /datum/job/terragov/command/pilot = 1, + /datum/job/terragov/command/transportofficer = 1, /datum/job/terragov/engineering/chief = 1, /datum/job/terragov/engineering/tech = 2, /datum/job/terragov/requisitions/officer = 1, @@ -19,6 +20,8 @@ /datum/job/terragov/civilian/liaison = 1, /datum/job/terragov/silicon/synthetic = 1, /datum/job/terragov/command/mech_pilot = 0, + /datum/job/terragov/command/assault_crewman = 2, + /datum/job/terragov/command/transport_crewman = 1, /datum/job/terragov/silicon/ai = 1, /datum/job/terragov/squad/engineer = 8, /datum/job/terragov/squad/corpsman = 8, diff --git a/code/datums/gamemodes/extended.dm b/code/datums/gamemodes/extended.dm index 6babe060702..83fee22e3aa 100644 --- a/code/datums/gamemodes/extended.dm +++ b/code/datums/gamemodes/extended.dm @@ -6,8 +6,11 @@ /datum/job/terragov/command/captain = 1, /datum/job/terragov/command/fieldcommander = 1, /datum/job/terragov/command/staffofficer = 4, - /datum/job/terragov/command/pilot = 2, + /datum/job/terragov/command/pilot = 1, + /datum/job/terragov/command/transportofficer = 1, /datum/job/terragov/command/mech_pilot = 0, + /datum/job/terragov/command/assault_crewman = 2, + /datum/job/terragov/command/transport_crewman = 1, /datum/job/terragov/engineering/chief = 1, /datum/job/terragov/engineering/tech = 1, /datum/job/terragov/requisitions/officer = 1, diff --git a/code/datums/gamemodes/infestation.dm b/code/datums/gamemodes/infestation.dm index de2e61a0d4d..2aac22ccacc 100644 --- a/code/datums/gamemodes/infestation.dm +++ b/code/datums/gamemodes/infestation.dm @@ -52,9 +52,8 @@ /datum/game_mode/infestation/announce_bioscans(show_locations = TRUE, delta = 2, ai_operator = FALSE, announce_humans = TRUE, announce_xenos = TRUE, send_fax = TRUE) if(ai_operator) - var/mob/living/silicon/ai/bioscanning_ai = usr #ifndef TESTING - + var/mob/living/silicon/ai/bioscanning_ai = usr if((bioscanning_ai.last_ai_bioscan + COOLDOWN_AI_BIOSCAN) > world.time) to_chat(bioscanning_ai, "Bioscan instruments are still recalibrating from their last use.") return diff --git a/code/datums/gamemodes/nuclear_war.dm b/code/datums/gamemodes/nuclear_war.dm index 19edc0242a5..1070e35ccf7 100644 --- a/code/datums/gamemodes/nuclear_war.dm +++ b/code/datums/gamemodes/nuclear_war.dm @@ -9,7 +9,8 @@ /datum/job/terragov/command/captain = 1, /datum/job/terragov/command/fieldcommander = 1, /datum/job/terragov/command/staffofficer = 4, - /datum/job/terragov/command/pilot = 2, + /datum/job/terragov/command/pilot = 1, + /datum/job/terragov/command/transportofficer = 1, /datum/job/terragov/engineering/chief = 1, /datum/job/terragov/engineering/tech = 2, /datum/job/terragov/requisitions/officer = 1, @@ -19,6 +20,8 @@ /datum/job/terragov/civilian/liaison = 1, /datum/job/terragov/silicon/synthetic = 1, /datum/job/terragov/command/mech_pilot = 0, + /datum/job/terragov/command/assault_crewman = 2, + /datum/job/terragov/command/transport_crewman = 1, /datum/job/terragov/silicon/ai = 1, /datum/job/terragov/squad/engineer = 1, /datum/job/terragov/squad/corpsman = 1, diff --git a/code/datums/interior/_interior.dm b/code/datums/interior/_interior.dm new file mode 100644 index 00000000000..4fb6bcbdb0a --- /dev/null +++ b/code/datums/interior/_interior.dm @@ -0,0 +1,108 @@ +#define INTERIOR_BUFFER_TILES 1 + +/datum/interior + ///map template to load as the interior + var/template = /datum/map_template + ///container that this interior is attached to; what we are the inside of + var/atom/container + ///callback to execute when we want to eject the mob + var/datum/callback/exit_callback + ///occupants that entered this interior through the intended way + var/list/mob/occupants = list() + ///turf reservation where we will load our interior + var/datum/turf_reservation/reservation + ///list of all loaded turfs. we keep this around in case we need to update linkages or similar + var/list/turf/loaded_turfs = list() + /// the interior area. you should only be using 1 area for the whole thing, if you're not, make this support it lol + var/area/this_area + +/datum/interior/New(atom/container, datum/callback/exit_callback) + ..() + src.container = container + src.exit_callback = exit_callback + RegisterSignal(container, COMSIG_QDELETING, PROC_REF(handle_container_del)) + RegisterSignal(container, COMSIG_ATOM_ENTERED, PROC_REF(on_container_enter)) + INVOKE_NEXT_TICK(src, PROC_REF(init_map)) + +///actual inits the map, seperate proc because otherwise it fails linter due to "sleep in new" +/datum/interior/proc/init_map() + var/datum/map_template/map = new template + reservation = SSmapping.RequestBlockReservation(map.width + (INTERIOR_BUFFER_TILES*2), map.height + (INTERIOR_BUFFER_TILES*2)) + + var/list/load_coords = reservation.bottom_left_coords.Copy() + load_coords[1] = load_coords[1] + INTERIOR_BUFFER_TILES + load_coords[2] = load_coords[2] + INTERIOR_BUFFER_TILES + var/turf/load_loc = locate(load_coords[1], load_coords[2], load_coords[3]) + var/list/bounds = map.load(load_loc) + this_area = load_loc.loc + + loaded_turfs = block( + locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), + locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ]) + ) + + connect_atoms() + +/datum/interior/Destroy(force, ...) + for(var/mob/occupant AS in occupants) + mob_leave(occupant) + exit_callback = null + this_area = null + loaded_turfs = null + QDEL_NULL(reservation) //all the turfs/objs are deleted past this point + container = null + return ..() + +///connects all atoms as needed to the interior. seperate so it can be used in debugging +/datum/interior/proc/connect_atoms() + for(var/turf/tile AS in loaded_turfs) + for(var/atom/subject AS in tile.GetAllContents()) + subject.link_interior(src) + CHECK_TICK + +///called when someone enters the container +/datum/interior/proc/on_container_enter(datum/source, atom/movable/moved_in, direction) + SIGNAL_HANDLER + if(ismob(moved_in)) + mob_enter(moved_in) + +///called when we want to move a mob into the interior +/datum/interior/proc/mob_enter(mob/enterer) + RegisterSignal(enterer, COMSIG_QDELETING, PROC_REF(handle_occupant_del)) + RegisterSignal(enterer, COMSIG_EXIT_AREA, PROC_REF(handle_area_leave)) + occupants += enterer + //teleporting the mob is on a case-by-case basis + +///called when we want to remove a mob from the interior +/datum/interior/proc/mob_leave(mob/leaver, teleport = TRUE) + UnregisterSignal(leaver, list(COMSIG_QDELETING, COMSIG_EXIT_AREA)) + occupants -= leaver + exit_callback?.Invoke(leaver, src, teleport) + +///called when a mob gets deleted while an occupant +/datum/interior/proc/handle_occupant_del(mob/source) + SIGNAL_HANDLER + mob_leave(source, FALSE) + +///called when parent container is deleted +/datum/interior/proc/handle_container_del(atom/source) + SIGNAL_HANDLER + qdel(src) + +///when someone who entered the "proper" way leaves the area, remove them as an occupant without teleporting +/datum/interior/proc/handle_area_leave(mob/source, area/oldarea, direction) + SIGNAL_HANDLER + if(get_area(source) != this_area) + mob_leave(source, FALSE) + +#undef INTERIOR_BUFFER_TILES + +/area/interior + name = "ERROR AREA DO NOT USE" + base_lighting_alpha = 128 + +/turf/closed/interior + resistance_flags = RESIST_ALL + +/turf/open/interior + resistance_flags = RESIST_ALL diff --git a/code/datums/interior/interior_apc.dm b/code/datums/interior/interior_apc.dm new file mode 100644 index 00000000000..6739c6a658a --- /dev/null +++ b/code/datums/interior/interior_apc.dm @@ -0,0 +1,102 @@ +/datum/interior/armored/transport + template = /datum/map_template/interior/transport + +/datum/interior/armored/medical + template = /datum/map_template/interior/medical + +/datum/interior/armored/clone_bay + template = /datum/map_template/interior/clone_bay + +/turf/closed/interior/apc + name = "\improper Athena tank interior" + icon = 'icons/obj/armored/3x3/apc_interior.dmi' + +/turf/closed/interior/apc/one + icon_state = "apc_interior_1" + +/turf/closed/interior/apc/two + icon_state = "apc_interior_2" + +/turf/closed/interior/apc/three + icon_state = "apc_interior_3" + +/turf/closed/interior/apc/four + icon_state = "apc_interior_4" + +/turf/closed/interior/apc/five + icon_state = "apc_interior_5" + +/turf/closed/interior/apc/six + icon_state = "apc_interior_6" + +/turf/closed/interior/apc/twelve + icon_state = "apc_interior_12" + +/turf/closed/interior/apc/thirteen + icon_state = "apc_interior_13" + +/turf/closed/interior/apc/seventeen + icon_state = "apc_interior_17" + +/turf/closed/interior/apc/eighteen + icon_state = "apc_interior_18" + +/turf/closed/interior/apc/nineteen + icon_state = "apc_interior_19" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/apc/twenty + icon_state = "apc_interior_20" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/apc/twentythree + icon_state = "apc_interior_23" + +/turf/closed/interior/apc/twentyfour + icon_state = "apc_interior_24" + +/turf/closed/interior/apc/twentyseven + icon_state = "apc_interior_27" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/apc/twentyeight + icon_state = "apc_interior_28" + +/turf/open/interior/apc + name = "\improper Athena tank interior" + icon = 'icons/obj/armored/3x3/apc_interior.dmi' + +/turf/open/interior/apc/eight + icon_state = "apc_interior_8" + +/turf/open/interior/apc/nine + icon_state = "apc_interior_9" + +/turf/open/interior/apc/ten + icon_state = "apc_interior_10" + +/turf/open/interior/apc/eleven + icon_state = "apc_interior_11" + +/turf/open/interior/apc/fourteen + icon_state = "apc_interior_14" + +/turf/open/interior/apc/fifteen + icon_state = "apc_interior_15" + +/turf/open/interior/apc/sixteen + icon_state = "apc_interior_16" + +/turf/open/interior/apc/twentytwo + icon_state = "apc_interior_22" + +/turf/open/interior/apc/twentynine + icon_state = "apc_interior_29" + +/obj/structure/bed/chair/dropship/doublewide/apc + name = "apc seat" + desc = "Stops you from bouncing around inside the APC. You don't see a seatbelt." + +/area/interior/apc + name = "APC Interior" + icon_state = "shuttle" diff --git a/code/datums/interior/interior_tank.dm b/code/datums/interior/interior_tank.dm new file mode 100644 index 00000000000..35d051cd78b --- /dev/null +++ b/code/datums/interior/interior_tank.dm @@ -0,0 +1,164 @@ +/datum/interior/armored + template = /datum/map_template/interior/medium_tank + ///main cannon ammo management + var/obj/structure/gun_breech/breech + ///secondary gun ammo management + var/obj/structure/gun_breech/secondary_breech + ///door to enter and leave the tank. TODO: make this support multiple doors + var/turf/closed/interior/tank/door/door + +/datum/interior/armored/Destroy(force, ...) + breech = null + secondary_breech = null + door = null + return ..() + +/datum/interior/armored/mob_enter(mob/enterer) + . = ..() + if(door) + enterer.forceMove(door.get_enter_location()) + enterer.setDir(EAST) + return + to_chat(enterer, span_userdanger("AN ERROR OCCURED PUTTING YOU INTO AN INTERIOR")) + stack_trace("a [enterer.type] could not find a door when entering an interior") + enterer.forceMove(pick(loaded_turfs)) + +/turf/closed/interior/tank + name = "\improper Banteng tank interior" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + +/turf/closed/interior/tank/one + icon_state = "tank_interior_1" + +/turf/closed/interior/tank/two + icon_state = "tank_interior_2" + +/turf/closed/interior/tank/three + icon_state = "tank_interior_3" + +/turf/closed/interior/tank/four + icon_state = "tank_interior_4" + +/turf/closed/interior/tank/five + icon_state = "tank_interior_5" + +/turf/closed/interior/tank/six + icon_state = "tank_interior_6" + +/turf/closed/interior/tank/twelve + icon_state = "tank_interior_12" + +/turf/closed/interior/tank/thirteen + icon_state = "tank_interior_13" + +/turf/closed/interior/tank/seventeen + icon_state = "tank_interior_17" + +/turf/closed/interior/tank/eighteen + icon_state = "tank_interior_18" + +/turf/closed/interior/tank/nineteen + icon_state = "tank_interior_19" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/tank/twenty + icon_state = "tank_interior_20" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/tank/twentyone + icon_state = "tank_interior_21" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/tank/twentythree + icon_state = "tank_interior_23" + +/turf/closed/interior/tank/twentyfour + icon_state = "tank_interior_24" + +/turf/closed/interior/tank/twentyfive + icon_state = "tank_interior_25" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/tank/twentysix + icon_state = "tank_interior_26" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/tank/twentyseven + icon_state = "tank_interior_27" + layer = ABOVE_ALL_MOB_LAYER + +/turf/closed/interior/tank/twentyeight + icon_state = "tank_interior_28" + +/turf/closed/interior/tank/door + name = "exit hatch" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "tank_interior_7" + resistance_flags = RESIST_ALL + ///owner of this object, assigned during interior linkage + var/obj/vehicle/sealed/armored/owner + +/turf/closed/interior/tank/door/Destroy() + owner = null + return ..() + +/turf/closed/interior/tank/door/link_interior(datum/interior/link) + if(!istype(link, /datum/interior/armored)) + CRASH("invalid interior [link.type] passed to [name]") + var/datum/interior/armored/inside = link + inside.door = src + owner = inside.container + +/turf/closed/interior/tank/door/attack_hand(mob/living/user) + . = ..() + owner.interior.mob_leave(user) + +/turf/closed/interior/tank/door/attack_ghost(mob/dead/observer/user) + . = ..() + owner.interior.mob_leave(user) + +/turf/closed/interior/tank/door/MouseDrop_T(atom/movable/dropping, mob/M) + if(!ismob(dropping)) + return ..() + owner.interior.mob_leave(dropping) + +/turf/closed/interior/tank/door/grab_interact(obj/item/grab/grab, mob/user, base_damage, is_sharp) + if(!ismob(grab.grabbed_thing)) + return ..() + owner.interior.mob_leave(grab.grabbed_thing) + +///returns where we want to spit out new enterers +/turf/closed/interior/tank/door/proc/get_enter_location() + return get_step(src, EAST) + +/turf/open/interior/tank + name = "\improper Banteng tank interior" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + +/turf/open/interior/tank/eight + icon_state = "tank_interior_8" + +/turf/open/interior/tank/nine + icon_state = "tank_interior_9" + +/turf/open/interior/tank/ten + icon_state = "tank_interior_10" + +/turf/open/interior/tank/eleven + icon_state = "tank_interior_11" + +/turf/open/interior/tank/fourteen + icon_state = "tank_interior_14" + +/turf/open/interior/tank/fifteen + icon_state = "tank_interior_15" + +/turf/open/interior/tank/sixteen + icon_state = "tank_interior_16" + +/turf/open/interior/tank/twentytwo + icon_state = "tank_interior_22" + +/area/interior/tank + name = "Tank Interior" + icon_state = "shuttle" diff --git a/code/datums/interior/link_interior.dm b/code/datums/interior/link_interior.dm new file mode 100644 index 00000000000..f91ac65286c --- /dev/null +++ b/code/datums/interior/link_interior.dm @@ -0,0 +1,3 @@ +///generic linkage proc for atoms to an interior. e.g loading the tank +/atom/proc/link_interior(datum/interior/link) + return diff --git a/code/datums/interior/map_templates.dm b/code/datums/interior/map_templates.dm new file mode 100644 index 00000000000..470bc172346 --- /dev/null +++ b/code/datums/interior/map_templates.dm @@ -0,0 +1,26 @@ +/datum/map_template/interior + name = "Base Interior Template" + ///just the prefix so we dont need to fill in the entire thing + var/prefix = "_maps/interiors/" + ///filename without file type for the map + var/filename + +/datum/map_template/interior/New() + mappath = "[prefix][filename].dmm" + return ..() + +/datum/map_template/interior/medium_tank + name = "medium tank interior template" + filename = "tank" + +/datum/map_template/interior/transport + name = "transport apc interior template" + filename = "apc_transport" + +/datum/map_template/interior/medical + name = "medical apc interior template" + filename = "apc_medical" + +/datum/map_template/interior/clone_bay + name = "clone bay apc interior template" + filename = "apc_cloner" diff --git a/code/datums/jobs/access.dm b/code/datums/jobs/access.dm index 67d7f55f3e4..65b0495d74e 100644 --- a/code/datums/jobs/access.dm +++ b/code/datums/jobs/access.dm @@ -39,7 +39,7 @@ if(0) return ALL_ACCESS if(1) - return list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_COMMANDER, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_MECH, ACCESS_MARINE_BRIDGE)//command + return list(ACCESS_MARINE_CAPTAIN, ACCESS_MARINE_COMMANDER, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE, ACCESS_MARINE_PILOT, ACCESS_MARINE_MECH, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_ARMORED)//command if(2) return list(ACCESS_MARINE_CE, ACCESS_MARINE_ENGINEERING, ACCESS_MARINE_REMOTEBUILD)//engineering and maintenance if(3) @@ -132,10 +132,14 @@ return "Requisitions" if(ACCESS_MARINE_DROPSHIP) return "Dropship Piloting" + if(ACCESS_MARINE_TADPOLE) + return "Tadpole Piloting" if(ACCESS_MARINE_PILOT) return "Pilot Gear" if(ACCESS_MARINE_MECH) return "Mech" + if(ACCESS_MARINE_ARMORED) + return "Armored Vehicle Bay" if(ACCESS_CIVILIAN_RESEARCH) return "Civilian Research" if(ACCESS_CIVILIAN_LOGISTICS) diff --git a/code/datums/jobs/job/fallen.dm b/code/datums/jobs/job/fallen.dm index 29433b45461..8ed0a3ccec6 100644 --- a/code/datums/jobs/job/fallen.dm +++ b/code/datums/jobs/job/fallen.dm @@ -62,8 +62,8 @@ /datum/job/fallen/marine/leader title = ROLE_FALLEN(SQUAD_LEADER) skills_type = /datum/skills/sl - access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) - minimal_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) + access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE) + minimal_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE) outfit = /datum/outfit/job/marine/leader /datum/job/fallen/marine/mechpilot diff --git a/code/datums/jobs/job/marines.dm b/code/datums/jobs/job/marines.dm index 3abab6bc09a..c824b0af5c5 100644 --- a/code/datums/jobs/job/marines.dm +++ b/code/datums/jobs/job/marines.dm @@ -41,6 +41,7 @@ Make your way to the cafeteria for some post-cryosleep chow, and then get equipp /datum/job/terragov/squad/engineer = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Easy

@@ -107,6 +108,7 @@ What you lack alone, you gain standing shoulder to shoulder with the men and wom /datum/job/terragov/squad/corpsman = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) job_points_needed = 5 html_description = {" @@ -169,6 +171,7 @@ Your squaddies will look to you when it comes to construction in the field of ba jobworth = list( /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, /datum/job/xenomorph = LARVA_POINTS_REGULAR, /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_MEDIUM, /datum/job/terragov/squad/engineer = SMARTIE_POINTS_REGULAR, @@ -317,8 +320,8 @@ You can serve a variety of roles, so choose carefully."}) comm_title = JOB_COMM_TITLE_SQUAD_LEADER total_positions = 4 supervisors = "the acting field commander" - access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) - minimal_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) + access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE) + minimal_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE) skills_type = /datum/skills/sl exp_type = EXP_TYPE_MARINES @@ -336,6 +339,7 @@ You can serve a variety of roles, so choose carefully."}) /datum/job/terragov/squad/engineer = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Hard

@@ -399,6 +403,7 @@ You are also in charge of communicating with command and letting them know about /datum/job/xenomorph = LARVA_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) minimap_icon = "private" diff --git a/code/datums/jobs/job/shipside.dm b/code/datums/jobs/job/shipside.dm index e82078c7ebe..a3acf102a84 100644 --- a/code/datums/jobs/job/shipside.dm +++ b/code/datums/jobs/job/shipside.dm @@ -32,6 +32,7 @@ /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Hard

@@ -139,6 +140,7 @@ Godspeed, captain! And remember, you are not above the law."}) /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty:Very Hard

@@ -275,6 +277,7 @@ Make the TGMC proud!"}) /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Medium

@@ -347,12 +350,92 @@ You are in charge of logistics and the overwatch system. You are also in line to /datum/outfit/job/command/staffofficer/campaign l_store = /obj/item/binoculars/fire_support/campaign + id = /obj/item/card/id/silver + +//Transport Officer +/datum/job/terragov/command/transportofficer + title = TRANSPORT_OFFICER + paygrade = "WO" + comm_title = "TO" + total_positions = 1 + access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE) + minimal_access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_MEDBAY) + skills_type = /datum/skills/transportofficer + display_order = JOB_DISPLAY_ORDER_TRANSPORT_OFFICER + outfit = /datum/outfit/job/command/transportofficer + exp_requirements = XP_REQ_EXPERT + exp_type = EXP_TYPE_REGULAR_ALL + job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD + jobworth = list( + /datum/job/xenomorph = LARVA_POINTS_SHIPSIDE_STRONG, + /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, + /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, + /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + ) + html_description = {" + Difficulty: Hard

+ You answer to the acting Command Staff

+ Unlock Requirement: 100 hours

+ Gamemode Availability: Nuclear War


+ Duty: Pilot the Tadpole, a versatile dropship capable of fulfilling roles ranging from ambulance to mobile bunker. + "} + minimap_icon = "transportofficer" + +/datum/job/terragov/command/transportofficer/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE) + . = ..() + if(!ishuman(new_mob)) + return + var/mob/living/carbon/human/new_human = new_mob + var/playtime_mins = user?.client?.get_exp(title) + if(!playtime_mins || playtime_mins < 1 ) + return + switch(playtime_mins) + if(0 to 600) // starting + new_human.wear_id.paygrade = "WO" + if(601 to 3000) // 10 hrs + new_human.wear_id.paygrade = "CWO" + if(3001 to 6000) // 50 hrs + new_human.wear_id.paygrade = "O1" + if(6001 to INFINITY) // 100 hrs + new_human.wear_id.paygrade = "O2" + +/datum/job/terragov/command/transportofficer/radio_help_message(mob/M) + . = ..() + to_chat(M, {"Your job is to support marines mobile dropship support with the Tadpole. +You are to ensure the Tadpole's survival and to transport marines around, acting as a mobile bunker. In the case of it's death, you may perform the role of Combat Engineer. +"}) + +/datum/outfit/job/command/transportofficer + name = TRANSPORT_OFFICER + jobtype = /datum/job/terragov/command/transportofficer + + id = /obj/item/card/id/silver + belt = /obj/item/storage/belt/utility/full + ears = /obj/item/radio/headset/mainship/mcom + w_uniform = /obj/item/clothing/under/marine/officer/pilot + wear_suit = /obj/item/clothing/suit/modular/xenonauten/pilot + shoes = /obj/item/clothing/shoes/marine/full + gloves = /obj/item/clothing/gloves/marine/insulated + glasses = /obj/item/clothing/glasses/welding/superior + head = /obj/item/clothing/head/helmet/marine/pilot + r_store = /obj/item/storage/pouch/construction + l_store = /obj/item/hud_tablet/transportofficer + back = /obj/item/storage/backpack/marine/engineerpack + suit_store = /obj/item/storage/holster/belt/pistol/m4a3/vp70 + +/datum/outfit/job/command/transportofficer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + . = ..() + H.equip_to_slot_or_hand(new /obj/item/stack/sheet/metal/large_stack, SLOT_IN_R_POUCH) + H.equip_to_slot_or_hand(new /obj/item/stack/sheet/plasteel/large_stack, SLOT_IN_R_POUCH) + H.equip_to_slot_or_hand(new /obj/item/stack/sandbags/large_stack, SLOT_IN_R_POUCH) + H.equip_to_slot_or_hand(new /obj/item/stack/barbed_wire/full, SLOT_IN_R_POUCH) + //Pilot Officer /datum/job/terragov/command/pilot title = PILOT_OFFICER paygrade = "WO" comm_title = "PO" - total_positions = 2 + total_positions = 1 access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT) minimal_access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_PILOT, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO, ACCESS_MARINE_RO, ACCESS_MARINE_MEDBAY) skills_type = /datum/skills/pilot @@ -366,13 +449,14 @@ You are in charge of logistics and the overwatch system. You are also in line to /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Medium

You answer to the acting Command Staff

Unlock Requirement: Starting Role

Gamemode Availability: Nuclear War


- Duty: Choose between the Condor, a modular attack aircraft that provides close air support with a variety of weapons ranging from the inbuilt gatling to wing mounted rockets; or the Tadpole, a versatile dropship capable of fulfilling roles ranging from ambulance to mobile bunker. + Duty: Pilot the Condor, a modular attack aircraft that provides close air support with a variety of weapons ranging from the inbuilt gatling to wing mounted rockets. "} minimap_icon = "pilot" @@ -396,9 +480,9 @@ You are in charge of logistics and the overwatch system. You are also in line to /datum/job/terragov/command/pilot/radio_help_message(mob/M) . = ..() - to_chat(M, {"Your job is to support marines with either close air support via the Condor, or mobile dropship support with the Tadpole. -While you are in charge of all aerial crafts the Normandy does not require supervision outside of turning automatic mode on or off at crucial times, and you are expected to choose between the Condor and Tadpole. -Though you are a warrant officer, your authority is limited to the dropship and your chosen aerial craft, where you have authority over the enlisted personnel. + to_chat(M, {"Your job is to support marines with either close air support via the Condor. +You are expected to use the Condor as the Alamo is able to be ran automatically, though at some points you will be required to take control of the Alamo for the operation's success, though highly unlikey. +Though you are a warrant officer, your authority is limited to the dropship and the Condor, where you have authority over the enlisted personnel. "}) /datum/outfit/job/command/pilot @@ -436,6 +520,7 @@ Though you are a warrant officer, your authority is limited to the dropship and jobworth = list( /datum/job/xenomorph = LARVA_POINTS_REGULAR, /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty:Very Hard

@@ -481,6 +566,285 @@ You can serve your Division in a variety of roles, so choose carefully."}) shoes = /obj/item/clothing/shoes/marine/full gloves = /obj/item/clothing/gloves/marine +//tank/arty driver+gunner +/datum/job/terragov/command/assault_crewman + title = ASSAULT_CREWMAN + req_admin_notify = TRUE + paygrade = "E3" + comm_title = "AC" + total_positions = 0 + skills_type = /datum/skills/assault_crewman + access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC) + minimal_access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO) + display_order = JOB_DISPLAY_ORDER_MECH_PILOT + outfit = /datum/outfit/job/command/assault_crewman + exp_requirements = XP_REQ_EXPERT + exp_type = EXP_TYPE_REGULAR_ALL + job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS|JOB_FLAG_ALWAYS_VISIBLE_ON_MINIMAP + job_points_needed = 999 //50 + jobworth = list( + /datum/job/xenomorph = LARVA_POINTS_REGULAR, + /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, + ) + html_description = {" + Difficulty:Very Hard

+ You answer to the acting Command Staff

+ Unlock Requirement: Starting Role

+ Gamemode Availability: Nuclear War


+ Duty: Provide heavy fire support + "} + minimap_icon = "assault_crew" + +/datum/job/terragov/command/assault_crewman/add_job_points(amount) + . = ..() + if(total_positions % 2) + add_job_positions(1) //always 2 there are, a master and an apprentice + +/datum/job/terragov/command/assault_crewman/radio_help_message(mob/M) + . = ..() + to_chat(M, {"You are an Assault Crewman. You operate the TGMC's armored assault vehicles along with your partner, and in some cases a \"willing\" loader. Make sure that you work as a team to advance the front!"}) + +/datum/job/terragov/command/assault_crewman/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE) + . = ..() + if(!ishuman(new_mob)) + return + var/mob/living/carbon/human/new_human = new_mob + var/playtime_mins = user?.client?.get_exp(title) + if(!playtime_mins || playtime_mins < 1 ) + return + switch(playtime_mins) + if(0 to 1500) // starting + new_human.wear_id.paygrade = "E3" + if(1501 to 6000) // 25 hrs + new_human.wear_id.paygrade = "E4" + if(6001 to 18000) // 100 hrs + new_human.wear_id.paygrade = "E5" + if(18001 to 60000) // 300 hrs + new_human.wear_id.paygrade = "E6" + if(60001 to INFINITY) // 1000 hrs + new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours. + +/datum/outfit/job/command/assault_crewman + name = ASSAULT_CREWMAN + jobtype = /datum/job/terragov/command/assault_crewman + + id = /obj/item/card/id/dogtag + belt = /obj/item/storage/belt/utility/full + glasses = /obj/item/clothing/glasses/welding + ears = /obj/item/radio/headset/mainship/mcom + w_uniform = /obj/item/clothing/under/marine/officer/assault_crewman + wear_suit = /obj/item/clothing/suit/storage/marine/assault_crewman + head = /obj/item/clothing/head/helmet/marine/assault_crewman + shoes = /obj/item/clothing/shoes/marine/full + gloves = /obj/item/clothing/gloves/marine + + +//apc/jeep driver +/datum/job/terragov/command/transport_crewman + title = TRANSPORT_CREWMAN + req_admin_notify = TRUE + paygrade = "E3" + comm_title = "TC" + total_positions = 0 + skills_type = /datum/skills/transport_crewman + access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC) + minimal_access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO) + display_order = JOB_DISPLAY_ORDER_MECH_PILOT + outfit = /datum/outfit/job/command/transport_crewman + exp_requirements = XP_REQ_EXPERT + exp_type = EXP_TYPE_REGULAR_ALL + job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS|JOB_FLAG_ALWAYS_VISIBLE_ON_MINIMAP + job_points_needed = 40 + jobworth = list( + /datum/job/xenomorph = LARVA_POINTS_REGULAR, + /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, + ) + html_description = {" + Difficulty:Very Hard

+ You answer to the acting Command Staff

+ Unlock Requirement: Starting Role

+ Gamemode Availability: Nuclear War


+ Duty: Transport and support the frontline troops + "} + minimap_icon = "transport_crew" + +/datum/job/terragov/command/transport_crewman/radio_help_message(mob/M) + . = ..() + to_chat(M, {"You are a Transport Crewman. You operate the TGMC's transport vehciles to ensure that marines and equipment gets to the front in a timely and safe manner."}) + +/datum/job/terragov/command/transport_crewman/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE) + . = ..() + if(!ishuman(new_mob)) + return + var/mob/living/carbon/human/new_human = new_mob + var/playtime_mins = user?.client?.get_exp(title) + if(!playtime_mins || playtime_mins < 1 ) + return + switch(playtime_mins) + if(0 to 1500) // starting + new_human.wear_id.paygrade = "E3" + if(1501 to 6000) // 25 hrs + new_human.wear_id.paygrade = "E4" + if(6001 to 18000) // 100 hrs + new_human.wear_id.paygrade = "E5" + if(18001 to 60000) // 300 hrs + new_human.wear_id.paygrade = "E6" + if(60001 to INFINITY) // 1000 hrs + new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours. + +/datum/outfit/job/command/transport_crewman + name = TRANSPORT_CREWMAN + jobtype = /datum/job/terragov/command/transport_crewman + + id = /obj/item/card/id/dogtag + belt = /obj/item/storage/belt/utility/full + glasses = /obj/item/clothing/glasses/welding + ears = /obj/item/radio/headset/mainship/mcom + w_uniform = /obj/item/clothing/under/marine/officer/transport_crewman + wear_suit = /obj/item/clothing/suit/storage/marine/transport_crewman + head = /obj/item/clothing/head/helmet/marine/transport_crewman + shoes = /obj/item/clothing/shoes/marine/full + gloves = /obj/item/clothing/gloves/marine + +//tank/arty driver+gunner +/datum/job/terragov/command/assault_crewman + title = ASSAULT_CREWMAN + req_admin_notify = TRUE + paygrade = "E3" + comm_title = "AC" + total_positions = 0 + skills_type = /datum/skills/assault_crewman + access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC) + minimal_access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO) + display_order = JOB_DISPLAY_ORDER_MECH_PILOT + outfit = /datum/outfit/job/command/assault_crewman + exp_requirements = XP_REQ_EXPERT + exp_type = EXP_TYPE_REGULAR_ALL + job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS|JOB_FLAG_ALWAYS_VISIBLE_ON_MINIMAP + job_points_needed = 999 //50 + jobworth = list( + /datum/job/xenomorph = LARVA_POINTS_REGULAR, + /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, + ) + html_description = {" + Difficulty:Very Hard

+ You answer to the acting Command Staff

+ Unlock Requirement: Starting Role

+ Gamemode Availability: Nuclear War


+ Duty: Provide heavy fire support + "} + minimap_icon = "assault_crew" + +/datum/job/terragov/command/assault_crewman/add_job_points(amount) + . = ..() + if(total_positions % 2) + add_job_positions(1) //always 2 there are, a master and an apprentice + +/datum/job/terragov/command/assault_crewman/radio_help_message(mob/M) + . = ..() + to_chat(M, {"You are an Assault Crewman. You operate the TGMC's armored assault vehicles along with your partner, and in some cases a \"willing\" loader. Make sure that you work as a team to advance the front!"}) + +/datum/job/terragov/command/assault_crewman/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE) + . = ..() + if(!ishuman(new_mob)) + return + var/mob/living/carbon/human/new_human = new_mob + var/playtime_mins = user?.client?.get_exp(title) + if(!playtime_mins || playtime_mins < 1 ) + return + switch(playtime_mins) + if(0 to 1500) // starting + new_human.wear_id.paygrade = "E3" + if(1501 to 6000) // 25 hrs + new_human.wear_id.paygrade = "E4" + if(6001 to 18000) // 100 hrs + new_human.wear_id.paygrade = "E5" + if(18001 to 60000) // 300 hrs + new_human.wear_id.paygrade = "E6" + if(60001 to INFINITY) // 1000 hrs + new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours. + +/datum/outfit/job/command/assault_crewman + name = ASSAULT_CREWMAN + jobtype = /datum/job/terragov/command/assault_crewman + + id = /obj/item/card/id/dogtag + belt = /obj/item/storage/belt/utility/full + glasses = /obj/item/clothing/glasses/welding + ears = /obj/item/radio/headset/mainship/mcom + w_uniform = /obj/item/clothing/under/marine/officer/assault_crewman + wear_suit = /obj/item/clothing/suit/storage/marine/assault_crewman + head = /obj/item/clothing/head/helmet/marine/assault_crewman + shoes = /obj/item/clothing/shoes/marine/full + gloves = /obj/item/clothing/gloves/marine + +//apc/jeep driver +/datum/job/terragov/command/transport_crewman + title = TRANSPORT_CREWMAN + req_admin_notify = TRUE + paygrade = "E3" + comm_title = "TC" + total_positions = 0 + skills_type = /datum/skills/transport_crewman + access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC) + minimal_access = list(ACCESS_MARINE_WO, ACCESS_MARINE_PREP, ACCESS_MARINE_ARMORED, ACCESS_CIVILIAN_PUBLIC, ACCESS_MARINE_BRIDGE, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LOGISTICS, ACCESS_MARINE_CARGO) + display_order = JOB_DISPLAY_ORDER_MECH_PILOT + outfit = /datum/outfit/job/command/transport_crewman + exp_requirements = XP_REQ_EXPERT + exp_type = EXP_TYPE_REGULAR_ALL + job_flags = JOB_FLAG_LATEJOINABLE|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_ALLOWS_PREFS_GEAR|JOB_FLAG_PROVIDES_BANK_ACCOUNT|JOB_FLAG_ADDTOMANIFEST|JOB_FLAG_PROVIDES_SQUAD_HUD|JOB_FLAG_CAN_SEE_ORDERS|JOB_FLAG_ALWAYS_VISIBLE_ON_MINIMAP + job_points_needed = 40 + jobworth = list( + /datum/job/xenomorph = LARVA_POINTS_REGULAR, + /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, + ) + html_description = {" + Difficulty:Very Hard

+ You answer to the acting Command Staff

+ Unlock Requirement: Starting Role

+ Gamemode Availability: Nuclear War


+ Duty: Transport and support the frontline troops + "} + minimap_icon = "transport_crew" + +/datum/job/terragov/command/transport_crewman/radio_help_message(mob/M) + . = ..() + to_chat(M, {"You are a Transport Crewman. You operate the TGMC's transport vehciles to ensure that marines and equipment gets to the front in a timely and safe manner."}) + +/datum/job/terragov/command/transport_crewman/after_spawn(mob/living/carbon/new_mob, mob/user, latejoin = FALSE) + . = ..() + if(!ishuman(new_mob)) + return + var/mob/living/carbon/human/new_human = new_mob + var/playtime_mins = user?.client?.get_exp(title) + if(!playtime_mins || playtime_mins < 1 ) + return + switch(playtime_mins) + if(0 to 1500) // starting + new_human.wear_id.paygrade = "E3" + if(1501 to 6000) // 25 hrs + new_human.wear_id.paygrade = "E4" + if(6001 to 18000) // 100 hrs + new_human.wear_id.paygrade = "E5" + if(18001 to 60000) // 300 hrs + new_human.wear_id.paygrade = "E6" + if(60001 to INFINITY) // 1000 hrs + new_human.wear_id.paygrade = "E9A" //If you play way too much TGMC. 1000 hours. + +/datum/outfit/job/command/transport_crewman + name = TRANSPORT_CREWMAN + jobtype = /datum/job/terragov/command/transport_crewman + + id = /obj/item/card/id/dogtag + belt = /obj/item/storage/belt/utility/full + glasses = /obj/item/clothing/glasses/welding + ears = /obj/item/radio/headset/mainship/mcom + w_uniform = /obj/item/clothing/under/marine/officer/transport_crewman + wear_suit = /obj/item/clothing/suit/storage/marine/transport_crewman + head = /obj/item/clothing/head/helmet/marine/transport_crewman + shoes = /obj/item/clothing/shoes/marine/full + gloves = /obj/item/clothing/gloves/marine + /datum/job/terragov/engineering job_category = JOB_CAT_ENGINEERING selection_color = "#fff5cc" @@ -508,6 +872,7 @@ You can serve your Division in a variety of roles, so choose carefully."}) /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Hard

@@ -584,6 +949,7 @@ You are also next in the chain of command, should the bridge crew fall in the li /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Medium

@@ -662,6 +1028,7 @@ requisitions line and later on to be ready to send supplies for marines who are /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Medium

@@ -745,6 +1112,7 @@ A happy ship is a well-functioning ship."}) /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Hard

@@ -831,6 +1199,7 @@ Make sure that the doctors and nurses are doing their jobs and keeping the marin /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Medium

@@ -919,6 +1288,7 @@ You are also an expert when it comes to medication and treatment. If you do not /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Medium

@@ -1007,6 +1377,7 @@ It is also recommended that you gear up like a regular marine, or your 'internsh /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Hard (varies)

@@ -1081,6 +1452,7 @@ Use your office fax machine to communicate with corporate headquarters or to acq /datum/job/xenomorph = LARVA_POINTS_SHIPSIDE_STRONG, /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Soul Crushing

@@ -1173,6 +1545,7 @@ In addition, being a Synthetic gives you knowledge in every field and specializa /datum/job/terragov/squad/smartgunner = SMARTIE_POINTS_REGULAR, /datum/job/terragov/silicon/synthetic = SYNTH_POINTS_REGULAR, /datum/job/terragov/command/mech_pilot = MECH_POINTS_REGULAR, + /datum/job/terragov/command/assault_crewman = ARMORED_VEHICLE_POINTS_REGULAR, ) html_description = {" Difficulty: Easy

diff --git a/code/datums/jobs/squads.dm b/code/datums/jobs/squads.dm index 0ea83a21482..b5a745427cc 100644 --- a/code/datums/jobs/squads.dm +++ b/code/datums/jobs/squads.dm @@ -294,7 +294,7 @@ R.use_command = FALSE var/obj/item/card/id/ID = squad_leader.get_idcard() if(istype(ID)) - ID.access -= list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) + ID.access -= list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE) to_chat(squad_leader, "You're no longer the Squad Leader for [src]!") var/mob/living/carbon/human/H = squad_leader @@ -319,7 +319,7 @@ squad_leader.comm_title = "aSL" var/obj/item/card/id/ID = squad_leader.get_idcard() if(istype(ID)) - ID.access += list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) + ID.access += list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_TADPOLE) if(istype(squad_leader.wear_ear, /obj/item/radio/headset/mainship/marine)) var/obj/item/radio/headset/mainship/marine/R = squad_leader.wear_ear diff --git a/code/datums/keybinding/human.dm b/code/datums/keybinding/human.dm index e2e7d0bfe02..e031518f157 100644 --- a/code/datums/keybinding/human.dm +++ b/code/datums/keybinding/human.dm @@ -174,3 +174,9 @@ full_name = "Issue Retreat Order" description = "Order and rally marines to retreat" keybind_signal = COMSIG_KB_RETREATORDER + +/datum/keybinding/human/vehicle_honk + name = "vehicle_honk" + full_name = "Honk Horn" + description = "Tell marines to move so that they don't get run over" + keybind_signal = COMSIG_KB_VEHICLEHONK diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm index c209d5101e6..c9bbbd4a855 100644 --- a/code/datums/shuttles.dm +++ b/code/datums/shuttles.dm @@ -188,6 +188,10 @@ shuttle_id = SHUTTLE_SUPPLY name = SHUTTLE_SUPPLY +/datum/map_template/shuttle/supply/vehicle + shuttle_id = SHUTTLE_VEHICLE_SUPPLY + name = SHUTTLE_VEHICLE_SUPPLY + /datum/map_template/shuttle/tgs_canterbury shuttle_id = SHUTTLE_CANTERBURY name = "Canterbury" diff --git a/code/datums/skills.dm b/code/datums/skills.dm index de0aacadccd..017a179adcf 100644 --- a/code/datums/skills.dm +++ b/code/datums/skills.dm @@ -422,12 +422,33 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader powerloader = SKILL_POWERLOADER_PRO leadership = SKILL_LEAD_TRAINED +/datum/skills/transportofficer + name = TRANSPORT_OFFICER + construction = SKILL_CONSTRUCTION_ADVANCED + powerloader = SKILL_POWERLOADER_PRO + engineer = SKILL_ENGINEER_ENGI + leadership = SKILL_LEAD_TRAINED + /datum/skills/mech_pilot name = MECH_PILOT engineer = SKILL_ENGINEER_METAL construction = SKILL_CONSTRUCTION_METAL powerloader = SKILL_POWERLOADER_PRO - large_vehicle = SKILL_LARGE_VEHICLE_TRAINED + large_vehicle = SKILL_LARGE_VEHICLE_VETERAN + +/datum/skills/assault_crewman + name = ASSAULT_CREWMAN + engineer = SKILL_ENGINEER_METAL + construction = SKILL_CONSTRUCTION_METAL + powerloader = SKILL_POWERLOADER_PRO + large_vehicle = SKILL_LARGE_VEHICLE_VETERAN + +/datum/skills/transport_crewman + name = TRANSPORT_CREWMAN + engineer = SKILL_ENGINEER_METAL + construction = SKILL_CONSTRUCTION_METAL + powerloader = SKILL_POWERLOADER_PRO + large_vehicle = SKILL_LARGE_VEHICLE_EXPERIENCED /datum/skills/ce name = CHIEF_SHIP_ENGINEER @@ -633,7 +654,7 @@ engineer, construction, leadership, medical, surgery, pilot, police, powerloader heavy_weapons = SKILL_HEAVY_WEAPONS_TRAINED police = SKILL_POLICE_MP powerloader = SKILL_POWERLOADER_MASTER - large_vehicle = SKILL_LARGE_VEHICLE_TRAINED + large_vehicle = SKILL_LARGE_VEHICLE_VETERAN swordplay = SKILL_SWORDPLAY_TRAINED /* Deathsquad */ diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 2b91f168c1e..67fc9d7b579 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -442,6 +442,7 @@ return ..() /datum/status_effect/spacefreeze + alert_type = /atom/movable/screen/alert/status_effect/spacefreeze id = "spacefreeze" alert_type = /atom/movable/screen/alert/status_effect/spacefreeze @@ -841,3 +842,8 @@ scale = generator(GEN_VECTOR, list(0.6, 0.6), list(1, 1), NORMAL_RAND) friction = -0.05 color = "#818181" + +/atom/movable/screen/alert/status_effect/spacefreeze + name = "Freezing" + desc = "Space is very very cold, who would've thought?" + icon_state = "cold3" diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm new file mode 100644 index 00000000000..2e66443154b --- /dev/null +++ b/code/game/alternate_appearance.dm @@ -0,0 +1,134 @@ +GLOBAL_LIST_EMPTY(active_alternate_appearances) + +/atom/proc/remove_alt_appearance(key) + if(alternate_appearances) + for(var/K in alternate_appearances) + var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] + if(AA.appearance_key == key) + AA.remove_from_hud(src) + break + +/atom/proc/add_alt_appearance(type, key, ...) + if(!type || !key) + return + if(alternate_appearances && alternate_appearances[key]) + return + if(!ispath(type, /datum/atom_hud/alternate_appearance)) + CRASH("Invalid type passed in: [type]") + var/list/arguments = args.Copy(2) + return new type(arglist(arguments)) + +/datum/atom_hud/alternate_appearance + var/appearance_key + var/transfer_overlays = FALSE + +/datum/atom_hud/alternate_appearance/New(key) + ..() + GLOB.active_alternate_appearances += src + appearance_key = key + + for(var/mob AS in GLOB.player_list) + if(mobShouldSee(mob)) + add_hud_to(mob) + +/datum/atom_hud/alternate_appearance/Destroy() + GLOB.active_alternate_appearances -= src + return ..() + +/datum/atom_hud/alternate_appearance/proc/onNewMob(mob/M) + if(mobShouldSee(M)) + add_hud_to(M) + +/datum/atom_hud/alternate_appearance/proc/mobShouldSee(mob/M) + return FALSE + +/datum/atom_hud/alternate_appearance/add_to_hud(atom/A, image/I) + . = ..() + if(.) + LAZYINITLIST(A.alternate_appearances) + A.alternate_appearances[appearance_key] = src + +/datum/atom_hud/alternate_appearance/remove_from_hud(atom/A) + . = ..() + if(.) + LAZYREMOVE(A.alternate_appearances, appearance_key) + +/datum/atom_hud/alternate_appearance/proc/copy_overlays(atom/other, cut_old) + return + +//an alternate appearance that attaches a single image to a single atom +/datum/atom_hud/alternate_appearance/basic + var/atom/target + var/image/image + var/add_ghost_version = FALSE + var/ghost_appearance + +/datum/atom_hud/alternate_appearance/basic/New(key, image/I, options = AA_TARGET_SEE_APPEARANCE) + ..() + transfer_overlays = options & AA_MATCH_TARGET_OVERLAYS + image = I + target = I.loc + if(transfer_overlays) + I.copy_overlays(target) + + hud_icons = list(appearance_key) + add_to_hud(target, I) + if((options & AA_TARGET_SEE_APPEARANCE) && ismob(target)) + add_hud_to(target) + if(add_ghost_version) + var/image/ghost_image = image(icon = I.icon , icon_state = I.icon_state, loc = I.loc) + ghost_image.override = FALSE + ghost_image.alpha = 128 + ghost_appearance = new /datum/atom_hud/alternate_appearance/basic/observers(key + "_observer", ghost_image, NONE) + +/datum/atom_hud/alternate_appearance/basic/Destroy() + . = ..() + QDEL_NULL(image) + target = null + if(ghost_appearance) + QDEL_NULL(ghost_appearance) + +/datum/atom_hud/alternate_appearance/basic/add_to_hud(atom/A) + LAZYINITLIST(A.hud_list) + A.hud_list[appearance_key] = image + . = ..() + +/datum/atom_hud/alternate_appearance/basic/remove_from_hud(atom/A) + . = ..() + A.hud_list -= appearance_key + if(. && !QDELETED(src)) + qdel(src) + +/datum/atom_hud/alternate_appearance/basic/copy_overlays(atom/other, cut_old) + image.copy_overlays(other, cut_old) + +/datum/atom_hud/alternate_appearance/basic/everyone + add_ghost_version = TRUE + +/datum/atom_hud/alternate_appearance/basic/everyone/mobShouldSee(mob/M) + return !isdead(M) + +/datum/atom_hud/alternate_appearance/basic/silicons + +/datum/atom_hud/alternate_appearance/basic/silicons/mobShouldSee(mob/M) + if(issilicon(M)) + return TRUE + return FALSE + +/datum/atom_hud/alternate_appearance/basic/observers + add_ghost_version = FALSE //just in case, to prevent infinite loops + +/datum/atom_hud/alternate_appearance/basic/observers/mobShouldSee(mob/M) + return isobserver(M) + +/datum/atom_hud/alternate_appearance/basic/one_person + var/mob/seer + +/datum/atom_hud/alternate_appearance/basic/one_person/mobShouldSee(mob/M) + if(M == seer) + return TRUE + return FALSE + +/datum/atom_hud/alternate_appearance/basic/one_person/New(key, image/I, mob/living/M) + ..(key, I, FALSE) + seer = M diff --git a/code/game/area/area.dm b/code/game/area/area.dm index 523665a9b27..08cd6abb3f9 100644 --- a/code/game/area/area.dm +++ b/code/game/area/area.dm @@ -197,16 +197,24 @@ for(var/obj/machinery/computer/station_alert/a in GLOB.machines) a.cancelAlarm("Fire", src, src) -/area/update_icon() + +/area/update_icon_state() + . = ..() var/I //More important == bottom. Fire normally takes priority over everything. if(flags_alarm_state && (!requires_power || power_environ)) //It either doesn't require power or the environment is powered. And there is an alarm. - if(flags_alarm_state & ALARM_WARNING_READY) I = "alarm_ready" //Area is ready for something. - if(flags_alarm_state & ALARM_WARNING_EVAC) I = "alarm_evac" //Evacuation happening. - if(flags_alarm_state & ALARM_WARNING_ATMOS) I = "alarm_atmos" //Atmos breach. - if(flags_alarm_state & ALARM_WARNING_FIRE) I = "alarm_fire" //Fire happening. - if(flags_alarm_state & ALARM_WARNING_DOWN) I = "alarm_down" //Area is shut down. - - if(icon_state != I) icon_state = I //If the icon state changed, change it. Otherwise do nothing. + if(flags_alarm_state & ALARM_WARNING_READY) + I = "alarm_ready" //Area is ready for something. + if(flags_alarm_state & ALARM_WARNING_EVAC) + I = "alarm_evac" //Evacuation happening. + if(flags_alarm_state & ALARM_WARNING_ATMOS) + I = "alarm_atmos" //Atmos breach. + if(flags_alarm_state & ALARM_WARNING_FIRE) + I = "alarm_fire" //Fire happening. + if(flags_alarm_state & ALARM_WARNING_DOWN) + I = "alarm_down" //Area is shut down. + + if(icon_state != I) + icon_state = I //If the icon state changed, change it. Otherwise do nothing. /area/proc/powered(chan) if(!requires_power) diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 9feee726edc..e7bfd2bd325 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -95,15 +95,16 @@ /area/shuttle/mining name = "Mining Shuttle" -// blob_allowed = FALSE /area/shuttle/labor name = "Labor Camp Shuttle" -// blob_allowed = FALSE /area/shuttle/supply name = "Supply Shuttle" -// blob_allowed = FALSE + +/area/shuttle/vehicle_supply + name = "Vehicle Supply Shuttle" + /* /area/shuttle/escape name = "Emergency Shuttle" diff --git a/code/game/atoms.dm b/code/game/atoms/_atom.dm similarity index 96% rename from code/game/atoms.dm rename to code/game/atoms/_atom.dm index 49375d5c8f6..ecdfb01ff98 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms/_atom.dm @@ -39,9 +39,6 @@ ///How much does this atom block the explosion's shock wave. var/explosion_block = 0 - ///overlays managed by update_overlays() to prevent removing overlays that weren't added by the same proc - var/list/managed_overlays - var/datum/component/orbiter/orbiters var/datum/proximity_monitor/proximity_monitor @@ -124,6 +121,11 @@ ///Cooldown for telling someone they're buckled COOLDOWN_DECLARE(buckle_message_cooldown) + ///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays. + var/list/managed_vis_overlays + ///The list of alternate appearances for this atom + var/list/alternate_appearances + /* We actually care what this returns, since it can return different directives. Not specifically here, but in other variations of this. As a general safety, @@ -144,6 +146,11 @@ directive is properly returned. if(isturf(loc)) loc.fingerprints = fingerprints + if(alternate_appearances) + for(var/K in alternate_appearances) + var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] + AA.remove_from_hud(src) + return ..() //=========================================================================== @@ -333,32 +340,6 @@ directive is properly returned. SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .) - -/// Updates the icon of the atom -/atom/proc/update_icon() - var/signalOut = SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON) - - if(!(signalOut & COMSIG_ATOM_NO_UPDATE_ICON_STATE)) - update_icon_state() - - if(!(signalOut & COMSIG_ATOM_NO_UPDATE_OVERLAYS)) - var/list/new_overlays = update_overlays() - if(managed_overlays) - cut_overlay(managed_overlays) - managed_overlays = null - if(length(new_overlays)) - managed_overlays = new_overlays - add_overlay(new_overlays) - -/// Updates the icon state of the atom -/atom/proc/update_icon_state() - -/// Updates the overlays of the atom -/atom/proc/update_overlays() - SHOULD_CALL_PARENT(TRUE) - . = list() - SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .) - /// Checks if the colors given are different and if so causes a greyscale icon update /// The colors argument can be either a list or the full color string /atom/proc/set_greyscale_colors(list/colors, update=TRUE) @@ -861,11 +842,16 @@ directive is properly returned. /atom/proc/prepare_huds() hud_list = new for(var/hud in hud_possible) //Providing huds. - var/image/new_hud = image('icons/mob/hud.dmi', src, "") - if(hud == HUNTER_CLAN || hud == HUNTER_HUD) - new_hud = image('icons/mob/hud_yautja.dmi', src, "") - new_hud.appearance_flags = KEEP_APART - hud_list[hud] = new_hud + var/hint = hud_possible[hud] + switch(hint) + if(HUD_LIST_LIST) + hud_list[hud] = list() + else + var/image/I = image('icons/mob/hud.dmi', src, "") + if(hud == HUNTER_CLAN || hud == HUNTER_HUD) + I = image('icons/mob/hud_yautja.dmi', src, "") + I.appearance_flags = RESET_COLOR|RESET_TRANSFORM + hud_list[hud] = I /** * If this object has lights, turn it on/off. @@ -954,3 +940,8 @@ directive is properly returned. ///Returns the hard armor for the given atom. If human and a limb is specified, gets the armor for that specific limb. /atom/proc/get_hard_armor(armor_type, proj_def_zone) return + +//not fully portet from tg +///Interaction for using a grab on an atom +/atom/proc/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE) + return diff --git a/code/game/atoms/atom_appearance.dm b/code/game/atoms/atom_appearance.dm new file mode 100644 index 00000000000..76a8268a932 --- /dev/null +++ b/code/game/atoms/atom_appearance.dm @@ -0,0 +1,112 @@ +/atom + ///overlays managed by [update_overlays][/atom/proc/update_overlays] to prevent removing overlays that weren't added by the same proc. Single items are stored on their own, not in a list. + var/list/managed_overlays + +/** + * Updates the appearence of the icon + * + * Mostly delegates to update_name, update_desc, and update_icon + * + * Arguments: + * - updates: A set of bitflags dictating what should be updated. Defaults to [ALL] + */ +/atom/proc/update_appearance(updates=ALL) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + + . = NONE + updates &= ~SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_APPEARANCE, updates) + if(updates & UPDATE_NAME) + . |= update_name(updates) + if(updates & UPDATE_DESC) + . |= update_desc(updates) + if(updates & UPDATE_ICON) + . |= update_icon(updates) + +/// Updates the name of the atom +/atom/proc/update_name(updates=ALL) + SHOULD_CALL_PARENT(TRUE) + return SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_NAME, updates) + +/// Updates the description of the atom +/atom/proc/update_desc(updates=ALL) + SHOULD_CALL_PARENT(TRUE) + return SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_DESC, updates) + +/// Updates the icon of the atom +/atom/proc/update_icon(updates=ALL) + SHOULD_CALL_PARENT(TRUE) + + . = NONE + updates &= ~SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON, updates) + if(updates & UPDATE_ICON_STATE) + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON_STATE) + update_icon_state() + . |= UPDATE_ICON_STATE + + if(updates & UPDATE_OVERLAYS) + if(LAZYLEN(managed_vis_overlays)) + SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) + + var/list/new_overlays = update_overlays(updates) + var/nulls = 0 + for(var/i in 1 to length(new_overlays)) + var/atom/maybe_not_an_atom = new_overlays[i] + if(isnull(maybe_not_an_atom)) + nulls++ + continue + if(istext(maybe_not_an_atom) || isicon(maybe_not_an_atom)) + continue + new_overlays[i] = maybe_not_an_atom.appearance + if(nulls) + for(var/i in 1 to nulls) + new_overlays -= null + + var/identical = FALSE + var/new_length = length(new_overlays) + if(!managed_overlays && !new_length) + identical = TRUE + else if(!islist(managed_overlays)) + if(new_length == 1 && managed_overlays == new_overlays[1]) + identical = TRUE + else if(length(managed_overlays) == new_length) + identical = TRUE + for(var/i in 1 to length(managed_overlays)) + if(managed_overlays[i] != new_overlays[i]) + identical = FALSE + break + + if(!identical) + var/full_control = FALSE + if(managed_overlays) + full_control = length(overlays) == (islist(managed_overlays) ? length(managed_overlays) : 1) + if(full_control) + overlays = null + else + cut_overlay(managed_overlays) + + switch(length(new_overlays)) + if(0) + if(full_control) + POST_OVERLAY_CHANGE(src) + managed_overlays = null + if(1) + add_overlay(new_overlays) + managed_overlays = new_overlays[1] + else + add_overlay(new_overlays) + managed_overlays = new_overlays + + . |= UPDATE_OVERLAYS + + . |= SEND_SIGNAL(src, COMSIG_ATOM_UPDATED_ICON, updates, .) + +/// Updates the icon state of the atom +/atom/proc/update_icon_state() + + +/// Updates the overlays of the atom +/atom/proc/update_overlays() + SHOULD_CALL_PARENT(TRUE) + . = list() + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .) diff --git a/code/game/atoms_movable.dm b/code/game/atoms/atom_movable.dm similarity index 96% rename from code/game/atoms_movable.dm rename to code/game/atoms/atom_movable.dm index 4ed246e2f4d..64ab0a3c83d 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms/atom_movable.dm @@ -1,7 +1,7 @@ /atom/movable layer = OBJ_LAYER glide_size = 8 - appearance_flags = TILE_BOUND|PIXEL_SCALE + appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE var/last_move = null var/last_move_time = 0 var/anchored = FALSE @@ -263,6 +263,10 @@ RU TGMC EDIT */ return var/atom/oldloc = loc + //Early override for some cases like diagonal movement + if(glide_size_override) + set_glide_size(glide_size_override) + loc = newloc oldloc.Exited(src, direction) @@ -281,9 +285,6 @@ RU TGMC EDIT */ if(oldarea != newarea) newarea.Entered(src, oldarea) - if(glide_size_override) - set_glide_size(glide_size_override) - Moved(oldloc, direction) if(pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move. @@ -294,14 +295,19 @@ RU TGMC EDIT */ //puller and pullee more than one tile away or in diagonal position if(get_dist(src, pulling) > 1 || (pull_dir - 1) & pull_dir) pulling.moving_from_pull = src - pulling.Move(oldloc, get_dir(pulling, oldloc), glide_size_override) //the pullee tries to reach our previous position + pulling.Move(oldloc, get_dir(pulling, oldloc), glide_size) //the pullee tries to reach our previous position pulling.moving_from_pull = null check_pulling() + //glide_size strangely enough can change mid movement animation and update correctly while the animation is playing + //This means that if you don't override it late like this, it will just be set back by the movement update that's called when you move turfs. + if(glide_size_override) + set_glide_size(glide_size_override) + last_move = direction last_move_time = world.time - if(LAZYLEN(buckled_mobs) && !handle_buckled_mob_movement(loc, direction)) //movement failed due to buckled mob(s) + if(LAZYLEN(buckled_mobs) && !handle_buckled_mob_movement(loc, direction, glide_size_override)) //movement failed due to buckled mob(s) return FALSE return TRUE @@ -368,12 +374,12 @@ RU TGMC EDIT */ /atom/movable/proc/Moved(atom/old_loc, movement_dir, forced = FALSE, list/old_locs) - SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, movement_dir, forced, old_locs) + SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, movement_dir, forced, locs) if(client_mobs_in_contents) update_parallax_contents() if(pulledby) - SEND_SIGNAL(src, COMSIG_MOVABLE_PULL_MOVED, old_loc, movement_dir, forced, old_locs) + SEND_SIGNAL(src, COMSIG_MOVABLE_PULL_MOVED, old_loc, movement_dir, forced, locs) //Cycle through the light sources on this atom and tell them to update. for(var/datum/dynamic_light_source/light AS in hybrid_light_sources) light.source_atom.update_light() @@ -576,7 +582,8 @@ RU TGMC EDIT */ var/atom/step = get_step(src, dy) if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - Move(step) + if(!Move(step, glide_size_override = DELAY_TO_GLIDE_SIZE(1 / speed))) + throwing = FALSE error += dist_x dist_since_sleep++ if(dist_since_sleep >= speed) @@ -586,7 +593,8 @@ RU TGMC EDIT */ var/atom/step = get_step(src, dx) if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - Move(step) + if(!Move(step, glide_size_override = DELAY_TO_GLIDE_SIZE(1 / speed))) + throwing = FALSE error -= dist_y dist_since_sleep++ if(dist_since_sleep >= speed) @@ -600,7 +608,8 @@ RU TGMC EDIT */ var/atom/step = get_step(src, dx) if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - Move(step) + if(!Move(step, glide_size_override = DELAY_TO_GLIDE_SIZE(1 / speed))) + throwing = FALSE error += dist_y dist_since_sleep++ if(dist_since_sleep >= speed) @@ -610,7 +619,8 @@ RU TGMC EDIT */ var/atom/step = get_step(src, dy) if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - Move(step) + if(!Move(step, glide_size_override = DELAY_TO_GLIDE_SIZE(1 / speed))) + throwing = FALSE error -= dist_x dist_since_sleep++ if(dist_since_sleep >= speed) @@ -636,10 +646,10 @@ RU TGMC EDIT */ thrown_speed = 0 throw_source = null -/atom/movable/proc/handle_buckled_mob_movement(NewLoc, direct) +/atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m - if(buckled_mob.Move(NewLoc, direct)) + if(buckled_mob.Move(newloc, direct, glide_size_override)) continue forceMove(buckled_mob.loc) last_move = buckled_mob.last_move @@ -923,7 +933,7 @@ RU TGMC EDIT */ var/turf/destination_turf = get_step(pulling.loc, move_dir) if(!Adjacent(destination_turf) || (destination_turf == loc && pulling.density)) return FALSE - pulling.Move(destination_turf, move_dir) + pulling.Move(destination_turf, move_dir, glide_size) return TRUE @@ -963,45 +973,18 @@ RU TGMC EDIT */ /atom/movable/proc/is_buckled() return buckled - /atom/movable/proc/set_glide_size(target = 8) - if(glide_size == target) - return FALSE SEND_SIGNAL(src, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, target) glide_size = target - if(pulling && pulling.glide_size != target) - pulling.set_glide_size(target) - return TRUE -/obj/set_glide_size(target = 8) - . = ..() - if(!.) - return - for(var/m in buckled_mobs) - var/mob/living/buckled_mob = m - if(buckled_mob.glide_size == target) - continue + for(var/mob/buckled_mob AS in buckled_mobs) buckled_mob.set_glide_size(target) -/obj/structure/bed/set_glide_size(target = 8) - . = ..() - if(!.) - return - if(buckled_bodybag && buckled_bodybag.glide_size != target) - buckled_bodybag.set_glide_size(target) - glide_size = target - - /atom/movable/proc/reset_glide_size() if(glide_modifier_flags) return set_glide_size(initial(glide_size)) -/obj/vehicle/reset_glide_size() - if(glide_modifier_flags) - return - set_glide_size(DELAY_TO_GLIDE_SIZE_STATIC(move_delay)) - /mob/reset_glide_size() if(glide_modifier_flags) return diff --git a/code/game/buckling.dm b/code/game/buckling.dm index 853d8b635e0..7d2af076096 100644 --- a/code/game/buckling.dm +++ b/code/game/buckling.dm @@ -61,6 +61,7 @@ if(buckle_lying != -1) ADD_TRAIT(buckling_mob, TRAIT_FLOORED, BUCKLE_TRAIT) buckling_mob.throw_alert("buckled", /atom/movable/screen/alert/restrained/buckled) + buckling_mob.set_glide_size(glide_size) post_buckle_mob(buckling_mob, silent) RegisterSignal(buckling_mob, COMSIG_LIVING_DO_RESIST, PROC_REF(resisted_against)) @@ -87,6 +88,7 @@ if(buckle_lying != -1) REMOVE_TRAIT(buckled_mob, TRAIT_FLOORED, BUCKLE_TRAIT) buckled_mob.clear_alert("buckled") + buckled_mob.set_glide_size(DELAY_TO_GLIDE_SIZE(buckled_mob.cached_multiplicative_slowdown)) LAZYREMOVE(buckled_mobs, buckled_mob) UnregisterSignal(buckled_mob, COMSIG_LIVING_DO_RESIST) diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm index b5af9a359fd..4fe964eb2a0 100644 --- a/code/game/objects/effects/decals/Cleanable/aliens.dm +++ b/code/game/objects/effects/decals/Cleanable/aliens.dm @@ -16,9 +16,6 @@ basecolor = "#dffc00" amount = 0 -/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon() - color = "#FFFFFF" - /obj/effect/decal/cleanable/blood/gibs/xeno/up random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1") diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index e9a20b87673..1c038448f44 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -46,9 +46,8 @@ deltimer(drying_timer) return ..() - -/obj/effect/decal/cleanable/blood/update_icon() - if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" +/obj/effect/decal/cleanable/blood/update_icon_state() + . = ..() color = basecolor /obj/effect/decal/cleanable/blood/proc/on_cross(datum/source, mob/living/carbon/human/perp, oldloc, oldlocs) @@ -171,20 +170,22 @@ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6") var/fleshcolor = "#FFC896" -/obj/effect/decal/cleanable/blood/gibs/update_icon() - - var/image/giblets = new(base_icon, "[icon_state]_flesh", dir) - if(!fleshcolor || fleshcolor == "rainbow") +/obj/effect/decal/cleanable/blood/gibs/update_icon_state() + . = ..() + if(!fleshcolor) fleshcolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" - giblets.color = fleshcolor - var/icon/blood = new(base_icon,"[icon_state]",dir) - if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" - blood.Blend(basecolor,ICON_MULTIPLY) + if(basecolor == "rainbow") + basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" + blood.Blend(basecolor, ICON_MULTIPLY) icon = blood - overlays.Cut() - overlays += giblets + +/obj/effect/decal/cleanable/blood/gibs/update_overlays() + . = ..() + var/image/giblets = new(base_icon, "[icon_state]_flesh", dir) + giblets.color = fleshcolor + . += giblets /obj/effect/decal/cleanable/blood/gibs/up random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1") diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm index d2a1b539f78..1f8fa7aafd1 100644 --- a/code/game/objects/effects/decals/Cleanable/robots.dm +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -6,9 +6,6 @@ basecolor="#030303" random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") -/obj/effect/decal/cleanable/blood/gibs/robot/update_icon() - color = "#FFFFFF" - /obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like return diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm index 624fbcf6a50..5f71d971b94 100644 --- a/code/game/objects/effects/decals/Cleanable/tracks.dm +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -116,9 +116,8 @@ if(updated) update_icon() -/obj/effect/decal/cleanable/blood/tracks/update_icon() - overlays.Cut() - color = "#FFFFFF" +/obj/effect/decal/cleanable/blood/tracks/update_overlays() + . = ..() var/truedir=0 // Update ONLY the overlays that have changed. @@ -131,14 +130,14 @@ truedir=truedir>>4 if(track.overlay) - track.overlay=null + track.overlay=null //todo, not handling track overlays properly. fuck this shitcode. var/image/I = image(icon, icon_state=state, dir=num2dir(truedir)) I.color = track.basecolor track.fresh=0 track.overlay=I stack[stack_idx]=track - overlays += I + . += I updatedtracks=0 // Clear our memory of updated tracks. /obj/effect/decal/cleanable/blood/tracks/footprints diff --git a/code/game/objects/effects/effect_system/particle_effects.dm b/code/game/objects/effects/effect_system/particle_effects.dm index e05140985ec..29e31351e5c 100644 --- a/code/game/objects/effects/effect_system/particle_effects.dm +++ b/code/game/objects/effects/effect_system/particle_effects.dm @@ -58,7 +58,7 @@ var/life = 15 mouse_opacity = MOUSE_OPACITY_TRANSPARENT -/obj/effect/particle_effect/water/Move(turf/newloc) +/obj/effect/particle_effect/water/Move(atom/newloc, direction, glide_size_override) if (--life < 1) qdel(src) if(newloc.density) diff --git a/code/game/objects/effects/landmarks/marine_spawns.dm b/code/game/objects/effects/landmarks/marine_spawns.dm index 835203c1e87..f41fd3650e9 100644 --- a/code/game/objects/effects/landmarks/marine_spawns.dm +++ b/code/game/objects/effects/landmarks/marine_spawns.dm @@ -34,6 +34,10 @@ icon_state = "PO" job = /datum/job/terragov/command/pilot +/obj/effect/landmark/start/job/transportofficer + icon_state = "TO" + job = /datum/job/terragov/command/transportofficer + /obj/effect/landmark/start/job/chiefshipengineer icon_state = "CSE" job = /datum/job/terragov/engineering/chief @@ -46,6 +50,14 @@ icon_state = "MP" job = /datum/job/terragov/command/mech_pilot +/obj/effect/landmark/start/job/assault_crewman + icon_state = "AC" + job = /datum/job/terragov/command/assault_crewman + +/obj/effect/landmark/start/job/transport_crewman + icon_state = "TC" + job = /datum/job/terragov/command/transport_crewman + /obj/effect/landmark/start/job/shiptech icon_state = "SE" job = /datum/job/terragov/engineering/tech diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index fde38d34fce..e5d264c5ba6 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -386,3 +386,12 @@ icon_state = "spooky" pixel_x = 16 pixel_y = 16 + +/obj/effect/overlay/vis + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + anchored = TRUE + vis_flags = VIS_INHERIT_DIR + /// When detected to be unused it gets set to world.time, after a while it gets removed + var/unused = 0 + /// Overlays which go unused for 2 minutes get cleaned up + var/cache_expiration = 2 MINUTES diff --git a/code/game/objects/effects/weeds.dm b/code/game/objects/effects/weeds.dm index 8f8bc4e368b..cedb86c3f13 100644 --- a/code/game/objects/effects/weeds.dm +++ b/code/game/objects/effects/weeds.dm @@ -186,6 +186,7 @@ icon_state = "weedwall" /obj/alien/weeds/weedwall/update_icon_state() + . = ..() var/turf/closed/wall/W = loc if(!istype(W)) icon_state = initial(icon_state) @@ -204,6 +205,7 @@ var/window_type = /obj/structure/window/framed /obj/alien/weeds/weedwall/window/update_icon_state() + . = ..() var/obj/structure/window/framed/F = locate() in loc icon_state = F?.smoothing_junction ? "weedwall-[F.smoothing_junction]" : initial(icon_state) if(color_variant == STICKY_COLOR) diff --git a/code/game/objects/items/ashtray.dm b/code/game/objects/items/ashtray.dm index 1304a5f2dd2..cfbe8f24f16 100644 --- a/code/game/objects/items/ashtray.dm +++ b/code/game/objects/items/ashtray.dm @@ -43,22 +43,29 @@ AM.forceMove(loc) return ..() - -/obj/item/ashtray/update_icon() +/obj/item/ashtray/update_desc(updates) + . = ..() if(length(contents) >= max_butts) - icon_state = icon_full desc = empty_desc + " It's stuffed full." return if(length(contents) >= max_butts / 2) - icon_state = icon_half desc = empty_desc + " It's half-filled." return - icon_state = icon_empty desc = empty_desc +/obj/item/ashtray/update_icon_state() + . = ..() + if(length(contents) >= max_butts) + icon_state = icon_full + return + + if(length(contents) >= max_butts / 2) + icon_state = icon_half + return + icon_state = icon_empty /obj/item/ashtray/plastic name = "plastic ashtray" diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index c00dd31701e..1914d371a07 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -63,6 +63,8 @@ var/obj/item/bodybag/foldedbag_instance = null var/obj/structure/bed/roller/roller_buckled //the roller bed this bodybag is attached to. var/mob/living/bodybag_occupant + ///Should the name of the person inside be displayed? + var/display_name = TRUE /obj/structure/closet/bodybag/Initialize(mapload, foldedbag) . = ..() @@ -86,7 +88,11 @@ return roller_buckled return ..() -/obj/structure/closet/bodybag/proc/update_name() + +/obj/structure/closet/bodybag/update_name(updates) + . = ..() + if(!display_name) + return if(opened) name = bag_name else @@ -134,7 +140,7 @@ var/mob/living/carbon/human/new_guest = locate() in contents if(new_guest) bodybag_occupant = new_guest - update_name() + update_appearance() return TRUE return FALSE @@ -142,7 +148,7 @@ . = ..() if(bodybag_occupant) bodybag_occupant = null - update_name() + update_appearance() /obj/structure/closet/bodybag/MouseDrop(over_object, src_location, over_location) . = ..() @@ -158,10 +164,11 @@ usr.put_in_hands(foldedbag_instance) moveToNullspace() -/obj/structure/closet/bodybag/Move(NewLoc, direct) - if (roller_buckled && roller_buckled.loc != NewLoc) //not updating position + +/obj/structure/closet/bodybag/Move(atom/newloc, direction, glide_size_override) + if (roller_buckled && roller_buckled.loc != newloc) //not updating position if (!roller_buckled.anchored) - return roller_buckled.Move(NewLoc, direct) + return roller_buckled.Move(newloc, direction, glide_size) else return FALSE else @@ -172,7 +179,8 @@ roller_buckled.unbuckle_bodybag() return ..() -/obj/structure/closet/bodybag/update_icon() +/obj/structure/closet/bodybag/update_icon_state() + . = ..() if(!opened) icon_state = icon_closed for(var/mob/living/L in contents) @@ -385,6 +393,7 @@ close_sound = 'sound/effects/vegetation_walk_2.ogg' foldedbag_path = /obj/item/bodybag/tarp closet_stun_delay = 0.5 SECONDS //Short delay to prevent ambushes from being too degenerate. + display_name = FALSE var/serial_number //Randomized serial number used to stop point macros and such. /obj/structure/closet/bodybag/tarp/close() @@ -418,9 +427,6 @@ SIGNAL_HANDLER open() -/obj/structure/closet/bodybag/tarp/update_name() - return //Shouldn't be revealing who's inside. - /obj/structure/closet/bodybag/tarp/MouseDrop(over_object, src_location, over_location) . = ..() var/obj/item/bodybag/tarp/folded_tarp = foldedbag_instance diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index b20ca89c1d6..fa976e66826 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -261,6 +261,7 @@ var/dogtag_taken = FALSE /obj/item/card/id/dogtag/update_icon_state() + . = ..() if(dogtag_taken) icon_state = initial(icon_state) + "_taken" return diff --git a/code/game/objects/items/cocoon.dm b/code/game/objects/items/cocoon.dm index 46dfd2b7b3b..22d0030e892 100644 --- a/code/game/objects/items/cocoon.dm +++ b/code/game/objects/items/cocoon.dm @@ -115,6 +115,7 @@ return ..() /obj/structure/cocoon/update_icon_state() + . = ..() if(anchored) icon_state = "xeno_cocoon" return diff --git a/code/game/objects/items/defibrillator.dm b/code/game/objects/items/defibrillator.dm index 799522fdbe4..387ad2e37c8 100644 --- a/code/game/objects/items/defibrillator.dm +++ b/code/game/objects/items/defibrillator.dm @@ -44,6 +44,7 @@ /obj/item/defibrillator/update_icon_state() + . = ..() icon_state = "defib" if(ready) icon_state += "_out" @@ -372,4 +373,4 @@ defibrillate(target, user) /obj/item/defibrillator/gloves/update_icon_state() - return + return //The parent has some behaviour we don't want diff --git a/code/game/objects/items/devices/tablets.dm b/code/game/objects/items/devices/tablets.dm index 53140f52d59..cb0cb9295e9 100644 --- a/code/game/objects/items/devices/tablets.dm +++ b/code/game/objects/items/devices/tablets.dm @@ -61,8 +61,12 @@ req_access = list(ACCESS_MARINE_BRIDGE, ACCESS_MARINE_LEADER) if(/datum/job/terragov/command/pilot) dat += " pilot's" - network = list("dropship1", "dropship2") + network = list("dropship1") req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_DROPSHIP) + if(/datum/job/terragov/command/transportofficer) + dat += " transport officer's" + network = list("dropship2") + req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE) name = dat + " hud tablet" // Convert networks to lowercase for(var/i in network) @@ -252,10 +256,15 @@ /obj/item/hud_tablet/pilot name = "pilot officers's hud tablet" - network = list("dropship1", "dropship2") + network = list("dropship1") req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_DROPSHIP) max_view_dist = WORLD_VIEW_NUM +/obj/item/hud_tablet/transportofficer + name = "transport officer's hud tablet" + network = list("dropship2") + req_access = list(ACCESS_MARINE_PILOT, ACCESS_MARINE_TADPOLE) + max_view_dist = WORLD_VIEW_NUM /obj/item/hud_tablet/artillery name = "artillery impact hud tablet" diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm index 36a4b860316..7f7cf370755 100644 --- a/code/game/objects/items/explosives/mine.dm +++ b/code/game/objects/items/explosives/mine.dm @@ -44,7 +44,8 @@ Stepping directly on the mine will also blow it up return ..() /// Update the icon, adding "_armed" if appropriate to the icon_state. -/obj/item/explosive/mine/update_icon() +/obj/item/explosive/mine/update_icon_state() + . = ..() icon_state = "[initial(icon_state)][armed ? "_armed" : ""]" /// On explosion mines trigger their own explosion, assuming there were not deleted straight away (larger explosions or probability) diff --git a/code/game/objects/items/explosives/plastique.dm b/code/game/objects/items/explosives/plastique.dm index c4ff43adbc8..058841c1c2e 100644 --- a/code/game/objects/items/explosives/plastique.dm +++ b/code/game/objects/items/explosives/plastique.dm @@ -27,6 +27,7 @@ return ..() /obj/item/explosive/plastique/update_icon_state() + . = ..() icon_state = "[initial(icon_state)][plant_target ? "_set" : ""]" if(armed) icon_state = "[icon_state][alarm_sounded ? "_armed" : "_on"]" diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 98185408be9..ff6464e1bda 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -110,7 +110,7 @@ user.put_in_hands(W) to_chat(user, span_notice("You wrap the cable restraint around the top of the rod.")) qdel(src) - update_icon(user) + update_icon() /obj/item/restraints/handcuffs/cyborg diff --git a/code/game/objects/items/implants/implantcase.dm b/code/game/objects/items/implants/implantcase.dm index 204d9a1b28b..bcb06fffdc1 100644 --- a/code/game/objects/items/implants/implantcase.dm +++ b/code/game/objects/items/implants/implantcase.dm @@ -25,6 +25,7 @@ return ..() /obj/item/implantcase/update_icon_state() + . = ..() if(imp) icon_state = "implantcase-[imp.implant_color]" else diff --git a/code/game/objects/items/motion_detector.dm b/code/game/objects/items/motion_detector.dm index f53c32863f4..dac330864b0 100644 --- a/code/game/objects/items/motion_detector.dm +++ b/code/game/objects/items/motion_detector.dm @@ -24,6 +24,7 @@ qdel(src) /obj/effect/blip/edge_blip/update_icon_state() + . = ..() icon_state = "edge_blip_[identifier]" /obj/effect/blip/close_blip @@ -99,6 +100,7 @@ action.update_button_icon() /obj/item/attachable/motiondetector/update_icon_state() + . = ..() icon_state = initial(icon_state) + (isnull(operator) ? "" : "_on") /obj/item/attachable/motiondetector/equipped(mob/user, slot) diff --git a/code/game/objects/items/pamphlets.dm b/code/game/objects/items/pamphlets.dm new file mode 100644 index 00000000000..fde4f41ea1a --- /dev/null +++ b/code/game/objects/items/pamphlets.dm @@ -0,0 +1,40 @@ +//skill modifying item +/obj/item/pamphlet + name = "generic phamplet" + desc = "you shouldnt see this" + icon = 'icons/obj/items/paper.dmi' + icon_state = "paper_words" + var/cqc + var/melee_weapons + var/firearms + var/pistols + var/shotguns + var/rifles + var/smgs + var/heavy_weapons + var/smartgun + var/engineer + var/construction + var/leadership + var/medical + var/surgery + var/pilot + var/police + var/powerloader + var/large_vehicle + var/stamina + +/obj/item/pamphlet/attack_self(mob/living/user) + . = ..() + if(!do_after(user, 5 SECONDS, NONE, user)) + return + user.set_skills(user.skills.modifyRating(cqc, melee_weapons, firearms, pistols, shotguns, rifles, smgs, heavy_weapons, smartgun, \ + engineer, construction, leadership, medical, surgery, pilot, police, powerloader, large_vehicle, stamina)) + user.temporarilyRemoveItemFromInventory(src) + qdel(src) + +/obj/item/pamphlet/tank_loader + name = "loader's instruction manual" + desc = "A crude drawing depicting what you think is loading a tank gun. Is that crayon?" + large_vehicle = 1 + diff --git a/code/game/objects/items/plantable_flags.dm b/code/game/objects/items/plantable_flags.dm index 4f172ae09b9..4a9d4bdbbff 100644 --- a/code/game/objects/items/plantable_flags.dm +++ b/code/game/objects/items/plantable_flags.dm @@ -25,7 +25,7 @@ playsound(loc, 'sound/effects/thud.ogg', 100) user.dropItemToGround(src) is_collapsed = FALSE - update_icon_state() + update_appearance() /obj/item/flag_base/attack_hand(mob/living/user) @@ -34,8 +34,8 @@ to_chat(user, "You decide against removing the flag here.") return is_collapsed = TRUE - update_icon_state() - . = ..() + update_appearance() + return ..() /obj/item/flag_base/update_icon_state() diff --git a/code/game/objects/items/portable_vendor.dm b/code/game/objects/items/portable_vendor.dm index bc4ea5ce610..85f33c40db3 100644 --- a/code/game/objects/items/portable_vendor.dm +++ b/code/game/objects/items/portable_vendor.dm @@ -132,7 +132,7 @@ playsound(src, "sound/machines/fax.ogg", 5) balloon_alert(user, "fabricating") fabricating = TRUE - update_overlays() + update_appearance() addtimer(CALLBACK(src, PROC_REF(do_vend), L[3], user), 1 SECONDS) /obj/item/portable_vendor/proc/do_vend(thing, mob/user) @@ -140,7 +140,7 @@ if(loc == user) user.put_in_hands(IT) fabricating = FALSE - update_overlays() + update_appearance() /obj/item/portable_vendor/update_overlays() . = ..() @@ -161,7 +161,7 @@ /obj/item/portable_vendor/Initialize(mapload) . = ..() START_PROCESSING(SSobj, src) - update_overlays() + update_appearance() /obj/item/portable_vendor/Destroy() STOP_PROCESSING(SSobj, src) @@ -173,7 +173,7 @@ T.visible_message(span_warning("[src] shudders as its internal components break apart!")) broken = 1 STOP_PROCESSING(SSobj, src) - update_overlays() + update_appearance() playsound(src, 'sound/effects/sparks4.ogg', 60, 1) var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread diff --git a/code/game/objects/items/radio/detpack.dm b/code/game/objects/items/radio/detpack.dm index 3c89c0ba1f7..1244691bf39 100644 --- a/code/game/objects/items/radio/detpack.dm +++ b/code/game/objects/items/radio/detpack.dm @@ -70,6 +70,7 @@ /obj/item/detpack/update_icon_state() + . = ..() icon_state = "detpack_[plant_target ? "set_" : ""]" if(on) icon_state = "[icon_state][armed ? "armed" : "on"]" diff --git a/code/game/objects/items/radio/intercom.dm b/code/game/objects/items/radio/intercom.dm index 9f57c4770f6..e10be7f7d34 100644 --- a/code/game/objects/items/radio/intercom.dm +++ b/code/game/objects/items/radio/intercom.dm @@ -28,15 +28,15 @@ pixel_x = 32 START_PROCESSING(SSobj, src) become_hearing_sensitive() - update_icon() + check_light() /obj/item/radio/intercom/Destroy() STOP_PROCESSING(SSobj, src) return ..() -/obj/item/radio/intercom/update_icon() - . = ..() +///Checks if we're on, if so a light turns on +/obj/item/radio/intercom/proc/check_light() if(!on) set_light(0) return @@ -44,6 +44,7 @@ set_light(initial(light_range)) /obj/item/radio/intercom/update_icon_state() + . = ..() if(!on) icon_state = "intercom_unpowered" else @@ -56,16 +57,14 @@ . += emissive_appearance(icon, "[icon_state]_emissive") /obj/item/radio/intercom/attack_ai(mob/user as mob) - spawn (0) - attack_self(user) + attack_self(user) /obj/item/radio/intercom/attack_hand(mob/living/user) . = ..() if(.) return - spawn (0) - attack_self(user) + attack_self(user) /obj/item/radio/intercom/can_receive(freq, list/levels) @@ -100,7 +99,7 @@ return else on = new_state - update_icon() + check_light() /obj/item/radio/intercom/general name = "General Listening Channel" diff --git a/code/game/objects/items/reagent_containers/autoinjectors.dm b/code/game/objects/items/reagent_containers/autoinjectors.dm index 8b7652dd415..4609378dd63 100644 --- a/code/game/objects/items/reagent_containers/autoinjectors.dm +++ b/code/game/objects/items/reagent_containers/autoinjectors.dm @@ -11,6 +11,7 @@ list_reagents = list(/datum/reagent/consumable/sodiumchloride = 30) /obj/item/reagent_containers/hypospray/autoinjector/update_icon_state() + . = ..() if(!(reagents.total_volume) && is_drawable()) icon_state += "X" name = "expended [name]" //So people can see what have been expended since we have smexy new sprites people aren't used too... diff --git a/code/game/objects/items/reagent_containers/blood_pack.dm b/code/game/objects/items/reagent_containers/blood_pack.dm index 760e4b61a80..05909c8ccb6 100644 --- a/code/game/objects/items/reagent_containers/blood_pack.dm +++ b/code/game/objects/items/reagent_containers/blood_pack.dm @@ -20,7 +20,7 @@ update_icon() /obj/item/reagent_containers/blood/update_icon_state() - + . = ..() var/percent = PERCENT(reagents.total_volume / volume) switch(percent) if(0 to 9.9) diff --git a/code/game/objects/items/reagent_containers/food/pizzapasta.dm b/code/game/objects/items/reagent_containers/food/pizzapasta.dm index 0b6c83ce486..4e8922b4687 100644 --- a/code/game/objects/items/reagent_containers/food/pizzapasta.dm +++ b/code/game/objects/items/reagent_containers/food/pizzapasta.dm @@ -171,56 +171,55 @@ var/list/boxes = list() // If the boxes are stacked, they come here var/boxtag = "" -/obj/item/pizzabox/update_icon() - - overlays = list() - - // Set appropriate description - if( open && pizza ) +/obj/item/pizzabox/update_desc(updates) + . = ..() + if(open && pizza) desc = "A box suited for pizzas. It appears to have a [pizza.name] inside." - else if( boxes.len > 0 ) + else if(boxes.len > 0) desc = "A pile of boxes suited for pizzas. There appears to be [boxes.len + 1] boxes in the pile." var/obj/item/pizzabox/topbox = boxes[boxes.len] var/toptag = topbox.boxtag - if( toptag != "" ) + if(toptag != "") desc = "[desc] The box on top has a tag, it reads: '[toptag]'." else desc = "A box suited for pizzas." - if( boxtag != "" ) + if(boxtag != "") desc = "[desc] The box has a tag, it reads: '[boxtag]'." - // Icon states and overlays - if( open ) - if( ismessy ) +/obj/item/pizzabox/update_icon_state() + . = ..() + if(open) + if(ismessy) icon_state = "pizzabox_messy" else icon_state = "pizzabox_open" + return - if( pizza ) - var/image/pizzaimg = image("pizzaspaghetti.dmi", icon_state = pizza.icon_state) - pizzaimg.pixel_y = -3 - overlays += pizzaimg + icon_state = "pizzabox[boxes.len+1]" +/obj/item/pizzabox/update_overlays() + . = ..() + if(open && pizza) + var/image/pizzaimg = image("pizzaspaghetti.dmi", icon_state = pizza.icon_state) + pizzaimg.pixel_y = -3 + . += pizzaimg return + // Stupid code because byondcode sucks - imagine blaming the engine for you being bad at coding. TODO: clean this up + var/doimgtag = 0 + if(boxes.len > 0) + var/obj/item/pizzabox/topbox = boxes[boxes.len] + if(topbox.boxtag != "") + doimgtag = 1 else - // Stupid code because byondcode sucks - var/doimgtag = 0 - if( boxes.len > 0 ) - var/obj/item/pizzabox/topbox = boxes[boxes.len] - if( topbox.boxtag != "" ) - doimgtag = 1 - else - if( boxtag != "" ) - doimgtag = 1 - - if( doimgtag ) - var/image/tagimg = image("pizzaspaghetti.dmi", icon_state = "pizzabox_tag") - tagimg.pixel_y = boxes.len * 3 - overlays += tagimg + if(boxtag != "") + doimgtag = 1 - icon_state = "pizzabox[boxes.len+1]" + if(doimgtag) + var/image/tagimg = image("pizzaspaghetti.dmi", icon_state = "pizzabox_tag") + tagimg.pixel_y = boxes.len * 3 + . += tagimg //ATTACK HAND IGNORING PARENT RETURN VALUE /obj/item/pizzabox/attack_hand(mob/living/user) diff --git a/code/game/objects/items/reagent_containers/glass.dm b/code/game/objects/items/reagent_containers/glass.dm index d3eca61d7cb..528b8232d5a 100644 --- a/code/game/objects/items/reagent_containers/glass.dm +++ b/code/game/objects/items/reagent_containers/glass.dm @@ -151,28 +151,35 @@ return update_icon() -/obj/item/reagent_containers/glass/beaker/update_icon() - overlays.Cut() +/obj/item/reagent_containers/glass/beaker/update_overlays() + . = ..() if(reagents.total_volume) var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") var/percent = round((reagents.total_volume / volume) * 100) switch(percent) - if(0 to 9) filling.icon_state = "[icon_state]-10" - if(10 to 24) filling.icon_state = "[icon_state]10" - if(25 to 49) filling.icon_state = "[icon_state]25" - if(50 to 74) filling.icon_state = "[icon_state]50" - if(75 to 79) filling.icon_state = "[icon_state]75" - if(80 to 90) filling.icon_state = "[icon_state]80" - if(91 to INFINITY) filling.icon_state = "[icon_state]100" + if(0 to 9) + filling.icon_state = "[icon_state]-10" + if(10 to 24) + filling.icon_state = "[icon_state]10" + if(25 to 49) + filling.icon_state = "[icon_state]25" + if(50 to 74) + filling.icon_state = "[icon_state]50" + if(75 to 79) + filling.icon_state = "[icon_state]75" + if(80 to 90) + filling.icon_state = "[icon_state]80" + if(91 to INFINITY) + filling.icon_state = "[icon_state]100" filling.color = mix_color_from_reagents(reagents.reagent_list) - overlays += filling + . += filling if(!is_open_container()) var/image/lid = image(icon, src, "lid_[initial(icon_state)]") - overlays += lid + . += lid /obj/item/reagent_containers/glass/beaker/large name = "large beaker" @@ -260,12 +267,12 @@ to_chat(user, span_notice("You wet [I] in [src].")) playsound(loc, 'sound/effects/slosh.ogg', 25, 1) -/obj/item/reagent_containers/glass/bucket/update_icon() - overlays.Cut() +/obj/item/reagent_containers/glass/bucket/update_overlays() + . = ..() if(!is_open_container()) var/image/lid = image(icon, src, "lid_[initial(icon_state)]") - overlays += lid + . += lid /obj/item/reagent_containers/glass/bucket/janibucket name = "janitorial bucket" @@ -276,14 +283,17 @@ update_icon() -/obj/item/reagent_containers/glass/bucket/janibucket/update_icon() - ..() +/obj/item/reagent_containers/glass/bucket/janibucket/update_icon_state() + . = ..() if(reagents.total_volume) var/percent = round((reagents.total_volume / volume) * 100) switch(percent) - if(0 to 9) icon_state = "janibucket" - if(10 to 65) icon_state = "janibucket_half" - if(66 to INFINITY) icon_state = "janibucket_full" + if(0 to 9) + icon_state = "janibucket" + if(10 to 65) + icon_state = "janibucket_half" + if(66 to INFINITY) + icon_state = "janibucket_full" else icon_state = "janibucket" diff --git a/code/game/objects/items/reagent_containers/glass/bottle.dm b/code/game/objects/items/reagent_containers/glass/bottle.dm index 6c4f380e379..53fa1b3444f 100644 --- a/code/game/objects/items/reagent_containers/glass/bottle.dm +++ b/code/game/objects/items/reagent_containers/glass/bottle.dm @@ -34,8 +34,8 @@ if(!icon_state) icon_state = "bottle-[rand(1, 5)]" -/obj/item/reagent_containers/glass/bottle/update_icon() - overlays.Cut() +/obj/item/reagent_containers/glass/bottle/update_overlays() + . = ..() if(reagents?.total_volume && (icon_state == "bottle-1" || icon_state == "bottle-2" || icon_state == "bottle-3" || icon_state == "bottle-4")) //only for those who have reagentfillings icons var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") @@ -58,11 +58,11 @@ filling.icon_state = "[icon_state]-100" filling.color = mix_color_from_reagents(reagents.reagent_list) - overlays += filling + . += filling if(!is_open_container()) var/image/lid = image(icon, src, "lid_bottle") - overlays += lid + . += lid /obj/item/reagent_containers/glass/bottle/empty //Because the parent has RNG icon_state icon_state = "bottle-1" //Same one when you make a bottle in the chem master diff --git a/code/game/objects/items/reagent_containers/hypospray.dm b/code/game/objects/items/reagent_containers/hypospray.dm index 185321e1928..7690ff02bf9 100644 --- a/code/game/objects/items/reagent_containers/hypospray.dm +++ b/code/game/objects/items/reagent_containers/hypospray.dm @@ -354,11 +354,31 @@ if(href_list["displayreagents"]) to_chat(usr, display_reagents()) +/obj/item/reagent_containers/hypospray/advanced/update_icon_state() + . = ..() + if(!reagents?.total_volume) + icon_state = "[initial(icon_state)]_0" + return + var/percent = round((reagents.total_volume / volume) * 100) + switch(percent) + if(0 to 9) + icon_state = initial(icon_state) + if(10 to 24) + icon_state = "[initial(icon_state)]_10" + if(25 to 49) + icon_state = "[initial(icon_state)]_25" + if(50 to 64) + icon_state = "[initial(icon_state)]_50" + if(65 to 79) + icon_state = "[initial(icon_state)]_65" + if(80 to 90) + icon_state = "[initial(icon_state)]_80" + if(91 to INFINITY) + icon_state = "[initial(icon_state)]_100" /obj/item/reagent_containers/hypospray/advanced/update_overlays() . = ..() - overlays.Cut() if(reagents.total_volume) var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") @@ -368,37 +388,28 @@ filling.icon_state = "[initial(icon_state)]-10" if(10 to 24) filling.icon_state = "[initial(icon_state)]10" - icon_state = "[initial(icon_state)]_10" if(25 to 49) filling.icon_state = "[initial(icon_state)]25" - icon_state = "[initial(icon_state)]_25" if(50 to 64) filling.icon_state = "[initial(icon_state)]50" - icon_state = "[initial(icon_state)]_50" if(65 to 79) filling.icon_state = "[initial(icon_state)]65" - icon_state = "[initial(icon_state)]_65" if(80 to 90) filling.icon_state = "[initial(icon_state)]80" - icon_state = "[initial(icon_state)]_80" if(91 to INFINITY) filling.icon_state = "[initial(icon_state)]100" - icon_state = "[initial(icon_state)]_100" filling.color = mix_color_from_reagents(reagents.reagent_list) - overlays += filling - - else - icon_state = "[initial(icon_state)]_0" + . += filling if(ismob(loc)) var/injoverlay switch(inject_mode) - if (HYPOSPRAY_INJECT_MODE_DRAW) + if(HYPOSPRAY_INJECT_MODE_DRAW) injoverlay = "draw" - if (HYPOSPRAY_INJECT_MODE_INJECT) + if(HYPOSPRAY_INJECT_MODE_INJECT) injoverlay = "inject" - add_overlay(injoverlay) + . += injoverlay /obj/item/reagent_containers/hypospray/advanced/examine(mob/user as mob) . = ..() diff --git a/code/game/objects/items/reagent_containers/syringes.dm b/code/game/objects/items/reagent_containers/syringes.dm index bdbf7038c12..f7f9a602a0e 100644 --- a/code/game/objects/items/reagent_containers/syringes.dm +++ b/code/game/objects/items/reagent_containers/syringes.dm @@ -185,32 +185,37 @@ update_icon() -/obj/item/reagent_containers/syringe/update_icon() +/obj/item/reagent_containers/syringe/update_icon_state() + . = ..() if(mode == SYRINGE_BROKEN) icon_state = "broken" - overlays.Cut() return + var/rounded_vol = round(reagents.total_volume,5) - overlays.Cut() + icon_state = "[rounded_vol]" + item_state = "syringe_[rounded_vol]" + +/obj/item/reagent_containers/syringe/update_overlays() + . = ..() + if(mode == SYRINGE_BROKEN) + return if(ismob(loc)) var/injoverlay switch(mode) - if (SYRINGE_DRAW) + if(SYRINGE_DRAW) injoverlay = "draw" - if (SYRINGE_INJECT) + if(SYRINGE_INJECT) injoverlay = "inject" - overlays += injoverlay - icon_state = "[rounded_vol]" - item_state = "syringe_[rounded_vol]" + . += injoverlay + var/rounded_vol = round(reagents.total_volume,5) if(reagents.total_volume) var/image/filling = image('icons/obj/reagentfillings.dmi', src, "syringe10") filling.icon_state = "syringe[rounded_vol]" filling.color = mix_color_from_reagents(reagents.reagent_list) - overlays += filling - + . += filling /obj/item/reagent_containers/syringe/proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 9e6e5c78c0f..c155eda8b8c 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -187,24 +187,6 @@ skill_level_needed = SKILL_MEDICAL_PRACTICED unskilled_delay = SKILL_TASK_EASY -/* //RUTGMC edit - turning off unused proc -/obj/item/stack/medical/heal_pack/advanced/update_icon_state() - if(max_amount < 1 || amount > max_amount) - return - var/percentage = round(amount / max_amount) * 100 - switch(percentage) - if(1 to 20) - setDir(SOUTH) - if(21 to 40) - setDir(EAST) - if(41 to 60) - setDir(SOUTHEAST) - if(61 to 80) - setDir(WEST) - if(81 to INFINITY) - setDir(NORTH) -*/ - /obj/item/stack/medical/heal_pack/advanced/bruise_pack name = "advanced trauma kit" singular_name = "advanced trauma kit" diff --git a/code/game/objects/items/stacks/snow.dm b/code/game/objects/items/stacks/snow.dm index 91c1af488d7..bf7f196cf67 100644 --- a/code/game/objects/items/stacks/snow.dm +++ b/code/game/objects/items/stacks/snow.dm @@ -61,7 +61,8 @@ return var/turf/open/T = target if(T.get_dirt_type() == DIRT_TYPE_SNOW) - if(T.slayer >= 3) + var/turf/open/floor/plating/ground/snow/snowy_turf = T + if(snowy_turf.slayer >= 3) to_chat(user, "This ground is already full of snow.") return if(amount < 5) @@ -70,11 +71,12 @@ to_chat(user, "You start putting some snow back on the ground.") if(!do_after(user, 15, IGNORE_HELD_ITEM, target, BUSY_ICON_BUILD)) return - if(T.slayer >= 3) + if(snowy_turf.slayer >= 3) return to_chat(user, "You put a new snow layer on the ground.") - T.slayer += 1 - T.update_icon(TRUE, FALSE) + snowy_turf.slayer += 1 + snowy_turf.update_appearance() + snowy_turf.update_sides() use(5) /obj/item/stack/snow/attack_self(mob/user) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index a6363a127de..7c910d61276 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -56,6 +56,7 @@ /obj/item/stack/update_icon_state() + . = ..() if(!number_of_extra_variants) return var/ratio = round((amount * (number_of_extra_variants + 1)) / max_amount) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index adc439a8123..51516c68f6d 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -348,6 +348,7 @@ . += span_warning("Its defibrillator recharge unit does not have a power cell installed!") /obj/item/storage/backpack/marine/corpsman/update_icon_state() + . = ..() icon_state = icon_skin if(cell?.charge >= 0) switch(PERCENT(cell.charge/cell.maxcharge)) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 70b204e0bcb..cd893a2c778 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -39,6 +39,7 @@ cant_hold = list(/obj/item/disk/nuclear) /obj/item/storage/bag/trash/update_icon_state() + . = ..() if(length(contents) == 0) icon_state = "trashbag0" else if(length(contents) < 12) diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index bdac456b9a3..4afa1202940 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -866,10 +866,10 @@ /obj/item/storage/belt/shotgun/martini name = "martini henry ammo belt" desc = "A belt good enough for holding all your .577/400 ball rounds." - icon_state = ".557_belt" + icon_state = "martini_belt" storage_slots = 12 max_storage_space = 24 - + sprite_slots = 6 draw_mode = 1 flags_atom = DIRLOCK @@ -878,15 +878,6 @@ . = ..() update_icon() -/obj/item/storage/belt/shotgun/martini/update_icon() - if(!length(contents)) - icon_state = initial(icon_state) + "_e" - return - icon_state = initial(icon_state) - - var/holding = round((length(contents) + 1) / 2) - setDir(holding + round(holding/3)) - /obj/item/storage/belt/shotgun/martini/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/ammo_magazine)) var/obj/item/ammo_magazine/new_mag = I diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 1d5eec2983d..75fe6ff0e2b 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -349,6 +349,7 @@ spawn_number = 5 /obj/item/storage/box/explosive_mines/update_icon_state() + . = ..() icon_state = initial(icon_state) if(!length(contents)) icon_state += "_e" @@ -381,7 +382,8 @@ spawn_type = /obj/item/explosive/grenade/flare spawn_number = 14 -/obj/item/storage/box/m94/update_icon() +/obj/item/storage/box/m94/update_icon_state() + . = ..() icon_state = initial(icon_state) if(!length(contents)) icon_state += "_e" @@ -445,7 +447,8 @@ if(. && !length(contents) && !gc_destroyed) qdel(src) -/obj/item/storage/box/MRE/update_icon() +/obj/item/storage/box/MRE/update_icon_state() + . = ..() if(!isopened) isopened = 1 icon_state += "opened" diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index 02d96ac9f7e..ef030db3850 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -29,6 +29,7 @@ new spawn_type(src) /obj/item/storage/fancy/update_icon_state() + . = ..() icon_state = "[icon_type]box[length(contents)]" /obj/item/storage/fancy/remove_from_storage(obj/item/W, atom/new_location, mob/user) @@ -146,6 +147,7 @@ new /obj/item/clothing/mask/cigarette(src) /obj/item/storage/fancy/cigarettes/update_icon_state() + . = ..() icon_state = "[initial(icon_state)][length(contents)]" /obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) @@ -196,6 +198,7 @@ new /obj/item/tool/lighter(src) /obj/item/storage/fancy/chemrettes/update_icon_state() + . = ..() icon_state = "[initial(icon_state)][length(contents)]" /obj/item/storage/fancy/cigarettes/dromedaryco @@ -238,6 +241,7 @@ icon_type = "cigar" /obj/item/storage/fancy/cigar/update_icon_state() + . = ..() icon_state = "[initial(icon_state)][length(contents)]" @@ -287,8 +291,9 @@ . = ..() update_icon() -/obj/item/storage/lockbox/vials/update_icon(itemremoved = 0) - icon_state = "vialbox[length(contents)-itemremoved]" +/obj/item/storage/lockbox/vials/update_icon_state() + . = ..() + icon_state = "vialbox[length(contents)]" /obj/item/storage/lockbox/vials/update_overlays() . = ..() diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index 0afa7561e1c..761d6ae21e0 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -36,7 +36,8 @@ fill_firstaid_kit() -/obj/item/storage/firstaid/update_icon() +/obj/item/storage/firstaid/update_icon_state() + . = ..() if(!length(contents)) icon_state = icon_state += "_empty" else diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm index 4d04ba8ca2f..df438955980 100644 --- a/code/game/objects/items/storage/holsters.dm +++ b/code/game/objects/items/storage/holsters.dm @@ -70,6 +70,7 @@ return ..() /obj/item/storage/holster/update_icon_state() + . = ..() if(holstered_item) icon_state = initial(icon_state) + "_full" else diff --git a/code/game/objects/items/storage/internal.dm b/code/game/objects/items/storage/internal.dm index 2604e4522a8..15950a7b7fb 100644 --- a/code/game/objects/items/storage/internal.dm +++ b/code/game/objects/items/storage/internal.dm @@ -43,9 +43,6 @@ if(user.lying_angle || user.incapacitated()) //Can't use your inventory when lying return FALSE - if(istype(user.loc, /obj/vehicle/multitile/root/cm_armored)) //Stops inventory actions in a mech/tank - return FALSE - if(over_object == user && Adjacent(user)) //This must come before the screen objects only block open(user) return FALSE diff --git a/code/game/objects/items/storage/marine_boxes.dm b/code/game/objects/items/storage/marine_boxes.dm index 08ef5190e71..52ac0d190ed 100644 --- a/code/game/objects/items/storage/marine_boxes.dm +++ b/code/game/objects/items/storage/marine_boxes.dm @@ -6,6 +6,7 @@ foldable = /obj/item/stack/sheet/wood /obj/item/storage/box/crate/update_icon_state() + . = ..() icon_state = length(contents) ? initial(icon_state) : "empty_case" /obj/item/storage/box/crate/heavy_armor diff --git a/code/game/objects/items/storage/misc.dm b/code/game/objects/items/storage/misc.dm index 14dfdedafb7..be83920b3bc 100644 --- a/code/game/objects/items/storage/misc.dm +++ b/code/game/objects/items/storage/misc.dm @@ -36,18 +36,22 @@ if(!length(contents)) return ..() - -/obj/item/storage/donut_box/update_icon() - overlays.Cut() +/obj/item/storage/donut_box/update_icon_state() + . = ..() if(!open) icon_state = "donutbox" return icon_state = "donutbox_o" + +/obj/item/storage/donut_box/update_overlays() + . = ..() + if(!open) + return var/i = 0 for(var/obj/item/reagent_containers/food/snacks/donut/D in contents) i++ var/image/img = image('icons/obj/items/food/donuts.dmi', "[D.overlay_state]-[i]") - overlays += img + . += img /obj/item/storage/donut_box/empty icon_state = "donutbox_o" diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index fde59f2dd7f..2545ab767e9 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -86,9 +86,6 @@ if(usr.lying_angle) return - if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech/tank - return - if(over_object == usr && Adjacent(usr)) // this must come before the screen objects only block open(usr) return @@ -304,9 +301,6 @@ if(usr.incapacitated(TRUE)) return - if(istype(usr.loc, /obj/vehicle/multitile/root/cm_armored)) // stops inventory actions in a mech/tank - return - var/list/PL = params2list(params) if(!master) @@ -668,7 +662,7 @@ if(!allow_drawing_method) verbs -= /obj/item/storage/verb/toggle_draw_mode - boxes = new + boxes = new() boxes.name = "storage" boxes.master = src boxes.icon_state = "block" @@ -676,21 +670,21 @@ boxes.layer = HUD_LAYER boxes.plane = HUD_PLANE - storage_start = new /atom/movable/screen/storage( ) + storage_start = new /atom/movable/screen/storage() storage_start.name = "storage" storage_start.master = src storage_start.icon_state = "storage_start" storage_start.screen_loc = "7,7 to 10,8" storage_start.layer = HUD_LAYER storage_start.plane = HUD_PLANE - storage_continue = new /atom/movable/screen/storage( ) + storage_continue = new /atom/movable/screen/storage() storage_continue.name = "storage" storage_continue.master = src storage_continue.icon_state = "storage_continue" storage_continue.screen_loc = "7,7 to 10,8" storage_continue.layer = HUD_LAYER storage_continue.plane = HUD_PLANE - storage_end = new /atom/movable/screen/storage( ) + storage_end = new /atom/movable/screen/storage() storage_end.name = "storage" storage_end.master = src storage_end.icon_state = "storage_end" @@ -698,20 +692,20 @@ storage_end.layer = HUD_LAYER storage_end.plane = HUD_PLANE - stored_start = new /obj //we just need these to hold the icon + stored_start = new /obj() //we just need these to hold the icon stored_start.icon_state = "stored_start" stored_start.layer = HUD_LAYER stored_start.plane = HUD_PLANE - stored_continue = new /obj + stored_continue = new /obj() stored_continue.icon_state = "stored_continue" stored_continue.layer = HUD_LAYER stored_continue.plane = HUD_PLANE - stored_end = new /obj + stored_end = new /obj() stored_end.icon_state = "stored_end" stored_end.layer = HUD_LAYER stored_end.plane = HUD_PLANE - closer = new + closer = new() closer.master = src /obj/item/storage/Destroy() @@ -876,6 +870,7 @@ return /obj/item/storage/update_icon_state() + . = ..() if(!sprite_slots) icon_state = initial(icon_state) return diff --git a/code/game/objects/items/storage/surgical_tray.dm b/code/game/objects/items/storage/surgical_tray.dm index bed8f1703cf..99fc99fb6b7 100644 --- a/code/game/objects/items/storage/surgical_tray.dm +++ b/code/game/objects/items/storage/surgical_tray.dm @@ -27,6 +27,7 @@ new /obj/item/stack/nanopaste(src) /obj/item/storage/surgical_tray/update_icon_state() + . = ..() if(!length(contents)) icon_state = "surgical_tray_e" else diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index 2e6133e9764..45653a58fe6 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -46,8 +46,8 @@ name = "[name] ([front_id])" update_icon() -/obj/item/storage/wallet/update_icon() - +/obj/item/storage/wallet/update_icon_state() + . = ..() if(front_id) switch(front_id.icon_state) if("id") diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm index cfd33b2c409..150299f3fdf 100644 --- a/code/game/objects/items/tools/flame_tools.dm +++ b/code/game/objects/items/tools/flame_tools.dm @@ -34,14 +34,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/wax = 800 /obj/item/tool/candle/update_icon_state() - var/i - if(wax>150) - i = 1 - else if(wax>80) - i = 2 + . = ..() + if(wax > 150) + icon_state = "candle[1][heat ? "_lit" : ""]" + else if(wax > 80) + icon_state = "candle[2][heat ? "_lit" : ""]" else - i = 3 - icon_state = "candle[i][heat ? "_lit" : ""]" + icon_state = "candle[3][heat ? "_lit" : ""]" /obj/item/tool/candle/Destroy() if(heat) diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm index 7691c7f0d88..b39b743e678 100644 --- a/code/game/objects/items/tools/maintenance_tools.dm +++ b/code/game/objects/items/tools/maintenance_tools.dm @@ -471,7 +471,14 @@ /obj/item/tool/handheld_charger/Initialize(mapload) . = ..() - cell = null + update_icon() + +/obj/item/tool/handheld_charger/update_icon_state() + . = ..() + if(cell) + icon_state = initial(icon_state) + else + icon_state = initial(icon_state) + "_empty" /obj/item/tool/handheld_charger/attack_self(mob/user) if(!cell) @@ -528,7 +535,7 @@ cell = null playsound(user, 'sound/machines/click.ogg', 20, 1, 5) balloon_alert(user, "Removes the cell") - icon_state = "handheldcharger_black_empty" + update_appearance() /obj/item/tool/handheld_charger/attack_hand(mob/living/user) if(user.get_inactive_held_item() != src) @@ -540,7 +547,7 @@ cell = null playsound(user, 'sound/machines/click.ogg', 20, 1, 5) balloon_alert(user, "Removes the cell") - icon_state = "handheldcharger_black_empty" + update_appearance() /obj/item/tool/handheld_charger/Destroy() QDEL_NULL(cell) diff --git a/code/game/objects/items/tools/mining_tools.dm b/code/game/objects/items/tools/mining_tools.dm index 104f3f9a1d5..25a6f794dd5 100644 --- a/code/game/objects/items/tools/mining_tools.dm +++ b/code/game/objects/items/tools/mining_tools.dm @@ -288,7 +288,8 @@ if(!ST.slayer) return ST.slayer = max(0 , ST.slayer - dirt_amt_per_dig) - ST.update_icon(1,0) + ST.update_appearance() + ST.update_sides() cut_apart(user, target.name, target, 0, "You melt the snow with [src]. ") //costs nothing diff --git a/code/game/objects/items/tools/shovel_tools.dm b/code/game/objects/items/tools/shovel_tools.dm index 3b0c7490102..311e59b587c 100644 --- a/code/game/objects/items/tools/shovel_tools.dm +++ b/code/game/objects/items/tools/shovel_tools.dm @@ -85,7 +85,8 @@ if(!ST.slayer) return ST.slayer -= 1 - ST.update_icon(1,0) + ST.update_appearance() + ST.update_sides() balloon_alert(user, "Digs up snow") else balloon_alert(user, "Digs up dirt") @@ -156,7 +157,7 @@ else icon_state = "etool_c" item_state = "etool_c" - ..() + return ..() /obj/item/tool/shovel/etool/attack_self(mob/user as mob) if(sharp) diff --git a/code/game/objects/items/tools/surgery_tools.dm b/code/game/objects/items/tools/surgery_tools.dm index 3043f24f9dd..df5d9222b9c 100644 --- a/code/game/objects/items/tools/surgery_tools.dm +++ b/code/game/objects/items/tools/surgery_tools.dm @@ -215,6 +215,7 @@ var/loaded = TRUE /obj/item/tool/surgery/healing_gun/update_icon() + . = ..() if(loaded) icon_state = "healing_gun" else diff --git a/code/game/objects/items/toys/cards.dm b/code/game/objects/items/toys/cards.dm index b4aeeeb525c..7bfbba2f4d6 100644 --- a/code/game/objects/items/toys/cards.dm +++ b/code/game/objects/items/toys/cards.dm @@ -42,6 +42,7 @@ to_chat(user, "You place your cards on the bottom of the deck.") /obj/item/toy/deck/update_icon_state() + . = ..() switch(length(cards)) if(52) icon_state = "deck" @@ -167,6 +168,8 @@ var/concealed = 0 var/list/cards = list() + ///The last direction the person who dropped us was facing + var/last_direction = SOUTH /obj/item/toy/handcard/Initialize(mapload, card_type) . = ..() @@ -250,16 +253,22 @@ for(var/datum/playingcard/P in cards) . += "-[P.name]" -/obj/item/toy/handcard/update_icon(direction = 0) +/obj/item/toy/handcard/update_name(updates) + . = ..() if(length(cards) > 1) name = "hand of cards" - desc = "Some playing cards." else name = "a playing card" + +/obj/item/toy/handcard/update_desc(updates) + . = ..() + if(length(cards) > 1) + desc = "Some playing cards." + else desc = "A playing card." - overlays.Cut() - +/obj/item/toy/handcard/update_overlays() + . = ..() if(!length(cards)) return @@ -268,14 +277,14 @@ var/image/I = new(src.icon, (concealed ? "card_back" : "[P.card_icon]") ) I.pixel_x += (-5+rand(10)) I.pixel_y += (-5+rand(10)) - overlays += I + . += I return var/offset = FLOOR(20/length(cards), 1) var/matrix/M = matrix() - if(direction) - switch(direction) + if(last_direction) + switch(last_direction) if(NORTH) M.Translate( 0, 0) if(SOUTH) @@ -290,7 +299,7 @@ for(var/datum/playingcard/P in cards) var/image/I = new(src.icon, (concealed ? "card_back" : "[P.card_icon]") ) //I.pixel_x = origin+(offset*i) - switch(direction) + switch(last_direction) if(SOUTH) I.pixel_x = 8-(offset*i) if(WEST) @@ -300,15 +309,14 @@ else I.pixel_x = -7+(offset*i) I.transform = M - overlays += I + . += I i++ /obj/item/toy/handcard/dropped(mob/user as mob) - ..() + . = ..() if(locate(/obj/structure/table, loc)) - src.update_icon(user.dir) - else - update_icon() + last_direction = user.dir + update_icon() /obj/item/toy/handcard/pickup(mob/user as mob) src.update_icon() @@ -362,7 +370,11 @@ cards += P /obj/item/toy/deck/kotahi/update_icon_state() + . = ..() switch(length(cards)) - if(107 to 108) icon_state = "deck" - if(37 to 106) icon_state = "deck_open" - if(0 to 36) icon_state = "deck_empty" + if(107 to 108) + icon_state = "deck" + if(37 to 106) + icon_state = "deck_open" + if(0 to 36) + icon_state = "deck_empty" diff --git a/code/game/objects/items/toys/toy_weapons.dm b/code/game/objects/items/toys/toy_weapons.dm index 27393f6e8f0..589a30318b0 100644 --- a/code/game/objects/items/toys/toy_weapons.dm +++ b/code/game/objects/items/toys/toy_weapons.dm @@ -66,6 +66,7 @@ var/amount_left = 7 /obj/item/toy/gun_ammo/update_icon_state() + . = ..() if(amount_left) icon_state = "cap_ammo" else diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm index 786dfd86bc0..6945968b569 100644 --- a/code/game/objects/items/toys/toys.dm +++ b/code/game/objects/items/toys/toys.dm @@ -75,6 +75,7 @@ QDEL_IN(src, 5) /obj/item/toy/balloon/update_icon_state() + . = ..() if(reagents.total_volume) icon_state = "waterballoon" item_state = "balloon" diff --git a/code/game/objects/items/weapons/blades.dm b/code/game/objects/items/weapons/blades.dm index c6b5c0707f1..eb3e46e0955 100644 --- a/code/game/objects/items/weapons/blades.dm +++ b/code/game/objects/items/weapons/blades.dm @@ -426,13 +426,9 @@ RegisterSignal(src, COMSIG_MOVABLE_POST_THROW, PROC_REF(post_throw)) AddComponent(/datum/component/automatedfire/autofire, throw_delay, _fire_mode = GUN_FIREMODE_AUTOMATIC, _callback_reset_fire = CALLBACK(src, PROC_REF(stop_fire)), _callback_fire = CALLBACK(src, PROC_REF(throw_knife))) -/obj/item/stack/throwing_knife/update_icon() +/obj/item/stack/throwing_knife/update_icon_state() . = ..() - var/amount_to_show = amount > max_amount ? max_amount : amount - if(amount_to_show > 8) - setDir(8) - return - setDir(amount_to_show + round(amount_to_show / 3)) + icon_state = "throwing_knife_[amount]" /obj/item/stack/throwing_knife/equipped(mob/user, slot) . = ..() diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index e50a9dd5bbd..59b9c6f622f 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -104,6 +104,7 @@ AddElement(/datum/element/strappable) /obj/item/weapon/shield/riot/marine/update_icon_state() + . = ..() if(obj_integrity <= integrity_failure) icon_state = initial(icon_state) + "_broken" else diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 5c264d6b096..3dcb2b5c921 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -38,6 +38,7 @@ return 0 /obj/item/weapon/baton/update_icon_state() + . = ..() if(status) icon_state = "[initial(name)]_active" else if(!bcell) @@ -223,6 +224,7 @@ /obj/item/weapon/stunprod/update_icon_state() + . = ..() if(status) icon_state = "stunbaton_active" else diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 89bb9d67d44..3809ce7da60 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -444,6 +444,7 @@ update_icon() /obj/item/weapon/twohanded/rocketsledge/update_icon_state() + . = ..() if ((reagents.get_reagent_amount(/datum/reagent/fuel) > fuel_used) && (CHECK_BITFIELD(flags_item, WIELDED))) icon_state = "rocketsledge_w" else diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index aeddd6d6a4d..60a22c43925 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -135,4 +135,4 @@ to_chat(user, span_notice("You fasten the glass shard to the top of the rod with the cable.")) qdel(I) qdel(src) - update_icon(user) + update_icon() diff --git a/code/game/objects/machinery/adv_med.dm b/code/game/objects/machinery/adv_med.dm index 967f8bb7ead..6071640a96c 100644 --- a/code/game/objects/machinery/adv_med.dm +++ b/code/game/objects/machinery/adv_med.dm @@ -30,6 +30,7 @@ set_light(initial(light_range)) /obj/machinery/bodyscanner/update_icon_state() + . = ..() if(occupant) icon_state = "[initial(icon_state)]_occupied" else diff --git a/code/game/objects/machinery/air_alarm.dm b/code/game/objects/machinery/air_alarm.dm index e644e46a4e2..ea737f7f2af 100644 --- a/code/game/objects/machinery/air_alarm.dm +++ b/code/game/objects/machinery/air_alarm.dm @@ -36,6 +36,7 @@ set_light(initial(light_range)) /obj/machinery/air_alarm/update_icon_state() + . = ..() if(machine_stat & (NOPOWER|BROKEN)) icon_state = "alarm_unpowered" else diff --git a/code/game/objects/machinery/autodoc.dm b/code/game/objects/machinery/autodoc.dm index cf84cdef5ac..9d73567ca6a 100644 --- a/code/game/objects/machinery/autodoc.dm +++ b/code/game/objects/machinery/autodoc.dm @@ -102,6 +102,7 @@ set_light(initial(light_range)) /obj/machinery/autodoc/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "autodoc_off" else if(surgery) diff --git a/code/game/objects/machinery/bioprinter.dm b/code/game/objects/machinery/bioprinter.dm index d58009e2896..2d92eb9bd58 100644 --- a/code/game/objects/machinery/bioprinter.dm +++ b/code/game/objects/machinery/bioprinter.dm @@ -83,6 +83,7 @@ . += "It has [stored_matter] matter and [stored_metal] metal left." /obj/machinery/bioprinter/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "bioprinter_off" return diff --git a/code/game/objects/machinery/buttons.dm b/code/game/objects/machinery/buttons.dm index b13274b5783..7accb3f062d 100644 --- a/code/game/objects/machinery/buttons.dm +++ b/code/game/objects/machinery/buttons.dm @@ -24,6 +24,7 @@ update_icon() /obj/machinery/button/update_icon_state() + . = ..() if(machine_stat & (NOPOWER|BROKEN)) icon_state = "[initial(icon_state)]-p" else @@ -238,6 +239,7 @@ update_icon() /obj/machinery/medical_help_button/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "doorctrl-p" else @@ -297,4 +299,35 @@ return linked.equipOutfit(job_outfits[selected_outfit], FALSE) +/obj/machinery/button/valhalla/vehicle_button + name = "Vehicle Spawner" + +/obj/machinery/button/valhalla/vehicle_button/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, armor_type = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE) + var/list/spawnable_vehicles = list(/obj/vehicle/sealed/armored/multitile, + /obj/vehicle/sealed/armored/multitile/apc) + + var/selected_vehicle = tgui_input_list(usr, "Which vehicle do you want to spawn?", "Vehicle spawn", spawnable_vehicles) + if(!selected_vehicle) + return + + QDEL_NULL(linked) + if(!get_turf(GLOB.valhalla_button_spawn_landmark[link])) + to_chat(xeno_attacker, span_warning("An error occured, yell at the coders.")) + CRASH("Valhalla button linked with an improper landmark: button ID: [link].") + linked = new selected_vehicle(get_turf(GLOB.valhalla_button_spawn_landmark[link])) + +/obj/machinery/button/valhalla/vehicle_button/attack_hand(mob/living/user) + var/list/spawnable_vehicles = list(/obj/vehicle/sealed/armored/multitile, + /obj/vehicle/sealed/armored/multitile/apc) + + var/selected_vehicle = tgui_input_list(usr, "Which vehicle do you want to spawn?", "Vehicle spawn", spawnable_vehicles) + if(!selected_vehicle) + return + + QDEL_NULL(linked) + if(!get_turf(GLOB.valhalla_button_spawn_landmark[link])) + to_chat(user, span_warning("An error occured, yell at the coders.")) + CRASH("Valhalla button linked with an improper landmark: button ID: [link].") + linked = new selected_vehicle(get_turf(GLOB.valhalla_button_spawn_landmark[link])) + #undef DOOR_FLAG_OPEN_ONLY diff --git a/code/game/objects/machinery/camera/camera.dm b/code/game/objects/machinery/camera/camera.dm index dac8478a6af..4de512e5344 100644 --- a/code/game/objects/machinery/camera/camera.dm +++ b/code/game/objects/machinery/camera/camera.dm @@ -201,6 +201,7 @@ to_chat(AI, span_notice("[src] has been deactivated at [myarea]")) /obj/machinery/camera/update_icon_state() + . = ..() if(obj_integrity <= 0) icon_state = "camera_assembly" else @@ -375,9 +376,6 @@ /obj/machinery/camera/autoname/lz_camera/ex_act() return -/obj/machinery/camera/autoname/lz_camera/update_icon() - return - //Thunderdome cameras /obj/machinery/camera/autoname/thunderdome name = "thunderdome camera" @@ -387,7 +385,8 @@ //Special invisible cameras, to get even better angles without looking ugly /obj/machinery/camera/autoname/thunderdome/hidden -/obj/machinery/camera/autoname/thunderdome/hidden/update_icon() +/obj/machinery/camera/autoname/thunderdome/hidden/update_icon_state() + . = ..() icon_state = "nothing" /obj/machinery/camera/miner diff --git a/code/game/objects/machinery/camera/deployable_camera.dm b/code/game/objects/machinery/camera/deployable_camera.dm index 35e5791b334..58058623dff 100644 --- a/code/game/objects/machinery/camera/deployable_camera.dm +++ b/code/game/objects/machinery/camera/deployable_camera.dm @@ -7,7 +7,8 @@ GLOBAL_VAR_INIT(deployed_cameras, 0) icon_state = "deployable" layer = ABOVE_ALL_MOB_LAYER//it flies after all -/obj/machinery/camera/deployable/update_icon() +/obj/machinery/camera/deployable/update_icon_state() + . = ..() if(obj_integrity <= 0) icon_state = "deployableoff" else diff --git a/code/game/objects/machinery/cic_maptable.dm b/code/game/objects/machinery/cic_maptable.dm index dafadd77d28..e9a3b1a7feb 100644 --- a/code/game/objects/machinery/cic_maptable.dm +++ b/code/game/objects/machinery/cic_maptable.dm @@ -179,7 +179,15 @@ pixel_x = -16 pixel_y = -14 coverage = 75 - allow_pass_flags = PASS_LOW_STRUCTURE|PASSABLE + allow_pass_flags = PASS_LOW_STRUCTURE|PASSABLE|PASS_WALKOVER + bound_width = 64 + +/obj/machinery/cic_maptable/drawable/big/Initialize(mapload) + . = ..() + var/static/list/connections = list( + COMSIG_OBJ_TRY_ALLOW_THROUGH = PROC_REF(can_climb_over), + ) + AddElement(/datum/element/connect_loc, connections) /obj/machinery/cic_maptable/drawable/big/som minimap_flag = MINIMAP_FLAG_MARINE_SOM diff --git a/code/game/objects/machinery/cloning/cloning.dm b/code/game/objects/machinery/cloning/cloning.dm index e16ee314f84..22d99e6a376 100644 --- a/code/game/objects/machinery/cloning/cloning.dm +++ b/code/game/objects/machinery/cloning/cloning.dm @@ -71,7 +71,7 @@ These act as a respawn mechanic growning a body and offering it up to ghosts. if(!linked_machine) // Try to find the machine nearby - linked_machine = locate() in orange(1, src) + linked_machine = locate() in get_step(src, REVERSE_DIR(dir)) if(!linked_machine) visible_message("[icon2html(src, viewers(src))] [src] beeps in error, 'Connection not available'.") return TRUE @@ -218,6 +218,7 @@ These act as a respawn mechanic growning a body and offering it up to ghosts. set_light(0) /obj/machinery/cloning/vats/update_icon_state() + . = ..() if(!beaker) icon_state = "cell_0" return @@ -287,3 +288,13 @@ You are weak, best rest up and get your strength before fighting."}) linked_console.radio.talk_into(src, "New clone: [occupant] has been grown in [src] at: [get_area(src)]. Please move the fresh clone to a squad using the squad distribution console.", RADIO_CHANNEL_COMMAND) occupant = null update_icon() + +/obj/machinery/cloning/vats/apc + grow_timer = 8 MINUTES + pixel_y = 16 + dir = NORTH + +/obj/machinery/cloning/vats/apc/south + pixel_y = -16 + dir = SOUTH + layer = BELOW_OBJ_LAYER diff --git a/code/game/objects/machinery/computer/camera_advanced.dm b/code/game/objects/machinery/computer/camera_advanced.dm index 8099fb2f152..e34ffd342e8 100644 --- a/code/game/objects/machinery/computer/camera_advanced.dm +++ b/code/game/objects/machinery/computer/camera_advanced.dm @@ -249,6 +249,11 @@ user.see_in_dark = 2 return TRUE +/mob/camera/aiEye/remote/reset_glide_size() //because this mob only moves via relay move which has a hardcoded move delay var, we set for that specifically + if(glide_modifier_flags) + return + set_glide_size(16) + /mob/camera/aiEye/remote/Destroy() if(origin && eye_user) diff --git a/code/game/objects/machinery/computer/camera_console.dm b/code/game/objects/machinery/computer/camera_console.dm index a86c34b9a2a..b717b0c6e27 100644 --- a/code/game/objects/machinery/computer/camera_console.dm +++ b/code/game/objects/machinery/computer/camera_console.dm @@ -169,6 +169,7 @@ /obj/machinery/computer/security/telescreen/update_icon_state() + . = ..() icon_state = initial(icon_state) if(machine_stat & (BROKEN|DISABLED)) icon_state += "b" diff --git a/code/game/objects/machinery/computer/computer.dm b/code/game/objects/machinery/computer/computer.dm index f31a12d974e..a910c874333 100644 --- a/code/game/objects/machinery/computer/computer.dm +++ b/code/game/objects/machinery/computer/computer.dm @@ -85,6 +85,7 @@ set_light(initial(light_range)) /obj/machinery/computer/update_icon_state() + . = ..() if(machine_stat & (BROKEN|DISABLED)) icon_state = "[initial(icon_state)]_broken" else diff --git a/code/game/objects/machinery/computer/nt_access.dm b/code/game/objects/machinery/computer/nt_access.dm index 5e7724d4ff6..da86ba6ac91 100644 --- a/code/game/objects/machinery/computer/nt_access.dm +++ b/code/game/objects/machinery/computer/nt_access.dm @@ -71,7 +71,7 @@ visible_message("[src] shuts down as it loses power. Any running programs will now exit") /obj/machinery/computer/nt_access/update_icon_state() - icon_state = initial(icon_state) + return /obj/machinery/computer/nt_access/attackby(obj/item/I, mob/living/user, params) return attack_hand(user) diff --git a/code/game/objects/machinery/computer/som_computer.dm b/code/game/objects/machinery/computer/som_computer.dm index c1c60943a83..2dcd787e872 100644 --- a/code/game/objects/machinery/computer/som_computer.dm +++ b/code/game/objects/machinery/computer/som_computer.dm @@ -13,6 +13,7 @@ pixel_y = 10 /obj/machinery/computer/som/update_icon_state() + . = ..() if(machine_stat & (BROKEN|DISABLED)) icon_state = "[initial(icon_state)]_broken" else if(machine_stat & NOPOWER) diff --git a/code/game/objects/machinery/constructable_frame.dm b/code/game/objects/machinery/constructable_frame.dm index 22ef9574cdd..ebe3b925442 100644 --- a/code/game/objects/machinery/constructable_frame.dm +++ b/code/game/objects/machinery/constructable_frame.dm @@ -10,7 +10,8 @@ var/state = 1 -/obj/machinery/constructable_frame/proc/update_desc() +/obj/machinery/constructable_frame/update_desc(updates) + . = ..() var/D if(req_components) D = "Requires " diff --git a/code/game/objects/machinery/cryopod.dm b/code/game/objects/machinery/cryopod.dm index 10cb28b313c..7a443857f50 100644 --- a/code/game/objects/machinery/cryopod.dm +++ b/code/game/objects/machinery/cryopod.dm @@ -126,6 +126,7 @@ set_light(initial(light_range)) /obj/machinery/cryopod/update_icon_state() + . = ..() if(occupant) icon_state = "[initial(icon_state)]_occupied" else diff --git a/code/game/objects/machinery/deployable.dm b/code/game/objects/machinery/deployable.dm index ff4f2d652ef..18dd4eadc0f 100644 --- a/code/game/objects/machinery/deployable.dm +++ b/code/game/objects/machinery/deployable.dm @@ -1,5 +1,5 @@ /obj/machinery/deployable - flags_atom = PREVENT_CONTENTS_EXPLOSION + flags_atom = CRITICAL_ATOM|PREVENT_CONTENTS_EXPLOSION hud_possible = list(MACHINE_HEALTH_HUD) obj_flags = CAN_BE_HIT allow_pass_flags = PASS_AIR diff --git a/code/game/objects/machinery/door_control.dm b/code/game/objects/machinery/door_control.dm index 4bff0860412..eb004dc77b1 100644 --- a/code/game/objects/machinery/door_control.dm +++ b/code/game/objects/machinery/door_control.dm @@ -128,6 +128,7 @@ update_icon() /obj/machinery/door_control/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "doorctrl-p" else if(pressed) @@ -281,6 +282,7 @@ directional = FALSE /obj/machinery/door_control/old/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "olddoorctrl-p" else if(pressed) diff --git a/code/game/objects/machinery/door_display/door_display.dm b/code/game/objects/machinery/door_display/door_display.dm index 18d81891c61..43b7c871812 100644 --- a/code/game/objects/machinery/door_display/door_display.dm +++ b/code/game/objects/machinery/door_display/door_display.dm @@ -110,17 +110,17 @@ //icon update function // if NOPOWER, display blank // if BROKEN, display blue screen of death icon AI uses -/obj/machinery/door_display/update_icon() - cut_overlays() - if (machine_stat & (NOPOWER)) +/obj/machinery/door_display/update_overlays() + . = ..() + if(machine_stat & (NOPOWER)) return - if (machine_stat & (BROKEN)) - add_overlay("ai_bsod") + if(machine_stat & (BROKEN)) + . += "ai_bsod" return if(open) - add_overlay("open") + . += "open" else - add_overlay("closed") + . += "closed" //************ RESEARCH DOORS ****************\\ // Research cells have flashers and shutters/pod doors. diff --git a/code/game/objects/machinery/doors/airlock.dm b/code/game/objects/machinery/doors/airlock.dm index 7c18b6dfac2..416b9686e28 100644 --- a/code/game/objects/machinery/doors/airlock.dm +++ b/code/game/objects/machinery/doors/airlock.dm @@ -171,24 +171,29 @@ else return 0 -/obj/machinery/door/airlock/update_icon() - if(overlays) overlays.Cut() + +/obj/machinery/door/airlock/update_icon_state() + . = ..() if(density) - if(emergency && hasPower()) - overlays += image(icon, "emergency_access_on") if(locked && lights) icon_state = "door_locked" else icon_state = "door_closed" - if(CHECK_BITFIELD(machine_stat, PANEL_OPEN) || welded) - overlays = list() - if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) - overlays += image(icon, "panel_open") - if(welded) - overlays += image(icon, "welded") else icon_state = "door_open" +/obj/machinery/door/airlock/update_overlays() + . = ..() + if(!density) + return + if(emergency && hasPower()) + . += image(icon, "emergency_access_on") + if(CHECK_BITFIELD(machine_stat, PANEL_OPEN) || welded) + if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) + . += image(icon, "panel_open") + if(welded) + . += image(icon, "welded") + /obj/machinery/door/airlock/do_animate(animation) switch(animation) if("opening") diff --git a/code/game/objects/machinery/doors/airlock_control.dm b/code/game/objects/machinery/doors/airlock_control.dm index 60a254001d1..dcb7e9d0ac8 100644 --- a/code/game/objects/machinery/doors/airlock_control.dm +++ b/code/game/objects/machinery/doors/airlock_control.dm @@ -149,6 +149,7 @@ /obj/machinery/access_button/update_icon_state() + . = ..() if(on) icon_state = "access_button_standby" else diff --git a/code/game/objects/machinery/doors/door.dm b/code/game/objects/machinery/doors/door.dm index ee25b6bee32..e67e5aa3cca 100644 --- a/code/game/objects/machinery/doors/door.dm +++ b/code/game/objects/machinery/doors/door.dm @@ -153,7 +153,8 @@ else qdel(src) -/obj/machinery/door/update_icon() +/obj/machinery/door/update_icon_state() + . = ..() if(density) icon_state = "door1" else diff --git a/code/game/objects/machinery/doors/firedoor.dm b/code/game/objects/machinery/doors/firedoor.dm index 3c30d10bdd8..654d0df897f 100644 --- a/code/game/objects/machinery/doors/firedoor.dm +++ b/code/game/objects/machinery/doors/firedoor.dm @@ -281,24 +281,31 @@ flick("door_closing", src) playsound(loc, 'sound/machines/emergency_shutter.ogg', 25) -/obj/machinery/door/firedoor/update_icon() - overlays.Cut() + +/obj/machinery/door/firedoor/update_icon_state() + . = ..() if(density) icon_state = "door_closed" + else + icon_state = "door_open" + +/obj/machinery/door/firedoor/update_overlays() + . = ..() + if(density) if(blocked) - overlays += "welded" + . += "welded" if(pdiff_alert) - overlays += "palert" + . += "palert" if(dir_alerts) for(var/d=1;d<=4;d++) var/cdir = GLOB.cardinals[d] for(var/i=1;i<=length(ALERT_STATES);i++) if(dir_alerts[d] & (1<<(i-1))) - overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir) + . += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir) else - icon_state = "door_open" if(blocked) - overlays += "welded_open" + . += "welded_open" + /obj/machinery/door/firedoor/mainship name = "\improper Emergency Shutter" diff --git a/code/game/objects/machinery/doors/multi_tile.dm b/code/game/objects/machinery/doors/multi_tile.dm index 69595ac2e64..c53d5772818 100644 --- a/code/game/objects/machinery/doors/multi_tile.dm +++ b/code/game/objects/machinery/doors/multi_tile.dm @@ -2,10 +2,10 @@ /obj/machinery/door/airlock/multi_tile width = 2 -/obj/machinery/door/airlock/multi_tile/close() //Nasty as hell O(n^2) code but unfortunately necessary +/obj/machinery/door/airlock/multi_tile/close() //Nasty as hell O(n^2) code but unfortunately necessary //honestly probably not, TODO fixme for(var/turf/T in locs) - for(var/obj/vehicle/multitile/M in T) - if(M) return FALSE + for(var/obj/hitbox/hit in T) + return FALSE return ..() diff --git a/code/game/objects/machinery/doors/poddoor.dm b/code/game/objects/machinery/doors/poddoor.dm index 95e222e6b8d..da90b49b3f1 100644 --- a/code/game/objects/machinery/doors/poddoor.dm +++ b/code/game/objects/machinery/doors/poddoor.dm @@ -48,7 +48,8 @@ /obj/machinery/door/poddoor/try_to_activate_door(mob/user) return -/obj/machinery/door/poddoor/update_icon() +/obj/machinery/door/poddoor/update_icon_state() + . = ..() if(density) icon_state = "pdoor1" else diff --git a/code/game/objects/machinery/doors/railing.dm b/code/game/objects/machinery/doors/railing.dm index 65fcc858361..c27ffcaeb12 100644 --- a/code/game/objects/machinery/doors/railing.dm +++ b/code/game/objects/machinery/doors/railing.dm @@ -57,7 +57,8 @@ return TRUE -/obj/machinery/door/poddoor/railing/update_icon() +/obj/machinery/door/poddoor/railing/update_icon_state() + . = ..() if(density) icon_state = "railing1" else diff --git a/code/game/objects/machinery/doors/shutters.dm b/code/game/objects/machinery/doors/shutters.dm index a9ebd023520..5ed0955b219 100644 --- a/code/game/objects/machinery/doors/shutters.dm +++ b/code/game/objects/machinery/doors/shutters.dm @@ -55,7 +55,8 @@ operating = FALSE -/obj/machinery/door/poddoor/shutters/update_icon() +/obj/machinery/door/poddoor/shutters/update_icon_state() + . = ..() if(operating) return icon_state = "shutter[density]" diff --git a/code/game/objects/machinery/doors/windowdoor.dm b/code/game/objects/machinery/doors/windowdoor.dm index 56389874d96..b845a1bd5f0 100644 --- a/code/game/objects/machinery/doors/windowdoor.dm +++ b/code/game/objects/machinery/doors/windowdoor.dm @@ -44,7 +44,8 @@ return ..() -/obj/machinery/door/window/update_icon() +/obj/machinery/door/window/update_icon_state() + . = ..() if(operating) return icon_state = density ? base_state : "[base_state]open" diff --git a/code/game/objects/machinery/dropship_part_fabricator.dm b/code/game/objects/machinery/dropship_part_fabricator.dm index d2024fea2e5..0d7ccebc193 100644 --- a/code/game/objects/machinery/dropship_part_fabricator.dm +++ b/code/game/objects/machinery/dropship_part_fabricator.dm @@ -19,6 +19,7 @@ var/busy = FALSE /obj/machinery/dropship_part_fabricator/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "drone_fab_nopower" return diff --git a/code/game/objects/machinery/flasher.dm b/code/game/objects/machinery/flasher.dm index f269b918c1e..fbb06a6a8ae 100644 --- a/code/game/objects/machinery/flasher.dm +++ b/code/game/objects/machinery/flasher.dm @@ -34,6 +34,7 @@ /obj/machinery/flasher/update_icon_state() + . = ..() if(!(machine_stat & NOPOWER)) icon_state = "[base_state]1" else diff --git a/code/game/objects/machinery/floodlight.dm b/code/game/objects/machinery/floodlight.dm index 1b18c43cc83..c4daa19a1a1 100644 --- a/code/game/objects/machinery/floodlight.dm +++ b/code/game/objects/machinery/floodlight.dm @@ -127,6 +127,7 @@ turn_light(user, !light_on) /obj/machinery/deployable/floodlight/update_icon_state() + . = ..() icon_state = "floodlightcombat_deployed" + (light_on ? "_on" : "_off") /obj/item/deployable_floodlight @@ -179,7 +180,7 @@ update_icon() -/obj/machinery/floodlight/colony/update_icon() +/obj/machinery/floodlight/colony/update_icon_state() . = ..() if(light_on) icon_state = "floodon" @@ -201,7 +202,7 @@ resistance_flags = RESIST_ALL var/turned_on = FALSE //has to be toggled in engineering -/obj/machinery/colony_floodlight_switch/update_icon() +/obj/machinery/colony_floodlight_switch/update_icon_state() . = ..() if(machine_stat & NOPOWER) icon_state = "panelnopower" diff --git a/code/game/objects/machinery/fuelcell_recycler.dm b/code/game/objects/machinery/fuelcell_recycler.dm index a91363d7528..5d7050c77cb 100644 --- a/code/game/objects/machinery/fuelcell_recycler.dm +++ b/code/game/objects/machinery/fuelcell_recycler.dm @@ -85,18 +85,22 @@ update_icon() -/obj/machinery/fuelcell_recycler/update_icon() - src.overlays.Cut() - +/obj/machinery/fuelcell_recycler/update_icon_state() + . = ..() if(machine_stat & (BROKEN|NOPOWER)) icon_state = "recycler0" + else + icon_state = "recycler" + +/obj/machinery/fuelcell_recycler/update_overlays() + . = ..() + + if(machine_stat & (BROKEN|NOPOWER)) if(cell_left != null) src.overlays += "recycler-left-cell" if(cell_right != null) src.overlays += "recycler-right-cell" return - else - icon_state = "recycler" var/overlay_builder = "recycler-" if(cell_left == null && cell_right == null) @@ -107,8 +111,8 @@ else overlay_builder += "left-charging" - src.overlays += overlay_builder - src.overlays += "recycler-left-cell" + . += overlay_builder + . += "recycler-left-cell" return else if(cell_left == null) if(cell_right.is_regenerated()) @@ -116,8 +120,8 @@ else overlay_builder += "right-charging" - src.overlays += overlay_builder - src.overlays += "recycler-right-cell" + . += overlay_builder + . += "recycler-right-cell" return else // both left and right cells are there if(cell_left.is_regenerated()) @@ -130,7 +134,6 @@ else overlay_builder += "-right-charging" - src.overlays += overlay_builder - src.overlays += "recycler-left-cell" - src.overlays += "recycler-right-cell" - return + . += overlay_builder + . += "recycler-left-cell" + . += "recycler-right-cell" diff --git a/code/game/objects/machinery/gear.dm b/code/game/objects/machinery/gear.dm index 1e54c026534..9ddf140565a 100644 --- a/code/game/objects/machinery/gear.dm +++ b/code/game/objects/machinery/gear.dm @@ -30,3 +30,6 @@ /obj/machinery/elevator_strut/bottom icon_state = "strut_bottom" + +/obj/machinery/gear/vehicle // todo do for suppply as well instead of varediting + id = "vehicle_elevator_gear" diff --git a/code/game/objects/machinery/hologram.dm b/code/game/objects/machinery/hologram.dm index 1a6de82d0c0..d89c5699463 100644 --- a/code/game/objects/machinery/hologram.dm +++ b/code/game/objects/machinery/hologram.dm @@ -359,6 +359,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ update_icon() /obj/machinery/holopad/update_icon_state() + . = ..() var/total_users = LAZYLEN(masters) + LAZYLEN(holo_calls) if(ringing) icon_state = "holopad_ringing" diff --git a/code/game/objects/machinery/holosign.dm b/code/game/objects/machinery/holosign.dm index 4217b4ba818..d4259f279a2 100644 --- a/code/game/objects/machinery/holosign.dm +++ b/code/game/objects/machinery/holosign.dm @@ -17,6 +17,7 @@ update_icon() /obj/machinery/holosign/update_icon_state() + . = ..() if(!lit) icon_state = "sign_off" else diff --git a/code/game/objects/machinery/igniter.dm b/code/game/objects/machinery/igniter.dm index fb08154766e..4cd84718ca1 100644 --- a/code/game/objects/machinery/igniter.dm +++ b/code/game/objects/machinery/igniter.dm @@ -30,7 +30,8 @@ icon_state = "igniter[on]" -/obj/machinery/igniter/update_icon() +/obj/machinery/igniter/update_icon_state() + . = ..() if(is_operational()) icon_state = "igniter[on]" else @@ -52,14 +53,12 @@ var/base_state = "migniter" anchored = TRUE -/obj/machinery/sparker/update_icon() - if ( !(machine_stat & NOPOWER) && disable == 0 ) - +/obj/machinery/sparker/update_icon_state() + . = ..() + if(!(machine_stat & NOPOWER) && disable == 0) icon_state = "[base_state]" -// src.sd_SetLuminosity(2) else icon_state = "[base_state]-p" -// src.sd_SetLuminosity(0) /obj/machinery/sparker/attackby(obj/item/I, mob/user, params) . = ..() diff --git a/code/game/objects/machinery/iv_drip.dm b/code/game/objects/machinery/iv_drip.dm index 36a36d4766d..3f0b6e98c3f 100644 --- a/code/game/objects/machinery/iv_drip.dm +++ b/code/game/objects/machinery/iv_drip.dm @@ -10,37 +10,44 @@ var/obj/item/reagent_containers/beaker = null var/datum/beam/current_beam -/obj/machinery/iv_drip/update_icon() - /* СМ КОСТЫЛЬ - if(src.attached) +/obj/machinery/iv_drip/update_icon_state() + . = ..() + if(attached) icon_state = "hooked" else icon_state = "" - */ - icon_state = "" //КОСТЫЛЬ - //У нас нет системы которая позволила бы изменить pixel x/y вары у начальной и конечной точек beam'а - //Поэтому оставляю 1 айкон стейт, чтобы не выглядело всё слишком плохо +/obj/machinery/iv_drip/update_overlays() + . = ..() - overlays = null + if(!beaker) + return - if(beaker) - var/datum/reagents/reagents = beaker.reagents - if(reagents.total_volume) - var/image/filling = image('icons/obj/iv_drip.dmi', src, "reagent") - - var/percent = round((reagents.total_volume / beaker.volume) * 100) - switch(percent) - if(0 to 9) filling.icon_state = "reagent0" - if(10 to 24) filling.icon_state = "reagent10" - if(25 to 49) filling.icon_state = "reagent25" - if(50 to 74) filling.icon_state = "reagent50" - if(75 to 79) filling.icon_state = "reagent75" - if(80 to 90) filling.icon_state = "reagent80" - if(91 to INFINITY) filling.icon_state = "reagent100" - - filling.color = mix_color_from_reagents(reagents.reagent_list) - overlays += filling + var/datum/reagents/reagents = beaker.reagents + if(!reagents?.total_volume) + return + + var/image/filling = image('icons/obj/iv_drip.dmi', src, "reagent") + + var/percent = round((reagents.total_volume / beaker.volume) * 100) + switch(percent) + if(0 to 9) + filling.icon_state = "reagent0" + if(10 to 24) + filling.icon_state = "reagent10" + if(25 to 49) + filling.icon_state = "reagent25" + if(50 to 74) + filling.icon_state = "reagent50" + if(75 to 79) + filling.icon_state = "reagent75" + if(80 to 90) + filling.icon_state = "reagent80" + if(91 to INFINITY) + filling.icon_state = "reagent100" + + filling.color = mix_color_from_reagents(reagents.reagent_list) + . += filling /obj/machinery/iv_drip/proc/update_beam() if(current_beam && !attached) diff --git a/code/game/objects/machinery/kitchen/gibber.dm b/code/game/objects/machinery/kitchen/gibber.dm index 5f5b8a317d0..85e272f4688 100644 --- a/code/game/objects/machinery/kitchen/gibber.dm +++ b/code/game/objects/machinery/kitchen/gibber.dm @@ -41,7 +41,7 @@ go_out() -/obj/machinery/gibber/attack_hand(mob/living/user) +/obj/machinery/gibber/interact(mob/user) . = ..() if(.) return @@ -49,24 +49,24 @@ to_chat(user, span_warning("It's locked and running")) return - startgibbing(user) - -/obj/machinery/gibber/attackby(obj/item/grab/I, mob/user, param) - . = ..() + activate_gibber(user) +/obj/machinery/gibber/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE) + if(!is_operational()) + return ..() if(occupant) to_chat(user, span_warning("The gibber is full, empty it first!")) return - else if(!(istype(I, /obj/item/grab)) ) + else if(!(istype(grab, /obj/item/grab)) ) to_chat(user, span_warning("This item is not suitable for the gibber!")) return - else if(!iscarbon(I.grabbed_thing) && !istype(I.grabbed_thing, /mob/living/simple_animal)) + else if(!iscarbon(grab.grabbed_thing) && !istype(grab.grabbed_thing, /mob/living/simple_animal)) to_chat(user, span_warning("This item is not suitable for the gibber!")) return - var/mob/living/M = I.grabbed_thing + var/mob/living/M = grab.grabbed_thing if(user.grab_state < GRAB_AGGRESSIVE) to_chat(user, span_warning("You need a better grip to do that!")) return @@ -108,7 +108,7 @@ ///Gibs the victim, and sets the output -/obj/machinery/gibber/proc/startgibbing(mob/user as mob) +/obj/machinery/gibber/proc/activate_gibber(mob/user as mob) if(operating) return if(!occupant) @@ -173,14 +173,15 @@ var/turf/T = get_turf(src) var/list/turf/nearby_turfs = RANGE_TURFS(3, T) - T - for(var/i=1 to meat_produced) - var/obj/item/meatslab = meatlist[i] - meatslab.forceMove(loc) - meatslab.throw_at(pick(nearby_turfs),i,3) - for(var/turfs=1 to meat_produced) - var/turf/gibturf = pick(nearby_turfs) - if(!gibturf.density && (src in view(gibturf))) - new gibtype(gibturf,i) + if(meat_produced) + for(var/i=1 to meat_produced) + var/obj/item/meatslab = meatlist[i] + meatslab.forceMove(loc) + meatslab.throw_at(pick(nearby_turfs),i,3) + for(var/turfs=1 to meat_produced) + var/turf/gibturf = pick(nearby_turfs) + if(!gibturf.density && (src in view(gibturf))) + new gibtype(gibturf,i) playsound(loc, 'sound/effects/splat.ogg', 50, TRUE) operating = FALSE @@ -189,6 +190,66 @@ /obj/machinery/gibber/nopower use_power = NO_POWER_USE +/obj/machinery/gibber/apc + use_power = NO_POWER_USE + var/obj/item/reagent_containers/glass/beaker/bluespace/internal_beaker + +/obj/machinery/gibber/apc/Initialize(mapload) + . = ..() + internal_beaker = new(src) + +/obj/machinery/gibber/apc/Destroy() + qdel(internal_beaker) + return ..() + +/obj/machinery/gibber/apc/make_meat(list/meatlist, meat_produced, gibtype) + if(!internal_beaker) + return ..() + + for(var/obj/item/meatslab AS in meatlist) + var/biomass_amount = 0 + biomass_amount += 1 + floor(meatslab.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) * 0.5) + meatlist -= meatslab + meat_produced -- + internal_beaker.reagents.add_reagent(/datum/reagent/medicine/biomass, biomass_amount) + if(internal_beaker.reagents.holder_full()) + break + + return ..() + +/obj/machinery/gibber/apc/attackby(obj/item/I, mob/user, params) + . = ..() + if(.) + return + + if(internal_beaker) + return + if(!istype(I, /obj/item/reagent_containers/glass/beaker)) + balloon_alert(user, "Cannot insert") + return + user.transferItemToLoc(I, src) + internal_beaker = I + balloon_alert(user, "Adds beaker") + +/obj/machinery/gibber/apc/interact(mob/user) + . = ..() + if(.) + return + if(operating) + return + if(!internal_beaker) + return + internal_beaker.forceMove(drop_location()) + if(user && Adjacent(user) && !issiliconoradminghost(user)) + user.put_in_hands(internal_beaker) + internal_beaker = null + +/obj/machinery/gibber/apc/grab_interact(obj/item/grab/grab, mob/user, base_damage = BASE_OBJ_SLAM_DAMAGE, is_sharp = FALSE) + if(HAS_TRAIT(grab.grabbed_thing, TRAIT_MAPSPAWNED)) + balloon_alert(user, "bad meat") + return FALSE + return ..() + /obj/machinery/gibber/pred icon = 'icons/obj/machines/yautja_machines.dmi' icon_state = "grinder" diff --git a/code/game/objects/machinery/kitchen/smartfridge.dm b/code/game/objects/machinery/kitchen/smartfridge.dm index 1b8d4713d4a..b4ad08ae733 100644 --- a/code/game/objects/machinery/kitchen/smartfridge.dm +++ b/code/game/objects/machinery/kitchen/smartfridge.dm @@ -41,8 +41,9 @@ if(src.shoot_inventory && prob(2)) src.throw_item() -/obj/machinery/smartfridge/update_icon() - if( !(machine_stat & NOPOWER) ) +/obj/machinery/smartfridge/update_icon_state() + . = ..() + if(!(machine_stat & NOPOWER)) icon_state = icon_on else icon_state = icon_off diff --git a/code/game/objects/machinery/lightswitch.dm b/code/game/objects/machinery/lightswitch.dm index f4762b8f83a..b810656ae3e 100644 --- a/code/game/objects/machinery/lightswitch.dm +++ b/code/game/objects/machinery/lightswitch.dm @@ -25,6 +25,7 @@ update_icon() /obj/machinery/light_switch/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "light-p" return diff --git a/code/game/objects/machinery/miner.dm b/code/game/objects/machinery/miner.dm index 5bd3fc8b552..4171dc29985 100644 --- a/code/game/objects/machinery/miner.dm +++ b/code/game/objects/machinery/miner.dm @@ -76,7 +76,8 @@ var/marker_icon = "miner_[mineral_value >= PLATINUM_CRATE_SELL_AMOUNT ? "platinum" : "phoron"]_on" SSminimaps.add_marker(src, MINIMAP_FLAG_ALL, image('icons/UI_icons/map_blips.dmi', null, marker_icon)) //RU TGMC edit -/obj/machinery/miner/update_icon() +/obj/machinery/miner/update_icon_state() + . = ..() switch(miner_status) if(MINER_RUNNING) icon_state = "mining_drill_active_[miner_upgrade_type]" diff --git a/code/game/objects/machinery/recharger.dm b/code/game/objects/machinery/recharger.dm index 4c4f48c0fbe..675837aa8b9 100644 --- a/code/game/objects/machinery/recharger.dm +++ b/code/game/objects/machinery/recharger.dm @@ -140,29 +140,29 @@ B.bcell.charge = 0 ..(severity) -/obj/machinery/recharger/update_icon() - overlays = list() +/obj/machinery/recharger/update_overlays() + . = ..() if((machine_stat & (NOPOWER|BROKEN))) return - else if(!charging) - overlays += "recharger-power" + if(!charging) + . += "recharger-power" return if(percent_charge_complete < 25) - overlays += "recharger-10" + . += "recharger-10" else if(percent_charge_complete >= 25 && percent_charge_complete < 50) - overlays += "recharger-25" + . += "recharger-25" else if(percent_charge_complete >= 50 && percent_charge_complete < 75) - overlays += "recharger-50" + . += "recharger-50" else if(percent_charge_complete >= 75 && percent_charge_complete < 100) - overlays += "recharger-75" + . += "recharger-75" else if(percent_charge_complete >= 100) - overlays += "recharger-100" + . += "recharger-100" if(istype(charging, /obj/item/weapon/gun/energy/taser)) - overlays += "recharger-taser" + . += "recharger-taser" else if(istype(charging, /obj/item/weapon/baton)) - overlays += "recharger-baton" + . += "recharger-baton" /obj/machinery/recharger/nopower use_power = NO_POWER_USE diff --git a/code/game/objects/machinery/robotic_cradle.dm b/code/game/objects/machinery/robotic_cradle.dm index 6d3c5ef32e5..8aa08fa9b80 100644 --- a/code/game/objects/machinery/robotic_cradle.dm +++ b/code/game/objects/machinery/robotic_cradle.dm @@ -39,6 +39,7 @@ return ..() /obj/machinery/robotic_cradle/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "borgcharger0" return diff --git a/code/game/objects/machinery/sleeper.dm b/code/game/objects/machinery/sleeper.dm index fe3a9ba838b..8fb8c20cd38 100644 --- a/code/game/objects/machinery/sleeper.dm +++ b/code/game/objects/machinery/sleeper.dm @@ -254,6 +254,7 @@ set_light(initial(light_range)) /obj/machinery/sleeper/update_icon_state() + . = ..() if(occupant) icon_state = "[initial(icon_state)]_occupied" else diff --git a/code/game/objects/machinery/squad_supply/supply_beacon.dm b/code/game/objects/machinery/squad_supply/supply_beacon.dm index ceb32b5a178..089afae4871 100644 --- a/code/game/objects/machinery/squad_supply/supply_beacon.dm +++ b/code/game/objects/machinery/squad_supply/supply_beacon.dm @@ -14,6 +14,7 @@ var/beacon_mini_icon = null /obj/item/beacon/update_icon_state() + . = ..() icon_state = activated ? icon_activated : initial(icon_state) /obj/item/beacon/attack_self(mob/living/carbon/human/H) diff --git a/code/game/objects/machinery/suit_storage_unit.dm b/code/game/objects/machinery/suit_storage_unit.dm index c98e26910bc..f0cf3ce3829 100644 --- a/code/game/objects/machinery/suit_storage_unit.dm +++ b/code/game/objects/machinery/suit_storage_unit.dm @@ -35,31 +35,32 @@ inserted_tank = new starting_tank_type(src) update_icon() - -/obj/machinery/suit_storage_unit/update_icon() - overlays.Cut() - if(isUV) - icon_state = "disinfecting" +/obj/machinery/suit_storage_unit/update_overlays() + . = ..() + if(isUV || !isopen) return - else if(isopen) - if(inserted_helmet) - overlays += image("helmet") - if(inserted_suit) - overlays += image("suit") - if(inserted_mask) - overlays += image("mask") - if(inserted_tank) - overlays += image("tank") + if(inserted_helmet) + . += image("helmet") + if(inserted_suit) + . += image("suit") + if(inserted_mask) + . += image("mask") + if(inserted_tank) + . += image("tank") - icon_state = "open" +/obj/machinery/suit_storage_unit/update_icon_state() + . = ..() + if(isUV) + return + if(isopen) + icon_state = "open" else icon_state = "closed" if(machine_stat & NOPOWER) icon_state += "_off" - /obj/machinery/suit_storage_unit/power_change() ..() if(machine_stat & NOPOWER) diff --git a/code/game/objects/machinery/telecomms/telecomunications.dm b/code/game/objects/machinery/telecomms/telecomunications.dm index 37eee7febe7..523f07c031a 100644 --- a/code/game/objects/machinery/telecomms/telecomunications.dm +++ b/code/game/objects/machinery/telecomms/telecomunications.dm @@ -144,7 +144,8 @@ GLOBAL_LIST_EMPTY(telecomms_freq_listening_list) return -/obj/machinery/telecomms/update_icon() +/obj/machinery/telecomms/update_icon_state() + . = ..() if(on) if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) icon_state = "[initial(icon_state)]_o" diff --git a/code/game/objects/machinery/vending/loadout_vendor.dm b/code/game/objects/machinery/vending/loadout_vendor.dm index ba5fd54604b..42539a1bc0d 100644 --- a/code/game/objects/machinery/vending/loadout_vendor.dm +++ b/code/game/objects/machinery/vending/loadout_vendor.dm @@ -26,6 +26,7 @@ set_light(0) /obj/machinery/loadout_vendor/update_icon_state() + . = ..() if(is_operational()) icon_state = initial(icon_state) else diff --git a/code/game/objects/machinery/vending/marine_vending.dm b/code/game/objects/machinery/vending/marine_vending.dm index 22ccf856ed8..10a991939f1 100644 --- a/code/game/objects/machinery/vending/marine_vending.dm +++ b/code/game/objects/machinery/vending/marine_vending.dm @@ -880,7 +880,8 @@ . = ..() update_icon() -/obj/machinery/vending/lasgun/update_icon() +/obj/machinery/vending/lasgun/update_icon_state() + . = ..() if(machine_max_charge) switch(machine_current_charge / max(1,machine_max_charge)) if(0.7 to 1) @@ -1556,6 +1557,14 @@ RU TGMC EDIT*/ /obj/item/implanter/chem/blood = -1, /obj/item/implanter/blade = -1, ), + "Assault Vehicle" = list( + /obj/item/armored_weapon = -1, + /obj/item/armored_weapon/ltaap = -1, + /obj/item/armored_weapon/secondary_weapon = -1, + /obj/item/ammo_magazine/tank/ltb_cannon = -1, + /obj/item/ammo_magazine/tank/ltaap_chaingun = -1, + /obj/item/ammo_magazine/tank/secondary_cupola = -1, + ), ) /obj/machinery/vending/valhalla_seasonal_req diff --git a/code/game/objects/machinery/vending/new_marine_vendors.dm b/code/game/objects/machinery/vending/new_marine_vendors.dm index b76d4c78f87..c5eb0725891 100644 --- a/code/game/objects/machinery/vending/new_marine_vendors.dm +++ b/code/game/objects/machinery/vending/new_marine_vendors.dm @@ -41,6 +41,7 @@ set_light(0) /obj/machinery/marine_selector/update_icon_state() + . = ..() if(is_operational()) icon_state = initial(icon_state) else diff --git a/code/game/objects/machinery/vending/quick_vendor.dm b/code/game/objects/machinery/vending/quick_vendor.dm index db2e6553aaa..94e5dedc99e 100644 --- a/code/game/objects/machinery/vending/quick_vendor.dm +++ b/code/game/objects/machinery/vending/quick_vendor.dm @@ -119,6 +119,7 @@ GLOBAL_LIST_INIT(quick_loadouts, init_quick_loadouts()) set_light(0) /obj/machinery/quick_vendor/update_icon_state() + . = ..() if(is_operational()) icon_state = initial(icon_state) else diff --git a/code/game/objects/machinery/vending/vending.dm b/code/game/objects/machinery/vending/vending.dm index 5d530537e72..053d96aec8f 100644 --- a/code/game/objects/machinery/vending/vending.dm +++ b/code/game/objects/machinery/vending/vending.dm @@ -821,6 +821,7 @@ set_light(initial(light_range)) /obj/machinery/vending/update_icon_state() + . = ..() if(machine_stat & BROKEN) icon_state = "[initial(icon_state)]-broken" else if(machine_stat & NOPOWER) diff --git a/code/game/objects/machinery/washing_machine.dm b/code/game/objects/machinery/washing_machine.dm index 30f1aa74230..4f88a539cb5 100644 --- a/code/game/objects/machinery/washing_machine.dm +++ b/code/game/objects/machinery/washing_machine.dm @@ -67,7 +67,8 @@ usr.loc = src.loc -/obj/machinery/washing_machine/update_icon() +/obj/machinery/washing_machine/update_icon_state() + . = ..() icon_state = "wm_[state][panel]" diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 127984fb8dc..2a148ca6235 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -124,7 +124,7 @@ return FALSE if((allow_pass_flags & PASS_MOB)) return TRUE - if((allow_pass_flags & PASS_WALKOVER) && SEND_SIGNAL(target, COMSIG_OBJ_TRY_ALLOW_THROUGH)) + if((allow_pass_flags & PASS_WALKOVER) && SEND_SIGNAL(target, COMSIG_OBJ_TRY_ALLOW_THROUGH, mover)) return TRUE ///Handles extra checks for things trying to exit this objects turf @@ -147,7 +147,7 @@ return COMPONENT_ATOM_BLOCK_EXIT ///Signal handler to check if you can move from one low object to another -/obj/proc/can_climb_over(datum/source) +/obj/proc/can_climb_over(datum/source, atom/mover) SIGNAL_HANDLER if(!(flags_atom & ON_BORDER) && density) return TRUE diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 222fd603576..e34e2c82ff6 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -107,7 +107,8 @@ LINEN BINS . += "There are [amount] bed sheets in the bin." -/obj/structure/bedsheetbin/update_icon() +/obj/structure/bedsheetbin/update_icon_state() + . = ..() switch(amount) if(0) icon_state = "linenbin-empty" diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm index b3b7d817df8..5ab90d2842f 100644 --- a/code/game/objects/structures/bookcase.dm +++ b/code/game/objects/structures/bookcase.dm @@ -57,7 +57,8 @@ qdel(src) -/obj/structure/bookcase/update_icon() +/obj/structure/bookcase/update_icon_state() + . = ..() if(length(contents) < 5) icon_state = "book-[length(contents)]" else diff --git a/code/game/objects/structures/campaign_structures/campaign_structure.dm b/code/game/objects/structures/campaign_structures/campaign_structure.dm index f0b5597afde..96c0e026b27 100644 --- a/code/game/objects/structures/campaign_structures/campaign_structure.dm +++ b/code/game/objects/structures/campaign_structures/campaign_structure.dm @@ -3,6 +3,7 @@ name = "GENERIC CAMPAIGN STRUCTURE" desc = "THIS SHOULDN'T BE VISIBLE" icon = 'icons/obj/structures/campaign_structures.dmi' + flags_atom = CRITICAL_ATOM ///Missions that trigger this landmark to spawn an objective var/list/mission_types ///Campaign structure spawned by this landmark diff --git a/code/game/objects/structures/campaign_structures/capture_objectives.dm b/code/game/objects/structures/campaign_structures/capture_objectives.dm index 1c68a76a20b..6d0fbc4814b 100644 --- a/code/game/objects/structures/campaign_structures/capture_objectives.dm +++ b/code/game/objects/structures/campaign_structures/capture_objectives.dm @@ -148,6 +148,7 @@ countdown.pixel_y = 90 /obj/structure/campaign_objective/capture_objective/sensor_tower/update_icon_state() + . = ..() icon_state = initial(icon_state) if(!owning_faction) switch(capturing_faction) diff --git a/code/game/objects/structures/campaign_structures/deploy_blockers.dm b/code/game/objects/structures/campaign_structures/deploy_blockers.dm index 7e544312cde..e222042b9a5 100644 --- a/code/game/objects/structures/campaign_structures/deploy_blockers.dm +++ b/code/game/objects/structures/campaign_structures/deploy_blockers.dm @@ -11,6 +11,7 @@ desc = "A cutting edge piece of technology designed to disrupt long range bluespace interference in a given radius. The SOM's long range teleporters are unlikely to work here while this is active." density = TRUE anchored = TRUE + flags_atom = CRITICAL_ATOM allow_pass_flags = PASS_PROJECTILE|PASS_AIR destroy_sound = 'sound/effects/meteorimpact.ogg' icon = 'icons/obj/structures/campaign/tele_blocker.dmi' diff --git a/code/game/objects/structures/campaign_structures/destroy_objectives.dm b/code/game/objects/structures/campaign_structures/destroy_objectives.dm index b36a00e85cd..c4c8e855d4b 100644 --- a/code/game/objects/structures/campaign_structures/destroy_objectives.dm +++ b/code/game/objects/structures/campaign_structures/destroy_objectives.dm @@ -260,10 +260,10 @@ switch(status) if(BLUESPACE_CORE_OK) . += image(icon, icon_state = "top_overlay", layer = ABOVE_MOB_LAYER) - . += image(icon, icon_state = "bsd_c_s", layer = TANK_BARREL_LAYER) + . += image(icon, icon_state = "bsd_c_s", layer = ABOVE_MOB_PROP_LAYER) if(BLUESPACE_CORE_UNSTABLE) . += image(icon, icon_state = "top_overlay", layer = ABOVE_MOB_LAYER) - . += image(icon, icon_state = "bsd_c_u", layer = TANK_BARREL_LAYER) + . += image(icon, icon_state = "bsd_c_u", layer = ABOVE_MOB_PROP_LAYER) if(BLUESPACE_CORE_BROKEN) . += image(icon, icon_state = "top_overlay_broken", layer = ABOVE_MOB_LAYER) diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm index 150dbf41212..5d1e929bb7a 100644 --- a/code/game/objects/structures/coathanger.dm +++ b/code/game/objects/structures/coathanger.dm @@ -50,11 +50,11 @@ break -/obj/structure/coatrack/update_icon() - overlays.Cut() +/obj/structure/coatrack/update_overlays() + . = ..() if(istype(coat, /obj/item/clothing/suit/storage/labcoat)) - overlays += image(icon, icon_state = "coat_lab") + . += image(icon, icon_state = "coat_lab") if(istype(coat, /obj/item/clothing/suit/storage/labcoat/cmo)) - overlays += image(icon, icon_state = "coat_cmo") + . += image(icon, icon_state = "coat_cmo") if(istype(coat, /obj/item/clothing/suit/storage/det_suit)) - overlays += image(icon, icon_state = "coat_det") + . += image(icon, icon_state = "coat_det") diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index c66a428a193..05c27ffd7f7 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -316,15 +316,18 @@ else balloon_alert(usr, "Can't do this") -/obj/structure/closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot) - overlays.Cut() +/obj/structure/closet/update_icon_state()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot) + . = ..() if(!opened) icon_state = icon_closed - if(welded) - overlays += image(icon, overlay_welded) else icon_state = icon_opened +/obj/structure/closet/update_overlays() + . = ..() + if(!opened && welded) + . += image(icon, overlay_welded) + /obj/structure/closet/resisted_against(datum/source) container_resist(source) diff --git a/code/game/objects/structures/crates_lockers/closets/coffin.dm b/code/game/objects/structures/crates_lockers/closets/coffin.dm index 8d2413ac236..6a0eab48d6d 100644 --- a/code/game/objects/structures/crates_lockers/closets/coffin.dm +++ b/code/game/objects/structures/crates_lockers/closets/coffin.dm @@ -8,6 +8,7 @@ anchored = FALSE /obj/structure/closet/coffin/update_icon_state() + . = ..() if(!opened) icon_state = icon_closed else diff --git a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm index 9504f2a6639..69449f3b73a 100644 --- a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm +++ b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm @@ -191,7 +191,9 @@ to_chat(user, span_notice("Cabinet unlocked.")) return -/obj/structure/closet/fireaxecabinet/update_icon() //Template: fireaxe[has fireaxe][is opened][hits taken][is smashed]. If you want the opening or closing animations, add "opening" or "closing" right after the numbers +//Template: fireaxe[has fireaxe][is opened][hits taken][is smashed]. If you want the opening or closing animations, add "opening" or "closing" right after the numbers +/obj/structure/closet/fireaxecabinet/update_icon_state() + . = ..() var/hasaxe = 0 if(fireaxe) hasaxe = 1 diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm index 06e05dff086..c4f4a99119a 100644 --- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -9,6 +9,7 @@ AddElement(/datum/element/debris, DEBRIS_WOOD, -10, 5) /obj/structure/closet/cabinet/update_icon_state() + . = ..() if(!opened) icon_state = icon_closed else diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm index c3686b58dc4..92590d29814 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -23,6 +23,7 @@ new /obj/item/reagent_containers/food/drinks/cans/beer( src ) /obj/structure/closet/secure_closet/bar/update_icon_state() + . = ..() if(broken) icon_state = icon_broken return diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index fb8380cacfc..d2ab8412aec 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -8,6 +8,7 @@ icon_off = "fridge1" /obj/structure/closet/secure_closet/freezer/update_icon_state() + . = ..() if(broken) icon_state = icon_broken return diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index 68434d32844..ab112d20391 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -31,7 +31,8 @@ icon_broken = "cabinetdetective_broken" icon_off = "cabinetdetective_broken" -/obj/structure/closet/secure_closet/personal/cabinet/update_icon() +/obj/structure/closet/secure_closet/personal/cabinet/update_icon_state() + . = ..() if(broken) icon_state = icon_broken else diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm index a29102023f1..93618348f5f 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -50,14 +50,17 @@ return togglelock(usr) -/obj/structure/closet/secure_closet/update_icon() - overlays.Cut() +/obj/structure/closet/secure_closet/update_icon_state() + . = ..() if(opened) icon_state = icon_opened else icon_state = locked ? icon_locked : icon_closed + +/obj/structure/closet/secure_closet/update_overlays() + . = ..() if(welded) - overlays += overlay_welded + . += overlay_welded /obj/structure/closet/secure_closet/break_open() broken = TRUE diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 12872e153fd..e91d658cfd0 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -271,7 +271,8 @@ new /obj/item/armor_module/storage/uniform/holster/armpit(src) -/obj/structure/closet/secure_closet/detective/update_icon() +/obj/structure/closet/secure_closet/detective/update_icon_state() + . = ..() if(broken) icon_state = icon_broken else @@ -356,7 +357,8 @@ large = FALSE -/obj/structure/closet/secure_closet/wall/update_icon() +/obj/structure/closet/secure_closet/wall/update_icon_state() + . = ..() if(broken) icon_state = icon_broken else diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm index 58fc58a48db..461263a1d6f 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -78,7 +78,8 @@ new /obj/item/tool/extinguisher(src) new /obj/item/clothing/head/hardhat/red(src) -/obj/structure/closet/firecloset/update_icon() +/obj/structure/closet/firecloset/update_icon_state() + . = ..() if(!opened) icon_state = icon_closed else diff --git a/code/game/objects/structures/crates_lockers/secure_crates.dm b/code/game/objects/structures/crates_lockers/secure_crates.dm index 06f22499cc5..ac69840f78c 100644 --- a/code/game/objects/structures/crates_lockers/secure_crates.dm +++ b/code/game/objects/structures/crates_lockers/secure_crates.dm @@ -17,16 +17,17 @@ . = ..() update_icon() - -/obj/structure/closet/crate/secure/update_icon() - overlays.Cut() +/obj/structure/closet/crate/secure/update_icon_state() + . = ..() if(opened) icon_state = icon_opened else icon_state = locked ? icon_locked : icon_unlocked - if(welded) - overlays += overlay_welded +/obj/structure/closet/crate/secure/update_overlays() + . = ..() + if(welded) + . += overlay_welded /obj/structure/closet/crate/secure/can_open() return !locked diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 70352e706a1..d1e29cdba99 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -24,7 +24,8 @@ */ -/obj/structure/displaycase/update_icon() +/obj/structure/displaycase/update_icon_state() + . = ..() if(destroyed) icon_state = "glassboxb[occupied]" else diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index edb2d65539f..bbbcb99c86d 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -123,7 +123,7 @@ bound_height = width * world.icon_size update_state() -/obj/structure/door_assembly/multi_tile/Move() +/obj/structure/door_assembly/multi_tile/Move(atom/newloc, direction, glide_size_override) . = ..() if(dir in list(EAST, WEST)) bound_width = width * world.icon_size diff --git a/code/game/objects/structures/droppod.dm b/code/game/objects/structures/droppod.dm index 26289ea13af..be4ecce5044 100644 --- a/code/game/objects/structures/droppod.dm +++ b/code/game/objects/structures/droppod.dm @@ -99,6 +99,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi set_light(0) /obj/structure/droppod/update_icon_state() + . = ..() if(drop_state == DROPPOD_ACTIVE) icon_state = initial(icon_state) else if(operation_started && launch_allowed) @@ -378,6 +379,7 @@ GLOBAL_LIST_INIT(blocked_droppod_tiles, typecacheof(list(/turf/open/space/transi return ..() /obj/structure/droppod/nonmob/update_icon_state() + . = ..() if(drop_state == DROPPOD_ACTIVE) icon_state = initial(icon_state) else if(stored_object) diff --git a/code/game/objects/structures/dropship_equipment.dm b/code/game/objects/structures/dropship_equipment.dm index 918e89b11f4..4a6b9188e13 100644 --- a/code/game/objects/structures/dropship_equipment.dm +++ b/code/game/objects/structures/dropship_equipment.dm @@ -506,6 +506,7 @@ update_icon() /obj/structure/dropship_equipment/shuttle/weapon_holder/update_icon_state() + . = ..() if(ship_base) icon_state = deployed_icon_state else @@ -713,7 +714,8 @@ dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE ammo_type_used = CAS_30MM -/obj/structure/dropship_equipment/cas/weapon/heavygun/update_icon() +/obj/structure/dropship_equipment/cas/weapon/heavygun/update_icon_state() + . = ..() if(ammo_equipped) icon_state = "30mm_cannon_loaded[ammo_equipped.ammo_count?"1":"0"]" else @@ -744,7 +746,8 @@ ammo_equipped = null //nothing left to empty after firing update_icon() -/obj/structure/dropship_equipment/cas/weapon/rocket_pod/update_icon() +/obj/structure/dropship_equipment/cas/weapon/rocket_pod/update_icon_state() + . = ..() if(ammo_equipped?.ammo_count) icon_state = "rocket_pod_loaded[ammo_equipped.ammo_id]" else @@ -764,7 +767,8 @@ point_cost = 450 ammo_type_used = CAS_MINI_ROCKET -/obj/structure/dropship_equipment/cas/weapon/minirocket_pod/update_icon() +/obj/structure/dropship_equipment/cas/weapon/minirocket_pod/update_icon_state() + . = ..() if(ammo_equipped?.ammo_count) icon_state = "minirocket_pod_loaded" else @@ -789,7 +793,8 @@ dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE ammo_type_used = CAS_LASER_BATTERY -/obj/structure/dropship_equipment/cas/weapon/laser_beam_gun/update_icon() +/obj/structure/dropship_equipment/cas/weapon/laser_beam_gun/update_icon_state() + . = ..() if(ammo_equipped?.ammo_count) icon_state = "laser_beam_loaded" else @@ -810,7 +815,8 @@ equip_category = DROPSHIP_CREW_WEAPON //fits inside the central spot of the dropship point_cost = 0 -/obj/structure/dropship_equipment/cas/weapon/launch_bay/update_icon() +/obj/structure/dropship_equipment/cas/weapon/launch_bay/update_icon_state() + . = ..() if(ammo_equipped?.ammo_count) icon_state = "launch_bay_loaded" else @@ -857,3 +863,43 @@ deployed_table.layer = ABOVE_OBJ_LAYER + 0.01 //make sure its directly ABOVE the layer deployed_table.loc = loc icon_state = "table2-idle" + +/obj/structure/dropship_equipment/cas/weapon/bomblet_pod + name = "bomblet pod" + icon_state = "bomblet_pod" + desc = "A pnuematic thrower machine capable of up to 40 smaller bombs, generally called 'bomblets'. Moving this will require some sort of lifter." + icon = 'icons/Marine/mainship_props64.dmi' + firing_sound = 'sound/weapons/gunship_rocketpod.ogg' + firing_delay = 0.5 SECONDS + point_cost = 450 + dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE + ammo_type_used = CAS_BOMBLET + +/obj/structure/dropship_equipment/cas/weapon/bomblet_pod/update_icon_state() + . = ..() + if(ammo_equipped?.ammo_count) + icon_state = "bomblet_pod_loaded" + else if(ship_base) + icon_state = "bomblet_pod_installed" + else + icon_state = "bomblet_pod" + +/obj/structure/dropship_equipment/cas/weapon/bomb_pod + name = "bomb pod" + icon_state = "bomb_pod" + desc = "A bomb pod capable of launching several large bombs. Moving this will require some sort of lifter." + icon = 'icons/Marine/mainship_props64.dmi' + firing_sound = 'sound/weapons/gunship_rocketpod.ogg' + firing_delay = 2 SECONDS + point_cost = 450 + dropship_equipment_flags = USES_AMMO|IS_WEAPON|IS_INTERACTABLE + ammo_type_used = CAS_BOMB + +/obj/structure/dropship_equipment/cas/weapon/bomb_pod/update_icon_state() + . = ..() + if(ammo_equipped?.ammo_count) + icon_state = "bomb_pod_loaded" + else if(ship_base) + icon_state = "bomb_pod_installed" + else + icon_state = "bomb_pod" diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 97b19ed104a..861b1048969 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -58,12 +58,14 @@ opened = !opened update_icon() -/obj/structure/extinguisher_cabinet/update_icon() - overlays.Cut() +/obj/structure/extinguisher_cabinet/update_icon_state() + . = ..() icon_state = "[initial(icon_state)][opened]" +/obj/structure/extinguisher_cabinet/update_overlays() + . = ..() if(opened && has_extinguisher) - overlays += "extinguishero_[has_extinguisher.sprite_name]" + . += "extinguishero_[has_extinguisher.sprite_name]" /obj/structure/extinguisher_cabinet/mini starter_extinguisher = /obj/item/tool/extinguisher/mini diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index aef8e44d5f0..8dccd13526e 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -340,6 +340,7 @@ /obj/structure/girder/update_icon_state() + . = ..() switch(girder_state) if(GIRDER_BROKEN, GIRDER_BROKEN_PATCHED) icon = 'icons/obj/smooth_objects/girder_broke.dmi' diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index bfb07c51cf2..27de1ee757d 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -52,6 +52,7 @@ return ..() /obj/structure/ladder/update_icon_state() + . = ..() if(up && down) icon_state = "ladder11" diff --git a/code/game/objects/structures/lamarr_cage.dm b/code/game/objects/structures/lamarr_cage.dm index c3d25dadd31..3e83aed5577 100644 --- a/code/game/objects/structures/lamarr_cage.dm +++ b/code/game/objects/structures/lamarr_cage.dm @@ -55,5 +55,5 @@ stat = DEAD -/obj/item/clothing/mask/facehugger/lamarr/update_icon() +/obj/item/clothing/mask/facehugger/lamarr/update_icon_state() return diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 042c19e00b2..b19e279b6ce 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -75,7 +75,8 @@ update_icon() addtimer(VARSET_CALLBACK(src, switching_states, FALSE), 1 SECONDS) -/obj/structure/mineral_door/update_icon() +/obj/structure/mineral_door/update_icon_state() + . = ..() if(open) icon_state = "[base_icon_state][smoothing_flags ? "-[smoothing_junction]" : ""]-open" else diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index dcbe282aa85..ba875f9a7ae 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -23,7 +23,8 @@ QDEL_NULL(connected) return ..() -/obj/structure/morgue/update_icon() +/obj/structure/morgue/update_icon_state() + . = ..() if (morgue_open) icon_state = "[morgue_type]0" else @@ -173,11 +174,9 @@ /obj/structure/morgue/crematorium/update_icon() + . = ..() if(cremating) icon_state = "[morgue_type]_active" - else - ..() - /obj/structure/morgue/crematorium/proc/cremate(mob/user) set waitfor = 0 diff --git a/code/game/objects/structures/orbital_cannon.dm b/code/game/objects/structures/orbital_cannon.dm index d5b514ba4bb..d5183e38918 100644 --- a/code/game/objects/structures/orbital_cannon.dm +++ b/code/game/objects/structures/orbital_cannon.dm @@ -45,6 +45,7 @@ return ..() /obj/structure/orbital_cannon/update_icon_state() + . = ..() if(chambered_tray) icon_state = "OBC_chambered" return diff --git a/code/game/objects/structures/prop.dm b/code/game/objects/structures/prop.dm index fe0cf7f4843..b22640e2060 100644 --- a/code/game/objects/structures/prop.dm +++ b/code/game/objects/structures/prop.dm @@ -67,6 +67,7 @@ set_light(initial(light_range)) /obj/machinery/prop/computer/update_icon_state() + . = ..() if(machine_stat & (BROKEN|DISABLED)) icon_state = "[initial(icon_state)]_broken" else @@ -1086,7 +1087,7 @@ ///BROKEN VEHICLE PROPS /obj/structure/prop/vehicle - layer = TANK_BARREL_LAYER + layer = ABOVE_MOB_PROP_LAYER /obj/structure/prop/vehicle/van name = "van" desc = "An old van, seems to be broken down." @@ -1234,7 +1235,7 @@ /obj/structure/prop/vehicle/tank/east/barrel icon_state = "ltb_cannon_0" - layer = TANK_BARREL_LAYER + layer = ABOVE_MOB_PROP_LAYER mouse_opacity = MOUSE_OPACITY_TRANSPARENT /obj/structure/prop/vehicle/tank/east/barrel/broken diff --git a/code/game/objects/structures/razorwire.dm b/code/game/objects/structures/razorwire.dm index 0489da55955..118dcba90c4 100644 --- a/code/game/objects/structures/razorwire.dm +++ b/code/game/objects/structures/razorwire.dm @@ -200,6 +200,7 @@ return ..() /obj/structure/razorwire/update_icon_state() + . = ..() var/health_percent = round(obj_integrity/max_integrity * 100) var/remaining = CEILING(health_percent, 25) icon_state = "[base_icon_state]_[remaining]" diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index dc1a7805214..a7e977f1c64 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -96,6 +96,7 @@ FLOOR SAFES /obj/structure/safe/update_icon_state() + . = ..() if(open) icon_state = "[initial(icon_state)]-open" else diff --git a/code/game/objects/structures/sensor_tower.dm b/code/game/objects/structures/sensor_tower.dm index 351b017ff77..84a233b893f 100644 --- a/code/game/objects/structures/sensor_tower.dm +++ b/code/game/objects/structures/sensor_tower.dm @@ -36,6 +36,7 @@ update_icon() /obj/structure/sensor_tower/update_icon_state() + . = ..() icon_state = initial(icon_state) if(current_timer || activated) icon_state += "_tgmc" diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 0ff1c7b76f9..6434af0260e 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -28,6 +28,7 @@ icon_state = "bunkbed" /obj/structure/bed/update_icon_state() + . = ..() if(!base_bed_icon) return if(LAZYLEN(buckled_mobs) || buckled_bodybag) @@ -61,6 +62,10 @@ if(HAS_TRAIT(unbuckled_target, TRAIT_FLOORED)) unbuckled_target.set_lying_angle(pick(90, 270)) +/obj/structure/bed/set_glide_size(target = 8) + . = ..() + buckled_bodybag?.set_glide_size(target) + //Unsafe proc /obj/structure/bed/proc/buckle_bodybag(obj/structure/closet/bodybag/B, mob/user) if(buckled_bodybag || buckled) @@ -101,7 +106,7 @@ /obj/structure/bed/Moved(atom/old_loc, movement_dir, forced, list/old_locs) . = ..() - if(!buckled_bodybag || buckled_bodybag.Move(loc, movement_dir)) + if(!buckled_bodybag || buckled_bodybag.Move(loc, movement_dir, glide_size)) return TRUE forceMove(buckled_bodybag.loc) return FALSE @@ -327,14 +332,14 @@ GLOBAL_LIST_EMPTY(activated_medevac_stretchers) linked_beacon.remove_stretcher(src) return ..() -/obj/structure/bed/medevac_stretcher/update_icon() - ..() - overlays.Cut() +/obj/structure/bed/medevac_stretcher/update_overlays() + . = ..() + if(stretcher_activated) - overlays += image("beacon_active_[density ? "up":"down"]") + . += image("beacon_active_[density ? "up":"down"]") if(LAZYLEN(buckled_mobs) || buckled_bodybag) - overlays += image("icon_state"="stretcher_box","layer"=LYING_MOB_LAYER + 0.1) + . += image("icon_state"="stretcher_box","layer"=LYING_MOB_LAYER + 0.1) /obj/structure/bed/medevac_stretcher/verb/activate_medevac_displacer() set name = "Activate Medevac Displacement Field" diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 750507bcd1e..7b8f212396f 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -279,7 +279,7 @@ var/is_animating = 0 /obj/structure/bed/chair/dropship/passenger/CanAllowThrough(atom/movable/mover, turf/target, height = 0, air_group = 0) - if(chair_state == DROPSHIP_CHAIR_UNFOLDED && istype(mover, /obj/vehicle/multitile) && !is_animating) + if(chair_state == DROPSHIP_CHAIR_UNFOLDED && istype(mover, /obj/vehicle/sealed) && !is_animating) visible_message(span_danger("[mover] slams into [src] and breaks it!")) INVOKE_ASYNC(src, PROC_REF(fold_down), TRUE) return FALSE diff --git a/code/game/objects/structures/supplypod.dm b/code/game/objects/structures/supplypod.dm index c6777312b2d..ecd56aa50f7 100644 --- a/code/game/objects/structures/supplypod.dm +++ b/code/game/objects/structures/supplypod.dm @@ -76,15 +76,16 @@ GLOBAL_LIST_INIT(pod_styles, list(\ setStyle(style, TRUE) -/obj/structure/closet/supplypod/update_icon() - cut_overlays() +/obj/structure/closet/supplypod/update_overlays() + . = ..() + if(style == STYLE_SEETHROUGH || style == STYLE_INVISIBLE) return if(opened) - add_overlay("[icon_state]_open") + . += "[icon_state]_open" else - add_overlay("[icon_state]_door") + . += "[icon_state]_door" /obj/structure/closet/supplypod/proc/setStyle(chosenStyle, duringInit = FALSE) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index bba3588ba35..f7535e509da 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -76,7 +76,8 @@ visible_message(span_danger("[O] plows straight through [src]!")) deconstruct(FALSE) -/obj/structure/table/update_icon() +/obj/structure/table/update_icon_state() + . = ..() if(flipped) var/ttype = 0 var/tabledirs = 0 diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index 30052da2a34..b51a7409de2 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -24,14 +24,18 @@ update_icon() -/obj/structure/dispenser/update_icon() - overlays.Cut() +/obj/structure/dispenser/update_overlays() + . = ..() switch(oxygentanks) - if(1 to 3) overlays += "oxygen-[oxygentanks]" - if(4 to INFINITY) overlays += "oxygen-4" + if(1 to 3) + . += "oxygen-[oxygentanks]" + if(4 to INFINITY) + . += "oxygen-4" switch(phorontanks) - if(1 to 4) overlays += "phoron-[phorontanks]" - if(5 to INFINITY) overlays += "phoron-5" + if(1 to 4) + . += "phoron-[phorontanks]" + if(5 to INFINITY) + . += "phoron-5" /obj/structure/dispenser/interact(mob/user) . = ..() diff --git a/code/game/objects/structures/teleporter.dm b/code/game/objects/structures/teleporter.dm index b7b91ec5740..5837435ceec 100644 --- a/code/game/objects/structures/teleporter.dm +++ b/code/game/objects/structures/teleporter.dm @@ -139,6 +139,7 @@ update_icon() /obj/machinery/deployable/teleporter/update_icon_state() + . = ..() var/obj/item/teleporter_kit/kit = get_internal_item() if(powered() || kit?.cell?.charge > TELEPORTING_COST) icon_state = default_icon_state + "_on" diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index e91eb1a09b4..4afe14b3385 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -46,7 +46,8 @@ open = !open update_icon() -/obj/structure/toilet/update_icon() +/obj/structure/toilet/update_icon_state() + . = ..() icon_state = "toilet[open][cistern]" /obj/structure/toilet/attackby(obj/item/I, mob/user, params) @@ -114,7 +115,8 @@ /obj/structure/toilet/alternate icon_state = "toilet200" -/obj/structure/toilet/alternate/update_icon() +/obj/structure/toilet/alternate/update_icon_state() + . = ..() icon_state = "toilet2[open][cistern]" /obj/structure/urinal @@ -189,7 +191,7 @@ if(.) return on = !on - update_icon() + update_mist() if(on) start_processing() if (user.loc == loc) @@ -221,8 +223,9 @@ watertemp = "normal" user.visible_message(span_notice("[user] adjusts the shower with \the [I]."), span_notice("You adjust the shower with \the [I].")) -/obj/machinery/shower/update_icon() //this is terribly unreadable, but basically it makes the shower mist up - overlays.Cut() //once it's been on for a while, in addition to handling the water overlay. +/obj/machinery/shower/proc/update_mist() +//this is terribly unreadable, but basically it makes the shower mist up once it's been on for a while + update_icon() if(mymist) qdel(mymist) mymist = null @@ -248,6 +251,11 @@ mymist = null ismist = FALSE +/obj/machinery/shower/update_overlays() + . = ..() + if(on) + . += image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir) + /obj/machinery/shower/proc/on_cross(datum/source, atom/movable/O, oldloc, oldlocs) SIGNAL_HANDLER wash(O) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 0e04738990e..1c5a90454ce 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -47,6 +47,7 @@ update_icon() /obj/structure/windoor_assembly/update_icon_state() + . = ..() icon_state = "[facing]_[secure]windoor_assembly[state]" /obj/structure/windoor_assembly/attackby(obj/item/I, mob/user, params) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index ae5a47265a0..586cd78d0b2 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -263,9 +263,8 @@ INVOKE_NEXT_TICK(W, TYPE_PROC_REF(/atom/movable, update_icon)) //merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm) -/obj/structure/window/update_icon() - //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong. - //this way it will only update full-tile ones +/obj/structure/window/update_icon_state() + . = ..() if(!src) return if(!is_full_window()) @@ -408,7 +407,7 @@ reinf = TRUE flags_atom = NONE -/obj/structure/window/shuttle/update_icon() //icon_state has to be set manually +/obj/structure/window/shuttle/update_icon_state() return //Framed windows @@ -437,10 +436,8 @@ /obj/structure/window/framed/update_nearby_icons() QUEUE_SMOOTH_NEIGHBORS(src) -/obj/structure/window/framed/update_icon() - QUEUE_SMOOTH(src) - - +/obj/structure/window/framed/update_icon_state() + QUEUE_SMOOTH(src) //we update icon state through the smoothing system exclusively /obj/structure/window/framed/deconstruct(disassembled = TRUE, leave_frame = TRUE) if(window_frame && leave_frame) diff --git a/code/game/objects/structures/window_frame.dm b/code/game/objects/structures/window_frame.dm index db57f76bbef..a61ddd36b7e 100644 --- a/code/game/objects/structures/window_frame.dm +++ b/code/game/objects/structures/window_frame.dm @@ -49,6 +49,7 @@ /obj/structure/window_frame/update_icon() QUEUE_SMOOTH(src) + return ..() /obj/structure/window_frame/Destroy() density = FALSE diff --git a/code/game/sound.dm b/code/game/sound.dm index 330421670ea..3c908ca82a0 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -62,18 +62,27 @@ A good representation is: 'byond applies a volume reduction to the sound every X frequency = GET_RANDOM_FREQ // Same frequency for everybody // Looping through the player list has the added bonus of working for mobs inside containers var/sound/S = sound(get_sfx(soundin)) - for(var/i in GLOB.player_list) - var/mob/M = i - if(!M.client) + for(var/mob/M AS in GLOB.player_list|GLOB.aiEyes) + if(!M.client && !istype(M, /mob/camera/aiEye)) continue var/turf/T = get_turf(M) if(!T || T.z != turf_source.z || get_dist(M, turf_source) > sound_range) continue M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, S) + for(var/obj/vehicle/sealed/armored/armor AS in GLOB.tank_list) + if(!armor.interior || armor.z != turf_source.z || get_dist(armor, turf_source) > sound_range) + continue + for(var/mob/living/crew AS in armor.occupants) + //turf source is null on purpose because it will not work properly since crew is on a different z + crew.playsound_local(null, soundin, vol*0.5, vary, frequency, falloff, is_global, channel, S, sound_reciever = crew) + + //todo rename S to sound_to_use -/mob/proc/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1) - if(!client) +/mob/proc/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1, mob/sound_reciever) + if(!sound_reciever) + sound_reciever = src + if(!sound_reciever.client) return FALSE if(!S) @@ -108,10 +117,10 @@ A good representation is: 'byond applies a volume reduction to the sound every X if(!is_global) S.environment = SOUND_ENVIRONMENT_ROOM - SEND_SOUND(src, S) + SEND_SOUND(sound_reciever, S) -/mob/living/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1) +/mob/living/playsound_local(turf/turf_source, soundin, vol, vary, frequency, falloff, is_global, channel = 0, sound/S, distance_multiplier = 1, mob/sound_reciever) if(ear_deaf > 0) return FALSE return ..() diff --git a/code/game/turfs/floor.dm b/code/game/turfs/floor.dm index d076baca927..67937079490 100644 --- a/code/game/turfs/floor.dm +++ b/code/game/turfs/floor.dm @@ -59,6 +59,7 @@ return W /turf/open/floor/update_icon_state() + . = ..() if(broken) icon_state = broken_states() else if(burnt) diff --git a/code/game/turfs/open_ground.dm b/code/game/turfs/open_ground.dm index 679b0c6bf99..8854410f7e0 100644 --- a/code/game/turfs/open_ground.dm +++ b/code/game/turfs/open_ground.dm @@ -8,9 +8,10 @@ var/icon_variants = 1 /turf/open/ground/update_icon_state() + . = ..() if(icon_variants < 2) - return initial(icon_state) - return "[initial(icon_state)]_[rand(1, icon_variants)]" + icon_state = initial(icon_state) + icon_state = "[initial(icon_state)]_[rand(1, icon_variants)]" /turf/open/ground/AfterChange() . = ..() diff --git a/code/game/turfs/snow.dm b/code/game/turfs/snow.dm index d139db68722..c609e73f34a 100644 --- a/code/game/turfs/snow.dm +++ b/code/game/turfs/snow.dm @@ -16,12 +16,14 @@ /turf/open/floor/plating/ground/snow/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_ATOM_ACIDSPRAY_ACT, PROC_REF(acidspray_act)) - update_icon(TRUE,TRUE) //Update icon and sides on start, but skip nearby check for turfs. + update_appearance() + update_sides() // Melting snow /turf/open/floor/plating/ground/snow/fire_act(exposed_temperature, exposed_volume) slayer = 0 - update_icon(TRUE, FALSE) + update_appearance() + update_sides() //Xenos digging up snow /turf/open/floor/plating/ground/snow/attack_alien(mob/living/carbon/xenomorph/M, damage_amount = M.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE) @@ -46,7 +48,8 @@ M.visible_message(span_notice("\The [M] clears out \the [src]."), \ span_notice("We clear out \the [src]."), null, 5) slayer = 0 - update_icon(TRUE, FALSE) + update_appearance() + update_sides() //PLACING/REMOVING/BUILDING /turf/open/floor/plating/ground/snow/attackby(obj/item/I, mob/user, params) @@ -79,14 +82,13 @@ var/mob/living/carbon/xenomorph/xeno = arrived if(xeno.is_charging >= CHARGE_ON) // chargers = snow plows slayer = 0 - update_icon(TRUE, FALSE) + update_appearance() + update_sides() return ..() -//Update icon -/turf/open/floor/plating/ground/snow/update_icon(update_full, skip_sides) - icon_state = "snow_[slayer]" - setDir(pick(GLOB.alldirs)) +/turf/open/floor/plating/ground/snow/update_name(updates) + . = ..() switch(slayer) if(0) name = "dirt floor" @@ -97,53 +99,56 @@ if(3) name = "very deep [initial(name)]" - //Update the side overlays - if(update_full) - var/turf/open/T - if(!skip_sides) - for(var/dirn in GLOB.alldirs) - var/turf/open/floor/plating/ground/snow/D = get_step(src,dirn) - if(istype(D)) - //Update turfs that are near us, but only once - D.update_icon(TRUE, TRUE) - - overlays.Cut() - - for(var/dirn in GLOB.alldirs) - T = get_step(src, dirn) - if(istype(T)) - if(slayer > T.slayer && T.slayer < 1) - var/image/I = new('icons/turf/snow2.dmi', "snow_[(dirn & (dirn-1)) ? "outercorner" : pick("innercorner", "outercorner")]", dir = dirn) - switch(dirn) - if(NORTH) - I.pixel_y = 32 - if(SOUTH) - I.pixel_y = -32 - if(EAST) - I.pixel_x = 32 - if(WEST) - I.pixel_x = -32 - if(NORTHEAST) - I.pixel_x = 32 - I.pixel_y = 32 - if(SOUTHEAST) - I.pixel_x = 32 - I.pixel_y = -32 - if(NORTHWEST) - I.pixel_x = -32 - I.pixel_y = 32 - if(SOUTHWEST) - I.pixel_x = -32 - I.pixel_y = -32 - - I.layer = layer + 0.001 + slayer * 0.0001 - overlays += I +/turf/open/floor/plating/ground/snow/update_overlays() + . = ..() + for(var/dirn in GLOB.alldirs) + var/turf/open/T = get_step(src, dirn) + if(!isopenturf(T)) + continue + if(slayer > T.slayer && T.slayer < 1) + var/image/I = new('icons/turf/snow2.dmi', "snow_[(dirn & (dirn-1)) ? "outercorner" : pick("innercorner", "outercorner")]", dir = dirn) + switch(dirn) + if(NORTH) + I.pixel_y = 32 + if(SOUTH) + I.pixel_y = -32 + if(EAST) + I.pixel_x = 32 + if(WEST) + I.pixel_x = -32 + if(NORTHEAST) + I.pixel_x = 32 + I.pixel_y = 32 + if(SOUTHEAST) + I.pixel_x = 32 + I.pixel_y = -32 + if(NORTHWEST) + I.pixel_x = -32 + I.pixel_y = 32 + if(SOUTHWEST) + I.pixel_x = -32 + I.pixel_y = -32 + + I.layer = layer + 0.001 + slayer * 0.0001 + . += I + +/turf/open/floor/plating/ground/snow/update_icon_state() + . = ..() + icon_state = "snow_[slayer]_[rand(1,8)]" +///Fully update all the turfs around us +/turf/open/floor/plating/ground/snow/proc/update_sides() + for(var/dirn in GLOB.alldirs) + var/turf/open/floor/plating/ground/snow/D = get_step(src,dirn) + if(istype(D)) + //Update turfs that are near us, but only once + D.update_appearance(ALL) /turf/open/floor/plating/ground/snow/ex_act(severity) if(slayer && prob(severity / 5)) slayer = rand(0, 3) - update_icon(TRUE, FALSE) + update_appearance() + update_sides() return ..() //Fire act; fire now melts snow as it should; fire beats ice @@ -159,7 +164,8 @@ if(25 to INFINITY) slayer = 0 - update_icon(TRUE, FALSE) + update_appearance() + update_sides() /turf/open/floor/plating/ground/snow/proc/acidspray_act() SIGNAL_HANDLER diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index f0b8f5c2f55..7c889a5ef23 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -94,6 +94,12 @@ playsound(src, 'sound/effects/metal_crash.ogg', 35, 1) deconstruct(FALSE) +/obj/vehicle/sealed/armored/multitile/handle_airdrop(turf/target) + . = ..() + ex_act(2000) //Destroy it + cell_explosion(target, 300, 100) + flame_radius(6, target) + /obj/structure/closet/handle_airdrop(turf/target_turf) // good idea but no if(!opened) break_open() @@ -145,9 +151,11 @@ transform = turn(matrix(), get_transit_angle(src)) /turf/open/space/transit/update_icon_state() + . = ..() icon_state = "speedspace_ns_[get_transit_state(src, available_icon_state_amounts)]" /turf/open/space/transit/atmos/update_icon_state() + . = ..() icon_state = "Cloud_[get_transit_state(src, available_icon_state_amounts)]" /proc/get_transit_state(turf/T, available_icon_state_amounts) diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm index 61d19f73926..5395bee4d80 100644 --- a/code/game/turfs/walls/walls.dm +++ b/code/game/turfs/walls/walls.dm @@ -11,15 +11,27 @@ soft_armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0) var/wall_integrity var/max_integrity = 1000 //Wall will break down to girders if damage reaches this point - var/damage_overlay + var/global/damage_overlays[8] - var/current_bulletholes = 0 - var/bullethole_increment = 1 - var/bullethole_state = 0 - var/image/bullethole_overlay + + base_icon_state = "metal" + var/max_temperature = 1800 //K, walls will take damage if they're next to a fire hotter than this var/d_state = 0 //Normal walls are now as difficult to remove as reinforced walls var/obj/effect/acid_hole/acided_hole //the acid hole inside the wall + + ///The current number of bulletholes in this turf + var/current_bulletholes = 0 + ///A reference to the current bullethole overlay image, this is added and deleted as needed + var/image/bullethole_overlay + /** + * The variation set we're using + * There are 10 sets and it gets picked randomly the first time a wall is shot + * It corresponds to the first number in the icon_state (bhole_[**bullethole_variation**]_[current_bulletholes]) + * Gets reset to 0 if the wall reaches maximum health, so a new variation is picked when the wall gets shot again + */ + var/bullethole_variation = 0 + smoothing_flags = SMOOTH_BITMASK smoothing_groups = list( SMOOTH_GROUP_CLOSED_TURFS, @@ -48,6 +60,11 @@ visible_message(span_warning("\The [M] is sealed inside the wall as it is built")) qdel(M) +/turf/closed/wall/Destroy(force) + QDEL_NULL(acided_hole) + QDEL_NULL(bullethole_overlay) + return ..() + /turf/closed/wall/ChangeTurf(newtype) if(acided_hole) qdel(acided_hole) @@ -132,70 +149,34 @@ if(7) . += span_info("The inner sheath is gone. A blowtorch should finish off this wall.") -#define BULLETHOLE_STATES 10 //How many variations of bullethole patterns there are -#define BULLETHOLE_MAX 8 * 3 //Maximum possible bullet holes. -//Formulas. These don't need to be defines, but helpful green. Should likely reuse these for a base 8 icon system. -#define cur_increment(v) round((v-1)/8)+1 -#define base_dir(v,i) v-(i-1)*8 -#define cur_dir(v) round(v+round(v)/3) +/turf/closed/wall/update_overlays() + . = ..() + if(wall_integrity == max_integrity) + current_bulletholes = 0 + bullethole_variation = 0 + QDEL_NULL(bullethole_overlay) + return -/turf/closed/wall/update_icon() if(!damage_overlays[1]) //list hasn't been populated - generate_overlays() - - if(wall_integrity == max_integrity) //If the thing was healed for damage; otherwise update_icon() won't run at all, unless it was strictly damaged. - overlays.Cut() - damage_overlay = initial(damage_overlay) - current_bulletholes = initial(current_bulletholes) - bullethole_increment = initial(current_bulletholes) - bullethole_state = initial(current_bulletholes) - qdel(bullethole_overlay) - bullethole_overlay = null - return + var/alpha_inc = 256 / length(damage_overlays) - var/overlay = round((max_integrity - wall_integrity) / max_integrity * length(damage_overlays)) + 1 - if(overlay > length(damage_overlays)) overlay = length(damage_overlays) + for(var/i = 1; i <= length(damage_overlays); i++) + var/image/img = image(icon = 'icons/turf/walls.dmi', icon_state = "overlay_damage") + img.blend_mode = BLEND_MULTIPLY + img.alpha = (i * alpha_inc) - 1 + damage_overlays[i] = img - if(!damage_overlay || overlay != damage_overlay) - overlays -= damage_overlays[damage_overlay] - damage_overlay = overlay - overlays += damage_overlays[damage_overlay] + var/overlay = round((max_integrity - wall_integrity) / max_integrity * length(damage_overlays)) + 1 + if(overlay > length(damage_overlays)) + overlay = length(damage_overlays) - if(current_bulletholes > BULLETHOLE_MAX) //Could probably get away with a unique layer, but let's keep it standardized. - overlays -= bullethole_overlay //We need this to be the top layer, no matter what, but only if the layer is at max bulletholes. - overlays += bullethole_overlay + . += damage_overlays[overlay] if(current_bulletholes && current_bulletholes <= BULLETHOLE_MAX) - overlays -= bullethole_overlay - if(!bullethole_overlay) - bullethole_state = rand(1, BULLETHOLE_STATES) - bullethole_overlay = image('icons/effects/bulletholes.dmi', src, "bhole_[bullethole_state]_[bullethole_increment]") - //for(var/mob/M in view(7)) to_chat(M, bullethole_overlay) - if(cur_increment(current_bulletholes) > bullethole_increment) bullethole_overlay.icon_state = "bhole_[bullethole_state]_[++bullethole_increment]" - - var/base_direction = base_dir(current_bulletholes,bullethole_increment) - var/current_direction = cur_dir(base_direction) - setDir(current_direction) - /*Hack. Image overlays behave as the parent object, so that means they are also attached to it and follow its directional. - Luckily, it doesn't matter what direction the walls are set to, they link together via icon_state it seems. - But I haven't thoroughly tested it.*/ - overlays += bullethole_overlay - //to_chat(world, span_debuginfo("Increment: [bullethole_increment], Direction: [current_direction]")) - -#undef BULLETHOLE_STATES -#undef BULLETHOLE_MAX -#undef cur_increment -#undef base_dir -#undef cur_dir - -/turf/closed/wall/proc/generate_overlays() - var/alpha_inc = 256 / length(damage_overlays) - - for(var/i = 1; i <= length(damage_overlays); i++) - var/image/img = image(icon = 'icons/turf/walls.dmi', icon_state = "overlay_damage") - img.blend_mode = BLEND_MULTIPLY - img.alpha = (i * alpha_inc) - 1 - damage_overlays[i] = img + if(!bullethole_variation) + bullethole_variation = rand(1, BULLETHOLE_STATES) + bullethole_overlay = image('icons/effects/bulletholes.dmi', src, "bhole_[bullethole_variation]_[current_bulletholes]") + . += bullethole_overlay ///Applies damage to the wall /turf/closed/wall/proc/take_damage(damage_amount, damage_type = BRUTE, damage_flag = MELEE, armour_penetration = 0) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 9f6dfcfa750..4a11bd85bcc 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -1213,11 +1213,11 @@ if(!check_rights(R_ADMIN)) return - for(var/obj/vehicle/multitile/root/cm_armored/CA AS in GLOB.tank_list) - CA.remove_all_players() + for(var/obj/vehicle/sealed/armored/armor AS in GLOB.tank_list) + armor.dump_mobs(TRUE) - log_admin("[key_name(usr)] forcibly removed all players from [CA].") - message_admins("[ADMIN_TPMONTY(usr)] forcibly removed all players from [CA].") + log_admin("[key_name(usr)] forcibly removed all players from [armor].") + message_admins("[ADMIN_TPMONTY(usr)] forcibly removed all players from [armor].") /// Admin verb to delete a squad completely /datum/admins/proc/delete_squad() diff --git a/code/modules/admin/fun_verbs.dm b/code/modules/admin/fun_verbs.dm index 6824df9e03c..466c719cb5a 100644 --- a/code/modules/admin/fun_verbs.dm +++ b/code/modules/admin/fun_verbs.dm @@ -1174,15 +1174,15 @@ if("Low gravity") to_chat(GLOB.mob_living_list, span_highdanger("You feel gravity pull gently at you.")) for(var/mob/living/living_mob AS in GLOB.mob_living_list) - living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 32, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_DEFENSIVE_STRUCTURE) + living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 32, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_DEFENSIVE_STRUCTURE|PASS_TANK) if("John Woo") to_chat(GLOB.mob_living_list, span_highdanger("You feel gravity grow weak, and the urge to fly.")) for(var/mob/living/living_mob AS in GLOB.mob_living_list) - living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 48, sound = "jump", flags = JUMP_SPIN, flags_pass = HOVERING|PASS_PROJECTILE) + living_mob.set_jump_component(duration = 1 SECONDS, cooldown = 1.5 SECONDS, cost = 2, height = 48, sound = "jump", flags = JUMP_SPIN, flags_pass = HOVERING|PASS_PROJECTILE|PASS_TANK) if("Exceeding orbital velocity") to_chat(GLOB.mob_living_list, span_highdanger("You feel gravity fade to nothing. Will you even come back down?")) for(var/mob/living/living_mob AS in GLOB.mob_living_list) - living_mob.set_jump_component(duration = 4 SECONDS, cooldown = 6 SECONDS, cost = 0, height = 128, sound = "jump", flags = JUMP_SPIN, flags_pass = HOVERING|PASS_PROJECTILE) + living_mob.set_jump_component(duration = 4 SECONDS, cooldown = 6 SECONDS, cost = 0, height = 128, sound = "jump", flags = JUMP_SPIN, flags_pass = HOVERING|PASS_PROJECTILE|PASS_TANK) else return diff --git a/code/modules/admin/smites/puzzle.dm b/code/modules/admin/smites/puzzle.dm index e08425d972d..065c714d6ea 100644 --- a/code/modules/admin/smites/puzzle.dm +++ b/code/modules/admin/smites/puzzle.dm @@ -215,8 +215,8 @@ var/obj/effect/sliding_puzzle/source var/icon/puzzle_icon -/obj/structure/puzzle_element/Move(nloc, dir) - if(!isturf(nloc) || (dir - 1) & dir || get_dist(get_step(src,dir),get_turf(source)) > 1) +/obj/structure/puzzle_element/Move(atom/newloc, direction, glide_size_override) + if(!isturf(newloc) || (dir - 1) & dir || get_dist(get_step(src,dir),get_turf(source)) > 1) return 0 else return ..() diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm index cd985279eda..3e019efc78c 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm @@ -85,7 +85,10 @@ return min(arglist(args)) /proc/_new(type, arguments) - return new type (arglist(arguments)) + var/datum/result = new type(arglist(arguments)) + if(istype(result)) + result.datum_flags |= DF_VAR_EDITED + return result /proc/_num2text(N, SigFig = 6) return num2text(N, SigFig) diff --git a/code/modules/ai/ai_behaviors/xeno/xeno_illusion.dm b/code/modules/ai/ai_behaviors/xeno/xeno_illusion.dm index 15fd8b627f5..d724d679da7 100644 --- a/code/modules/ai/ai_behaviors/xeno/xeno_illusion.dm +++ b/code/modules/ai/ai_behaviors/xeno/xeno_illusion.dm @@ -86,5 +86,5 @@ . = ..() if(.) return INITIALIZE_HINT_QDEL - add_movespeed_modifier(MOVESPEED_ID_XENO_CASTE_SPEED, TRUE, 0, NONE, FALSE, original_mob.xeno_caste.speed * pick(0.9, 1, 1.1, 1.2, 1.3)) // rand doesn't work here because it's decimals + add_movespeed_modifier(MOVESPEED_ID_XENO_CASTE_SPEED, TRUE, 0, NONE, TRUE, MOB_RUN_MOVE_MOD + original_mob.xeno_caste.speed * pick(0.9, 1, 1.1, 1.2, 1.3)) // rand doesn't work here because it's decimals AddComponent(/datum/component/ai_controller, /datum/ai_behavior/xeno/illusion, escorted_atom) diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index 9a5dd95b76d..3448e5d5d71 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -45,24 +45,24 @@ A.holder_movement() -/obj/item/assembly_holder/update_icon() - cut_overlays() +/obj/item/assembly_holder/update_overlays() + . = ..() if(a_left) - add_overlay("[a_left.icon_state]_left") + . += "[a_left.icon_state]_left" for(var/O in a_left.attached_overlays) - add_overlay("[O]_l") + . += "[O]_l" if(a_right) if(a_right.is_position_sensitive) - add_overlay("[a_right.icon_state]_right") + . += "[a_right.icon_state]_right" for(var/O in a_right.attached_overlays) - add_overlay("[O]_r") + . += "[O]_r" else var/mutable_appearance/right = mutable_appearance(icon, "[a_right.icon_state]_left") right.transform = matrix(-1, 0, 0, 0, 1, 0) for(var/O in a_right.attached_overlays) right.add_overlay("[O]_l") - add_overlay(right) + . += right if(master) master.update_icon() diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 20e961ead70..123774de124 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -57,16 +57,18 @@ update_icon() return secured -/obj/item/assembly/infra/update_icon() - cut_overlays() +/obj/item/assembly/infra/update_overlays() + . = ..() attached_overlays = list() if(on) - add_overlay("infrared_on") + . += "infrared_on" attached_overlays += "infrared_on" if(visible && secured) - add_overlay("infrared_visible") + . += "infrared_visible" attached_overlays += "infrared_visible" +/obj/item/assembly/infra/update_icon() + . = ..() if(holder) holder.update_icon() diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 7ece31d072a..ed0bf5c07fa 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -31,6 +31,7 @@ /obj/item/assembly/mousetrap/update_icon_state() + . = ..() if(armed) icon_state = "mousetraparmed" else diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 297280a0ee6..384f331fe03 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -94,15 +94,19 @@ if(scanning && proximity_monitor.SetRange(sense)) sense() -/obj/item/assembly/prox_sensor/update_icon() - cut_overlays() +/obj/item/assembly/prox_sensor/update_overlays() + . = ..() + attached_overlays = list() if(timing) - add_overlay("prox_timing") + . += "prox_timing" attached_overlays += "prox_timing" if(scanning) - add_overlay("prox_scanning") + . += "prox_scanning" attached_overlays += "prox_scanning" + +/obj/item/assembly/prox_sensor/update_icon() + . = ..() if(holder) holder.update_icon() diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 2fb43429650..80f26a091fd 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -28,6 +28,7 @@ return TRUE /obj/item/assembly/signaler/update_icon() + . = ..() if(holder) holder.update_icon() diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 2332a74675f..e04770cc109 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -63,12 +63,15 @@ timer_end() time = saved_time -/obj/item/assembly/timer/update_icon() - cut_overlays() +/obj/item/assembly/timer/update_overlays() + . = ..() attached_overlays = list() if(timing) - add_overlay("timer_timing") + . += "timer_timing" attached_overlays += "timer_timing" + +/obj/item/assembly/timer/update_icon() + . = ..() if(holder) holder.update_icon() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm index 18d9828973c..b4503752f57 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm @@ -24,7 +24,8 @@ mode = CIRCULATOR_COLD -/obj/machinery/atmospherics/components/binary/circulator/update_icon() +/obj/machinery/atmospherics/components/binary/circulator/update_icon_state() + . = ..() if(!is_operational()) icon_state = "circ-p-[flipped]" else diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index 1849bb10057..35123445c3f 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -8,8 +8,12 @@ construction_type = /obj/item/pipe/trinary/flippable pipe_state = "filter" -/obj/machinery/atmospherics/components/trinary/filter/update_icon() + +/obj/machinery/atmospherics/components/trinary/filter/update_overlays() + . = ..() + cut_overlays() + for(var/direction in GLOB.cardinals) if(!(direction & initialize_directions)) continue @@ -21,7 +25,7 @@ else cap = getpipeimage(icon, "cap", direction, piping_layer = piping_layer) - add_overlay(cap) + . += cap return ..() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 277b5cf98ef..fa571c809ad 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -113,6 +113,7 @@ set_light(initial(light_range)) /obj/machinery/atmospherics/components/unary/cryo_cell/update_icon_state() + . = ..() if(!on) icon_state = "cell_off" else diff --git a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm index 06bbddd1b29..934ff6b9541 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm @@ -23,7 +23,8 @@ piping_layer = 3 icon_state = "he_map-3" -/obj/machinery/atmospherics/components/unary/heat_exchanger/update_icon() +/obj/machinery/atmospherics/components/unary/heat_exchanger/update_icon_state() + . = ..() if(nodes[1]) icon_state = "he1" var/obj/machinery/atmospherics/node = nodes[1] diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index 3e8adb4e811..455fb99911f 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -35,7 +35,8 @@ B += M.rating heat_capacity = 5000 * ((B - 1) ** 2) -/obj/machinery/atmospherics/components/unary/thermomachine/update_icon() +/obj/machinery/atmospherics/components/unary/thermomachine/update_icon_state() + . = ..() if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) icon_state = icon_state_open else if(on && is_operational()) diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm index daf2c643273..26784c857cf 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm @@ -23,7 +23,8 @@ return ..(target, given_layer, FALSE) //we want a normal pipe instead return ..(target, given_layer, TRUE) -/obj/machinery/atmospherics/pipe/heat_exchanging/junction/update_icon() +/obj/machinery/atmospherics/pipe/heat_exchanging/junction/update_icon_state() + . = ..() icon_state = "pipe[nodes[1] ? "1" : "0"][nodes[2] ? "1" : "0"]-[piping_layer]" update_layer() update_alpha() diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm index b1b011e25b2..b4ba2bbc436 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm @@ -26,16 +26,16 @@ initialize_directions = NORTH|SOUTH|EAST|WEST initialize_directions &= ~dir -/obj/machinery/atmospherics/pipe/heat_exchanging/manifold/update_icon() - cut_overlays() +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold/update_overlays() + . = ..() PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer) - add_overlay(center) + . += center //Add non-broken pieces for(var/i in 1 to device_type) if(nodes[i]) - add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) ) + . += getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) update_layer() update_alpha() diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm index 432413ab639..5e7fea7215b 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm @@ -24,16 +24,16 @@ /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/SetInitDirections() initialize_directions = initial(initialize_directions) -/obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/update_icon() - cut_overlays() +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/update_overlays() + . = ..() PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer) - add_overlay(center) + . += center //Add non-broken pieces for(var/i in 1 to device_type) if(nodes[i]) - add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) ) + . += getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) update_layer() update_alpha() diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm index e3ed1a6c37a..2143ac78a8d 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm @@ -24,7 +24,8 @@ if(EAST, WEST) initialize_directions = EAST|WEST -/obj/machinery/atmospherics/pipe/heat_exchanging/simple/update_icon() +/obj/machinery/atmospherics/pipe/heat_exchanging/simple/update_icon_state() + . = ..() icon_state = "pipe[nodes[1] ? "1" : "0"][nodes[2] ? "1" : "0"]-[piping_layer]" update_layer() update_alpha() diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm index 9b0c5fa98ef..24a44e0fb05 100644 --- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm +++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm @@ -40,8 +40,8 @@ /obj/machinery/atmospherics/pipe/layer_manifold/proc/get_all_connected_nodes() return front_nodes + back_nodes + nodes -/obj/machinery/atmospherics/pipe/layer_manifold/update_icon() //HEAVILY WIP FOR UPDATE ICONS!! - cut_overlays() +/obj/machinery/atmospherics/pipe/layer_manifold/update_icon() //this sucks and someone should do it properly + . = ..() layer = initial(layer) + (PIPING_LAYER_MAX * PIPING_LAYER_LCHANGE) //This is above everything else. for(var/node in front_nodes) @@ -49,8 +49,6 @@ for(var/node in back_nodes) add_attached_images(node) - update_alpha() - /obj/machinery/atmospherics/pipe/layer_manifold/proc/add_attached_images(obj/machinery/atmospherics/A) if(!A) return diff --git a/code/modules/atmospherics/machinery/pipes/manifold.dm b/code/modules/atmospherics/machinery/pipes/manifold.dm index 2f6e54d8881..a3ffa8c2c4c 100644 --- a/code/modules/atmospherics/machinery/pipes/manifold.dm +++ b/code/modules/atmospherics/machinery/pipes/manifold.dm @@ -26,17 +26,18 @@ initialize_directions = NORTH|SOUTH|EAST|WEST initialize_directions &= ~dir -/obj/machinery/atmospherics/pipe/manifold/update_icon() - cut_overlays() +/obj/machinery/atmospherics/pipe/manifold/update_overlays() + . = ..() + if(!center) center = mutable_appearance(icon, "manifold_center") PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer) - add_overlay(center) + . += center //Add non-broken pieces for(var/i in 1 to device_type) if(nodes[i]) - add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) ) + . += getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) update_layer() update_alpha() diff --git a/code/modules/atmospherics/machinery/pipes/manifold4w.dm b/code/modules/atmospherics/machinery/pipes/manifold4w.dm index 3f8539eccae..9c05f673187 100644 --- a/code/modules/atmospherics/machinery/pipes/manifold4w.dm +++ b/code/modules/atmospherics/machinery/pipes/manifold4w.dm @@ -23,17 +23,17 @@ /obj/machinery/atmospherics/pipe/manifold4w/SetInitDirections() initialize_directions = initial(initialize_directions) -/obj/machinery/atmospherics/pipe/manifold4w/update_icon() - cut_overlays() +/obj/machinery/atmospherics/pipe/manifold4w/update_overlays() + . = ..() if(!center) center = mutable_appearance(icon, "manifold_center") PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer) - add_overlay(center) + . += center //Add non-broken pieces for(var/i in 1 to device_type) if(nodes[i]) - add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) ) + . += getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) update_layer() update_alpha() diff --git a/code/modules/atmospherics/machinery/pipes/simple.dm b/code/modules/atmospherics/machinery/pipes/simple.dm index 672f4295dbf..70469ef0ff1 100644 --- a/code/modules/atmospherics/machinery/pipes/simple.dm +++ b/code/modules/atmospherics/machinery/pipes/simple.dm @@ -27,7 +27,8 @@ if(EAST, WEST) initialize_directions = EAST|WEST -/obj/machinery/atmospherics/pipe/simple/update_icon() +/obj/machinery/atmospherics/pipe/simple/update_icon_state() + . = ..() icon_state = "pipe[nodes[1] ? "1" : "0"][nodes[2] ? "1" : "0"]-[piping_layer]" if(pipe_vision_img) pipe_vision_img.icon_state = icon_state diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 59d6233e78b..41112bde842 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -56,6 +56,7 @@ resistance_flags = INDESTRUCTIBLE /obj/machinery/portable_atmospherics/canister/update_icon_state() + . = ..() if(machine_stat & BROKEN) icon_state = "[icon_state]-1" diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm index 0016cd92559..65ab1b00a39 100644 --- a/code/modules/atmospherics/machinery/portable/pump.dm +++ b/code/modules/atmospherics/machinery/portable/pump.dm @@ -6,14 +6,17 @@ /// If the pump is on, controls icon_state var/on = FALSE -/obj/machinery/portable_atmospherics/pump/update_icon() +/obj/machinery/portable_atmospherics/pump/update_icon_state() + . = ..() icon_state = "psiphon:[on]" - cut_overlays() +/obj/machinery/portable_atmospherics/pump/update_overlays() + . = ..() + if(holding) - add_overlay("siphon-open") + . += "siphon-open" if(connected_port) - add_overlay("siphon-connector") + . += "siphon-connector" /obj/machinery/portable_atmospherics/pump/emp_act(severity) . = ..() diff --git a/code/modules/buildmode/buildmode.dm b/code/modules/buildmode/buildmode.dm index 3701b3b7879..1e92fb8c0f5 100644 --- a/code/modules/buildmode/buildmode.dm +++ b/code/modules/buildmode/buildmode.dm @@ -153,7 +153,7 @@ /datum/buildmode/proc/change_dir(newdir) build_dir = newdir close_dirswitch() - dirbutton.update_icon() + dirbutton.update_dir() return TRUE diff --git a/code/modules/buildmode/buttons.dm b/code/modules/buildmode/buttons.dm index 884828f44d3..81fc6ef754e 100644 --- a/code/modules/buildmode/buttons.dm +++ b/code/modules/buildmode/buttons.dm @@ -38,7 +38,8 @@ return TRUE -/atom/movable/screen/buildmode/mode/update_icon() +/atom/movable/screen/buildmode/mode/update_icon_state() + . = ..() icon_state = bd.mode.get_button_iconstate() @@ -59,11 +60,10 @@ name = "Change Dir" -/atom/movable/screen/buildmode/bdir/update_icon() +///Updates the direction of the buildmode +/atom/movable/screen/buildmode/bdir/proc/update_dir() dir = bd.build_dir - - /atom/movable/screen/buildmode/bdir/Click() bd.toggle_dirswitch() update_icon() diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 782551b9a46..047f4549082 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -203,7 +203,7 @@ GLOBAL_LIST_INIT(ghost_forms, list("Default" = GHOST_DEFAULT_FORM, "Ghost Ian 1" return var/mob/dead/observer/O = mob - O.update_icon(GLOB.ghost_forms[new_form]) + O.pick_form(GLOB.ghost_forms[new_form]) GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE, GHOST_ORBIT_TRIANGLE, GHOST_ORBIT_SQUARE, GHOST_ORBIT_HEXAGON, GHOST_ORBIT_PENTAGON)) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index a22c884344f..6040609dbcb 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -187,7 +187,7 @@ set_light_on(toggle_on) flags_armor_features ^= ARMOR_LAMP_ON playsound(src, 'sound/items/flashlight.ogg', 15, TRUE) - update_icon(user) + update_icon() update_action_button_icons() /obj/item/clothing/suit/update_clothing_icon() diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 09296fbc91f..6e26cf44e02 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -107,7 +107,7 @@ qdel(src) user.put_in_hands(P) - update_icon(user) + update_icon() /obj/item/clothing/glasses/monocle @@ -142,7 +142,7 @@ qdel(src) user.put_in_hands(P) - update_icon(user) + update_icon() /obj/item/clothing/glasses/regular/hipster name = "prescription glasses" @@ -227,7 +227,7 @@ qdel(src) user.put_in_hands(S) - update_icon(user) + update_icon() /obj/item/clothing/glasses/m42_goggles name = "\improper M42 scout sight" @@ -385,7 +385,7 @@ qdel(src) user.put_in_hands(P) - update_icon(user) + update_icon() /obj/item/clothing/glasses/sunglasses/fake/prescription name = "prescription sunglasses" diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index e8e04673f13..cb626f31b65 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -44,7 +44,7 @@ xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW) to_chat(xeno_attacker, span_warning("We disable the metal thing's lights.") ) -/obj/item/clothing/head/hardhat/update_icon() +/obj/item/clothing/head/hardhat/update_icon_state() . = ..() icon_state = "hardhat[light_on]_[hardhat_color]" item_state = "hardhat[light_on]_[hardhat_color]" diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index b03ad6c3715..3c83b785644 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -162,7 +162,16 @@ . = ..() helmet_overlays = list("damage","band","item") //To make things simple. -/obj/item/clothing/head/helmet/marine/update_icon() +/obj/item/clothing/head/helmet/marine/on_pocket_insertion() + . = ..() + update_helmet_overlays() + +/obj/item/clothing/head/helmet/marine/on_pocket_removal() + . = ..() + update_helmet_overlays() + +///Updates the helmet_overlays list, inserting and removing images from it as necesarry +/obj/item/clothing/head/helmet/marine/proc/update_helmet_overlays() if(!attachments_by_slot[ATTACHMENT_SLOT_STORAGE]) return if(!istype(attachments_by_slot[ATTACHMENT_SLOT_STORAGE], /obj/item/armor_module/storage)) @@ -201,9 +210,11 @@ var/mutable_appearance/M for(var/i in helmet_overlays) M = helmet_overlays[i] - if(M) - M = mutable_appearance('icons/mob/modular/modular_helmet_storage.dmi',M.icon_state) - standing.overlays += M + if(!M) + continue + + M = mutable_appearance('icons/mob/modular/modular_helmet_storage.dmi', M.icon_state) + standing.overlays += M /obj/item/clothing/head/helmet/marine/specialist name = "\improper B18 helmet" @@ -250,6 +261,18 @@ desc = "A lightweight helmet with a small port in the back. Offers lower response times for TGMC mech pilots by integrating them directly into their mech suit's systems, though it certainly doesn't make them smarter." min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE +/obj/item/clothing/head/helmet/marine/assault_crewman + name = "\improper M12B pattern tanker helmet" + icon_state = "assault_crewman_helmet" + desc = "A lightweight helmet. Offers the user protection from being hit in the hell by ejected shell casings, mostly." + min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE + +/obj/item/clothing/head/helmet/marine/transport_crewman + name = "\improper M12A pattern transport helmet" + icon_state = "transport_crewman_helmet" + desc = "A lightweight helmet with a small port in the back. Offers decent protection against reckless driving." + min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE + /obj/item/clothing/head/helmet/marine/riot name = "M8 riot helmet" desc = "It's a modified version of the widely used Riot Helmets for use against angry jarheads. Boasts high ballistic protection" diff --git a/code/modules/clothing/modular_armor/attachments/cape.dm b/code/modules/clothing/modular_armor/attachments/cape.dm index c7b0156b461..d1a7b09ac43 100644 --- a/code/modules/clothing/modular_armor/attachments/cape.dm +++ b/code/modules/clothing/modular_armor/attachments/cape.dm @@ -49,6 +49,7 @@ var/hood = FALSE /obj/item/armor_module/armor/cape/update_icon_state() + . = ..() var/obj/item/armor_module/highlight = attachments_by_slot[ATTACHMENT_SLOT_CAPE_HIGHLIGHT] if(hood) icon_state = initial(icon_state) + "_[current_variant]_h" @@ -158,6 +159,7 @@ ) /obj/item/armor_module/armor/cape_highlight/update_icon_state() + . = ..() if(!parent) return var/obj/item/armor_module/armor/cape/cape_parent = parent diff --git a/code/modules/clothing/modular_armor/attachments/modules.dm b/code/modules/clothing/modular_armor/attachments/modules.dm index bb660bfc0ae..31bbc6123b0 100644 --- a/code/modules/clothing/modular_armor/attachments/modules.dm +++ b/code/modules/clothing/modular_armor/attachments/modules.dm @@ -285,6 +285,7 @@ parent.update_icon() /obj/item/armor_module/module/chemsystem/update_icon_state() + . = ..() if(chemsystem_is_active) icon_state = "mod_chemsystem_active" return diff --git a/code/modules/clothing/shoes/marine_shoes.dm b/code/modules/clothing/shoes/marine_shoes.dm index 5cd150c4d52..896726ef15e 100644 --- a/code/modules/clothing/shoes/marine_shoes.dm +++ b/code/modules/clothing/shoes/marine_shoes.dm @@ -26,6 +26,7 @@ update_icon() /obj/item/clothing/shoes/marine/update_icon_state() + . = ..() icon_state = initial(icon_state) if(!attachments_by_slot[ATTACHMENT_SLOT_STORAGE]) return diff --git a/code/modules/clothing/suits/marine_armor.dm b/code/modules/clothing/suits/marine_armor.dm index 1e672f8b7cd..e1f8a97c46a 100644 --- a/code/modules/clothing/suits/marine_armor.dm +++ b/code/modules/clothing/suits/marine_armor.dm @@ -52,18 +52,14 @@ armor_overlays = list("lamp") //Just one for now, can add more later. update_icon() -/obj/item/clothing/suit/storage/marine/update_icon(mob/user) - var/image/I - I = armor_overlays["lamp"] - overlays -= I - qdel(I) +/obj/item/clothing/suit/storage/marine/update_overlays() + . = ..() if(flags_armor_features & ARMOR_LAMP_OVERLAY) - I = image(icon, src, flags_armor_features & ARMOR_LAMP_ON? "lamp-on" : "lamp-off") + var/image/I = image(icon, src, flags_armor_features & ARMOR_LAMP_ON? "lamp-on" : "lamp-off") armor_overlays["lamp"] = I - overlays += I + . += I else armor_overlays["lamp"] = null - user?.update_inv_wear_suit() /obj/item/clothing/suit/storage/marine/apply_custom(mutable_appearance/standing, inhands, icon_used, state_used) if(inhands) @@ -106,6 +102,24 @@ soft_armor = list(MELEE = 45, BULLET = 55, LASER = 55, ENERGY = 20, BOMB = 45, BIO = 30, FIRE = 25, ACID = 35) flags_item_map_variant = NONE +/obj/item/clothing/suit/storage/marine/assault_crewman + name = "\improper PAS-73 pattern tanker armor" + desc = "A somewhat sparsely armored but robust armored vest. Used by tankers, mostly to absorb bumps in the road as they drive over enemies." + icon_state = "assault_crewman_suit" + item_state = "assault_crewman_suit" + slowdown = SLOWDOWN_ARMOR_LIGHT + soft_armor = list(MELEE = 45, BULLET = 55, LASER = 55, ENERGY = 20, BOMB = 45, BIO = 30, FIRE = 25, ACID = 35) + flags_item_map_variant = NONE + +/obj/item/clothing/suit/storage/marine/transport_crewman + name = "\improper PAS-74 pattern transport armor" + desc = "A somewhat sparsely armored but robust armored vest. Used by transport crewmen so that they can pretend that they may survice when their vehicle is overrun." + icon_state = "transport_crewman_suit" + item_state = "transport_crewman_suit" + slowdown = SLOWDOWN_ARMOR_LIGHT + soft_armor = list(MELEE = 45, BULLET = 55, LASER = 55, ENERGY = 20, BOMB = 45, BIO = 30, FIRE = 25, ACID = 35) + flags_item_map_variant = NONE + /obj/item/clothing/suit/storage/marine/riot name = "\improper M5 riot control armor" desc = "A heavily modified suit of M2 MP Armor used to supress riots from buckethead marines and their guns. Slows you down a lot." @@ -382,18 +396,14 @@ armor_overlays = list("lamp") update_icon() -/obj/item/clothing/suit/storage/faction/update_icon(mob/user) - var/image/I - I = armor_overlays["lamp"] - overlays -= I - qdel(I) +/obj/item/clothing/suit/storage/faction/update_overlays() + . = ..() if(flags_armor_features & ARMOR_LAMP_OVERLAY) - I = image(icon, src, flags_armor_features & ARMOR_LAMP_ON? "lamp-on" : "lamp-off") + var/image/I = image(icon, src, flags_armor_features & ARMOR_LAMP_ON? "lamp-on" : "lamp-off") armor_overlays["lamp"] = I - overlays += I - else armor_overlays["lamp"] = null - if(user) user.update_inv_wear_suit() - + . += I + else + armor_overlays["lamp"] = null /obj/item/clothing/suit/storage/faction/attack_self(mob/user) if(!isturf(user.loc)) diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm index c0cd4844b3f..1557d5d54dc 100644 --- a/code/modules/clothing/under/marine_uniform.dm +++ b/code/modules/clothing/under/marine_uniform.dm @@ -197,6 +197,16 @@ desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented uniform worn by mech pilots. Not as impressive as a titanium robot but good enough." icon_state = "marine_mech_pilot" +/obj/item/clothing/under/marine/officer/assault_crewman + name = "assault crewman uniform" + desc = "A standard-issue, carbon fibre uniform optimised for operating heavy equipment. Feels like a hand-me-down from last decade." + icon_state = "marine_assault_crewman" + +/obj/item/clothing/under/marine/officer/transport_crewman + name = "transport crewman uniform" + desc = "A standard issue comfortable uniform designed for sitting all day." + icon_state = "marine_transport_crewman" + /obj/item/clothing/under/marine/officer/bridge name = "staff officer uniform" desc = "A standard-issue, kevlar-weaved, hazmat-tested, EMF-augmented staff officer uniform. Do the navy proud." diff --git a/code/modules/cm_preds/yaut_items.dm b/code/modules/cm_preds/yaut_items.dm index 7fa78193a2f..d96349d6589 100644 --- a/code/modules/cm_preds/yaut_items.dm +++ b/code/modules/cm_preds/yaut_items.dm @@ -963,6 +963,7 @@ new /obj/item/tool/surgery/healing_gel/(src) /obj/item/storage/medicomp/update_icon() + . = ..() if(!contents.len) icon_state = "medicomp_open" else diff --git a/code/modules/cm_preds/yautja_weapons/one_handed.dm b/code/modules/cm_preds/yautja_weapons/one_handed.dm index cd4e2ab4fad..d46aa07784a 100644 --- a/code/modules/cm_preds/yautja_weapons/one_handed.dm +++ b/code/modules/cm_preds/yautja_weapons/one_handed.dm @@ -291,6 +291,7 @@ update_icon() /obj/item/weapon/yautja/combistick/update_icon() + . = ..() if(flags_item & WIELDED) item_state = "combistick_w" else if(!on) diff --git a/code/modules/cm_preds/yautja_weapons/ranged.dm b/code/modules/cm_preds/yautja_weapons/ranged.dm index 7490b03a908..abc86002c59 100644 --- a/code/modules/cm_preds/yautja_weapons/ranged.dm +++ b/code/modules/cm_preds/yautja_weapons/ranged.dm @@ -238,6 +238,7 @@ . += span_notice("This thing looks like an alien rifle of some kind. Strange.") /obj/item/weapon/gun/energy/yautja/plasmarifle/update_icon() + . = ..() if(last_regen < rounds + max_rounds / 5 || last_regen > rounds || rounds > max_rounds / 1.05) var/new_icon_state = rounds <= 15 ? null : icon_state + "[round(rounds/(max_rounds / 3), 1)]" update_special_overlay(new_icon_state) diff --git a/code/modules/economy/cash.dm b/code/modules/economy/cash.dm index 186f6404acb..f4b0db02a4a 100644 --- a/code/modules/economy/cash.dm +++ b/code/modules/economy/cash.dm @@ -45,8 +45,12 @@ desc = "They are worth 0 dollars." worth = 0 -/obj/item/spacecash/bundle/update_icon() - overlays.Cut() +/obj/item/spacecash/bundle/update_desc(updates) + . = ..() + desc = "They are worth [worth] dollars." + +/obj/item/spacecash/bundle/update_overlays() + . = ..() var/sum = worth var/num = 0 for(var/i in list(1000,500,200,100,50,20,10,1)) @@ -58,15 +62,14 @@ M.Translate(rand(-6, 6), rand(-4, 8)) M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45)) banknote.transform = M - overlays += banknote + . += banknote if(num == 0) // Less than one thaler, let's just make it look like 1 for ease var/image/banknote = image('icons/obj/stack_objects.dmi', "spacecash1") var/matrix/M = matrix() M.Translate(rand(-6, 6), rand(-4, 8)) M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45)) banknote.transform = M - overlays += banknote - desc = "They are worth [worth] dollars." + . += banknote /obj/item/spacecash/bundle/attack_self(mob/user) var/oldloc = loc @@ -76,7 +79,7 @@ if(gc_destroyed || loc != oldloc) return src.worth -= amount - src.update_icon() + src.update_appearance() if(!worth) usr.temporarilyRemoveItemFromInventory(src) if(amount in list(1000,500,200,100,50,20,1)) @@ -86,7 +89,7 @@ else var/obj/item/spacecash/bundle/bundle = new (usr.loc) bundle.worth = amount - bundle.update_icon() + bundle.update_appearance() user.put_in_hands(bundle) if(!worth) qdel(src) @@ -143,7 +146,7 @@ return var/obj/item/spacecash/bundle/bundle = new (spawnloc) bundle.worth = sum - bundle.update_icon() + bundle.update_appearance() if (ishuman(human_user) && !human_user.get_active_held_item()) human_user.put_in_hands(bundle) diff --git a/code/modules/factory/unboxer.dm b/code/modules/factory/unboxer.dm index 154ec3d995a..a52b07a9e85 100644 --- a/code/modules/factory/unboxer.dm +++ b/code/modules/factory/unboxer.dm @@ -54,6 +54,7 @@ balloon_alert(user, "Facing [dir2text(dir)]") /obj/machinery/unboxer/update_icon_state() + . = ..() if(datum_flags & DF_ISPROCESSING) icon_state = "unboxer" return diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index f5b04604335..4f9a8438e90 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -114,16 +114,6 @@ GLOBAL_LIST_INIT(hallucination_list, list( if(target.client) target.client.images |= current_image -/obj/effect/hallucination/simple/update_icon(new_state,new_icon,new_px=0,new_py=0) - icon_state = new_state - if(new_icon) - icon = new_icon - else - icon = initial(icon) - px = new_px - py = new_py - Show() - /obj/effect/hallucination/simple/Moved(atom/OldLoc, Dir) Show() diff --git a/code/modules/hydroponics/hydro_tray.dm b/code/modules/hydroponics/hydro_tray.dm index 8f50c4d7dd7..ce18d8f46bf 100644 --- a/code/modules/hydroponics/hydro_tray.dm +++ b/code/modules/hydroponics/hydro_tray.dm @@ -366,19 +366,22 @@ //Refreshes the icon and sets the luminosity /obj/machinery/hydroponics/update_icon() + update_bioluminescence() + return ..() - overlays.Cut() +/obj/machinery/hydroponics/update_overlays() + . = ..() // Updates the plant overlay. if(!isnull(seed)) if(draw_warnings && health <= (seed.endurance / 2)) - overlays += "over_lowhealth3" + . += "over_lowhealth3" if(dead) - overlays += "[seed.plant_icon]-dead" + . += "[seed.plant_icon]-dead" else if(harvest) - overlays += "[seed.plant_icon]-harvest" + . += "[seed.plant_icon]-harvest" else if(age < seed.maturation) var/t_growthstate @@ -387,26 +390,27 @@ else t_growthstate = round(seed.maturation / seed.growth_stages) - overlays += "[seed.plant_icon]-grow[t_growthstate]" + . += "[seed.plant_icon]-grow[t_growthstate]" lastproduce = age else - overlays += "[seed.plant_icon]-grow[seed.growth_stages]" + . += "[seed.plant_icon]-grow[seed.growth_stages]" //Draw the cover. if(closed_system) - overlays += "hydrocover" + . += "hydrocover" //Updated the various alert icons. if(draw_warnings) if(waterlevel <= 10) - overlays += "over_lowwater3" + . += "over_lowwater3" if(nutrilevel <= 2) - overlays += "over_lownutri3" + . += "over_lownutri3" if(weedlevel >= 5 || pestlevel >= 5 || toxins >= 40) - overlays += "over_alert3" + . += "over_alert3" if(harvest) - overlays += "over_harvest3" + . += "over_harvest3" +/obj/machinery/hydroponics/proc/update_bioluminescence() // Update bioluminescence. if(seed) if(seed.biolum) @@ -418,7 +422,6 @@ set_light(0) - // If a weed growth is sufficient, this proc is called. /obj/machinery/hydroponics/proc/weed_invasion() diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index b376eb7c549..bc40c1bbd39 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -20,12 +20,17 @@ seed = GLOB.seed_types[seed_type] update_appearance() -//Updates strings and icon appropriately based on seed datum. -/obj/item/seeds/proc/update_appearance() +/obj/item/seeds/update_appearance() + . = ..() icon_state = seed.packet_icon + +/obj/item/seeds/update_name(updates) + . = ..() name = "packet of [seed.seed_name] [seed.seed_noun]" - desc = "It has a picture of [seed.display_name] on the front." +/obj/item/seeds/update_desc(updates) + . = ..() + desc = "It has a picture of [seed.display_name] on the front." /obj/item/seeds/poppyseed name = "poppy seed" diff --git a/code/modules/mob/camera/imaginary_friend.dm b/code/modules/mob/camera/imaginary_friend.dm index 8cb16721dea..8b86c93be84 100644 --- a/code/modules/mob/camera/imaginary_friend.dm +++ b/code/modules/mob/camera/imaginary_friend.dm @@ -199,7 +199,7 @@ to_chat(M, "[link] [dead_rendered]") -/mob/camera/imaginary_friend/Move(newloc, Dir = 0) +/mob/camera/imaginary_friend/Move(atom/newloc, direction, glide_size_override) if(world.time < move_delay) return FALSE diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 4c1a14f54b7..6e92ee5e5d6 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -32,7 +32,7 @@ ghost_others = client.prefs.ghost_others - update_icon(client.prefs.ghost_form) + pick_form(client.prefs.ghost_form) updateghostimages() for(var/path in subtypesof(/datum/action/observer_action)) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 0b934215a5a..607dd5b6eea 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -123,7 +123,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) SSmobs.dead_players_by_zlevel[old_z] -= src SSmobs.dead_players_by_zlevel[new_z] += src -/mob/dead/observer/update_icon(new_form) +///Changes our sprite +/mob/dead/observer/proc/pick_form(new_form) if(client) //We update our preferences in case they changed right before update_icon was called. ghost_others = client.prefs.ghost_others @@ -134,7 +135,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) else ghostimage_default.icon_state = new_form - /mob/dead/observer/Topic(href, href_list) . = ..() if(.) @@ -299,10 +299,11 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) GLOB.key_to_time_of_xeno_death[ghost.key] = world.time //If you ghost as a xeno that is not a minion, sets respawn timer -/mob/dead/observer/Move(atom/newloc, direct) +/mob/dead/observer/Move(atom/newloc, direct, glide_size_override = 32) if(updatedir) setDir(direct)//only update dir if we actually need it, so overlays won't spin on base sprites that don't have directions of their own - + if(glide_size_override) + set_glide_size(glide_size_override) if(newloc) abstract_move(newloc) update_parallax_contents() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 02fa1a307a2..3de341f05f3 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -10,7 +10,7 @@ m_intent = MOVE_INTENT_WALK buckle_flags = CAN_BE_BUCKLED|CAN_BUCKLE resistance_flags = XENO_DAMAGEABLE|PORTAL_IMMUNE - appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE + appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE hud_type = /datum/hud/human diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 98dbc242806..bbcb07b53a9 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/human/Move(NewLoc, direct) +/mob/living/carbon/human/Move(atom/newloc, direction, glide_size_override) . = ..() if(!.) return diff --git a/code/modules/mob/living/carbon/human/life/handle_regular_hud_updates.dm b/code/modules/mob/living/carbon/human/life/handle_regular_hud_updates.dm index 743da349465..f62aa629c73 100644 --- a/code/modules/mob/living/carbon/human/life/handle_regular_hud_updates.dm +++ b/code/modules/mob/living/carbon/human/life/handle_regular_hud_updates.dm @@ -12,17 +12,6 @@ clear_fullscreen("brute") clear_fullscreen("oxy") clear_fullscreen("crit") - - if(!hud_used) - return - if(hud_used.nutrition_icon) - hud_used.nutrition_icon.icon_state = "nutrition1" - if(hud_used.oxygen_icon) - hud_used.oxygen_icon.icon_state = "oxy0" - if(hud_used.fire_icon) - hud_used.fire_icon.icon_state = "fire0" - if(hud_used.bodytemp_icon) - hud_used.bodytemp_icon.icon_state = "temp0" return if(stat == UNCONSCIOUS && health <= get_crit_threshold()) @@ -100,78 +89,13 @@ if(!hud_used) return - if(hud_used.nutrition_icon) - switch(nutrition) - if(NUTRITION_OVERFED to INFINITY) - hud_used.nutrition_icon.icon_state = "nutrition0" - if(NUTRITION_HUNGRY to NUTRITION_OVERFED) //Not-hungry. - hud_used.nutrition_icon.icon_state = "nutrition1" //Empty icon. - if(NUTRITION_STARVING to NUTRITION_HUNGRY) - hud_used.nutrition_icon.icon_state = "nutrition3" - else - hud_used.nutrition_icon.icon_state = "nutrition4" - - if(hud_used.oxygen_icon) - if(hal_screwyhud == 3 || oxygen_alert) - hud_used.oxygen_icon.icon_state = "oxy1" - else - hud_used.oxygen_icon.icon_state = "oxy0" - if(hud_used.fire_icon) - if(fire_alert) - hud_used.fire_icon.icon_state = "fire[fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. - else - hud_used.fire_icon.icon_state = "fire0" - - if(hud_used.bodytemp_icon) - if(!species) - switch(bodytemperature) //310.055 optimal body temp - if(370 to INFINITY) - hud_used.bodytemp_icon.icon_state = "temp4" - if(350 to 370) - hud_used.bodytemp_icon.icon_state = "temp3" - if(335 to 350) - hud_used.bodytemp_icon.icon_state = "temp2" - if(320 to 335) - hud_used.bodytemp_icon.icon_state = "temp1" - if(300 to 320) - hud_used.bodytemp_icon.icon_state = "temp0" - if(295 to 300) - hud_used.bodytemp_icon.icon_state = "temp-1" - if(280 to 295) - hud_used.bodytemp_icon.icon_state = "temp-2" - if(260 to 280) - hud_used.bodytemp_icon.icon_state = "temp-3" - else - hud_used.bodytemp_icon.icon_state = "temp-4" - else - var/temp_step - if(bodytemperature >= species.body_temperature) - temp_step = (species.heat_level_1 - species.body_temperature) / 4 - - if(bodytemperature >= species.heat_level_1) - hud_used.bodytemp_icon.icon_state = "temp4" - else if(bodytemperature >= species.body_temperature + temp_step * 3) - hud_used.bodytemp_icon.icon_state = "temp3" - else if(bodytemperature >= species.body_temperature + temp_step * 2) - hud_used.bodytemp_icon.icon_state = "temp2" - else if(bodytemperature >= species.body_temperature + temp_step * 1) - hud_used.bodytemp_icon.icon_state = "temp1" - else - hud_used.bodytemp_icon.icon_state = "temp0" - - else if(bodytemperature < species.body_temperature) - temp_step = (species.body_temperature - species.cold_level_1)/4 - - if(bodytemperature <= species.cold_level_1) - hud_used.bodytemp_icon.icon_state = "temp-4" - else if(bodytemperature <= species.body_temperature - temp_step * 3) - hud_used.bodytemp_icon.icon_state = "temp-3" - else if(bodytemperature <= species.body_temperature - temp_step * 2) - hud_used.bodytemp_icon.icon_state = "temp-2" - else if(bodytemperature <= species.body_temperature - temp_step * 1) - hud_used.bodytemp_icon.icon_state = "temp-1" - else - hud_used.bodytemp_icon.icon_state = "temp0" + hud_used?.nutrition_icon?.update_icon() + + hud_used?.oxygen_icon?.update_icon() + + hud_used?.fire_icon?.update_icon() + + hud_used?.bodytemp_icon?.update_icon() /mob/living/carbon/human/handle_healths_hud_updates() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/behemoth/abilities_behemoth.dm b/code/modules/mob/living/carbon/xenomorph/castes/behemoth/abilities_behemoth.dm index 8eefc8128ae..7a3a788ccee 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/behemoth/abilities_behemoth.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/behemoth/abilities_behemoth.dm @@ -131,7 +131,7 @@ #define LANDSLIDE_ENDING_COLLISION_DELAY 0.3 SECONDS #define LANDSLIDE_KNOCKDOWN_DURATION 1 SECONDS #define LANDSLIDE_DAMAGE_MULTIPLIER 1.2 -#define LANDSLIDE_DAMAGE_MECHA_MODIFIER 20 +#define LANDSLIDE_DAMAGE_VEHICLE_MODIFIER 20 #define LANDSLIDE_OBJECT_INTEGRITY_THRESHOLD 150 #define LANDSLIDE_ENDED_CANCELLED (1<<0) @@ -392,9 +392,9 @@ var/obj/structure/earth_pillar/affected_pillar = affected_atom affected_pillar.throw_pillar(get_ranged_target_turf(xeno_owner, xeno_owner.dir, 7), TRUE) continue - if(ismecha(affected_atom)) - var/obj/vehicle/sealed/mecha/affected_mecha = affected_atom - affected_mecha.take_damage(damage * LANDSLIDE_DAMAGE_MECHA_MODIFIER, MELEE) + if(isvehicle(affected_atom)) + var/obj/vehicle/veh_victim = affected_atom + veh_victim.take_damage(damage * LANDSLIDE_DAMAGE_VEHICLE_MODIFIER, MELEE) continue var/obj/affected_object = affected_atom if(!affected_object.density || affected_object.allow_pass_flags & PASS_MOB || affected_object.resistance_flags & INDESTRUCTIBLE) @@ -454,9 +454,9 @@ var/obj/structure/earth_pillar/affected_pillar = affected_atom affected_pillar.throw_pillar(get_ranged_target_turf(xeno_owner, xeno_owner.dir, 7), TRUE) continue - if(ismecha(affected_atom)) - var/obj/vehicle/sealed/mecha/affected_mecha = affected_atom - affected_mecha.take_damage(damage * LANDSLIDE_DAMAGE_MECHA_MODIFIER, MELEE) + if(isvehicle(affected_atom)) + var/obj/vehicle/veh_victim = affected_atom + veh_victim.take_damage(damage * LANDSLIDE_DAMAGE_VEHICLE_MODIFIER, MELEE) continue var/obj/affected_object = affected_atom if(!affected_object.density || affected_object.allow_pass_flags & PASS_MOB || affected_object.resistance_flags & INDESTRUCTIBLE) @@ -1300,6 +1300,11 @@ RU TGMC EDIT */ xeno_owner = null return ..() +/// Calls update_appearance, this exists to discard the arguments we get from the signals. +/obj/structure/earth_pillar/proc/call_update_icon_state() + SIGNAL_HANDLER + update_appearance() + /obj/structure/earth_pillar/update_icon_state() . = ..() if(obj_integrity <= max_integrity * 0.25) @@ -1371,11 +1376,6 @@ RU TGMC EDIT */ UnregisterSignal(xeno_owner, COMSIG_QDELETING) xeno_owner = null -/// Calls update_icon_state(). -/obj/structure/earth_pillar/proc/call_update_icon_state() - SIGNAL_HANDLER - update_icon_state() - /// Deletes the pillar and creates a projectile on the same tile, to be fired at the target atom. /obj/structure/earth_pillar/proc/throw_pillar(atom/target_atom, landslide) if(!isxeno(usr) || !in_range(src, usr) || target_atom == src || warning_flashes < initial(warning_flashes)) @@ -1429,6 +1429,8 @@ RU TGMC EDIT */ if(istype(hit_object, /obj/structure/reagent_dispensers/fueltank)) var/obj/structure/reagent_dispensers/fueltank/hit_tank = hit_object hit_tank.explode() + if(ishitbox(hit_object) || ismecha(hit_object)) // These don't hit the vehicles, but rather their hitboxes, so isarmored will not work here + return on_hit_anything(get_turf(hit_object), proj) return rock_broke(get_turf(hit_object), proj) /datum/ammo/xeno/earth_pillar/on_hit_mob(mob/hit_mob, obj/projectile/proj) @@ -1467,7 +1469,7 @@ RU TGMC EDIT */ // *************************************** // *********** Global Procs // *************************************** -#define AREA_ATTACK_DAMAGE_MECHA_MODIFIER 10 +#define AREA_ATTACK_DAMAGE_VEHICLE_MODIFIER 0.4 /** * Checks for any atoms caught in the attack's range, and applies several effects based on the atom's type. @@ -1498,7 +1500,7 @@ RU TGMC EDIT */ shake_camera(affected_living, 1, 0.8) affected_living.Paralyze(paralyze_duration) affected_living.apply_damage(attack_damage, BRUTE, blocked = MELEE) - else if(isearthpillar(affected_atom) || ismecha(affected_atom) || istype(affected_atom, /obj/structure/reagent_dispensers/fueltank)) + else if(isearthpillar(affected_atom) || isvehicle(affected_atom) || ishitbox(affected_atom) || istype(affected_atom, /obj/structure/reagent_dispensers/fueltank)) affected_atom.do_jitter_animation() new /obj/effect/temp_visual/behemoth/landslide/hit(affected_atom.loc) playsound(affected_atom.loc, get_sfx("behemoth_earth_pillar_hit"), 40) @@ -1512,9 +1514,12 @@ RU TGMC EDIT */ do_warning(xeno_owner, spread_turfs, wind_up_duration) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(behemoth_area_attack), xeno_owner, spread_turfs, enhanced), wind_up_duration) continue - if(ismecha(affected_atom)) - var/obj/vehicle/sealed/mecha/affected_mecha = affected_atom - affected_mecha.take_damage(attack_damage * AREA_ATTACK_DAMAGE_MECHA_MODIFIER, MELEE) + if(isvehicle(affected_atom) || ishitbox(affected_atom)) + var/obj/vehicle/veh_victim = affected_atom + var/damage_add = 0 + if(ismecha(veh_victim)) + damage_add = 9.5 + veh_victim.take_damage(attack_damage * (AREA_ATTACK_DAMAGE_VEHICLE_MODIFIER + damage_add), MELEE) continue if(istype(affected_atom, /obj/structure/reagent_dispensers/fueltank)) var/obj/structure/reagent_dispensers/fueltank/affected_tank = affected_atom diff --git a/code/modules/mob/living/carbon/xenomorph/castes/crusher/castedatum_crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/crusher/castedatum_crusher.dm index 5c8a0717399..76707b4dca2 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/crusher/castedatum_crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/crusher/castedatum_crusher.dm @@ -33,7 +33,7 @@ // *** Flags *** // can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_BE_GIVEN_PLASMA|CASTE_CAN_BE_LEADER - caste_traits = null + caste_traits = list(TRAIT_STOPS_TANK_COLLISION) // *** Defense *** // soft_armor = list(MELEE = 90, BULLET = 75, LASER = 75, ENERGY = 75, BOMB = 130, BIO = 100, FIRE = 40, ACID = 100) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/defender/abilities_defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/defender/abilities_defender.dm index 4ec98b59311..a6e2b090c25 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/defender/abilities_defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/defender/abilities_defender.dm @@ -306,6 +306,7 @@ SSblackbox.record_feedback("tally", "round_statistics", 1, "defender_fortifiy_toggles") if(on) ADD_TRAIT(X, TRAIT_IMMOBILE, FORTIFY_TRAIT) + ADD_TRAIT(X, TRAIT_STOPS_TANK_COLLISION, FORTIFY_TRAIT) if(!silent) to_chat(X, span_xenowarning("We tuck ourselves into a defensive stance.")) X.soft_armor = X.soft_armor.modifyAllRatings(last_fortify_bonus) @@ -317,6 +318,7 @@ X.soft_armor = X.soft_armor.modifyAllRatings(-last_fortify_bonus) X.soft_armor = X.soft_armor.modifyRating(BOMB = -last_fortify_bonus) REMOVE_TRAIT(X, TRAIT_IMMOBILE, FORTIFY_TRAIT) + REMOVE_TRAIT(X, TRAIT_STOPS_TANK_COLLISION, FORTIFY_TRAIT) X.fortify = on X.anchored = on diff --git a/code/modules/mob/living/carbon/xenomorph/castes/hivemind/hivemind.dm b/code/modules/mob/living/carbon/xenomorph/castes/hivemind/hivemind.dm index f84625dfc0a..c71a6865c7b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/hivemind/hivemind.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/hivemind/hivemind.dm @@ -119,7 +119,7 @@ setDir(SOUTH) addtimer(CALLBACK(src, PROC_REF(do_change_form)), TIME_TO_TRANSFORM) -/mob/living/carbon/xenomorph/hivemind/set_jump_component(duration = 0.5 SECONDS, cooldown = 2 SECONDS, cost = 0, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE) +/mob/living/carbon/xenomorph/hivemind/set_jump_component(duration = 0.5 SECONDS, cooldown = 2 SECONDS, cost = 0, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK) return //no jumping, bad hivemind ///Finish the form changing of the hivemind and give the needed stats @@ -204,21 +204,21 @@ flick("Hivemind_[initial(loc_weeds_type.color_variant)]_materialisation", src) setDir(SOUTH) -/mob/living/carbon/xenomorph/hivemind/Move(NewLoc, Dir = 0) +/mob/living/carbon/xenomorph/hivemind/Move(atom/newloc, direction, glide_size_override) if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_HIVEMIND_MANIFESTATION)) return if(!(status_flags & INCORPOREAL)) return ..() - if(!check_weeds(NewLoc)) + if(!check_weeds(newloc)) return FALSE // FIXME: Port canpass refactor from tg // Don't allow them over the timed_late doors - var/obj/machinery/door/poddoor/timed_late/door = locate() in NewLoc - if(door && !door.CanPass(src, NewLoc)) + var/obj/machinery/door/poddoor/timed_late/door = locate() in newloc + if(door && !door.CanPass(src, newloc)) return FALSE - abstract_move(NewLoc) + abstract_move(newloc) /mob/living/carbon/xenomorph/hivemind/receive_hivemind_message(mob/living/carbon/xenomorph/speaker, message) var/track = "(F)" @@ -248,6 +248,7 @@ /// handles hivemind updating with their respective weedtype /mob/living/carbon/xenomorph/hivemind/update_icon_state() + . = ..() if(status_flags & INCORPOREAL) icon_state = "hivemind_marker" return diff --git a/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm b/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm index 280405897dc..3961e9b8321 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm @@ -263,9 +263,9 @@ shake_camera(carbon_victim, 3 * severity, 3 * severity) carbon_victim.apply_effect(1 SECONDS, WEAKEN) to_chat(carbon_victim, "You are smashed to the ground!") - else if(ismecha(victim)) - var/obj/vehicle/sealed/mecha/mecha_victim = victim - mecha_victim.take_damage(SHATTERING_ROAR_DAMAGE * 5 * severity, BRUTE, MELEE) + else if(isvehicle(victim)) + var/obj/vehicle/veh_victim = victim + veh_victim.take_damage(SHATTERING_ROAR_DAMAGE * 5 * severity, BRUTE, MELEE) else if(istype(victim, /obj/structure/window)) var/obj/structure/window/window_victim = victim if(window_victim.damageable) @@ -299,7 +299,7 @@ /datum/action/ability/xeno_action/zero_form_beam name = "Zero-Form Energy Beam" action_icon_state = "zero_form_beam" - desc = "After a windup, concentrates the hives energy into a forward-facing beam that pierces everything, but only hurts living beings." + desc = "After a windup, concentrates the hives energy into a forward-facing beam that pierces everything, hurting living beings and vehicles." ability_cost = 25 cooldown_duration = 10 SECONDS keybind_flags = ABILITY_KEYBIND_USE_ABILITY @@ -401,9 +401,12 @@ human_victim.take_overall_damage(15, BURN, updating_health = TRUE) human_victim.flash_weak_pain() animation_flash_color(human_victim) - else if(ismecha(victim)) - var/obj/vehicle/sealed/mecha/mech_victim = victim - mech_victim.take_damage(75, BURN, ENERGY, armour_penetration = 60) + else if(isvehicle(victim) || ishitbox(victim)) + var/obj/obj_victim = victim + var/damage_mult = 1 + if(ismecha(obj_victim)) + damage_mult = 5 + obj_victim.take_damage(15 * damage_mult, BURN, ENERGY, armour_penetration = 60) timer_ref = addtimer(CALLBACK(src, PROC_REF(execute_attack)), ZEROFORM_TICK_RATE, TIMER_STOPPABLE) ///ends and cleans up beam diff --git a/code/modules/mob/living/carbon/xenomorph/castes/praetorian/abilities_praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/praetorian/abilities_praetorian.dm index 6f5c77c6971..70e47599d0b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/praetorian/abilities_praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/praetorian/abilities_praetorian.dm @@ -95,7 +95,7 @@ return FALSE return TRUE -GLOBAL_LIST_INIT(acid_spray_hit, typecacheof(list(/obj/structure/barricade, /obj/vehicle/multitile/root/cm_armored, /obj/structure/razorwire))) +GLOBAL_LIST_INIT(acid_spray_hit, typecacheof(list(/obj/structure/barricade, /obj/hitbox, /obj/structure/razorwire))) #define CONE_PART_MIDDLE (1<<0) #define CONE_PART_LEFT (1<<1) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm index a03b787cf7e..03580ce55a5 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/queen/abilities_queen.dm @@ -97,14 +97,16 @@ GLOB.round_statistics.queen_screech++ SSblackbox.record_feedback("tally", "round_statistics", 1, "queen_screech") X.create_shriekwave() //Adds the visual effect. Wom wom wom - //stop_momentum(charge_dir) //Screech kills a charge var/list/nearby_living = list() for(var/mob/living/L in hearers(WORLD_VIEW, X)) nearby_living.Add(L) + for(var/obj/vehicle/sealed/armored/tank AS in GLOB.tank_list) + if(get_dist(tank, X) > WORLD_VIEW_NUM) + continue + nearby_living += tank.occupants - for(var/i in GLOB.mob_living_list) - var/mob/living/L = i + for(var/mob/living/L AS in GLOB.mob_living_list) if(get_dist(L, X) > WORLD_VIEW_NUM) continue L.screech_act(X, WORLD_VIEW_NUM, L in nearby_living) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm b/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm index 45753dc7d1c..4e94675eea2 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/warlock/abilities_warlock.dm @@ -403,9 +403,12 @@ carbon_victim.apply_damage(xeno_owner.xeno_caste.crush_strength * 1.5, STAMINA, blocked = BOMB) carbon_victim.adjust_stagger(5 SECONDS) carbon_victim.add_slowdown(6) - else if(ismecha(victim)) - var/obj/vehicle/sealed/mecha/mecha_victim = victim - mecha_victim.take_damage(xeno_owner.xeno_caste.crush_strength * 5, BRUTE, BOMB) + else if(isvehicle(victim) || ishitbox(victim)) + var/obj/obj_victim = victim + var/dam_mult = 0.5 + if(ismecha(obj_victim)) + dam_mult = 5 + obj_victim.take_damage(xeno_owner.xeno_caste.crush_strength * dam_mult, BRUTE, BOMB) stop_crush() /// stops channeling and unregisters all listeners, resetting the ability diff --git a/code/modules/mob/living/carbon/xenomorph/charge_crush.dm b/code/modules/mob/living/carbon/xenomorph/charge_crush.dm index 44aa77c0e38..f8935a5347d 100644 --- a/code/modules/mob/living/carbon/xenomorph/charge_crush.dm +++ b/code/modules/mob/living/carbon/xenomorph/charge_crush.dm @@ -430,6 +430,9 @@ /obj/vehicle/sealed/mecha/pre_crush_act(mob/living/carbon/xenomorph/charger, datum/action/ability/xeno_action/ready_charge/charge_datum) return (CHARGE_SPEED(charge_datum) * 375) +/obj/hitbox/pre_crush_act(mob/living/carbon/xenomorph/charger, datum/action/ability/xeno_action/ready_charge/charge_datum) + return (CHARGE_SPEED(charge_datum) * 20) + /obj/structure/razorwire/pre_crush_act(mob/living/carbon/xenomorph/charger, datum/action/ability/xeno_action/ready_charge/charge_datum) if(CHECK_BITFIELD(resistance_flags, INDESTRUCTIBLE) || charger.is_charging < CHARGE_ON) charge_datum.do_stop_momentum() diff --git a/code/modules/mob/living/carbon/xenomorph/egg.dm b/code/modules/mob/living/carbon/xenomorph/egg.dm index 9361503d680..f67ceb114ab 100644 --- a/code/modules/mob/living/carbon/xenomorph/egg.dm +++ b/code/modules/mob/living/carbon/xenomorph/egg.dm @@ -21,6 +21,7 @@ advance_maturity(maturity_stage) /obj/alien/egg/update_icon_state() + . = ..() icon_state = initial(icon_state) + "[maturity_stage]" /obj/alien/egg/obj_break(damage_flag) diff --git a/code/modules/mob/living/carbon/xenomorph/embryo.dm b/code/modules/mob/living/carbon/xenomorph/embryo.dm index 26045ec4d60..58aedefb467 100644 --- a/code/modules/mob/living/carbon/xenomorph/embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/embryo.dm @@ -204,9 +204,9 @@ victim.update_burst() - if(istype(victim.loc, /obj/vehicle/multitile/root)) - var/obj/vehicle/multitile/root/V = victim.loc - V.handle_player_exit(src) + if(istype(victim.loc, /obj/vehicle/sealed)) + var/obj/vehicle/sealed/armored/veh = victim.loc + forceMove(veh.exit_location(src)) else forceMove(get_turf(victim)) //moved to the turf directly so we don't get stuck inside a cryopod or another mob container. playsound(src, pick('sound/voice/alien_chestburst.ogg','sound/voice/alien_chestburst2.ogg'), 25) diff --git a/code/modules/mob/living/carbon/xenomorph/facehuggers.dm b/code/modules/mob/living/carbon/xenomorph/facehuggers.dm index 7de6a01cac9..b39fb232626 100644 --- a/code/modules/mob/living/carbon/xenomorph/facehuggers.dm +++ b/code/modules/mob/living/carbon/xenomorph/facehuggers.dm @@ -100,7 +100,8 @@ clear_hugger_source() return ..() -/obj/item/clothing/mask/facehugger/update_icon() +/obj/item/clothing/mask/facehugger/update_icon_state() + . = ..() if(stat == DEAD) var/fertility = sterile ? "impregnated" : "dead" icon_state = "[initial(icon_state)]_[fertility]" @@ -294,12 +295,12 @@ if(stat == DEAD || stat == UNCONSCIOUS || !isturf(loc)) //It's dead or inactive or not on a turf don't bother return about_to_jump = TRUE - update_overlays() + update_appearance(UPDATE_OVERLAYS) ///Remove the hugger's alert overlay /obj/item/clothing/mask/facehugger/proc/remove_danger_overlay() about_to_jump = FALSE - update_overlays() + update_appearance(UPDATE_OVERLAYS) /obj/item/clothing/mask/facehugger/proc/check_lifecycle() diff --git a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm index 7267248e22a..b127aa0c497 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_datum.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_datum.dm @@ -579,7 +579,7 @@ var/obj/machinery/nuclearbomb/nuke = thing if(!nuke.timer) CRASH("hive_status's setup_nuke_hud_timer called with invalid nuke object") - nuke_hud_timer = new(null, get_all_xenos() , nuke.timer, "Nuke ACTIVE: ${timer}") + nuke_hud_timer = new(null, null, get_all_xenos() , nuke.timer, "Nuke ACTIVE: ${timer}") /datum/hive_status/Destroy(force, ...) . = ..() diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm index d223a0c456d..70508be1803 100644 --- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm +++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -177,6 +177,7 @@ update_flame_light(owner.fire_luminosity) /atom/movable/vis_obj/xeno_wounds/fire_overlay/update_icon_state() + . = ..() if(!owner.on_fire) icon_state = "" return diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm index a65f4b9b6e0..827fe656bac 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm @@ -263,7 +263,7 @@ RU TGMC EDIT */ see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE sight = SEE_SELF|SEE_OBJS|SEE_TURFS|SEE_MOBS - appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER + appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER|LONG_GLIDE see_infrared = TRUE hud_type = /datum/hud/alien hud_possible = list(HEALTH_HUD_XENO, PLASMA_HUD, PHEROMONE_HUD, XENO_RANK_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_DEBUFF_HUD, XENO_FIRE_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD, XENO_PRIMO_HUD, HUNTER_HUD) diff --git a/code/modules/mob/living/carbon/xenomorph/xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/xenomorph.dm index e6d2289291b..5cc5ffd2856 100644 --- a/code/modules/mob/living/carbon/xenomorph/xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/xenomorph.dm @@ -478,7 +478,7 @@ Returns TRUE when loc_weeds_type changes. Returns FALSE when it doesn’t change return return ..() -/mob/living/carbon/xenomorph/set_jump_component(duration = 0.5 SECONDS, cooldown = 2 SECONDS, cost = 0, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE) +/mob/living/carbon/xenomorph/set_jump_component(duration = 0.5 SECONDS, cooldown = 2 SECONDS, cost = 0, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK) var/gravity = get_gravity() if(gravity < 1) //low grav duration *= 2.5 - gravity diff --git a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm index 3347c9bd0e1..f84dc8aa2df 100644 --- a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm +++ b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm @@ -391,11 +391,6 @@ take_damage(2 * X.xeno_caste.acid_spray_structure_damage, BURN, ACID) return FALSE // not normal density flag -/obj/vehicle/multitile/root/cm_armored/acid_spray_act(mob/living/carbon/xenomorph/X) - take_damage_type(X.xeno_caste.acid_spray_structure_damage, ACID, src) - healthcheck() - return TRUE - /mob/living/carbon/acid_spray_act(mob/living/carbon/xenomorph/X) ExtinguishMob() if(isnestedhost(src)) @@ -425,7 +420,11 @@ ExtinguishMob() /obj/flamer_fire/acid_spray_act(mob/living/carbon/xenomorph/X) - Destroy() + qdel(src) + +/obj/hitbox/acid_spray_act(mob/living/carbon/xenomorph/X) + take_damage(X.xeno_caste.acid_spray_structure_damage, BURN, ACID) + return TRUE // Vent Crawl /mob/living/carbon/xenomorph/proc/vent_crawl() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3193e7d039e..a6c0684a8ec 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -201,17 +201,17 @@ return (health <= get_crit_threshold() && stat == UNCONSCIOUS) -/mob/living/Move(atom/newloc, direct) +/mob/living/Move(atom/newloc, direction, glide_size_override) if(buckled) if(buckled.loc != newloc) //not updating position if(!buckled.anchored) - return buckled.Move(newloc, direct) + return buckled.Move(newloc, direction, glide_size) else return FALSE else if(lying_angle) - if(direct & EAST) + if(direction & EAST) set_lying_angle(90) - else if(direct & WEST) + else if(direction & WEST) set_lying_angle(270) . = ..() @@ -871,12 +871,8 @@ below 100 is not dizzy hand = !hand SEND_SIGNAL(src, COMSIG_CARBON_SWAPPED_HANDS) if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) - hud_used.l_hand_hud_object.update_icon(hand) - hud_used.r_hand_hud_object.update_icon(!hand) - if(hand) //This being 1 means the left hand is in use - hud_used.l_hand_hud_object.add_overlay("hand_active") - else - hud_used.r_hand_hud_object.add_overlay("hand_active") + hud_used.l_hand_hud_object.update_icon() + hud_used.r_hand_hud_object.update_icon() return ///Swap to the hand clicked on the hud @@ -939,7 +935,7 @@ below 100 is not dizzy get_up() ///Sets up the jump component for the mob. Proc args can be altered so different mobs have different 'default' jump settings -/mob/living/proc/set_jump_component(duration = 0.5 SECONDS, cooldown = 1 SECONDS, cost = 8, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE) +/mob/living/proc/set_jump_component(duration = 0.5 SECONDS, cooldown = 1 SECONDS, cost = 8, height = 16, sound = null, flags = JUMP_SHADOW, flags_pass = PASS_LOW_STRUCTURE|PASS_FIRE|PASS_TANK) var/gravity = get_gravity() if(gravity < 1) //low grav duration *= 2.5 - gravity diff --git a/code/modules/mob/living/living_health_procs.dm b/code/modules/mob/living/living_health_procs.dm index f06b770cc75..65895f2de02 100644 --- a/code/modules/mob/living/living_health_procs.dm +++ b/code/modules/mob/living/living_health_procs.dm @@ -92,6 +92,7 @@ updateStamina(feedback) /mob/living/proc/updateStamina(feedback = TRUE) + hud_used?.staminas?.update_icon() if(staminaloss < max(health * 1.5,0) || !(COOLDOWN_CHECK(src, last_stamina_exhaustion))) //If we're on cooldown for stamina exhaustion, don't bother return @@ -105,21 +106,6 @@ adjust_blurriness(STAMINA_EXHAUSTION_DEBUFF_STACKS) COOLDOWN_START(src, last_stamina_exhaustion, LIVING_STAMINA_EXHAUSTION_COOLDOWN - (skills.getRating(SKILL_STAMINA) * STAMINA_SKILL_COOLDOWN_MOD)) //set the cooldown. - -/mob/living/carbon/human/updateStamina(feedback = TRUE) - . = ..() - if(!hud_used?.staminas) - return - if(stat == DEAD) - hud_used.staminas.icon_state = "stamloss200" - return - var/relative_stamloss = getStaminaLoss() - if(relative_stamloss < 0 && max_stamina) - relative_stamloss = round(((relative_stamloss * 14) / max_stamina), 1) - else - relative_stamloss = round(((relative_stamloss * 7) / (maxHealth * 2)), 1) - hud_used.staminas.icon_state = "stamloss[relative_stamloss]" - /// Adds an entry to our stamina_regen_modifiers and updates stamina_regen_multiplier /mob/living/proc/add_stamina_regen_modifier(mod_name, mod_value) if(stamina_regen_modifiers[mod_name] == mod_value) diff --git a/code/modules/mob/living/living_verbs.dm b/code/modules/mob/living/living_verbs.dm index 1d3806e4406..aae011baaec 100644 --- a/code/modules/mob/living/living_verbs.dm +++ b/code/modules/mob/living/living_verbs.dm @@ -38,11 +38,7 @@ if(!silent) to_chat(src, span_notice("You get up.")) SEND_SIGNAL(src, COMSIG_XENOMORPH_UNREST) - update_resting() - - -/mob/living/proc/update_resting() - hud_used?.rest_icon?.update_icon(src) + hud_used?.rest_icon?.update_icon() /mob/living/verb/ghost() diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 5f4ef743db4..97aeef106ec 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -93,7 +93,7 @@ return ..() -/mob/camera/aiEye/Move() +/mob/camera/aiEye/Move(atom/newloc, direction, glide_size_override) return FALSE diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index 680244b23c8..652c6bb1919 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -222,7 +222,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room) if(!silent) to_chat(src, span_warning("Cannot place more than [max_multicams] multicamera windows.")) return - var/atom/movable/screen/movable/pic_in_pic/ai/C = new /atom/movable/screen/movable/pic_in_pic/ai() + var/atom/movable/screen/movable/pic_in_pic/ai/C = new() C.set_view_size(3, 3, FALSE) C.set_view_center(get_turf(eyeobj)) C.set_ai(src) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 61420e9f7ee..af1fd20dfe8 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -18,6 +18,7 @@ /mob/living/silicon/Initialize(mapload) . = ..() + GLOB.silicon_mobs += src radio = new(src) if(SStts.tts_enabled) voice = pick(SStts.available_speakers) @@ -25,6 +26,7 @@ /mob/living/silicon/Destroy() QDEL_NULL(radio) + GLOB.silicon_mobs -= src return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index c9cb366bca4..db956f02486 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -393,7 +393,7 @@ return iswallturf(T) || ismineralturf(T) -/mob/living/simple_animal/hostile/Move(atom/newloc, dir , step_x , step_y) +/mob/living/simple_animal/hostile/Move(atom/newloc, direction, glide_size_override) if(dodging && approaching_target && prob(dodge_prob) && isturf(loc) && isturf(newloc)) return dodge(newloc,dir) else diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 41330bbeb4c..3f2eff2280d 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -34,6 +34,11 @@ GLOB.dead_mob_list += src set_focus(src) prepare_huds() + for(var/v in GLOB.active_alternate_appearances) + if(!v) + continue + var/datum/atom_hud/alternate_appearance/AA = v + AA.onNewMob(src) . = ..() if(islist(skills)) set_skills(getSkills(arglist(skills))) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 654a57c6173..aa513fc98a0 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -62,27 +62,23 @@ else mob.control_object.forceMove(get_step(mob.control_object, direct)) -#define MOVEMENT_DELAY_BUFFER 0.75 -#define MOVEMENT_DELAY_BUFFER_DELTA 1.25 - -/client/Move(n, direct) +/client/Move(atom/newloc, direction, glide_size_override) if(world.time < move_delay) //do not move anything ahead of this check please return FALSE - else - next_move_dir_add = 0 - next_move_dir_sub = 0 + next_move_dir_add = 0 + next_move_dir_sub = 0 var/old_move_delay = move_delay move_delay = world.time + world.tick_lag //this is here because Move() can now be called mutiple times per tick if(!mob?.loc) return FALSE - if(!n || !direct) + if(!newloc || !direction) return FALSE if(mob.notransform) return FALSE //This is sota the goto stop mobs from moving var if(mob.control_object) - return Move_object(direct) + return Move_object(direction) if(!isliving(mob)) - return mob.Move(n, direct) + return mob.Move(newloc, direction) if(mob.stat == DEAD && !HAS_TRAIT(mob, TRAIT_IS_RESURRECTING)) mob.ghostize() return FALSE @@ -90,10 +86,10 @@ var/mob/living/L = mob //Already checked for isliving earlier if(L.remote_control) //we're controlling something, our movement is relayed to it - return L.remote_control.relaymove(L, direct) + return L.remote_control.relaymove(L, direction) if(isAI(L)) - return AIMove(n, direct, L) + return AIMove(newloc, direction, L) //Check if you are being grabbed and if so attemps to break it if(SEND_SIGNAL(L, COMSIG_LIVING_DO_MOVE_RESIST) & COMSIG_LIVING_RESIST_SUCCESSFUL) @@ -111,14 +107,14 @@ return L.do_move_resist_grab() if(L.buckled) - return L.buckled.relaymove(L, direct) + return L.buckled.relaymove(L, direction) if(!L.canmove) return if(isobj(L.loc) || ismob(L.loc))//Inside an object, tell it we moved var/atom/O = L.loc - return O.relaymove(L, direct) + return O.relaymove(L, direction) var/add_delay = mob.cached_multiplicative_slowdown + mob.next_move_slowdown //RUTGMC EDIT ADDITION BEGIN - Preds @@ -126,7 +122,12 @@ add_delay += mob.shield_slowdown //RUTGMC EDIT ADDITION END mob.next_move_slowdown = 0 - if(old_move_delay + (add_delay * MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time) + mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * ( (NSCOMPONENT(direction) && EWCOMPONENT(direction)) ? DIAG_MOVEMENT_ADDED_DELAY_MULTIPLIER : 1 ) )) // set it now in case of pulled objects + //If the move was recent, count using old_move_delay + //We want fractional behavior and all + if(old_move_delay + world.tick_lag > world.time) + //Yes this makes smooth movement stutter if add_delay is too fractional + //Yes this is better then the alternative move_delay = old_move_delay else move_delay = world.time @@ -138,22 +139,20 @@ if(L.AmountConfused() > 40) newdir = pick(GLOB.alldirs) else if(prob(L.AmountConfused() * 1.5)) - newdir = angle2dir(dir2angle(direct) + pick(90, -90)) + newdir = angle2dir(dir2angle(direction) + pick(90, -90)) else if(prob(L.AmountConfused() * 3)) - newdir = angle2dir(dir2angle(direct) + pick(45, -45)) + newdir = angle2dir(dir2angle(direction) + pick(45, -45)) if(newdir) - direct = newdir - n = get_step(L, direct) + direction = newdir + newloc = get_step(L, direction) . = ..() - if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully + if((direction & (direction - 1)) && mob.loc == newloc) //moved diagonally successfully add_delay *= DIAG_MOVEMENT_ADDED_DELAY_MULTIPLIER + mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay)) move_delay += add_delay -#undef MOVEMENT_DELAY_BUFFER -#undef MOVEMENT_DELAY_BUFFER_DELTA - ///Process_Spacemove ///Called by /client/Move() ///For moving in space @@ -361,7 +360,7 @@ if(hud_used?.static_inventory) for(var/atom/movable/screen/mov_intent/selector in hud_used.static_inventory) - selector.update_icon(src) + selector.update_icon() return TRUE @@ -386,9 +385,9 @@ return FALSE switch(m_intent) if(MOVE_INTENT_WALK) - add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, NONE, TRUE, 4 + CONFIG_GET(number/movedelay/walk_delay)) + add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, NONE, TRUE, MOB_WALK_MOVE_MOD + CONFIG_GET(number/movedelay/walk_delay)) if(MOVE_INTENT_RUN) - add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, NONE, TRUE, 3 + CONFIG_GET(number/movedelay/run_delay)) + add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, NONE, TRUE, MOB_RUN_MOVE_MOD + CONFIG_GET(number/movedelay/run_delay)) /mob/proc/cadecheck() var/list/coords = list(list(x + 1, y, z), list(x, y + 1, z), list(x - 1, y, z), list(x, y - 1, z)) diff --git a/code/modules/mob/mob_movespeed.dm b/code/modules/mob/mob_movespeed.dm index 967a4c1f4a5..6b65336c374 100644 --- a/code/modules/mob/mob_movespeed.dm +++ b/code/modules/mob/mob_movespeed.dm @@ -132,13 +132,6 @@ Key procs return FALSE return TRUE -///Calculate the total slowdown of all movespeed modifiers -/mob/proc/total_multiplicative_slowdown() - . = 0 - for(var/id in get_movespeed_modifiers()) - var/list/data = movespeed_modification[id] - . += data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN] - ///Checks if a move speed modifier is valid and not missing any data /proc/movespeed_data_null_check(list/data) //Determines if a data list is not meaningful and should be discarded. . = TRUE diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 5b019faae00..8a80e501dba 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -293,7 +293,7 @@ popup.set_content(output) popup.open(FALSE) -/mob/new_player/Move() +/mob/new_player/Move(atom/newloc, direction, glide_size_override) return FALSE diff --git a/code/modules/paperwork/carbonpaper.dm b/code/modules/paperwork/carbonpaper.dm index 27357cecf4b..8639ccf0610 100644 --- a/code/modules/paperwork/carbonpaper.dm +++ b/code/modules/paperwork/carbonpaper.dm @@ -10,7 +10,8 @@ var/iscopy = 0 -/obj/item/paper/carbon/update_icon() +/obj/item/paper/carbon/update_icon_state() + . = ..() if(iscopy) if(info) icon_state = "cpaper_words" diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index f00baa297f2..5a1241ecbd2 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -35,14 +35,15 @@ return -/obj/item/clipboard/update_icon() - overlays.Cut() +/obj/item/clipboard/update_overlays() + . = ..() + if(toppaper) - overlays += toppaper.icon_state - overlays += toppaper.overlays + . += toppaper.icon_state + . += toppaper.overlays if(haspen) - overlays += "clipboard_pen" - overlays += "clipboard_over" + . += "clipboard_pen" + . += "clipboard_over" /obj/item/clipboard/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index 746aebeffcd..4c2e3f577a1 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -43,11 +43,11 @@ if(updateicon) update_icon() -/obj/item/folder/update_icon() - overlays.Cut() +/obj/item/folder/update_overlays() + . = ..() if(length(contents)) - overlays += "folder_paper" - return + . += "folder_paper" + /obj/item/folder/attackby(obj/item/I, mob/user, params) . = ..() diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index b37b62ba8e5..aa8693dd92a 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -51,9 +51,8 @@ update_icon() updateinfolinks() -/obj/item/paper/update_icon() - if(icon_state == "paper_talisman") - return +/obj/item/paper/update_icon_state() + . = ..() if(info) icon_state = "paper_words" return @@ -354,8 +353,9 @@ icon_state = "commendation" fields = 5 -/obj/item/paper/commendation/update_icon() //it looks fancy and we want it to stay fancy. +/obj/item/paper/commendation/update_icon_state() //it looks fancy and we want it to stay fancy. return + /*Let this be a lesson about pre-made forms. when building your paper, use the above parsed pen code in parsepencode(). no square bracket anything in the info field. @@ -432,7 +432,7 @@ then, for every time you included a field, increment fields. */ name = "paper scrap" icon_state = "scrap" -/obj/item/paper/crumpled/update_icon() +/obj/item/paper/crumpled/update_icon_state() return /obj/item/paper/crumpled/bloody/ diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm index 36bfd5eddd3..bb5997aca9e 100644 --- a/code/modules/paperwork/paper_bundle.dm +++ b/code/modules/paperwork/paper_bundle.dm @@ -196,36 +196,51 @@ usr.dropItemToGround(src) qdel(src) -/obj/item/paper_bundle/update_icon() +/obj/item/paper_bundle/update_icon_state() + . = ..() if(length(contents)) var/obj/item/I = contents[1] icon_state = I.icon_state - overlays = I.overlays + +/obj/item/paper_bundle/update_desc(updates) + . = ..() + var/paper_number = 0 + var/photo = FALSE + for(var/obj/thing in src) + if(istype(thing, /obj/item/paper)) + paper_number++ + else if(istype(thing, /obj/item/photo)) + photo = TRUE + if(paper_number>1) + desc = "[paper_number] papers clipped to each other." + else + desc = "A single sheet of paper." + if(photo) + desc += "There is a photo attached to it." + + +/obj/item/paper_bundle/update_overlays() + . = ..() + if(length(contents)) + var/obj/item/I = contents[1] + . = I.overlays underlays = 0 - var/i = 0 - var/photo + var/paper_number = 0 for(var/obj/O in src) var/image/IMG = image('icons/obj/items/paper.dmi') if(istype(O, /obj/item/paper)) IMG.icon_state = O.icon_state - IMG.pixel_x -= min(1*i, 2) - IMG.pixel_y -= min(1*i, 2) - pixel_x = min(0.5*i, 1) - pixel_y = min( 1*i, 2) + IMG.pixel_x -= min(1*paper_number, 2) + IMG.pixel_y -= min(1*paper_number, 2) + pixel_x = min(0.5*paper_number, 1) + pixel_y = min( 1*paper_number, 2) underlays += IMG - i++ + paper_number++ else if(istype(O, /obj/item/photo)) var/obj/item/photo/PH = O IMG = PH.picture.picture_icon - photo = 1 - overlays += IMG - if(i>1) - desc = "[i] papers clipped to each other." - else - desc = "A single sheet of paper." - if(photo) - desc += "\nThere is a photo attached to it." - overlays += image('icons/obj/items/paper.dmi', "clip") + . += IMG + . += image('icons/obj/items/paper.dmi', "clip") /obj/item/paper_bundle/proc/attach_doc(obj/item/I, mob/living/user, no_message) if(I.loc == user) diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index c3fd7b637b4..da6fbebe41a 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -66,7 +66,8 @@ . += span_notice("There are no papers in the bin.") -/obj/structure/paper_bin/update_icon() +/obj/structure/paper_bin/update_icon_state() + . = ..() if(amount < 1) icon_state = "paper_bin0" else diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index a4f224c4c2d..50edd24ff1a 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -103,7 +103,8 @@ return ..() -/obj/item/photo/update_icon() +/obj/item/photo/update_icon_state() + . = ..() if(!istype(picture) || !picture.picture_image) return var/icon/I = picture.get_small_icon() diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm deleted file mode 100644 index 5327936f159..00000000000 --- a/code/modules/power/apc.dm +++ /dev/null @@ -1,1136 +0,0 @@ -#define APC_RESET_EMP 5 - -#define APC_ELECTRONICS_MISSING 0 -#define APC_ELECTRONICS_INSTALLED 1 -#define APC_ELECTRONICS_SECURED 2 - -#define APC_COVER_CLOSED 0 -#define APC_COVER_OPENED 1 -#define APC_COVER_REMOVED 2 - -#define APC_NOT_CHARGING 0 -#define APC_CHARGING 1 -#define APC_FULLY_CHARGED 2 - -#define APC_EXTERNAL_POWER_NONE 0 -#define APC_EXTERNAL_POWER_LOW 1 -#define APC_EXTERNAL_POWER_GOOD 2 - -//The Area Power Controller (APC), formerly Power Distribution Unit (PDU) -//One per area, needs wire conection to power network - -//Controls power to devices in that area -//May be opened to change power cell -//Three different channels (lighting/equipment/environ) - may each be set to on, off, or auto - -/obj/machinery/power/apc - name = "area power controller" - desc = "A control terminal for the area electrical systems." - icon = 'icons/obj/machines/apc.dmi' - icon_state = "apc0" - //pixel_x = -16 - //pixel_y = -16 - anchored = TRUE - use_power = NO_POWER_USE - req_access = list(ACCESS_CIVILIAN_ENGINEERING) - resistance_flags = UNACIDABLE - interaction_flags = INTERACT_MACHINE_TGUI - light_range = 1 - light_power = 0.5 - var/area/area - var/areastring = null - var/obj/item/cell/cell - var/start_charge = 90 //Initial cell charge % - var/cell_type = /obj/item/cell/apc - var/opened = APC_COVER_CLOSED - var/shorted = FALSE - var/lighting = 3 - var/equipment = 3 - var/environ = 3 - var/operating = TRUE - var/charging = APC_NOT_CHARGING - var/chargemode = 1 - var/chargecount = 0 - var/locked = TRUE - var/coverlocked = TRUE - var/aidisabled = FALSE - var/obj/machinery/power/terminal/terminal = null - var/lastused_light = 0 - var/lastused_equip = 0 - var/lastused_environ = 0 - var/lastused_total = 0 - var/main_status = APC_EXTERNAL_POWER_NONE - var/debug = 0 - var/has_electronics = APC_ELECTRONICS_MISSING - var/overload = 1 //Used for the Blackout malf module - var/beenhit = 0 //Used for counting how many times it has been hit, used for Aliens at the moment - var/longtermpower = 10 - var/update_state = NONE - var/update_overlay = -1 - var/global/status_overlays = 0 - var/updating_icon = 0 - var/crash_break_probability = 85 //Probability of APC being broken by a shuttle crash on the same z-level - var/global/list/status_overlays_lock - var/global/list/status_overlays_charging - var/global/list/status_overlays_equipment - var/global/list/status_overlays_lighting - var/global/list/status_overlays_environ - var/obj/item/circuitboard/apc/electronics = null - -/obj/machinery/power/apc/connect_to_network() - //Override because the APC does not directly connect to the network; it goes through a terminal. - //The terminal is what the power computer looks for anyway. - if(terminal) - terminal.connect_to_network() - -/obj/machinery/power/apc/updateUsrDialog() - if(machine_stat & (BROKEN|MAINT)) - return - ..() - -/obj/machinery/power/apc/Initialize(mapload, ndir, building) - GLOB.apcs_list += src - wires = new /datum/wires/apc(src) - - // offset 32 pixels in direction of dir - // this allows the APC to be embedded in a wall, yet still inside an area - if (ndir) - setDir(ndir) - - switch(dir) - if(NORTH) - pixel_y = -32 - if(SOUTH) - pixel_y = 32 - if(EAST) - pixel_x = -32 - if(WEST) - pixel_x = 32 - - if(building) - var/area/A = get_area(src) - area = A - opened = APC_COVER_OPENED - operating = FALSE - name = "\improper [area.name] APC" - machine_stat |= MAINT - update_icon() - addtimer(CALLBACK(src, PROC_REF(update)), 5) - - start_processing() - - . = ..() - - var/area/A = get_area(src) - - //If area isn't specified use current - if(isarea(A) && areastring == null) - area = A - name = "\improper [area.name] APC" - else - area = get_area_name(areastring) - name = "\improper [area.name] APC" - - update_icon() - update() //areas should be lit on startup - - if(mapload) - has_electronics = APC_ELECTRONICS_SECURED - - //Is starting with a power cell installed, create it and set its charge level - if(cell_type) - set_cell(new cell_type(src)) - cell.charge = start_charge * cell.maxcharge / 100.0 //Convert percentage to actual value - cell.update_icon() - - make_terminal() - - update() //areas should be lit on startup - - //Break few ACPs on the colony - if(!start_charge && is_ground_level(z) && prob(10)) - addtimer(CALLBACK(src, PROC_REF(set_broken)), 5) - -/obj/machinery/power/apc/Destroy() - GLOB.apcs_list -= src - - area.power_light = 0 - area.power_equip = 0 - area.power_environ = 0 - area.power_change() - - QDEL_NULL(cell) - QDEL_NULL(wires) - if(terminal) - disconnect_terminal() - - return ..() - -///Wrapper to guarantee powercells are properly nulled and avoid hard deletes. -/obj/machinery/power/apc/proc/set_cell(obj/item/cell/new_cell) - if(cell) - UnregisterSignal(cell, COMSIG_QDELETING) - cell = new_cell - if(cell) - RegisterSignal(cell, COMSIG_QDELETING, PROC_REF(on_cell_deletion)) - -///Called by the deletion of the referenced powercell. -/obj/machinery/power/apc/proc/on_cell_deletion(obj/item/cell/source, force) - SIGNAL_HANDLER - set_cell(null) - -/obj/machinery/power/apc/proc/make_terminal() - //Create a terminal object at the same position as original turf loc - //Wires will attach to this - terminal = new(loc) - terminal.setDir(REVERSE_DIR(dir)) - terminal.master = src - -/obj/machinery/power/apc/examine(mob/user) - . = ..() - - if(machine_stat & BROKEN) - . += span_info("It appears to be completely broken. It's hard to see what else is wrong with it.") - return - - if(opened) - if(has_electronics && terminal) - . += span_info("The cover is [opened == APC_COVER_REMOVED ? "removed":"open"] and the power cell is [cell ? "installed":"missing"].") - else - . += span_info("It's [ !terminal ? "not" : "" ] wired up.") - . += span_info("The electronics are[!has_electronics?"n't":""] installed.") - else - if(machine_stat & MAINT) - . += span_info("The cover is closed. Something is wrong with it, it doesn't work.") - else - . += span_info("The cover is closed.") - - if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) - . += span_info("The wiring is exposed.") - -//Update the APC icon to show the three base states -//Also add overlays for indicator lights -/obj/machinery/power/apc/update_icon() //TODO JESUS CHRIST THIS IS SHIT - var/update = check_updates() //Returns 0 if no need to update icons. - //1 if we need to update the icon_state - //2 if we need to update the overlays - if(!update) - return - - set_light(0) - overlays.Cut() - - if(update & 1) - var/broken = CHECK_BITFIELD(update_state, UPSTATE_BROKE) ? "-b" : "" - var/status = (CHECK_BITFIELD(update_state, UPSTATE_WIREEXP) && !CHECK_BITFIELD(update_state, UPSTATE_OPENED1)) ? "-wires" : broken - icon_state = "apc[opened][status]" - - if(update & 2) - if(CHECK_BITFIELD(update_overlay, APC_UPOVERLAY_CELL_IN)) - overlays += "apco-cell" - else if(CHECK_BITFIELD(update_state, UPSTATE_ALLGOOD)) - overlays += emissive_appearance(icon, "apcox-[locked]") - overlays += mutable_appearance(icon, "apcox-[locked]") - overlays += emissive_appearance(icon, "apco3-[charging]") - overlays += mutable_appearance(icon, "apco3-[charging]") - var/operating = CHECK_BITFIELD(update_overlay, APC_UPOVERLAY_OPERATING) - overlays += emissive_appearance(icon, "apco0-[operating ? equipment : 0]") - overlays += mutable_appearance(icon, "apco0-[operating ? equipment : 0]") - overlays += emissive_appearance(icon, "apco1-[operating ? lighting : 0]") - overlays += mutable_appearance(icon, "apco1-[operating ? lighting : 0]") - overlays += emissive_appearance(icon, "apco2-[operating ? environ : 0]") - overlays += mutable_appearance(icon, "apco2-[operating ? environ : 0]") - - switch(charging) - if(APC_NOT_CHARGING) - set_light_color(LIGHT_COLOR_RED) - if(APC_CHARGING) - set_light_color(LIGHT_COLOR_BLUE) - if(APC_FULLY_CHARGED) - set_light_color(LIGHT_COLOR_GREEN) - set_light(initial(light_range)) - -/obj/machinery/power/apc/proc/check_updates() - - var/last_update_state = update_state - var/last_update_overlay = update_overlay - update_state = NONE - update_overlay = 0 - - if(machine_stat & BROKEN) - ENABLE_BITFIELD(update_state, UPSTATE_BROKE) - if(machine_stat & MAINT) - ENABLE_BITFIELD(update_state, UPSTATE_MAINT) - switch(opened) - if(APC_COVER_OPENED) - ENABLE_BITFIELD(update_state, UPSTATE_OPENED1) - if(APC_COVER_REMOVED) - ENABLE_BITFIELD(update_state, UPSTATE_OPENED2) - if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) - ENABLE_BITFIELD(update_state, UPSTATE_WIREEXP) - if(!update_state) - ENABLE_BITFIELD(update_state, UPSTATE_ALLGOOD) - if(locked) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_LOCKED) - if(operating) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_OPERATING) - - switch(charging) - if(APC_NOT_CHARGING) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_CHARGEING0) - if(APC_CHARGING) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_CHARGEING1) - if(APC_FULLY_CHARGED) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_CHARGEING2) - - switch(equipment) - if(0) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_EQUIPMENT0) - if(1) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_EQUIPMENT1) - if(2) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_EQUIPMENT2) - - switch(lighting) - if(0) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_LIGHTING0) - if(1) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_LIGHTING1) - if(2) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_LIGHTING2) - - switch(environ) - if(0) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_ENVIRON0) - if(1) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_ENVIRON1) - if(2) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_ENVIRON2) - - if(opened && cell && !CHECK_BITFIELD(update_state, UPSTATE_MAINT) && ((CHECK_BITFIELD(update_state, UPSTATE_OPENED1) && !CHECK_BITFIELD(update_state, UPSTATE_BROKE)) || CHECK_BITFIELD(update_state, UPSTATE_OPENED2))) - ENABLE_BITFIELD(update_overlay, APC_UPOVERLAY_CELL_IN) - - var/results = 0 - if(last_update_state == update_state && last_update_overlay == update_overlay) - return 0 - if(last_update_state != update_state) - results += 1 - if(last_update_overlay != update_overlay) - results += 2 - return results - -/obj/machinery/power/apc/proc/queue_icon_update() - updating_icon = TRUE - -/obj/machinery/power/apc/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE) - if(xeno_attacker.status_flags & INCORPOREAL) - return FALSE - - if(effects) - xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW) - xeno_attacker.visible_message(span_danger("[xeno_attacker] slashes \the [src]!"), \ - span_danger("We slash \the [src]!"), null, 5) - playsound(loc, "alien_claw_metal", 25, 1) - - var/allcut = wires.is_all_cut() - - if(beenhit >= pick(3, 4) && !CHECK_BITFIELD(machine_stat, PANEL_OPEN)) - ENABLE_BITFIELD(machine_stat, PANEL_OPEN) - update_icon() - visible_message(span_danger("\The [src]'s cover swings open, exposing the wires!"), null, null, 5) - - else if(CHECK_BITFIELD(machine_stat, PANEL_OPEN) && !allcut) - wires.cut_all() - update_icon() - visible_message(span_danger("\The [src]'s wires snap apart in a rain of sparks!"), null, null, 5) - if(xeno_attacker.client) - var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[xeno_attacker.ckey] - personal_statistics.apcs_slashed++ - else - beenhit += 1 - -//Attack with an item - open/close cover, insert cell, or (un)lock interface -/obj/machinery/power/apc/attackby(obj/item/I, mob/user, params) - . = ..() - - if(istype(I, /obj/item/cell) && opened) //Trying to put a cell inside - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - user.visible_message(span_notice("[user] fumbles around figuring out how to fit [I] into [src]."), - span_notice("You fumble around figuring out how to fit [I] into [src].")) - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - if(cell) - balloon_alert(user, "Already installed") - return - - if(machine_stat & MAINT) - balloon_alert(user, "No connector") - return - - if(!user.transferItemToLoc(I, src)) - return - - set_cell(I) - user.visible_message(span_notice("[user] inserts [I] into [src]!"), - span_notice("You insert [I] into [src]!")) - chargecount = 0 - update_icon() - - else if(istype(I, /obj/item/card/id)) //Trying to unlock the interface with an ID card - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - user.visible_message(span_notice("[user] fumbles around figuring out where to swipe [I] on [src]."), - span_notice("You fumble around figuring out where to swipe [I] on [src].")) - var/fumbling_time = 3 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - if(opened) - balloon_alert(user, "Close the cover first") - return - - if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) - balloon_alert(user, "Close the panel first") - return - - if(machine_stat & (BROKEN|MAINT)) - balloon_alert(user, "Nothing happens") - return - - if(!allowed(user)) - balloon_alert(user, "Access denied") - return - - locked = !locked - balloon_alert_to_viewers("[locked ? "locked" : "unlocked"]") - update_icon() - - else if(iscablecoil(I) && !terminal && opened && has_electronics != APC_ELECTRONICS_SECURED) - var/obj/item/stack/cable_coil/C = I - - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - var/turf/T = get_turf(src) - if(T.intact_tile) - balloon_alert(user, "Remove the floor plating") - return - - if(C.get_amount() < 10) - balloon_alert(user, "Not enough wires") - return - - balloon_alert_to_viewers("starts wiring [src]") - playsound(loc, 'sound/items/deconstruct.ogg', 25, 1) - - if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD) || terminal || !opened || has_electronics == APC_ELECTRONICS_SECURED) - return - - var/obj/structure/cable/N = T.get_cable_node() - if(prob(50) && electrocute_mob(user, N, N)) - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(5, 1, src) - s.start() - return - - if(!C.use(10)) - return - - balloon_alert_to_viewers("Wired]") - make_terminal() - terminal.connect_to_network() - - else if(istype(I, /obj/item/circuitboard/apc) && opened && has_electronics == APC_ELECTRONICS_MISSING && !(machine_stat & BROKEN)) - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - balloon_alert_to_viewers("Tries to insert APC board into [src]") - playsound(loc, 'sound/items/deconstruct.ogg', 25, 1) - - if(!do_after(user, 15, NONE, src, BUSY_ICON_BUILD)) - return - - has_electronics = APC_ELECTRONICS_INSTALLED - balloon_alert_to_viewers("Inserts APC board into [src]") - electronics = I - qdel(I) - - else if(istype(I, /obj/item/circuitboard/apc) && opened && has_electronics == APC_ELECTRONICS_MISSING && (machine_stat & BROKEN)) - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - balloon_alert(user, "Cannot, frame damaged") - - else if(istype(I, /obj/item/frame/apc) && opened && (machine_stat & BROKEN)) - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - if(has_electronics) - balloon_alert(user, "Cannot, electronics still inside") - return - - balloon_alert_to_viewers("Begins replacing front panel") - - if(!do_after(user, 50, NONE, src, BUSY_ICON_BUILD)) - return - - balloon_alert_to_viewers("Replaces front panel") - qdel(I) - DISABLE_BITFIELD(machine_stat, BROKEN) - if(opened == APC_COVER_REMOVED) - opened = APC_COVER_OPENED - update_icon() - - else if(istype(I, /obj/item/frame/apc) && opened) - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - if(opened == APC_COVER_REMOVED) - opened = APC_COVER_OPENED - balloon_alert_to_viewers("Replaces [src]'s front panel") - qdel(I) - update_icon() - - else - if(((machine_stat & BROKEN)) && !opened && I.force >= 5) - opened = APC_COVER_REMOVED - balloon_alert_to_viewers("Knocks down [src]'s panel") - update_icon() - else - if(issilicon(user)) - return attack_hand(user) - - if(!opened && CHECK_BITFIELD(machine_stat, PANEL_OPEN) && (ismultitool(I) || iswirecutter(I))) - return attack_hand(user) - balloon_alert_to_viewers("Hits [src] with [I]") - -/obj/machinery/power/apc/crowbar_act(mob/user, obj/item/I) - . = TRUE - if(opened) - if(has_electronics == APC_ELECTRONICS_INSTALLED) - if(terminal) - balloon_alert(user, "Disconnect the wires") - return - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("Fumbles around removing cell from [src]") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - I.play_tool_sound(src) - balloon_alert(user, "Removing APC board") - if(I.use_tool(src, user, 50)) - if(has_electronics == APC_ELECTRONICS_INSTALLED) - has_electronics = APC_ELECTRONICS_MISSING - if(machine_stat & BROKEN) - balloon_alert_to_viewers("Removes the charred control board") - return - else - balloon_alert_to_viewers("Removes the control board") - new /obj/item/circuitboard/apc(loc) - return - else if(opened != APC_COVER_REMOVED) - opened = APC_COVER_CLOSED - coverlocked = TRUE //closing cover relocks it - update_icon() - return - else if(!(machine_stat & BROKEN)) - if(coverlocked && !(machine_stat & MAINT)) // locked... - balloon_alert(user, "Locked") - return - else if(machine_stat & PANEL_OPEN) - balloon_alert(user, "Can't, wires in way") - return - else - opened = APC_COVER_OPENED - update_icon() - return - -/obj/machinery/power/apc/screwdriver_act(mob/living/user, obj/item/I) - . = ..() - if(.) - return TRUE - . = TRUE - if(opened) - if(cell) - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - balloon_alert_to_viewers("Removes cell") - var/turf/T = get_turf(user) - cell.forceMove(T) - cell.update_icon() - set_cell(null) - charging = APC_NOT_CHARGING - update_icon() - return - else - switch(has_electronics) - if(APC_ELECTRONICS_INSTALLED) - has_electronics = APC_ELECTRONICS_SECURED - machine_stat &= ~MAINT - I.play_tool_sound(src) - balloon_alert(user, "Screws circuit board in") - if(APC_ELECTRONICS_SECURED) - has_electronics = APC_ELECTRONICS_INSTALLED - machine_stat |= MAINT - I.play_tool_sound(src) - balloon_alert(user, "Unfastens electronics") - else - balloon_alert(user, "Nothing securable") - return - update_icon() - else - TOGGLE_BITFIELD(machine_stat, PANEL_OPEN) - balloon_alert(user, "wires [CHECK_BITFIELD(machine_stat, PANEL_OPEN) ? "exposed" : "unexposed"]") - update_icon() - -/obj/machinery/power/apc/wirecutter_act(mob/living/user, obj/item/I) - if(terminal && opened) - terminal.deconstruct(user) - return TRUE - -/obj/machinery/power/apc/welder_act(mob/living/user, obj/item/I) - if(!opened || has_electronics || terminal) - return - - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - if(!I.tool_start_check(user, amount = 3)) - return - balloon_alert_to_viewers("welds [src]") - - if(!I.use_tool(src, user, 50, volume = 50, amount = 3)) - return - - if((machine_stat & BROKEN) || opened == APC_COVER_REMOVED) - new /obj/item/stack/sheet/metal(loc) - balloon_alert_to_viewers("cuts apart [src]") - else - new /obj/item/frame/apc(loc) - balloon_alert_to_viewers("cuts [src] from the wall") - qdel(src) - return TRUE - -//Attack with hand - remove cell (if cover open) or interact with the APC -/obj/machinery/power/apc/attack_hand(mob/living/user) - . = ..() - if(.) - return - - if(!ishuman(user)) - return FALSE - var/mob/living/carbon/human/grabber = user - if(grabber.a_intent != INTENT_GRAB) - return FALSE - // Yautja Bracer Recharge - var/obj/item/clothing/gloves/yautja/bracer = grabber.gloves - if(istype(bracer)) - if(!COOLDOWN_CHECK(bracer, bracer_recharge)) - to_chat(user, span_warning("It is too soon for [bracer.name] to siphon power again. Wait [COOLDOWN_TIMELEFT(bracer, bracer_recharge)] seconds.")) - return FALSE - to_chat(user, span_notice("You rest your bracer against the APC interface and begin to siphon off some of the stored energy.")) - if(!do_after(grabber, 20, TRUE, src, BUSY_ICON_HOSTILE)) - return FALSE - - if(machine_stat & (BROKEN|MAINT)) - var/datum/effect_system/spark_spread/spark = new() - spark.set_up(3, 1, src) - spark.start() - to_chat(grabber, span_danger("The APC's power currents surge eratically, super-heating your bracer!")) - playsound(src.loc, 'sound/effects/sparks2.ogg', 25, 1) - grabber.apply_damage(10,0, BURN) - return FALSE - if(!cell || cell.charge <= 0) - to_chat(user, span_warning("There is no charge to draw from that APC.")) - return FALSE - - if(bracer.charge_max <= bracer.charge) - to_chat(user, span_warning("[bracer.name] is already fully charged.")) - return FALSE - - var/charge_to_use = min(cell.charge, bracer.charge_max - bracer.charge) - if(!(cell.use(charge_to_use))) - return FALSE - playsound(src.loc, 'sound/effects/sparks2.ogg', 25, 1) - bracer.charge += charge_to_use - COOLDOWN_START(bracer, bracer_recharge, bracer.charge_cooldown) - to_chat(grabber, span_yautjabold("[icon2html(bracer)] \The [bracer] beep: Power siphon complete. Charge at [bracer.charge]/[bracer.charge_max].")) - if(bracer.notification_sound) - playsound(bracer.loc, 'sound/items/pred_bracer.ogg', 75, 1) - charging = APC_CHARGING - set_broken() // Breaks the APC - - return TRUE - - if(opened && cell && !issilicon(user)) - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) - balloon_alert_to_viewers("fumbles") - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - balloon_alert_to_viewers("removes [src] from [src]") - user.put_in_hands(cell) - cell.update_icon() - set_cell(null) - charging = APC_NOT_CHARGING - update_icon() - return - - if(machine_stat & (BROKEN|MAINT)) - return - - interact(user) - -/obj/machinery/power/apc/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - - if(!ui) - ui = new(user, src, "Apc", name) - ui.open() - -/obj/machinery/power/apc/ui_data(mob/user) - var/list/data = list( - "locked" = locked, - "isOperating" = operating, - "externalPower" = main_status, - "powerCellStatus" = cell ? cell.percent() : null, - "chargeMode" = chargemode, - "chargingStatus" = charging, - "totalLoad" = DisplayPower(lastused_total), - "coverLocked" = coverlocked, - "siliconUser" = issilicon(user), - - "powerChannels" = list( - list( - "title" = "Equipment", - "powerLoad" = DisplayPower(lastused_equip), - "status" = equipment, - "topicParams" = list( - "auto" = list("eqp" = 3), - "on" = list("eqp" = 2), - "off" = list("eqp" = 1) - ) - ), - list( - "title" = "Lighting", - "powerLoad" = DisplayPower(lastused_light), - "status" = lighting, - "topicParams" = list( - "auto" = list("lgt" = 3), - "on" = list("lgt" = 2), - "off" = list("lgt" = 1) - ) - ), - list( - "title" = "Environment", - "powerLoad" = DisplayPower(lastused_environ), - "status" = environ, - "topicParams" = list( - "auto" = list("env" = 3), - "on" = list("env" = 2), - "off" = list("env" = 1) - ) - ) - ) - ) - return data - -/obj/machinery/power/apc/proc/setsubsystem(val) - if(cell?.charge > 0) - return (val==1) ? 0 : val - else if(val == 3) - return 1 - else - return 0 - -/obj/machinery/power/apc/proc/can_use(mob/user, loud = FALSE) //used by attack_hand() and Topic() - if(IsAdminGhost(user)) - return TRUE - if(isAI(user) && aidisabled) - if(!loud) - balloon_alert(user, "eee is disabled") - return FALSE - return TRUE - -/obj/machinery/power/apc/ui_act(action, list/params) - . = ..() - if(. || !can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege)) - return - switch(action) - if("lock") - if(usr.has_unlimited_silicon_privilege) - if((machine_stat & (BROKEN|MAINT))) - balloon_alert(usr, "APC unresponsive") - else - locked = !locked - update_icon() - . = TRUE - if("cover") - coverlocked = !coverlocked - . = TRUE - if("breaker") - toggle_breaker(usr) - . = TRUE - if("charge") - chargemode = !chargemode - if(!chargemode) - charging = APC_NOT_CHARGING - update_icon() - . = TRUE - if("channel") - if(params["eqp"]) - equipment = setsubsystem(text2num(params["eqp"])) - update_icon() - update() - else if(params["lgt"]) - lighting = setsubsystem(text2num(params["lgt"])) - update_icon() - update() - else if(params["env"]) - environ = setsubsystem(text2num(params["env"])) - update_icon() - update() - . = TRUE - if("overload") - if(usr.has_unlimited_silicon_privilege) - overload_lighting() - . = TRUE - return TRUE - -/obj/machinery/power/apc/proc/report() - return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" - -/obj/machinery/power/apc/proc/update() - if(operating && !shorted) - area.power_light = (lighting > 1) - area.power_equip = (equipment > 1) - area.power_environ = (environ > 1) - else - area.power_light = 0 - area.power_equip = 0 - area.power_environ = 0 - area.power_change() - -/obj/machinery/power/apc/proc/reset(wire) - switch(wire) - if(WIRE_IDSCAN) - locked = TRUE - if(WIRE_POWER1, WIRE_POWER2) - if(!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2)) - shorted = FALSE - if(WIRE_AI) - if(!wires.is_cut(WIRE_AI)) - aidisabled = FALSE - if(APC_RESET_EMP) - equipment = 3 - environ = 3 - update_icon() - update() - -/obj/machinery/power/apc/surplus() - if(terminal) - return terminal.surplus() - else - return 0 - -/obj/machinery/power/apc/add_load(amount) - if(terminal?.powernet) - return terminal.add_load(amount) - return 0 - -/obj/machinery/power/apc/avail() - if(terminal) - return terminal.avail() - else - return 0 - -/obj/machinery/power/apc/process() - if(updating_icon) - update_icon() - if(machine_stat & (BROKEN|MAINT)) - return - if(!area.requires_power) - return - - lastused_light = area.usage(STATIC_LIGHTS) - lastused_light += area.usage(LIGHT) - lastused_equip = area.usage(EQUIP) - lastused_equip += area.usage(STATIC_EQUIP) - lastused_environ = area.usage(ENVIRON) - lastused_environ += area.usage(STATIC_ENVIRON) - area.clear_usage() - - lastused_total = lastused_light + lastused_equip + lastused_environ - - //store states to update icon if any change - var/last_lt = lighting - var/last_eq = equipment - var/last_en = environ - var/last_ch = charging - - var/excess = surplus() - - if(!avail()) - main_status = APC_EXTERNAL_POWER_NONE - else if(excess < 0) - main_status = APC_EXTERNAL_POWER_LOW - else - main_status = APC_EXTERNAL_POWER_GOOD - - if(cell && !shorted) - // draw power from cell as before to power the area - var/cellused = min(cell.charge, GLOB.CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell - cell.use(cellused) - - if(excess > lastused_total) // if power excess recharge the cell - // by the same amount just used - cell.give(cellused) - add_load(cellused / GLOB.CELLRATE) // add the load used to recharge the cell - - - else // no excess, and not enough per-apc - if((cell.charge / GLOB.CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage? - cell.charge = min(cell.maxcharge, cell.charge + GLOB.CELLRATE * excess) //recharge with what we can - add_load(excess) // so draw what we can from the grid - charging = APC_NOT_CHARGING - - else // not enough power available to run the last tick! - charging = APC_NOT_CHARGING - chargecount = 0 - // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room. - equipment = autoset(equipment, 0) - lighting = autoset(lighting, 0) - environ = autoset(environ, 0) - - // set channels depending on how much charge we have left - - // Allow the APC to operate as normal if the cell can charge - if(charging && longtermpower < 10) - longtermpower += 1 - else if(longtermpower > -10) - longtermpower -= 2 - - if(cell.charge <= 0) // zero charge, turn all off - equipment = autoset(equipment, 0) - lighting = autoset(lighting, 0) - environ = autoset(environ, 0) - area.poweralert(0, src) - else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment - equipment = autoset(equipment, 2) - lighting = autoset(lighting, 2) - environ = autoset(environ, 1) - area.poweralert(0, src) - else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment - equipment = autoset(equipment, 2) - lighting = autoset(lighting, 1) - environ = autoset(environ, 1) - area.poweralert(0, src) - else // otherwise all can be on - equipment = autoset(equipment, 1) - lighting = autoset(lighting, 1) - environ = autoset(environ, 1) - area.poweralert(1, src) - if(cell.percent() > 75) - area.poweralert(1, src) - - // now trickle-charge the cell - if(chargemode && charging == APC_CHARGING && operating) - if(excess > 0) // check to make sure we have enough to charge - // Max charge is capped to % per second constant - var/ch = min(excess*GLOB.CELLRATE, cell.maxcharge*GLOB.CHARGELEVEL) - add_load(ch/GLOB.CELLRATE) // Removes the power we're taking from the grid - cell.give(ch) // actually recharge the cell - - else - charging = APC_NOT_CHARGING // stop charging - chargecount = 0 - - // show cell as fully charged if so - if(cell.charge >= cell.maxcharge) - cell.charge = cell.maxcharge - charging = APC_FULLY_CHARGED - - if(chargemode) - if(!charging) - if(excess > cell.maxcharge * GLOB.CHARGELEVEL) - chargecount++ - else - chargecount = 0 - - if(chargecount == 10) - - chargecount = 0 - charging = APC_CHARGING - - else // chargemode off - charging = APC_NOT_CHARGING - chargecount = 0 - - else // no cell, switch everything off - charging = APC_NOT_CHARGING - chargecount = 0 - equipment = autoset(equipment, 0) - lighting = autoset(lighting, 0) - environ = autoset(environ, 0) - area.poweralert(0, src) - - // update icon & area power if anything changed - if(last_lt != lighting || last_eq != equipment || last_en != environ) - queue_icon_update() - update() - else if(last_ch != charging) - queue_icon_update() - -//val 0 = off, 1 = off(auto) 2 = on, 3 = on(auto) -//on 0 = off, 1 = auto-on, 2 = auto-off - -/proc/autoset(val, on) - - switch(on) - if(0) //Turn things off - switch(val) - if(2) //If on, return off - return 0 - if(3) //If auto-on, return auto-off - return 1 - - if(1) //Turn things auto-on - if(val == 1) //If auto-off, return auto-on - return 3 - - if(2) //Turn things auto-off - if(val == 3) //If auto-on, return auto-off - return 1 - return val - -/obj/machinery/power/apc/emp_act(severity) - if(cell) - cell.emp_act(severity) - lighting = 0 - equipment = 0 - environ = 0 - update_icon() - update() - addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 60 SECONDS) - return ..() - -/obj/machinery/power/apc/ex_act(severity) - if(severity >= EXPLODE_HEAVY) - qdel(src) - else if(prob(severity / 2)) - set_broken() - cell.ex_act(severity) - -/obj/machinery/power/apc/proc/set_broken() - //Aesthetically much better! - visible_message(span_warning("[src]'s screen flickers with warnings briefly!")) - addtimer(CALLBACK(src, PROC_REF(do_break)), rand(2, 5)) - -/obj/machinery/power/apc/proc/do_break() - visible_message(span_danger("[src]'s screen suddenly explodes in rain of sparks and small debris!")) - machine_stat |= BROKEN - operating = FALSE - update_icon() - update() - -//Overload all the lights in this APC area -/obj/machinery/power/apc/proc/overload_lighting() - if(!operating || shorted) - return - if(cell?.charge >= 20) - cell.use(20) - INVOKE_ASYNC(src, PROC_REF(break_lights)) - -/obj/machinery/power/apc/proc/break_lights() - for(var/obj/machinery/light/L in get_area(src)) - L.broken() - stoplag() - -/obj/machinery/power/apc/disconnect_terminal() - if(terminal) - terminal.master = null - terminal = null - -/obj/machinery/power/apc/proc/toggle_breaker(mob/user) - if(machine_stat & (NOPOWER|BROKEN|MAINT)) - return - - operating = !operating - log_combat(user, src, "turned [operating ? "on" : "off"]") - update() - update_icon() - -//------Various APCs ------// - -// mapping helpers -/obj/machinery/power/apc/drained - start_charge = 0 - -/obj/machinery/power/apc/lowcharge - start_charge = 25 - -/obj/machinery/power/apc/potato - cell_type = /obj/item/cell/potato - -/obj/machinery/power/apc/weak - cell_type = /obj/item/cell - -/obj/machinery/power/apc/high - cell_type = /obj/item/cell/high - -/obj/machinery/power/apc/super - cell_type = /obj/item/cell/super - -/obj/machinery/power/apc/hyper - cell_type = /obj/item/cell/hyper - -//------Marine ship APCs ------// - -/obj/machinery/power/apc/mainship - req_access = list(ACCESS_MARINE_ENGINEERING) - cell_type = /obj/item/cell/high - -/obj/machinery/power/apc/mainship/hardened - name = "hardened area power controller" - desc = "A control terminal for the area electrical systems. This one is hardened against sudden power fluctuations caused by electrical grid damage." - crash_break_probability = 0 - -#undef APC_RESET_EMP - -#undef APC_ELECTRONICS_MISSING -#undef APC_ELECTRONICS_INSTALLED -#undef APC_ELECTRONICS_SECURED - -#undef APC_COVER_CLOSED -#undef APC_COVER_OPENED -#undef APC_COVER_REMOVED - -#undef APC_NOT_CHARGING -#undef APC_CHARGING -#undef APC_FULLY_CHARGED - -#undef APC_EXTERNAL_POWER_NONE -#undef APC_EXTERNAL_POWER_LOW -#undef APC_EXTERNAL_POWER_GOOD diff --git a/code/modules/power/apc/apc.dm b/code/modules/power/apc/apc.dm new file mode 100644 index 00000000000..fd28cb01f02 --- /dev/null +++ b/code/modules/power/apc/apc.dm @@ -0,0 +1,655 @@ +//The Area Power Controller (APC), formerly Power Distribution Unit (PDU) +//One per area, needs wire conection to power network + +//Controls power to devices in that area +//May be opened to change power cell +//Three different channels (lighting/equipment/environ) - may each be set to on, off, or auto + + +/obj/machinery/power/apc + name = "area power controller" + desc = "A control terminal for the area electrical systems." + icon = 'icons/obj/machines/apc.dmi' + icon_state = "apc0" + anchored = TRUE + use_power = NO_POWER_USE + req_access = list(ACCESS_CIVILIAN_ENGINEERING) + resistance_flags = UNACIDABLE + interaction_flags = INTERACT_MACHINE_TGUI + light_range = 1 + light_power = 0.5 + ///The area we're affecting + var/area/area + ///The power cell inside the APC + var/obj/item/cell/cell + ///The charge of the APC when first spawned + var/start_charge = 90 + ///The type of cell to spawn this APC with + var/cell_type = /obj/item/cell/apc + ///The current state of the APC cover + var/opened = APC_COVER_CLOSED + ///Is the APC shorted? + var/shorted = FALSE + ///State of the lighting channel (off, auto off, on, auto on) + var/lighting = APC_CHANNEL_AUTO_ON + ///State of the equipment channel (off, auto off, on, auto on) + var/equipment = APC_CHANNEL_AUTO_ON + ///State of the environmental channel (off, auto off, on, auto on) + var/environ = APC_CHANNEL_AUTO_ON + ///Is the apc working? + var/operating = TRUE + ///State of the apc charging (not charging, charging, fully charged) + var/charging = APC_NOT_CHARGING + ///Can the APC recharge? + var/chargemode = TRUE + ///Number of ticks where the apc is trying to recharge + var/chargecount = 0 + ///Is the apc interface locked? + var/locked = TRUE + ///Is the apc cover locked? + var/coverlocked = TRUE + ///Is the AI locked from using the APC + var/aidisabled = FALSE + ///Reference to our cable terminal + var/obj/machinery/power/terminal/terminal = null + ///Amount of power used by the lighting channel + var/lastused_light = 0 + ///Amount of power used by the equipment channel + var/lastused_equip = 0 + ///Amount of power used by the environmental channel + var/lastused_environ = 0 + ///Total amount of power used by the three channels + var/lastused_total = 0 + var/main_status = APC_EXTERNAL_POWER_NONE + ///State of the electronics inside (missing, installed, secured) + var/has_electronics = APC_ELECTRONICS_MISSING + ///Used for counting how many times it has been hit, used for Aliens at the moment + var/beenhit = 0 + ///Buffer state that makes apcs not shut off channels immediately as long as theres some power left, effect visible in apcs only slowly losing power + var/longtermpower = 10 + ///Stores the flags related to icon updating + var/update_state = NONE + ///Stores the flag for the overlays + var/update_overlay = NONE + ///Used to stop the icon from updating too much + var/icon_update_needed = FALSE + ///Probability of APC being broken by a shuttle crash on the same z-level + var/crash_break_probability = 85 + +/obj/machinery/power/apc/connect_to_network() + //Override because the APC does not directly connect to the network; it goes through a terminal. + //The terminal is what the power computer looks for anyway. + if(terminal) + terminal.connect_to_network() + +/obj/machinery/power/apc/updateUsrDialog() + if(machine_stat & (BROKEN|MAINT)) + return + return ..() + +/obj/machinery/power/apc/Initialize(mapload, ndir, building) + GLOB.apcs_list += src + wires = new /datum/wires/apc(src) + + // offset 32 pixels in direction of dir + // this allows the APC to be embedded in a wall, yet still inside an area + if (ndir) + setDir(ndir) + + switch(dir) + if(NORTH) + pixel_y = -32 + if(SOUTH) + pixel_y = 32 + if(EAST) + pixel_x = -32 + if(WEST) + pixel_x = 32 + + if(building) + var/area/A = get_area(src) + area = A + opened = APC_COVER_OPENED + operating = FALSE + name = "\improper [area.name] APC" + machine_stat |= MAINT + update_icon() + addtimer(CALLBACK(src, PROC_REF(update)), 5) + + start_processing() + + . = ..() + + var/area/A = get_area(src) + area = A + name = "\improper [area.name] APC" + + update_icon() + update() //areas should be lit on startup + + if(mapload) + has_electronics = APC_ELECTRONICS_SECURED + + //Is starting with a power cell installed, create it and set its charge level + if(cell_type) + set_cell(new cell_type(src)) + cell.charge = start_charge * cell.maxcharge / 100.0 //Convert percentage to actual value + cell.update_icon() + + + make_terminal() + + update() //areas should be lit on startup + + //Break few ACPs on the colony + if(!start_charge && is_ground_level(z) && prob(10)) + addtimer(CALLBACK(src, PROC_REF(set_broken)), 5) + +/obj/machinery/power/apc/Destroy() + GLOB.apcs_list -= src + + area.power_light = 0 + area.power_equip = 0 + area.power_environ = 0 + area.power_change() + + QDEL_NULL(cell) + QDEL_NULL(wires) + if(terminal) + disconnect_terminal() + + return ..() + +///Wrapper to guarantee powercells are properly nulled and avoid hard deletes. +/obj/machinery/power/apc/proc/set_cell(obj/item/cell/new_cell) + if(cell) + UnregisterSignal(cell, COMSIG_QDELETING) + cell = new_cell + if(cell) + RegisterSignal(cell, COMSIG_QDELETING, PROC_REF(on_cell_deletion)) + + +///Called by the deletion of the referenced powercell. +/obj/machinery/power/apc/proc/on_cell_deletion(obj/item/cell/source, force) + SIGNAL_HANDLER + set_cell(null) + + +/obj/machinery/power/apc/proc/make_terminal() + //Create a terminal object at the same position as original turf loc + //Wires will attach to this + terminal = new(loc) + terminal.setDir(REVERSE_DIR(dir)) + terminal.master = src + +/obj/machinery/power/apc/examine(mob/user) + . = ..() + + if(machine_stat & BROKEN) + . += span_info("It appears to be completely broken. It's hard to see what else is wrong with it.") + return + + if(opened) + if(has_electronics && terminal) + . += span_info("The cover is [opened == APC_COVER_REMOVED ? "removed":"open"] and the power cell is [cell ? "installed":"missing"].") + else + . += span_info("It's [ !terminal ? "not" : "" ] wired up.") + . += span_info("The electronics are[!has_electronics?"n't":""] installed.") + else + if(machine_stat & MAINT) + . += span_info("The cover is closed. Something is wrong with it, it doesn't work.") + else + . += span_info("The cover is closed.") + + if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) + . += span_info("The wiring is exposed.") + +/obj/machinery/power/apc/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + + if(!ui) + ui = new(user, src, "Apc", name) + ui.open() + +/obj/machinery/power/apc/ui_data(mob/user) + var/list/data = list( + "locked" = locked, + "isOperating" = operating, + "externalPower" = main_status, + "powerCellStatus" = cell ? cell.percent() : null, + "chargeMode" = chargemode, + "chargingStatus" = charging, + "totalLoad" = DisplayPower(lastused_total), + "coverLocked" = coverlocked, + "siliconUser" = issilicon(user), + + "powerChannels" = list( + list( + "title" = "Equipment", + "powerLoad" = DisplayPower(lastused_equip), + "status" = equipment, + "topicParams" = list( + "auto" = list("eqp" = 3), + "on" = list("eqp" = 2), + "off" = list("eqp" = 1) + ) + ), + list( + "title" = "Lighting", + "powerLoad" = DisplayPower(lastused_light), + "status" = lighting, + "topicParams" = list( + "auto" = list("lgt" = 3), + "on" = list("lgt" = 2), + "off" = list("lgt" = 1) + ) + ), + list( + "title" = "Environment", + "powerLoad" = DisplayPower(lastused_environ), + "status" = environ, + "topicParams" = list( + "auto" = list("env" = 3), + "on" = list("env" = 2), + "off" = list("env" = 1) + ) + ) + ) + ) + return data + + +/obj/machinery/power/apc/proc/setsubsystem(val) + if(cell?.charge > 0) + return (val==1) ? 0 : val + else if(val == 3) + return 1 + else + return 0 + +/obj/machinery/power/apc/proc/can_use(mob/user, loud = FALSE) //used by attack_hand() and Topic() + if(IsAdminGhost(user)) + return TRUE + if(isAI(user) && aidisabled) + if(!loud) + balloon_alert(user, "eee is disabled") + return FALSE + return TRUE + +/obj/machinery/power/apc/ui_act(action, list/params) + . = ..() + if(. || !can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege)) + return + switch(action) + if("lock") + if(usr.has_unlimited_silicon_privilege) + if((machine_stat & (BROKEN|MAINT))) + balloon_alert(usr, "APC unresponsive") + else + locked = !locked + update_icon() + . = TRUE + if("cover") + coverlocked = !coverlocked + . = TRUE + if("breaker") + toggle_breaker(usr) + . = TRUE + if("charge") + chargemode = !chargemode + if(!chargemode) + charging = APC_NOT_CHARGING + update_icon() + . = TRUE + if("channel") + if(params["eqp"]) + equipment = setsubsystem(text2num(params["eqp"])) + update_icon() + update() + else if(params["lgt"]) + lighting = setsubsystem(text2num(params["lgt"])) + update_icon() + update() + else if(params["env"]) + environ = setsubsystem(text2num(params["env"])) + update_icon() + update() + . = TRUE + if("overload") + if(usr.has_unlimited_silicon_privilege) + overload_lighting() + . = TRUE + return TRUE + +/obj/machinery/power/apc/proc/report() + return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" + + +/obj/machinery/power/apc/proc/update() + if(operating && !shorted) + area.power_light = (lighting > 1) + area.power_equip = (equipment > 1) + area.power_environ = (environ > 1) + else + area.power_light = 0 + area.power_equip = 0 + area.power_environ = 0 + area.power_change() + + +/obj/machinery/power/apc/proc/reset(wire) + switch(wire) + if(WIRE_IDSCAN) + locked = TRUE + if(WIRE_POWER1, WIRE_POWER2) + if(!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2)) + shorted = FALSE + if(WIRE_AI) + if(!wires.is_cut(WIRE_AI)) + aidisabled = FALSE + if(APC_RESET_EMP) + equipment = 3 + environ = 3 + update_icon() + update() + +/obj/machinery/power/apc/surplus() + if(terminal) + return terminal.surplus() + else + return 0 + + +/obj/machinery/power/apc/add_load(amount) + if(terminal?.powernet) + return terminal.add_load(amount) + return 0 + + +/obj/machinery/power/apc/avail() + if(terminal) + return terminal.avail() + else + return 0 + + +/obj/machinery/power/apc/process() + if(icon_update_needed) + update_icon() + if(machine_stat & (BROKEN|MAINT)) + return + if(!area.requires_power) + return + + lastused_light = area.usage(STATIC_LIGHTS) + lastused_light += area.usage(LIGHT) + lastused_equip = area.usage(EQUIP) + lastused_equip += area.usage(STATIC_EQUIP) + lastused_environ = area.usage(ENVIRON) + lastused_environ += area.usage(STATIC_ENVIRON) + area.clear_usage() + + lastused_total = lastused_light + lastused_equip + lastused_environ + + //store states to update icon if any change + var/last_lt = lighting + var/last_eq = equipment + var/last_en = environ + var/last_ch = charging + + var/excess = surplus() + + if(!avail()) + main_status = APC_EXTERNAL_POWER_NONE + else if(excess < 0) + main_status = APC_EXTERNAL_POWER_LOW + else + main_status = APC_EXTERNAL_POWER_GOOD + + if(cell && !shorted) + // draw power from cell as before to power the area + var/cellused = min(cell.charge, GLOB.CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell + cell.use(cellused) + + if(excess > lastused_total) // if power excess recharge the cell + // by the same amount just used + cell.give(cellused) + add_load(cellused / GLOB.CELLRATE) // add the load used to recharge the cell + + + else // no excess, and not enough per-apc + if((cell.charge / GLOB.CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage? + cell.charge = min(cell.maxcharge, cell.charge + GLOB.CELLRATE * excess) //recharge with what we can + add_load(excess) // so draw what we can from the grid + charging = APC_NOT_CHARGING + + else // not enough power available to run the last tick! + charging = APC_NOT_CHARGING + chargecount = 0 + // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room. + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + + + // set channels depending on how much charge we have left + + // Allow the APC to operate as normal if the cell can charge + if(charging && longtermpower < 10) + longtermpower += 1 + else if(longtermpower > -10) + longtermpower -= 2 + + if(cell.charge <= 0) // zero charge, turn all off + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + area.poweralert(0, src) + else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment + equipment = autoset(equipment, 2) + lighting = autoset(lighting, 2) + environ = autoset(environ, 1) + area.poweralert(0, src) + else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment + equipment = autoset(equipment, 2) + lighting = autoset(lighting, 1) + environ = autoset(environ, 1) + area.poweralert(0, src) + else // otherwise all can be on + equipment = autoset(equipment, 1) + lighting = autoset(lighting, 1) + environ = autoset(environ, 1) + area.poweralert(1, src) + if(cell.percent() > 75) + area.poweralert(1, src) + + // now trickle-charge the cell + if(chargemode && charging == APC_CHARGING && operating) + if(excess > 0) // check to make sure we have enough to charge + // Max charge is capped to % per second constant + var/ch = min(excess*GLOB.CELLRATE, cell.maxcharge*GLOB.CHARGELEVEL) + add_load(ch/GLOB.CELLRATE) // Removes the power we're taking from the grid + cell.give(ch) // actually recharge the cell + + else + charging = APC_NOT_CHARGING // stop charging + chargecount = 0 + + // show cell as fully charged if so + if(cell.charge >= cell.maxcharge) + cell.charge = cell.maxcharge + charging = APC_FULLY_CHARGED + + if(chargemode) + if(!charging) + if(excess > cell.maxcharge * GLOB.CHARGELEVEL) + chargecount++ + else + chargecount = 0 + + if(chargecount == 10) + + chargecount = 0 + charging = APC_CHARGING + + else // chargemode off + charging = APC_NOT_CHARGING + chargecount = 0 + + else // no cell, switch everything off + charging = APC_NOT_CHARGING + chargecount = 0 + equipment = autoset(equipment, 0) + lighting = autoset(lighting, 0) + environ = autoset(environ, 0) + area.poweralert(0, src) + + // update icon & area power if anything changed + if(last_lt != lighting || last_eq != equipment || last_en != environ) + queue_icon_update() + update() + else if(last_ch != charging) + queue_icon_update() + +//val 0 = off, 1 = off(auto) 2 = on, 3 = on(auto) +//on 0 = off, 1 = auto-on, 2 = auto-off + +/proc/autoset(val, on) + + switch(on) + if(0) //Turn things off + switch(val) + if(2) //If on, return off + return 0 + if(3) //If auto-on, return auto-off + return 1 + + if(1) //Turn things auto-on + if(val == 1) //If auto-off, return auto-on + return 3 + + if(2) //Turn things auto-off + if(val == 3) //If auto-on, return auto-off + return 1 + return val + + +/obj/machinery/power/apc/emp_act(severity) + if(cell) + cell.emp_act(severity) + lighting = 0 + equipment = 0 + environ = 0 + update_icon() + update() + addtimer(CALLBACK(src, PROC_REF(reset), APC_RESET_EMP), 60 SECONDS) + return ..() + + +/obj/machinery/power/apc/ex_act(severity) + switch(severity) + if(EXPLODE_DEVASTATE) + cell?.ex_act(1) //More lags woohoo + qdel(src) + return + if(EXPLODE_HEAVY) + if(prob(50)) + return + set_broken() + if(!cell || prob(50)) + return + if(EXPLODE_LIGHT) + if(prob(75)) + return + set_broken() + if(!cell || prob(75)) + return + if(EXPLODE_WEAK) + if(prob(80)) + return + set_broken() + if(!cell || prob(85)) + return + + cell.ex_act(severity) + + +/obj/machinery/power/apc/proc/set_broken() + //Aesthetically much better! + visible_message(span_warning("[src]'s screen flickers with warnings briefly!")) + addtimer(CALLBACK(src, PROC_REF(do_break)), rand(2, 5)) + + +/obj/machinery/power/apc/proc/do_break() + visible_message(span_danger("[src]'s screen suddenly explodes in rain of sparks and small debris!")) + machine_stat |= BROKEN + operating = FALSE + update_icon() + update() + + +//Overload all the lights in this APC area +/obj/machinery/power/apc/proc/overload_lighting() + if(!operating || shorted) + return + if(cell?.charge >= 20) + cell.use(20) + INVOKE_ASYNC(src, PROC_REF(break_lights)) + + +/obj/machinery/power/apc/proc/break_lights() + for(var/obj/machinery/light/L in get_area(src)) + L.broken() + stoplag() + + +/obj/machinery/power/apc/disconnect_terminal() + if(terminal) + terminal.master = null + terminal = null + + +/obj/machinery/power/apc/proc/toggle_breaker(mob/user) + if(machine_stat & (NOPOWER|BROKEN|MAINT)) + return + + operating = !operating + log_combat(user, src, "turned [operating ? "on" : "off"]") + update() + update_icon() + + +//------Various APCs ------// + +// mapping helpers +/obj/machinery/power/apc/drained + start_charge = 0 + +/obj/machinery/power/apc/lowcharge + start_charge = 25 + +/obj/machinery/power/apc/potato + cell_type = /obj/item/cell/potato + +/obj/machinery/power/apc/weak + cell_type = /obj/item/cell + +/obj/machinery/power/apc/high + cell_type = /obj/item/cell/high + +/obj/machinery/power/apc/super + cell_type = /obj/item/cell/super + +/obj/machinery/power/apc/hyper + cell_type = /obj/item/cell/hyper + +//------Marine ship APCs ------// + +/obj/machinery/power/apc/mainship + req_access = list(ACCESS_MARINE_ENGINEERING) + cell_type = /obj/item/cell/high + +/obj/machinery/power/apc/mainship/hardened + name = "hardened area power controller" + desc = "A control terminal for the area electrical systems. This one is hardened against sudden power fluctuations caused by electrical grid damage." + crash_break_probability = 0 diff --git a/code/modules/power/apc/apc_appearance.dm b/code/modules/power/apc/apc_appearance.dm new file mode 100644 index 00000000000..fe95cfb6809 --- /dev/null +++ b/code/modules/power/apc/apc_appearance.dm @@ -0,0 +1,88 @@ +/obj/machinery/power/apc/update_appearance(updates=check_updates()) + icon_update_needed = FALSE + if(!updates) + return + . = ..() + // And now, separately for cleanness, the lighting changing + if(!update_state) + switch(charging) + if(APC_NOT_CHARGING) + set_light_color(LIGHT_COLOR_RED) + if(APC_CHARGING) + set_light_color(LIGHT_COLOR_BLUE) + if(APC_FULLY_CHARGED) + set_light_color(LIGHT_COLOR_GREEN) + set_light(initial(light_range)) + return + set_light(0) + +/obj/machinery/power/apc/update_icon_state() + . = ..() + + var/broken = CHECK_BITFIELD(update_state, UPSTATE_BROKE) ? "-b" : "" + var/status = (CHECK_BITFIELD(update_state, UPSTATE_WIREEXP) && !CHECK_BITFIELD(update_state, UPSTATE_OPENED1)) ? "-wires" : broken + icon_state = "apc[opened][status]" + +/obj/machinery/power/apc/update_overlays() + . = ..() + + if(opened && cell) + . += "apco-cell" + + if((machine_stat & (BROKEN|MAINT)) || update_state) + return + + . += emissive_appearance(icon, "apcox-[locked]") + . += mutable_appearance(icon, "apcox-[locked]") + . += emissive_appearance(icon, "apco3-[charging]") + . += mutable_appearance(icon, "apco3-[charging]") + + . += emissive_appearance(icon, "apco0-[operating ? equipment : 0]") + . += mutable_appearance(icon, "apco0-[operating ? equipment : 0]") + . += emissive_appearance(icon, "apco1-[operating ? lighting : 0]") + . += mutable_appearance(icon, "apco1-[operating ? lighting : 0]") + . += emissive_appearance(icon, "apco2-[operating ? environ : 0]") + . += mutable_appearance(icon, "apco2-[operating ? environ : 0]") + +/// Checks for what icon updates we will need to handle +/obj/machinery/power/apc/proc/check_updates() + SIGNAL_HANDLER + . = NONE + + // Handle icon status: + var/new_update_state = NONE + if(machine_stat & BROKEN) + new_update_state |= UPSTATE_BROKE + if(machine_stat & MAINT) + new_update_state |= UPSTATE_MAINT + + if(opened) + new_update_state |= (opened << UPSTATE_COVER_SHIFT) + + else if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) + new_update_state |= UPSTATE_WIREEXP + + if(new_update_state != update_state) + update_state = new_update_state + . |= UPDATE_ICON_STATE + + // Handle overlay status: + var/new_update_overlay = NONE + if(operating) + new_update_overlay |= UPOVERLAY_OPERATING + + if(!update_state) + if(locked) + new_update_overlay |= UPOVERLAY_LOCKED + + new_update_overlay |= (charging << UPOVERLAY_CHARGING_SHIFT) + new_update_overlay |= (equipment << UPOVERLAY_EQUIPMENT_SHIFT) + new_update_overlay |= (lighting << UPOVERLAY_LIGHTING_SHIFT) + new_update_overlay |= (environ << UPOVERLAY_ENVIRON_SHIFT) + + if(new_update_overlay != update_overlay) + update_overlay = new_update_overlay + . |= UPDATE_OVERLAYS + +/obj/machinery/power/apc/proc/queue_icon_update() + icon_update_needed = TRUE diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm new file mode 100644 index 00000000000..ac98cc52b74 --- /dev/null +++ b/code/modules/power/apc/apc_attack.dm @@ -0,0 +1,221 @@ +/obj/machinery/power/apc/attack_alien(mob/living/carbon/xenomorph/X, damage_amount = X.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE) + if(X.status_flags & INCORPOREAL) + return FALSE + + if(effects) + X.do_attack_animation(src, ATTACK_EFFECT_CLAW) + X.visible_message(span_danger("[X] slashes \the [src]!"), \ + span_danger("We slash \the [src]!"), null, 5) + playsound(loc, "alien_claw_metal", 25, 1) + + var/allcut = wires.is_all_cut() + + if(beenhit >= pick(3, 4) && !CHECK_BITFIELD(machine_stat, PANEL_OPEN)) + ENABLE_BITFIELD(machine_stat, PANEL_OPEN) + update_appearance() + visible_message(span_danger("\The [src]'s cover swings open, exposing the wires!"), null, null, 5) + + else if(CHECK_BITFIELD(machine_stat, PANEL_OPEN) && !allcut) + wires.cut_all() + update_appearance() + visible_message(span_danger("\The [src]'s wires snap apart in a rain of sparks!"), null, null, 5) + if(X.client) + var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[X.ckey] + personal_statistics.apcs_slashed++ + else + beenhit += 1 + +//Attack with an item - open/close cover, insert cell, or (un)lock interface //todo please clean this up +/obj/machinery/power/apc/attackby(obj/item/I, mob/user, params) + . = ..() + + if(istype(I, /obj/item/cell) && opened) //Trying to put a cell inside + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + user.visible_message(span_notice("[user] fumbles around figuring out how to fit [I] into [src]."), + span_notice("You fumble around figuring out how to fit [I] into [src].")) + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + if(cell) + balloon_alert(user, "Already installed") + return + + if(machine_stat & MAINT) + balloon_alert(user, "No connector") + return + + if(!user.transferItemToLoc(I, src)) + return + + set_cell(I) + user.visible_message("[user] inserts [I] into [src]!", + "You insert [I] into [src]!") + chargecount = 0 + update_appearance() + + else if(istype(I, /obj/item/card/id)) //Trying to unlock the interface with an ID card + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + user.visible_message(span_notice("[user] fumbles around figuring out where to swipe [I] on [src]."), + span_notice("You fumble around figuring out where to swipe [I] on [src].")) + var/fumbling_time = 3 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + if(opened) + balloon_alert(user, "Close the cover first") + return + + if(CHECK_BITFIELD(machine_stat, PANEL_OPEN)) + balloon_alert(user, "Close the panel first") + return + + if(machine_stat & (BROKEN|MAINT)) + balloon_alert(user, "Nothing happens") + return + + if(!allowed(user)) + balloon_alert(user, "Access denied") + return + + locked = !locked + balloon_alert_to_viewers("[locked ? "locked" : "unlocked"]") + update_appearance() + + else if(iscablecoil(I) && !terminal && opened && has_electronics != APC_ELECTRONICS_SECURED) + var/obj/item/stack/cable_coil/C = I + + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + var/turf/T = get_turf(src) + if(T.intact_tile) + balloon_alert(user, "Remove the floor plating") + return + + if(C.get_amount() < 10) + balloon_alert(user, "Not enough wires") + return + + balloon_alert_to_viewers("starts wiring [src]") + playsound(loc, 'sound/items/deconstruct.ogg', 25, 1) + + if(!do_after(user, 20, NONE, src, BUSY_ICON_BUILD) || terminal || !opened || has_electronics == APC_ELECTRONICS_SECURED) + return + + var/obj/structure/cable/N = T.get_cable_node() + if(prob(50) && electrocute_mob(user, N, N)) + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(5, 1, src) + s.start() + return + + if(!C.use(10)) + return + + balloon_alert_to_viewers("Wired]") + make_terminal() + terminal.connect_to_network() + + else if(istype(I, /obj/item/circuitboard/apc) && opened && has_electronics == APC_ELECTRONICS_MISSING && !(machine_stat & BROKEN)) + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + balloon_alert_to_viewers("Tries to insert APC board into [src]") + playsound(loc, 'sound/items/deconstruct.ogg', 25, 1) + + if(!do_after(user, 15, NONE, src, BUSY_ICON_BUILD)) + return + + has_electronics = APC_ELECTRONICS_INSTALLED + balloon_alert_to_viewers("Inserts APC board into [src]") + qdel(I) + + else if(istype(I, /obj/item/circuitboard/apc) && opened && has_electronics == APC_ELECTRONICS_MISSING && (machine_stat & BROKEN)) + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + balloon_alert(user, "Cannot, frame damaged") + + else if(istype(I, /obj/item/frame/apc) && opened && (machine_stat & BROKEN)) + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + if(has_electronics) + balloon_alert(user, "Cannot, electronics still inside") + return + + balloon_alert_to_viewers("Begins replacing front panel") + + if(!do_after(user, 50, NONE, src, BUSY_ICON_BUILD)) + return + + balloon_alert_to_viewers("Replaces front panel") + qdel(I) + DISABLE_BITFIELD(machine_stat, BROKEN) + if(opened == APC_COVER_REMOVED) + opened = APC_COVER_OPENED + update_appearance() + + else if(istype(I, /obj/item/frame/apc) && opened) + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + if(opened == APC_COVER_REMOVED) + opened = APC_COVER_OPENED + balloon_alert_to_viewers("Replaces [src]'s front panel") + qdel(I) + update_appearance() + + else + if(((machine_stat & BROKEN)) && !opened && I.force >= 5) + opened = APC_COVER_REMOVED + balloon_alert_to_viewers("Knocks down [src]'s panel") + update_appearance() + else + if(issilicon(user)) + return attack_hand(user) + + if(!opened && CHECK_BITFIELD(machine_stat, PANEL_OPEN) && (ismultitool(I) || iswirecutter(I))) + return attack_hand(user) + balloon_alert_to_viewers("Hits [src] with [I]") + +//Attack with hand - remove cell (if cover open) or interact with the APC +/obj/machinery/power/apc/attack_hand(mob/living/user) + . = ..() + if(.) + return + + if(opened && cell && !issilicon(user)) + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + balloon_alert_to_viewers("Removes [src] from [src]") + user.put_in_hands(cell) + cell.update_appearance() + set_cell(null) + charging = APC_NOT_CHARGING + update_appearance() + return + + if(machine_stat & (BROKEN|MAINT)) + return + + interact(user) diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm new file mode 100644 index 00000000000..6fcf7c56774 --- /dev/null +++ b/code/modules/power/apc/apc_tool_act.dm @@ -0,0 +1,116 @@ +/obj/machinery/power/apc/crowbar_act(mob/user, obj/item/I) + . = TRUE + if(opened) + if(has_electronics == APC_ELECTRONICS_INSTALLED) + if(terminal) + balloon_alert(user, "Disconnect the wires") + return + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("Fumbles around removing cell from [src]") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + I.play_tool_sound(src) + balloon_alert(user, "Removing APC board") + if(I.use_tool(src, user, 50)) + if(has_electronics == APC_ELECTRONICS_INSTALLED) + has_electronics = APC_ELECTRONICS_MISSING + if(machine_stat & BROKEN) + balloon_alert_to_viewers("Removes the charred control board") + return + else + balloon_alert_to_viewers("Removes the control board") + new /obj/item/circuitboard/apc(loc) + return + else if(opened != APC_COVER_REMOVED) + opened = APC_COVER_CLOSED + coverlocked = TRUE //closing cover relocks it + update_appearance() + return + else if(!(machine_stat & BROKEN)) + if(coverlocked && !(machine_stat & MAINT)) // locked... + balloon_alert(user, "Locked") + return + else if(machine_stat & PANEL_OPEN) + balloon_alert(user, "Can't, wires in way") + return + else + opened = APC_COVER_OPENED + update_appearance() + return + + +/obj/machinery/power/apc/screwdriver_act(mob/living/user, obj/item/I) + . = ..() + if(.) + return TRUE + . = TRUE + if(opened) + if(cell) + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + balloon_alert_to_viewers("Removes cell") + var/turf/T = get_turf(user) + cell.forceMove(T) + cell.update_appearance() + set_cell(null) + charging = APC_NOT_CHARGING + update_appearance() + return + else + switch(has_electronics) + if(APC_ELECTRONICS_INSTALLED) + has_electronics = APC_ELECTRONICS_SECURED + machine_stat &= ~MAINT + I.play_tool_sound(src) + balloon_alert(user, "Screws circuit board in") + if(APC_ELECTRONICS_SECURED) + has_electronics = APC_ELECTRONICS_INSTALLED + machine_stat |= MAINT + I.play_tool_sound(src) + balloon_alert(user, "Unfastens electronics") + else + balloon_alert(user, "Nothing securable") + return + update_appearance() + else + TOGGLE_BITFIELD(machine_stat, PANEL_OPEN) + balloon_alert(user, "wires [CHECK_BITFIELD(machine_stat, PANEL_OPEN) ? "exposed" : "unexposed"]") + update_appearance() + + +/obj/machinery/power/apc/wirecutter_act(mob/living/user, obj/item/I) + if(terminal && opened) + terminal.deconstruct(user) + return TRUE + + +/obj/machinery/power/apc/welder_act(mob/living/user, obj/item/I) + if(!opened || has_electronics || terminal) + return + + if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) + balloon_alert_to_viewers("fumbles") + var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_ENGI - user.skills.getRating(SKILL_ENGINEER) ) + if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) + return + + if(!I.tool_start_check(user, amount = 3)) + return + balloon_alert_to_viewers("welds [src]") + + if(!I.use_tool(src, user, 50, volume = 50, amount = 3)) + return + + if((machine_stat & BROKEN) || opened == APC_COVER_REMOVED) + new /obj/item/stack/sheet/metal(loc) + balloon_alert_to_viewers("cuts apart [src]") + else + new /obj/item/frame/apc(loc) + balloon_alert_to_viewers("cuts [src] from the wall") + qdel(src) + return TRUE + diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm index 9e5b59adea4..485fa245ebc 100644 --- a/code/modules/power/batteryrack.dm +++ b/code/modules/power/batteryrack.dm @@ -68,19 +68,19 @@ capacity = C * 40 //Basic cells are such crap. Hyper cells needed to get on normal SMES levels. -/obj/machinery/power/smes/batteryrack/update_icon() - overlays.Cut() +/obj/machinery/power/smes/batteryrack/update_overlays() + . = ..() if(machine_stat & BROKEN) return - if (outputting) - overlays += image('icons/obj/power.dmi', "gsmes_outputting") + if(outputting) + . += image('icons/obj/power.dmi', "gsmes_outputting") if(inputting) - overlays += image('icons/obj/power.dmi', "gsmes_charging") + . += image('icons/obj/power.dmi', "gsmes_charging") var/clevel = chargedisplay() if(clevel>0) - overlays += image('icons/obj/power.dmi', "gsmes_og[clevel]") + . += image('icons/obj/power.dmi', "gsmes_og[clevel]") @@ -147,20 +147,21 @@ /obj/machinery/power/smes/batteryrack/makeshift/update_icon() - overlays.Cut() - if(machine_stat & BROKEN) return + . = ..() + if(machine_stat & BROKEN) + return - if (outputting) - overlays += image('icons/obj/power.dmi', "gsmes_outputting") + if(outputting) + . += image('icons/obj/power.dmi', "gsmes_outputting") if(inputting) - overlays += image('icons/obj/power.dmi', "gsmes_charging") - if (overcharge_percent > 100) - overlays += image('icons/obj/power.dmi', "gsmes_overcharge") + . += image('icons/obj/power.dmi', "gsmes_charging") + if(overcharge_percent > 100) + . += image('icons/obj/power.dmi', "gsmes_overcharge") else var/clevel = chargedisplay() if(clevel>0) - overlays += image('icons/obj/power.dmi', "gsmes_og[clevel]") - return + . += image('icons/obj/power.dmi', "gsmes_og[clevel]") + //This mess of if-elses and magic numbers handles what happens if the engies don't pay attention and let it eat too much charge //What happens depends on how much capacity has the ghetto smes and how much it is overcharged. diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ac6306358e0..417fe84ccf9 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -132,6 +132,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri /////////////////////////////////// /obj/structure/cable/update_icon_state() + . = ..() if(!linked_dirs) icon_state = "l[cable_layer]-noconnection" else diff --git a/code/modules/power/fusion_engine.dm b/code/modules/power/fusion_engine.dm index 46694659353..99acae32b3f 100644 --- a/code/modules/power/fusion_engine.dm +++ b/code/modules/power/fusion_engine.dm @@ -318,7 +318,8 @@ else . += span_info("There is no fuel cell in the receptacle.") -/obj/machinery/power/fusion_engine/update_icon() +/obj/machinery/power/fusion_engine/update_icon_state() + . = ..() switch(buildstate) if(FUSION_ENGINE_NO_DAMAGE) if(fusion_cell?.fuel_amount > 0) @@ -383,7 +384,8 @@ fuel_amount = rand(0,100) update_icon() -/obj/item/fuel_cell/update_icon() +/obj/item/fuel_cell/update_icon_state() + . = ..() switch(get_fuel_percent()) if(-INFINITY to 0) icon_state = "cell-empty" diff --git a/code/modules/power/groundmap_geothermal.dm b/code/modules/power/groundmap_geothermal.dm index 6e0c52648ab..0513ccac01b 100644 --- a/code/modules/power/groundmap_geothermal.dm +++ b/code/modules/power/groundmap_geothermal.dm @@ -55,7 +55,7 @@ GLOBAL_VAR_INIT(generators_on_ground, 0) return TRUE //We don't want to cut/update the power overlays every single proc. Just when it actually changes. This should save on CPU cycles. Efficiency! -/obj/machinery/power/geothermal/update_icon() +/obj/machinery/power/geothermal/update_icon_state() . = ..() SSminimaps.remove_marker(src) if(!corrupted && !is_on) @@ -89,6 +89,19 @@ GLOBAL_VAR_INIT(generators_on_ground, 0) icon_state = "wrench" desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is lightly damaged. Use a wrench to repair it." +/obj/machinery/power/geothermal/update_desc(updates) + . = ..() + switch(buildstate) + if(GEOTHERMAL_NO_DAMAGE) + if(!is_on) + desc = "A thermoelectric generator sitting atop a borehole dug deep in the planet's surface. It generates energy by boiling the plasma steam that rises from the well.\nIt is old technology and has a large failure rate, and must be repaired frequently.\nIt is currently turned off and silent." + if(GEOTHERMAL_HEAVY_DAMAGE) + desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is heavily damaged. Use a blowtorch, wirecutters, and then a wrench to repair it." + if(GEOTHERMAL_MEDIUM_DAMAGE) + desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is damaged. Use wirecutters and then a wrench to repair it." + if(GEOTHERMAL_LIGHT_DAMAGE) + desc = "A thermoelectric generator sitting atop a plasma-filled borehole. This one is lightly damaged. Use a wrench to repair it." + /obj/machinery/power/geothermal/update_overlays() . = ..() if(corrupted) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index cf408b666d4..bfe4927c835 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -243,7 +243,8 @@ return TRUE return FALSE -/obj/machinery/light/update_icon() +/obj/machinery/light/update_icon_state() + . = ..() switch(status) // set icon_states if(LIGHT_OK) icon_state = "[base_state][light_on]" diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm index 15f2790b817..9a55a43d286 100644 --- a/code/modules/power/pipecleaners.dm +++ b/code/modules/power/pipecleaners.dm @@ -120,10 +120,14 @@ By design, d1 is the smallest direction and d2 is the highest // General procedures /////////////////////////////////// -/obj/structure/pipe_cleaner/update_icon() +/obj/structure/pipe_cleaner/update_icon_state() + . = ..() icon_state = "[d1]-[d2]" + +/obj/structure/pipe_cleaner/update_icon() color = null add_atom_colour(pipe_cleaner_color, FIXED_COLOUR_PRIORITY) + return ..() // Items usable on a pipe_cleaner : // - Wirecutters : cut it duh ! @@ -206,11 +210,18 @@ By design, d1 is the smallest direction and d2 is the highest /////////////////////////////////// -/obj/item/stack/pipe_cleaner_coil/update_icon() +/obj/item/stack/pipe_cleaner_coil/update_icon_state() + . = ..() icon_state = "[initial(item_state)][amount < 3 ? amount : ""]" + +/obj/item/stack/pipe_cleaner_coil/update_name(updates) + . = ..() name = "pipe cleaner [amount < 3 ? "piece" : "coil"]" + +/obj/item/stack/pipe_cleaner_coil/update_icon() color = null add_atom_colour(pipe_cleaner_color, FIXED_COLOUR_PRIORITY) + return ..() /obj/item/stack/pipe_cleaner_coil/attack_hand(mob/user) . = ..() diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index ce344304609..a23692ddcb1 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -70,6 +70,7 @@ soundloop.start() /obj/machinery/power/port_gen/update_icon_state() + . = ..() icon_state = "[base_icon]" /obj/machinery/power/port_gen/process() diff --git a/code/modules/power/power_monitor.dm b/code/modules/power/power_monitor.dm index 1c2875e9f34..41dd8c3ddc6 100644 --- a/code/modules/power/power_monitor.dm +++ b/code/modules/power/power_monitor.dm @@ -87,6 +87,7 @@ set_light(initial(light_range)) /obj/machinery/power/monitor/update_icon_state() + . = ..() if(machine_stat & (BROKEN|DISABLED)) icon_state = "[initial(icon_state)]_broken" else diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm index c9bd9c43214..a8c3587eb3b 100644 --- a/code/modules/power/smes_construction.dm +++ b/code/modules/power/smes_construction.dm @@ -168,12 +168,10 @@ A.set_broken() // Failing SMES has special icon overlay. -/obj/machinery/power/smes/buildable/update_icon() - if (failing) - overlays.Cut() - overlays += image('icons/obj/power.dmi', "smes_crit") - else - ..() +/obj/machinery/power/smes/buildable/update_overlays() + . = ..() + if(failing) + . += image('icons/obj/power.dmi', "smes_crit") /obj/machinery/power/smes/buildable/attackby(obj/item/I, mob/user, params) // No more disassembling of overloaded SMESs. You broke it, now enjoy the consequences. diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm index db810b1b640..a6fe32376fa 100644 --- a/code/modules/projectiles/ammo_datums.dm +++ b/code/modules/projectiles/ammo_datums.dm @@ -1369,6 +1369,17 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh accurate_range = 25 accurate_range_min = 3 +/datum/ammo/bullet/cupola + name = "cupola bullet" + bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction + hud_state = "smartgun" + hud_state_empty = "smartgun_empty" + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SUNDERING|AMMO_IFF + accurate_range = 12 + damage = 30 + penetration = 10 + sundering = 1 + /datum/ammo/bullet/spottingrifle name = "smart spotting bullet" bullet_color = COLOR_SOFT_RED //Red bullets to indicate friendly fire restriction @@ -1522,6 +1533,15 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh penetration = 10 sundering = 0.5 +/datum/ammo/bullet/minigun/ltaap + name = "chaingun bullet" + damage = 30 + penetration = 10 + sundering = 0 + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IFF + damage_falloff = 2 + accuracy = 80 + /datum/ammo/bullet/auto_cannon name = "autocannon high-velocity bullet" hud_state = "minigun" @@ -2215,8 +2235,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET accurate_range = 15 max_range = 40 - penetration = 200 - damage = 300 + penetration = 50 + damage = 200 + hud_state = "bigshell_he" /datum/ammo/rocket/ltb/drop_nade(turf/T) cell_explosion(T, 200, 45) @@ -3411,9 +3432,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh glow_color = "#CB0166" /datum/ammo/energy/xeno/psy_blast/psy_lance/on_hit_obj(obj/O, obj/projectile/P) - if(ismecha(O)) - var/obj/vehicle/sealed/mecha/mech_victim = O - mech_victim.take_damage(200, BURN, ENERGY, TRUE, armour_penetration = penetration) + if(isvehicle(O)) + var/obj/vehicle/veh_victim = O + veh_victim.take_damage(200, BURN, ENERGY, TRUE, armour_penetration = penetration) /datum/ammo/energy/xeno/psy_blast/psy_lance/on_hit_mob(mob/M, obj/projectile/P) if(isxeno(M)) @@ -3732,6 +3753,9 @@ GLOBAL_LIST_INIT(no_sticky_resin, typecacheof(list(/obj/item/clothing/mask/faceh /datum/ammo/xeno/sticky/on_hit_obj(obj/O, obj/projectile/P) + if(isarmoredvehicle(O)) + var/obj/vehicle/sealed/armored/tank = O + COOLDOWN_START(tank, cooldown_vehicle_move, tank.move_delay) var/turf/T = get_turf(O) drop_resin(T.density ? P.loc : T) diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index d396b81d1d8..5e8af955032 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -53,6 +53,7 @@ update_icon() /obj/item/ammo_magazine/update_icon_state() + . = ..() if(CHECK_BITFIELD(flags_magazine, MAGAZINE_HANDFUL)) setDir(current_rounds + round(current_rounds/3)) return @@ -313,10 +314,16 @@ Turn() or Shift() as there is virtually no overhead. ~N pixel_y = rand(-2, 2) icon_state = initial_icon_state += "[rand(1, number_of_states)]" //Set the icon to it. -//This does most of the heavy lifting. It updates the icon and name if needed, then changes .dir to simulate new casings. -/obj/item/ammo_casing/update_icon() +//This does most of the heavy lifting. It updates the icon and name if needed + +/obj/item/ammo_casing/update_name(updates) + . = ..() + if(max_casings >= current_casings && current_casings == 2) + name += "s" //In case there is more than one. + +/obj/item/ammo_casing/update_icon_state() + . = ..() if(max_casings >= current_casings) - if(current_casings == 2) name += "s" //In case there is more than one. if(round((current_casings-1)/8) > current_icon) current_icon++ icon_state += "_[current_icon]" @@ -324,9 +331,24 @@ Turn() or Shift() as there is virtually no overhead. ~N var/base_direction = current_casings - (current_icon * 8) setDir(base_direction + round(base_direction)/3) switch(current_casings) - if(3 to 5) w_class = WEIGHT_CLASS_SMALL //Slightly heavier. - if(9 to 10) w_class = WEIGHT_CLASS_NORMAL //Can't put it in your pockets and stuff. + if(3 to 5) + w_class = WEIGHT_CLASS_SMALL //Slightly heavier. + if(9 to 10) + w_class = WEIGHT_CLASS_NORMAL //Can't put it in your pockets and stuff. + +///changes .dir to simulate new casings, also sets the new w_class +/obj/item/ammo_casing/proc/update_dir() + var/base_direction = current_casings - (current_icon * 8) + setDir(base_direction + round(base_direction)/3) + switch(current_casings) + if(3 to 5) + w_class = WEIGHT_CLASS_SMALL //Slightly heavier. + if(9 to 10) + w_class = WEIGHT_CLASS_NORMAL //Can't put it in your pockets and stuff. +/obj/item/ammo_casing/update_icon() + update_dir() + return ..() //Making child objects so that locate() and istype() doesn't screw up. /obj/item/ammo_casing/bullet @@ -360,6 +382,7 @@ Turn() or Shift() as there is virtually no overhead. ~N var/caliber = CALIBER_10X24_CASELESS /obj/item/big_ammo_box/update_icon_state() + . = ..() if(bullet_amount) icon_state = base_icon_state return @@ -398,7 +421,7 @@ Turn() or Shift() as there is virtually no overhead. ~N var/S = min(bullet_amount, AM.max_rounds - AM.current_rounds) AM.current_rounds += S bullet_amount -= S - AM.update_icon(S) + AM.update_icon() update_icon() if(AM.current_rounds == AM.max_rounds) to_chat(user, span_notice("You refill [AM].")) @@ -450,7 +473,8 @@ Turn() or Shift() as there is virtually no overhead. ~N var/caliber = CALIBER_12G -/obj/item/shotgunbox/update_icon() +/obj/item/shotgunbox/update_icon_state() + . = ..() if(!deployed) icon_state = "[initial(icon_state)]" else if(current_rounds > 0) diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index e96f7bcd861..ab741a08336 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -1675,7 +1675,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. continue QDEL_NULL(action_to_delete) break - update_icon(user) + update_icon() master_gun.base_gun_icon = initial(master_gun.icon_state) master_gun.update_icon() UnregisterSignal(detaching_item, list(COMSIG_ITEM_EQUIPPED, COMSIG_ATOM_ATTACK_HAND_ALTERNATE, COMSIG_ATOM_ATTACKBY_ALTERNATE)) @@ -1860,7 +1860,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. activate(user) new_action.set_toggle(TRUE) new_action.update_button_icon() - update_icon(user) + update_icon() RegisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY, TYPE_PROC_REF(/obj/item/weapon/gun, drop_connected_mag)) ///This is called when an attachment gun (src) detaches from a gun. @@ -1879,7 +1879,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. UnregisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY) master_gun = null attached_to:gunattachment = null - update_icon(user) + update_icon() ///This activates the weapon for use. /obj/item/weapon/gun/proc/activate(mob/user) diff --git a/code/modules/projectiles/gun_system.dm b/code/modules/projectiles/gun_system.dm index e115b4717e0..06ba5a24061 100644 --- a/code/modules/projectiles/gun_system.dm +++ b/code/modules/projectiles/gun_system.dm @@ -505,7 +505,7 @@ SIGNAL_HANDLER set_gun_user(null) -/obj/item/weapon/gun/update_icon(mob/user) +/obj/item/weapon/gun/update_icon() . = ..() for(var/datum/action/action AS in actions) @@ -1480,7 +1480,7 @@ num_of_casings-- if(num_of_casings) casing.current_casings += num_of_casings - casing.update_icon() + casing.update_appearance() playsound(current_turf, sound_to_play, 25, 1, 5) ///Gets a projectile to fire from the magazines ammo type. diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index ca33294e560..22a0b45a190 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -1104,12 +1104,12 @@ light_power = 0.1 light_color = LIGHT_COLOR_ORANGE -/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/update_icon(mob/user) +/obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/update_icon() . = ..() if(rounds) - turn_light(user, TRUE) + turn_light(null, TRUE) else - turn_light(user, FALSE) + turn_light(null, FALSE) /obj/item/weapon/gun/energy/lasgun/lasrifle/volkite/turn_light(mob/user, toggle_on) . = ..() diff --git a/code/modules/projectiles/guns/flamer.dm b/code/modules/projectiles/guns/flamer.dm index 37df4a7cdaa..cdbb8de3836 100644 --- a/code/modules/projectiles/guns/flamer.dm +++ b/code/modules/projectiles/guns/flamer.dm @@ -458,7 +458,8 @@ /turf/open/floor/plating/ground/snow/ignite(fire_lvl, burn_lvl, f_color, fire_stacks = 0, fire_damage = 0) if(slayer > 0) slayer -= 1 - update_icon(1, 0) + update_appearance() + update_sides() return ..() diff --git a/code/modules/projectiles/guns/sentries.dm b/code/modules/projectiles/guns/sentries.dm index 03489ffd340..6e89e632bff 100644 --- a/code/modules/projectiles/guns/sentries.dm +++ b/code/modules/projectiles/guns/sentries.dm @@ -182,7 +182,7 @@ deployed_machine.max_integrity = max_integrity //Syncs new machine or structure integrity with that of the item. deployed_machine.obj_integrity = obj_integrity - deployed_machine.update_icon_state() + deployed_machine.update_appearance() forceMove(deployed_machine) //Moves the Item into the machine or structure diff --git a/code/modules/projectiles/guns/specialist.dm b/code/modules/projectiles/guns/specialist.dm index d690755b7b5..b3a268791ab 100644 --- a/code/modules/projectiles/guns/specialist.dm +++ b/code/modules/projectiles/guns/specialist.dm @@ -852,6 +852,7 @@ Note that this means that snipers will have a slowdown of 3, due to the scope update_icon() /obj/item/weapon/gun/launcher/rocket/oneuse/update_icon_state() + . = ..() if(extended) icon_state = "[base_gun_icon]_extended" else diff --git a/code/modules/projectiles/magazines/flamer.dm b/code/modules/projectiles/magazines/flamer.dm index 5da294ba2a5..824ad515f5a 100644 --- a/code/modules/projectiles/magazines/flamer.dm +++ b/code/modules/projectiles/magazines/flamer.dm @@ -54,9 +54,6 @@ to_chat(user, span_notice("You refill [src] with [lowertext(caliber)].")) update_icon() -/obj/item/ammo_magazine/flamer_tank/update_icon() - return - /obj/item/ammo_magazine/flamer_tank/large // Extra thicc tank name = "large flamerthrower tank" desc = "A large fuel tank of ultra thick napthal, a sticky combustable liquid chemical, for use in the FL-84 flamethrower." diff --git a/code/modules/projectiles/magazines/specialist.dm b/code/modules/projectiles/magazines/specialist.dm index fe61d29686f..042f81290cf 100644 --- a/code/modules/projectiles/magazines/specialist.dm +++ b/code/modules/projectiles/magazines/specialist.dm @@ -108,12 +108,22 @@ user.drop_held_item() qdel(src) -/obj/item/ammo_magazine/rocket/update_icon() - overlays.Cut() +/obj/item/ammo_magazine/rocket/update_name(updates) + . = ..() if(current_rounds > 0) return name = "empty rocket frame" + +/obj/item/ammo_magazine/rocket/update_desc(updates) + . = ..() + if(current_rounds > 0) + return desc = "A spent rocket rube. Activate it to deconstruct it and receive some materials." + +/obj/item/ammo_magazine/rocket/update_icon_state() + . = ..() + if(current_rounds > 0) + return icon_state = istype(src, /obj/item/ammo_magazine/rocket/m57a4) ? "quad_rocket_e" : "rocket_e" //------------------------------------------------------- diff --git a/code/modules/projectiles/mounted.dm b/code/modules/projectiles/mounted.dm index 501cbde1121..a20c3c3ab16 100644 --- a/code/modules/projectiles/mounted.dm +++ b/code/modules/projectiles/mounted.dm @@ -4,7 +4,7 @@ anchored = TRUE resistance_flags = XENO_DAMAGEABLE density = TRUE - layer = TANK_BARREL_LAYER + layer = ABOVE_MOB_PROP_LAYER use_power = FALSE hud_possible = list(MACHINE_HEALTH_HUD, MACHINE_AMMO_HUD) allow_pass_flags = PASSABLE @@ -18,7 +18,7 @@ var/has_anchored_sprite = FALSE ///generates the icon based on how much ammo it has. -/obj/machinery/deployable/mounted/update_icon_state(mob/user) +/obj/machinery/deployable/mounted/update_icon_state() . = ..() var/obj/item/weapon/gun/gun = get_internal_item() if(gun && (!length(gun.chamber_items) || !gun.chamber_items[gun.current_chamber_position])) @@ -97,10 +97,10 @@ var/obj/item/weapon/gun/gun = get_internal_item() if(length(gun?.chamber_items)) gun.unload(user) - update_icon_state() + update_appearance() gun?.reload(ammo_magazine, user) - update_icon_state() + update_appearance() REMOVE_TRAIT(src, TRAIT_GUN_RELOADING, GUN_TRAIT) @@ -243,7 +243,7 @@ return FALSE operator.setDir(dir) gun?.set_target(target) - update_icon_state() + update_appearance() return TRUE if(CHECK_BITFIELD(gun?.flags_item, DEPLOYED_NO_ROTATE)) to_chat(operator, "This one is anchored in place and cannot be rotated.") diff --git a/code/modules/projectiles/sentries.dm b/code/modules/projectiles/sentries.dm index 4ed6405f75c..2ebff4387c0 100644 --- a/code/modules/projectiles/sentries.dm +++ b/code/modules/projectiles/sentries.dm @@ -572,4 +572,4 @@ internal_item = null QDEL_NULL(src) - attached_item.update_icon_state() + attached_item.update_appearance() diff --git a/code/modules/reagents/machinery/chem_dispenser.dm b/code/modules/reagents/machinery/chem_dispenser.dm index 31c5614e601..45b12c4fccb 100644 --- a/code/modules/reagents/machinery/chem_dispenser.dm +++ b/code/modules/reagents/machinery/chem_dispenser.dm @@ -399,6 +399,7 @@ . += image(icon, "[initial(icon_state)]_nobat") /obj/machinery/chem_dispenser/update_icon_state() + . = ..() if(machine_stat & NOPOWER) icon_state = "dispenser_nopower" return @@ -461,6 +462,7 @@ /obj/machinery/chem_dispenser/soda/update_icon_state() return + /obj/machinery/chem_dispenser/beer icon_state = "booze_dispenser" name = "booze dispenser" diff --git a/code/modules/reagents/machinery/chem_master.dm b/code/modules/reagents/machinery/chem_master.dm index 8f6b53ccc3c..b899c101f96 100644 --- a/code/modules/reagents/machinery/chem_master.dm +++ b/code/modules/reagents/machinery/chem_master.dm @@ -415,7 +415,8 @@ popup.set_content(dat) popup.open() -/obj/machinery/chem_master/update_icon() +/obj/machinery/chem_master/update_icon_state() + . = ..() if(machine_stat & BROKEN) icon_state = (beaker?"mixer1_b":"mixer0_b") else if(machine_stat & NOPOWER) diff --git a/code/modules/reagents/machinery/reagentgrinder.dm b/code/modules/reagents/machinery/reagentgrinder.dm index 67d3ab908ef..c37b914a381 100644 --- a/code/modules/reagents/machinery/reagentgrinder.dm +++ b/code/modules/reagents/machinery/reagentgrinder.dm @@ -66,6 +66,7 @@ /obj/machinery/reagentgrinder/update_icon_state() + . = ..() icon_state = "juicer"+num2text(!isnull(beaker)) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index aa3561200a8..8dacbdb9675 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -119,6 +119,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) update() /obj/machinery/conveyor/update_icon_state() + . = ..() if(machine_stat & BROKEN) icon_state = "conveyor-broken" else @@ -285,6 +286,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) // update the icon depending on the position /obj/machinery/conveyor_switch/update_icon_state() + . = ..() if(position<0) if(invert_icon) icon_state = "switch-fwd" diff --git a/code/modules/recycling/recycler.dm b/code/modules/recycling/recycler.dm index d0430626397..551b82d21ee 100644 --- a/code/modules/recycling/recycler.dm +++ b/code/modules/recycling/recycler.dm @@ -9,7 +9,8 @@ //Pointing west because that's the only sprite we got dir = NORTH -/obj/machinery/recycler/update_icon() +/obj/machinery/recycler/update_icon_state() + . = ..() icon_state = "grinder-o[(machine_stat & (BROKEN|NOPOWER)) ? "0":"1"]" /obj/machinery/recycler/Bumped(atom/movable/AM) diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 7df00b91bf7..f60cc5d6ef6 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -24,8 +24,8 @@ GLOBAL_LIST_EMPTY(tagger_locations) qdel(src) return -/obj/structure/bigDelivery/update_icon() - overlays = new() +/obj/structure/bigDelivery/update_overlays() + . = ..() if(nameset || examtext) var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_label") if(icon_state == "deliverycloset") @@ -38,7 +38,7 @@ GLOBAL_LIST_EMPTY(tagger_locations) label_x = rand(-8, 6) I.pixel_x = label_x I.pixel_y = -3 - overlays += I + . += I if(src.sortTag) var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_tag") if(icon_state == "deliverycloset") @@ -51,7 +51,7 @@ GLOBAL_LIST_EMPTY(tagger_locations) tag_x = rand(-8, 6) I.pixel_x = tag_x I.pixel_y = -3 - overlays += I + . += I /obj/structure/bigDelivery/examine(mob/user) ..() @@ -138,13 +138,13 @@ GLOBAL_LIST_EMPTY(tagger_locations) qdel(src) return -/obj/item/smallDelivery/update_icon() - overlays = new() +/obj/item/smallDelivery/update_overlays() + . = ..() if((nameset || examtext) && icon_state != "deliverycrate1") var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_label") if(icon_state == "deliverycrate5") I.pixel_y = -1 - overlays += I + . += I if(src.sortTag) var/image/I = new/image('icons/obj/items/storage/storage.dmi',"delivery_tag") switch(icon_state) @@ -161,7 +161,7 @@ GLOBAL_LIST_EMPTY(tagger_locations) I.pixel_y = 3 if("deliverycrate5") I.pixel_y = -3 - overlays += I + . += I /obj/item/smallDelivery/examine(mob/user) ..() diff --git a/code/modules/reqs/supply.dm b/code/modules/reqs/supply.dm index 43fccb8daa4..3c8728da521 100644 --- a/code/modules/reqs/supply.dm +++ b/code/modules/reqs/supply.dm @@ -1,7 +1,8 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( /mob/living, /obj/item/disk/nuclear, - /obj/item/radio/beacon + /obj/item/radio/beacon, + /obj/vehicle, ))) /datum/supply_order @@ -45,6 +46,8 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( var/faction = FACTION_TERRAGOV /// Id of the home docking port var/home_id = "supply_home" + ///prefix for railings and gear todo should probbaly be defines instead? + var/railing_gear_name = "supply" /obj/docking_port/mobile/supply/Destroy(force) for(var/i in railings) @@ -77,11 +80,11 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( /obj/docking_port/mobile/supply/register() . = ..() for(var/obj/machinery/gear/G in GLOB.machines) - if(G.id == "supply_elevator_gear") + if(G.id == (railing_gear_name+"_elevator_gear")) gears += G RegisterSignal(G, COMSIG_QDELETING, PROC_REF(clean_gear)) for(var/obj/machinery/door/poddoor/railing/R in GLOB.machines) - if(R.id == "supply_elevator_railing") + if(R.id == (railing_gear_name+"_elevator_railing")) railings += R RegisterSignal(R, COMSIG_QDELETING, PROC_REF(clean_railing)) R.linked_pad = src @@ -127,7 +130,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( return 2 return ..() -/obj/docking_port/mobile/supply/proc/buy(mob/user) +/obj/docking_port/mobile/supply/proc/buy(mob/user, datum/supply_ui/supply_ui) if(!length(SSpoints.shoppinglist[faction])) return log_game("Supply pack orders have been purchased by [key_name(user)]") @@ -470,7 +473,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( addtimer(CALLBACK(supply_shuttle, TYPE_PROC_REF(/obj/docking_port/mobile/supply, sell)), 15 SECONDS) else var/obj/docking_port/D = SSshuttle.getDock(home_id) - supply_shuttle.buy(usr) + supply_shuttle.buy(usr, src) playsound(D.return_center_turf(), 'sound/machines/elevator_move.ogg', 50, 0) SSshuttle.moveShuttle(shuttle_id, home_id, TRUE) . = TRUE @@ -655,3 +658,298 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( /obj/item/storage/backpack/marine/radiopack/proc/clean_beacon_datum() SIGNAL_HANDLER beacon_datum = null + +/obj/docking_port/mobile/supply/vehicle + railing_gear_name = "vehicle" + id = SHUTTLE_VEHICLE_SUPPLY + home_id = "vehicle_home" + +/obj/docking_port/mobile/supply/vehicle/buy(mob/user, datum/supply_ui/supply_ui) + var/datum/supply_ui/vehicles/veh_ui = supply_ui + if(!veh_ui || !veh_ui.current_veh_type) + return + var/obj/vehicle/sealed/armored/tanktype = veh_ui.current_veh_type + var/is_assault = initial(tanktype.flags_armored) & ARMORED_PURCHASABLE_ASSAULT + if(GLOB.purchased_tanks[user.faction]?["[is_assault]"]) + to_chat(usr, span_danger("A vehicle of this type has already been purchased!")) + return + if(!GLOB.purchased_tanks[user.faction]) + GLOB.purchased_tanks[user.faction] = list() + GLOB.purchased_tanks[user.faction]["[is_assault]"] += 1 + var/obj/vehicle/sealed/armored/tank = new tanktype(loc) + if(veh_ui.current_primary) + var/obj/item/armored_weapon/gun = new veh_ui.current_primary(loc) + gun.attach(tank, TRUE) + if(veh_ui.current_secondary) + var/obj/item/armored_weapon/gun = new veh_ui.current_secondary(loc) + gun.attach(tank, FALSE) + if(veh_ui.current_driver_mod) + var/obj/item/tank_module/mod = new veh_ui.current_driver_mod(loc) + mod.on_equip(tank) + if(veh_ui.current_gunner_mod) + var/obj/item/tank_module/mod = new veh_ui.current_gunner_mod(loc) + mod.on_equip(tank) + if(length(veh_ui.primary_ammo)) + var/turf/dumploc = get_step(get_step(loc, NORTH), NORTH) // todo should autoload depending on tank prolly + for(var/ammo in veh_ui.primary_ammo) + for(var/i=1 to veh_ui.primary_ammo[ammo]) + new ammo(dumploc) + if(length(veh_ui.secondary_ammo)) + var/turf/dumploc = get_step(get_step(loc, NORTH), NORTH) // todo should autoload depending on tank prolly + for(var/ammo in veh_ui.secondary_ammo) + for(var/i=1 to veh_ui.secondary_ammo[ammo]) + new ammo(dumploc) + +/obj/docking_port/stationary/supply/vehicle + id = "vehicle_home" + roundstart_template = /datum/map_template/shuttle/supply/vehicle + + + +GLOBAL_LIST_EMPTY(armored_gunammo) +GLOBAL_LIST_EMPTY(armored_modtypes) +GLOBAL_LIST_INIT(armored_guntypes, armored_init_guntypes()) +GLOBAL_LIST_EMPTY(purchased_tanks) +#define DEFAULT_MAX_ARMORED_AMMO 20 + +///im a lazy bum who cant use initial on lists, so we just load everything into a list +/proc/armored_init_guntypes() + . = list() + for(var/obj/vehicle/sealed/armored/vehtype AS in typesof(/obj/vehicle/sealed/armored)) + vehtype = new vehtype + GLOB.armored_modtypes[vehtype.type] = vehtype.permitted_mods + .[vehtype.type] = vehtype.permitted_weapons + qdel(vehtype) + for(var/obj/item/armored_weapon/gun AS in typesof(/obj/item/armored_weapon)) + gun = new gun + GLOB.armored_gunammo[gun.type] = gun.accepted_ammo + qdel(gun) + +/datum/supply_ui/vehicles + tgui_name = "VehicleSupply" + shuttle_id = SHUTTLE_VEHICLE_SUPPLY + home_id = "vehicle_home" + /// current selected vehicles typepath + var/current_veh_type + /// current selected primary weapons typepath + var/current_primary + /// current selected secondaryies typepath + var/current_secondary + /// current driver mod typepath + var/current_driver_mod + /// current gunner mod typepath + var/current_gunner_mod + /// current primary ammo list, type = count + var/list/primary_ammo = list() + /// current secondary ammo list, type = count + var/list/secondary_ammo = list() + +/datum/supply_ui/vehicles/ui_static_data(mob/user) + var/list/data = list() + for(var/obj/vehicle/sealed/armored/vehtype AS in typesof(/obj/vehicle/sealed/armored)) + var/flags = vehtype::flags_armored + + if(flags & ARMORED_PURCHASABLE_TRANSPORT) + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_EXPERIENCED) + continue + else if(flags & ARMORED_PURCHASABLE_ASSAULT) + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN) + continue + else + continue + + data["vehicles"] += list(list("name" = initial(vehtype.name), "desc" = initial(vehtype.desc), "type" = "[vehtype]", "isselected" = (vehtype == current_veh_type))) + if(vehtype != current_veh_type) + continue + for(var/obj/item/armored_weapon/gun AS in GLOB.armored_guntypes[vehtype]) + var/primary_selected = (current_primary == gun) + var/secondary_selected = (current_secondary == gun) + if(initial(gun.weapon_slot) & MODULE_PRIMARY) + data["primaryWeapons"] += list(list( + "name" = initial(gun.name), + "desc" = initial(gun.desc), + "type" = gun, + "isselected" = primary_selected, + )) + if(primary_selected) + for(var/obj/item/ammo_magazine/mag AS in primary_ammo) + data["primaryammotypes"] += list(list( + "name" = initial(mag.name), + "type" = mag, + "current" = primary_ammo[mag], + "max" = DEFAULT_MAX_ARMORED_AMMO, //TODO make vehicle ammo dynamic instead of fixed number + )) + + if(initial(gun.weapon_slot) & MODULE_SECONDARY) + data["secondaryWeapons"] += list(list( + "name" = initial(gun.name), + "desc" = initial(gun.desc), + "type" = gun, + "isselected" = secondary_selected, + )) + if(secondary_selected) + for(var/obj/item/ammo_magazine/mag AS in secondary_ammo) + data["secondarymmotypes"] += list(list( + "name" = initial(mag.name), + "type" = mag, + "current" = secondary_ammo[mag], + "max" = DEFAULT_MAX_ARMORED_AMMO, //TODO make vehicle ammo dynamic instead of fixed number + )) + + for(var/obj/item/tank_module/mod AS in GLOB.armored_modtypes[vehtype]) + if(initial(mod.is_driver_module)) + data["driverModules"] += list(list( + "name" = initial(mod.name), + "desc" = initial(mod.desc), + "type" = mod, + "isselected" = (current_driver_mod == mod), + )) + else + data["gunnerModules"] += list(list( + "name" = initial(mod.name), + "desc" = initial(mod.desc), + "type" = mod, + "isselected" = (current_gunner_mod == mod), + )) + return data + +/datum/supply_ui/vehicles/ui_data(mob/living/user) + var/list/data = list() + if(supply_shuttle) + if(supply_shuttle?.mode == SHUTTLE_CALL) + if(is_mainship_level(supply_shuttle.destination.z)) + data["elevator"] = "Raising" + data["elevator_dir"] = "up" + else + data["elevator"] = "Lowering" + data["elevator_dir"] = "down" + else if(supply_shuttle?.mode == SHUTTLE_IDLE) + if(is_mainship_level(supply_shuttle.z)) + data["elevator"] = "Raised" + data["elevator_dir"] = "down" + else if(current_veh_type) + data["elevator"] = "Purchase" + data["elevator_dir"] = "store" + else + data["elevator"] = "Lowered" + data["elevator_dir"] = "up" + else + if(is_mainship_level(supply_shuttle.z)) + data["elevator"] = "Lowering" + data["elevator_dir"] = "down" + else + data["elevator"] = "Raising" + data["elevator_dir"] = "up" + else + data["elevator"] = "MISSING!" + return data + +/datum/supply_ui/vehicles/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + switch(action) + if("setvehicle") + var/newtype = text2path(params["type"]) + if(!ispath(newtype, /obj/vehicle/sealed/armored)) + return + var/obj/vehicle/sealed/armored/tank_type = newtype + var/is_assault = initial(tank_type.flags_armored) & ARMORED_PURCHASABLE_ASSAULT + if(GLOB.purchased_tanks[usr.faction]?["[is_assault]"]) + to_chat(usr, span_danger("A vehicle of this type has already been purchased!")) + return + current_veh_type = newtype + . = TRUE + + if("setprimary") + if(!current_veh_type) + return + var/newtype = text2path(params["type"]) + if(!(newtype in GLOB.armored_guntypes[current_veh_type])) + return + current_primary = newtype + var/list/assoc_cast = GLOB.armored_gunammo[newtype] + primary_ammo = assoc_cast.Copy() + for(var/ammo in primary_ammo) + primary_ammo[ammo] = 0 + . = TRUE + + if("setsecondary") + if(!current_veh_type) + return + var/newtype = text2path(params["type"]) + if(!(newtype in GLOB.armored_guntypes[current_veh_type])) + return + current_secondary = newtype + var/list/assoc_cast = GLOB.armored_gunammo[newtype] + secondary_ammo = assoc_cast.Copy() + for(var/ammo in secondary_ammo) + secondary_ammo[ammo] = 0 + . = TRUE + + if("set_ammo_primary") + if(!current_primary) + return + var/newtype = text2path(params["type"]) + if(!(newtype in primary_ammo)) + return + var/non_adjusted_total = 0 + for(var/ammo in primary_ammo) + if(ammo == newtype) + continue + non_adjusted_total += primary_ammo[ammo] + var/newvalue = clamp(params["new_value"], 0, DEFAULT_MAX_ARMORED_AMMO-non_adjusted_total) + primary_ammo[newtype] = newvalue + . = TRUE + + if("set_ammo_secondary") + if(!current_secondary) + return + var/newtype = text2path(params["type"]) + if(!(newtype in secondary_ammo)) + return + var/non_adjusted_total = 0 + for(var/ammo in secondary_ammo) + if(ammo == newtype) + continue + non_adjusted_total += secondary_ammo[ammo] + var/newvalue = clamp(params["new_value"], 0, DEFAULT_MAX_ARMORED_AMMO-non_adjusted_total) + secondary_ammo[newtype] = newvalue + . = TRUE + + if("set_driver_mod") + if(!current_veh_type) + return + var/newtype = text2path(params["type"]) + if(!ispath(newtype, /obj/item/tank_module)) + return + if(!(newtype in GLOB.armored_modtypes[current_veh_type])) + return + current_driver_mod = newtype + . = TRUE + + if("set_gunner_mod") + if(!current_veh_type) + return + var/newtype = text2path(params["type"]) + if(!ispath(newtype, /obj/item/tank_module)) + return + if(!(newtype in GLOB.armored_modtypes[current_veh_type])) + return + current_gunner_mod = newtype + . = TRUE + + if("deploy") + if(supply_shuttle.mode != SHUTTLE_IDLE) + to_chat(usr, span_danger("Elevator moving!")) + return + if(is_mainship_level(supply_shuttle.z)) + to_chat(usr, span_danger("Elevator raised. Lower to deploy vehicle.")) + return + supply_shuttle.buy(usr, src) + ui_act("send", params, ui, state) + SStgui.close_user_uis(usr, src) + + if(.) + update_static_data(usr) diff --git a/code/modules/reqs/supplypacks.dm b/code/modules/reqs/supplypacks.dm index c8d5b176d5b..dd01b0f1750 100644 --- a/code/modules/reqs/supplypacks.dm +++ b/code/modules/reqs/supplypacks.dm @@ -925,6 +925,21 @@ WEAPONS contains = list(/obj/item/weapon/gun/grenade_launcher/multinade_launcher/unloaded) cost = 450 +/datum/supply_packs/weapons/ltb_shells + name = "LTB tank shell" + contains = list(/obj/item/ammo_magazine/tank/ltb_cannon) + cost = 10 + +/datum/supply_packs/weapons/ltaap_rounds + name = "LTAAP tank magazine" + contains = list(/obj/item/ammo_magazine/tank/ltaap_chaingun) + cost = 10 + +/datum/supply_packs/weapons/cupola_rounds + name = "Cupola tank magazine" + contains = list(/obj/item/ammo_magazine/tank/secondary_cupola) + cost = 10 + /******************************************************************************* EXPLOSIVES *******************************************************************************/ diff --git a/code/modules/screen_alert/misc_alert.dm b/code/modules/screen_alert/misc_alert.dm index 9f206bfbecd..0a28b80b244 100644 --- a/code/modules/screen_alert/misc_alert.dm +++ b/code/modules/screen_alert/misc_alert.dm @@ -17,7 +17,7 @@ ///x offset of image var/image_to_play_offset_x = 0 -/atom/movable/screen/text/screen_text/picture/Initialize(mapload) +/atom/movable/screen/text/screen_text/picture/Initialize(mapload, datum/hud/hud_owner) . = ..() overlays += image('icons/UI_Icons/screen_alert_images.dmi', icon_state = image_to_play, pixel_y = image_to_play_offset_y, pixel_x = image_to_play_offset_x) diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index 438ef05dab5..8601ec98aaf 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -42,7 +42,8 @@ event_triggered_by = user broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices -/obj/machinery/keycard_auth/update_icon() +/obj/machinery/keycard_auth/update_icon_state() + . = ..() if(machine_stat &NOPOWER) icon_state = "auth_off" diff --git a/code/modules/shuttle/mini_dropship.dm b/code/modules/shuttle/mini_dropship.dm index e79a4a85420..bc3fba62e13 100644 --- a/code/modules/shuttle/mini_dropship.dm +++ b/code/modules/shuttle/mini_dropship.dm @@ -17,7 +17,7 @@ desc = "Used to designate a precise transit location for the Tadpole." icon_state = "shuttlecomputer" screen_overlay = "shuttlecomputer_screen" - req_one_access = list(ACCESS_MARINE_DROPSHIP, ACCESS_MARINE_LEADER) + req_access = list(ACCESS_MARINE_TADPOLE) density = FALSE interaction_flags = INTERACT_OBJ_UI resistance_flags = RESIST_ALL diff --git a/code/modules/shuttle/shuttle_rotate.dm b/code/modules/shuttle/shuttle_rotate.dm index e761b5270c6..1a8f1a85e39 100644 --- a/code/modules/shuttle/shuttle_rotate.dm +++ b/code/modules/shuttle/shuttle_rotate.dm @@ -63,6 +63,12 @@ If ever any of these procs are useful for non-shuttles, rename it to proc/rotate /************************************Machine rotate procs************************************/ +//override to avoid rotating multitile vehicles +/obj/vehicle/shuttleRotate(rotation, params) + if(hitbox) + params = NONE + return ..() + /obj/machinery/atmospherics/shuttleRotate(rotation, params) var/list/real_node_connect = getNodeConnects() for(var/i in 1 to device_type) diff --git a/code/modules/unit_tests/create_and_destroy.dm b/code/modules/unit_tests/create_and_destroy.dm index be40f64df11..b8b9bc011f2 100644 --- a/code/modules/unit_tests/create_and_destroy.dm +++ b/code/modules/unit_tests/create_and_destroy.dm @@ -47,6 +47,8 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) ignore += typesof(/obj/effect/temp_visual) ignore += typesof(/obj/effect/landmark) ignore += typesof(/obj/effect/baseturf_helper) + ///forcespawned abstract type for vehicles, will never spawn outside of it + ignore += typesof(/obj/hitbox) //Screen objects don't play nicely when spawned manually. ignore += typesof(/atom/movable/screen) diff --git a/code/modules/unit_tests/map_templates.dm b/code/modules/unit_tests/map_templates.dm index f79919bad70..907ef824dc0 100644 --- a/code/modules/unit_tests/map_templates.dm +++ b/code/modules/unit_tests/map_templates.dm @@ -7,6 +7,7 @@ /datum/map_template/modular/prison, /datum/map_template/modular/bigred, /datum/map_template/modular/end_of_round, + /datum/map_template/interior, ) /datum/unit_test/map_templates/Run() diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/__vehicle.dm similarity index 91% rename from code/modules/vehicles/_vehicle.dm rename to code/modules/vehicles/__vehicle.dm index 64236ebe0e9..eefeefb0925 100644 --- a/code/modules/vehicles/_vehicle.dm +++ b/code/modules/vehicles/__vehicle.dm @@ -9,6 +9,8 @@ anchored = FALSE blocks_emissive = EMISSIVE_BLOCK_GENERIC obj_flags = CAN_BE_HIT + flags_atom = CRITICAL_ATOM + appearance_flags = TILE_BOUND|PIXEL_SCALE|LONG_GLIDE resistance_flags = XENO_DAMAGEABLE allow_pass_flags = PASS_AIR COOLDOWN_DECLARE(cooldown_vehicle_move) @@ -20,6 +22,8 @@ var/max_drivers = 1 var/move_delay = 2 var/lastmove = 0 + ///multitile hitbox, set to a hitbox type to make this vehicle multitile. + var/obj/hitbox/hitbox /** * If the driver needs a certain item in hand (or inserted, for vehicles) to drive this. For vehicles, this must be duplicated on their riding component subtype * [/datum/component/riding/var/keytype] variable because only a few specific checks are handled here with this var, and the majority of it is on the riding component @@ -42,6 +46,8 @@ /obj/vehicle/Initialize(mapload) . = ..() + if(hitbox) + hitbox = new hitbox(loc, src) occupants = list() autogrant_actions_passenger = list() autogrant_actions_controller = list() @@ -92,6 +98,10 @@ /obj/vehicle/proc/is_driver(mob/M) return is_occupant(M) && occupants[M] & VEHICLE_CONTROL_DRIVE +///Is the passed mob an equipment controller? +/obj/vehicle/proc/is_equipment_controller(mob/M) + return is_occupant(M) && occupants[M] & VEHICLE_CONTROL_EQUIPMENT + /obj/vehicle/proc/is_occupant(mob/M) return !isnull(LAZYACCESS(occupants, M)) @@ -157,7 +167,7 @@ /obj/vehicle/Moved(atom/old_loc, movement_dir, forced, list/old_locs) . = ..() if(trailer) - trailer.Move(old_loc, movement_dir) + trailer.Move(old_loc, movement_dir, glide_size) //TGMC ADDED BELOW diff --git a/code/modules/vehicles/_hitbox.dm b/code/modules/vehicles/_hitbox.dm new file mode 100644 index 00000000000..12f7f32783e --- /dev/null +++ b/code/modules/vehicles/_hitbox.dm @@ -0,0 +1,238 @@ +/** + * HITBOX + * The core of multitile. Acts as a relay for damage and stops people from walking onto the multitle sprite + * has changed bounds and as thus must always be forcemoved so it doesnt break everything + * I would use pixel movement but the maptick caused by it is way too high and a fake tile based movement might work? but I want this to at least pretend to be generic + * Thus we just use this relay. it's an obj so we can make sure all the damage procs that work on root also work on the hitbox + */ +/obj/hitbox + density = TRUE + anchored = TRUE + invisibility = INVISIBILITY_MAXIMUM + bound_width = 96 + bound_height = 96 + bound_x = -32 + bound_y = -32 + max_integrity = INFINITY + move_resist = INFINITY // non forcemoving this could break gliding so lets just say no + ///people riding on this hitbox that we want to move with us + var/list/atom/movable/tank_desants + ///The "parent" that this hitbox is attached to and to whom it will relay damage + var/obj/vehicle/root = null + +/obj/hitbox/Initialize(mapload, obj/vehicle/new_root) + . = ..() + root = new_root + allow_pass_flags = root.allow_pass_flags + flags_atom = root.flags_atom + resistance_flags = root.resistance_flags + RegisterSignal(new_root, COMSIG_MOVABLE_MOVED, PROC_REF(root_move)) + RegisterSignal(new_root, COMSIG_QDELETING, PROC_REF(root_delete)) + RegisterSignals(new_root, list(COMSIG_RIDDEN_DRIVER_MOVE, COMSIG_VEHICLE_MOVE), PROC_REF(on_attempt_drive)) + RegisterSignal(new_root, COMSIG_ATOM_DIR_CHANGE, PROC_REF(owner_turned)) + + var/static/list/connections = list( + COMSIG_OBJ_TRY_ALLOW_THROUGH = PROC_REF(can_cross_hitbox), + COMSIG_TURF_JUMP_ENDED_HERE = PROC_REF(on_jump_landed), + COMSIG_ATOM_EXITED = PROC_REF(on_exited), + ) + AddElement(/datum/element/connect_loc, connections) + +/obj/hitbox/Destroy(force) + if(!force) // only when the parent is deleted + return QDEL_HINT_LETMELIVE + root?.hitbox = null + root = null + return ..() + +///signal handler for handling PASS_WALKOVER +/obj/hitbox/proc/can_cross_hitbox(datum/source, atom/mover) + SIGNAL_HANDLER + if(locate(src) in mover.loc) + return TRUE + +///Signal handler to spin the desants as well when the tank turns +/obj/hitbox/proc/owner_turned(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + if(!new_dir || new_dir == old_dir) + return + for(var/mob/living/desant AS in tank_desants) + if(desant.loc == root.loc) + continue + var/turf/new_pos + //doesnt work with diags, but that shouldnt happen, right? + if(REVERSE_DIR(old_dir) == new_dir) + new_pos = get_step(root, REVERSE_DIR(get_dir(desant, root))) + else if(turn(old_dir, 90) == new_dir) + new_pos = get_step(root, turn(get_dir(desant, root), -90)) + else + new_pos = get_step(root, turn(get_dir(desant, root), 90)) + desant.set_glide_size(32) + desant.forceMove(new_pos) + +///signal handler when someone jumping lands on us +/obj/hitbox/proc/on_jump_landed(datum/source, atom/lander) + SIGNAL_HANDLER + if(HAS_TRAIT(lander, TRAIT_TANK_DESANT)) + return + ADD_TRAIT(lander, TRAIT_TANK_DESANT, VEHICLE_TRAIT) + LAZYSET(tank_desants, lander, lander.layer) + RegisterSignal(lander, COMSIG_QDELETING, PROC_REF(on_desant_del)) + lander.layer = ABOVE_MOB_PLATFORM_LAYER + +///signal handler when we leave a turf under the hitbox +/obj/hitbox/proc/on_exited(atom/source, atom/movable/AM, direction) + SIGNAL_HANDLER + if(!HAS_TRAIT(AM, TRAIT_TANK_DESANT)) + return + if(locate(src) in AM.loc) //Î'd cut the locate but for some reason it wdoesnt work lol + return + REMOVE_TRAIT(AM, TRAIT_TANK_DESANT, VEHICLE_TRAIT) + AM.layer = LAZYACCESS(tank_desants, AM) + LAZYREMOVE(tank_desants, AM) + UnregisterSignal(AM, COMSIG_QDELETING) + +///cleanup riders on deletion +/obj/hitbox/proc/on_desant_del(datum/source) + SIGNAL_HANDLER + LAZYREMOVE(tank_desants, source) + +///when root deletes is the only time we want to be deleting +/obj/hitbox/proc/root_delete() + SIGNAL_HANDLER + qdel(src, TRUE) + +///when the owner moves, let's move with them! +/obj/hitbox/proc/root_move(atom/movable/mover, atom/oldloc, direction) + SIGNAL_HANDLER + //direction is null here, so we improvise + direction = get_dir(oldloc, mover) + var/move_dist = get_dist(oldloc, mover) + forceMove(mover.loc) + var/new_z = (z != oldloc.z) + for(var/mob/living/tank_desant AS in tank_desants) + tank_desant.set_glide_size(root.glide_size) + tank_desant.forceMove(new_z ? loc : get_step(tank_desant, direction)) //For simplicity we just move desants to the middle of the tank on z change to avoid various issues + if(isxeno(tank_desant)) + continue + if(move_dist > 1) + continue + if(!tank_desant.l_hand || !tank_desant.r_hand) + continue + balloon_alert(tank_desant, "poor grip!") + var/away_dir = get_dir(tank_desant, root) + if(!away_dir) + away_dir = pick(GLOB.alldirs) + away_dir = REVERSE_DIR(away_dir) + var/turf/target = get_step(get_step(root, away_dir), away_dir) + tank_desant.throw_at(target, 3, 3, root) + +///called when the tank is off movement cooldown and someone tries to move it +/obj/hitbox/proc/on_attempt_drive(atom/movable/movable_parent, mob/living/user, direction) + SIGNAL_HANDLER + if(ISDIAGONALDIR(direction)) + return COMPONENT_DRIVER_BLOCK_MOVE + if((root.dir != direction) && (root.dir != REVERSE_DIR(direction))) + root.setDir(direction) + if(isarmoredvehicle(root)) + var/obj/vehicle/sealed/armored/armor = root + playsound(armor, armor.engine_sound, 100, TRUE, 20) + return COMPONENT_DRIVER_BLOCK_MOVE + //Due to this being a hot proc this part here is inlined and set on a by-hitbox-size basis + ///////////////////////////// + var/turf/centerturf = get_step(get_step(root, direction), direction) + var/list/enteringturfs = list(centerturf) + enteringturfs += get_step(centerturf, turn(direction, 90)) + enteringturfs += get_step(centerturf, turn(direction, -90)) + ///////////////////////////// + var/canstep = TRUE + for(var/turf/T AS in enteringturfs) //No break because we want to crush all the turfs before we start trying to move + if(!T.Enter(root, direction)) //Check if we can cross the turf first/bump the turf + canstep = FALSE + + for(var/atom/movable/AM AS in T.contents) // this is checked in turf/enter but it doesnt return false so lmao + if(AM.pass_flags & PASS_TANK) //rather than add it to AM/CanAllowThrough for this one interaction, lets just check it manually + continue + if(AM.CanPass(root)) // Then check for obstacles to crush + continue + root.Bump(AM) //manually call bump on everything + canstep = FALSE + + if(canstep) + return NONE + return COMPONENT_DRIVER_BLOCK_MOVE + +/obj/hitbox/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return + if((allow_pass_flags & PASS_TANK) && (mover.pass_flags & PASS_TANK)) + return TRUE + +/obj/hitbox/projectile_hit(obj/projectile/proj) + if(proj.firer == root) + return FALSE + return root.projectile_hit(arglist(args)) + +/obj/hitbox/bullet_act(obj/projectile/proj) + SHOULD_CALL_PARENT(FALSE) // this is an abstract object: we have to avoid everything on parent + SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, proj) + return root.bullet_act(proj) + +/obj/hitbox/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", effects = TRUE, attack_dir, armour_penetration = 0, mob/living/blame_mob) + return root.take_damage(arglist(args)) + +/obj/hitbox/ex_act(severity) + return + +/obj/hitbox/effect_smoke(obj/effect/particle_effect/smoke/S) + . = ..() + if(CHECK_BITFIELD(S.smoke_traits, SMOKE_XENO_ACID)) + take_damage(2 * S.strength, BURN, ACID) + +///2x2 hitbox version +/obj/hitbox/medium + bound_width = 64 + bound_height = 64 + bound_x = 0 + bound_y = -32 + +/obj/hitbox/medium/on_attempt_drive(atom/movable/movable_parent, mob/living/user, direction) + if(ISDIAGONALDIR(direction)) + return COMPONENT_DRIVER_BLOCK_MOVE + if((root.dir != direction) && (root.dir != REVERSE_DIR(direction))) + root.setDir(direction) + if(isarmoredvehicle(root)) + var/obj/vehicle/sealed/armored/armor = root + playsound(armor, armor.engine_sound, 100, TRUE, 20) + return COMPONENT_DRIVER_BLOCK_MOVE + /////////////////////////// + var/turf/centerturf = get_step(root, direction) + var/list/enteringturfs = list() + switch(direction) + if(NORTH) + enteringturfs += get_step(centerturf, turn(direction, -90)) + if(SOUTH) + centerturf = get_step(centerturf, direction) + enteringturfs += get_step(centerturf, turn(direction, 90)) + if(EAST) + centerturf = get_step(centerturf, direction) + enteringturfs += get_step(centerturf, turn(direction, -90)) + if(WEST) + enteringturfs += get_step(centerturf, turn(direction, 90)) + enteringturfs += centerturf + //////////////////////////////////// + var/canstep = TRUE + for(var/turf/T AS in enteringturfs) //No break because we want to crush all the turfs before we start trying to move + if(!T.Enter(root, direction)) //Check if we can cross the turf first/bump the turf + canstep = FALSE + + for(var/atom/movable/O AS in T.contents) // this is checked in turf/enter but it doesnt return false so lmao + if(O.CanPass(root)) // Then check for obstacles to crush + continue + root.Bump(O) //manually call bump on everything + canstep = FALSE + + if(canstep) + return NONE + return COMPONENT_DRIVER_BLOCK_MOVE diff --git a/code/modules/vehicles/armored/__armored.dm b/code/modules/vehicles/armored/__armored.dm new file mode 100644 index 00000000000..fe8162801d9 --- /dev/null +++ b/code/modules/vehicles/armored/__armored.dm @@ -0,0 +1,689 @@ +/obj/vehicle/sealed/armored + name = "\improper MT - Shortstreet MK4" + desc = "An adorable chunk of metal with an alarming amount of firepower designed to crush, immolate, destroy and maim anything that Nanotrasen wants it to. This model contains advanced Bluespace technology which allows a TARDIS-like amount of room on the inside." + icon = 'icons/obj/armored/1x1/tinytank.dmi' + icon_state = "tank" + pixel_x = -16 + pixel_y = -8 + layer = ABOVE_MOB_LAYER + max_drivers = 1 + move_resist = INFINITY + flags_atom = BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION|CRITICAL_ATOM + allow_pass_flags = PASS_TANK|PASS_AIR|PASS_WALKOVER|PASS_THROW + resistance_flags = XENO_DAMAGEABLE|UNACIDABLE|PLASMACUTTER_IMMUNE|PORTAL_IMMUNE + + move_delay = 0.7 SECONDS + max_integrity = 600 + light_range = 10 + ///Tank bitflags + var/flags_armored = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_HEADLIGHTS + ///Sound file(s) to play when we drive around + var/engine_sound = 'sound/ambience/tank_driving.ogg' + ///frequency to play the sound with + var/engine_sound_length = 2 SECONDS + /// How long it takes to rev (vrrm vrrm!) TODO: merge this up to /vehicle here and on tg because of cars + COOLDOWN_DECLARE(enginesound_cooldown) + + ///Cool and good turret overlay that allows independently swiveling guns + var/atom/movable/vis_obj/turret_overlay/turret_overlay + ///Icon for the rotating turret icon. also should hold the icons for the weapon icons + var/turret_icon = 'icons/obj/armored/1x1/tinytank_gun.dmi' + ///Iconstate for the rotating main turret + var/turret_icon_state = "turret" + ///secondary independently rotating overlay, if we only have a secondary weapon + var/image/secondary_weapon_overlay + ///Damage overlay for when the vehicle gets damaged + var/atom/movable/vis_obj/tank_damage/damage_overlay + ///Icon file path for the damage overlay + var/damage_icon_path + ///Overlay for larger vehicles that need under parts + var/image/underlay + + ///reference to our interior datum if set, uses the typepath its set to + var/datum/interior/armored/interior + ///Skill required to enter this vehicle + var/required_entry_skill = SKILL_LARGE_VEHICLE_DEFAULT + ///What weapon we have in our primary slot + var/obj/item/armored_weapon/primary_weapon + ///What weapon we have in our secondary slot + var/obj/item/armored_weapon/secondary_weapon + ///Our driver utility module + var/obj/item/tank_module/driver_utility_module + ///Our driver utility module + var/obj/item/tank_module/gunner_utility_module + ///list of weapons we allow to attach + var/list/permitted_weapons = list(/obj/item/armored_weapon, /obj/item/armored_weapon/ltaap, /obj/item/armored_weapon/secondary_weapon) + ///list of mods we allow to attach + var/list/permitted_mods = list(/obj/item/tank_module/overdrive, /obj/item/tank_module/passenger, /obj/item/tank_module/ability/zoom) + ///Minimap flags to use for this vehcile + var/minimap_flags = MINIMAP_FLAG_MARINE + ///minimap iconstate to use for this vehicle + var/minimap_icon_state + ///if true disables stops users from being able to shoot weapons + var/weapons_safety = FALSE + //Bool for zoom on/off + var/zoom_mode = FALSE + /// damage done by rams + var/ram_damage = 20 + /** + * List for storing all item typepaths that we may "easy load" into the tank by attacking its entrance + * This will be turned into a typeCache on initialize + */ + var/list/easy_load_list + +/obj/vehicle/sealed/armored/Initialize(mapload) + easy_load_list = typecacheof(easy_load_list) + if(interior) + interior = new interior(src, CALLBACK(src, PROC_REF(interior_exit))) + . = ..() + if(flags_armored & ARMORED_HAS_UNDERLAY) + underlay = new(icon, icon_state + "_underlay", layer = layer-0.1) + add_overlay(underlay) + if(damage_icon_path) + damage_overlay = new() + damage_overlay.icon = damage_icon_path + damage_overlay.layer = layer+0.001 + vis_contents += damage_overlay + if(flags_armored & ARMORED_HAS_PRIMARY_WEAPON) + turret_overlay = new() + turret_overlay.icon = turret_icon + turret_overlay.icon_state = turret_icon_state + turret_overlay.setDir(dir) + turret_overlay.layer = layer+0.002 + if(flags_armored & ARMORED_HAS_MAP_VARIANTS) + switch(SSmapping.configs[GROUND_MAP].armor_style) + if(MAP_ARMOR_STYLE_JUNGLE) + turret_overlay.icon_state += "_jungle" + if(MAP_ARMOR_STYLE_ICE) + turret_overlay.icon_state += "_snow" + if(MAP_ARMOR_STYLE_PRISON) + turret_overlay.icon_state += "_urban" + if(MAP_ARMOR_STYLE_DESERT) + turret_overlay.icon_state += "_desert" + vis_contents += turret_overlay + if(flags_armored & ARMORED_HAS_MAP_VARIANTS) + switch(SSmapping.configs[GROUND_MAP].armor_style) + if(MAP_ARMOR_STYLE_JUNGLE) + icon_state += "_jungle" + if(MAP_ARMOR_STYLE_ICE) + icon_state += "_snow" + if(MAP_ARMOR_STYLE_PRISON) + icon_state += "_urban" + if(MAP_ARMOR_STYLE_DESERT) + icon_state += "_desert" + if(minimap_icon_state) + SSminimaps.add_marker(src, minimap_flags, image('icons/UI_icons/map_blips_large.dmi', null, minimap_icon_state)) + GLOB.tank_list += src + +/obj/vehicle/sealed/armored/Destroy() + if(primary_weapon) + QDEL_NULL(primary_weapon) + if(secondary_weapon) + QDEL_NULL(secondary_weapon) + if(driver_utility_module) + QDEL_NULL(driver_utility_module) + if(gunner_utility_module) + QDEL_NULL(gunner_utility_module) + if(damage_overlay) + QDEL_NULL(damage_overlay) + if(turret_overlay) + QDEL_NULL(turret_overlay) + if(isdatum(interior)) + QDEL_NULL(interior) + underlay = null + GLOB.tank_list -= src + return ..() + +/obj/vehicle/sealed/armored/generate_actions() + if(flags_armored & ARMORED_HAS_HEADLIGHTS) + initialize_controller_action_type(/datum/action/vehicle/sealed/armored/toggle_lights, VEHICLE_CONTROL_SETTINGS) + initialize_controller_action_type(/datum/action/vehicle/sealed/armored/horn, VEHICLE_CONTROL_SETTINGS) + if(interior) + return + initialize_passenger_action_type(/datum/action/vehicle/sealed/armored/eject) + if(max_occupants > 1) + initialize_passenger_action_type(/datum/action/vehicle/sealed/armored/swap_seat) + +///returns a list of possible locations that this vehicle may be entered from +/obj/vehicle/sealed/armored/proc/enter_locations(atom/movable/entering_thing) + // from any adjacent position + if(Adjacent(entering_thing, src)) + return list(get_turf(entering_thing)) + +/obj/vehicle/sealed/armored/obj_destruction(damage_amount, damage_type, damage_flag) + . = ..() + playsound(get_turf(src), 'sound/weapons/guns/fire/tank_cannon1.ogg', 100, TRUE) + +/obj/vehicle/sealed/armored/update_icon() + . = ..() + if(!damage_overlay) + return + switch(PERCENT(obj_integrity / max_integrity)) + if(0 to 20) + damage_overlay.icon_state = "damage_veryhigh" + if(20 to 40) + damage_overlay.icon_state = "damage_high" + if(40 to 70) + damage_overlay.icon_state = "damage_medium" + if(70 to 90) + damage_overlay.icon_state = "damage_small" + else + damage_overlay.icon_state = "null" + +/obj/vehicle/sealed/armored/update_overlays() + . = ..() + if(secondary_weapon_overlay) + . += secondary_weapon_overlay + +/obj/vehicle/sealed/armored/setDir(newdir) + . = ..() + if(secondary_weapon_overlay) + cut_overlay(secondary_weapon_overlay) + secondary_weapon_overlay.icon_state = secondary_weapon.icon_state + "_" + "[newdir]" + add_overlay(secondary_weapon_overlay) + +/obj/vehicle/sealed/armored/examine(mob/user) + . = ..() + if(!isxeno(user)) + . += "To fire its main cannon, left click a tile." + . += "To fire its secondary weapon, right click a tile." + . += "Middle click to toggle weapon safety." + . += "It's currently holding [LAZYLEN(occupants)]/[max_occupants] crew." + . += span_notice("There is [isnull(primary_weapon) ? "nothing" : "[primary_weapon]"] in the primary attachment point, [isnull(secondary_weapon) ? "nothing" : "[secondary_weapon]"] installed in the secondary slot, [isnull(driver_utility_module) ? "nothing" : "[driver_utility_module]"] in the driver utility slot and [isnull(gunner_utility_module) ? "nothing" : "[gunner_utility_module]"] in the gunner utility slot.") + if(!isxeno(user)) + . += "It is currently at [PERCENT(obj_integrity / max_integrity)]% integrity." + +/obj/vehicle/sealed/armored/get_mechanics_info() + . = ..() + var/list/named_paths = list() + named_paths += " You can easily load the following items by attacking the vehicle at its entrance or click dragging them " + for(var/obj/path AS in easy_load_list) + named_paths.Add(initial(path:name)) + var/list/entries = SScodex.retrieve_entries_for_string(name) + var/datum/codex_entry/general_entry = LAZYACCESS(entries, 1) + if(general_entry?.mechanics_text) + named_paths += general_entry.mechanics_text + return jointext(named_paths, "
") + +/obj/vehicle/sealed/armored/vehicle_move(mob/living/user, direction) + . = ..() + if(!.) + return + if(COOLDOWN_CHECK(src, enginesound_cooldown)) + COOLDOWN_START(src, enginesound_cooldown, engine_sound_length) + playsound(get_turf(src), engine_sound, 100, TRUE, 20) + after_move(direction) + forceMove(get_step(src, direction)) // still animates and calls moved() and all that stuff BUT we skip checks + +/obj/vehicle/sealed/armored/resisted_against(mob/living/user) + balloon_alert(user, "exiting...") + if(do_after(user, enter_delay, NONE, src)) + balloon_alert(user, "exited") + mob_exit(user, TRUE) + +/obj/vehicle/sealed/armored/CanAllowThrough(atom/movable/mover, turf/target) + . = ..() + if(.) + return + if((allow_pass_flags & PASS_TANK) && (mover.pass_flags & PASS_TANK)) + return TRUE + +/obj/vehicle/sealed/armored/Bump(atom/A) + . = ..() + if(HAS_TRAIT(A, TRAIT_STOPS_TANK_COLLISION)) + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_VEHICLE_CRUSHSOUND)) + visible_message(span_danger("[src] is stopped by [A]!")) + playsound(src, 'sound/effects/metal_crash.ogg', 45) + TIMER_COOLDOWN_START(src, COOLDOWN_VEHICLE_CRUSHSOUND, 1 SECONDS) + return + var/pilot + var/list/drivers = return_drivers() + if(length(drivers)) + pilot = drivers[1] + A.vehicle_collision(src, get_dir(src, A), get_turf(loc), get_turf(loc), pilot) + +/obj/vehicle/sealed/armored/auto_assign_occupant_flags(mob/new_occupant) + if(interior) //handled by interior seats + return + if(max_occupants == 1) + add_control_flags(new_occupant, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS|VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + return + + if(driver_amount() < max_drivers) //movement controllers + add_control_flags(new_occupant, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + else if(length(return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)) < 1) + add_control_flags(new_occupant, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + +/obj/vehicle/sealed/armored/exit_location(mob/M) + return get_step(src, REVERSE_DIR(dir)) + +///called when a mob tried to leave our interior +/obj/vehicle/sealed/armored/proc/interior_exit(mob/leaver, datum/interior/inside, teleport) + if(!teleport) + remove_occupant(leaver) + return + mob_exit(leaver, TRUE) + +/// call to try easy_loading an item into the tank. Checks for all being in the list , interior existing and the user bieng at the enter loc +/obj/vehicle/sealed/armored/proc/try_easy_load(atom/movable/thing_to_load, mob/living/user) + if(isgrabitem(thing_to_load)) + var/obj/item/grab/grab_item = thing_to_load + thing_to_load = grab_item.grabbed_thing + if(!isliving(thing_to_load) && !is_type_in_typecache(thing_to_load.type, easy_load_list)) + return + if(!interior) + user.balloon_alert(user, "no interior") + return + if(!interior.door) + user.balloon_alert(user, "no door") + return + var/list/enter_locs = enter_locations(user) + if(!((user.loc in enter_locs) || (thing_to_load.loc in enter_locs))) + user.balloon_alert(user, "not at entrance") + return + if(isliving(thing_to_load)) + user.visible_message(span_notice("[user] starts to stuff [thing_to_load] into \the [src]!")) + mob_try_enter(thing_to_load, user, TRUE) + return + user.temporarilyRemoveItemFromInventory(thing_to_load) + thing_to_load.forceMove(interior.door.get_enter_location()) + user.balloon_alert(user, "item thrown inside") + +/obj/vehicle/sealed/armored/mob_try_enter(mob/entering_mob, mob/user, loc_override = FALSE) + if(isobserver(entering_mob)) + interior?.mob_enter(entering_mob) + return FALSE + if(!ishuman(entering_mob)) + return FALSE + if(entering_mob.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + return FALSE + if(!loc_override && !(entering_mob.loc in enter_locations(entering_mob))) + balloon_alert(entering_mob, "not at entrance") + return FALSE + return ..() + +/obj/vehicle/sealed/armored/enter_checks(mob/entering_mob, loc_override = FALSE) + . = ..() + if(!.) + return + if(LAZYLEN(entering_mob.buckled_mobs)) + balloon_alert(entering_mob, "remove riders first") + return FALSE + +/obj/vehicle/sealed/armored/add_occupant(mob/M, control_flags) + if(!interior) + RegisterSignal(M, COMSIG_MOB_DEATH, PROC_REF(mob_exit), TRUE) + RegisterSignal(M, COMSIG_LIVING_DO_RESIST, TYPE_PROC_REF(/atom/movable, resisted_against), TRUE) + . = ..() + if(primary_weapon) + var/list/primary_icons + if(primary_weapon.ammo) + primary_icons = list(primary_weapon.ammo.default_ammo.hud_state, primary_weapon.ammo.default_ammo.hud_state_empty) + else + primary_icons = list(primary_weapon.hud_state_empty, primary_weapon.hud_state_empty) + M?.hud_used?.add_ammo_hud(primary_weapon, primary_icons, primary_weapon?.ammo?.current_rounds) + if(secondary_weapon) + var/list/secondary_icons + if(secondary_weapon.ammo) + secondary_icons = list(secondary_weapon.ammo.default_ammo.hud_state, secondary_weapon.ammo.default_ammo.hud_state_empty) + else + secondary_icons = list(secondary_weapon.hud_state_empty, secondary_weapon.hud_state_empty) + M?.hud_used?.add_ammo_hud(secondary_weapon, secondary_icons, secondary_weapon?.ammo?.current_rounds) + +/obj/vehicle/sealed/armored/after_add_occupant(mob/M) + . = ..() + if(interior) + REMOVE_TRAIT(M, TRAIT_HANDS_BLOCKED, VEHICLE_TRAIT) + +/obj/vehicle/sealed/armored/grant_controller_actions_by_flag(mob/M, flag) + . = ..() + if(. && (flag & VEHICLE_CONTROL_EQUIPMENT)) + RegisterSignal(M, COMSIG_MOB_MOUSEDOWN, PROC_REF(on_mouseclick), TRUE) + +/obj/vehicle/sealed/armored/remove_controller_actions_by_flag(mob/M, flag) + . = ..() + if(. && (flag & VEHICLE_CONTROL_EQUIPMENT)) + UnregisterSignal(M, COMSIG_MOB_MOUSEDOWN) + +/obj/vehicle/sealed/armored/remove_occupant(mob/M) + M?.hud_used?.remove_ammo_hud(primary_weapon) + M?.hud_used?.remove_ammo_hud(secondary_weapon) + UnregisterSignal(M, COMSIG_MOB_DEATH) + UnregisterSignal(M, COMSIG_LIVING_DO_RESIST) + return ..() + +/obj/vehicle/sealed/armored/relaymove(mob/living/user, direction) + . = ..() + if(!is_driver(user) && is_equipment_controller(user)) + swivel_turret(null, direction) + +/obj/vehicle/sealed/armored/projectile_hit(obj/projectile/proj, cardinal_move, uncrossing) + for(var/mob/living/carbon/human/crew AS in occupants) + if(crew.wear_id?.iff_signal & proj.iff_signal) + return FALSE + return ..() + +/obj/vehicle/sealed/armored/attack_hand(mob/living/user) + . = ..() + if(interior?.breech) // handled by gun breech + return + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + balloon_alert(user, "not enough skill") + return + if(!primary_weapon) + balloon_alert(user, "no primary") + return + if(!length(primary_weapon.ammo_magazine)) + balloon_alert(user, "magazine empty") + return + var/choice + if(length(primary_weapon.ammo_magazine) == 1) + choice = primary_weapon.ammo_magazine[1] + else + choice = tgui_input_list(user, "Select a magazine to take out", primary_weapon.name, primary_weapon.ammo_magazine) + if(!choice) + return + if(!do_after(user, 1 SECONDS, NONE, src)) + return + balloon_alert(user, "magazine removed") + primary_weapon.ammo_magazine -= choice + user.put_in_hands(choice) + +/obj/vehicle/sealed/armored/attack_hand_alternate(mob/living/user) + . = ..() + if(interior?.secondary_breech) // handled by gun breech + return + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + balloon_alert(user, "not enough skill") + return + if(!secondary_weapon) + balloon_alert(user, "no secondary") + return + if(!length(secondary_weapon.ammo_magazine)) + balloon_alert(user, "magazine empty") + return + var/choice + if(length(secondary_weapon.ammo_magazine) == 1) + choice = secondary_weapon.ammo_magazine[1] + else + choice = tgui_input_list(user, "Select a magazine to take out", secondary_weapon.name, secondary_weapon.ammo_magazine) + if(!choice) + return + if(!do_after(user, 1 SECONDS, NONE, src)) + return + balloon_alert(user, "magazine removed") + secondary_weapon.ammo_magazine -= choice + user.put_in_hands(choice) + +/obj/vehicle/sealed/armored/attackby(obj/item/I, mob/user, params) + . = ..() + if(istype(I, /obj/item/armored_weapon)) + var/obj/item/armored_weapon/gun = I + if(!(gun.type in permitted_weapons)) + balloon_alert(user, "cannot attach") + return + if(!(gun.weapon_slot & MODULE_PRIMARY)) + balloon_alert(user, "not a primary weapon") + return + if(!do_after(user, 2 SECONDS, NONE, src)) + return + user.temporarilyRemoveItemFromInventory(I) + gun.attach(src, TRUE) + return + if(istype(I, /obj/item/tank_module)) + if(!(I.type in permitted_mods)) + balloon_alert(user, "cannot attach") + return + var/obj/item/tank_module/mod = I + mod.on_equip(src, user) + return + if(!istype(I, /obj/item/ammo_magazine)) + try_easy_load(I, user) + return + var/obj/item/armored_weapon/weapon_to_load + if(!interior?.breech && primary_weapon && (I.type in primary_weapon.accepted_ammo)) + weapon_to_load = primary_weapon + else if(!interior?.secondary_breech && secondary_weapon && (I.type in secondary_weapon.accepted_ammo)) + weapon_to_load = secondary_weapon + else + try_easy_load(I, user) + return + if(length(primary_weapon.ammo_magazine) >= primary_weapon.maximum_magazines) + balloon_alert(user, "magazine already full") + return + user.temporarilyRemoveItemFromInventory(I) + I.forceMove(weapon_to_load) + if(!weapon_to_load.ammo) + weapon_to_load.ammo = I + balloon_alert(user, "primary gun loaded") + for(var/mob/occupant AS in occupants) + occupant?.hud_used?.update_ammo_hud(weapon_to_load, list(weapon_to_load.ammo.default_ammo.hud_state, weapon_to_load.ammo.default_ammo.hud_state_empty), weapon_to_load.ammo.current_rounds) + else + weapon_to_load.ammo_magazine += I + balloon_alert(user, "magazines [length(weapon_to_load.ammo_magazine)]/[weapon_to_load.maximum_magazines]") + +/obj/vehicle/sealed/armored/MouseDrop_T(atom/movable/dropping, mob/M) + // Bypass to parent to handle mobs entering the vehicle. + if(dropping == M) + return ..() + if(!isliving(M)) + return + try_easy_load(dropping, M) + +/obj/vehicle/sealed/armored/grab_interact(obj/item/grab/grab, mob/user, base_damage, is_sharp) + try_easy_load(grab.grabbed_thing, user) + +/obj/vehicle/sealed/armored/attackby_alternate(obj/item/I, mob/user, params) + . = ..() + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + balloon_alert(user, "not enough skill") + return + if(istype(I, /obj/item/armored_weapon)) + var/obj/item/armored_weapon/gun = I + if(!(gun.type in permitted_weapons)) + balloon_alert(user, "cannot attach") + return + if(!(gun.weapon_slot & MODULE_SECONDARY)) + balloon_alert(user, "not a secondary weapon") + return + if(!do_after(user, 2 SECONDS, NONE, src)) + return + user.temporarilyRemoveItemFromInventory(I) + gun.attach(src, FALSE) + return + if(isscrewdriver(I)) + if(!gunner_utility_module) + balloon_alert(user, "no gunner utility module") + return + balloon_alert(user, "detaching gunner utility") + if(!do_after(user, 2 SECONDS, NONE, src)) + return + gunner_utility_module.on_unequip(user) + balloon_alert(user, "detached") + return + if(interior?.secondary_breech) // if interior handle by gun breech + return + if(istype(I, /obj/item/ammo_magazine)) + if(!secondary_weapon) + balloon_alert(user, "no primary weapon") + return + if(!(I.type in secondary_weapon.accepted_ammo)) + balloon_alert(user, "not accepted ammo") + return + if(length(secondary_weapon.ammo_magazine) >= secondary_weapon.maximum_magazines) + balloon_alert(user, "magazine already full") + return + user.temporarilyRemoveItemFromInventory(I) + I.forceMove(secondary_weapon) + if(!secondary_weapon.ammo) + secondary_weapon.ammo = I + balloon_alert(user, "secondary gun loaded") + for(var/mob/occupant AS in occupants) + occupant?.hud_used?.update_ammo_hud(secondary_weapon, list(secondary_weapon.ammo.default_ammo.hud_state, secondary_weapon.ammo.default_ammo.hud_state_empty), secondary_weapon.ammo.current_rounds) + else + secondary_weapon.ammo_magazine += I + balloon_alert(user, "magazines [length(secondary_weapon.ammo_magazine)]/[secondary_weapon.maximum_magazines]") + + +/obj/vehicle/sealed/armored/welder_act(mob/living/user, obj/item/I) + return welder_repair_act(user, I, 50, 5 SECONDS, 0, SKILL_ENGINEER_METAL, 5, 2 SECONDS) + +/obj/vehicle/sealed/armored/crowbar_act(mob/living/user, obj/item/I) + . = ..() + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + balloon_alert(user, "not enough skill") + return + if(!primary_weapon) + balloon_alert(user, "no primary weapon") + return + balloon_alert(user, "detaching primary") + if(!do_after(user, 2 SECONDS, NONE, src)) + return + var/obj/item/armored_weapon/gun = primary_weapon + primary_weapon.detach(loc) + user.put_in_hands(gun) + balloon_alert(user, "detached") + +/obj/vehicle/sealed/armored/wrench_act(mob/living/user, obj/item/I) + . = ..() + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + balloon_alert(user, "not enough skill") + return + if(!secondary_weapon) + balloon_alert(user, "no secondary weapon") + return + balloon_alert(user, "detaching secondary") + if(!do_after(user, 2 SECONDS, NONE, src)) + return + var/obj/item/armored_weapon/gun = secondary_weapon + secondary_weapon.detach(loc) + user.put_in_hands(gun) + balloon_alert(user, "detached") + +/obj/vehicle/sealed/armored/screwdriver_act(mob/living/user, obj/item/I) + . = ..() + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < required_entry_skill) + balloon_alert(user, "not enough skill") + return + if(!driver_utility_module) + balloon_alert(user, "no driver utility module") + return + balloon_alert(user, "detaching driver utility") + if(!do_after(user, 2 SECONDS, NONE, src)) + return + driver_utility_module.on_unequip(user) + balloon_alert(user, "detached") + +/obj/vehicle/sealed/armored/plastique_act(mob/living/plastique_user) + ex_act(EXPLODE_LIGHT) + +/** + * Toggles Weapons Safety + * + * Handles enabling or disabling the safety function. + */ +/obj/vehicle/sealed/armored/proc/set_safety(mob/user) + weapons_safety = !weapons_safety + SEND_SOUND(user, sound('sound/machines/beep.ogg', volume = 25)) + balloon_alert(user, "equipment [weapons_safety ? "safe" : "ready"]") + // todo maybe make tanks also update the mouse icon? + +///Rotates the cannon overlay +/obj/vehicle/sealed/armored/proc/swivel_turret(atom/A, new_weapon_dir) + if(!new_weapon_dir) + new_weapon_dir = angle_to_cardinal_dir(Get_Angle(get_turf(src), get_turf(A))) + if(turret_overlay.dir == new_weapon_dir) + return FALSE + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_TANK_SWIVEL)) //Slight cooldown to avoid spam + return FALSE + playsound(src, 'sound/effects/tankswivel.ogg', 80,1) + TIMER_COOLDOWN_START(src, COOLDOWN_TANK_SWIVEL, 3 SECONDS) + turret_overlay.setDir(new_weapon_dir) + return TRUE + +///handles mouseclicks by a user in the vehicle +/obj/vehicle/sealed/armored/proc/on_mouseclick(mob/user, atom/target, turf/location, control, list/modifiers) + SIGNAL_HANDLER + modifiers = params2list(modifiers) + if(isnull(location) && target.plane == CLICKCATCHER_PLANE) //Checks if the intended target is in deep darkness and adjusts target based on params. + target = params2turf(modifiers["screen-loc"], get_turf(user), user.client) + modifiers["icon-x"] = num2text(ABS_PIXEL_TO_REL(text2num(modifiers["icon-x"]))) + modifiers["icon-y"] = num2text(ABS_PIXEL_TO_REL(text2num(modifiers["icon-y"]))) + if(modifiers[SHIFT_CLICK]) //Allows things to be examined. + return + if(!isturf(target) && !isturf(target.loc)) // Prevents inventory from being drilled + return + if(HAS_TRAIT(user, TRAIT_INCAPACITATED)) + return + if(src == target) + return + if(!is_equipment_controller(user)) + balloon_alert(user, "wrong seat for equipment!") + return COMSIG_MOB_CLICK_CANCELED + if(LAZYACCESS(modifiers, MIDDLE_CLICK)) + set_safety(user) + return COMSIG_MOB_CLICK_CANCELED + var/dir_to_target = get_cardinal_dir(src, target) + var/obj/item/armored_weapon/selected + if(modifiers[BUTTON] == RIGHT_CLICK) + selected = secondary_weapon + else + if(!turret_overlay) + return COMSIG_MOB_CLICK_CANCELED + if(turret_overlay.dir != dir_to_target) + swivel_turret(target) + return COMSIG_MOB_CLICK_CANCELED + selected = primary_weapon + if(!selected) + return + if(weapons_safety || zoom_mode) + return + INVOKE_ASYNC(selected, TYPE_PROC_REF(/obj/item/armored_weapon, begin_fire), user, target, modifiers) + +/atom/movable/vis_obj/turret_overlay + name = "Tank gun turret" + desc = "The shooty bit on a tank." + icon = 'icons/obj/armored/3x3/tank_gun.dmi' //set by owner + icon_state = "turret" + layer = ABOVE_ALL_MOB_LAYER + ///overlay for the attached gun + var/image/gun_overlay + ///overlay for the shooting version of that gun + var/image/flash_overlay + ///currently using the flashing overlay + var/flashing = FALSE + ///icon state for the secondary + var/image/secondary_overlay + +/atom/movable/vis_obj/turret_overlay/proc/update_gun_overlay(gun_icon_state) + cut_overlays() + if(!gun_icon_state) + flash_overlay = null + gun_overlay = null + return + flashing = FALSE + flash_overlay = image(icon, gun_icon_state + "_fire", pixel_x = -70, pixel_y = -69) + gun_overlay = image(icon, gun_icon_state, pixel_x = -40, pixel_y = -48) + update_appearance(UPDATE_OVERLAYS) + +/atom/movable/vis_obj/turret_overlay/proc/set_flashing(new_flashing) + flashing = new_flashing + update_appearance(UPDATE_OVERLAYS) + +/atom/movable/vis_obj/turret_overlay/update_overlays() + . = ..() + . += (flashing ? flash_overlay : gun_overlay) + +/atom/movable/vis_obj/turret_overlay/setDir(newdir) + . = ..() + if(secondary_overlay) + cut_overlay(secondary_overlay) + secondary_overlay.icon_state = copytext(secondary_overlay.icon_state, 1, length(secondary_overlay.icon_state)) + "[dir]" + add_overlay(secondary_overlay) + +/atom/movable/vis_obj/tank_damage + name = "Tank damage overlay" + desc = "ow." + icon = 'icons/obj/armored/3x3/tank_damage.dmi' //set by owner + icon_state = "null" // set on demand + vis_flags = VIS_INHERIT_DIR diff --git a/code/modules/vehicles/armored/_multitile.dm b/code/modules/vehicles/armored/_multitile.dm new file mode 100644 index 00000000000..5ebcde5eef0 --- /dev/null +++ b/code/modules/vehicles/armored/_multitile.dm @@ -0,0 +1,38 @@ +/obj/vehicle/sealed/armored/multitile + name = "\improper MT - Banteng" + desc = "A gigantic wall of metal designed for maximum Xeno destruction. Drag yourself onto it at an entrance to get inside." + icon = 'icons/obj/armored/3x3/tank.dmi' + turret_icon = 'icons/obj/armored/3x3/tank_gun.dmi' + damage_icon_path = 'icons/obj/armored/3x3/tank_damage.dmi' + icon_state = "tank" + hitbox = /obj/hitbox + interior = /datum/interior/armored + minimap_icon_state = "tank" + required_entry_skill = SKILL_LARGE_VEHICLE_TRAINED + flags_atom = DIRLOCK|BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION|CRITICAL_ATOM + flags_armored = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_SECONDARY_WEAPON|ARMORED_HAS_UNDERLAY|ARMORED_HAS_HEADLIGHTS|ARMORED_PURCHASABLE_ASSAULT + pixel_x = -56 + pixel_y = -48 + max_integrity = 900 + soft_armor = list(MELEE = 50, BULLET = 100 , LASER = 90, ENERGY = 60, BOMB = 60, BIO = 60, FIRE = 50, ACID = 50) + hard_armor = list(MELEE = 0, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0) + permitted_mods = list(/obj/item/tank_module/overdrive, /obj/item/tank_module/ability/zoom) + max_occupants = 4 + move_delay = 0.75 SECONDS + glide_size = 2.5 + ram_damage = 100 + easy_load_list = list( + /obj/item/ammo_magazine/tank, + ) + +/obj/vehicle/sealed/armored/multitile/enter_locations(atom/movable/entering_thing) + return list(get_step_away(get_step(src, REVERSE_DIR(dir)), src, 2)) + +/obj/vehicle/sealed/armored/multitile/exit_location(mob/M) + return pick(enter_locations(M)) + +/obj/vehicle/sealed/armored/multitile/enter_checks(mob/entering_mob, loc_override = FALSE) + . = ..() + if(!.) + return + return (loc_override || (entering_mob.loc in enter_locations(entering_mob))) diff --git a/code/modules/vehicles/armored/ammo_magazine.dm b/code/modules/vehicles/armored/ammo_magazine.dm new file mode 100644 index 00000000000..155d64ff70d --- /dev/null +++ b/code/modules/vehicles/armored/ammo_magazine.dm @@ -0,0 +1,83 @@ +//FEB 2024 NOTE: some of these are missing loading_sounds, fix it before using these ingame +//Special ammo magazines for hardpoint modules. Some may not be here since you can use normal magazines on them +/obj/item/ammo_magazine/tank + flags_magazine = NONE + ///loading sound to play when + var/loading_sound + +/obj/item/ammo_magazine/tank/ltb_cannon + name = "high explosive LTB round" + desc = "A primary armament cannon magazine" + caliber = CALIBER_84MM + icon_state = "ltbammo" + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/rocket/ltb + max_rounds = 1 + loading_sound = 'sound/vehicles/weapons/ltb_reload.ogg' + +/obj/item/ammo_magazine/tank/ltaap_chaingun + name = "\improper LTA-AP chaingun Magazine" + desc = "A primary armament chaingun magazine." + caliber = CALIBER_762X51 + icon_state = "ltaap" + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/bullet/minigun/ltaap + max_rounds = 150 + loading_sound = 'sound/weapons/guns/interact/working_the_bolt.ogg' + +/obj/item/ammo_magazine/tank/flamer + name = "Flamer Magazine" + desc = "A secondary armament flamethrower magazine" + caliber = CALIBER_FUEL_THICK + icon_state = "flametank_large" + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/flamethrower/tank_flamer + max_rounds = 120 + +/obj/item/ammo_magazine/tank/towlauncher + name = "TOW Launcher Magazine" + desc = "A secondary armament rocket magazine" + caliber = CALIBER_68MM + icon_state = "quad_rocket" + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/rocket/ap //Fun fact, AP rockets seem to be a straight downgrade from normal rockets. Maybe I'm missing something... + max_rounds = 5 + +/obj/item/ammo_magazine/tank/secondary_cupola + name = "M56 Cupola Magazine" + desc = "A secondary armament MG magazine" + caliber = CALIBER_10X28 + icon_state = "cupolaammo" + loading_sound = 'sound/weapons/guns/interact/working_the_bolt.ogg' + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/bullet/cupola + max_rounds = 75 + +/obj/item/ammo_magazine/tank/tank_glauncher + name = "Grenade Launcher Magazine" + desc = "A secondary armament grenade magazine" + caliber = CALIBER_40MM + icon_state = "glauncher_2" + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/grenade_container + max_rounds = 10 + +/obj/item/ammo_magazine/tank/tank_glauncher/update_icon_state() + if(current_rounds >= max_rounds) + icon_state = "glauncher_2" + else if(current_rounds <= 0) + icon_state = "glauncher_0" + else + icon_state = "glauncher_1" + +/obj/item/ammo_magazine/tank/tank_slauncher + name = "Smoke Launcher Magazine" + desc = "A support armament grenade magazine" + caliber = CALIBER_40MM + icon_state = "slauncher_1" + w_class = WEIGHT_CLASS_GIGANTIC + default_ammo = /datum/ammo/grenade_container/smoke + max_rounds = 6 + +/obj/item/ammo_magazine/tank/tank_slauncher/update_icon_state() + icon_state = "slauncher_[current_rounds <= 0 ? "0" : "1"]" diff --git a/code/modules/vehicles/armored/apc.dm b/code/modules/vehicles/armored/apc.dm new file mode 100644 index 00000000000..7a1a5905428 --- /dev/null +++ b/code/modules/vehicles/armored/apc.dm @@ -0,0 +1,25 @@ +/obj/vehicle/sealed/armored/multitile/apc + name = "\improper APC - Athena" + desc = "An unarmed command APC designed to command and transport troops in the battlefield." + icon = 'icons/obj/armored/3x3/apc.dmi' + icon_state = "apc" + damage_icon_path = 'icons/obj/armored/3x3/apc_damage_overlay.dmi' + interior = /datum/interior/armored/transport + flags_armored = ARMORED_HAS_HEADLIGHTS|ARMORED_PURCHASABLE_TRANSPORT + permitted_weapons = list(/obj/item/armored_weapon/secondary_weapon) + permitted_mods = list(/obj/item/tank_module/overdrive, /obj/item/tank_module/ability/zoom, /obj/item/tank_module/interior/medical, /obj/item/tank_module/interior/clone_bay) + required_entry_skill = SKILL_LARGE_VEHICLE_DEFAULT + minimap_icon_state = "apc" + turret_icon = null + pixel_x = -48 + pixel_y = -40 + max_integrity = 600 + soft_armor = list(MELEE = 40, BULLET = 100 , LASER = 90, ENERGY = 60, BOMB = 60, BIO = 60, FIRE = 40, ACID = 40) + max_occupants = 20 //Clown car? Clown car. + ram_damage = 25 + move_delay = 0.5 SECONDS + easy_load_list = list( + /obj/item/ammo_magazine/tank, + /obj/structure/largecrate, + /obj/structure/closet/crate, + ) diff --git a/code/modules/vehicles/armored/armored_actions.dm b/code/modules/vehicles/armored/armored_actions.dm new file mode 100644 index 00000000000..3976a6f9064 --- /dev/null +++ b/code/modules/vehicles/armored/armored_actions.dm @@ -0,0 +1,152 @@ +/obj/vehicle/sealed/armored/generate_action_type() + . = ..() + if(istype(., /datum/action/vehicle/sealed/armored)) + var/datum/action/vehicle/sealed/armored/armor = . + armor.chassis = src + +///yes this is a blatant mech copypaste +/datum/action/vehicle/sealed/armored + action_icon = 'icons/mob/actions/actions_mecha.dmi' + ///mech owner of this action + var/obj/vehicle/sealed/armored/chassis + +/datum/action/vehicle/sealed/armored/Destroy() + chassis = null + return ..() + +/datum/action/vehicle/sealed/armored/eject + name = "Eject From Mech" + action_icon_state = "mech_eject" + +/datum/action/vehicle/sealed/armored/eject/action_activate(trigger_flags) + if(!owner) + return + if(!chassis || !(owner in chassis.occupants)) + return + chassis.resisted_against(owner) + +/datum/action/vehicle/sealed/armored/swap_seat + name = "Switch Seats" + action_icon_state = "mech_seat_swap" + +#define ARMOR_DRIVER "Driver" +#define ARMOR_GUNNER "Gunner" +#define ARMOR_PASSENGER "Passenger" + +/datum/action/vehicle/sealed/armored/swap_seat/action_activate(trigger_flags) + if(!transfer_checks()) + return + var/list/choices = list() + if(!chassis.is_driver(owner)) + choices += ARMOR_DRIVER + if(!chassis.is_equipment_controller(owner)) + choices += ARMOR_GUNNER + choices += ARMOR_PASSENGER + var/choice = tgui_input_list(owner, "Select a seat", chassis.name, choices) + if(!choice) + return + if(!transfer_checks(choice)) + return + chassis.balloon_alert(owner, "moving to other seat...") + if(!do_after(owner, chassis.enter_delay, target = chassis, extra_checks=CALLBACK(src, PROC_REF(transfer_checks), choice))) + chassis.balloon_alert(owner, "interrupted!") + return + chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT|VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + switch(choice) + if(ARMOR_GUNNER) + chassis.balloon_alert(owner, "controlling gunner seat") + chassis.add_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + if(ARMOR_DRIVER) + chassis.balloon_alert(owner, "controlling pilot seat") + chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + if(ARMOR_PASSENGER) + chassis.balloon_alert(owner, "entered passenger seat") + +///checks if owner can still transfer +/datum/action/vehicle/sealed/armored/swap_seat/proc/transfer_checks(choice) + if(!owner || !chassis || !(owner in chassis.occupants)) + return FALSE + if(length(chassis.occupants) >= chassis.max_occupants) + chassis.balloon_alert(owner, "other seats occupied!") + return FALSE + switch(choice) + if(ARMOR_GUNNER) + if(length(chassis.return_controllers_with_flag(VEHICLE_CONTROL_EQUIPMENT)) >= 1) + chassis.balloon_alert(owner, "gunner occupied!") + return FALSE + if(ARMOR_DRIVER) + if(chassis.driver_amount() >= chassis.max_drivers) + chassis.balloon_alert(owner, "driver occupied!") + return FALSE + return TRUE + +#undef ARMOR_DRIVER +#undef ARMOR_GUNNER +#undef ARMOR_PASSENGER + +/datum/action/vehicle/sealed/armored/toggle_lights + name = "Toggle Lights" + action_icon_state = "mech_lights_off" + +/datum/action/vehicle/sealed/armored/toggle_lights/action_activate(trigger_flags) + if(!owner || !chassis || !(owner in chassis.occupants)) + return + + if(!(chassis.flags_armored & ARMORED_HAS_HEADLIGHTS)) + chassis.balloon_alert(owner, "the vehicle's lights are broken!") + return + chassis.flags_armored ^= ARMORED_LIGHTS_ON + if(chassis.flags_armored & ARMORED_LIGHTS_ON) + action_icon_state = "mech_lights_on" + else + action_icon_state = "mech_lights_off" + chassis.set_light_on(chassis.flags_armored & ARMORED_LIGHTS_ON) + chassis.balloon_alert(owner, "toggled lights [chassis.flags_armored & ARMORED_LIGHTS_ON ? "on":"off"]") + playsound(chassis,'sound/mecha/brass_skewer.ogg', 40, TRUE) + chassis.log_message("Toggled lights [(chassis.flags_armored & ARMORED_LIGHTS_ON)?"on":"off"].", LOG_MECHA) + update_button_icon() + +/datum/action/vehicle/sealed/armored/zoom + name = "Zoom" + action_icon_state = "mech_zoom_off" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_MECHABILITY_TOGGLE_ZOOM, + ) + +/datum/action/vehicle/sealed/armored/zoom/action_activate(trigger_flags) + if(!owner?.client || !chassis || !(owner in chassis.occupants)) + return + chassis.zoom_mode = !chassis.zoom_mode + action_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]" + chassis.log_message("Toggled zoom mode.", LOG_MECHA) + to_chat(owner, "Zoom mode [chassis.zoom_mode?"en":"dis"]abled.") + if(chassis.zoom_mode) + owner.client.view_size.set_view_radius_to(4.5) + SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg', volume=50)) + else + owner.client.view_size.reset_to_default() + update_button_icon() + +/datum/action/vehicle/sealed/armored/zoom/remove_action(mob/M) + if(chassis.zoom_mode) + M.client.view_size.reset_to_default() + chassis.zoom_mode = FALSE + return ..() + +/datum/action/vehicle/sealed/armored/horn + name = "Honk Horn" + action_icon = 'icons/mob/actions/actions_vehicle.dmi' + action_icon_state = "car_horn" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_KB_VEHICLEHONK, + ) + +/datum/action/vehicle/sealed/armored/horn/action_activate(trigger_flags) + if(!owner?.client || !chassis || !(owner in chassis.occupants)) + return + if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_ARMORED_HORN)) + return + + chassis.visible_message("[chassis] honks its horn!") + playsound(chassis, 'sound/vehicles/horns/armored_horn.ogg', 70) + TIMER_COOLDOWN_START(chassis, COOLDOWN_ARMORED_HORN, 15 SECONDS) //To keep people's eardrums intact diff --git a/code/modules/vehicles/armored/armored_modules.dm b/code/modules/vehicles/armored/armored_modules.dm new file mode 100644 index 00000000000..c22429de8d7 --- /dev/null +++ b/code/modules/vehicles/armored/armored_modules.dm @@ -0,0 +1,182 @@ +/** + *TANK MODULES + * + * Attached to the tank and provide abilities/ passive upgrades + */ +/obj/item/tank_module + name = "Tank Module" + desc = "Yell at the admin that spawned this in please." + icon = 'icons/obj/armored/hardpoint_modules.dmi' + icon_state = "ltb_cannon" + ///reference to current overlay added to owner + var/image/overlay + ///vehicle this overlay is attached to + var/obj/vehicle/sealed/armored/owner + ///Bool whether this module is a driver module or not + var/is_driver_module = TRUE + ///Bool whether this module is visually attached to the hull or not + var/attached_to_hull = FALSE + +///Called to apply modules to a vehicle +/obj/item/tank_module/proc/on_equip(obj/vehicle/sealed/armored/vehicle, mob/living/user) + SHOULD_CALL_PARENT(TRUE) + if(!istype(vehicle)) + return FALSE + var/slot = is_driver_module ? vehicle.driver_utility_module : vehicle.gunner_utility_module + if(slot) + user?.balloon_alert(user, "module slot full") + return FALSE + user?.temporarilyRemoveItemFromInventory(src) + forceMove(vehicle) + if(is_driver_module) + vehicle.driver_utility_module = src + else + vehicle.gunner_utility_module = src + if(!vehicle.turret_overlay || attached_to_hull) + overlay = image(vehicle.icon, null, icon_state) + vehicle.add_overlay(overlay) + else + overlay = image(vehicle.turret_overlay.icon, null, icon_state) + vehicle.turret_overlay.add_overlay(overlay) + owner = vehicle + return TRUE + +///called to remove this module from its vehicle +/obj/item/tank_module/proc/on_unequip(mob/user) + SHOULD_CALL_PARENT(TRUE) + if(owner.driver_utility_module == src) + owner.driver_utility_module = null + else + owner.gunner_utility_module = null + forceMove(owner.drop_location()) + owner.cut_overlay(overlay) + owner.turret_overlay?.cut_overlay(overlay) + owner = null + overlay = null + user?.put_in_hands(src) + return TRUE + +/obj/item/tank_module/Destroy() + if(owner) + on_unequip() + return ..() + +/obj/item/tank_module/overdrive + name = "overdrive module" + desc = "A module that enhances the speed of armored combat vehicles by increasing fuel efficiency." + icon_state = "overdrive" + attached_to_hull = TRUE + +/obj/item/tank_module/overdrive/on_equip(obj/vehicle/sealed/armored/vehicle, mob/living/user) + . = ..() + if(!.) + return + vehicle.move_delay -= 0.15 SECONDS + +/obj/item/tank_module/overdrive/on_unequip() + owner.move_delay += 0.15 SECONDS + return ..() + +/obj/item/tank_module/passenger + name = "passenger module" + desc = "A module that increases the carrying capacity of a vehicle with extra seats." + icon_state = "uninstalled APC frieght carriage" + +/obj/item/tank_module/passenger/on_equip(obj/vehicle/sealed/armored/vehicle, mob/living/user) + . = ..() + if(!.) + return + vehicle.max_occupants += 4 + +/obj/item/tank_module/passenger/on_unequip(obj/vehicle/sealed/armored/vehicle, mob/living/user) + owner.max_occupants -= 4 + return ..() + +/obj/item/tank_module/ability + name = "Ability Module" + desc = "You shouldnt be seeing this." + icon_state = "overdrive" + ///typepaths for the ability we want to grant + var/ability_to_grant + ///if given, a single flag of who we want this ability to be granted to + var/flag_controller = NONE + +/obj/item/tank_module/ability/on_equip(obj/vehicle/sealed/armored/vehicle, attach_right) + . = ..() + if(!.) + return + if(flag_controller) + vehicle.initialize_controller_action_type(ability_to_grant, flag_controller) + else + vehicle.initialize_passenger_action_type(ability_to_grant) + +/obj/item/tank_module/ability/on_unequip(atom/moveto) + if(flag_controller) + owner.destroy_controller_action_type(ability_to_grant, flag_controller) + else + owner.destroy_passenger_action_type(ability_to_grant) + return ..() + +/obj/item/tank_module/ability/zoom + name = "zoom module" + desc = "Allows gunners to see further while looking through it. Weapons cannot be used while looking through it." + icon_state = "zoom" + is_driver_module = FALSE + flag_controller = VEHICLE_CONTROL_EQUIPMENT + ability_to_grant = /datum/action/vehicle/sealed/armored/zoom + +/obj/item/tank_module/interior + name = "generic interior module" + desc = "you shouldnt see this" + is_driver_module = TRUE + ///max occupants to set when adding this module + var/set_max_occupants + /// typepath we want to be using for interiors + var/interior_typepath + +/obj/item/tank_module/interior/Initialize(mapload) + . = ..() +#ifdef UNIT_TESTS + if(!interior_typepath && (type != /obj/item/tank_module/interior)) + CRASH("Error: [type] has no interior_typepath") +#endif + +/obj/item/tank_module/interior/on_equip(obj/vehicle/sealed/armored/vehicle, mob/living/user) + . = ..() + if(!.) + return + if(LAZYLEN(vehicle.occupants)) + if(user) + balloon_alert(user, "occupants still inside") + return FALSE + QDEL_NULL(vehicle.interior) + vehicle.interior = new interior_typepath(vehicle, CALLBACK(vehicle, TYPE_PROC_REF(/obj/vehicle/sealed/armored, interior_exit))) + if(set_max_occupants) + owner.max_occupants = set_max_occupants + +/obj/item/tank_module/interior/on_unequip(mob/user) + if(LAZYLEN(owner.occupants)) + if(user) + balloon_alert(user, "occupants still inside") + return FALSE + QDEL_NULL(owner.interior) + var/init_type = initial(owner.interior) + if(init_type) + owner.interior = new init_type(owner, CALLBACK(owner, TYPE_PROC_REF(/obj/vehicle/sealed/armored, interior_exit))) + if(set_max_occupants) + owner.max_occupants = initial(owner.max_occupants) + return ..() + +/obj/item/tank_module/interior/medical + name = "medical interior" + desc = "A medical interior package, stocked with a operating table and a medical vendor." + icon_state = "medical_interior" + interior_typepath = /datum/interior/armored/medical + set_max_occupants = 12 + +/obj/item/tank_module/interior/clone_bay + name = "clone bay interior" + desc = "A clone interior package, designed for the rapid production of cheap clone soldiers." + icon_state = "cloner_interior" + interior_typepath = /datum/interior/armored/clone_bay + set_max_occupants = 12 diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm new file mode 100644 index 00000000000..76cf047e558 --- /dev/null +++ b/code/modules/vehicles/armored/armored_weapons.dm @@ -0,0 +1,338 @@ +/obj/item/armored_weapon + name = "\improper LTB main battle tank cannon" + desc = "A TGMC vehicle's main turret cannon. It fires 86mm rocket propelled shells" + icon = 'icons/obj/armored/hardpoint_modules.dmi' + icon_state = "ltb_cannon" + ///owner this is attached to + var/obj/vehicle/sealed/armored/chassis + ///Weapon slot this weapon fits in + var/weapon_slot = MODULE_PRIMARY + + ///currently loaded ammo. initial value is ammo we start with + var/obj/item/ammo_magazine/ammo = /obj/item/ammo_magazine/tank/ltb_cannon + ///Current loaded magazines: top one empties into ammo + var/list/obj/item/ammo_magazine/ammo_magazine = list() + ///maximum magazines ammo_magazine can hold + var/maximum_magazines = 5 + ///ammo types we'll be able to accept + var/list/accepted_ammo = list( + /obj/item/ammo_magazine/tank/tank_glauncher, + /obj/item/ammo_magazine/tank/ltb_cannon, + ) + ///current tracked target for fire(), updated when user drags + var/atom/current_target + ///current mob firing this weapon. used for tracking for iff and etc in fire() + var/mob/current_firer + + ///sound file to play when this weapon you know, fires + var/fire_sound = list('sound/weapons/guns/fire/tank_cannon1.ogg', 'sound/weapons/guns/fire/tank_cannon2.ogg') + ///Tracks windups + var/windup_checked = WEAPON_WINDUP_NOT_CHECKED + ///windup sound played during windup + var/windup_sound + ///windup delay for this object + var/windup_delay = 0 + ///scatter of this weapon. in degrees and modified by arm this is attached to + var/variance = 0 + /// since mech guns only get one firemode this is for all types of shots + var/projectile_delay = 5 SECONDS + /// time between shots in a burst + var/projectile_burst_delay = 2 + ///bullets per burst if firemode is set to burst + var/burst_amount = 0 + ///fire mode to use for autofire + var/fire_mode = GUN_FIREMODE_SEMIAUTO + ///how many seconds automatic, and manual, reloading takes + var/rearm_time = 4 SECONDS + ///ammo hud icon to display when no ammo is loaded + var/hud_state_empty = "shell_empty" + +/obj/item/armored_weapon/Initialize(mapload) + . = ..() + if(ammo) + ammo = new ammo(src) + AddComponent(/datum/component/automatedfire/autofire, projectile_delay, projectile_delay, projectile_burst_delay, burst_amount, fire_mode, CALLBACK(src, PROC_REF(set_bursting)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(fire))) + +/obj/item/armored_weapon/Destroy() + if(chassis) + detach(get_turf(chassis)) + if(isdatum(ammo)) + QDEL_NULL(ammo) + QDEL_LIST(ammo_magazine) + return ..() + +///called by the chassis: begins firing, yes this is stolen from mech but I made both so bite me +/obj/item/armored_weapon/proc/begin_fire(mob/source, atom/target, list/modifiers) + if(!ammo || ammo.current_rounds < 0) + playsound(source, 'sound/weapons/guns/fire/empty.ogg', 15, 1) + return + if(TIMER_COOLDOWN_CHECK(chassis, COOLDOWN_MECHA_EQUIPMENT(type))) + return + TIMER_COOLDOWN_START(chassis, COOLDOWN_MECHA_EQUIPMENT(type), projectile_delay) + + set_target(get_turf_on_clickcatcher(target, source, list2params(modifiers))) + if(!current_target) + return + RegisterSignal(source, COMSIG_MOB_MOUSEUP, PROC_REF(stop_fire)) + RegisterSignal(source, COMSIG_MOB_MOUSEDRAG, PROC_REF(change_target)) + if(windup_delay && windup_checked == WEAPON_WINDUP_NOT_CHECKED) + windup_checked = WEAPON_WINDUP_CHECKING + playsound(chassis.loc, windup_sound, 30, TRUE) + if(!do_after(source, windup_delay, IGNORE_TARGET_LOC_CHANGE, chassis, BUSY_ICON_DANGER, BUSY_ICON_DANGER, extra_checks = CALLBACK(src, PROC_REF(do_after_checks), current_target))) + windup_checked = WEAPON_WINDUP_NOT_CHECKED + return + windup_checked = WEAPON_WINDUP_CHECKED + if(QDELETED(current_target)) + windup_checked = WEAPON_WINDUP_NOT_CHECKED + return + current_firer = source + if(fire_mode == GUN_FIREMODE_SEMIAUTO) + var/fire_return // todo fix: code expecting return values from async + ASYNC + fire_return = fire() + if(!fire_return || windup_checked == WEAPON_WINDUP_CHECKING) + return + reset_fire() + return + SEND_SIGNAL(src, COMSIG_ARMORED_FIRE) + source?.client?.mouse_pointer_icon = 'icons/effects/supplypod_target.dmi' + +/// do after checks for the mecha equipment do afters +/obj/item/armored_weapon/proc/do_after_checks(atom/target) + if(!chassis) + return FALSE + if(QDELETED(current_target)) + return FALSE + if(chassis.primary_weapon == src) + var/dir_target_diff = get_between_angles(Get_Angle(chassis, current_target), dir2angle(chassis.turret_overlay.dir)) + if(dir_target_diff > (ARMORED_FIRE_CONE_ALLOWED / 2)) + if(!chassis.swivel_turret(current_target)) + return FALSE + dir_target_diff = get_between_angles(Get_Angle(chassis, current_target), dir2angle(chassis.turret_overlay.dir)) + if(dir_target_diff > (ARMORED_FIRE_CONE_ALLOWED / 2)) + return FALSE + return TRUE + +///callback wrapper for adding/removing trait +/obj/item/armored_weapon/proc/set_bursting(bursting) + if(bursting) + ADD_TRAIT(src, TRAIT_GUN_BURST_FIRING, VEHICLE_TRAIT) + return + REMOVE_TRAIT(src, TRAIT_GUN_BURST_FIRING, VEHICLE_TRAIT) + +///Changes the current target. +/obj/item/armored_weapon/proc/change_target(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + SIGNAL_HANDLER + set_target(get_turf_on_clickcatcher(over_object, source, params)) + +///Sets the current target and registers for qdel to prevent hardels +/obj/item/armored_weapon/proc/set_target(atom/object) + if(object == current_target || object == chassis) + return + if(current_target) + UnregisterSignal(current_target, COMSIG_QDELETING) + current_target = object + if(current_target) + RegisterSignal(current_target, COMSIG_QDELETING, PROC_REF(clean_target)) + +///Stops the Autofire component and resets the current cursor. +/obj/item/armored_weapon/proc/stop_fire(mob/living/source, atom/object, location, control, params) + SIGNAL_HANDLER + var/list/modifiers = params2list(params) + if(!((modifiers[BUTTON] == RIGHT_CLICK) && chassis.secondary_weapon == src) && !((modifiers[BUTTON] == LEFT_CLICK) && chassis.primary_weapon == src)) + return + SEND_SIGNAL(src, COMSIG_ARMORED_STOP_FIRE) + if(!HAS_TRAIT(src, TRAIT_GUN_BURST_FIRING)) + reset_fire() + UnregisterSignal(source, list(COMSIG_MOB_MOUSEDRAG, COMSIG_MOB_MOUSEUP)) + +///Cleans the current target in case of Hardel +/obj/item/armored_weapon/proc/clean_target() + SIGNAL_HANDLER + current_target = get_turf(current_target) + +///Resets the autofire component. +/obj/item/armored_weapon/proc/reset_fire() + windup_checked = WEAPON_WINDUP_NOT_CHECKED + current_firer?.client?.mouse_pointer_icon = chassis.mouse_pointer + set_target(null) + current_firer = null + +///does any effects and changes to the projectile when it is fired +/obj/item/armored_weapon/proc/apply_weapon_modifiers(obj/projectile/projectile_to_fire, mob/firer) + projectile_to_fire.shot_from = src + projectile_to_fire.projectile_speed = projectile_to_fire.ammo.shell_speed + if(chassis.hitbox?.tank_desants) + projectile_to_fire.hit_atoms += chassis.hitbox.tank_desants + if((projectile_to_fire.ammo.flags_ammo_behavior & AMMO_IFF) && ishuman(firer)) + var/mob/living/carbon/human/human_firer = firer + var/obj/item/card/id/id = human_firer.get_idcard() + projectile_to_fire.iff_signal = id?.iff_signal + if(firer) + projectile_to_fire.def_zone = firer.zone_selected + +///actually executes firing when autofire asks for it, returns TRUE to keep firing FALSE to stop +/obj/item/armored_weapon/proc/fire() + if(chassis.primary_weapon == src) + var/dir_target_diff = get_between_angles(Get_Angle(chassis, current_target), dir2angle(chassis.turret_overlay.dir)) + if(dir_target_diff > (ARMORED_FIRE_CONE_ALLOWED / 2)) + chassis.swivel_turret(current_target) + return AUTOFIRE_CONTINUE + else if(chassis.turret_overlay) + chassis.turret_overlay.cut_overlay(chassis.turret_overlay.secondary_overlay) + chassis.turret_overlay.secondary_overlay.dir = get_cardinal_dir(chassis, current_target) + chassis.turret_overlay.add_overlay(chassis.turret_overlay.secondary_overlay) + else + chassis.cut_overlay(chassis.secondary_weapon_overlay) + chassis.secondary_weapon_overlay.dir = get_cardinal_dir(chassis, current_target) + chassis.add_overlay(chassis.secondary_weapon_overlay) + + + var/type_to_spawn = CHECK_BITFIELD(initial(ammo.default_ammo.flags_ammo_behavior), AMMO_HITSCAN) ? /obj/projectile/hitscan : /obj/projectile + var/obj/projectile/projectile_to_fire = new type_to_spawn(get_turf(src), initial(ammo.default_ammo.hitscan_effect_icon)) + projectile_to_fire.generate_bullet(GLOB.ammo_list[ammo.default_ammo]) + + apply_weapon_modifiers(projectile_to_fire, current_firer) + var/firing_angle = get_angle_with_scatter(chassis, current_target, projectile_to_fire.scatter, projectile_to_fire.p_x, projectile_to_fire.p_y) + + playsound(chassis, islist(fire_sound) ? pick(fire_sound):fire_sound, 20, TRUE) + projectile_to_fire.fire_at(current_target, chassis, null, projectile_to_fire.ammo.max_range, projectile_to_fire.projectile_speed, firing_angle, suppress_light = HAS_TRAIT(src, TRAIT_GUN_SILENCED)) + + chassis.log_message("Fired from [name], targeting [current_target] at [AREACOORD(current_target)].", LOG_ATTACK) + + if(chassis.primary_weapon == src && !chassis.turret_overlay.flashing) + chassis.turret_overlay.set_flashing(TRUE) + addtimer(CALLBACK(chassis.turret_overlay, TYPE_PROC_REF(/atom/movable/vis_obj/turret_overlay, set_flashing), FALSE), 7, TIMER_CLIENT_TIME) + chassis.interior?.breech.on_main_fire(ammo) + + ammo.current_rounds-- + for(var/mob/occupant AS in chassis.occupants) + occupant.hud_used.update_ammo_hud(src, list(ammo.default_ammo.hud_state, ammo.default_ammo.hud_state_empty), ammo.current_rounds) + if(ammo.current_rounds > 0) + return AUTOFIRE_CONTINUE|AUTOFIRE_SUCCESS + playsound(src, 'sound/weapons/guns/misc/empty_alarm.ogg', 25, 1) + eject_ammo() + if(LAZYACCESS(current_firer.do_actions, src) || length(ammo_magazine) < 1) + return AUTOFIRE_SUCCESS + var/obj/item/ammo_magazine/tank/new_mag = ammo_magazine[1] + if(istype(new_mag) && new_mag.loading_sound) + // .5 sec delay to let other sounds play out + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), src, new_mag.loading_sound, 40), 5) + if(!do_after(current_firer, rearm_time, IGNORE_HELD_ITEM|IGNORE_LOC_CHANGE, chassis, BUSY_ICON_GENERIC)) + return AUTOFIRE_SUCCESS + reload() + return AUTOFIRE_CONTINUE|AUTOFIRE_SUCCESS + +///eject current ammo from tank +/obj/item/armored_weapon/proc/eject_ammo() + for(var/mob/occupant AS in chassis.occupants) + occupant.hud_used.update_ammo_hud(src, list(hud_state_empty, hud_state_empty), 0) + ammo.update_appearance() + var/obj/item/ammo_magazine/old_ammo = ammo + ammo = null + if(chassis.interior) + if(chassis.primary_weapon == src) + chassis.interior.breech.do_eject_ammo(old_ammo) + else + chassis.interior.secondary_breech.do_eject_ammo(old_ammo) + return + old_ammo.forceMove(chassis.exit_location()) + +///load topmost ammo magazine, if there is any +/obj/item/armored_weapon/proc/reload() + if(ammo) + eject_ammo() + ammo = popleft(ammo_magazine) + for(var/mob/occupant AS in chassis.occupants) + occupant.hud_used.update_ammo_hud(src, list(ammo.default_ammo.hud_state, ammo.default_ammo.hud_state_empty), ammo.current_rounds) + +///attach this weapon to a chassis +/obj/item/armored_weapon/proc/attach(obj/vehicle/sealed/armored/tank, attach_primary) + if(attach_primary) + tank.primary_weapon?.detach(tank.exit_location()) + tank.primary_weapon = src + tank.turret_overlay.update_gun_overlay(icon_state) + else + tank.secondary_weapon?.detach(tank.exit_location()) + tank.secondary_weapon = src + if(tank.turret_overlay) + // do not remove the dir = SOUTH becuase otherwise byond flips an internal flag so the dir is inherited from the turret + tank.turret_overlay.secondary_overlay = image(tank.turret_icon, icon_state = icon_state + "_" + "[tank.turret_overlay.dir]", dir = SOUTH) + tank.turret_overlay.add_overlay(tank.turret_overlay.secondary_overlay) + else + tank.secondary_weapon_overlay = image(tank.icon, icon_state = icon_state + "_" + "[tank.dir]", dir = SOUTH) + tank.update_appearance(UPDATE_OVERLAYS) + chassis = tank + forceMove(tank) + var/icon_list + if(ammo?.default_ammo) + icon_list = list(ammo.default_ammo.hud_state, ammo.default_ammo.hud_state_empty) + else + icon_list = list(hud_state_empty, hud_state_empty) + for(var/mob/occupant AS in chassis.occupants) + occupant.hud_used.add_ammo_hud(src, icon_list, ammo ? ammo.current_rounds : 0) + +///detach this weapon to a chassis +/obj/item/armored_weapon/proc/detach(atom/moveto) + if(chassis.primary_weapon == src) + chassis.primary_weapon = null + chassis.turret_overlay.update_gun_overlay() + else + chassis.secondary_weapon = null + if(chassis.turret_overlay) + chassis.turret_overlay.cut_overlay(chassis.turret_overlay.secondary_overlay) + chassis.turret_overlay.secondary_overlay = null + else + chassis.secondary_weapon_overlay = null + chassis.update_appearance(UPDATE_OVERLAYS) + for(var/mob/occupant AS in chassis.occupants) + occupant.hud_used.remove_ammo_hud(src) + chassis = null + forceMove(moveto) + +/obj/item/armored_weapon/secondary_weapon + name = "secondary cupola minigun" + desc = "A robotically controlled minigun that spews lead." + icon_state = "cupola" + fire_sound = 'sound/weapons/guns/fire/tank_minigun_loop.ogg' + windup_delay = 5 + windup_sound = 'sound/weapons/guns/fire/tank_minigun_start.ogg' + weapon_slot = MODULE_SECONDARY + ammo = /obj/item/ammo_magazine/tank/secondary_cupola + accepted_ammo = list(/obj/item/ammo_magazine/tank/secondary_cupola) + fire_mode = GUN_FIREMODE_AUTOMATIC + projectile_delay = 2 + variance = 5 + rearm_time = 1 SECONDS + maximum_magazines = 5 + hud_state_empty = "rifle_empty" + +/obj/item/armored_weapon/ltaap + name = "\improper LTA-AP chaingun" + desc = "A hefty, large caliber chaingun" + icon_state = "ltaap_chaingun" + fire_sound = 'sound/weapons/guns/fire/tank_minigun_loop.ogg' + windup_delay = 5 + windup_sound = 'sound/weapons/guns/fire/tank_minigun_start.ogg' + weapon_slot = MODULE_PRIMARY + ammo = /obj/item/ammo_magazine/tank/ltaap_chaingun + accepted_ammo = list(/obj/item/ammo_magazine/tank/ltaap_chaingun) + fire_mode = GUN_FIREMODE_AUTOMATIC + variance = 5 + projectile_delay = 0.1 SECONDS + rearm_time = 3 SECONDS + maximum_magazines = 5 + hud_state_empty = "rifle_empty" + +/obj/item/armored_weapon/apc_cannon + name = "MKV-7 utility payload launcher" + desc = "A double barrelled cannon which can rapidly deploy utility packages to the battlefield." + icon_state = "APC uninstalled dualcannon" + fire_sound = 'sound/weapons/guns/fire/tank_smokelauncher.ogg' + ammo = /obj/item/ammo_magazine/tank/tank_slauncher + accepted_ammo = list( + /obj/item/ammo_magazine/tank/tank_slauncher, + /obj/item/ammo_magazine/tank/tank_glauncher, + ) + projectile_delay = 0.7 SECONDS + hud_state_empty = "grenade_empty" diff --git a/code/modules/vehicles/armored/interiors/ammo_rack.dm b/code/modules/vehicles/armored/interiors/ammo_rack.dm new file mode 100644 index 00000000000..ff873bf7818 --- /dev/null +++ b/code/modules/vehicles/armored/interiors/ammo_rack.dm @@ -0,0 +1,76 @@ +/obj/structure/ammo_rack + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + resistance_flags = RESIST_ALL + ///ref to the actual internal storage + var/obj/item/storage/internal/storage = /obj/item/storage/internal + +/obj/structure/ammo_rack/Initialize(mapload) + . = ..() + storage = new storage(src) + update_appearance(UPDATE_OVERLAYS) + +/obj/structure/ammo_rack/examine(mob/user) + . = ..() + . += "Right click to remove the topmost object." + +/obj/structure/ammo_rack/attack_hand(mob/living/user) + return storage.open(user) + +/obj/structure/ammo_rack/MouseDrop(obj/over_object) + if(storage.handle_mousedrop(usr, over_object)) + return ..() + +/obj/structure/ammo_rack/attackby(obj/item/I, mob/user, params) + ..() + return storage.attackby(I, user, params) + +/obj/structure/ammo_rack/attack_hand_alternate(mob/user) + ..() + return storage.attack_hand_alternate(user) + +/obj/structure/ammo_rack/update_overlays() + . = ..() + if(length(storage.contents)) + var/atom/bottommost = storage.contents[1] + var/total_w = 0 + for(var/obj/item/I AS in storage) + total_w += I.w_class + var/thirds = clamp(round(3 * (total_w / storage.max_storage_space)), 1, 3) + . += image(icon, src, bottommost.icon_state + "_" + "[thirds]") // "ltb_3"/"ltb_2"/"ltb_1" + +/obj/structure/ammo_rack/on_pocket_insertion() + update_appearance() + +/obj/structure/ammo_rack/on_pocket_removal() + update_appearance() + +/obj/structure/ammo_rack/primary + name = "primary ammo rack" + icon_state = "primaryrack" + storage = /obj/item/storage/internal/ammorack_primary + +/obj/structure/ammo_rack/primary/update_overlays() + . = ..() + . += image(icon, src, "primaryrack_overlay") + +/obj/structure/ammo_rack/secondary + name = "secondary ammo rack" + icon_state = "secondaryrack" + storage = /obj/item/storage/internal/ammorack_secondary + +/obj/item/storage/internal/ammorack_primary + max_storage_space = 120 //they're all WEIGHT_CLASS_GIGANTIC which is 6 + storage_slots = 20 + max_w_class = WEIGHT_CLASS_GIGANTIC + can_hold = list( + /obj/item/ammo_magazine/tank/ltb_cannon, + /obj/item/ammo_magazine/tank/ltaap_chaingun, + ) + +/obj/item/storage/internal/ammorack_secondary + max_storage_space = 120 + storage_slots = 20 + max_w_class = WEIGHT_CLASS_GIGANTIC + can_hold = list( + /obj/item/ammo_magazine/tank/secondary_cupola, + ) diff --git a/code/modules/vehicles/armored/interiors/breech.dm b/code/modules/vehicles/armored/interiors/breech.dm new file mode 100644 index 00000000000..56efb84abe4 --- /dev/null +++ b/code/modules/vehicles/armored/interiors/breech.dm @@ -0,0 +1,156 @@ +/obj/structure/gun_breech + name = "gun breech" + desc = "A gun breech used for loading large caliber rounds into the main gun." + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "breech" + resistance_flags = RESIST_ALL + ///bool if this laods the secondary gun + var/is_secondary = FALSE + ///owner of this object, assigned during interior linkage + var/obj/vehicle/sealed/armored/owner + +/obj/structure/gun_breech/Destroy() + owner = null + return ..() + +/obj/structure/gun_breech/link_interior(datum/interior/link) + if(!istype(link, /datum/interior/armored)) + CRASH("invalid interior [link.type] passed to [name]") + var/datum/interior/armored/inside = link + if(!is_secondary) + inside.breech = src + else + inside.secondary_breech = src + owner = inside.container + +/obj/structure/gun_breech/attack_hand(mob/living/user) + . = ..() + var/obj/item/armored_weapon/weapon = is_secondary ? owner.secondary_weapon : owner.primary_weapon + if(!weapon) + balloon_alert(user, "no weapon") + return + if(!weapon.ammo) + balloon_alert(user, "breech empty") + return + if(user.do_actions) + balloon_alert(user, "busy") + return + if(!do_after(user, 1 SECONDS, NONE, src)) + return + owner.balloon_alert(user, "breech unloaded") + user.put_in_hands(weapon.ammo) + weapon.ammo.update_appearance() + weapon.ammo = null + +/obj/structure/gun_breech/attackby(obj/item/I, mob/user, params) + . = ..() + if(!istype(I, /obj/item/ammo_magazine)) + return + var/obj/item/ammo_magazine/mag = I + var/obj/item/armored_weapon/weapon = is_secondary ? owner.secondary_weapon : owner.primary_weapon + if(!reload_checks(user)) + return + if(!(mag.type in weapon.accepted_ammo)) + balloon_alert(user, "not accepted ammo") + return + if(user.do_actions) + balloon_alert(user, "busy") + return + var/channel = SSsounds.random_available_channel() + var/sound = 'sound/weapons/guns/interact/working_the_bolt.ogg' + if(istype(mag, /obj/item/ammo_magazine/tank)) + var/obj/item/ammo_magazine/tank/t_mag = mag + sound = islist(t_mag.loading_sound)? pick(t_mag.loading_sound):t_mag.loading_sound + playsound(src, sound, 20, channel = channel) + if(!do_after(user, weapon.rearm_time, NONE, src, extra_checks=CALLBACK(src, PROC_REF(reload_checks), user))) + for(var/mob/crew AS in owner.interior.occupants) + crew.stop_sound_channel(channel) + return + user.temporarilyRemoveItemFromInventory(mag) + mag.forceMove(weapon) + weapon.ammo = mag + user.say(is_secondary ? "Loaded!" : "Up!") + for(var/mob/occupant AS in owner.interior.occupants) + occupant.hud_used.update_ammo_hud(weapon, list( + mag.default_ammo.hud_state, + mag.default_ammo.hud_state_empty), + mag.current_rounds + ) + +///checks to perform while reloading +/obj/structure/gun_breech/proc/reload_checks(mob/user) + var/obj/item/armored_weapon/weapon = is_secondary ? owner.secondary_weapon : owner.primary_weapon + if(!weapon) + balloon_alert(user, "no weapon") + return FALSE + if(weapon.ammo) + balloon_alert(user, "already loaded") + return FALSE + return TRUE + +///called every time the firing animation is refreshed, not every actual fire +/obj/structure/gun_breech/proc/on_main_fire(obj/item/ammo_magazine/owner_ammo) + if(owner_ammo.default_ammo.flags_ammo_behavior & AMMO_ENERGY) // todo add puffs of smoke that fly out + return + if(owner_ammo.max_rounds == 1) + return + //todo get an animation for bullets flying out + var/turf/eject_loc = get_step(src, WEST) + var/obj/item/ammo_casing/cartridge/pile = locate(/obj/item/ammo_casing/cartridge) in eject_loc + if(!pile) + pile = new(eject_loc) + return + pile.current_casings += 1 + pile.update_appearance() + +///when we run out of ammo; how do we eject the magazine? +/obj/structure/gun_breech/proc/do_eject_ammo(obj/item/ammo_magazine/old_ammo) + old_ammo.forceMove(get_step(src, WEST)) + if(old_ammo.max_rounds != 1) + //todo make non shell and energy ejection anim? + return + old_ammo.pixel_x = 20 + old_ammo.pixel_y = 4 + var/matrix/hit_back_transform = matrix() + var/rand_spin = rand(-90, 90) + hit_back_transform.Turn(rand_spin) + var/hit_back_x = 6 + rand(-1, 1) + var/hit_back_y = -4 + rand(-1, 1) + + var/matrix/rest_transform = matrix() + rest_transform.Turn(rand_spin + rand(-45, 45)) + var/rest_x = 3 + rand(0, 10) + var/rest_y = -17 + rand(-2, 2) + + animate(old_ammo, time=3, easing=CUBIC_EASING|EASE_OUT, transform = hit_back_transform, pixel_x = hit_back_x, pixel_y = hit_back_y) + animate(time=3, easing=CUBIC_EASING|EASE_IN, transform = rest_transform, pixel_x = rest_x, pixel_y = rest_y) + var/obj/effect/abstract/particle_holder/smoke_visuals = new(src, /particles/breech_smoke) + QDEL_IN(smoke_visuals, 0.7 SECONDS) + +/particles/breech_smoke + icon = 'icons/effects/effects.dmi' + icon_state = "smoke" + width = 300 + height = 300 + count = 20 + spawning = 20 + lifespan = 1 SECONDS + fade = 8 SECONDS + grow = 0.1 + scale = 0.2 + spin = generator(GEN_NUM, -20, 20) + velocity = list(-4, 0) + position = list(-2, 2) + gravity = list(0, 2) + friction = generator(GEN_NUM, 0.1, 0.5) + +/obj/structure/gun_breech/secondary + name = "secondary loading mechanism" + desc = "A feeding mechanism for loading ammo into the secondary weapon." + icon_state = "secondary_breech" + is_secondary = TRUE + +/obj/structure/gun_breech/secondary/do_eject_ammo(obj/item/ammo_magazine/old_ammo) + old_ammo.forceMove(get_turf(src)) + old_ammo.pixel_x = rand(-10, 10) + old_ammo.pixel_y = rand(-10, 10) diff --git a/code/modules/vehicles/armored/interiors/chairs.dm b/code/modules/vehicles/armored/interiors/chairs.dm new file mode 100644 index 00000000000..bc6fe655d4e --- /dev/null +++ b/code/modules/vehicles/armored/interiors/chairs.dm @@ -0,0 +1,121 @@ +/obj/structure/bed/chair/loader_seat + name = "loader seat" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "vehicle_chair" + resistance_flags = RESIST_ALL + dir = EAST + +/obj/structure/bed/chair/vehicle_driver_seat + name = "driver seat" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "vehicle_chair" + resistance_flags = RESIST_ALL + dir = EAST + ///owner of this object, assigned during interior linkage + var/obj/vehicle/sealed/armored/owner + +/obj/structure/bed/chair/vehicle_driver_seat/Destroy() + owner = null + return ..() + +/obj/structure/bed/chair/vehicle_driver_seat/link_interior(datum/interior/link) + if(!istype(link, /datum/interior/armored)) + CRASH("invalid interior [link.type] passed to [name]") + var/datum/interior/armored/inside = link + owner = inside.container + +/obj/structure/bed/chair/vehicle_driver_seat/buckle_mob(mob/living/buckling_mob, force, check_loc, lying_buckle, hands_needed, target_hands_needed, silent) + if(buckling_mob.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN) + return FALSE + return ..() + +/obj/structure/bed/chair/vehicle_driver_seat/post_buckle_mob(mob/buckling_mob) + . = ..() + owner.add_control_flags(buckling_mob, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + buckling_mob.reset_perspective(owner) + buckling_mob.pixel_x = pixel_x + buckling_mob.pixel_y = pixel_y + +/obj/structure/bed/chair/vehicle_driver_seat/post_unbuckle_mob(mob/buckled_mob) + . = ..() + owner.remove_control_flags(buckled_mob, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + buckled_mob.reset_perspective() + buckled_mob.pixel_x = initial(buckled_mob.pixel_x) + buckled_mob.pixel_y = initial(buckled_mob.pixel_y) + +/obj/structure/bed/chair/vehicle_driver_seat/relaymove(mob/living/user, direct) + return owner.relaymove(arglist(args)) + +/obj/structure/bed/chair/vehicle_gunner_seat + name = "gunner seat" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "vehicle_chair" + resistance_flags = RESIST_ALL + dir = EAST + ///owner of this object, assigned during interior linkage + var/obj/vehicle/sealed/armored/owner + +/obj/structure/bed/chair/vehicle_gunner_seat/link_interior(datum/interior/link) + if(!istype(link, /datum/interior/armored)) + CRASH("invalid interior [link.type] passed to [name]") + var/datum/interior/armored/inside = link + owner = inside.container + +/obj/structure/bed/chair/vehicle_gunner_seat/buckle_mob(mob/living/buckling_mob, force, check_loc, lying_buckle, hands_needed, target_hands_needed, silent) + if(buckling_mob.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN) + return FALSE + return ..() + +/obj/structure/bed/chair/vehicle_gunner_seat/post_buckle_mob(mob/buckling_mob) + . = ..() + owner.add_control_flags(buckling_mob, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + buckling_mob.reset_perspective(owner) + buckling_mob.pixel_x = pixel_x + buckling_mob.pixel_y = pixel_y + +/obj/structure/bed/chair/vehicle_gunner_seat/post_unbuckle_mob(mob/buckled_mob) + . = ..() + owner.remove_control_flags(buckled_mob, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) + buckled_mob.reset_perspective() + buckled_mob.pixel_x = initial(buckled_mob.pixel_x) + buckled_mob.pixel_y = initial(buckled_mob.pixel_y) + +/obj/structure/bed/chair/vehicle_gunner_seat/relaymove(mob/living/user, direct) + return owner.relaymove(arglist(args)) + +/obj/structure/bed/chair/driver_gunner_seat + name = "apc commander seat" + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "vehicle_chair" + resistance_flags = RESIST_ALL + dir = EAST + ///owner of this object, assigned during interior linkage + var/obj/vehicle/sealed/armored/owner + +/obj/structure/bed/chair/driver_gunner_seat/link_interior(datum/interior/link) + if(!istype(link, /datum/interior/armored)) + CRASH("invalid interior [link.type] passed to [name]") + var/datum/interior/armored/inside = link + owner = inside.container + +/obj/structure/bed/chair/driver_gunner_seat/buckle_mob(mob/living/buckling_mob, force, check_loc, lying_buckle, hands_needed, target_hands_needed, silent) + if(buckling_mob.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_EXPERIENCED) + return FALSE + return ..() + +/obj/structure/bed/chair/driver_gunner_seat/post_buckle_mob(mob/buckling_mob) + . = ..() + owner.add_control_flags(buckling_mob, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT|VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + buckling_mob.reset_perspective(owner) + buckling_mob.pixel_x = pixel_x + buckling_mob.pixel_y = pixel_y + +/obj/structure/bed/chair/driver_gunner_seat/post_unbuckle_mob(mob/buckled_mob) + . = ..() + owner.remove_control_flags(buckled_mob, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT|VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) + buckled_mob.reset_perspective() + buckled_mob.pixel_x = initial(buckled_mob.pixel_x) + buckled_mob.pixel_y = initial(buckled_mob.pixel_y) + +/obj/structure/bed/chair/driver_gunner_seat/relaymove(mob/living/user, direct) + return owner.relaymove(arglist(args)) diff --git a/code/modules/vehicles/armored/interiors/periscope.dm b/code/modules/vehicles/armored/interiors/periscope.dm new file mode 100644 index 00000000000..3af381e9ee9 --- /dev/null +++ b/code/modules/vehicles/armored/interiors/periscope.dm @@ -0,0 +1,37 @@ +/obj/structure/periscope + name = "tank periscope" + desc = "A periscope for viewing the outside of the vehicle. Resist or move to stop looking through it." + icon = 'icons/obj/armored/3x3/tank_interior.dmi' + icon_state = "periscope" + density = FALSE + resistance_flags = RESIST_ALL + ///owner of this object, assigned during interior linkage + var/obj/vehicle/sealed/armored/owner + +/obj/structure/periscope/Destroy() + owner = null + return ..() + +/obj/structure/periscope/link_interior(datum/interior/link) + owner = link.container + +/obj/structure/periscope/attack_hand(mob/living/user) + . = ..() + user.reset_perspective(owner) + ADD_TRAIT(user, TRAIT_SEE_IN_DARK, VEHICLE_TRAIT) + user.update_sight() + user.client.view_size.set_view_radius_to(4.5) + RegisterSignals(user, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DO_RESIST, COMSIG_MOB_LOGOUT), PROC_REF(stop_looking)) + +///signal handler for canceling the looking +/obj/structure/periscope/proc/stop_looking(mob/source) + SIGNAL_HANDLER + UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DO_RESIST, COMSIG_MOB_LOGOUT)) + source.reset_perspective() + REMOVE_TRAIT(source, TRAIT_SEE_IN_DARK, VEHICLE_TRAIT) + source.client.view_size.reset_to_default() + source.update_sight() + +/obj/structure/periscope/apc + name = "apc periscope" + diff --git a/code/modules/vehicles/armored/medium_apc.dm b/code/modules/vehicles/armored/medium_apc.dm new file mode 100644 index 00000000000..e88806f4155 --- /dev/null +++ b/code/modules/vehicles/armored/medium_apc.dm @@ -0,0 +1,14 @@ +/obj/vehicle/sealed/armored/multitile/medium/apc + name = "TAV - Nike" + desc = "A heavily armoured vehicle with light armaments designed to ferry troops around the battlefield, or assist with search and rescue (SAR) operations." + icon = 'icons/obj/armored/2x2/medium_vehicles.dmi' + turret_icon = 'icons/obj/armored/2x2/medium_vehicles.dmi' + turret_icon_state = "apc_turret" + damage_icon_path = null + interior = null + required_entry_skill = SKILL_LARGE_VEHICLE_DEFAULT + minimap_icon_state = null + flags_armored = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_SECONDARY_WEAPON|ARMORED_HAS_UNDERLAY + icon_state = "apc" + move_delay = 0.25 SECONDS + max_occupants = 5 diff --git a/code/modules/vehicles/armored/medium_tank.dm b/code/modules/vehicles/armored/medium_tank.dm new file mode 100644 index 00000000000..b03d9fc4f55 --- /dev/null +++ b/code/modules/vehicles/armored/medium_tank.dm @@ -0,0 +1,19 @@ +/obj/vehicle/sealed/armored/multitile/medium //Its a smaller tank, we had sprites for it so whoo + name = "THV - Hades" + desc = "A metal behemoth which is designed to cleave through enemy lines. It comes pre installed with a main tank cannon capable of deploying heavy payloads, as well as a minigun which can tear through multiple targets in quick succession." + icon = 'icons/obj/armored/2x2/medium_vehicles.dmi' + turret_icon = 'icons/obj/armored/2x2/medium_vehicles.dmi' + turret_icon_state = "tank_turret" + hitbox = /obj/hitbox/medium + damage_icon_path = null + interior = null + icon_state = "tank" + flags_armored = ARMORED_HAS_PRIMARY_WEAPON|ARMORED_HAS_UNDERLAY + pixel_x = -16 + pixel_y = -32 + obj_integrity = 1300 + max_integrity = 1300 + max_occupants = 3 + +/obj/vehicle/sealed/armored/multitile/medium/enter_locations(atom/movable/entering_thing) + return list(get_step(src, REVERSE_DIR(dir))) diff --git a/code/modules/vehicles/armored/small_apc.dm b/code/modules/vehicles/armored/small_apc.dm new file mode 100644 index 00000000000..755e4131ca9 --- /dev/null +++ b/code/modules/vehicles/armored/small_apc.dm @@ -0,0 +1,13 @@ +/obj/vehicle/sealed/armored/apc + name = "TAV - Nike" + desc = "A miniaturized replica of a popular personnel carrier. For ages 5 and up." + icon = 'icons/obj/armored/1x1/tinytank.dmi' + turret_icon = 'icons/obj/armored/1x1/tinytank_gun.dmi' + turret_icon_state = "apc_turret" + icon_state = "apc" + flags_armored = NONE + move_delay = 0.3 SECONDS + flags_armored = NONE + pixel_x = -16 + pixel_y = -8 + max_occupants = 3 diff --git a/code/modules/vehicles/armored/tank_fabricator.dm b/code/modules/vehicles/armored/tank_fabricator.dm new file mode 100644 index 00000000000..6db634f4bff --- /dev/null +++ b/code/modules/vehicles/armored/tank_fabricator.dm @@ -0,0 +1,26 @@ +/obj/machinery/tank_part_fabricator + name = "vehicle part fabricator" + desc = "A large automated 3D printer for producing new vehicle parts and maintaining old ones." + density = TRUE + anchored = TRUE + use_power = IDLE_POWER_USE + req_access = list(ACCESS_MARINE_ARMORED) + idle_power_usage = 20 + bound_width = 64 + icon = 'icons/obj/machines/drone_fab.dmi' + icon_state = "drone_fab_idle" + /// actual UI that will be interacted with + var/datum/supply_ui/vehicles/supply_ui + +/obj/machinery/tank_part_fabricator/interact(mob/user) + . = ..() + if(.) + return + if(!allowed(user)) + return + if(!supply_ui) + supply_ui = new(src) + supply_ui.shuttle_id = SHUTTLE_VEHICLE_SUPPLY + supply_ui.home_id = "vehicle_home" + supply_ui.faction = FACTION_TERRAGOV + return supply_ui.interact(user) diff --git a/code/modules/vehicles/armored/vehicle_collision.dm b/code/modules/vehicles/armored/vehicle_collision.dm new file mode 100644 index 00000000000..a23e9b6e40c --- /dev/null +++ b/code/modules/vehicles/armored/vehicle_collision.dm @@ -0,0 +1,63 @@ +/** + *This proc is called when a atom is crashed into by a [armored vehicle][/obj/vehicle/sealed/armored]. Damage is then dealt to both the vehicle and atom + * + * * Arguments: + * * veh is the vehicle that is ramming + * * facing is the direction the vehicle is facing for when we ram it + * * T is the turf where the vehicle is used with- + * * temp to check whether a mob is squished + */ +/atom/proc/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + var/damage = veh.ram_damage // Each vehicle gets its own damage, you can modify it with snowplows and such ideally + + if(!TIMER_COOLDOWN_CHECK(veh, COOLDOWN_VEHICLE_CRUSHSOUND)) + visible_message(span_danger("[veh] rams [src]!")) + playsound(src, 'sound/effects/metal_crash.ogg', 45) + TIMER_COOLDOWN_START(veh, COOLDOWN_VEHICLE_CRUSHSOUND, 1 SECONDS) + return damage + +/obj/structure/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + . = ..() + take_damage(., BRUTE, MELEE, TRUE, facing, 0) + +/obj/structure/barricade/plasteel/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + . = ..() + toggle_open(FALSE) + +/obj/vehicle/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) //MONSTER TRUCKS + . = ..() + take_damage(., BRUTE, MELEE, TRUE, facing, 0) + +/obj/machinery/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + . = ..() + take_damage(., BRUTE, MELEE, TRUE, facing, 0) + +/turf/closed/wall/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + . = ..() + take_damage(., BRUTE, MELEE, TRUE, facing, 0) + +/mob/living/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp, mob/pilot) + . = ..() + if(stat == DEAD) + return 0 + if(lying_angle) + return 0 + log_attack("[key_name(pilot)] drove into [key_name(src)] with [veh]") + temp = get_step(veh.loc, facing) + T = temp + T = get_step(T, facing) + T = get_step(T, facing) + T = get_step(T, facing) + face_atom(T) + throw_at(T, 3, 2, veh, 1) + return take_overall_damage(., BRUTE, MELEE, FALSE, FALSE, TRUE, 0, 4) + +/mob/living/carbon/xenomorph/larva/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + gib() //fuck you + +/obj/effect/alien/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + . = ..() + take_damage(., BRUTE, MELEE, TRUE, facing, 0) + +/obj/effect/alien/weeds/vehicle_collision(obj/vehicle/sealed/armored/veh, facing, turf/T, turf/temp) + return diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm index 4997d335498..51874b52aaa 100644 --- a/code/modules/vehicles/cargo_train.dm +++ b/code/modules/vehicles/cargo_train.dm @@ -43,7 +43,7 @@ overlays += I turn_off() //so engine verbs are correctly set -/obj/vehicle/train/cargo/engine/Move() +/obj/vehicle/train/cargo/engine/Move(atom/newloc, direction, glide_size_override) if(on && cell.charge < charge_use) turn_off() @@ -65,7 +65,8 @@ verbs += /obj/vehicle/train/cargo/engine/verb/remove_key -/obj/vehicle/train/cargo/update_icon() +/obj/vehicle/train/cargo/update_icon_state() + . = ..() if(open) icon_state = initial(icon_state) + "_open" else diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm index 42efcee22e8..987755a4967 100644 --- a/code/modules/vehicles/cars/car.dm +++ b/code/modules/vehicles/cars/car.dm @@ -1,6 +1,7 @@ /obj/vehicle/sealed/car layer = ABOVE_MOB_LAYER move_resist = MOVE_FORCE_VERY_STRONG + move_delay = 1 ///Bitflags for special behavior such as kidnapping var/car_traits = NONE ///Sound file(s) to play when we drive around @@ -9,8 +10,6 @@ var/engine_sound_length = 2 SECONDS ///Time it takes to break out of the car. var/escape_time = 6 SECONDS - /// How long it takes to move, cars don't use the riding component similar to mechs so we handle it ourselves - var/vehicle_move_delay = 1 /// How long it takes to rev (vrrm vrrm!) COOLDOWN_DECLARE(enginesound_cooldown) @@ -79,13 +78,13 @@ /obj/vehicle/sealed/car/relaymove(mob/living/user, direction) if(is_driver(user) && canmove && (!key_type || istype(inserted_key, key_type))) - vehicle_move(direction) + vehicle_move(user, direction) return TRUE -/obj/vehicle/sealed/car/vehicle_move(direction) - if(!COOLDOWN_CHECK(src, cooldown_vehicle_move)) - return FALSE - COOLDOWN_START(src, cooldown_vehicle_move, vehicle_move_delay) +/obj/vehicle/sealed/car/vehicle_move(mob/living/user, direction) + . = ..() + if(!.) + return if(COOLDOWN_CHECK(src, enginesound_cooldown)) COOLDOWN_START(src, enginesound_cooldown, engine_sound_length) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index affd94ef163..3541225beef 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -24,7 +24,8 @@ move_force = MOVE_FORCE_VERY_STRONG move_resist = MOVE_FORCE_OVERPOWERING resistance_flags = UNACIDABLE|XENO_DAMAGEABLE|PORTAL_IMMUNE|PLASMACUTTER_IMMUNE - flags_atom = BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION + flags_atom = BUMP_ATTACKABLE|PREVENT_CONTENTS_EXPLOSION|CRITICAL_ATOM + appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER max_integrity = 300 soft_armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, FIRE = 100, ACID = 100) force = 5 @@ -184,7 +185,7 @@ /obj/vehicle/sealed/mecha/Initialize(mapload) . = ..() - ui_view = new(null, src) + ui_view = new(null, null, src) RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(play_stepsound)) spark_system.set_up(2, 0, src) diff --git a/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm b/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm index 1d2a6d4aac3..7482af329bc 100644 --- a/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm +++ b/code/modules/vehicles/mecha/combat/greyscale/greyscale.dm @@ -65,9 +65,9 @@ return ..() -/obj/vehicle/sealed/mecha/combat/greyscale/mob_try_enter(mob/M) - if((mecha_flags & MECHA_SKILL_LOCKED) && M.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_TRAINED) - balloon_alert(M, "You don't know how to pilot this") +/obj/vehicle/sealed/mecha/combat/greyscale/mob_try_enter(mob/entering_mob, mob/user, loc_override = FALSE) + if((mecha_flags & MECHA_SKILL_LOCKED) && entering_mob.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN) + balloon_alert(entering_mob, "You don't know how to pilot this") return FALSE return ..() diff --git a/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm b/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm index cb8067cda55..032633edb19 100644 --- a/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm +++ b/code/modules/vehicles/mecha/combat/greyscale/greyscale_constructor.dm @@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(greyscale_weapons_data, generate_greyscale_weapons_data()) ///list of plane masters to apply to owners var/list/plane_masters = list() -/atom/movable/screen/mech_builder_view/Initialize(mapload) +/atom/movable/screen/mech_builder_view/Initialize(mapload, datum/hud/hud_owner) . = ..() assigned_map = "mech_preview_[REF(src)]" set_position(1, 1) @@ -175,7 +175,7 @@ GLOBAL_LIST_INIT(greyscale_weapons_data, generate_greyscale_weapons_data()) . = ..() if(!.) return - if(user.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_TRAINED) + if(user.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_VETERAN) return FALSE /obj/machinery/computer/mech_builder/ui_interact(mob/user, datum/tgui/ui) diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 7e9f9a41c52..e737aad2616 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -151,13 +151,12 @@ holding = grey.limbs[MECH_GREY_L_ARM] projectile_to_fire.scatter = max(variance + holding?.scatter_mod, 0) projectile_to_fire.projectile_speed = projectile_to_fire.ammo.shell_speed - if(projectile_to_fire.ammo.flags_ammo_behavior & AMMO_IFF) - var/iff_signal - if(ishuman(firer)) - var/mob/living/carbon/human/human_firer = firer - var/obj/item/card/id/id = human_firer.get_idcard() - iff_signal = id?.iff_signal - projectile_to_fire.iff_signal = iff_signal + if((projectile_to_fire.ammo.flags_ammo_behavior & AMMO_IFF) && ishuman(firer)) + var/mob/living/carbon/human/human_firer = firer + var/obj/item/card/id/id = human_firer.get_idcard() + projectile_to_fire.iff_signal = id?.iff_signal + if(firer) + projectile_to_fire.def_zone = firer.zone_selected ///actually executes firing when autofire asks for it, returns TRUE to keep firing FALSE to stop /obj/item/mecha_parts/mecha_equipment/weapon/proc/fire() diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm index 0d4465ef1c9..43698b584e0 100644 --- a/code/modules/vehicles/mecha/mecha_actions.dm +++ b/code/modules/vehicles/mecha/mecha_actions.dm @@ -124,4 +124,4 @@ chassis.balloon_alert(owner, "controlling pilot seat") chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT) chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS) - chassis.update_icon_state() + chassis.update_appearance() diff --git a/code/modules/vehicles/mecha/mecha_mob_interaction.dm b/code/modules/vehicles/mecha/mecha_mob_interaction.dm index 513217edafa..63988a4f68c 100644 --- a/code/modules/vehicles/mecha/mecha_mob_interaction.dm +++ b/code/modules/vehicles/mecha/mecha_mob_interaction.dm @@ -1,36 +1,36 @@ -/obj/vehicle/sealed/mecha/mob_try_enter(mob/M) - if(!ishuman(M)) // no silicons or drones in mechas. +/obj/vehicle/sealed/mecha/mob_try_enter(mob/entering_mob, mob/user, loc_override = FALSE) + if(!ishuman(entering_mob)) // no silicons or drones in mechas. return - log_message("[M] tried to move into [src].", LOG_MECHA) + log_message("[entering_mob] tried to move into [src].", LOG_MECHA) if(dna_lock) - var/mob/living/carbon/entering_carbon = M + var/mob/living/carbon/entering_carbon = entering_mob if(md5(REF(entering_carbon)) != dna_lock) - to_chat(M, span_warning("Access denied. [name] is secured with a DNA lock.")) + to_chat(entering_mob, span_warning("Access denied. [name] is secured with a DNA lock.")) log_message("Permission denied (DNA LOCK).", LOG_MECHA) return - if(!operation_allowed(M)) - to_chat(M, span_warning("Access denied. Insufficient operation keycodes.")) + if(!operation_allowed(entering_mob)) + to_chat(entering_mob, span_warning("Access denied. Insufficient operation keycodes.")) log_message("Permission denied (No keycode).", LOG_MECHA) return . = ..() if(.) - moved_inside(M) + moved_inside(entering_mob) -/obj/vehicle/sealed/mecha/enter_checks(mob/M) +/obj/vehicle/sealed/mecha/enter_checks(mob/entering_mob, loc_override = FALSE) if(obj_integrity <= 0) - to_chat(M, span_warning("You cannot get in the [src], it has been destroyed!")) + to_chat(entering_mob, span_warning("You cannot get in the [src], it has been destroyed!")) return FALSE - if(M.buckled) - to_chat(M, span_warning("You can't enter the exosuit while buckled.")) + if(entering_mob.buckled) + to_chat(entering_mob, span_warning("You can't enter the exosuit while buckled.")) log_message("Permission denied (Buckled).", LOG_MECHA) return FALSE - if(LAZYLEN(M.buckled_mobs)) - to_chat(M, span_warning("You can't enter the exosuit with other creatures attached to you!")) + if(LAZYLEN(entering_mob.buckled_mobs)) + to_chat(entering_mob, span_warning("You can't enter the exosuit with other creatures attached to you!")) log_message("Permission denied (Attached mobs).", LOG_MECHA) return FALSE - var/obj/item/I = M.get_item_by_slot(SLOT_BACK) + var/obj/item/I = entering_mob.get_item_by_slot(SLOT_BACK) if(I && istype(I, /obj/item/jetpack_marine)) - to_chat(M, span_warning("Something on your back prevents you from entering the mech!")) + to_chat(entering_mob, span_warning("Something on your back prevents you from entering the mech!")) return FALSE return ..() diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index c81f635be83..6773cde6448 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -15,12 +15,12 @@ . = TRUE if(!canmove || !(user in return_drivers())) return - vehicle_move(direction) + vehicle_move(user, direction) -/obj/vehicle/sealed/mecha/vehicle_move(direction, forcerotate = FALSE) - if(!COOLDOWN_CHECK(src, cooldown_vehicle_move)) - return FALSE - COOLDOWN_START(src, cooldown_vehicle_move, move_delay) +/obj/vehicle/sealed/mecha/vehicle_move(mob/living/user, direction, forcerotate = FALSE) + . = ..() + if(!.) + return if(completely_disabled) return FALSE if(!direction) diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm index 5b5fe0276cb..bfcdd0b91a1 100644 --- a/code/modules/vehicles/mecha/mecha_ui.dm +++ b/code/modules/vehicles/mecha/mecha_ui.dm @@ -10,7 +10,7 @@ ///list of plane masters to apply to owners var/list/plane_masters = list() -/atom/movable/screen/mech_view/Initialize(mapload, obj/vehicle/sealed/mecha/newowner) +/atom/movable/screen/mech_view/Initialize(mapload, datum/hud/hud_owner, obj/vehicle/sealed/mecha/newowner) . = ..() owner = newowner assigned_map = "mech_view_[REF(owner)]" diff --git a/code/modules/vehicles/motorbike.dm b/code/modules/vehicles/motorbike.dm index e95fbd25887..a903fc3b339 100644 --- a/code/modules/vehicles/motorbike.dm +++ b/code/modules/vehicles/motorbike.dm @@ -197,9 +197,6 @@ if(user.lying_angle || user.incapacitated()) //Can't use your inventory when lying return FALSE - if(istype(user.loc, /obj/vehicle/multitile/root/cm_armored)) //Stops inventory actions in a mech/tank - return FALSE - if(over_object == user && Adjacent(user)) //This must come before the screen objects only block open(user) return FALSE diff --git a/code/modules/vehicles/multitile/cm_armored.dm b/code/modules/vehicles/multitile/cm_armored.dm deleted file mode 100644 index 2ce17a9ef33..00000000000 --- a/code/modules/vehicles/multitile/cm_armored.dm +++ /dev/null @@ -1,787 +0,0 @@ -//NOT bitflags, just global constant values -#define HDPT_PRIMARY "primary" -#define HDPT_SECDGUN "secondary" -#define HDPT_SUPPORT "support" -#define HDPT_ARMOR "armor" -#define HDPT_TREADS "treads" - -//Percentages of what hardpoints take what damage, e.g. armor takes 37.5% of the damage -GLOBAL_LIST_INIT(armorvic_dmg_distributions, list( - HDPT_PRIMARY = 0.15, - HDPT_SECDGUN = 0.125, - HDPT_SUPPORT = 0.075, - HDPT_ARMOR = 0.5, - HDPT_TREADS = 0.15)) - -//The main object, should be an abstract class // todo delete me -/obj/vehicle/multitile/root/cm_armored - name = "Armored Vehicle" - desc = "Get inside to operate the vehicle." - hitbox_type = /obj/vehicle/multitile/hitbox/cm_armored //Used for emergencies and respawning hitboxes - - ///What slots the vehicle can have - var/list/hardpoints = list(HDPT_ARMOR, HDPT_TREADS, HDPT_SECDGUN, HDPT_SUPPORT, HDPT_PRIMARY) - ///The next world.time when the tank can move - var/next_move = 0 - //Below are vars that can be affected by hardpoints, generally used as ratios or decisecond timers - move_delay = 30 //default 3 seconds per tile - var/active_hp - var/list/dmg_distribs = list() - ///Changes cooldowns and accuracies - var/list/misc_ratios = list( - "move" = 1.0, - "prim_acc" = 1.0, - "secd_acc" = 1.0, - "supp_acc" = 1.0, - "prim_cool" = 1.0, - "secd_cool" = 1.0, - "supp_cool" = 1.0) - ///Changes how much damage the tank takes - var/list/dmg_multipliers = list( - "all" = 1.0, //for when you want to make it invincible - "acid" = 1.0, - "slash" = 1.0, - "bullet" = 1.0, - "explosive" = 1.0, - "blunt" = 1.0, - "abstract" = 1.0) //abstract for when you just want to hurt it - ///Decisecond cooldowns for the slots - var/list/internal_cooldowns = list( - "primary" = 300, - "secondary" = 200, - "support" = 150) - ///Percentage accuracies for slot - var/list/accuracies = list( - "primary" = 0.97, - "secondary" = 0.67, - "support" = 0.5) - - //Placeholders - icon = 'icons/obj/vehicles.dmi' - icon_state = "cargo_engine" - -/obj/vehicle/multitile/root/cm_armored/Initialize(mapload) - . = ..() - GLOB.tank_list += src - set_light(0.01) - -/obj/vehicle/multitile/root/cm_armored/Destroy() - for(var/i in linked_objs) - var/obj/O = linked_objs[i] - if(O == src) - continue - qdel(O, TRUE) //Delete all of the hitboxes etc - GLOB.tank_list -= src - return ..() - -//What to do if all ofthe installed modules have been broken -/obj/vehicle/multitile/root/cm_armored/proc/handle_all_modules_broken() - return - -/obj/vehicle/multitile/root/cm_armored/proc/deactivate_all_hardpoints() - var/list/slots = get_activatable_hardpoints() - for(var/slot in slots) - var/obj/item/hardpoint/HP = hardpoints[slot] - HP?.deactivate() - -/obj/vehicle/multitile/root/cm_armored/proc/remove_all_players() - return - -//The basic vehicle code that moves the tank, with movement delay implemented -/obj/vehicle/multitile/root/cm_armored/relaymove(mob/user, direction) - if(world.time < next_move) - return - next_move = world.time + move_delay * misc_ratios["move"] - - return ..() - -//Same thing but for rotations -/obj/vehicle/multitile/root/cm_armored/try_rotate(deg, mob/user, force = FALSE) - if(world.time < next_move && !force) - return - next_move = world.time + move_delay * misc_ratios["move"] * (force ? 2 : 3) //3 for a 3 point turn, idk - return ..() - -/obj/vehicle/multitile/root/cm_armored/proc/can_use_hp(mob/M) - return TRUE - -//Used by the gunner to swap which module they are using -//e.g. from the minigun to the smoke launcher -//Only the active hardpoint module can be used -/obj/vehicle/multitile/root/cm_armored/verb/switch_active_hp() - set name = "Change Active Weapon" - set category = "Vehicle" - set src in view(0) - - if(!can_use_hp(usr)) - return - - var/list/slots = get_activatable_hardpoints() - - if(!length(slots)) - to_chat(usr, span_warning("All of the modules can't be activated or are broken.")) - return - - var/slot = tgui_input_list(usr, "Select a slot.", null, slots) - - var/obj/item/hardpoint/HP = hardpoints[slot] - if(!(HP?.obj_integrity)) - to_chat(usr, span_warning("That module is either missing or broken.")) - return - - active_hp = slot - to_chat(usr, span_notice("You select the [slot] slot.")) - if(isliving(usr)) - var/mob/living/M = usr - M.set_interaction(src) - -/obj/vehicle/multitile/root/cm_armored/verb/reload_hp() - set name = "Reload Active Weapon" - set category = "Vehicle" - set src in view(0) - - if(!can_use_hp(usr)) - return - - //TODO: make this a proc so I don't keep repeating this code - var/list/slots = get_activatable_hardpoints() - - if(!length(slots)) - to_chat(usr, span_warning("All of the modules can't be reloaded or are broken.")) - return - - var/slot = tgui_input_list(usr, "Select a slot.", null, slots) - - var/obj/item/hardpoint/HP = hardpoints[slot] - if(!length(HP?.backup_clips)) - to_chat(usr, span_warning("That module is either missing or has no remaining backup clips.")) - return - - var/obj/item/ammo_magazine/A = HP.backup_clips[1] //LISTS START AT 1 REEEEEEEEEEEE - if(!A) - to_chat(usr, span_danger("Something went wrong! PM a staff member! Code: T_RHPN")) - return - - to_chat(usr, span_notice("You begin reloading the [slot] module.")) - - addtimer(CALLBACK(src, PROC_REF(finish_reloading_hp), usr, HP, A, slot), 2 SECONDS) - -/obj/vehicle/multitile/root/cm_armored/proc/finish_reloading_hp(mob/living/user, obj/item/hardpoint/HP, obj/item/ammo_magazine/A, slot) - if(!can_use_hp(usr)) - return - - HP.ammo.forceMove(get_turf(entrance)) - HP.ammo.update_icon() - HP.ammo = A - HP.backup_clips.Remove(A) - - to_chat(usr, span_notice("You reload the [slot] module.")) - -/obj/vehicle/multitile/root/cm_armored/proc/get_activatable_hardpoints() - var/list/slots = list() - for(var/slot in hardpoints) - var/obj/item/hardpoint/HP = hardpoints[slot] - if(!(HP?.obj_integrity)) - continue - if(!HP.is_activatable) - continue - slots += slot - - return slots - -//Special armored vic healthcheck that mainly updates the hardpoint states -/obj/vehicle/multitile/root/cm_armored/proc/healthcheck() - repair_damage(max_integrity) //The tank itself doesn't take damage - var/i - var/remove_person = TRUE //Whether or not to call handle_all_modules_broken() - for(i in hardpoints) - var/obj/item/hardpoint/H = hardpoints[i] - if(!H) - continue - if(!H.obj_integrity) - H.remove_buff() - else - remove_person = FALSE //if something exists but isnt broken - - if(remove_person) - handle_all_modules_broken() - - update_icon() - -//Since the vics are 3x4 we need to swap between the two files with different dimensions -//Also need to offset to center the tank about the root object -/obj/vehicle/multitile/root/cm_armored/update_icon() - - overlays.Cut() - - //Assuming 3x3 with half block overlaps in the tank's direction - if(dir in list(NORTH, SOUTH)) - pixel_x = -32 - pixel_y = -48 - icon = 'icons/obj/vehicles/tank_NS.dmi' - - else if(dir in list(EAST, WEST)) - pixel_x = -48 - pixel_y = -32 - icon = 'icons/obj/vehicles/tank_EW.dmi' - - //Basic iteration that snags the overlay from the hardpoint module object - for(var/i in hardpoints) - var/obj/item/hardpoint/H = hardpoints[i] - - if((i == HDPT_TREADS && !H) || (H && !H.obj_integrity)) //Treads not installed or broken - var/image/I = image(icon, icon_state = "damaged_hardpt_[i]") - overlays += I - - if(H) - var/image/I = H.get_icon_image(0, 0, dir) - overlays += I - -//Hitboxes but with new names -/obj/vehicle/multitile/hitbox/cm_armored - name = "Armored Vehicle" - desc = "Get inside to operate the vehicle." - allow_pass_flags = PASSABLE - var/lastsound = 0 - -//If something want to delete this, it's probably either an admin or the shuttle -//If it's an admin, they want to disable this -//If it's the shuttle, it should do damage -//If fully repaired and moves at least once, the broken hitboxes will respawn according to multitile.dm -/obj/vehicle/multitile/hitbox/cm_armored/Destroy() - var/obj/vehicle/multitile/root/cm_armored/C = root - C?.take_damage_type(1000000, "abstract") - return ..() - -//Tramplin' time, but other than that identical -/obj/vehicle/multitile/hitbox/cm_armored/Bump(atom/A) - . = ..() - var/facing = get_dir(src, A) - var/turf/temp = loc - var/turf/T = loc - A.tank_collision(src, facing, T, temp) - if(isliving(A)) - log_attack("[get_driver()] drove over [A] with [root]") - -/obj/vehicle/multitile/hitbox/cm_armored/proc/get_driver() - return "Someone" - -/atom/proc/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - return - -/mob/living/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - if(stat == DEAD) //We don't care about the dead - return - if(loc == C.loc) // treaded over. - ParalyzeNoChain(2 SECONDS) - var/target_dir = REVERSE_DIR(C.dir) - temp = get_step(C.loc, target_dir) - T = temp - target_dir = REVERSE_DIR(C.dir) - T = get_step(T, target_dir) - face_atom(T) - throw_at(T, 3, 2, C, 1) - apply_damage(randfloat(5, 7.5), BRUTE, blocked = MELEE) - return - if(!lying_angle) - temp = get_step(T, facing) - T = temp - T = get_step(T, pick(GLOB.cardinals)) - if(mob_size == MOB_SIZE_BIG) - throw_at(T, 3, 2, C, 0) - else - throw_at(T, 3, 2, C, 1) - ParalyzeNoChain(2 SECONDS) - apply_damage(rand(10, 15), BRUTE, blocked = MELEE) - visible_message(span_danger("[C] bumps into [src], throwing [p_them()] away!"), span_danger("[C] violently bumps into you!")) - var/obj/vehicle/multitile/root/cm_armored/CA = C.root - var/list/slots = CA.get_activatable_hardpoints() - for(var/slot in slots) - var/obj/item/hardpoint/H = CA.hardpoints[slot] - H?.livingmob_interact(src) - -/mob/living/carbon/xenomorph/queen/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - if(lying_angle || loc == C.loc) - return ..() - temp = get_step(T, facing) - T = temp - T = get_step(T, pick(GLOB.cardinals)) - throw_at(T, 2, 2, C, 0) - visible_message(span_danger("[C] bumps into [src], pushing [p_them()] away!"), span_danger("[C] bumps into you!")) - -/mob/living/carbon/xenomorph/crusher/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - if(lying_angle || loc == C.loc) - return ..() - temp = get_step(T, facing) - T = temp - T = get_step(T, pick(GLOB.cardinals)) - throw_at(T, 2, 2, C, 0) - visible_message(span_danger("[C] bumps into [src], pushing [p_them()] away!"), span_danger("[C] bumps into you!")) - -/mob/living/carbon/xenomorph/larva/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - if(loc == C.loc) // treaded over. - ParalyzeNoChain(2 SECONDS) - apply_damage(randfloat(5, 7.5), BRUTE, blocked = MELEE) - return - var/obj/vehicle/multitile/root/cm_armored/CA = C.root - var/list/slots = CA.get_activatable_hardpoints() - for(var/slot in slots) - var/obj/item/hardpoint/H = CA.hardpoints[slot] - H?.livingmob_interact(src) - -/turf/closed/wall/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - var/obj/vehicle/multitile/root/cm_armored/tank/CA = C.root - var/damage = 30 - var/tank_damage = 2 - - if(facing == CA.old_dir && istype(CA.hardpoints[HDPT_ARMOR], /obj/item/hardpoint/armor/snowplow) ) //Snowplow eliminates collision damage, and doubles damage dealt if we're facing the thing we're crushing - var/obj/item/hardpoint/armor/snowplow/SP = CA.hardpoints[HDPT_ARMOR] - if(SP.obj_integrity) - damage = 45 - tank_damage = 1 - - take_damage(damage) - CA.take_damage_type(tank_damage, "blunt", src) - if(world.time > C.lastsound + 1 SECONDS) - playsound(src, 'sound/effects/metal_crash.ogg', 35) - C.lastsound = world.time - -/obj/machinery/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - var/obj/vehicle/multitile/root/cm_armored/tank/CA = C.root - var/damage = 30 - var/tank_damage = 2 - - if(facing == CA.old_dir && istype(CA.hardpoints[HDPT_ARMOR], /obj/item/hardpoint/armor/snowplow) ) //Snowplow eliminates collision damage, and doubles damage dealt if we're facing the thing we're crushing - var/obj/item/hardpoint/armor/snowplow/SP = CA.hardpoints[HDPT_ARMOR] - if(SP.obj_integrity) - damage = 60 - tank_damage = 0 - - take_damage(damage) - CA.take_damage_type(tank_damage, "blunt", src) - if(world.time > C.lastsound + 1 SECONDS) - visible_message(span_danger("[CA] rams into \the [src]!")) - playsound(src, 'sound/effects/metal_crash.ogg', 35) - C.lastsound = world.time - -/obj/structure/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - var/obj/vehicle/multitile/root/cm_armored/tank/CA = C.root - var/damage = 30 - var/tank_damage = 2 - - if(facing == CA.old_dir && istype(CA.hardpoints[HDPT_ARMOR], /obj/item/hardpoint/armor/snowplow) ) //Snowplow eliminates collision damage, and doubles damage dealt if we're facing the thing we're crushing - var/obj/item/hardpoint/armor/snowplow/SP = CA.hardpoints[HDPT_ARMOR] - if(SP.obj_integrity) - damage = 60 - tank_damage = 0 - - take_damage(damage) - CA.take_damage_type(tank_damage, "blunt", src) - if(world.time > C.lastsound + 1 SECONDS) - visible_message(span_danger("[CA] crushes \the [src]!")) - playsound(src, 'sound/effects/metal_crash.ogg', 35) - C.lastsound = world.time - -/obj/alien/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - take_damage(40) - -/obj/alien/weeds/tank_collision(obj/vehicle/multitile/hitbox/cm_armored/C, facing, turf/T, turf/temp) - return - -/obj/vehicle/multitile/hitbox/cm_armored/Move(atom/A, direction) - - for(var/mob/living/M in get_turf(src)) - M.tank_collision(src) - - . = ..() - - if(.) - for(var/mob/living/M in get_turf(A)) - M.tank_collision(src) - -//Can't hit yourself with your own bullet -/obj/vehicle/multitile/hitbox/cm_armored/projectile_hit(obj/projectile/proj) - if(proj.firer == root) //Don't hit our own hitboxes - return FALSE - - return ..() - -/obj/vehicle/multitile/hitbox/cm_armored/ex_act(severity) - return root.ex_act(severity) - -/obj/vehicle/multitile/hitbox/cm_armored/attackby(obj/item/I, mob/user, params) - return root.attackby(I, user, params) - -/obj/vehicle/multitile/hitbox/cm_armored/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE) - return root.attack_alien(xeno_attacker, damage_amount) - -/obj/vehicle/multitile/hitbox/cm_armored/effect_smoke(obj/effect/particle_effect/smoke/S) - . = ..() - if(!.) - return - if(CHECK_BITFIELD(S.smoke_traits, SMOKE_XENO_ACID)) - var/obj/vehicle/multitile/root/cm_armored/T = root - T.take_damage_type(30, ACID) - -//A bit icky, but basically if you're adjacent to the tank hitbox, you are then adjacent to the root object -/obj/vehicle/multitile/root/cm_armored/Adjacent(atom/A) - for(var/i in linked_objs) - var/obj/vehicle/multitile/hitbox/cm_armored/H = linked_objs[i] - if(!H) - continue - if(get_dist(H, A) <= 1) - return TRUE //Using get_dist() to avoid hidden code that recurs infinitely here - return ..() - -//Returns the ratio of damage to take, just a housekeeping thing -/obj/vehicle/multitile/root/cm_armored/proc/get_dmg_multi(type) - if(!dmg_multipliers.Find(type)) - return 0 - return dmg_multipliers[type] * dmg_multipliers["all"] - -//Generic proc for taking damage -//ALWAYS USE THIS WHEN INFLICTING DAMAGE TO THE VEHICLES -/obj/vehicle/multitile/root/cm_armored/proc/take_damage_type(damage, type, atom/attacker) - for(var/i in hardpoints) - var/obj/item/hardpoint/HP = hardpoints[i] - if(HP) - HP.take_damage(HP.obj_integrity - damage * dmg_distribs[i] * get_dmg_multi(type)) - - healthcheck() - - if(istype(attacker, /mob)) - var/mob/M = attacker - log_attack("[src] took [damage] [type] damage from [M] ([M.client ? M.client.ckey : "disconnected"]).") - else - log_attack("[src] took [damage] [type] damage from [attacker].") - -/obj/vehicle/multitile/root/cm_armored/projectile_hit(obj/projectile/proj) - if(proj.firer == src) //Don't hit ourself. - return FALSE - - return ..() - -//severity 1.0 explosions never really happen so we're gonna follow everyone else's example -/obj/vehicle/multitile/root/cm_armored/ex_act(severity) - - switch(severity) - if(EXPLODE_DEVASTATE) - take_damage(rand(250, 350)) //Devastation level explosives are anti-tank and do real damage. - - if(EXPLODE_HEAVY) - take_damage(rand(30, 40)) //Heavy explosions do some damage, but are largely deferred by the armour/bulk. - -//Honestly copies some code from the Xeno files, just handling some special cases -/obj/vehicle/multitile/root/cm_armored/attack_alien(mob/living/carbon/xenomorph/M, damage_amount = M.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE) - - if(M.loc == entrance.loc && M.a_intent == INTENT_HELP) - handle_player_entrance(M) //will call the get out of tank proc on its own - return - - var/damage = damage_amount - - //Somehow we will deal no damage on this attack - if(!damage) - playsound(M.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1) - M.do_attack_animation(src) - M.visible_message(span_danger("\The [M] lunges at [src]!"), \ - span_danger("We lunge at [src]!")) - return FALSE - - M.do_attack_animation(src, ATTACK_EFFECT_CLAW) - playsound(loc, "alien_claw_metal", 25, 1) - - M.visible_message(span_danger("\The [M] slashes [src]!"), \ - span_danger("We slash [src]!")) - - take_damage_type(damage * ( (isxenoravager(M)) ? 2 : 1 ), "slash", M) //Ravs do a bitchin double damage - return ..() - -//Special case for entering the vehicle without using the verb -/obj/vehicle/multitile/root/cm_armored/attack_hand(mob/living/user) - . = ..() - if(.) - return - if(user.loc == entrance.loc) - handle_player_entrance(user) - return - -/obj/vehicle/multitile/root/cm_armored/Entered(atom/movable/A) - if(istype(A, /obj) && !istype(A, /obj/item/ammo_magazine/tank) && !istype(A, /obj/item/hardpoint)) - A.forceMove(loc) - return - - return ..() - -//Redistributes damage ratios based off of what things are attached (no armor means the armor doesn't mitigate any damage) -/obj/vehicle/multitile/root/cm_armored/proc/update_damage_distribs() - dmg_distribs = GLOB.armorvic_dmg_distributions.Copy() //Assume full installs - for(var/slot in hardpoints) - var/obj/item/hardpoint/HP = hardpoints[slot] - if(!HP) - dmg_distribs[slot] = 0.0 //Remove empty slots' damage mitigation - var/acc = 0 - for(var/slot in dmg_distribs) - var/ratio = dmg_distribs[slot] - acc += ratio //Get total current ratio applications - if(acc == 0) - return - for(var/slot in dmg_distribs) - var/ratio = dmg_distribs[slot] - dmg_distribs[slot] = ratio/acc //Redistribute according to previous ratios for full damage taking, but ignoring empty slots - -//Special cases abound, handled below or in subclasses -/obj/vehicle/multitile/root/cm_armored/attackby(obj/item/O, mob/user) - - if(istype(O, /obj/item/hardpoint)) //Are we trying to install stuff? - var/obj/item/hardpoint/HP = O - install_hardpoint(HP, user) - - else if(istype(O, /obj/item/ammo_magazine)) //Are we trying to reload? - var/obj/item/ammo_magazine/AM = O - handle_ammomag_attackby(AM, user) - - else if(iswelder(O) || iswrench(O)) //Are we trying to repair stuff? - handle_hardpoint_repair(O, user) - update_damage_distribs() - - else if(iscrowbar(O)) //Are we trying to remove stuff? - uninstall_hardpoint(O, user) - - else - . = ..() - if(!(O.flags_item & NOBLUDGEON)) - take_damage_type(O.force * 0.05, "blunt", user) //Melee weapons from people do very little damage - -/obj/vehicle/multitile/root/cm_armored/proc/handle_hardpoint_repair(obj/item/O, mob/user) - - //Need to the what the hell you're doing - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER) - user.visible_message(span_notice("[user] fumbles around figuring out what to do with [O] on the [src]."), - span_notice("You fumble around figuring out what to do with [O] on the [src].")) - var/fumbling_time = 5 SECONDS * (SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER)) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - //Pick what to repair - var/slot = tgui_input_list(user, "Select a slot to try and repair", null, hardpoints) //maybe tgui alert ? - var/obj/item/I = user.get_active_held_item() - if(!Adjacent(user) || (!iswelder(I) && !iswrench(I))) - return - - var/obj/item/hardpoint/old = hardpoints[slot] //Is there something there already? - - if(!old) - to_chat(user, span_warning("There is nothing installed on that slot.")) - return - - if(old.obj_integrity >= old.max_integrity) - to_chat(user, span_notice("\the [old] is already in perfect conditions.")) - return - - //Determine how many 3 second intervals to wait and if you have the right tool - var/num_delays = 6 - switch(slot) - if(HDPT_PRIMARY) - num_delays = 5 - if(!iswelder(I)) - to_chat(user, span_warning("That's the wrong tool. Use a welder.")) - return - var/obj/item/tool/weldingtool/WT = I - if(!WT.isOn()) - to_chat(user, span_warning("You need to light your [WT] first.")) - return - - if(HDPT_SECDGUN) - num_delays = 3 - if(!iswrench(I)) - to_chat(user, span_warning("That's the wrong tool. Use a wrench.")) - return - - if(HDPT_SUPPORT) - num_delays = 2 - if(!iswrench(I)) - to_chat(user, span_warning("That's the wrong tool. Use a wrench.")) - return - - if(HDPT_ARMOR) - num_delays = 10 - if(!iswelder(I)) - to_chat(user, span_warning("That's the wrong tool. Use a welder.")) - return - var/obj/item/tool/weldingtool/WT = I - if(!WT.isOn()) - to_chat(user, span_warning("You need to light your [WT] first.")) - return - - if(HDPT_TREADS) - if(!iswelder(I)) - to_chat(user, span_warning("That's the wrong tool. Use a welder.")) - return - var/obj/item/tool/weldingtool/WT = I - if(!WT.isOn()) - to_chat(user, span_warning("You need to light your [WT] first.")) - return - WT.remove_fuel(num_delays, user) - - user.visible_message(span_notice("[user] starts repairing the [slot] slot on [src]."), - span_notice("You start repairing the [slot] slot on the [src].")) - - if(!do_after(user, 30 * num_delays, NONE, src, BUSY_ICON_BUILD, extra_checks = iswelder(O) ? CALLBACK(O, /obj/item/tool/weldingtool/proc/isOn) : null)) - user.visible_message(span_notice("[user] stops repairing the [slot] slot on [src]."), - span_notice("You stop repairing the [slot] slot on the [src].")) - return - - if(iswelder(O)) - var/obj/item/tool/weldingtool/WT = O - WT.remove_fuel(num_delays, user) - - user.visible_message(span_notice("[user] repairs the [slot] slot on the [src]."), - span_notice("You repair the [slot] slot on [src].")) - - old.repair_damage(old.max_integrity) //We repaired it, good job - old.apply_buff() - - update_icon() - -//Relaoding stuff, pretty bare-bones and basic -/obj/vehicle/multitile/root/cm_armored/proc/handle_ammomag_attackby(obj/item/ammo_magazine/AM, mob/user) - - //No skill checks for reloading - //Maybe I should delineate levels of skill for reloading, installation, and repairs? - //That would make it easier to differentiate between the two for skills - //Instead of using MT skills for these procs and TC skills for operation - //Oh but wait then the MTs would be able to drive fuck that - var/slot = tgui_input_list(user, "Select a slot to try and refill", null, hardpoints) - if(!Adjacent(user) || user.get_active_held_item() != AM) - return - var/obj/item/hardpoint/HP = hardpoints[slot] - - if(!HP) - to_chat(user, span_warning("There is nothing installed on that slot.")) - return - - HP.try_add_clip(AM, user) - -//Putting on hardpoints -//Similar to repairing stuff, down to the time delay -/obj/vehicle/multitile/root/cm_armored/proc/install_hardpoint(obj/item/hardpoint/HP, mob/user) - - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER) - user.visible_message(span_notice("[user] fumbles around figuring out what to do with [HP] on the [src]."), - span_notice("You fumble around figuring out what to do with [HP] on the [src].")) - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - var/obj/item/hardpoint/occupied = hardpoints[HP.slot] - - if(occupied) - to_chat(user, span_warning("Remove the previous hardpoint module first.")) - return - - user.visible_message(span_notice("[user] begins installing [HP] on the [HP.slot] hardpoint slot on the [src]."), - span_notice("You begin installing [HP] on the [HP.slot] hardpoint slot on the [src].")) - - var/num_delays = 1 - - switch(HP.slot) - if(HDPT_PRIMARY) - num_delays = 5 - if(HDPT_SECDGUN) - num_delays = 3 - if(HDPT_SUPPORT) - num_delays = 2 - if(HDPT_ARMOR) - num_delays = 10 - if(HDPT_TREADS) - num_delays = 7 - - if(!do_after(user, 30 * num_delays, NONE, src, BUSY_ICON_BUILD)) - user.visible_message(span_warning("[user] stops installing \the [HP] on [src]."), span_warning("You stop installing \the [HP] on [src].")) - return - - if(occupied) - return - - user.visible_message(span_notice("[user] installs \the [HP] on [src]."), span_notice("You install \the [HP] on [src].")) - - user.temporarilyRemoveItemFromInventory(HP, 0) - - add_hardpoint(HP, user) - -//User-orientated proc for taking of hardpoints -//Again, similar to the above ones -/obj/vehicle/multitile/root/cm_armored/proc/uninstall_hardpoint(obj/item/O, mob/user) - - if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_MASTER) - user.visible_message(span_notice("[user] fumbles around figuring out what to do with [O] on the [src]."), - span_notice("You fumble around figuring out what to do with [O] on the [src].")) - var/fumbling_time = 5 SECONDS * ( SKILL_ENGINEER_MASTER - user.skills.getRating(SKILL_ENGINEER) ) - if(!do_after(user, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED)) - return - - var/slot = tgui_input_list(user, "Select a slot to try and remove", null, hardpoints) - if(!Adjacent(user) || !iscrowbar(user.get_active_held_item())) - return - - var/obj/item/hardpoint/old = hardpoints[slot] - - if(!old) - to_chat(user, span_warning("There is nothing installed there.")) - return - - user.visible_message(span_notice("[user] begins removing [old] on the [old.slot] hardpoint slot on [src]."), - span_notice("You begin removing [old] on the [old.slot] hardpoint slot on [src].")) - - var/num_delays = 1 - - switch(old.slot) - if(HDPT_PRIMARY) - num_delays = 5 - if(HDPT_SECDGUN) - num_delays = 3 - if(HDPT_SUPPORT) - num_delays = 2 - if(HDPT_ARMOR) - num_delays = 10 - if(HDPT_TREADS) - num_delays = 7 - - if(!do_after(user, 30 * num_delays, NONE, src, BUSY_ICON_BUILD)) - user.visible_message(span_warning("[user] stops removing \the [old] on [src]."), span_warning("You stop removing \the [old] on [src].")) - return - if(QDELETED(old) || old != hardpoints[slot]) - return - - user.visible_message(span_notice("[user] removes \the [old] on [src]."), span_notice("You remove \the [old] on [src].")) - - remove_hardpoint(old, user) - -//General proc for putting on hardpoints -//ALWAYS CALL THIS WHEN ATTACHING HARDPOINTS -/obj/vehicle/multitile/root/cm_armored/proc/add_hardpoint(obj/item/hardpoint/HP, mob/user) - if(!istype(HP)) - return - HP.owner = src - if(HP.obj_integrity) - HP.apply_buff() - HP.forceMove(src) - - hardpoints[HP.slot] = HP - update_damage_distribs() - update_icon() - -//General proc for taking off hardpoints -//ALWAYS CALL THIS WHEN REMOVING HARDPOINTS -/obj/vehicle/multitile/root/cm_armored/proc/remove_hardpoint(obj/item/hardpoint/old, mob/user) - old.forceMove(user ? user.loc : entrance.loc) - old.remove_buff() - old.owner = null - - hardpoints[old.slot] = null - update_damage_distribs() - update_icon() - -/obj/vehicle/multitile/root/cm_armored/contents_explosion(severity) - return diff --git a/code/modules/vehicles/multitile/hardpoints.dm b/code/modules/vehicles/multitile/hardpoints.dm deleted file mode 100644 index a238093cc6d..00000000000 --- a/code/modules/vehicles/multitile/hardpoints.dm +++ /dev/null @@ -1,996 +0,0 @@ -/* -All of the hardpoints, for the tank or other -Currently only has the tank hardpoints -*/ - -/obj/item/hardpoint - - var/slot //What slot do we attach to? - var/obj/vehicle/multitile/root/cm_armored/owner //Who do we work for? - - icon = 'icons/obj/vehicles/hardpoint_modules.dmi' - icon_state = "tires" //Placeholder - - max_integrity = 100 - w_class = WEIGHT_CLASS_GIGANTIC - - var/obj/item/ammo_magazine/tank/ammo - //If we use ammo, put it here - var/obj/item/ammo_magazine/tank/starter_ammo - - //Strings, used to get the overlay for the armored vic - var/disp_icon //This also differentiates tank vs apc vs other - var/disp_icon_state - - var/next_use = 0 - var/is_activatable = FALSE - var/max_angle = 180 - var/point_cost = 0 - - var/list/backup_clips = list() - var/max_clips = 1 //1 so they can reload their backups and actually reload once - var/buyable = TRUE - -/obj/item/hardpoint/Initialize(mapload) - . = ..() - if(starter_ammo) - ammo = new starter_ammo - -/obj/item/hardpoint/examine(mob/user) - . = ..() - var/status = obj_integrity <= 0.1 ? "broken" : "functional" - var/span_class = obj_integrity <= 0.1 ? "" : "" - if((user.skills.getRating(SKILL_ENGINEER) >= SKILL_ENGINEER_METAL) || isobserver(user)) - switch(PERCENT(obj_integrity / max_integrity)) - if(0.1 to 33) - status = "heavily damaged" - span_class = "" - if(33.1 to 66) - status = "damaged" - span_class = "" - if(66.1 to 90) - status = "slighty damaged" - if(90.1 to 100) - status = "intact" - to_chat(user, "[span_class]It's [status].") - -/obj/item/hardpoint/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/ammo_magazine/tank)) - try_add_clip(W, user) - return - if(!iswelder(W) && !iswrench(W)) - return ..() - if(obj_integrity >= max_integrity) - to_chat(user, span_notice("[src] is already in perfect conditions.")) - return - var/repair_delays = 6 - var/obj/item/tool/repair_tool = /obj/item/tool/weldingtool - switch(slot) - if(HDPT_PRIMARY) - repair_delays = 5 - if(HDPT_SECDGUN) - repair_tool = /obj/item/tool/wrench - repair_delays = 3 - if(HDPT_SUPPORT) - repair_tool = /obj/item/tool/wrench - repair_delays = 2 - if(HDPT_ARMOR) - repair_delays = 10 - var/obj/item/tool/weldingtool/WT = iswelder(W) ? W : null - if(!istype(W, repair_tool)) - to_chat(user, span_warning("That's the wrong tool. Use a [WT ? "wrench" : "welder"].")) - return - if(WT && !WT.isOn()) - to_chat(user, span_warning("You need to light your [WT] first.")) - return - user.visible_message(span_notice("[user] starts repairing [src]."), - span_notice("You start repairing [src].")) - if(!do_after(user, 3 SECONDS * repair_delays, NONE, src, BUSY_ICON_BUILD)) - user.visible_message(span_notice("[user] stops repairing [src]."), - span_notice("You stop repairing [src].")) - return - if(WT) - if(!WT.isOn()) - return - WT.remove_fuel(repair_delays, user) - user.visible_message(span_notice("[user] finishes repairing [src]."), - span_notice("You finish repairing [src].")) - repair_damage(max_integrity) - -//Called on attaching, for weapons sets the actual cooldowns -/obj/item/hardpoint/proc/apply_buff() - return - -//Called when removing, resets cooldown lengths, move delay, etc -/obj/item/hardpoint/proc/remove_buff() - return - -//Called when you want to activate the hardpoint, such as a gun -//This can also be used for some type of temporary buff, up to you -/obj/item/hardpoint/proc/active_effect(atom/A) - return - -/obj/item/hardpoint/proc/deactivate() - return - -/obj/item/hardpoint/proc/livingmob_interact(mob/living/M) - return - -//If our cooldown has elapsed -/obj/item/hardpoint/proc/is_ready() - if(world.time < next_use) - to_chat(usr, span_warning("This module is not ready to be used yet.")) - return FALSE - if(!obj_integrity) - to_chat(usr, span_warning("This module is too broken to be used.")) - return FALSE - return TRUE - -/obj/item/hardpoint/proc/try_add_clip(obj/item/ammo_magazine/tank/A, mob/user) - - if(!max_clips) - to_chat(user, span_warning("This module does not have room for additional ammo.")) - return FALSE - else if(length(backup_clips) >= max_clips) - to_chat(user, span_warning("The reloader is full.")) - return FALSE - else if(!istype(A, starter_ammo)) - to_chat(user, span_warning("That is the wrong ammo type.")) - return FALSE - - to_chat(user, span_notice("You start loading [A] in [src].")) - - var/atom/target = owner ? owner : src - - if(!do_after(user, 10, NONE, target) || QDELETED(src)) - to_chat(user, span_warning("Something interrupted you while loading [src].")) - return FALSE - - user.temporarilyRemoveItemFromInventory(A, FALSE) - user.visible_message(span_notice("[user] loads [A] in [src]"), - span_notice("You finish loading [A] in \the [src]."), null, 3) - backup_clips += A - playsound(user.loc, 'sound/weapons/guns/interact/minigun_cocked.ogg', 25) - return TRUE - -//Returns the image object to overlay onto the root object -/obj/item/hardpoint/proc/get_icon_image(x_offset, y_offset, new_dir) - - var/icon_suffix = "NS" - var/icon_state_suffix = "0" - - if(new_dir in list(NORTH, SOUTH)) - icon_suffix = "NS" - else if(new_dir in list(EAST, WEST)) - icon_suffix = "EW" - - if(!obj_integrity) - icon_state_suffix = "1" - - return image(icon = "[disp_icon]_[icon_suffix]", icon_state = "[disp_icon_state]_[icon_state_suffix]", pixel_x = x_offset, pixel_y = y_offset) - -/obj/item/hardpoint/proc/firing_arc(atom/A) - var/turf/T = get_turf(A) - if(!T || !owner) - return FALSE - var/dx = T.x - owner.x - var/dy = T.y - owner.y - var/deg = 0 - switch(owner.dir) - if(EAST) deg = 0 - if(NORTH) deg = -90 - if(WEST) deg = -180 - if(SOUTH) deg = -270 - - var/nx = dx * cos(deg) - dy * sin(deg) - var/ny = dx * sin(deg) + dy * cos(deg) - if(nx == 0) - return max_angle >= 90 - var/angle = arctan(ny/nx) - if(nx < 0) - angle += 180 - return abs(angle) <= max_angle - -//Delineating between slots -/obj/item/hardpoint/primary - slot = HDPT_PRIMARY - is_activatable = TRUE - -/obj/item/hardpoint/secondary - slot = HDPT_SECDGUN - is_activatable = TRUE - -/obj/item/hardpoint/support - slot = HDPT_SUPPORT - -/obj/item/hardpoint/armor - slot = HDPT_ARMOR - max_clips = 0 - -/obj/item/hardpoint/treads - slot = HDPT_TREADS - max_clips = 0 - gender = PLURAL - -//////////////////// -// PRIMARY SLOTS // START -//////////////////// - -/obj/item/hardpoint/primary/cannon - name = "LTB Cannon" - desc = "A primary cannon for tanks that shoots explosive rounds" - - max_integrity = 500 - point_cost = 100 - - icon_state = "ltb_cannon" - - disp_icon = "tank" - disp_icon_state = "ltb_cannon" - - starter_ammo = /obj/item/ammo_magazine/tank/ltb_cannon - max_clips = 3 - max_angle = 45 - -/obj/item/hardpoint/primary/cannon/broken - obj_integrity = 0 - buyable = FALSE - -/obj/item/hardpoint/primary/cannon/apply_buff() - owner.internal_cooldowns["primary"] = 200 - owner.accuracies["primary"] = 0.97 - -/obj/item/hardpoint/primary/cannon/active_effect(atom/A) - - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - - next_use = world.time + owner.internal_cooldowns["primary"] * owner.misc_ratios["prim_cool"] - var/obj/item/hardpoint/secondary/towlauncher/HP = owner.hardpoints[HDPT_SECDGUN] - if(istype(HP)) - HP.next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"] - - var/delay = 5 - var/turf/T = get_turf(A) - if(!T) - return - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - var/obj/effect/overlay/temp/tank_laser/TL - if(C.is_zoomed) - delay = 20 - TL = new /obj/effect/overlay/temp/tank_laser (T) - - to_chat(usr, span_warning("Preparing to fire... keep the tank still for [delay * 0.1] seconds.")) - - if(!do_after(usr, delay, IGNORE_HELD_ITEM, src) || QDELETED(owner)) - to_chat(usr, span_warning("The [name]'s firing was interrupted.")) - qdel(TL) - - return - - qdel(TL) - - if(!prob(owner.accuracies["primary"] * 100 * owner.misc_ratios["prim_acc"])) - T = get_step(T, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - log_bomber(usr, "fired", src) - P.fire_at(T, owner, src, P.ammo.max_range, P.ammo.shell_speed) - playsound(get_turf(src), pick('sound/weapons/guns/fire/tank_cannon1.ogg', 'sound/weapons/guns/fire/tank_cannon2.ogg'), 60, 1) - ammo.current_rounds-- - -/obj/item/hardpoint/primary/minigun - name = "LTAA-AP Minigun" - desc = "A primary weapon for tanks that spews bullets" - - max_integrity = 350 - point_cost = 100 - - icon_state = "ltaaap_minigun" - - disp_icon = "tank" - disp_icon_state = "ltaaap_minigun" - - starter_ammo = /obj/item/ammo_magazine/tank/ltaaap_minigun - max_angle = 45 - - //Miniguns don't use a conventional cooldown - //If you fire quickly enough, the cooldown decreases according to chain_delays - //If you fire too slowly, you slowly slow back down - //Also, different sounds play and it sounds sick, thanks Rahlzel - var/chained = 0 //how many quick succession shots we've fired - var/list/chain_delays = list(4, 4, 3, 3, 2, 2, 2, 1, 1) //the different cooldowns in deciseconds, sequentially - - //MAIN PROBLEM WITH THIS IMPLEMENTATION OF DELAYS: - //If you spin all the way up and then stop firing, your chained shots will only decrease by 1 - //TODO: Implement a rolling average for seconds per shot that determines chain length without being slow or buggy - //You'd probably have to normalize it between the length of the list and the actual ROF - //But you don't want to map it below a certain point probably since seconds per shot would go to infinity - - //So, I came back to this and changed it by adding a fixed reset at 1.5 seconds or later, which seems reasonable - //Now the cutoff is a little abrupt, but at least it exists. --MadSnailDisease - -/obj/item/hardpoint/primary/minigun/apply_buff() - owner.internal_cooldowns["primary"] = 2 //will be overridden, please ignore - owner.accuracies["primary"] = 0.33 - -/obj/item/hardpoint/primary/minigun/active_effect(atom/A) - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - var/S = 'sound/weapons/guns/fire/tank_minigun_start.ogg' - if(world.time - next_use <= 5) - chained++ //minigun spins up, minigun spins down - S = 'sound/weapons/guns/fire/tank_minigun_loop.ogg' - else if(world.time - next_use >= 15) //Too long of a delay, they restart the chain - chained = 1 - else //In between 5 and 15 it slows down but doesn't stop - chained-- - S = 'sound/weapons/guns/fire/tank_minigun_stop.ogg' - if(chained <= 0) - chained = 1 - - next_use = world.time + (chained > length(chain_delays) ? 0.5 : chain_delays[chained]) * owner.misc_ratios["prim_cool"] - if(!prob(owner.accuracies["primary"] * 100 * owner.misc_ratios["prim_acc"])) - A = get_step(A, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed) - - playsound(get_turf(src), S, 60) - ammo.current_rounds-- - -//////////////////// -// PRIMARY SLOTS // END -//////////////////// - -///////////////////// -// SECONDARY SLOTS // START -///////////////////// - -/obj/item/hardpoint/secondary/flamer - name = "Secondary Flamer Unit" - desc = "A secondary weapon for tanks that shoots flames" - - max_integrity = 300 - point_cost = 100 - - icon_state = "flamer" - - disp_icon = "tank" - disp_icon_state = "flamer" - - starter_ammo = /obj/item/ammo_magazine/tank/flamer - max_angle = 90 - -/obj/item/hardpoint/secondary/flamer/apply_buff() - owner.internal_cooldowns["secondary"] = 20 - owner.accuracies["secondary"] = 0.5 - -/obj/item/hardpoint/secondary/flamer/active_effect(atom/A) - - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - - next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"] - if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"])) - A = get_step(A, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed) - playsound(get_turf(src), 'sound/weapons/guns/fire/tank_flamethrower.ogg', 60, 1) - ammo.current_rounds-- - -/obj/item/hardpoint/secondary/towlauncher - name = "TOW Launcher" - desc = "A secondary weapon for tanks that shoots rockets" - - max_integrity = 500 - point_cost = 100 - - icon_state = "tow_launcher" - - disp_icon = "tank" - disp_icon_state = "towlauncher" - - starter_ammo = /obj/item/ammo_magazine/tank/towlauncher - max_clips = 1 - max_angle = 90 - -/obj/item/hardpoint/secondary/towlauncher/apply_buff() - owner.internal_cooldowns["secondary"] = 150 - owner.accuracies["secondary"] = 0.8 - -/obj/item/hardpoint/secondary/towlauncher/active_effect(atom/A) - - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - - var/delay = 3 - var/turf/T = get_turf(A) - if(!T) - return - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - var/obj/effect/overlay/temp/tank_laser/TL - if(C.is_zoomed) - delay = 15 - TL = new /obj/effect/overlay/temp/tank_laser (T) - - to_chat(usr, span_warning("Preparing to fire... keep the tank still for [delay * 0.1] seconds.")) - - if(!do_after(usr, delay, IGNORE_HELD_ITEM, src) || QDELETED(owner)) - to_chat(usr, span_warning("The [name]'s firing was interrupted.")) - qdel(TL) - return - - qdel(TL) - - next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"] - var/obj/item/hardpoint/primary/cannon/HP = owner.hardpoints[HDPT_PRIMARY] - if(istype(HP)) - HP.next_use = world.time + owner.internal_cooldowns["primary"] * owner.misc_ratios["prim_cool"] - - if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"])) - T = get_step(T, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - log_bomber(usr, "fired", src) - P.fire_at(T, owner, src, P.ammo.max_range, P.ammo.shell_speed) - ammo.current_rounds-- - -/obj/item/hardpoint/secondary/m56cupola/broken - obj_integrity = 0 - buyable = FALSE - -/obj/item/hardpoint/secondary/m56cupola/apply_buff() - owner.internal_cooldowns["secondary"] = 3 - owner.accuracies["secondary"] = 0.7 - -/obj/item/hardpoint/secondary/m56cupola/active_effect(atom/A) - - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - - next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"] - if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"])) - A = get_step(A, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed) - playsound(get_turf(src), pick(list('sound/weapons/guns/fire/smartgun1.ogg', 'sound/weapons/guns/fire/smartgun2.ogg', 'sound/weapons/guns/fire/smartgun3.ogg')), 60, 1) - ammo.current_rounds-- - -/obj/item/hardpoint/secondary/grenade_launcher - name = "Grenade Launcher" - desc = "A secondary weapon for tanks that shoots grenades" - - max_integrity = 500 - point_cost = 25 - - icon_state = "glauncher" - - disp_icon = "tank" - disp_icon_state = "glauncher" - - starter_ammo = /obj/item/ammo_magazine/tank/tank_glauncher - max_clips = 3 - max_angle = 90 - -/obj/item/hardpoint/secondary/grenade_launcher/apply_buff() - owner.internal_cooldowns["secondary"] = 30 - owner.accuracies["secondary"] = 0.4 - -/obj/item/hardpoint/secondary/grenade_launcher/active_effect(atom/A) - - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - - next_use = world.time + owner.internal_cooldowns["secondary"] * owner.misc_ratios["secd_cool"] - if(!prob(owner.accuracies["secondary"] * 100 * owner.misc_ratios["secd_acc"])) - A = get_step(A, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - log_bomber(usr, "fired", src) - P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed) - playsound(get_turf(src), 'sound/weapons/guns/fire/grenadelauncher.ogg', 60, 1) - ammo.current_rounds-- -///////////////////// -// SECONDARY SLOTS // END -///////////////////// - -/////////////////// -// SUPPORT SLOTS // START -/////////////////// - -/obj/item/hardpoint/support/smoke_launcher - name = "Smoke Launcher" - desc = "Launches smoke forward to obscure vision" - - max_integrity = 300 - point_cost = 10 - - icon_state = "slauncher_0" - - disp_icon = "tank" - disp_icon_state = "slauncher" - - starter_ammo = /obj/item/ammo_magazine/tank/tank_slauncher - max_clips = 4 - is_activatable = TRUE - -/obj/item/hardpoint/support/smoke_launcher/broken - obj_integrity = 0 - buyable = FALSE - -/obj/item/hardpoint/support/smoke_launcher/apply_buff() - owner.internal_cooldowns["support"] = 30 - owner.accuracies["support"] = 0.8 - -/obj/item/hardpoint/support/smoke_launcher/active_effect(atom/A) - - if(!(ammo?.current_rounds > 0)) - to_chat(usr, span_warning("This module does not have any ammo.")) - return - - next_use = world.time + owner.internal_cooldowns["support"] * owner.misc_ratios["supp_cool"] - if(!prob(owner.accuracies["support"] * 100 * owner.misc_ratios["supp_acc"])) - A = get_step(A, pick(GLOB.cardinals)) - var/obj/projectile/P = new - P.generate_bullet(new ammo.default_ammo) - P.fire_at(A, owner, src, P.ammo.max_range, P.ammo.shell_speed) - playsound(get_turf(src), 'sound/weapons/guns/fire/tank_smokelauncher.ogg', 60, 1) - ammo.current_rounds-- - -/obj/item/hardpoint/support/smoke_launcher/get_icon_image(x_offset, y_offset, new_dir) - - var/icon_suffix = "NS" - var/icon_state_suffix = "0" - - if(new_dir in list(NORTH, SOUTH)) - icon_suffix = "NS" - else if(new_dir in list(EAST, WEST)) - icon_suffix = "EW" - - if(!obj_integrity) - icon_state_suffix = "1" - else if(!(ammo?.current_rounds > 0)) - icon_state_suffix = "2" - - return image(icon = "[disp_icon]_[icon_suffix]", icon_state = "[disp_icon_state]_[icon_state_suffix]", pixel_x = x_offset, pixel_y = y_offset) - -/obj/item/hardpoint/support/weapons_sensor - name = "Integrated Weapons Sensor Array" - desc = "Improves the accuracy and fire rate of all onboard weapons" - - max_integrity = 250 - point_cost = 100 - max_clips = 0 - - icon_state = "warray" - - disp_icon = "tank" - disp_icon_state = "warray" - -/obj/item/hardpoint/support/weapons_sensor/apply_buff() - owner.misc_ratios["prim_cool"] = 0.67 - owner.misc_ratios["secd_cool"] = 0.67 - owner.misc_ratios["supp_cool"] = 0.67 - - owner.misc_ratios["prim_acc"] = 1.67 - owner.misc_ratios["secd_acc"] = 1.67 - owner.misc_ratios["supp_acc"] = 1.67 - -/obj/item/hardpoint/support/weapons_sensor/remove_buff() - owner.misc_ratios["prim_cool"] = 1 - owner.misc_ratios["secd_cool"] = 1 - owner.misc_ratios["supp_cool"] = 1 - - owner.misc_ratios["prim_acc"] = 1 - owner.misc_ratios["secd_acc"] = 1 - owner.misc_ratios["supp_acc"] = 1 - -/obj/item/hardpoint/support/overdrive_enhancer - name = "Overdrive Enhancer" - desc = "Increases the movement speed of the vehicle it's atached to" - - max_integrity = 250 - point_cost = 100 - max_clips = 0 - - icon_state = "odrive_enhancer" - is_activatable = TRUE - - disp_icon = "tank" - disp_icon_state = "odrive_enhancer" - - var/last_boost - -/obj/item/hardpoint/support/overdrive_enhancer/proc/nitros_on(mob/M) - owner.misc_ratios["move"] = 0.2 - if(M) - to_chat(M, span_danger("You hit the nitros! RRRRRRRMMMM!!")) - playsound(M, 'sound/mecha/hydraulic.ogg', 60, 1, vary = 0) - addtimer(CALLBACK(src, PROC_REF(boost_off)), TANK_OVERDRIVE_BOOST_DURATION) - addtimer(CALLBACK(src, PROC_REF(boost_ready_notice)), TANK_OVERDRIVE_BOOST_COOLDOWN) - -/obj/item/hardpoint/support/overdrive_enhancer/remove_buff() - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - C.verbs -= /obj/vehicle/multitile/root/cm_armored/tank/verb/overdrive_multitile - boost_off() - -/obj/item/hardpoint/support/overdrive_enhancer/apply_buff() - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - C.verbs += /obj/vehicle/multitile/root/cm_armored/tank/verb/overdrive_multitile - -/obj/item/hardpoint/support/overdrive_enhancer/proc/boost_off() - owner.misc_ratios["move"] = 1 - -/obj/item/hardpoint/support/overdrive_enhancer/proc/boost_ready_notice() - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - if(C.driver) - to_chat(C.driver, span_danger("The overdrive nitros are ready for use.")) - -/obj/item/hardpoint/support/overdrive_enhancer/proc/activate_overdrive() - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - if(!C.driver) - return - if(world.time < last_boost + TANK_OVERDRIVE_BOOST_COOLDOWN) - to_chat(C.driver, span_warning("Your nitro overdrive isn't yet ready. It will be available again in [(last_boost + TANK_OVERDRIVE_BOOST_COOLDOWN - world.time) * 0.1] seconds.")) - return - last_boost = world.time - nitros_on(C.driver) - -//How to get out, via verb -/obj/vehicle/multitile/root/cm_armored/tank/verb/overdrive_multitile() - set category = "Vehicle" - set name = "Activate Overdrive" - set src in view(0) - - if(usr.incapacitated(TRUE)) - return - - if(usr != driver) - to_chat(usr, span_warning("You need to be in the driver seat to use this!")) - return - - var/obj/item/hardpoint/support/overdrive_enhancer/OE = hardpoints[HDPT_SUPPORT] - if(!istype(OE, /obj/item/hardpoint/support/overdrive_enhancer) || OE.obj_integrity <= 0) - to_chat(usr, span_warning("The overdrive engine is missing or too badly damaged!")) - return - OE.activate_overdrive(usr) - -/obj/item/hardpoint/support/artillery_module - name = "Artillery Module" - desc = "Allows the gunner to look far into the distance." - - max_integrity = 250 - point_cost = 100 - max_clips = 0 - - is_activatable = TRUE - var/is_active = FALSE - - var/view_buff = "25x25" //This way you can VV for more or less fun - var/view_tile_offset = 5 - - icon_state = "artillery" - - disp_icon = "tank" - disp_icon_state = "artillerymod" - -/obj/item/hardpoint/support/artillery_module/active_effect(atom/A) - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - if(!C.gunner) - return - var/mob/M = C.gunner - if(!M.client) - return - if(is_active) - M.client.view_size.reset_to_default() - M.client.pixel_x = 0 - M.client.pixel_y = 0 - is_active = FALSE - C.is_zoomed = FALSE - return - M.client.view_size.reset_to_default() - is_active = TRUE - C.is_zoomed = TRUE - switch(C.dir) - if(NORTH) - M.client.pixel_x = 0 - M.client.pixel_y = view_tile_offset * 32 - if(SOUTH) - M.client.pixel_x = 0 - M.client.pixel_y = -1 * view_tile_offset * 32 - if(EAST) - M.client.pixel_x = view_tile_offset * 32 - M.client.pixel_y = 0 - if(WEST) - M.client.pixel_x = -1 * view_tile_offset * 32 - M.client.pixel_y = 0 - -/obj/item/hardpoint/support/artillery_module/deactivate() - var/obj/vehicle/multitile/root/cm_armored/tank/C = owner - if(!ismob(C.gunner)) - return - var/mob/M = C.gunner - if(!M.client) - return - is_active = FALSE - M.client.view_size.reset_to_default() - M.client.pixel_x = 0 - M.client.pixel_y = 0 - -/obj/item/hardpoint/support/artillery_module/remove_buff() - deactivate() - -/obj/item/hardpoint/support/artillery_module/is_ready() - if(!obj_integrity) - to_chat(usr, span_warning("This module is too broken to be used.")) - return FALSE - return TRUE - -/////////////////// -// SUPPORT SLOTS // END -/////////////////// - -///////////////// -// ARMOR SLOTS // START -///////////////// - -/obj/item/hardpoint/armor/ballistic - name = "Ballistic Armor" - desc = "Protects the vehicle from high-penetration weapons. Provides some protection against slashing and high impact attacks." - - max_integrity = 1000 - point_cost = 100 - - icon_state = "ballistic_armor" - - disp_icon = "tank" - disp_icon_state = "ballistic_armor" - -/obj/item/hardpoint/armor/ballistic/broken - obj_integrity = 0 - buyable = FALSE - -/obj/item/hardpoint/armor/ballistic/apply_buff() - owner.dmg_multipliers["bullet"] = 0.5 - owner.dmg_multipliers["slash"] = 0.75 - owner.dmg_multipliers["blunt"] = 0.75 - owner.dmg_multipliers["all"] = 0.9 - -/obj/item/hardpoint/armor/ballistic/remove_buff() - owner.dmg_multipliers["bullet"] = 1 - owner.dmg_multipliers["slash"] = 1 - owner.dmg_multipliers["blunt"] = 1 - owner.dmg_multipliers["all"] = 1 - -/obj/item/hardpoint/armor/caustic - name = "Caustic Armor" - desc = "Protects vehicles from most types of acid. Provides some protection against slashing and high impact attacks." - - max_integrity = 1000 - point_cost = 100 - - icon_state = "caustic_armor" - - disp_icon = "tank" - disp_icon_state = "caustic_armor" - -/obj/item/hardpoint/armor/caustic/apply_buff() - owner.dmg_multipliers["acid"] = 0.5 - owner.dmg_multipliers["slash"] = 0.75 - owner.dmg_multipliers["blunt"] = 0.75 - owner.dmg_multipliers["all"] = 0.9 - -/obj/item/hardpoint/armor/caustic/remove_buff() - owner.dmg_multipliers["acid"] = 1 - owner.dmg_multipliers["slash"] = 1 - owner.dmg_multipliers["blunt"] = 1 - owner.dmg_multipliers["all"] = 1 - -/obj/item/hardpoint/armor/concussive - name = "Concussive Armor" - desc = "Protects the vehicle from high-impact weapons. Provides some protection against ballistic and explosive attacks." - - max_integrity = 1000 - point_cost = 100 - - icon_state = "concussive_armor" - - disp_icon = "tank" - disp_icon_state = "concussive_armor" - -/obj/item/hardpoint/armor/concussive/apply_buff() - owner.dmg_multipliers["blunt"] = 0.5 - owner.dmg_multipliers["explosive"] = 0.75 - owner.dmg_multipliers["ballistic"] = 0.75 - owner.dmg_multipliers["all"] = 0.9 - -/obj/item/hardpoint/armor/concussive/remove_buff() - owner.dmg_multipliers["blunt"] = 1 - owner.dmg_multipliers["explosive"] = 1 - owner.dmg_multipliers["ballistic"] = 1 - owner.dmg_multipliers["all"] = 1 - -/obj/item/hardpoint/armor/paladin - name = "Paladin Armor" - desc = "Protects the vehicle from large incoming explosive projectiles. Provides some protection against slashing and high impact attacks." - - max_integrity = 1000 - point_cost = 100 - - icon_state = "paladin_armor" - - disp_icon = "tank" - disp_icon_state = "paladin_armor" - -/obj/item/hardpoint/armor/paladin/apply_buff() - owner.dmg_multipliers["explosive"] = 0.5 - owner.dmg_multipliers["blunt"] = 0.75 - owner.dmg_multipliers["slash"] = 0.75 - owner.dmg_multipliers["all"] = 0.9 - -/obj/item/hardpoint/armor/paladin/remove_buff() - owner.dmg_multipliers["explosive"] = 1 - owner.dmg_multipliers["blunt"] = 1 - owner.dmg_multipliers["slash"] = 1 - owner.dmg_multipliers["all"] = 1 - -/obj/item/hardpoint/armor/snowplow - name = "Snowplow" - desc = "Clears a path in the snow for friendlies" - - max_integrity = 700 - is_activatable = TRUE - point_cost = 50 - - icon_state = "snowplow" - - disp_icon = "tank" - disp_icon_state = "snowplow" - -/obj/item/hardpoint/armor/snowplow/livingmob_interact(mob/living/M) - var/turf/targ = get_step(M, owner.dir) - targ = get_step(M, owner.dir) - targ = get_step(M, owner.dir) - M.throw_at(targ, 4, 2, src, 1) - M.apply_damage(7 + rand(0, 3), BRUTE, blocked = MELEE) - -///////////////// -// ARMOR SLOTS // END -///////////////// - -///////////////// -// TREAD SLOTS // START -///////////////// - -/obj/item/hardpoint/treads/standard - name = "Treads" - desc = "Integral to the movement of the vehicle" - - max_integrity = 500 - point_cost = 25 - - icon_state = "treads" - - disp_icon = "tank" - disp_icon_state = "treads" - -/obj/item/hardpoint/treads/standard/broken - obj_integrity = 0 - buyable = FALSE - -/obj/item/hardpoint/treads/standard/get_icon_image(x_offset, y_offset, new_dir) - return null //Handled in update_icon() - -/obj/item/hardpoint/treads/standard/apply_buff() - owner.move_delay = 7 - -/obj/item/hardpoint/treads/standard/remove_buff() - owner.move_delay = 30 - -///////////////// -// TREAD SLOTS // END -///////////////// - - -/////////////// -// AMMO MAGS // START -/////////////// - -//Special ammo magazines for hardpoint modules. Some aren't here since you can use normal magazines on them -/obj/item/ammo_magazine/tank - flags_magazine = NONE //No refilling - var/point_cost = 0 - -/obj/item/ammo_magazine/tank/ltb_cannon - name = "LTB Cannon Magazine" - desc = "A primary armament cannon magazine" - caliber = CALIBER_86 //Making this unique on purpose - icon_state = "ltbcannon_4" - w_class = WEIGHT_CLASS_GIGANTIC - default_ammo = /datum/ammo/rocket/ltb - max_rounds = 4 - point_cost = 50 - -/obj/item/ammo_magazine/tank/ltb_cannon/update_icon() - icon_state = "ltbcannon_[current_rounds]" - - -/obj/item/ammo_magazine/tank/ltaaap_minigun - name = "LTAA-AP Minigun Magazine" - desc = "A primary armament minigun magazine" - caliber = CALIBER_762X51 //Correlates to miniguns - icon_state = "painless" - w_class = WEIGHT_CLASS_GIGANTIC - default_ammo = /datum/ammo/bullet/minigun - max_rounds = 500 - point_cost = 25 - - - -/obj/item/ammo_magazine/tank/flamer - name = "Flamer Magazine" - desc = "A secondary armament flamethrower magazine" - caliber = CALIBER_FUEL_THICK //correlates to flamer mags - icon_state = "flametank_large" - w_class = WEIGHT_CLASS_GIGANTIC - default_ammo = /datum/ammo/flamethrower/tank_flamer - max_rounds = 120 - point_cost = 50 - - - -/obj/item/ammo_magazine/tank/towlauncher - name = "TOW Launcher Magazine" - desc = "A secondary armament rocket magazine" - caliber = CALIBER_84MM //correlates to any rocket mags - icon_state = "quad_rocket" - w_class = WEIGHT_CLASS_GIGANTIC - default_ammo = /datum/ammo/rocket/ap //Fun fact, AP rockets seem to be a straight downgrade from normal rockets. Maybe I'm missing something... - max_rounds = 5 - point_cost = 100 - -/obj/item/ammo_magazine/tank/tank_glauncher - name = "Grenade Launcher Magazine" - desc = "A secondary armament grenade magazine" - caliber = CALIBER_40MM - icon_state = "glauncher_2" - w_class = WEIGHT_CLASS_GIGANTIC - default_ammo = /datum/ammo/grenade_container - max_rounds = 10 - point_cost = 25 - - -/obj/item/ammo_magazine/tank/tank_glauncher/update_icon() - if(current_rounds >= max_rounds) - icon_state = "glauncher_2" - else if(current_rounds <= 0) - icon_state = "glauncher_0" - else - icon_state = "glauncher_1" - - -/obj/item/ammo_magazine/tank/tank_slauncher - name = "Smoke Launcher Magazine" - desc = "A support armament grenade magazine" - caliber = CALIBER_40MM - icon_state = "slauncher_1" - w_class = WEIGHT_CLASS_GIGANTIC - default_ammo = /datum/ammo/grenade_container/smoke - max_rounds = 6 - point_cost = 5 - -/obj/item/ammo_magazine/tank/tank_slauncher/update_icon() - icon_state = "slauncher_[current_rounds <= 0 ? "0" : "1"]" - -/////////////// -// AMMO MAGS // END -/////////////// diff --git a/code/modules/vehicles/multitile/multitile.dm b/code/modules/vehicles/multitile/multitile.dm deleted file mode 100644 index 784a98157af..00000000000 --- a/code/modules/vehicles/multitile/multitile.dm +++ /dev/null @@ -1,246 +0,0 @@ - -/* -A multitile vehicle is made up of 2 types of objects, root and hitbox -relaymove() only does something for root -You can inherit and do special stuff for either, but only one will let you move -Rotations treat root as x = 0, y = 0 -All of the backend for movement will be under root - -Vehicles are placed on the map by a spawner or admin verb -*/ - -//This was part of an old plan to have a dynamic number of vehicle interiors -//Turns out that's incredibly fucking dificult, so a fixed number is gonna be the ideal choice -/* -/obj/effect/landmark/multitile_starter - name = "Landmark" - desc = "Where the interiors for multitiles start spawning" -*/ - -/obj/effect/multitile_spawner - - var/width = 2 - var/height = 3 - var/spawn_dir = SOUTH - -//A hidden marker for where you mount and dismount the vehicle -//You could have multiple if you wanted -/obj/effect/multitile_entrance - name = "Entrance marker" - desc = "Marker for the entrance of a multitile vehicle." - - var/obj/vehicle/multitile/root/master - invisibility = INVISIBILITY_MAXIMUM - -/obj/effect/multitile_entrance/Destroy(force = FALSE) - if(!force) - return QDEL_HINT_LETMELIVE - return ..() - -//Always moves where you want it to, no matter what -/obj/effect/multitile_entrance/Move(atom/A) - loc = get_turf(A) - return TRUE - -//A basic handoff to the root object to actually deal with attempted player entrance -/obj/effect/multitile_entrance/verb/enter_multitile() - set category = "Vehicle" - set name = "Enter Vehicle" - set src in view(0) - - master.handle_player_entrance(usr) - -//Remnant of vehicle interiors -/* -/obj/effect/landmark/multitile_exit - name = "Landmark" - desc = "Marker for the exit of the interior" - - invisibility = INVISIBILITY_MAXIMUM - - var/obj/vehicle/multitile/root/master -*/ - -/* -/obj/effect/landmark/multitile_exit/verb/exit_multitile(mob/M) - set category = "Vehicle" - set name = "Exit Vehicle" - set src in master - - master.handle_player_exit(M) -*/ - -//Super super generic, doesn't really need to exist -/obj/vehicle/multitile - name = "multitile vehicle" - desc = "You shouldn't see this" - -/obj/vehicle/multitile/relaymove(mob/user, direction) - return - -//Hitboxes, do notthing but move with the root object and take up space -//All interactions like bullets or whatever should be passed up to the root object -/obj/vehicle/multitile/hitbox - name = "hitbox" - desc = "Generic multitile vehicle hitbox" - - var/obj/vehicle/multitile/root/root - invisibility = INVISIBILITY_MAXIMUM - -/obj/vehicle/multitile/root - name = "root" - desc = "Root tile for multitile vehicles" - - var/old_dir - - var/obj/effect/multitile_entrance/entrance - //var/obj/effect/landmark/multitile_exit/exit - - //Objects that move in accordance with this one - //Objects indexed by /datum/coords - //Does not include the root obj - var/list/linked_objs = list() - - //list of turfs that the vehicle was in before - var/list/old_locs = list() - - //list of idle passengers in the vehicle - //used for any type of APC - var/list/idle_passengers = list() - var/max_idle_passengers = 0 - - //Another remnant of vehicle interiors - //var/list/interior_data = list() - - var/base_icon_type = "" //e.g. "tank" or "apc", used to assign icons to the hitboxes - - var/hitbox_type = /obj/vehicle/multitile/hitbox - -//How to get out, via verb -/obj/vehicle/multitile/root/verb/exit_multitile() - set category = "Vehicle" - set name = "Exit Vehicle" - set src in view(0) - - if(!usr.incapacitated(TRUE)) - handle_player_exit(usr) - -/obj/vehicle/multitile/root/proc/handle_player_exit(mob/M) - return - -/obj/vehicle/multitile/root/proc/handle_player_entrance(mob/living/M) - if(M.resting || M.buckled || M.incapacitated()) - return FALSE - return TRUE - -/obj/vehicle/multitile/root/proc/handle_harm_attack(mob/living/M) - if(M.resting || M.buckled || M.incapacitated()) - return FALSE - return TRUE - -//Vebrs for rotations, set up a macro and get turnin -/obj/vehicle/multitile/root/verb/clockwise_rotate_multitile() - set category = "Vehicle" - set name = "Rotate Vehicle Clockwise" - set src in view(0) - - var/mob/M = usr - try_rotate(-90, M) - -/obj/vehicle/multitile/root/verb/counterclockwise_rotate_multitile() - set category = "Vehicle" - set name = "Rotate Vehicle Counterclockwise" - set src in view(0) - - var/mob/M = usr - try_rotate(90, M) - -//A wrapper for try_move() that rotates -/obj/vehicle/multitile/root/proc/try_rotate(deg, mob/user, force = FALSE) - save_locs() - rotate_coords(deg) - if(!try_move(linked_objs, null, TRUE)) - rotate_coords(-1*deg) - revert_locs() - return FALSE - - update_icon() - return TRUE - -//Called when players try to move from inside the vehicle -//Another wrapper for try_move() -/obj/vehicle/multitile/root/relaymove(mob/user, direction) - if(dir in list(EAST, WEST)) - if(direction == SOUTH) - return try_rotate( (dir == WEST ? 90 : -90), user, 1) - else if(direction == NORTH) - return try_rotate( (dir == EAST ? 90 : -90), user, 1) - - else if(dir in list(SOUTH, NORTH)) - if(direction == EAST) - return try_rotate( (dir == SOUTH ? 90 : -90), user, 1) - else if(direction == WEST) - return try_rotate( (dir == NORTH ? 90 : -90), user, 1) - - old_dir = dir - save_locs() - if(!try_move(linked_objs, direction)) - revert_locs() - setDir(old_dir) - return FALSE //Failed movement - - setDir(old_dir) //Preserve the direction you're facing when moving backwards - return TRUE - - -/obj/vehicle/multitile/root/proc/load_hitboxes() - return - -/obj/vehicle/multitile/root/proc/load_entrance_marker() - return - -//Saves where everything is so we can revert -/obj/vehicle/multitile/root/proc/save_locs() - - - -//We were unable to move, so revert everything we may have done so far -/obj/vehicle/multitile/root/proc/revert_locs() - - -//Forces the root object to move so everything can update relative to it -/obj/vehicle/multitile/root/proc/move_root(direction) - - var/turf/T = get_step(loc, direction) - loc = T - -//The REAL guts of multitile movement -//Here's how this shit works: - -//Step 1: Iterate over every associated object and move what can be moved in the right dir -//Step 2: Save everything that couldn't move in a list -//Step 3: Recursively try to move those after everything else that can move has done so -// This is so if one hitbox is blocking another, eventually they will both move -//Step 4: If on this level of recursion, we couldn't move any more things, we've failed -//Step 5: Continue steps 1 through 4 until we fail or succeed -/obj/vehicle/multitile/root/proc/try_move(list/objs, direction, is_rotation = FALSE) - - var/list/blocked = list() //What couldn't move this time - - - if(length(blocked) == length(objs)) - return FALSE //No more things can move, return false - - else if(length(blocked)) - return try_move(blocked, direction, is_rotation) //Some things moved, retry the others - - else if(!length(blocked)) - return TRUE //Everything finished moving, return true - - else - return FALSE //Shouldn't even be possible, so say we failed anyways - -//Applies the 2D transformation matrix to the saved coords -/obj/vehicle/multitile/root/proc/rotate_coords(deg) - - diff --git a/code/modules/vehicles/multitile/tank.dm b/code/modules/vehicles/multitile/tank.dm deleted file mode 100644 index d7ca9e8d39a..00000000000 --- a/code/modules/vehicles/multitile/tank.dm +++ /dev/null @@ -1,308 +0,0 @@ - -//TANKS, HURRAY -//Read the documentation in cm_armored.dm and multitile.dm before trying to decipher this stuff - - -/obj/vehicle/multitile/root/cm_armored/tank - name = "\improper M34A2 Longstreet Light Tank" - desc = "A giant piece of armor with a big gun, you know what to do. Entrance in the back." - - icon = 'icons/obj/vehicles/tank_NS.dmi' - icon_state = "tank_base" - pixel_x = -32 - pixel_y = -32 - - var/mob/gunner - var/mob/driver - - var/mob/occupant_exiting - var/next_sound_play = 0 - - var/is_zoomed = FALSE - - req_access = list() - -/obj/effect/multitile_spawner/cm_armored/tank - - width = 3 - height = 3 - spawn_dir = EAST - var/list/spawn_hardpoints = list() - -/obj/effect/multitile_spawner/cm_armored/tank/Initialize(mapload) - . = ..() - return INITIALIZE_HINT_QDEL - -//Spawns a tank that has a bunch of broken hardpoints -/obj/effect/multitile_spawner/cm_armored/tank/decrepit - spawn_hardpoints = list(HDPT_PRIMARY = /obj/item/hardpoint/primary/cannon/broken, - HDPT_SECDGUN = /obj/item/hardpoint/secondary/m56cupola/broken, - HDPT_SUPPORT = /obj/item/hardpoint/support/smoke_launcher/broken, - HDPT_ARMOR = /obj/item/hardpoint/armor/ballistic/broken, - HDPT_TREADS = /obj/item/hardpoint/treads/standard/broken) - -/obj/effect/multitile_spawner/cm_armored/tank/fixed - spawn_hardpoints = list(HDPT_PRIMARY = /obj/item/hardpoint/primary/cannon, - HDPT_SECDGUN = /obj/item/hardpoint/secondary/m56cupola, - HDPT_SUPPORT = /obj/item/hardpoint/support/smoke_launcher, - HDPT_ARMOR = /obj/item/hardpoint/armor/ballistic, - HDPT_TREADS = /obj/item/hardpoint/treads/standard) - -//For the tank, start forcing people out if everything is broken -/obj/vehicle/multitile/root/cm_armored/tank/handle_all_modules_broken() - deactivate_all_hardpoints() - - if(driver) - to_chat(driver, span_danger("You dismount to as the smoke and flames start to choke you!")) - driver.Move(entrance.loc) - driver.unset_interaction() - driver = null - else if(gunner) - to_chat(gunner, span_danger("You dismount to as the smoke and flames start to choke you!")) - gunner.Move(entrance.loc) - gunner.unset_interaction() - gunner = null - -/obj/vehicle/multitile/root/cm_armored/tank/remove_all_players() - deactivate_all_hardpoints() - for(var/mob/living/L in (contents + loc.contents)) - if(!entrance) //Something broke, uh oh - forceMove(get_turf(src)) - else - forceMove(get_turf(entrance)) - gunner = null - driver = null - -//Let's you switch into the other seat, doesn't work if it's occupied -/obj/vehicle/multitile/root/cm_armored/tank/verb/switch_seats() - set name = "Swap Seats" - set category = "Vehicle" - set src in view(0) - - if(usr.incapacitated()) - return - - var/wannabe_trucker = (usr == gunner) ? TRUE : FALSE - var/neighbour = wannabe_trucker ? driver : gunner - if(neighbour) - to_chat(usr, span_notice("There's already someone in the other seat.")) - return - - to_chat(usr, span_notice("You start getting into the other seat.")) - addtimer(CALLBACK(src, PROC_REF(seat_switched), wannabe_trucker, usr), 3 SECONDS) - -/obj/vehicle/multitile/root/cm_armored/tank/proc/seat_switched(wannabe_trucker, mob/living/user) - - var/player = wannabe_trucker ? gunner : driver - var/challenger = wannabe_trucker ? driver : gunner - if(QDELETED(user) || user.incapacitated() || player != user) - return - - if(challenger) - to_chat(usr, span_notice("Someone beat you to the other seat!")) - return - - to_chat(usr, span_notice("You man up the [wannabe_trucker ? "driver" : "gunner"]'s seat.")) - - if(wannabe_trucker) - deactivate_all_hardpoints() - driver = wannabe_trucker ? user : null - gunner = wannabe_trucker ? null : user - -/obj/vehicle/multitile/root/cm_armored/tank/can_use_hp(mob/M) - if(!M || M != gunner) - return FALSE - if(!M.dextrous) - to_chat(M, span_warning("You don't have the dexterity to do this!")) - return FALSE - return !M.incapacitated() - -/obj/vehicle/multitile/root/cm_armored/tank/handle_harm_attack(mob/M, mob/occupant) - . = ..() - if(!.) - return - if(!occupant) - to_chat(M, span_warning("There is no one on that seat.")) - return - M.visible_message(span_warning("[M] starts pulling [occupant] out of \the [src]."), - span_warning("You start pulling [occupant] out of \the [src]. (this will take a while...)"), null, 6) - var/fumbling_time = 20 SECONDS - 2 SECONDS * M.skills.getRating(SKILL_POLICE) - 2 SECONDS * M.skills.getRating(SKILL_LARGE_VEHICLE) - if(!do_after(M, fumbling_time, NONE, src, BUSY_ICON_HOSTILE)) - return - exit_tank(occupant, TRUE, TRUE) - M.visible_message(span_warning("[M] forcibly pulls [occupant] out of [src]."), - span_notice("you forcibly pull [occupant] out of [src]."), null, 6) - if(!isliving(occupant)) - return - var/mob/living/L = occupant - L.Paralyze(8 SECONDS) - -//Two seats, gunner and driver -//Must have the skills to do so -/obj/vehicle/multitile/root/cm_armored/tank/handle_player_entrance(mob/living/carbon/M) - . = ..() - if(!. || !istype(M) || M.do_actions) - return - - var/slot = tgui_alert(M, "Select a seat", null, list("Driver", "Gunner")) - if(!Adjacent(M)) - return - - var/occupant = (slot == "Driver") ? driver : gunner - if((M.a_intent == INTENT_HARM || isxeno(M)) && occupant) - handle_harm_attack(M, occupant) - return - - if(!M.dextrous) - to_chat(M, span_warning("You don't have the dexterity to drive [src]!")) - return - if(!allowed(M)) - to_chat(M, span_warning("Access denied.")) - return - if(occupant) - to_chat(M, span_warning("That seat is already taken.")) - return - var/obj/item/offhand = M.get_inactive_held_item() - if(offhand && !(HAS_TRAIT(offhand, TRAIT_NODROP) || (offhand.flags_item & (DELONDROP|ITEM_ABSTRACT)))) - to_chat(M, span_warning("You need your hands free to climb on [src].")) - return - - if(M.skills.getRating(SKILL_LARGE_VEHICLE) < SKILL_LARGE_VEHICLE_TRAINED) - M.visible_message(span_notice("[M] fumbles around figuring out how to get into the [src]."), - span_notice("You fumble around figuring out how to get into [src].")) - var/fumbling_time = 10 SECONDS - 2 SECONDS * M.skills.getRating(SKILL_LARGE_VEHICLE) - if(!do_after(M, fumbling_time, NONE, src, BUSY_ICON_UNSKILLED) || \ - (offhand && !(HAS_TRAIT(offhand, TRAIT_NODROP) || (offhand.flags_item & DELONDROP)))) - return - - to_chat(M, span_notice("You start climbing into [src].")) - if(!do_after(M, 10 SECONDS, NONE, src, BUSY_ICON_GENERIC) || \ - (offhand && !(HAS_TRAIT(offhand, TRAIT_NODROP) || (offhand.flags_item & DELONDROP)))) - return - if(occupant) - to_chat(M, span_warning("Someone got into the [lowertext(slot)]'s seat before you could.")) - return - - if(slot == "Driver") - driver = M - else - gunner = M - M.forceMove(src) - to_chat(M, span_notice("You enter into the [lowertext(slot)]'s seat.")) - M.set_interaction(src) - -//Deposits you onto the exit marker -/obj/vehicle/multitile/root/cm_armored/tank/handle_player_exit(mob/M) - - if(!(M in list(gunner, driver))) //someone whom isn't supposed to be here to begin with. - exit_tank(M, TRUE) - return - - if(!M.do_actions) - if(occupant_exiting) - to_chat(M, span_notice("Someone is already getting out of [src].")) - return - occupant_exiting = M - - to_chat(M, span_notice("You start climbing out of [src].")) - - addtimer(CALLBACK(src, PROC_REF(exit_tank), M), 5 SECONDS) - -/obj/vehicle/multitile/root/cm_armored/tank/proc/exit_tank(mob/M, forced = FALSE, silent = FALSE) - if(!forced) - occupant_exiting = null - - if(!M || get_turf(M) != get_turf(src) || (M.incapacitated() && !forced)) - return - - var/turf/T = get_turf(entrance) - if(!forced) - if(!T.CanPass(M, T)) - if(!silent) - to_chat(M, span_notice("Something is blocking you from exiting.")) - return - for(var/atom/A in T) - if(A.CanPass(M, T)) - continue - if(!silent) - to_chat(M, span_notice("Something is blocking you from exiting.")) - return - M.forceMove(T) - - if(M == gunner) - deactivate_all_hardpoints() - gunner = null - else if(M == driver) - driver = null - M.unset_interaction() - if(!silent) - to_chat(M, span_notice("You climb out of [src].")) - -//No one but the driver can drive -/obj/vehicle/multitile/root/cm_armored/tank/relaymove(mob/user, direction) - if(user != driver || user.incapacitated()) - return - - . = ..(user, direction) - - - - if(next_sound_play < world.time) - playsound(src, 'sound/ambience/tank_driving.ogg', vol = 20, sound_range = 30) - next_sound_play = world.time + 21 - -//No one but the driver can turn -/obj/vehicle/multitile/root/cm_armored/tank/try_rotate(deg, mob/user, force = FALSE) - - if(user != driver || user.incapacitated()) - return - - . = ..(deg, user, force) - - if(. && istype(hardpoints[HDPT_SUPPORT], /obj/item/hardpoint/support/artillery_module) && gunner?.client) - var/client/C = gunner.client - var/old_x = C.pixel_x - var/old_y = C.pixel_y - C.pixel_x = old_x*cos(deg) - old_y*sin(deg) - C.pixel_y = old_x*sin(deg) + old_y*cos(deg) - -/obj/vehicle/multitile/hitbox/cm_armored/tank/get_driver() - var/obj/vehicle/multitile/root/cm_armored/tank/T = root - return T?.driver - - -/obj/vehicle/multitile/root/cm_armored/tank/take_damage_type(damage, type, atom/attacker) - . = ..() - - if(istype(attacker, /mob)) - var/mob/M = attacker - log_combat(M, src, "damaged [src] with [damage] [type] damage.") - - if(gunner) - log_combat(gunner, null, "[src] took [damage] [type] damage [ismob(attacker) ? "from [key_name(attacker)]" : ""].") - if(driver) - log_combat(driver, null, "[src] took [damage] [type] damage [ismob(attacker) ? "from [key_name(attacker)]" : ""].") - - -/obj/vehicle/multitile/root/cm_armored/proc/click_action(A, mob/user, params) - if(istype(A, /atom/movable/screen) || A == src) - return FALSE - - if(!can_use_hp(user)) - return TRUE - - if(!hardpoints.Find(active_hp)) - to_chat(user, span_warning("Please select an active hardpoint first.")) - return TRUE - - var/obj/item/hardpoint/HP = hardpoints[active_hp] - - if(!HP?.is_ready()) - return TRUE - - if(!HP.firing_arc(A)) - to_chat(user, span_warning("The target is not within your firing arc.")) - return TRUE - - HP.active_effect(A) - return TRUE diff --git a/code/modules/vehicles/multitile/tankvendor.dm b/code/modules/vehicles/multitile/tankvendor.dm deleted file mode 100644 index 2aee8558ff5..00000000000 --- a/code/modules/vehicles/multitile/tankvendor.dm +++ /dev/null @@ -1,290 +0,0 @@ -#define TANKFAB_MAIN_MENU 0 -#define TANKFAB_MOD_MAINT 1 -#define TANKFAB_PRINTER 2 -#define TANKFAB_BUSY 3 - - -/obj/machinery/tank_part_fabricator - name = "tank part fabricator" - desc = "A large automated 3D printer for producing new tank parts and maintaining old ones." - density = TRUE - anchored = TRUE - use_power = IDLE_POWER_USE - idle_power_usage = 20 - icon = 'icons/obj/machines/drone_fab.dmi' - icon_state = "drone_fab_idle" - var/obj/item/loaded_mod - var/tank_points = 625 - var/busy = FALSE - var/screen = TANKFAB_MAIN_MENU - -/obj/machinery/tank_part_fabricator/proc/set_busy(business = TRUE, timer) - busy = business - if(timer) - addtimer(CALLBACK(src, PROC_REF(set_busy), !business), timer) - update_icon() - updateUsrDialog() - -/obj/machinery/tank_part_fabricator/update_icon() - if(machine_stat & NOPOWER) - icon_state = "drone_fab_nopower" - return - if(busy) - icon_state = "drone_fab_active" - return - else - icon_state = "drone_fab_idle" - -/obj/machinery/tank_part_fabricator/interact(mob/user) - . = ..() - if(.) - return - var/dat - if(screen == TANKFAB_BUSY) - dat += "[src] is busy. Please wait for completion of the current operation..." - else - dat += "

Points Available: [tank_points]

" - var/slot = loaded_mod ? "[icon2html(loaded_mod, usr)] [loaded_mod]" : "None" - dat += "

Loaded Hardpoint/Ammo Clip: [slot]

" - - var/screen_menu = screen != TANKFAB_MAIN_MENU ? "Main Menu" : "Main Menu" - var/screen_maint = screen != TANKFAB_MOD_MAINT ? "Hardpoint Maintenance" : "Hardpoint Maintenance" - var/screen_fab = screen != TANKFAB_PRINTER ? "Hardpoint Printer" : "Hardpoint Printer" - dat += "
[screen_fab]
[screen_menu]
[screen_maint]
" - - - switch(screen) - - if(TANKFAB_MOD_MAINT) - if(!loaded_mod) - dat += "No hardpoint or clip loaded. Please stand-by..." - else - var/price = calculate_mod_value(loaded_mod) - var/restore = istype(loaded_mod, /obj/item/hardpoint) ? "Repair" : "Refill" - var/cost = calculate_repair_price(loaded_mod) - dat += "
[restore] ([cost])
Refund ([price])

" - dat += "

Hardpoint/Ammo Clip infos:

" - dat += "Brief description: [loaded_mod.desc]
" - if(istype(loaded_mod, /obj/item/hardpoint)) - var/obj/item/hardpoint/H = loaded_mod - dat += "Hardpoint integrity: [PERCENT(H.obj_integrity/H.max_integrity)]%
" - if(H.starter_ammo) - var/ammo_count = H.ammo ? "[H.ammo] ([H.ammo.current_rounds]/[H.ammo.max_rounds])" : "No clip loaded" - dat += "Current clip: [ammo_count]
" - if(H.max_clips) - dat += "Backup clips:
" - for(var/I in H.backup_clips) - var/obj/item/ammo_magazine/tank/A = I - dat += "[A] ([A.current_rounds]/[A.max_rounds])
" - else if(istype(loaded_mod, /obj/item/ammo_magazine)) - var/obj/item/ammo_magazine/A = loaded_mod - dat += "Current rounds: [A] [A.current_rounds]/[A.max_rounds]
" - dat += "Caliber: [A.caliber]
" - //var/obj/item/hardpoint/H = A.gun_type //Ima break this. - //dat += "Supported Hardpoint: [initial(H.name)]
" - - if(TANKFAB_PRINTER) - dat += "

Armor:

" - for(var/build_type in subtypesof(/obj/item/hardpoint/armor)) - var/obj/item/hardpoint/armor/AR = build_type - if(!initial(AR.buyable)) - continue - var/build_name = initial(AR.name) - var/build_cost = initial(AR.point_cost) - dat += "[build_name] ([build_cost])
" - - dat += "

Primary Weapon:

" - for(var/build_type in subtypesof(/obj/item/hardpoint/primary)) - var/obj/item/hardpoint/primary/PR = build_type - if(!initial(PR.buyable)) - continue - var/build_name = initial(PR.name) - var/build_cost = initial(PR.point_cost) - dat += "[build_name] ([build_cost])
" - - dat += "

Secondary Weapon:

" - for(var/build_type in subtypesof(/obj/item/hardpoint/secondary)) - var/obj/item/hardpoint/secondary/SE = build_type - if(!initial(SE.buyable)) - continue - var/build_name = initial(SE.name) - var/build_cost = initial(SE.point_cost) - dat += "[build_name] ([build_cost])
" - - dat += "

Support Module:

" - for(var/build_type in subtypesof(/obj/item/hardpoint/support)) - var/obj/item/hardpoint/support/SP = build_type - if(!initial(SP.buyable)) - continue - var/build_name = initial(SP.name) - var/build_cost = initial(SP.point_cost) - dat += "[build_name] ([build_cost])
" - - dat += "

Treads:

" - for(var/build_type in subtypesof(/obj/item/hardpoint/treads)) - var/obj/item/hardpoint/treads/TR = build_type - if(!initial(TR.buyable)) - continue - var/build_name = initial(TR.name) - var/build_cost = initial(TR.point_cost) - dat += "[build_name] ([build_cost])
" - - dat += "

Weapon Ammo:

" - for(var/build_type in subtypesof(/obj/item/ammo_magazine/tank)) - var/obj/item/ammo_magazine/tank/AM = build_type - var/build_name = initial(AM.name) - var/build_cost = initial(AM.point_cost) - dat += "[build_name] ([build_cost])
" - - var/datum/browser/popup = new(user, "dropship_part_fab", "
Tank Part Fabricator
") - popup.set_content(dat) - popup.open(TRUE) - - -/obj/machinery/tank_part_fabricator/attackby(obj/item/W, mob/user) - if((istype(W, /obj/item/hardpoint) || istype(W, /obj/item/ammo_magazine/tank)) && user.a_intent != INTENT_HARM) - if(machine_stat & (NOPOWER|BROKEN)) - return - if(busy) - to_chat(usr, span_warning("[src] is busy. Please wait for completion of previous operation.")) - else if(user.transferItemToLoc(W, src)) - user.visible_message(span_notice("[user] loads [W] into [src]'s maintenance slot."), span_notice("You load [W] into [src]'s maintenance slot."), null, 4) - loaded_mod = W - else - to_chat(user, span_warning("[W] appears to be stuck to your hands.")) - else if(iscrowbar(W) && machine_stat & (NOPOWER|BROKEN) && !QDELETED(loaded_mod)) - user.visible_message(span_warning("[user] starts to pry [src]'s maintenance slot open."), span_notice("You start to pry [loaded_mod] out of [src]'s maintenance slot...")) - if(!do_after(user, 4 SECONDS, NONE, src, BUSY_ICON_GENERIC) || QDELETED(loaded_mod)) - return - user.visible_message("[user] pries [loaded_mod] out of [src].", span_notice("You retrieve [loaded_mod] from [src].")) - eject_tank_part() - else - return ..() - -/obj/machinery/tank_part_fabricator/proc/build_tank_part(part_type, cost, mob/user) - if(machine_stat & (NOPOWER|BROKEN) || busy) - return - if(tank_points < cost) - to_chat(user, span_warning("You don't have enough points to build that.")) - return - visible_message(span_notice("[src] starts printing something.")) - tank_points -= cost - set_busy() - addtimer(CALLBACK(src, PROC_REF(dispense_tank_part), part_type), 10 SECONDS) - -/obj/machinery/tank_part_fabricator/proc/dispense_tank_part(part_type) - set_busy(FALSE) - var/turf/T = get_step(src, SOUTHEAST) - playsound(src, 'sound/machines/hydraulics_1.ogg', 40, 1) - new part_type(T) - -/obj/machinery/tank_part_fabricator/proc/calculate_mod_value() - if(istype(loaded_mod, /obj/item/hardpoint)) - var/obj/item/hardpoint/mod = loaded_mod - . = (mod.point_cost - mod.point_cost * (1 - (mod.obj_integrity/mod.max_integrity)) * 0.5) * 0.5 - if(mod.starter_ammo) - if(mod.ammo) - . += (mod.ammo.point_cost - mod.ammo.point_cost * (1 - (mod.ammo.current_rounds/mod.ammo.max_rounds)) * 0.5) * 0.5 - else - . -= initial(mod.starter_ammo.point_cost) * 0.5 - for(var/O in mod.backup_clips) - var/obj/item/ammo_magazine/tank/A = O - . = (A.point_cost - A.point_cost * (1 - (A.current_rounds/A.max_rounds)) * 0.5) * 0.5 - else if(istype(loaded_mod, /obj/item/ammo_magazine/tank)) - var/obj/item/ammo_magazine/tank/A = loaded_mod - . = (A.point_cost - A.point_cost * (1 - (A.current_rounds/A.max_rounds)) * 0.5) * 0.5 - . = max(round(.), 0) - -/obj/machinery/tank_part_fabricator/proc/calculate_repair_price() - if(istype(loaded_mod, /obj/item/hardpoint)) - var/obj/item/hardpoint/mod = loaded_mod - . = ((mod.point_cost - mod.point_cost * (mod.obj_integrity/mod.max_integrity)) * 0.1) - if(mod.starter_ammo) - if(mod.ammo) - . += ((mod.ammo.point_cost - mod.ammo.point_cost * (mod.ammo.current_rounds/mod.ammo.max_rounds)) * 0.9) - else - . += initial(mod.starter_ammo.point_cost) * 0.9 - else if(istype(loaded_mod, /obj/item/ammo_magazine/tank)) - var/obj/item/ammo_magazine/tank/A = loaded_mod - . = ((A.point_cost - A.point_cost * (A.current_rounds/A.max_rounds)) * 0.9) - - . = max(round(.), 0) - -/obj/machinery/tank_part_fabricator/proc/eject_tank_part(mob/user) - if(busy || QDELETED(loaded_mod)) - return - var/turf/T = get_step(src, SOUTHEAST) - if(user) - to_chat(user, span_notice("You retrieve [loaded_mod] from [src].")) - loaded_mod.forceMove(T) - loaded_mod = null - -/obj/machinery/tank_part_fabricator/proc/refund_tank_part() - if(machine_stat & (NOPOWER|BROKEN) || busy || QDELETED(loaded_mod)) - return - tank_points += calculate_mod_value() - visible_message(span_notice("[src] starts disassembling [loaded_mod].")) - QDEL_NULL(loaded_mod) - set_busy(TRUE, 10 SECONDS) - -/obj/machinery/tank_part_fabricator/proc/restore_tank_part(mob/user) - if(machine_stat & (NOPOWER|BROKEN) || busy || QDELETED(loaded_mod)) - return - var/cost = calculate_repair_price() - if(tank_points < cost) - to_chat(user, span_warning("You don't have enough points to repair that.")) - tank_points -= cost - if(istype(loaded_mod, /obj/item/hardpoint)) - var/obj/item/hardpoint/H = loaded_mod - H.repair_damage(H.max_integrity) - if(H.ammo) - H.ammo.current_rounds = H.ammo.max_rounds - H.ammo.update_icon() - else if(H.starter_ammo) - H.ammo = new H.starter_ammo - else if(istype(loaded_mod, /obj/item/ammo_magazine/tank)) - var/obj/item/ammo_magazine/tank/A = loaded_mod - A.current_rounds = A.max_rounds - set_busy(TRUE, 6 SECONDS) - -/obj/machinery/tank_part_fabricator/Topic(href, href_list) - . =..() - if(.) - return - - if(busy) - to_chat(usr, span_warning("[src] is busy. Please wait for completion of previous operation.")) - return - - if(href_list["produce"]) - var/produce = text2path(href_list["produce"]) - var/cost - if(ispath(produce, /obj/item/hardpoint)) - var/obj/item/hardpoint/H = produce - cost = initial(H.point_cost) - else if(ispath(produce, /obj/item/ammo_magazine/tank)) - var/obj/item/ammo_magazine/tank/A = produce - cost = initial(A.point_cost) - if(isnull(cost)) - updateUsrDialog() - return - build_tank_part(produce, cost, usr) - - if(href_list["eject"]) - eject_tank_part(usr) - - if(href_list["refund"]) - refund_tank_part() - - if(href_list["restore"]) - restore_tank_part(usr) - - if(href_list["screen"]) - screen = text2num(href_list["screen"]) - - updateUsrDialog() - -#undef TANKFAB_MAIN_MENU -#undef TANKFAB_MOD_MAINT -#undef TANKFAB_PRINTER -#undef TANKFAB_BUSY diff --git a/code/modules/vehicles/powerloader.dm b/code/modules/vehicles/powerloader.dm index a5bb786c0cb..71dbd2eac73 100644 --- a/code/modules/vehicles/powerloader.dm +++ b/code/modules/vehicles/powerloader.dm @@ -28,12 +28,12 @@ PC.linked_powerloader = src AddElement(/datum/element/ridable, /datum/component/riding/vehicle/powerloader) -/obj/vehicle/ridden/powerloader/Move(newloc, newdir) - if(dir == newdir) +/obj/vehicle/ridden/powerloader/Move(atom/newloc, direction, glide_size_override) + if(dir == direction) playsound(src, pick(move_sounds), 40, TRUE) return ..() playsound(src, pick(change_dir_sounds), 40, TRUE) - setDir(newdir) + setDir(direction) return TRUE /obj/vehicle/ridden/powerloader/attack_powerloader(mob/living/user, obj/item/powerloader_clamp/attached_clamp) @@ -176,7 +176,8 @@ return target.attack_powerloader(user, src) -/obj/item/powerloader_clamp/update_icon() +/obj/item/powerloader_clamp/update_icon_state() + . = ..() if(loaded) icon_state = "loader_clamp_full" else diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm index 3413ae5ea1d..5ef2a223e08 100644 --- a/code/modules/vehicles/sealed.dm +++ b/code/modules/vehicles/sealed.dm @@ -1,5 +1,5 @@ /obj/vehicle/sealed - flags_atom = PREVENT_CONTENTS_EXPLOSION + flags_atom = PREVENT_CONTENTS_EXPLOSION|CRITICAL_ATOM var/enter_delay = 2 SECONDS var/mouse_pointer var/headlights_toggle = FALSE @@ -43,12 +43,14 @@ . = ..() REMOVE_TRAIT(M, TRAIT_HANDS_BLOCKED, VEHICLE_TRAIT) - -/obj/vehicle/sealed/proc/mob_try_enter(mob/M) - if(!istype(M)) +///Entry checks for the mob before entering the vehicle +/obj/vehicle/sealed/proc/mob_try_enter(mob/entering_mob, mob/user, loc_override = FALSE) + if(!istype(entering_mob)) return FALSE - if(do_after(M, get_enter_delay(M), NONE, extra_checks = CALLBACK(src, PROC_REF(enter_checks), M))) - mob_enter(M) + if(!user) + user = entering_mob + if(do_after(user, get_enter_delay(entering_mob), target = entering_mob, user_display = BUSY_ICON_FRIENDLY, extra_checks = CALLBACK(src, PROC_REF(enter_checks), entering_mob, loc_override))) + mob_enter(entering_mob) return TRUE return FALSE @@ -58,9 +60,10 @@ return enter_delay ///Extra checks to perform during the do_after to enter the vehicle -/obj/vehicle/sealed/proc/enter_checks(mob/M) +/obj/vehicle/sealed/proc/enter_checks(mob/entering_mob, loc_override = FALSE) return occupant_amount() < max_occupants +///Enters the vehicle /obj/vehicle/sealed/proc/mob_enter(mob/M, silent = FALSE) if(!istype(M)) return FALSE @@ -70,9 +73,11 @@ add_occupant(M) return TRUE +///Exit checks for the mob before exiting the vehicle /obj/vehicle/sealed/proc/mob_try_exit(mob/M, mob/user, silent = FALSE, randomstep = FALSE) mob_exit(M, silent, randomstep) +///Exits the vehicle /obj/vehicle/sealed/proc/mob_exit(mob/M, silent = FALSE, randomstep = FALSE) SIGNAL_HANDLER if(!istype(M)) @@ -88,7 +93,7 @@ M.visible_message(span_notice("[M] drops out of \the [src]!")) return TRUE -/obj/vehicle/sealed/proc/exit_location(M) +/obj/vehicle/sealed/proc/exit_location(mob/M) return drop_location() /obj/vehicle/sealed/attackby(obj/item/I, mob/user, params) @@ -141,10 +146,14 @@ return FALSE /obj/vehicle/sealed/relaymove(mob/living/user, direction) - if(canmove) - vehicle_move(direction) + if(is_driver(user) && canmove) + vehicle_move(user, direction) return TRUE /// Sinced sealed vehicles (cars and mechs) don't have riding components, the actual movement is handled here from [/obj/vehicle/sealed/proc/relaymove] -/obj/vehicle/sealed/proc/vehicle_move(direction) - return FALSE +/obj/vehicle/sealed/proc/vehicle_move(mob/living/user, direction) + SHOULD_CALL_PARENT(TRUE) + if(!COOLDOWN_CHECK(src, cooldown_vehicle_move)) + return FALSE + COOLDOWN_START(src, cooldown_vehicle_move, move_delay) + return !(SEND_SIGNAL(src, COMSIG_VEHICLE_MOVE, user, direction) & COMPONENT_DRIVER_BLOCK_MOVE) diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm index af051386fed..2d11ca08504 100644 --- a/code/modules/vehicles/train.dm +++ b/code/modules/vehicles/train.dm @@ -23,7 +23,7 @@ for(var/obj/vehicle/train/T in orange(1, src)) latch(T,silent=TRUE) -/obj/vehicle/train/Move() +/obj/vehicle/train/Move(atom/newloc, direction, glide_size_override) var/old_loc = get_turf(src) if(..()) if(tow) diff --git a/code/modules/xenomorph/xeno_structures.dm b/code/modules/xenomorph/xeno_structures.dm index 55b5a858495..51991c3b656 100644 --- a/code/modules/xenomorph/xeno_structures.dm +++ b/code/modules/xenomorph/xeno_structures.dm @@ -90,6 +90,7 @@ take_damage(severity, BRUTE, BOMB) /obj/structure/xeno/trap/update_icon_state() + . = ..() switch(trap_type) if(TRAP_HUGGER) icon_state = "traphugger" @@ -1272,6 +1273,7 @@ TUNNEL update_icon() /obj/structure/xeno/pherotower/update_icon_state() + . = ..() switch(current_aura.aura_types[1]) if(AURA_XENO_RECOVERY) icon_state = "recoverytower" diff --git a/html/changelogs/AutoChangeLog-pr-16329.yml b/html/changelogs/AutoChangeLog-pr-16329.yml new file mode 100644 index 00000000000..a2cdca64a20 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-16329.yml @@ -0,0 +1,4 @@ +author: "blackdav123" +delete-after: True +changes: + - rscadd: "Added 10 more intel computers to Magmoor." \ No newline at end of file diff --git a/icons/UI_Icons/map_blips.dmi b/icons/UI_Icons/map_blips.dmi index b19a391b8ee..6f9514cdc41 100644 Binary files a/icons/UI_Icons/map_blips.dmi and b/icons/UI_Icons/map_blips.dmi differ diff --git a/icons/UI_Icons/map_blips_large.dmi b/icons/UI_Icons/map_blips_large.dmi index c7e8d0f59b7..8d79f9a729e 100644 Binary files a/icons/UI_Icons/map_blips_large.dmi and b/icons/UI_Icons/map_blips_large.dmi differ diff --git a/icons/effects/bulletholes.dmi b/icons/effects/bulletholes.dmi index 1166c0f20a1..bc464d95fdc 100644 Binary files a/icons/effects/bulletholes.dmi and b/icons/effects/bulletholes.dmi differ diff --git a/icons/mob/actions/actions_vehicle.dmi b/icons/mob/actions/actions_vehicle.dmi index c8fce478813..41cdfb44baf 100644 Binary files a/icons/mob/actions/actions_vehicle.dmi and b/icons/mob/actions/actions_vehicle.dmi differ diff --git a/icons/mob/ammoHUD.dmi b/icons/mob/ammoHUD.dmi index 4f8ec4096fb..b965869730f 100644 Binary files a/icons/mob/ammoHUD.dmi and b/icons/mob/ammoHUD.dmi differ diff --git a/icons/mob/clothing/headwear/marine_helmets.dmi b/icons/mob/clothing/headwear/marine_helmets.dmi index 55e1300eb28..8707127bf98 100644 Binary files a/icons/mob/clothing/headwear/marine_helmets.dmi and b/icons/mob/clothing/headwear/marine_helmets.dmi differ diff --git a/icons/mob/clothing/suits/marine_armor.dmi b/icons/mob/clothing/suits/marine_armor.dmi index 15b13b67be5..bf24ae0aae0 100644 Binary files a/icons/mob/clothing/suits/marine_armor.dmi and b/icons/mob/clothing/suits/marine_armor.dmi differ diff --git a/icons/mob/clothing/uniforms/marine_uniforms.dmi b/icons/mob/clothing/uniforms/marine_uniforms.dmi index 85bf2a0fc49..9cc221bb6c9 100644 Binary files a/icons/mob/clothing/uniforms/marine_uniforms.dmi and b/icons/mob/clothing/uniforms/marine_uniforms.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index 6918f8de8d3..cf1b9073338 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/icons/mob/landmarks.dmi b/icons/mob/landmarks.dmi index 3c7514cc76d..d02a6f8bf88 100644 Binary files a/icons/mob/landmarks.dmi and b/icons/mob/landmarks.dmi differ diff --git a/icons/obj/armored/1x1/tinytank.dmi b/icons/obj/armored/1x1/tinytank.dmi new file mode 100644 index 00000000000..8f45e78adef Binary files /dev/null and b/icons/obj/armored/1x1/tinytank.dmi differ diff --git a/icons/obj/armored/1x1/tinytank_gun.dmi b/icons/obj/armored/1x1/tinytank_gun.dmi new file mode 100644 index 00000000000..83176645615 Binary files /dev/null and b/icons/obj/armored/1x1/tinytank_gun.dmi differ diff --git a/icons/obj/armored/2x2/medium_vehicles.dmi b/icons/obj/armored/2x2/medium_vehicles.dmi new file mode 100644 index 00000000000..f8234bb6c9c Binary files /dev/null and b/icons/obj/armored/2x2/medium_vehicles.dmi differ diff --git a/icons/obj/armored/3x3/apc.dmi b/icons/obj/armored/3x3/apc.dmi new file mode 100644 index 00000000000..6e507dcc3e9 Binary files /dev/null and b/icons/obj/armored/3x3/apc.dmi differ diff --git a/icons/obj/armored/3x3/apc_damage_overlay.dmi b/icons/obj/armored/3x3/apc_damage_overlay.dmi new file mode 100644 index 00000000000..e3da1e1f15f Binary files /dev/null and b/icons/obj/armored/3x3/apc_damage_overlay.dmi differ diff --git a/icons/obj/armored/3x3/apc_interior.dmi b/icons/obj/armored/3x3/apc_interior.dmi new file mode 100644 index 00000000000..eff98b345e1 Binary files /dev/null and b/icons/obj/armored/3x3/apc_interior.dmi differ diff --git a/icons/obj/armored/3x3/tank.dmi b/icons/obj/armored/3x3/tank.dmi new file mode 100644 index 00000000000..5a7fe1a097c Binary files /dev/null and b/icons/obj/armored/3x3/tank.dmi differ diff --git a/icons/obj/armored/3x3/tank_damage.dmi b/icons/obj/armored/3x3/tank_damage.dmi new file mode 100644 index 00000000000..86eda8545e3 Binary files /dev/null and b/icons/obj/armored/3x3/tank_damage.dmi differ diff --git a/icons/obj/armored/3x3/tank_gun.dmi b/icons/obj/armored/3x3/tank_gun.dmi new file mode 100644 index 00000000000..e97adc12df3 Binary files /dev/null and b/icons/obj/armored/3x3/tank_gun.dmi differ diff --git a/icons/obj/armored/3x3/tank_interior.dmi b/icons/obj/armored/3x3/tank_interior.dmi new file mode 100644 index 00000000000..f1a97c4bcdf Binary files /dev/null and b/icons/obj/armored/3x3/tank_interior.dmi differ diff --git a/icons/obj/armored/hardpoint_modules.dmi b/icons/obj/armored/hardpoint_modules.dmi new file mode 100644 index 00000000000..094679fc52b Binary files /dev/null and b/icons/obj/armored/hardpoint_modules.dmi differ diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi index df13c7bf829..556ac989c9a 100644 Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ diff --git a/icons/obj/clothing/headwear/marine_helmets.dmi b/icons/obj/clothing/headwear/marine_helmets.dmi index 13e7be47b71..c1cbbf2f206 100644 Binary files a/icons/obj/clothing/headwear/marine_helmets.dmi and b/icons/obj/clothing/headwear/marine_helmets.dmi differ diff --git a/icons/obj/clothing/suits/marine_armor.dmi b/icons/obj/clothing/suits/marine_armor.dmi index 424b541cb9c..accf825518c 100644 Binary files a/icons/obj/clothing/suits/marine_armor.dmi and b/icons/obj/clothing/suits/marine_armor.dmi differ diff --git a/icons/obj/clothing/uniforms/marine_uniforms.dmi b/icons/obj/clothing/uniforms/marine_uniforms.dmi index 183e55d7d0a..3e3d2698c17 100644 Binary files a/icons/obj/clothing/uniforms/marine_uniforms.dmi and b/icons/obj/clothing/uniforms/marine_uniforms.dmi differ diff --git a/icons/obj/items/ammo.dmi b/icons/obj/items/ammo.dmi index 1f3de7c781f..e3b23ae0a2e 100644 Binary files a/icons/obj/items/ammo.dmi and b/icons/obj/items/ammo.dmi differ diff --git a/icons/obj/items/projectiles.dmi b/icons/obj/items/projectiles.dmi index 39e41b16485..ffd138c7c35 100644 Binary files a/icons/obj/items/projectiles.dmi and b/icons/obj/items/projectiles.dmi differ diff --git a/icons/obj/items/weapons.dmi b/icons/obj/items/weapons.dmi index 4f033b65bcd..1729b0ec16f 100644 Binary files a/icons/obj/items/weapons.dmi and b/icons/obj/items/weapons.dmi differ diff --git a/icons/obj/machines/cryogenics.dmi b/icons/obj/machines/cryogenics.dmi index 0721ceb5695..93ec64a3541 100644 Binary files a/icons/obj/machines/cryogenics.dmi and b/icons/obj/machines/cryogenics.dmi differ diff --git a/icons/obj/vehicles/hardpoint_modules.dmi b/icons/obj/vehicles/hardpoint_modules.dmi deleted file mode 100644 index 0c720a9237c..00000000000 Binary files a/icons/obj/vehicles/hardpoint_modules.dmi and /dev/null differ diff --git a/icons/obj/vehicles/tank_EW.dmi b/icons/obj/vehicles/tank_EW.dmi deleted file mode 100644 index ff984a6abb1..00000000000 Binary files a/icons/obj/vehicles/tank_EW.dmi and /dev/null differ diff --git a/icons/obj/vehicles/tank_NS.dmi b/icons/obj/vehicles/tank_NS.dmi deleted file mode 100644 index a709c718c33..00000000000 Binary files a/icons/obj/vehicles/tank_NS.dmi and /dev/null differ diff --git a/icons/turf/snow2.dmi b/icons/turf/snow2.dmi index 24f6fc5b0bd..501434e0630 100644 Binary files a/icons/turf/snow2.dmi and b/icons/turf/snow2.dmi differ diff --git a/sound/effects/tankswivel.ogg b/sound/effects/tankswivel.ogg new file mode 100644 index 00000000000..775a13c07cc Binary files /dev/null and b/sound/effects/tankswivel.ogg differ diff --git a/sound/vehicles/horns/armored_horn.ogg b/sound/vehicles/horns/armored_horn.ogg new file mode 100644 index 00000000000..147d39acb28 Binary files /dev/null and b/sound/vehicles/horns/armored_horn.ogg differ diff --git a/sound/vehicles/weapons/ltb_reload.ogg b/sound/vehicles/weapons/ltb_reload.ogg new file mode 100644 index 00000000000..476eba1ddb9 Binary files /dev/null and b/sound/vehicles/weapons/ltb_reload.ogg differ diff --git a/tgmc.dme b/tgmc.dme index 1c93b62eab4..f7fd5a87327 100644 --- a/tgmc.dme +++ b/tgmc.dme @@ -28,6 +28,7 @@ #include "code\__DEFINES\admin.dm" #include "code\__DEFINES\ai.dm" #include "code\__DEFINES\alerts.dm" +#include "code\__DEFINES\apc_defines.dm" #include "code\__DEFINES\area.dm" #include "code\__DEFINES\atmospherics.dm" #include "code\__DEFINES\atom_hud.dm" @@ -321,6 +322,7 @@ #include "code\controllers\subsystem\time_track.dm" #include "code\controllers\subsystem\timer.dm" #include "code\controllers\subsystem\tts.dm" +#include "code\controllers\subsystem\vis_overlays.dm" #include "code\controllers\subsystem\vote.dm" #include "code\controllers\subsystem\weather.dm" #include "code\controllers\subsystem\weeds.dm" @@ -518,6 +520,11 @@ #include "code\datums\greyscale\layer.dm" #include "code\datums\helper_datums\getrev.dm" #include "code\datums\helper_datums\stack_end_detector.dm" +#include "code\datums\interior\_interior.dm" +#include "code\datums\interior\interior_apc.dm" +#include "code\datums\interior\interior_tank.dm" +#include "code\datums\interior\link_interior.dm" +#include "code\datums\interior\map_templates.dm" #include "code\datums\jobs\access.dm" #include "code\datums\jobs\squads.dm" #include "code\datums\jobs\job\clf.dm" @@ -592,8 +599,7 @@ #include "code\datums\wires\radio.dm" #include "code\datums\wires\spaceship.dm" #include "code\datums\wires\vending.dm" -#include "code\game\atoms.dm" -#include "code\game\atoms_movable.dm" +#include "code\game\alternate_appearance.dm" #include "code\game\blood.dm" #include "code\game\buckling.dm" #include "code\game\communications.dm" @@ -632,6 +638,9 @@ #include "code\game\area\areas\shuttles.dm" #include "code\game\area\campaign_maps\jungle_outpost.dm" #include "code\game\area\campaign_maps\som_base.dm" +#include "code\game\atoms\_atom.dm" +#include "code\game\atoms\atom_appearance.dm" +#include "code\game\atoms\atom_movable.dm" #include "code\game\mecha\mech_bay.dm" #include "code\game\mecha\mecha_parts.dm" #include "code\game\mecha\mecha_wreckage.dm" @@ -745,6 +754,7 @@ #include "code\game\objects\items\misc.dm" #include "code\game\objects\items\motion_detector.dm" #include "code\game\objects\items\multitool.dm" +#include "code\game\objects\items\pamphlets.dm" #include "code\game\objects\items\pinpointer.dm" #include "code\game\objects\items\pipe_painter.dm" #include "code\game\objects\items\plantable_flags.dm" @@ -1848,7 +1858,6 @@ #include "code\modules\paperwork\paperbin.dm" #include "code\modules\paperwork\photocopier.dm" #include "code\modules\paperwork\photography.dm" -#include "code\modules\power\apc.dm" #include "code\modules\power\batteryrack.dm" #include "code\modules\power\cable.dm" #include "code\modules\power\cell.dm" @@ -1867,6 +1876,10 @@ #include "code\modules\power\smes.dm" #include "code\modules\power\smes_construction.dm" #include "code\modules\power\terminal.dm" +#include "code\modules\power\apc\apc.dm" +#include "code\modules\power\apc\apc_appearance.dm" +#include "code\modules\power\apc\apc_attack.dm" +#include "code\modules\power\apc\apc_tool_act.dm" #include "code\modules\power\singularity\emitter.dm" #include "code\modules\projectiles\ammo_datums.dm" #include "code\modules\projectiles\ammunition.dm" @@ -2005,7 +2018,8 @@ #include "code\modules\tgui_panel\tgui_panel.dm" #include "code\modules\tooltip\tooltip.dm" #include "code\modules\unit_tests\_unit_tests.dm" -#include "code\modules\vehicles\_vehicle.dm" +#include "code\modules\vehicles\__vehicle.dm" +#include "code\modules\vehicles\_hitbox.dm" #include "code\modules\vehicles\atv.dm" #include "code\modules\vehicles\bicycle.dm" #include "code\modules\vehicles\cargo_train.dm" @@ -2017,6 +2031,22 @@ #include "code\modules\vehicles\vehicle_actions.dm" #include "code\modules\vehicles\vehicle_key.dm" #include "code\modules\vehicles\wheelchair.dm" +#include "code\modules\vehicles\armored\__armored.dm" +#include "code\modules\vehicles\armored\_multitile.dm" +#include "code\modules\vehicles\armored\ammo_magazine.dm" +#include "code\modules\vehicles\armored\apc.dm" +#include "code\modules\vehicles\armored\armored_actions.dm" +#include "code\modules\vehicles\armored\armored_modules.dm" +#include "code\modules\vehicles\armored\armored_weapons.dm" +#include "code\modules\vehicles\armored\medium_apc.dm" +#include "code\modules\vehicles\armored\medium_tank.dm" +#include "code\modules\vehicles\armored\small_apc.dm" +#include "code\modules\vehicles\armored\tank_fabricator.dm" +#include "code\modules\vehicles\armored\vehicle_collision.dm" +#include "code\modules\vehicles\armored\interiors\ammo_rack.dm" +#include "code\modules\vehicles\armored\interiors\breech.dm" +#include "code\modules\vehicles\armored\interiors\chairs.dm" +#include "code\modules\vehicles\armored\interiors\periscope.dm" #include "code\modules\vehicles\cars\car.dm" #include "code\modules\vehicles\mecha\_mecha.dm" #include "code\modules\vehicles\mecha\mech_bay.dm" @@ -2049,11 +2079,6 @@ #include "code\modules\vehicles\mecha\equipment\weapons\weapons.dm" #include "code\modules\vehicles\mecha\working\ripley.dm" #include "code\modules\vehicles\mecha\working\working.dm" -#include "code\modules\vehicles\multitile\cm_armored.dm" -#include "code\modules\vehicles\multitile\hardpoints.dm" -#include "code\modules\vehicles\multitile\multitile.dm" -#include "code\modules\vehicles\multitile\tank.dm" -#include "code\modules\vehicles\multitile\tankvendor.dm" #include "code\modules\vehicles\unmanned\deployable_vehicles.dm" #include "code\modules\vehicles\unmanned\unmanned_droid.dm" #include "code\modules\vehicles\unmanned\unmanned_turrets.dm" diff --git a/tgui/packages/tgui/interfaces/PlayerPreferences/JobPreferences.tsx b/tgui/packages/tgui/interfaces/PlayerPreferences/JobPreferences.tsx index c33aa8d766b..b9029213e3e 100644 --- a/tgui/packages/tgui/interfaces/PlayerPreferences/JobPreferences.tsx +++ b/tgui/packages/tgui/interfaces/PlayerPreferences/JobPreferences.tsx @@ -25,8 +25,10 @@ export const JobPreferences = (props, context) => { 'Field Commander', 'Staff Officer', 'Pilot Officer', + 'Transport Officer', 'Synthetic', 'AI', + 'Mech Pilot', ]; const supportRoles = [ 'Chief Ship Engineer', @@ -35,6 +37,8 @@ export const JobPreferences = (props, context) => { 'Chief Medical Officer', 'Medical Doctor', 'Medical Researcher', + 'Assault Crewman', + 'Transport Crewman', ]; const marineJobs = [ 'Squad Marine', @@ -42,7 +46,6 @@ export const JobPreferences = (props, context) => { 'Squad Corpsman', 'Squad Smartgunner', 'Squad Leader', - 'Mech Pilot', // not really a marine job but creating empty space in the support section is lame ]; const somJobs = [ 'SOM Squad Standard', diff --git a/tgui/packages/tgui/interfaces/VehicleSupply.tsx b/tgui/packages/tgui/interfaces/VehicleSupply.tsx new file mode 100644 index 00000000000..6c702305745 --- /dev/null +++ b/tgui/packages/tgui/interfaces/VehicleSupply.tsx @@ -0,0 +1,215 @@ +import { useBackend } from '../backend'; +import { Button, Collapsible, Section, Slider, Stack } from '../components'; +import { Window } from '../layouts'; + +type SelectionEntry = { + name: string; + desc: string; + type: string; + isselected: boolean; +}; + +type AmmoData = { + name: string; + type: string; + current: number; + max: number; +}; + +type VehicleSupplyData = { + vehicles: SelectionEntry[]; + primaryWeapons: SelectionEntry[]; + secondaryWeapons: SelectionEntry[]; + driverModules: SelectionEntry[]; + gunnerModules: SelectionEntry[]; + + primaryammotypes?: AmmoData[]; + secondarymmotypes?: AmmoData[]; + + elevator: string; + elevator_dir: string; +}; + +export const VehicleSupply = (props, context) => { + const { act, data } = useBackend(context); + const { + vehicles, + primaryWeapons, + secondaryWeapons, + driverModules, + gunnerModules, + primaryammotypes, + secondarymmotypes, + elevator, + elevator_dir, + } = data; + return ( + + + + + + +
+ {primaryWeapons?.map((primary) => ( + + act('setprimary', { type: primary.type }) + } + icon="check" + content="Select" + selected={primary.isselected} + /> + } + > + {!primary.isselected + ? null + : primaryammotypes?.map((ammotype) => ( + + act('set_ammo_primary', { + type: ammotype.type, + new_value: value, + }) + } + value={ammotype.current} + /> + ))} + + ))} +
+
+ +
+ {secondaryWeapons?.map((secondary) => ( + + act('setsecondary', { type: secondary.type }) + } + icon="check" + content="Select" + selected={secondary.isselected} + /> + } + > + {!secondary.isselected + ? null + : secondarymmotypes?.map((ammotype) => ( + + act('set_ammo_secondary', { + type: ammotype.type, + new_value: value, + }) + } + value={ammotype.current} + /> + ))} + + ))} +
+
+
+
+ +