diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index ebb62bff375..1ecd393cc7d 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -1228,7 +1228,7 @@ /area/lavaland/surface/outdoors) "JD" = ( /obj/effect/mapping_helpers/no_lava, -/obj/structure/ore_container/gutlunch_trough, +/obj/structure/ore_container/food_trough/gutlunch_trough, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "Kg" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index c8f317683df..7dd7e89f1c2 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -11952,6 +11952,10 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/aft) +"dya" = ( +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "dyf" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -13654,6 +13658,12 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/service) +"eaM" = ( +/obj/structure/railing/wooden_fence{ + dir = 6 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "ebb" = ( /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/iron, @@ -15743,6 +15753,17 @@ /obj/structure/lattice, /turf/open/openspace/icemoon/keep_below, /area/icemoon/underground/explored) +"eJo" = ( +/obj/structure/table/wood, +/obj/item/raptor_dex{ + pixel_y = 13 + }, +/obj/item/raptor_dex{ + pixel_y = 7 + }, +/obj/item/raptor_dex, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "eJq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -19135,6 +19156,12 @@ dir = 1 }, /area/station/hallway/primary/port) +"fNL" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "fNN" = ( /obj/structure/cable, /turf/open/floor/engine, @@ -22278,6 +22305,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"gOv" = ( +/obj/structure/flora/rock/icy/style_random, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "gOx" = ( /obj/effect/turf_decal/loading_area, /obj/effect/turf_decal/tile/neutral/half/contrasted, @@ -23684,6 +23715,12 @@ /obj/machinery/vending/clothing, /turf/open/floor/iron, /area/station/commons/locker) +"hma" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "hmb" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, @@ -26602,6 +26639,9 @@ /obj/machinery/space_heater, /turf/open/floor/plating, /area/station/maintenance/department/medical/morgue) +"iiv" = ( +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "iiy" = ( /obj/machinery/firealarm/directional/north, /obj/structure/chair{ @@ -30249,6 +30289,9 @@ /obj/structure/railing/corner/end/flip, /turf/open/floor/iron, /area/mine/production) +"jrY" = ( +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "jrZ" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -30559,6 +30602,9 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"jvk" = ( +/turf/closed/mineral/random/snow, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "jvs" = ( /obj/machinery/power/apc/auto_name/directional/east, /obj/structure/cable, @@ -31181,6 +31227,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port/lesser) +"jGp" = ( +/obj/structure/flora/rock/icy/style_random, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "jGB" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -35655,6 +35705,10 @@ dir = 1 }, /area/station/service/chapel/office) +"kTp" = ( +/obj/structure/ore_container/food_trough/raptor_trough, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "kTz" = ( /turf/open/floor/iron/smooth_half, /area/station/security/brig/upper) @@ -40458,6 +40512,10 @@ /obj/item/stack/ducts/fifty, /turf/open/floor/iron/dark, /area/station/medical/chemistry) +"msC" = ( +/obj/structure/railing/wooden_fence, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "msN" = ( /obj/machinery/atmospherics/pipe/smart/simple/dark/visible, /turf/closed/wall/r_wall, @@ -41523,6 +41581,9 @@ /obj/machinery/firealarm/directional/west, /turf/open/floor/carpet, /area/station/service/library) +"mME" = ( +/turf/closed/wall/mineral/wood/nonmetal, +/area/icemoon/surface) "mMM" = ( /turf/closed/wall/r_wall, /area/station/security/prison) @@ -43960,6 +44021,11 @@ }, /turf/open/floor/iron/white, /area/station/science/genetics) +"nwn" = ( +/obj/item/stack/sheet/mineral/wood, +/obj/effect/decal/cleanable/generic, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "nwr" = ( /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 8 @@ -47228,6 +47294,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/fore) +"ouz" = ( +/obj/structure/signpost, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "ouE" = ( /obj/effect/turf_decal/stripes/line{ dir = 6 @@ -48880,6 +48950,12 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat_interior) +"oUe" = ( +/obj/structure/railing/wooden_fence{ + dir = 10 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "oUG" = ( /obj/machinery/door/airlock{ id_tag = "Toilet2"; @@ -49297,6 +49373,17 @@ "pbs" = ( /turf/closed/wall, /area/station/ai_monitored/turret_protected/aisat/maint) +"pbv" = ( +/obj/structure/table/wood, +/obj/item/soap/deluxe{ + pixel_y = 11 + }, +/obj/item/soap/deluxe{ + pixel_y = 6 + }, +/obj/item/soap/deluxe, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "pby" = ( /obj/effect/gibspawner/human, /turf/open/misc/asteroid/snow/icemoon, @@ -51667,6 +51754,12 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"pLb" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "pLe" = ( /obj/structure/sign/warning/xeno_mining, /turf/closed/wall/ice, @@ -56310,6 +56403,12 @@ }, /turf/open/floor/iron/white/smooth_large, /area/station/service/kitchen/diner) +"rgh" = ( +/obj/structure/railing/wooden_fence{ + dir = 6 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rgi" = ( /obj/structure/sign/poster/contraband/random/directional/west, /turf/open/floor/plating, @@ -56350,6 +56449,10 @@ /obj/item/stack/package_wrap, /turf/open/floor/wood/large, /area/mine/eva/lower) +"rgn" = ( +/obj/effect/spawner/random/lavaland_mob/raptor, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rgs" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -57046,6 +57149,11 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/service) +"rrE" = ( +/obj/structure/railing/wooden_fence, +/obj/item/flashlight/lantern/on, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rrV" = ( /obj/effect/spawner/structure/window/hollow/reinforced/end, /turf/open/floor/plating, @@ -57114,6 +57222,15 @@ /obj/structure/sign/poster/random/directional/north, /turf/open/floor/iron, /area/station/hallway/secondary/service) +"rtl" = ( +/obj/structure/marker_beacon/burgundy{ + name = "landing marker" + }, +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "rtn" = ( /obj/structure/chair/comfy/black, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -60256,6 +60373,12 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) +"sqZ" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "sra" = ( /obj/structure/table, /obj/item/flashlight{ @@ -61614,6 +61737,12 @@ }, /turf/open/floor/plating/icemoon, /area/station/security/execution/education) +"sJx" = ( +/obj/structure/railing/wooden_fence{ + dir = 9 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "sJA" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -61734,6 +61863,10 @@ dir = 1 }, /area/station/medical/chemistry) +"sLI" = ( +/obj/item/flashlight/lantern/on, +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/explored) "sLR" = ( /obj/machinery/conveyor{ dir = 1; @@ -63070,6 +63203,12 @@ }, /turf/open/floor/iron/dark, /area/station/commons/fitness) +"tld" = ( +/obj/structure/railing/wooden_fence{ + dir = 5 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "tlh" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -68081,6 +68220,9 @@ }, /turf/open/floor/plating, /area/station/engineering/storage/tech) +"uQX" = ( +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "uQY" = ( /obj/structure/window/reinforced/spawner/directional/east, /turf/open/floor/carpet, @@ -69342,6 +69484,10 @@ /obj/structure/cable, /turf/open/floor/iron/large, /area/station/hallway/secondary/entry) +"vmJ" = ( +/obj/structure/railing/wooden_fence, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "vmP" = ( /obj/effect/spawner/structure/window/hollow/reinforced/end, /turf/open/floor/plating, @@ -72059,6 +72205,12 @@ }, /turf/open/floor/iron/smooth_edge, /area/station/command/heads_quarters/rd) +"wfU" = ( +/obj/structure/railing/wooden_fence{ + dir = 1 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "wgr" = ( /obj/structure/cable, /obj/machinery/door/poddoor/preopen{ @@ -73792,6 +73944,11 @@ /obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"wFI" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "wFN" = ( /mob/living/basic/slime, /turf/open/floor/engine, @@ -78541,6 +78698,12 @@ "ybQ" = ( /turf/closed/wall/r_wall, /area/station/ai_monitored/command/nuke_storage) +"ybW" = ( +/obj/structure/railing/wooden_fence{ + dir = 10 + }, +/turf/open/misc/hay/icemoon, +/area/icemoon/surface) "yca" = ( /obj/machinery/door/airlock/maintenance{ name = "Mining Station Maintenance" @@ -168378,22 +168541,22 @@ thA thA thA thA -thA -thA -thA -thA -xMq -ebd +mME +mME +mME +mME +mME +mME +mME +mME +hma +hma +nwn +rtl +oUe iDt iDt iDt -scw -iDt -nfG -thA -thA -thA -iDt iDt iDt scw @@ -168635,22 +168798,22 @@ thA thA thA thA -thA -thA -thA -thA -xMq -xMq -iDt -iDt +mME +kTp +iiv +iiv +wfU +kTp +iiv +vmJ ijY -xMq -thA -thA -thA -thA -thA -nfG +iDt +iDt +iDt +msC +iDt +iDt +jZN iDt iDt iDt @@ -168892,22 +169055,22 @@ thA thA thA thA -thA -thA -thA -thA -thA -xMq -xMq -scw -xMq -xMq -thA -thA -thA -thA -thA -xMq +mME +dya +iiv +iiv +wfU +dya +iiv +vmJ +iDt +iDt +iDt +iDt +msC +iDt +iDt +iDt iDt scw cCb @@ -169149,23 +169312,23 @@ thA thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA +mME +iiv +iiv +iiv +wfU +iiv +iiv +vmJ +iDt +iDt +rgn +iDt +msC +iDt +iDt +iDt +iDt iDt iDt iDt @@ -169406,23 +169569,23 @@ tjo thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -xMq -xMq +mME +sqZ +sqZ +iiv +tld +sqZ +iiv +eaM +iDt +iDt +iDt +iDt +msC +iDt +iDt +iDt +iDt ijY iDt iDt @@ -169660,34 +169823,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -xMq -xMq -xMq -xMq +mME +iiv +iiv +iiv +iiv +iiv +iiv +iiv iDt iDt +iDt +iDt +rrE scw iDt +scw +scw +scw iDt +scw +scw iDt -iDt +ouz +sLI +scw scw iDt iDt @@ -169917,34 +170080,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo thA thA thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -thA -psb -scw -psb +mME +pbv +wFI +iiv +iiv +eJo +wFI +iiv +rgn iDt -thA -thA -xMq -ijY -jZN +iDt +iDt +iDt +scw +scw +scw +scw +scw +scw +scw +jrY +jrY +scw +gOv +nfG scw iDt iDt @@ -170174,34 +170337,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA -thA -thA -thA thA thA thA +mME +iiv +iiv +iiv +iiv +iiv +iiv +iiv iDt +iDt +iDt +iDt +rrE +scw +scw scw iDt scw -iDt -thA -thA -thA -xMq -xMq +scw +scw +uQX +jrY +jrY +scw +scw aRt aRt xMq @@ -170431,34 +170594,34 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA thA thA thA +mME +fNL +fNL +iiv +sJx +fNL +iiv +ybW iDt iDt -psb -scw -psb iDt -thA -thA -thA -thA -thA +iDt +msC +iDt +iDt +iDt +iDt +iDt +iDt +iDt +uQX +jGp +uQX +uQX +uQX iDt scw thA @@ -170688,33 +170851,33 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA thA thA thA +mME +iiv +iiv +iiv +wfU +iiv +iiv +vmJ +iDt +iDt +rgn +iDt +msC iDt iDt iDt daZ iDt iDt -thA -thA -thA -thA -thA +jvk +uQX +uQX +uQX +uQX iDt iDt iDt @@ -170945,28 +171108,28 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA thA thA thA +mME +dya +iiv +iiv +wfU +dya +iiv +vmJ +iDt +iDt +iDt +iDt +msC iDt iDt iDt iDt iDt -iDt -iDt -thA +jvk thA thA thA @@ -171202,24 +171365,24 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo -thA -thA -thA -thA thA thA thA +mME +kTp +iiv +iiv +wfU +kTp +iiv +vmJ iDt iDt iDt iDt +msC +iDt +iDt iDt iDt iDt @@ -171459,22 +171622,22 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo thA thA thA -thA -thA -thA -iDt -iDt -iDt +mME +mME +mME +mME +mME +mME +mME +mME +pLb +nwn +pLb +pLb +rgh iDt daZ iDt @@ -171716,18 +171879,18 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo -tjo thA thA thA thA thA +thA +thA +thA +thA +iDt +iDt +iDt iDt xPu iDt @@ -171974,16 +172137,16 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo thA thA thA thA +thA +thA +thA +thA +iDt +iDt iDt iDt aaD @@ -172231,15 +172394,15 @@ tjo tjo tjo tjo -tjo -tjo -tjo -tjo -tjo -tjo thA thA thA +thA +thA +thA +thA +thA +iDt iDt iDt iDt diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index 5ebd7a02e91..72fe092d5ca 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -343,6 +343,12 @@ /obj/structure/cable, /turf/open/floor/plating, /area/mine/maintenance/service) +"ct" = ( +/obj/structure/railing/wooden_fence{ + dir = 6 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "cw" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1299,6 +1305,9 @@ /obj/structure/stone_tile, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"hM" = ( +/turf/closed/wall/mineral/wood/nonmetal, +/area/lavaland/surface) "hR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1397,6 +1406,10 @@ /obj/item/clothing/glasses/meson, /turf/open/floor/iron/dark, /area/mine/storage/public) +"il" = ( +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "io" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1669,6 +1682,12 @@ dir = 8 }, /area/mine/production) +"jX" = ( +/obj/structure/railing/wooden_fence{ + dir = 1 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "ka" = ( /obj/structure/table, /obj/machinery/newscaster/directional/north, @@ -1930,6 +1949,12 @@ }, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) +"lt" = ( +/obj/structure/railing/wooden_fence{ + dir = 5 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "lv" = ( /obj/structure/stone_tile/block/cracked{ dir = 8 @@ -2156,6 +2181,17 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"mk" = ( +/obj/structure/table/wood, +/obj/item/raptor_dex{ + pixel_y = 13 + }, +/obj/item/raptor_dex{ + pixel_y = 7 + }, +/obj/item/raptor_dex, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "ml" = ( /obj/structure/stone_tile/block/cracked{ dir = 8 @@ -2833,7 +2869,7 @@ /area/mine/laborcamp/production) "ps" = ( /obj/structure/cable, -/obj/machinery/power/smes/super/full, +/obj/machinery/power/smes/full, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/service) @@ -3006,6 +3042,12 @@ dir = 4 }, /area/mine/laborcamp/quarters) +"qi" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "qo" = ( /obj/machinery/door/airlock/glass{ name = "Equipment Storage" @@ -3146,17 +3188,6 @@ }, /turf/open/floor/iron/smooth, /area/mine/laborcamp) -"rr" = ( -/obj/structure/cable, -/obj/machinery/door/airlock/external{ - name = "Mining External Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "lavaland_services_north" - }, -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, -/turf/open/floor/plating, -/area/mine/maintenance/service) "rv" = ( /obj/effect/turf_decal/trimline/brown/filled/line, /turf/open/floor/iron/dark/smooth_edge{ @@ -3255,6 +3286,11 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/service) +"sa" = ( +/obj/structure/table/wood, +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "se" = ( /turf/open/floor/iron/dark/textured_large, /area/mine/eva) @@ -3351,6 +3387,10 @@ "sO" = ( /turf/open/floor/plating, /area/mine/maintenance/service) +"sQ" = ( +/obj/structure/ore_container/food_trough/raptor_trough, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "sR" = ( /obj/machinery/light/small/directional/west, /obj/effect/decal/cleanable/dirt, @@ -3430,7 +3470,7 @@ name = "Mining Station Maintenance" }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, +/obj/effect/mapping_helpers/airlock/access/all/engineering/atmos, /turf/open/floor/plating, /area/mine/maintenance/service) "ti" = ( @@ -3602,6 +3642,10 @@ }, /turf/open/floor/iron/white/smooth_edge, /area/mine/cafeteria) +"uw" = ( +/obj/effect/spawner/random/lavaland_mob/raptor, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "ux" = ( /obj/machinery/door/airlock{ id_tag = "miningdorm1"; @@ -3683,7 +3727,7 @@ name = "Mining Station Maintenance" }, /obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, +/obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/plating, /area/mine/maintenance/service) "vd" = ( @@ -4122,7 +4166,7 @@ name = "Mining Station Maintenance" }, /obj/structure/cable, -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, +/obj/effect/mapping_helpers/airlock/access/all/engineering/tcoms, /turf/open/floor/plating, /area/mine/maintenance/service/comms) "xJ" = ( @@ -4172,10 +4216,6 @@ dir = 1 }, /area/mine/storage/public) -"xX" = ( -/obj/structure/gulag_vent, -/turf/open/misc/asteroid/basalt/lava_land_surface, -/area/lavaland/surface/outdoors) "yc" = ( /obj/docking_port/stationary{ dir = 2; @@ -4349,6 +4389,10 @@ /obj/structure/rack, /turf/open/floor/plating, /area/mine/maintenance/service) +"ze" = ( +/obj/effect/spawner/random/lavaland_mob/raptor, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "zf" = ( /obj/machinery/door/airlock{ name = "Restroom" @@ -4405,6 +4449,10 @@ /obj/item/cigbutt, /turf/open/floor/iron/smooth, /area/mine/laborcamp) +"zs" = ( +/obj/structure/railing/wooden_fence, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "zw" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4503,7 +4551,7 @@ /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "Af" = ( -/obj/machinery/mineral/processing_unit/gulag{ +/obj/machinery/mineral/processing_unit{ dir = 1; input_dir = 8; output_dir = 4 @@ -4740,6 +4788,12 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) +"Cv" = ( +/obj/structure/railing/wooden_fence{ + dir = 5 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "Cz" = ( /obj/machinery/door/airlock/medical/glass{ name = "Infirmary" @@ -4914,6 +4968,12 @@ "Dz" = ( /turf/closed/wall, /area/mine/medical) +"DB" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "DF" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4978,7 +5038,7 @@ /turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) "Ee" = ( -/obj/machinery/power/smes/super/full, +/obj/machinery/power/smes/full, /obj/structure/cable, /turf/open/floor/plating, /area/mine/maintenance/labor) @@ -5318,6 +5378,12 @@ dir = 8 }, /area/mine/production) +"GG" = ( +/obj/structure/railing/wooden_fence{ + dir = 9 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "GH" = ( /obj/machinery/door/airlock/glass{ name = "Arrival Lounge" @@ -6551,6 +6617,12 @@ /obj/machinery/computer/order_console/mining, /turf/open/floor/iron/dark, /area/mine/production) +"NK" = ( +/obj/structure/railing/wooden_fence{ + dir = 1 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "NL" = ( /obj/structure/railing, /obj/structure/lattice/catwalk/mining, @@ -6569,6 +6641,9 @@ dir = 1 }, /area/mine/laborcamp/production) +"NS" = ( +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "NT" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -6730,6 +6805,17 @@ /obj/structure/cable, /turf/open/floor/iron/white/textured_large, /area/mine/cafeteria) +"OW" = ( +/obj/structure/table/wood, +/obj/item/soap/deluxe{ + pixel_y = 11 + }, +/obj/item/soap/deluxe{ + pixel_y = 6 + }, +/obj/item/soap/deluxe, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "OZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7137,17 +7223,6 @@ /obj/structure/closet/toolcloset, /turf/open/floor/plating, /area/mine/maintenance/service) -"Rx" = ( -/obj/machinery/door/airlock/external{ - name = "Mining External Airlock" - }, -/obj/structure/disposalpipe/segment, -/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ - cycle_id = "lavaland_services_north" - }, -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, -/turf/open/floor/plating, -/area/mine/maintenance/service) "RB" = ( /obj/structure/railing/corner{ dir = 1 @@ -7432,6 +7507,12 @@ dir = 4 }, /area/mine/production) +"Tt" = ( +/obj/structure/railing/wooden_fence{ + dir = 10 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "Tu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7503,7 +7584,7 @@ /obj/machinery/door/airlock/maintenance{ name = "Mining Station Maintenance" }, -/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance/departmental, +/obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance, /turf/open/floor/plating, /area/mine/maintenance/service) "TW" = ( @@ -7622,6 +7703,12 @@ }, /turf/open/floor/iron/freezer, /area/mine/living_quarters) +"UI" = ( +/obj/structure/railing/wooden_fence{ + dir = 4 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "UK" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/siding/wideplating_new{ @@ -7699,6 +7786,12 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"Vd" = ( +/obj/structure/railing/wooden_fence{ + dir = 9 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "Ve" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/textured_large, @@ -7842,6 +7935,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/labor) +"VP" = ( +/obj/structure/railing/wooden_fence{ + dir = 8 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface) "VS" = ( /obj/machinery/hydroponics/constructable, /obj/effect/decal/cleanable/dirt, @@ -8006,15 +8105,6 @@ /obj/effect/mapping_helpers/airlock/access/any/supply/mining_station, /turf/open/floor/plating, /area/mine/storage) -"Xb" = ( -/obj/structure/lattice/catwalk/mining, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/item/toy/plush/shark{ - desc = "A plushie depicting a somewhat cartoonish shark. The tag calls it a 'hákarl', noting that it was made by an obscure furniture manufacturer in old Scandinavia. This one seems to have some cable wiring sticking out of its mouth." - }, -/turf/open/lava/smooth/lava_land_surface, -/area/lavaland/surface/outdoors) "Xd" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -22605,7 +22695,7 @@ uU uU uU pU -xX +pU pU ff Gf @@ -29811,7 +29901,7 @@ Xw aj aj aj -Xb +cU aj aj aj @@ -39030,7 +39120,7 @@ pU Dx cm FL -Rx +cm Ao Ao aW @@ -39287,7 +39377,7 @@ pU aD cV fi -rr +cV Jh cr JS @@ -47817,7 +47907,7 @@ aj aj aj pU -aj +pU aj aj aj @@ -49096,15 +49186,15 @@ aj aj aj aj -aj -aj -aj pU pU -aj -aj -aj -aj +pU +pU +pU +pU +pU +pU +pU aj aj "} @@ -49352,18 +49442,18 @@ aj aj aj aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +GG +DB +DB +hM +hM +hM +hM +hM +hM +hM +hM +hM "} (160,1,1) = {" aa @@ -49608,19 +49698,19 @@ aj aj aj aj -aj -aj -aj -aj pU -aj -aj -aj -aj -aj -aj -aj -aj +jX +pU +pU +NK +sQ +NS +zs +NS +NS +sQ +NS +hM "} (161,1,1) = {" aa @@ -49865,19 +49955,19 @@ aj aj aj aj -aj -aj -aj pU -aj -aj -aj -aj -aj -aj -aj -aj -aj +jX +pU +pU +NK +il +NS +zs +NS +NS +il +NS +hM "} (162,1,1) = {" aa @@ -50122,19 +50212,19 @@ aj aj aj aj -aj -aj +pU +jX pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj +NK +NS +NS +zs +NS +NS +NS +NS +hM "} (163,1,1) = {" aa @@ -50377,21 +50467,21 @@ aj aj pU aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +pU +pU +jX +pU +pU +Cv +qi +NS +ct +NS +NS +qi +qi +hM "} (164,1,1) = {" aa @@ -50634,21 +50724,21 @@ aj aj pU pU -aj -aj -aj -aj -aj -aj pU pU -aj -aj -aj -aj -aj -aj -aj +pU +pU +ze +pU +NS +NS +NS +NS +NS +uw +NS +NS +hM "} (165,1,1) = {" aa @@ -50893,19 +50983,19 @@ pU pU pU pU -aj -aj pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +pU +pU +NS +mk +sa +NS +NS +NS +OW +sa +hM "} (166,1,1) = {" aa @@ -51152,17 +51242,17 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +pU +NS +NS +uw +NS +NS +NS +NS +NS +hM "} (167,1,1) = {" aa @@ -51408,18 +51498,18 @@ pU pU pU pU +jX pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +Vd +VP +NS +Tt +NS +NS +VP +VP +hM "} (168,1,1) = {" aa @@ -51665,18 +51755,18 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +jX +pU +pU +NK +NS +NS +zs +NS +NS +NS +NS +hM "} (169,1,1) = {" aa @@ -51921,19 +52011,19 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +jX +pU +pU +NK +il +NS +zs +NS +NS +il +NS +hM "} (170,1,1) = {" aa @@ -52178,19 +52268,19 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj -aj +pU +jX +pU +pU +NK +sQ +NS +zs +NS +NS +sQ +NS +hM "} (171,1,1) = {" aa @@ -52435,19 +52525,19 @@ pU pU pU pU -aj -aj -aj -aj -aj -aj pU -aj -aj -aj -aj -aj -aj +lt +UI +UI +hM +hM +hM +hM +hM +hM +hM +hM +hM "} (172,1,1) = {" aa @@ -52693,10 +52783,10 @@ pU pU pU pU -aj -aj -aj -aj +pU +pU +pU +pU aj aj aj @@ -52950,8 +53040,8 @@ pU pU pU pU -pU -pU +aj +aj aj aj aj @@ -52959,7 +53049,7 @@ aj aj pU aj -aj +pU aj aj "} diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 0047c9c63a4..1a2b19740f6 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -14,6 +14,11 @@ #define BB_BREED_READY "BB_breed_ready" ///maximum kids we can have #define BB_MAX_CHILDREN "BB_max_children" +///our current happiness level +#define BB_BASIC_HAPPINESS "BB_basic_happiness" +///can this mob heal? +#define BB_BASIC_MOB_HEALER "BB_basic_mob_healer" + /// Store a single or list of emotes at this key #define BB_EMOTE_KEY "BB_emotes" diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index c827f760b8a..ae74872cd73 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -32,3 +32,43 @@ ///keeps track of how many gutlunches are born GLOBAL_VAR_INIT(gutlunch_count, 0) + +//raptor defines + +#define RAPTOR_RED "Red" +#define RAPTOR_GREEN "Green" +#define RAPTOR_PURPLE "Purple" +#define RAPTOR_WHITE "White" +#define RAPTOR_YELLOW "Yellow" +#define RAPTOR_BLACK "Black" +#define RAPTOR_BLUE "Blue" + +#define RAPTOR_INHERIT_MAX_ATTACK 5 +#define RAPTOR_INHERIT_MAX_HEALTH 30 + +///this mob suffers depression +#define BB_BASIC_DEPRESSED "basic_depressed" +///this mob will care for its young +#define BB_RAPTOR_MOTHERLY "raptor_motherly" +///this mob will be playful around their owners +#define BB_RAPTOR_PLAYFUL "raptor_playful" +///this mob will flee combat when it feels threatened +#define BB_RAPTOR_COWARD "raptor_coward" +///this mob will go out seeking trouble against its kind +#define BB_RAPTOR_TROUBLE_MAKER "raptor_trouble_maker" +///cooldown till we go out cause trouble again +#define BB_RAPTOR_TROUBLE_COOLDOWN "raptor_trouble_maker_cooldown" +///our raptor baby target we will take care of +#define BB_RAPTOR_BABY "raptor_baby" +///the raptor we will heal up +#define BB_INJURED_RAPTOR "injured_raptor" +///the raptor we will bully +#define BB_RAPTOR_VICTIM "raptor_victim" +///the cooldown for next time we eat +#define BB_RAPTOR_EAT_COOLDOWN "raptor_eat_cooldown" +///our trough target +#define BB_RAPTOR_TROUGH_TARGET "raptor_trough_target" + +#define MAX_RAPTOR_POP 64 + + diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm index 932fc008848..f79f91ff641 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm @@ -18,6 +18,7 @@ #define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" //from base of atom/attack_basic_mob(): (/mob/user) #define COMSIG_ATOM_ATTACK_BASIC_MOB "attack_basic_mob" + #define COMSIG_BASIC_ATTACK_CANCEL_CHAIN (1<<0) /// from /atom/proc/atom_break: (damage_flag) #define COMSIG_ATOM_BREAK "atom_break" /// from base of [/atom/proc/atom_fix]: () diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm index 2ea2e4d5fe3..06d372ceb0d 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm @@ -9,6 +9,8 @@ ///from base of atom/ShiftClick(): (/mob) #define COMSIG_CLICK_SHIFT "shift_click" #define COMPONENT_ALLOW_EXAMINATE (1<<0) //! Allows the user to examinate regardless of client.eye. +///from base of atom/ShiftClick() +#define COMSIG_SHIFT_CLICKED_ON "shift_clicked_on" ///from base of atom/CtrlClickOn(): (/mob) #define COMSIG_CLICK_CTRL "ctrl_click" ///from base of atom/AltClick(): (/mob) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 5a328a62ef7..8f7fa11f57b 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -273,3 +273,6 @@ /// From /datum/element/basic_eating/finish_eating() #define COMSIG_MOB_ATE "mob_ate" + +///From /datum/component/happiness() +#define COMSIG_MOB_HAPPINESS_CHANGE "happiness_change" diff --git a/code/__DEFINES/mobfactions.dm b/code/__DEFINES/mobfactions.dm index d503a499d0d..aea143dad25 100644 --- a/code/__DEFINES/mobfactions.dm +++ b/code/__DEFINES/mobfactions.dm @@ -83,7 +83,8 @@ #define FACTION_TURRET "turret" /// Vines, lots of overlap with plants #define FACTION_VINES "vines" - +///raptor factions +#define FACTION_RAPTOR "raptor" // Antagonist factions /// Cultists and their constructs diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 474f5069227..4c1411d3cfd 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1083,8 +1083,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given to a dragon who fails to defend their rifts #define TRAIT_RIFT_FAILURE "fail_dragon_loser" +///this mob is able to relay happiness, given by /datum/component/happiness +#define TRAIT_MOB_RELAY_HAPPINESS "mob_relay_happiness" ///trait determines if this mob can breed given by /datum/component/breeding #define TRAIT_MOB_BREEDER "mob_breeder" +///trait given to mobs that are hatched +#define TRAIT_MOB_HATCHED "mob_hatched" /// Trait given to mobs that we do not want to mindswap #define TRAIT_NO_MINDSWAP "no_mindswap" ///trait given to food that can be baked by /datum/component/bakeable diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 2cd5e354a5e..19449c6e463 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -298,6 +298,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MIND_TEMPORARILY_GONE" = TRAIT_MIND_TEMPORARILY_GONE, "TRAIT_MOB_BREEDER" = TRAIT_MOB_BREEDER, "TRAIT_MOB_EATER" = TRAIT_MOB_EATER, + "TRAIT_MOB_HATCHED" = TRAIT_MOB_HATCHED, + "TRAIT_MOB_RELAY_HAPPINESS" = TRAIT_MOB_RELAY_HAPPINESS, "TRAIT_MOB_TIPPED" = TRAIT_MOB_TIPPED, "TRAIT_MORBID" = TRAIT_MORBID, "TRAIT_MULTIZ_SUIT_SENSORS" = TRAIT_MULTIZ_SUIT_SENSORS, diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index eecad5c7522..3c99364542c 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -341,6 +341,7 @@ return /atom/proc/ShiftClick(mob/user) + SEND_SIGNAL(src, COMSIG_SHIFT_CLICKED_ON, user) var/flags = SEND_SIGNAL(user, COMSIG_CLICK_SHIFT, src) if(flags & COMSIG_MOB_CANCEL_CLICKON) return diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index f46ab02433d..0dd8ee0a582 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -187,7 +187,8 @@ ///When a basic mob attacks something, either by AI or user. /atom/proc/attack_basic_mob(mob/user, list/modifiers) SHOULD_CALL_PARENT(TRUE) - SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_BASIC_MOB, user) + if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_BASIC_MOB, user) & COMSIG_BASIC_ATTACK_CANCEL_CHAIN) + return return handle_basic_attack(user, modifiers) //return value of attack animal, this is how much damage was dealt to the attacked thing ///This exists so stuff can override the default call of attack_animal for attack_basic_mob diff --git a/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm new file mode 100644 index 00000000000..74ec9d98191 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm @@ -0,0 +1,44 @@ +#define HIGH_HAPPINESS_THRESHOLD 0.7 +#define MODERATE_HAPPINESS_THRESHOLD 0.5 + +/datum/ai_planning_subtree/express_happiness + operational_datums = list(/datum/component/happiness) + ///the key storing our happiness value + var/happiness_key = BB_BASIC_HAPPINESS + ///list of emotions we relay when happy + var/static/list/happy_emotions = list( + "celebrate happily!", + "dances around in excitement!", + ) + ///our moderate emotions + var/static/list/moderate_emotions = list( + "looks satisfied.", + "trots around.", + ) + ///emotions we display when we are sad + var/static/list/depressed_emotions = list( + "looks depressed...", + "turns its back and sulks...", + "looks towards the floor in dissapointment...", + ) + +/datum/ai_planning_subtree/express_happiness/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!SPT_PROB(5, seconds_per_tick)) + return + var/happiness_value = controller.blackboard[happiness_key] + if(isnull(happiness_value)) + return + var/list/final_list + switch(happiness_value) + if(HIGH_HAPPINESS_THRESHOLD to INFINITY) + final_list = happy_emotions + if(MODERATE_HAPPINESS_THRESHOLD to HIGH_HAPPINESS_THRESHOLD) + final_list = moderate_emotions + else + final_list = depressed_emotions + if(!length(final_list)) + return + controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(final_list)) + +#undef HIGH_HAPPINESS_THRESHOLD +#undef MODERATE_HAPPINESS_THRESHOLD diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm index 2c65dfbb6a9..ef44df82f78 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm @@ -11,7 +11,7 @@ return if(get_dist(target, baby) > minimum_distance) - controller.queue_behavior(/datum/ai_behavior/travel_towards, BB_FOUND_MOM) + controller.queue_behavior(/datum/ai_behavior/travel_towards/stop_on_arrival, BB_FOUND_MOM) return SUBTREE_RETURN_FINISH_PLANNING if(!SPT_PROB(15, seconds_per_tick)) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm index 6630f7d193d..d9e0d1e7fb9 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm @@ -9,13 +9,16 @@ /// Find the nearest thing on our list of 'things which have done damage to me' and set it as the flee target /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee + ///the targeting strategy we use var/targeting_key = BB_TARGETING_STRATEGY + ///what key should we set the target as + var/target_key = BB_BASIC_MOB_CURRENT_TARGET /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING]) return - controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key targeting_key = BB_FLEE_TARGETING_STRATEGY diff --git a/code/datums/components/breeding.dm b/code/datums/components/breeding.dm index 7c9bcecf7bc..3c2ffb61b5a 100644 --- a/code/datums/components/breeding.dm +++ b/code/datums/components/breeding.dm @@ -62,7 +62,7 @@ return COMPONENT_HOSTILE_NO_ATTACK var/turf/delivery_destination = get_turf(source) - var/mob/living/baby = new baby_path(delivery_destination) + var/atom/baby = new baby_path(delivery_destination) new /obj/effect/temp_visual/heart(delivery_destination) toggle_status(source) diff --git a/code/datums/components/fertile_egg.dm b/code/datums/components/fertile_egg.dm index dba704812b0..59100028e85 100644 --- a/code/datums/components/fertile_egg.dm +++ b/code/datums/components/fertile_egg.dm @@ -29,7 +29,10 @@ /// If true, being in an unsuitable location spoils the egg (ie. kills the component). If false, it just pauses the egg's development. var/spoilable -/datum/component/fertile_egg/Initialize(embryo_type, minimum_growth_rate, maximum_growth_rate, total_growth_required, current_growth, location_allowlist, spoilable, examine_message) + ///callback after the egg hatches + var/datum/callback/post_hatch + +/datum/component/fertile_egg/Initialize(embryo_type, minimum_growth_rate, maximum_growth_rate, total_growth_required, current_growth, location_allowlist, spoilable, examine_message, post_hatch) // Quite how an _area_ can be a fertile egg is an open question, but it still has a location. Technically. if(!isatom(parent)) return COMPONENT_INCOMPATIBLE @@ -41,6 +44,7 @@ src.current_growth = current_growth src.location_allowlist = location_allowlist src.spoilable = spoilable + src.post_hatch = post_hatch START_PROCESSING(SSobj, src) @@ -58,8 +62,10 @@ return current_growth += rand(minimum_growth_rate, maximum_growth_rate) * seconds_per_tick - if(current_growth >= total_growth_required) - parent_atom.visible_message(span_notice("[parent] hatches with a quiet cracking sound.")) - new embryo_type(get_turf(parent_atom)) - // We destroy the parent on hatch, which will destroy the component as well, which will stop us processing. - qdel(parent_atom) + if(current_growth < total_growth_required) + return + parent_atom.visible_message(span_notice("[parent] hatches with a quiet cracking sound.")) + new embryo_type(get_turf(parent_atom)) + post_hatch?.Invoke(embryo_type) + // We destroy the parent on hatch, which will destroy the component as well, which will stop us processing. + qdel(parent_atom) diff --git a/code/datums/components/growth_and_differentiation.dm b/code/datums/components/growth_and_differentiation.dm index a6e10b98f6d..bcf67224922 100644 --- a/code/datums/components/growth_and_differentiation.dm +++ b/code/datums/components/growth_and_differentiation.dm @@ -37,6 +37,7 @@ growth_probability, lower_growth_value, upper_growth_value, + scale_with_happiness, list/signals_to_kill_on, datum/callback/optional_checks, datum/callback/optional_grow_behavior, @@ -55,6 +56,11 @@ if(islist(signals_to_kill_on)) src.signals_to_kill_on = signals_to_kill_on RegisterSignals(parent, src.signals_to_kill_on, PROC_REF(stop_component_processing_entirely)) + + if(scale_with_happiness) + if(!HAS_TRAIT(parent, TRAIT_MOB_RELAY_HAPPINESS)) + AddComponent(/datum/component/happiness) + RegisterSignal(parent, COMSIG_MOB_HAPPINESS_CHANGE, PROC_REF(on_happiness_change)) // If we haven't started the round, we can't do timer stuff. Let's wait in case we're mapped in or something. if(!SSticker.HasRoundStarted() && !isnull(growth_time)) @@ -113,6 +119,12 @@ if(SPT_PROB(growth_probability, seconds_per_tick)) percent_grown += rand(lower_growth_value, upper_growth_value) +/datum/component/growth_and_differentiation/proc/on_happiness_change(datum/source, happiness_percentage) + SIGNAL_HANDLER + + var/probability_to_add = initial(growth_probability) * happiness_percentage + growth_probability = min(initial(growth_probability) + probability_to_add, 100) + /// Grows the mob into its new form. /datum/component/growth_and_differentiation/proc/grow(silent) if(!isnull(optional_checks) && !optional_checks.Invoke()) // we failed our checks somehow, but we're still ready to grow. Let's wait until next tick to see if our circumstances have changed. @@ -143,3 +155,4 @@ var/mob/living/transformed_mob = old_mob.change_mob_type(growth_path, old_mob.loc, new_name = new_mob_name, delete_old_mob = TRUE) if(initial(new_mob.unique_name)) transformed_mob.set_name() + ADD_TRAIT(transformed_mob, TRAIT_MOB_HATCHED, INNATE_TRAIT) diff --git a/code/datums/components/happiness.dm b/code/datums/components/happiness.dm new file mode 100644 index 00000000000..0a627461192 --- /dev/null +++ b/code/datums/components/happiness.dm @@ -0,0 +1,159 @@ +#define INSPECT_TIMER 10 SECONDS +#define PET_COOLDOWN 10 SECONDS +#define GROOM_COOLDOWN 30 SECONDS + +/* + * A component that allows mobs to have happiness levels + */ +/datum/component/happiness + ///our current happiness level + var/happiness_level + ///our maximum happiness level + var/maximum_happiness + ///happiness AI blackboard key + var/blackboard_key + ///happiness when we get groomed + var/on_groom_change + ///happiness when we get petted + var/on_petted_change + ///happiness when we eat + var/on_eat_change + ///percentages we should be calling back on + var/list/callback_percentages + ///callback when our happiness changes + var/datum/callback/happiness_callback + + ///how long till we can inspect happiness again? + COOLDOWN_DECLARE(happiness_inspect) + ///how long till we can pet it again? + COOLDOWN_DECLARE(pet_cooldown) + ///how long till we can groom it again + COOLDOWN_DECLARE(groom_cooldown) + +/datum/component/happiness/Initialize(maximum_happiness = 400, blackboard_key = BB_BASIC_HAPPINESS, on_groom_change = 200, on_eat_change = 300, on_petted_change = 30, callback_percentages = list(0, 25, 50, 75, 100), happiness_callback) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + + src.maximum_happiness = maximum_happiness + src.blackboard_key = blackboard_key + src.on_groom_change = on_groom_change + src.on_petted_change = on_petted_change + src.on_eat_change = on_eat_change + src.happiness_callback = happiness_callback + src.callback_percentages = callback_percentages + + ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + +/datum/component/happiness/RegisterWithParent() + + if(on_petted_change) + RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_petted)) + if(on_groom_change) + RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean)) + if(on_eat_change) + RegisterSignal(parent, COMSIG_MOB_ATE, PROC_REF(on_eat)) + RegisterSignal(parent, COMSIG_SHIFT_CLICKED_ON, PROC_REF(view_happiness)) + ADD_TRAIT(parent, TRAIT_MOB_RELAY_HAPPINESS, REF(src)) + +/datum/component/happiness/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_MOB_ATE)) + REMOVE_TRAIT(parent, TRAIT_MOB_RELAY_HAPPINESS, REF(src)) + happiness_callback = null + +/datum/component/happiness/proc/on_eat(datum/source) + SIGNAL_HANDLER + + increase_happiness_level(on_eat_change) + +/datum/component/happiness/proc/on_clean(mob/living/source) + SIGNAL_HANDLER + if(!COOLDOWN_FINISHED(src, groom_cooldown)) + return + COOLDOWN_START(src, groom_cooldown, GROOM_COOLDOWN) + increase_happiness_level(on_groom_change) + +/datum/component/happiness/proc/on_petted(datum/source, mob/living/petter, list/modifiers) + SIGNAL_HANDLER + if(!LAZYACCESS(modifiers, LEFT_CLICK) || petter.combat_mode) + return + pet_animal() + +/datum/component/happiness/proc/on_animal_petted(datum/source, mob/living/petter) + SIGNAL_HANDLER + + if(petter.combat_mode) + return + pet_animal() + return COMSIG_BASIC_ATTACK_CANCEL_CHAIN + +/datum/component/happiness/proc/pet_animal() + if(!COOLDOWN_FINISHED(src, pet_cooldown)) + return + increase_happiness_level(on_petted_change) + COOLDOWN_START(src, pet_cooldown, PET_COOLDOWN) + + +/datum/component/happiness/proc/increase_happiness_level(amount) + happiness_level = min(happiness_level + amount, maximum_happiness) + var/mob/living/living_parent = parent + new /obj/effect/temp_visual/heart(living_parent.loc) + living_parent.spin(spintime = 2 SECONDS, speed = 1) + START_PROCESSING(SSprocessing, src) + +/datum/component/happiness/proc/view_happiness(mob/living/source, mob/living/clicker) + if(!istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !clicker.CanReach(source)) + return + var/list/offset_to_add = get_icon_dimensions(source.icon) + var/y_position = offset_to_add["height"] + 1 + var/obj/effect/overlay/happiness_overlay/hearts = new + hearts.pixel_y = y_position + hearts.set_hearts(happiness_level/maximum_happiness) + source.vis_contents += hearts + COOLDOWN_START(src, happiness_inspect, INSPECT_TIMER) + + +/datum/component/happiness/process() + var/mob/living/living_parent = parent + var/happiness_percentage = happiness_level/maximum_happiness + living_parent.ai_controller?.set_blackboard_key(blackboard_key, happiness_percentage) + var/check_percentage_in_list = round(happiness_percentage * 100, 1) + if(check_percentage_in_list in callback_percentages) + SEND_SIGNAL(parent, COMSIG_MOB_HAPPINESS_CHANGE, happiness_percentage) + happiness_callback?.Invoke(happiness_percentage) + + if(happiness_level <= 0) + return PROCESS_KILL + var/modifier = living_parent.ai_controller?.blackboard[BB_BASIC_DEPRESSED] ? 2 : 1 + happiness_level = max(0, happiness_level - modifier) + +/obj/effect/overlay/happiness_overlay + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + anchored = TRUE + vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE + layer = ABOVE_HUD_PLANE + ///how many hearts should we display + VAR_PRIVATE/hearts_percentage + ///icon of our heart + var/heart_icon = 'icons/effects/effects.dmi' + +/obj/effect/overlay/happiness_overlay/Initialize(mapload) + . = ..() + QDEL_IN(src, 5 SECONDS) + +/obj/effect/overlay/happiness_overlay/proc/set_hearts(happiness_percentage) + hearts_percentage = happiness_percentage + update_appearance(UPDATE_OVERLAYS) + +/obj/effect/overlay/happiness_overlay/update_overlays() + . = ..() + var/static/list/heart_positions = list(-13, -5, 3, 11) + var/display_amount = round(length(heart_positions) * hearts_percentage, 1) + for(var/index in 1 to length(heart_positions)) + var/heart_icon_state = display_amount >= index ? "full_heart" : "empty_heart" + var/mutable_appearance/display_icon = mutable_appearance(icon = heart_icon, icon_state = heart_icon_state, layer = ABOVE_HUD_PLANE) + display_icon.pixel_x = heart_positions[index] + . += display_icon + +#undef INSPECT_TIMER +#undef PET_COOLDOWN +#undef GROOM_COOLDOWN diff --git a/code/datums/components/healing_touch.dm b/code/datums/components/healing_touch.dm index bc0493b4787..07f04cba01d 100644 --- a/code/datums/components/healing_touch.dm +++ b/code/datums/components/healing_touch.dm @@ -90,6 +90,8 @@ RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_healing)) // Players RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(try_healing)) // NPCs + var/mob/living/living_parent = parent + living_parent.ai_controller?.set_blackboard_key(BB_BASIC_MOB_HEALER, TRUE) // Let's populate this list as we actually use it, this thing has too many args /datum/component/healing_touch/InheritComponent( @@ -100,6 +102,8 @@ src.heal_color = heal_color /datum/component/healing_touch/UnregisterFromParent() + var/mob/living/living_parent = parent + living_parent.ai_controller?.set_blackboard_key(BB_BASIC_MOB_HEALER, FALSE) UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)) return ..() diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 7ac6027944c..7ead11012b0 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -118,6 +118,7 @@ if (HAS_TRAIT(parent, trait)) ADD_TRAIT(rider, trait, REF(src)) rider.add_traits(rider_traits, REF(src)) + post_vehicle_mob_buckle(movable_parent, rider) /// This proc is called when the rider attempts to grab the thing they're riding, preventing them from doing so. /datum/component/riding/proc/on_rider_try_pull(mob/living/rider_pulling, atom/movable/target, force) @@ -127,6 +128,10 @@ ridden.balloon_alert(rider_pulling, "not while riding it!") return COMSIG_LIVING_CANCEL_PULL +///any behavior we want to happen after buckling the mob +/datum/component/riding/proc/post_vehicle_mob_buckle(atom/movable/ridden, atom/movable/rider) + return TRUE + /// Some ridable atoms may want to only show on top of the rider in certain directions, like wheelchairs /datum/component/riding/proc/handle_vehicle_layer(dir) var/atom/movable/AM = parent diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index 20afd232726..d6c07d43423 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -5,6 +5,8 @@ var/can_be_driven = TRUE /// If TRUE, this creature's abilities can be triggered by the rider while mounted var/can_use_abilities = FALSE + /// shall we require riders to go through the riding minigame if they arent in our friends list + var/require_minigame = FALSE /// list of blacklisted abilities that cant be shared var/list/blacklist_abilities = list() @@ -216,6 +218,14 @@ else if(ride_check_flags & CARRIER_NEEDS_ARM) // fireman human_parent.buckle_lying = 90 +/datum/component/riding/creature/post_vehicle_mob_buckle(mob/living/ridden, mob/living/rider) + if(!require_minigame || ridden.faction.Find(REF(rider))) + return + ridden.Shake(duration = 2 SECONDS) + ridden.balloon_alert(rider, "tries to shake you off!") + var/datum/riding_minigame/game = new(ridden, rider, FALSE) + game.commence_minigame() + /datum/component/riding/creature/human/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_host_unarmed_melee)) @@ -522,3 +532,127 @@ /datum/component/riding/leaper/handle_unbuckle(mob/living/rider) . = ..() UnregisterSignal(rider, COMSIG_MOB_POINTED) + +/datum/component/riding/creature/raptor + require_minigame = TRUE + ride_check_flags = RIDER_NEEDS_ARM + +/datum/component/riding/creature/raptor/handle_specials() + . = ..() + if(!SSmapping.is_planetary()) + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(7, 7), TEXT_SOUTH = list(2, 10), TEXT_EAST = list(12, 7), TEXT_WEST = list(10, 7))) + else + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 7), TEXT_SOUTH = list(0, 10), TEXT_EAST = list(-3, 9), TEXT_WEST = list(3, 9))) + set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) + set_vehicle_dir_layer(NORTH, OBJ_LAYER) + set_vehicle_dir_layer(EAST, OBJ_LAYER) + set_vehicle_dir_layer(WEST, OBJ_LAYER) + +/datum/component/riding/creature/raptor/fast + vehicle_move_delay = 1.5 + +//a simple minigame players must win to mount and tame a mob +/datum/riding_minigame + ///our host mob + var/datum/weakref/host + ///our current rider + var/datum/weakref/mounter + ///the total amount of tries the rider gets + var/maximum_attempts = 6 + ///maximum number of failures before we fail + var/maximum_failures = 3 + ///cached directional icons of our host + var/list/cached_icons = list() + +/datum/riding_minigame/New(mob/living/ridden, mob/living/rider, use_mob_icons = TRUE) + . = ..() + RegisterSignal(rider, COMSIG_MOB_UNBUCKLED, PROC_REF(lose_game)) + host = WEAKREF(ridden) + mounter = WEAKREF(rider) + var/used_icon = use_mob_icons ? initial(ridden.icon) : 'icons/testing/turf_analysis.dmi' + var/used_icon_state = use_mob_icons ? initial(ridden.icon_state) : "red_arrow" + for(var/direction in GLOB.cardinals) + var/icon/directional_icon = getFlatIcon(image(icon = used_icon, icon_state = used_icon_state, dir = direction)) + var/string_icon = icon2base64(directional_icon) + var/opposite_direction = dir2text(REVERSE_DIR(direction)) + cached_icons[opposite_direction] = string_icon + +/datum/riding_minigame/proc/commence_minigame() + set waitfor = FALSE + START_PROCESSING(SSprocessing, src) + var/mob/living/rider = mounter?.resolve() + if(isnull(rider)) + lose_game() + return + ui_interact(rider) + +/datum/riding_minigame/process() + var/mob/living/living_host = host?.resolve() + if(isnull(living_host)) + return PROCESS_KILL + if(prob(60)) //we shake and move uncontrollably! + living_host.Shake(duration = 2 SECONDS) + var/list/new_direction = GLOB.cardinals.Copy() - living_host.dir + living_host.setDir(pick(new_direction)) + +/datum/riding_minigame/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RideMinigame") + ui.open() + +/datum/riding_minigame/ui_static_data(mob/user) + var/list/data = list() + data["maximum_attempts"] = maximum_attempts + data["maximum_failures"] = maximum_failures + data["all_icons"] = list() + for(var/index in cached_icons) + data["all_icons"] += list(list( + "direction" = index, + "icon" = cached_icons[index], + )) + return data + +/datum/riding_minigame/ui_state(mob/user) + return GLOB.always_state + +/datum/riding_minigame/ui_act(action, params, datum/tgui/ui) + . = ..() + switch(action) + if("lose_game") + lose_game() + if("win_game") + win_game() + +/datum/riding_minigame/proc/win_game() + var/mob/living/living_host = host?.resolve() + var/mob/living/living_rider = mounter?.resolve() + if(isnull(living_host) || isnull(living_rider)) + qdel(src) + return + living_host.befriend(living_rider) + living_host.balloon_alert(living_rider, "calms down...") + qdel(src) + +/datum/riding_minigame/proc/lose_game() + var/mob/living/living_host = host?.resolve() + var/mob/living/living_rider = mounter?.resolve() + if(isnull(living_host) || isnull(living_rider)) + qdel(src) + return + if(LAZYFIND(living_host.buckled_mobs, living_rider)) + UnregisterSignal(living_rider, COMSIG_MOB_UNBUCKLED) //we're about to knock them down! + living_host.spin(spintime = 2 SECONDS, speed = 1) + living_rider.Knockdown(4 SECONDS) + living_host.unbuckle_mob(living_rider) + living_host.balloon_alert(living_rider, "knocks you down!") + qdel(src) + +/datum/riding_minigame/ui_close(mob/user) + lose_game() + +/datum/riding_minigame/Destroy() + STOP_PROCESSING(SSprocessing, src) + mounter = null + host = null + return ..() diff --git a/code/datums/components/udder.dm b/code/datums/components/udder.dm index cd87ff44c17..a659efbc504 100644 --- a/code/datums/components/udder.dm +++ b/code/datums/components/udder.dm @@ -204,3 +204,16 @@ reagents.add_reagent(/datum/reagent/medicine/salglu_solution, rand(2,5)) if(on_generate_callback) on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume) + +/obj/item/udder/raptor + name = "bird udder" + +/obj/item/udder/raptor/generate() + if(!prob(production_probability)) + return FALSE + var/happiness_percentage = udder_mob.ai_controller?.blackboard[BB_BASIC_HAPPINESS] + if(prob(happiness_percentage)) + reagents.add_reagent(/datum/reagent/consumable/cream, 5, added_purity = 1) + var/minimum_bound = happiness_percentage > 0.6 ? 10 : 5 + var/upper_bound = minimum_bound + 5 + reagents.add_reagent(reagent_produced_typepath, rand(minimum_bound, upper_bound), added_purity = 1) diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 757fd8b3519..92b303c9be2 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -83,9 +83,14 @@ return TRUE /datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target) + set waitfor = FALSE SEND_SIGNAL(eater, COMSIG_MOB_ATE) if(drinking) playsound(eater.loc,'sound/items/drink.ogg', rand(10,50), TRUE) else playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) - qdel(target) + var/atom/final_target = target + if(isstack(target)) //if stack, only consume 1 + var/obj/item/stack/food_stack = target + final_target = food_stack.split_stack(eater, 1) + qdel(final_target) diff --git a/code/datums/elements/proficient_miner.dm b/code/datums/elements/proficient_miner.dm new file mode 100644 index 00000000000..9a382afce28 --- /dev/null +++ b/code/datums/elements/proficient_miner.dm @@ -0,0 +1,19 @@ +///element given to mobs that can mine when moving +/datum/element/proficient_miner + +/datum/element/proficient_miner/Attach(datum/target) + . = ..() + if(!ismovable(target)) + return + RegisterSignal(target, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump)) + +/datum/element/proficient_miner/proc/on_bump(mob/living/source, atom/target) + SIGNAL_HANDLER + if(!ismineralturf(target)) + return + var/turf/closed/mineral/mineral_wall = target + mineral_wall.gets_drilled(source) + +/datum/element/proficient_miner/Detach(datum/source, ...) + UnregisterSignal(source, COMSIG_MOVABLE_BUMP) + return ..() diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm index 91348dd5c17..dee0bc2bdcc 100644 --- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm +++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm @@ -11,6 +11,7 @@ /mob/living/basic/mining/legion/snow = 50, /mob/living/basic/mining/lobstrosity = 15, /mob/living/basic/mining/wolf = 50, + /obj/effect/spawner/random/lavaland_mob/raptor = 15, /mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon = 3, /obj/structure/spawner/ice_moon/polarbear = 3, @@ -65,7 +66,7 @@ ) mob_spawn_chance = 0.2 - weighted_mob_spawn_list = list(/mob/living/basic/deer/ice = 99, /mob/living/basic/tree = 1) + weighted_mob_spawn_list = list(/mob/living/basic/deer/ice = 99, /mob/living/basic/tree = 1, /obj/effect/spawner/random/lavaland_mob/raptor = 15) /datum/map_generator/cave_generator/icemoon/surface/noruins //use this for when you don't want ruins to spawn in a certain area @@ -76,6 +77,8 @@ /mob/living/basic/mining/ice_demon = 100, /mob/living/basic/mining/ice_whelp = 60, /mob/living/basic/mining/legion/snow = 100, + /obj/effect/spawner/random/lavaland_mob/raptor = 25, + /obj/structure/spawner/ice_moon/demonic_portal = 6, /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 6, /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 6, diff --git a/code/datums/mapgen/Cavegens/LavalandGenerator.dm b/code/datums/mapgen/Cavegens/LavalandGenerator.dm index 846e23181e0..47b62ce4a1b 100644 --- a/code/datums/mapgen/Cavegens/LavalandGenerator.dm +++ b/code/datums/mapgen/Cavegens/LavalandGenerator.dm @@ -10,6 +10,7 @@ /mob/living/basic/mining/bileworm = 20, /mob/living/basic/mining/brimdemon = 20, /mob/living/basic/mining/lobstrosity/lava = 20, + /obj/effect/spawner/random/lavaland_mob/raptor = 15, /mob/living/basic/mining/goldgrub = 10, /obj/structure/spawner/lavaland = 2, /obj/structure/spawner/lavaland/goliath = 3, diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 34c3038460e..90e5a00334a 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -74,6 +74,9 @@ /// If we support smartly removing/inserting things from ourselves var/supports_smart_equip = TRUE + ///do we insert items when clicked by them? + var/insert_on_attack = TRUE + /// An additional description shown on double-examine. /// Is autogenerated to the can_hold list if not set. var/can_hold_description @@ -196,10 +199,10 @@ parent = new_parent // a few of theses should probably be on the real_location rather than the parent + RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_HAND), PROC_REF(on_attack)) RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, PROC_REF(on_mousedrop_onto)) RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(on_mousedropped_onto)) - RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack)) RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(mass_empty)) RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal)) @@ -791,7 +794,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) /datum/storage/proc/on_attackby(datum/source, obj/item/thing, mob/user, params) SIGNAL_HANDLER - if(!thing.attackby_storage_insert(src, parent, user)) + if(!insert_on_attack || !thing.attackby_storage_insert(src, parent, user)) return if(iscyborg(user)) diff --git a/code/game/objects/effects/spawners/random/lavaland_mobs.dm b/code/game/objects/effects/spawners/random/lavaland_mobs.dm index 7b4bec1f6a1..b0957ed84e9 100644 --- a/code/game/objects/effects/spawners/random/lavaland_mobs.dm +++ b/code/game/objects/effects/spawners/random/lavaland_mobs.dm @@ -49,3 +49,17 @@ /mob/living/basic/mining/legion = 19, /mob/living/basic/mining/legion/dwarf = 1, ) + +/obj/effect/spawner/random/lavaland_mob/raptor + name = "random raptor" + desc = "Chance to spawn a rare shiny version." + icon = 'icons/mob/simple/lavaland/raptor_big.dmi' + icon_state = "raptor_red" + loot = list( + /mob/living/basic/mining/raptor/red = 20, + /mob/living/basic/mining/raptor/white = 20, + /mob/living/basic/mining/raptor/purple = 20, + /mob/living/basic/mining/raptor/green = 20, + /mob/living/basic/mining/raptor/yellow = 20, + /mob/living/basic/mining/raptor/black = 1, + ) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index c92e3b7e659..d0b72fe2de8 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -666,6 +666,9 @@ light_color = "#ffcc66" light_system = OVERLAY_LIGHT +/obj/item/flashlight/lantern/on + start_on = TRUE + /obj/item/flashlight/lantern/heirloom_moth name = "old lantern" desc = "An old lantern that has seen plenty of use." diff --git a/code/game/objects/items/food/egg.dm b/code/game/objects/items/food/egg.dm index 356059a097a..62113e02e77 100644 --- a/code/game/objects/items/food/egg.dm +++ b/code/game/objects/items/food/egg.dm @@ -144,12 +144,15 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) /obj/item/food/egg/blue icon_state = "egg-blue" inhand_icon_state = "egg-blue" + /obj/item/food/egg/green icon_state = "egg-green" inhand_icon_state = "egg-green" + /obj/item/food/egg/mime icon_state = "egg-mime" inhand_icon_state = "egg-mime" + /obj/item/food/egg/orange icon_state = "egg-orange" inhand_icon_state = "egg-orange" diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 86da06549a9..155ba411715 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -311,6 +311,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \ new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ + new/datum/stack_recipe("raptor trough", /obj/structure/ore_container/food_trough/raptor_trough, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \ new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ diff --git a/code/game/turfs/open/hay.dm b/code/game/turfs/open/hay.dm new file mode 100644 index 00000000000..b0bd581c2bb --- /dev/null +++ b/code/game/turfs/open/hay.dm @@ -0,0 +1,14 @@ +/turf/open/misc/hay + name = "hay" + desc = "For horses and cows like you." + icon = 'icons/turf/floors.dmi' + icon_state = "hay" + base_icon_state = "hay" + +/turf/open/misc/hay/lavaland + baseturfs = list(/turf/open/misc/basalt) + initial_gas_mix = LAVALAND_DEFAULT_ATMOS + +/turf/open/misc/hay/icemoon + baseturfs = list(/turf/open/misc/snow) + initial_gas_mix = ICEMOON_DEFAULT_ATMOS diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm index 734d431912f..0180c4f1797 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutluncher_foodtrough.dm @@ -1,31 +1,31 @@ -/obj/structure/ore_container/gutlunch_trough - name = "gutlunch trough" - desc = "The gutlunches will eat out of it!" - icon = 'icons/obj/structures.dmi' - icon_state = "gutlunch_trough" +/obj/structure/ore_container/food_trough density = TRUE anchored = TRUE ///list of materials in the trough var/list/list_of_materials = list() + ///x offsets for materials to be placed + var/list/x_offsets = list() + ///y offsets for materials to be placed + var/list/y_offsets = list() -/obj/structure/ore_container/gutlunch_trough/Entered(atom/movable/mover) +/obj/structure/ore_container/food_trough/Entered(atom/movable/mover) if(!istype(mover, /obj/item/stack/ore)) return ..() if(list_of_materials[mover.type]) return ..() - list_of_materials[mover.type] = list("pixel_x" = rand(-5, 8), "pixel_y" = rand(-2, -7)) + list_of_materials[mover.type] = list("pixel_x" = rand(x_offsets[1], x_offsets[2]), "pixel_y" = rand(y_offsets[1], y_offsets[2])) return ..() -/obj/structure/ore_container/gutlunch_trough/Exited(atom/movable/mover) +/obj/structure/ore_container/food_trough/Exited(atom/movable/mover) if(!istype(mover, /obj/item/stack/ore) || !isnull(locate(mover.type) in contents)) return ..() list_of_materials -= mover.type return ..() -/obj/structure/ore_container/gutlunch_trough/atom_deconstruct(disassembled = TRUE) +/obj/structure/ore_container/food_trough/atom_deconstruct(disassembled = TRUE) new /obj/item/stack/sheet/mineral/wood(drop_location(), 5) -/obj/structure/ore_container/gutlunch_trough/update_overlays() +/obj/structure/ore_container/food_trough/update_overlays() . = ..() for(var/ore_entry in list_of_materials) var/obj/item/ore_item = ore_entry @@ -35,3 +35,11 @@ ore_icon.pixel_x = pixel_positions["pixel_x"] ore_icon.pixel_y = pixel_positions["pixel_y"] . += ore_icon + +/obj/structure/ore_container/food_trough/gutlunch_trough + name = "gutlunch trough" + desc = "The gutlunches will eat out of it!" + icon = 'icons/obj/structures.dmi' + icon_state = "gutlunch_trough" + x_offsets = list(-5, 8) + y_offsets = list(-2, -7) diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm index 6d8f91ff8ce..f9e1d458ef2 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm @@ -55,7 +55,7 @@ /mob/living/basic/mining/gutlunch/proc/pre_attack(mob/living/puncher, atom/target) SIGNAL_HANDLER - if(!istype(target, /obj/structure/ore_container/gutlunch_trough)) + if(!istype(target, /obj/structure/ore_container/food_trough/gutlunch_trough)) return var/obj/ore_food = locate(/obj/item/stack/ore) in target diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm index 352f1b46b17..c7f7e86c866 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm @@ -75,7 +75,7 @@ target_key = BB_TROUGH_TARGET hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/food_trough finding_behavior = /datum/ai_behavior/find_hunt_target/food_trough - hunt_targets = list(/obj/structure/ore_container/gutlunch_trough) + hunt_targets = list(/obj/structure/ore_container/food_trough/gutlunch_trough) hunt_chance = 75 hunt_range = 9 diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm new file mode 100644 index 00000000000..78c4e9c61ea --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -0,0 +1,306 @@ +GLOBAL_LIST_INIT(raptor_growth_paths, list( + /mob/living/basic/mining/raptor/baby_raptor/red = list(RAPTOR_PURPLE, RAPTOR_WHITE), + /mob/living/basic/mining/raptor/baby_raptor/white = list(RAPTOR_GREEN, RAPTOR_PURPLE), + /mob/living/basic/mining/raptor/baby_raptor/purple = list(RAPTOR_GREEN, RAPTOR_WHITE), + /mob/living/basic/mining/raptor/baby_raptor/yellow = list(RAPTOR_GREEN, RAPTOR_RED), + /mob/living/basic/mining/raptor/baby_raptor/green = list(RAPTOR_RED, RAPTOR_YELLOW), + /mob/living/basic/mining/raptor/baby_raptor/blue = list(RAPTOR_RED, RAPTOR_PURPLE) +)) + +GLOBAL_LIST_INIT(raptor_inherit_traits, list( + BB_BASIC_DEPRESSED = "Depressed", + BB_RAPTOR_MOTHERLY = "Motherly", + BB_RAPTOR_PLAYFUL = "Playful", + BB_RAPTOR_COWARD = "Coward", + BB_RAPTOR_TROUBLE_MAKER = "Trouble Maker", +)) + +GLOBAL_LIST_EMPTY(raptor_population) + +#define HAPPINESS_BOOST_DAMPENER 0.3 + +/mob/living/basic/mining/raptor + name = "raptor" + desc = "A trusty powerful stead. Taming it might prove difficult..." + icon = 'icons/mob/simple/lavaland/raptor_big.dmi' + speed = 2 + mob_biotypes = MOB_ORGANIC|MOB_BEAST + maxHealth = 400 + health = 400 + melee_damage_lower = 10 + melee_damage_upper = 15 + sentience_type = SENTIENCE_BOSS + attack_verb_continuous = "pecks" + attack_verb_simple = "chomps" + attack_sound = 'sound/weapons/punch1.ogg' + faction = list(FACTION_RAPTOR, FACTION_NEUTRAL) + speak_emote = list("screeches") + ai_controller = /datum/ai_controller/basic_controller/raptor + ///can this mob breed + var/can_breed = TRUE + ///should we change offsets on direction change? + var/change_offsets = TRUE + ///can we ride this mob + var/ridable_component = /datum/component/riding/creature/raptor + //pet commands when we tame the raptor + var/static/list/pet_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/follow, + /datum/pet_command/point_targeting/fetch, + ) + ///things we inherited from our parent + var/datum/raptor_inheritance/inherited_stats + ///our color + var/raptor_color + ///the description that appears in the dex + var/dex_description + ///path of our child + var/child_path + + +/mob/living/basic/mining/raptor/Initialize(mapload) + . = ..() + if(SSmapping.is_planetary()) + change_offsets = FALSE + icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi' + + if(!mapload) + GLOB.raptor_population += REF(src) + AddComponent(/datum/component/obeys_commands, pet_commands) + + AddElement(\ + /datum/element/change_force_on_death,\ + move_resist = MOVE_RESIST_DEFAULT,\ + ) + + var/static/list/display_emote = list( + BB_EMOTE_SAY = list("Chirp chirp chirp!", "Kweh!", "Bwark!"), + BB_EMOTE_SEE = list("shakes its feathers!", "stretches!", "flaps it's wings!", "pecks at the ground!"), + BB_EMOTE_SOUND = list( + 'sound/creatures/raptor_1.ogg', + 'sound/creatures/raptor_2.ogg', + 'sound/creatures/raptor_3.ogg', + 'sound/creatures/raptor_4.ogg', + 'sound/creatures/raptor_5.ogg', + ), + BB_SPEAK_CHANCE = 2, + ) + + ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, display_emote) + inherited_stats = new + inherit_properties() + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack)) + var/static/list/my_food = list(/obj/item/stack/ore) + AddElement(/datum/element/basic_eating, food_types = my_food) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/ai_flee_while_injured, stop_fleeing_at = 0.5, start_fleeing_below = 0.2) + + if(ridable_component) + AddElement(/datum/element/ridable, ridable_component) + + if(can_breed) + AddComponent(\ + /datum/component/breed,\ + can_breed_with = typecacheof(list(/mob/living/basic/mining/raptor)),\ + baby_path = /obj/item/food/egg/raptor_egg,\ + post_birth = CALLBACK(src, PROC_REF(egg_inherit)),\ + breed_timer = 3 MINUTES,\ + ) + AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW) + RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change)) + adjust_offsets(dir) + add_happiness_component() + + +/mob/living/basic/mining/raptor/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE) + if(!iscarbon(target)) + return + return ..() + +/mob/living/basic/mining/raptor/proc/add_happiness_component() + var/static/list/percentage_callbacks = list(0, 15, 25, 35, 50, 75, 90, 100) + AddComponent(\ + /datum/component/happiness,\ + on_petted_change = 100,\ + on_groom_change = 100,\ + on_eat_change = 400,\ + callback_percentages = percentage_callbacks,\ + happiness_callback = CALLBACK(src, PROC_REF(happiness_change)),\ + ) + +/mob/living/basic/mining/raptor/proc/on_dir_change(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + adjust_offsets(new_dir) + +/mob/living/basic/mining/raptor/proc/adjust_offsets(direction) + if(!change_offsets) + return + pixel_x = (direction & EAST) ? -20 : 0 + pixel_y = (direction & NORTH) ? -5 : 0 + + +/mob/living/basic/mining/raptor/proc/pre_attack(mob/living/puncher, atom/target) + SIGNAL_HANDLER + + if(!istype(target, /obj/structure/ore_container/food_trough/raptor_trough)) + return + + var/obj/ore_food = locate(/obj/item/stack/ore) in target + + if(isnull(ore_food)) + balloon_alert(src, "no food!") + else + INVOKE_ASYNC(src, PROC_REF(melee_attack), ore_food) + return COMPONENT_HOSTILE_NO_ATTACK + +/mob/living/basic/mining/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) + if(!combat_mode && istype(target, /mob/living/basic/mining/raptor/baby_raptor)) + target.attack_hand(src, list(LEFT_CLICK = TRUE)) + return + return ..() + +/mob/living/basic/mining/raptor/death(gibbed) + . = ..() + GLOB.raptor_population -= REF(src) + +/mob/living/basic/mining/raptor/proc/happiness_change(percent_value) + var/attack_boost = round(initial(melee_damage_lower) * percent_value * HAPPINESS_BOOST_DAMPENER, 1) + melee_damage_lower = initial(melee_damage_lower) + attack_boost + melee_damage_upper = melee_damage_lower + 5 + + +///pass down our inheritance to the egg +/mob/living/basic/mining/raptor/proc/egg_inherit(obj/item/food/egg/raptor_egg/baby_egg, mob/living/basic/mining/raptor/partner) + var/datum/raptor_inheritance/inherit = new + inherit.set_parents(inherited_stats, partner.inherited_stats) + baby_egg.inherited_stats = inherit + baby_egg.determine_growth_path(src, partner) + +/mob/living/basic/mining/raptor/proc/inherit_properties() + if(isnull(inherited_stats)) + return + for(var/trait in GLOB.raptor_inherit_traits) // done this way to allow overriding of traits when assigned new inherit datum + var/should_inherit = (trait in inherited_stats.inherit_traits) + ai_controller?.set_blackboard_key(trait, should_inherit) + melee_damage_lower += inherited_stats.attack_modifier + melee_damage_upper += melee_damage_lower + 5 + maxHealth += inherited_stats.health_modifier + heal_overall_damage(maxHealth) + +/mob/living/basic/mining/raptor/Destroy() + QDEL_NULL(inherited_stats) + return ..() + +/mob/living/basic/mining/raptor/red + name = "red raptor" + icon_state = "raptor_red" + icon_living = "raptor_red" + icon_dead = "raptor_red_dead" + melee_damage_lower = 15 + melee_damage_upper = 20 + raptor_color = RAPTOR_RED + dex_description = "A resilient breed of raptors, battle-tested and bred for the purpose of humbling its foes in combat, \ + This breed demonstrates higher combat capabilities than its peers and oozes rutheless aggression." + child_path = /mob/living/basic/mining/raptor/baby_raptor/red + +/mob/living/basic/mining/raptor/purple + name = "purple raptor" + icon_state = "raptor_purple" + icon_living = "raptor_purple" + icon_dead = "raptor_purple_dead" + raptor_color = RAPTOR_PURPLE + dex_description = "A dependable mount, bred for the purpose of long distance pilgrimages. This breed is also able to store its rider's possessions." + child_path = /mob/living/basic/mining/raptor/baby_raptor/purple + +/mob/living/basic/mining/raptor/purple/Initialize(mapload) + . = ..() + create_storage( + max_specific_storage = WEIGHT_CLASS_NORMAL, + max_total_storage = 10, + storage_type = /datum/storage/raptor_storage, + ) + +/mob/living/basic/mining/raptor/green + name = "green raptor" + icon_state = "raptor_green" + icon_living = "raptor_green" + icon_dead = "raptor_green_dead" + maxHealth = 460 + health = 460 + raptor_color = RAPTOR_GREEN + dex_description = "A tough breed of raptor, made to withstand the harshest of punishment and to laugh in the face of pain, \ + This breed is able to withstand more beating than its peers." + child_path = /mob/living/basic/mining/raptor/baby_raptor/green + +/mob/living/basic/mining/raptor/green/Initialize(mapload) + . = ..() + AddElement(/datum/element/proficient_miner) + +/mob/living/basic/mining/raptor/white + name = "white raptor" + icon_state = "raptor_white" + icon_living = "raptor_white" + icon_dead = "raptor_white_dead" + raptor_color = RAPTOR_WHITE + dex_description = "A loving sort, it cares for it peers and rushes to their aid with reckless abandon. It is able to heal any raptors' ailments." + child_path = /mob/living/basic/mining/raptor/baby_raptor/white + +/mob/living/basic/mining/raptor/white/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/healing_touch,\ + heal_brute = melee_damage_upper,\ + heal_burn = melee_damage_upper,\ + heal_time = 0,\ + valid_targets_typecache = typecacheof(list(/mob/living/basic/mining/raptor)),\ + ) + +/mob/living/basic/mining/raptor/black + name = "black raptor" + icon_state = "raptor_black" + icon_living = "raptor_black" + icon_dead = "raptor_black_dead" + maxHealth = 460 + health = 460 + speed = 1 + ridable_component = /datum/component/riding/creature/raptor/fast + melee_damage_lower = 20 + melee_damage_upper = 25 + raptor_color = RAPTOR_BLACK + dex_description = "An ultra rare breed. Due to its sparse nature, not much is known about this sort. However it is said to possess many of its peers' abilities." + child_path = /mob/living/basic/mining/raptor/baby_raptor/black + +/mob/living/basic/mining/raptor/yellow + name = "yellow raptor" + icon_state = "raptor_yellow" + icon_living = "raptor_yellow" + icon_dead = "raptor_yellow_dead" + ridable_component = /datum/component/riding/creature/raptor/fast + speed = 1 + raptor_color = RAPTOR_YELLOW + dex_description = "This breed possesses greasy fast speed, DEMON speed, making light work of long pilgrimages. It's said that a thunderclap could be heard when this breed reaches its maximum speed." + child_path = /mob/living/basic/mining/raptor/baby_raptor/yellow + +/mob/living/basic/mining/raptor/blue + name = "blue raptor" + icon_state = "raptor_blue" + icon_living = "raptor_blue" + icon_dead = "raptor_blue_dead" + raptor_color = RAPTOR_BLUE + dex_description = "Known to produce nutritous and equally delicious milk, which is also said to possess healing properties." + child_path = /mob/living/basic/mining/raptor/baby_raptor/blue + +/mob/living/basic/mining/raptor/blue/Initialize(mapload) + . = ..() + AddComponent(\ + /datum/component/udder,\ + udder_type = /obj/item/udder/raptor,\ + ) + +/datum/storage/raptor_storage + animated = FALSE + insert_on_attack = FALSE + +#undef HAPPINESS_BOOST_DAMPENER diff --git a/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm new file mode 100644 index 00000000000..a0a4f6aebc1 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm @@ -0,0 +1,102 @@ +/mob/living/basic/mining/raptor/baby_raptor + name = "baby raptor" + desc = "Will this grow into something useful?" + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + speed = 5 + maxHealth = 25 + health = 25 + melee_damage_lower = 3 + melee_damage_upper = 5 + density = FALSE + can_breed = FALSE + move_resist = MOVE_RESIST_DEFAULT + ai_controller = /datum/ai_controller/basic_controller/baby_raptor + ridable_component = null + change_offsets = FALSE + dex_description = "A cute baby raptor, Having it near a parent or a birds-nest could encourage it to grow faster, \ + grooming it and feeding it could also ensure that it grows up quicker!" + ///what do we grow into + var/growth_path + ///probability we are to be rolled + var/roll_rate = 100 + +/mob/living/basic/mining/raptor/baby_raptor/Initialize(mapload) + . = ..() + if(isnull(growth_path)) + return + AddComponent(\ + /datum/component/growth_and_differentiation,\ + growth_time = null,\ + growth_path = growth_path,\ + growth_probability = 80,\ + lower_growth_value = 0.5,\ + upper_growth_value = 0.8,\ + signals_to_kill_on = list(COMSIG_MOB_CLIENT_LOGIN),\ + optional_checks = CALLBACK(src, PROC_REF(check_grow)),\ + optional_grow_behavior = CALLBACK(src, PROC_REF(ready_to_grow)),\ + ) + +/mob/living/basic/mining/raptor/baby_raptor/add_happiness_component() + AddComponent(/datum/component/happiness, on_petted_change = 100) + +/mob/living/basic/mining/raptor/baby_raptor/proc/check_grow() + return (stat != DEAD) + +/mob/living/basic/mining/raptor/baby_raptor/proc/ready_to_grow() + var/mob/living/basic/mining/raptor/grown_mob = new growth_path(get_turf(src)) + QDEL_NULL(grown_mob.inherited_stats) + grown_mob.inherited_stats = inherited_stats + inherited_stats = null + grown_mob.inherit_properties() + ADD_TRAIT(grown_mob, TRAIT_MOB_HATCHED, INNATE_TRAIT) //pass on the hatched trait + qdel(src) + +/mob/living/basic/mining/raptor/baby_raptor/black + name = "baby black raptor" + icon_state = "baby_black" + icon_living = "baby_black" + icon_dead = "baby_black_dead" + growth_path = /mob/living/basic/mining/raptor/black + roll_rate = 10 + +/mob/living/basic/mining/raptor/baby_raptor/red + name = "baby red raptor" + icon_state = "baby_red" + icon_living = "baby_red" + icon_dead = "baby_red_dead" + growth_path = /mob/living/basic/mining/raptor/red + +/mob/living/basic/mining/raptor/baby_raptor/purple + name = "baby purple raptor" + icon_state = "baby_purple" + icon_living = "baby_purple" + icon_dead = "baby_purple_dead" + growth_path = /mob/living/basic/mining/raptor/purple + +/mob/living/basic/mining/raptor/baby_raptor/white + name = "baby white raptor" + icon_state = "baby_white" + icon_living = "baby_white" + icon_dead = "baby_white_dead" + growth_path = /mob/living/basic/mining/raptor/white + +/mob/living/basic/mining/raptor/baby_raptor/yellow + name = "baby yellow raptor" + icon_state = "baby_yellow" + icon_living = "baby_yellow" + icon_dead = "baby_yellow_dead" + growth_path = /mob/living/basic/mining/raptor/yellow + +/mob/living/basic/mining/raptor/baby_raptor/green + name = "baby green raptor" + icon_state = "baby_green" + icon_living = "baby_green" + icon_dead = "baby_green_dead" + growth_path = /mob/living/basic/mining/raptor/green + +/mob/living/basic/mining/raptor/baby_raptor/blue + name = "baby blue raptor" + icon_state = "baby_blue" + icon_living = "baby_blue" + icon_dead = "baby_blue_dead" + growth_path = /mob/living/basic/mining/raptor/blue diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm new file mode 100644 index 00000000000..33a65586907 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm @@ -0,0 +1,54 @@ +/datum/ai_behavior/hunt_target/unarmed_attack_target/heal_raptor + always_reset_target = TRUE + +/datum/ai_behavior/find_hunt_target/injured_raptor + +/datum/ai_behavior/find_hunt_target/injured_raptor/valid_dinner(mob/living/source, mob/living/target, radius) + return (source != target && target.health < target.maxHealth) + +/datum/ai_behavior/find_hunt_target/raptor_victim + +/datum/ai_behavior/find_hunt_target/raptor_victim/valid_dinner(mob/living/source, mob/living/target, radius) + if(target.ai_controller?.blackboard[BB_RAPTOR_TROUBLE_MAKER]) + return FALSE + return target.stat != DEAD && can_see(source, target, radius) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/bully_raptors + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/unarmed_attack_target/bully_raptors/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) + if(succeeded) + controller.set_blackboard_key(BB_RAPTOR_TROUBLE_COOLDOWN, world.time + 2 MINUTES) + return ..() + +/datum/ai_behavior/find_hunt_target/raptor_baby/valid_dinner(mob/living/source, mob/living/target, radius) + return can_see(source, target, radius) && target.stat != DEAD + +/datum/ai_behavior/hunt_target/care_for_young + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/care_for_young/target_caught(mob/living/hunter, atom/hunted) + hunter.manual_emote("grooms [hunted]!") + hunter.set_combat_mode(FALSE) + hunter.ClickOn(hunted) + +/datum/ai_behavior/hunt_target/care_for_young/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) + var/mob/living/living_pawn = controller.pawn + living_pawn.set_combat_mode(initial(living_pawn.combat_mode)) + return ..() + +/datum/ai_behavior/find_hunt_target/raptor_trough + +/datum/ai_behavior/find_hunt_target/raptor_trough/valid_dinner(mob/living/source, atom/movable/trough, radius) + return !!(locate(/obj/item/stack/ore) in trough.contents) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/raptor_trough + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/unarmed_attack_target/raptor_trough/target_caught(mob/living/hunter, atom/hunted) + hunter.set_combat_mode(FALSE) + +/datum/ai_behavior/hunt_target/unarmed_attack_target/raptor_trough/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key) + var/mob/living/living_pawn = controller.pawn + living_pawn.set_combat_mode(initial(living_pawn.combat_mode)) + return ..() diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm new file mode 100644 index 00000000000..40c2d836554 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm @@ -0,0 +1,64 @@ +#define NEXT_EAT_COOLDOWN 45 SECONDS + +/datum/ai_controller/basic_controller/raptor + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, + BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/mining/raptor), + BB_BABIES_CHILD_TYPES = list(/mob/living/basic/mining/raptor/baby_raptor), + BB_MAX_CHILDREN = 5, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor, + /datum/ai_planning_subtree/flee_target/from_flee_key, + /datum/ai_planning_subtree/find_and_hunt_target/heal_raptors, + /datum/ai_planning_subtree/random_speech/blackboard, + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_trough, + /datum/ai_planning_subtree/find_and_hunt_target/care_for_young, + /datum/ai_planning_subtree/make_babies, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble, + /datum/ai_planning_subtree/express_happiness, + ) + +/datum/ai_controller/basic_controller/raptor/TryPossessPawn(atom/new_pawn) + . = ..() + if(. & AI_CONTROLLER_INCOMPATIBLE) + return + RegisterSignal(new_pawn, COMSIG_MOB_ATE, PROC_REF(post_eat)) + +/datum/ai_controller/basic_controller/raptor/proc/post_eat() + clear_blackboard_key(BB_RAPTOR_TROUGH_TARGET) + set_blackboard_key(BB_RAPTOR_EAT_COOLDOWN, world.time + NEXT_EAT_COOLDOWN) + +/datum/targeting_strategy/basic/raptor + +//dont attack anyone with the neutral faction. +/datum/targeting_strategy/basic/raptor/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) + return (the_target.faction.Find(FACTION_NEUTRAL) || the_target.faction.Find(FACTION_RAPTOR)) + +/datum/ai_controller/basic_controller/baby_raptor + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, + BB_FIND_MOM_TYPES = list(/mob/living/basic/mining/raptor), + BB_IGNORE_MOM_TYPES = list(/mob/living/basic/mining/raptor/baby_raptor), + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/random_speech/blackboard, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_trough, + /datum/ai_planning_subtree/express_happiness, + /datum/ai_planning_subtree/look_for_adult, + ) + +#undef NEXT_EAT_COOLDOWN diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm new file mode 100644 index 00000000000..2d23268d35c --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm @@ -0,0 +1,62 @@ +/datum/ai_planning_subtree/find_and_hunt_target/heal_raptors + target_key = BB_INJURED_RAPTOR + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/heal_raptor + finding_behavior = /datum/ai_behavior/find_hunt_target/injured_raptor + hunt_targets = list(/mob/living/basic/mining/raptor) + hunt_chance = 70 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/heal_raptors/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_BASIC_MOB_HEALER]) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble + target_key = BB_RAPTOR_VICTIM + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/bully_raptors + finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_victim + hunt_targets = list(/mob/living/basic/mining/raptor) + hunt_chance = 30 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(controller.blackboard[BB_BASIC_MOB_HEALER] || !controller.blackboard[BB_RAPTOR_TROUBLE_MAKER]) + return + if(world.time < controller.blackboard[BB_RAPTOR_TROUBLE_COOLDOWN]) + return + return ..() + +/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor + target_key = BB_BASIC_MOB_FLEE_TARGET + +/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_RAPTOR_COWARD]) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/care_for_young + target_key = BB_RAPTOR_BABY + hunting_behavior = /datum/ai_behavior/hunt_target/care_for_young + finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_baby + hunt_targets = list(/mob/living/basic/mining/raptor/baby_raptor) + hunt_chance = 75 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/care_for_young/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_RAPTOR_MOTHERLY]) + return + return ..() + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough + target_key = BB_RAPTOR_TROUGH_TARGET + hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target + finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_trough + hunt_targets = list(/obj/structure/ore_container/food_trough/raptor_trough) + hunt_chance = 80 + hunt_range = 9 + +/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(world.time < controller.blackboard[BB_RAPTOR_EAT_COOLDOWN]) + return + return ..() + diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm new file mode 100644 index 00000000000..7080c91a500 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm @@ -0,0 +1,62 @@ +/obj/item/raptor_dex + name = "raptor Dex" + desc = "A device used to analyze lavaland raptors!" + icon = 'icons/obj/devices/scanner.dmi' + icon_state = "raptor_dex" + item_flags = NOBLUDGEON + ///current raptor we are analyzing + var/datum/weakref/raptor + +/obj/item/raptor_dex/ui_interact(mob/user, datum/tgui/ui) + if(isnull(raptor?.resolve())) + balloon_alert(user, "no specimen data!") + return TRUE + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RaptorDex") + ui.open() + +/obj/item/raptor_dex/ui_static_data(mob/user) + var/list/data = list() + var/mob/living/basic/mining/raptor/my_raptor = raptor.resolve() + + data["raptor_image"] = icon2base64(getFlatIcon(image(icon = my_raptor.icon, icon_state = my_raptor.icon_state))) + data["raptor_attack"] = my_raptor.melee_damage_lower + data["raptor_health"] = my_raptor.maxHealth + data["raptor_speed"] = my_raptor.speed + data["raptor_color"] = my_raptor.name + data["raptor_gender"] = my_raptor.gender + data["raptor_description"] = my_raptor.dex_description + + var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS] + var/obj/effect/overlay/happiness_overlay/display = new + display.set_hearts(happiness_percentage) + display.pixel_y = world.icon_size * 0.5 + data["raptor_happiness"] = icon2base64(getFlatIcon(display)) + qdel(display) + + var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats + if(isnull(inherit)) + return data + + data["inherited_attack"] = inherit.attack_modifier + data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK + data["inherited_health"] = inherit.health_modifier + data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH + + data["inherited_traits"] = list() + for(var/index in inherit.inherit_traits) + data["inherited_traits"] += GLOB.raptor_inherit_traits[index] + return data + + +/obj/item/raptor_dex/interact_with_atom(atom/attacked_atom, mob/living/user) + if(!istype(attacked_atom, /mob/living/basic/mining/raptor)) + return NONE + + raptor = WEAKREF(attacked_atom) + playsound(src, 'sound/items/orbie_send_out.ogg', 20) + balloon_alert(user, "scanned") + ui_interact(user) + return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm new file mode 100644 index 00000000000..9fb72239ca7 --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm @@ -0,0 +1,58 @@ +/obj/item/food/egg/raptor_egg + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + icon_state = "raptor_egg" + ///inheritance datum to pass on to the child + var/datum/raptor_inheritance/inherited_stats + +/obj/item/food/egg/raptor_egg/Initialize(mapload) + . = ..() + if(SSmapping.is_planetary()) + icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi' + +/obj/item/food/egg/raptor_egg/proc/determine_growth_path(mob/living/basic/mining/raptor/dad, mob/living/basic/mining/raptor/mom) + if(dad.type == mom.type) + add_growth_component(dad.child_path) + return + var/dad_color = dad.raptor_color + var/mom_color = mom.raptor_color + var/list/my_colors = list(dad_color, mom_color) + sortTim(my_colors, GLOBAL_PROC_REF(cmp_text_asc)) + for(var/path in GLOB.raptor_growth_paths) //guaranteed spawns + var/list/required_colors = GLOB.raptor_growth_paths[path] + if(!compare_list(my_colors, required_colors)) + continue + add_growth_component(path) + return + var/list/valid_subtypes = list() + var/static/list/all_subtypes = subtypesof(/mob/living/basic/mining/raptor/baby_raptor) + for(var/path in all_subtypes) + var/mob/living/basic/mining/raptor/baby_raptor/raptor_path = path + if(!prob(initial(raptor_path.roll_rate))) + continue + valid_subtypes += raptor_path + add_growth_component(pick(valid_subtypes)) + +/obj/item/food/egg/raptor_egg/proc/add_growth_component(growth_path) + if(length(GLOB.raptor_population) >= MAX_RAPTOR_POP) + return + AddComponent(\ + /datum/component/fertile_egg,\ + embryo_type = growth_path,\ + minimum_growth_rate = 0.5,\ + maximum_growth_rate = 1,\ + total_growth_required = 100,\ + current_growth = 0,\ + location_allowlist = typecacheof(list(/turf)),\ + post_hatch = CALLBACK(src, PROC_REF(post_hatch)),\ + ) + +/obj/item/food/egg/raptor_egg/proc/post_hatch(mob/living/basic/mining/raptor/baby) + if(!istype(baby)) + return + QDEL_NULL(baby.inherited_stats) + baby.inherited_stats = inherited_stats + inherited_stats = null + +/obj/item/food/egg/raptor_egg/Destroy() + QDEL_NULL(inherited_stats) + return ..() diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_food_trough.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_food_trough.dm new file mode 100644 index 00000000000..03289f2d0fe --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_food_trough.dm @@ -0,0 +1,7 @@ +/obj/structure/ore_container/food_trough/raptor_trough + name = "raptor trough" + desc = "The raptors will eat out of it!" + icon = 'icons/obj/structures.dmi' + icon_state = "raptor_trough" + x_offsets = list(-5, 5) + y_offsets = list(-4, 5) diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm new file mode 100644 index 00000000000..4f72e37a4cf --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm @@ -0,0 +1,31 @@ +#define RANDOM_INHERIT_AMOUNT 2 +/datum/raptor_inheritance + ///list of traits we inherit + var/list/inherit_traits = list() + ///attack modifier + var/attack_modifier + ///health_modifier + var/health_modifier + +/datum/raptor_inheritance/New(datum/raptor_inheritance/father, datum/raptor_inheritance/mother) + . = ..() + randomize_stats() + +/datum/raptor_inheritance/proc/randomize_stats() + attack_modifier = rand(0, RAPTOR_INHERIT_MAX_ATTACK) + health_modifier = rand(0, RAPTOR_INHERIT_MAX_HEALTH) + var/list/traits_to_pick = GLOB.raptor_inherit_traits.Copy() + for(var/i in 1 to RANDOM_INHERIT_AMOUNT) + inherit_traits += pick_n_take(traits_to_pick) + +/datum/raptor_inheritance/proc/set_parents(datum/raptor_inheritance/father, datum/raptor_inheritance/mother) + if(isnull(father) || isnull(mother)) + return + if(length(father.inherit_traits)) + inherit_traits += pick(father.inherit_traits) + if(length(mother.inherit_traits)) + inherit_traits += pick(mother.inherit_traits) + attack_modifier = rand(min(father.attack_modifier, mother.attack_modifier), max(father.attack_modifier, mother.attack_modifier)) + health_modifier = rand(min(father.health_modifier, mother.health_modifier), max(father.health_modifier, mother.health_modifier)) + +#undef RANDOM_INHERIT_AMOUNT diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index dab4f272d96..5c64474dc0a 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/simple/lavaland/raptor_baby.dmi b/icons/mob/simple/lavaland/raptor_baby.dmi new file mode 100644 index 00000000000..f892a3cb84f Binary files /dev/null and b/icons/mob/simple/lavaland/raptor_baby.dmi differ diff --git a/icons/mob/simple/lavaland/raptor_big.dmi b/icons/mob/simple/lavaland/raptor_big.dmi new file mode 100644 index 00000000000..2a89d84c85e Binary files /dev/null and b/icons/mob/simple/lavaland/raptor_big.dmi differ diff --git a/icons/mob/simple/lavaland/raptor_icebox.dmi b/icons/mob/simple/lavaland/raptor_icebox.dmi new file mode 100644 index 00000000000..86b82e7142d Binary files /dev/null and b/icons/mob/simple/lavaland/raptor_icebox.dmi differ diff --git a/icons/obj/devices/scanner.dmi b/icons/obj/devices/scanner.dmi index cea20f32f7f..f02fa0e4ecd 100644 Binary files a/icons/obj/devices/scanner.dmi and b/icons/obj/devices/scanner.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index cf6cdbdf0d8..96e803a52ee 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index de3287c1636..29eb7d3eaec 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/sound/creatures/raptor_1.ogg b/sound/creatures/raptor_1.ogg new file mode 100644 index 00000000000..94d53073aa6 Binary files /dev/null and b/sound/creatures/raptor_1.ogg differ diff --git a/sound/creatures/raptor_2.ogg b/sound/creatures/raptor_2.ogg new file mode 100644 index 00000000000..01c23ff03ce Binary files /dev/null and b/sound/creatures/raptor_2.ogg differ diff --git a/sound/creatures/raptor_3.ogg b/sound/creatures/raptor_3.ogg new file mode 100644 index 00000000000..dff3946ec04 Binary files /dev/null and b/sound/creatures/raptor_3.ogg differ diff --git a/sound/creatures/raptor_4.ogg b/sound/creatures/raptor_4.ogg new file mode 100644 index 00000000000..53c28c72ffd Binary files /dev/null and b/sound/creatures/raptor_4.ogg differ diff --git a/sound/creatures/raptor_5.ogg b/sound/creatures/raptor_5.ogg new file mode 100644 index 00000000000..dd424a1566f Binary files /dev/null and b/sound/creatures/raptor_5.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 2914a33ea38..2e7b8532db0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -899,6 +899,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\call_reinforcements.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\capricious_retaliate.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\climb_tree.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\express_happiness.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_paper_and_write.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" @@ -1095,6 +1096,7 @@ #include "code\datums\components\ground_sinking.dm" #include "code\datums\components\growth_and_differentiation.dm" #include "code\datums\components\gunpoint.dm" +#include "code\datums\components\happiness.dm" #include "code\datums\components\hazard_area.dm" #include "code\datums\components\healing_touch.dm" #include "code\datums\components\health_scaling_effects.dm" @@ -1473,6 +1475,7 @@ #include "code\datums\elements\point_of_interest.dm" #include "code\datums\elements\poster_tearer.dm" #include "code\datums\elements\prevent_attacking_of_types.dm" +#include "code\datums\elements\proficient_miner.dm" #include "code\datums\elements\projectile_drop.dm" #include "code\datums\elements\projectile_shield.dm" #include "code\datums\elements\radiation_protected_clothing.dm" @@ -2751,6 +2754,7 @@ #include "code\game\turfs\open\dirtystation.dm" #include "code\game\turfs\open\floor.dm" #include "code\game\turfs\open\grass.dm" +#include "code\game\turfs\open\hay.dm" #include "code\game\turfs\open\ice.dm" #include "code\game\turfs\open\lava.dm" #include "code\game\turfs\open\misc.dm" @@ -4760,6 +4764,15 @@ #include "code\modules\mob\living\basic\lavaland\mook\mook_ai.dm" #include "code\modules\mob\living\basic\lavaland\mook\mook_village.dm" #include "code\modules\mob\living\basic\lavaland\node_drone\node_drone.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\_raptor.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\baby_raptor.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_behavior.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_controller.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_subtrees.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_dex.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_egg.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_food_trough.dm" +#include "code\modules\mob\living\basic\lavaland\raptor\raptor_inheritance.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher_ai.dm" #include "code\modules\mob\living\basic\lavaland\watcher\watcher_gaze.dm" diff --git a/tgui/packages/tgui/interfaces/RaptorDex.tsx b/tgui/packages/tgui/interfaces/RaptorDex.tsx new file mode 100644 index 00000000000..946f8fb2b95 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RaptorDex.tsx @@ -0,0 +1,130 @@ +import { useBackend } from '../backend'; +import { Image, LabeledList, ProgressBar, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + raptor_attack: number; + raptor_health: number; + raptor_speed: number; + raptor_color: String; + raptor_image: String; + raptor_gender: String; + raptor_happiness: String; + raptor_description: String; + inherited_attack: number; + inherited_attack_max: number; + inherited_health: number; + inherited_health_max: number; + inherited_traits: String[]; +}; + +export const RaptorDex = (props) => { + const { act, data } = useBackend(); + const { + raptor_attack, + raptor_health, + raptor_speed, + raptor_image, + raptor_gender, + inherited_attack, + inherited_attack_max, + inherited_health, + inherited_health_max, + raptor_happiness, + inherited_traits, + raptor_description, + raptor_color, + } = data; + return ( + + + + +
+ +
+
+ +
+ + + {raptor_health} + + + {raptor_attack} + + + {10 - raptor_speed} + + + {raptor_gender} + + +
+
+ + + + + + + + +
+
+ +
+ +
+
+ + {inherited_traits.map((trait, index) => ( + {trait} + ))} + +
+
+
+
+ {raptor_description} +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/RideMinigame.tsx b/tgui/packages/tgui/interfaces/RideMinigame.tsx new file mode 100644 index 00000000000..6ed708840b9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/RideMinigame.tsx @@ -0,0 +1,131 @@ +import { randomPick } from 'common/random'; +import { useEffect, useState } from 'react'; + +import { useBackend } from '../backend'; +import { Button, Image, LabeledList, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Data = { + current_attempts: number; + current_failures: number; + all_icons: Icon_Data[]; + maximum_attempts: number; + maximum_failures: number; +}; + +type Icon_Data = { + direction: String; + icon: String; +}; + +export const RideMinigame = (props) => { + const { act, data } = useBackend(); + const { all_icons, maximum_attempts, maximum_failures } = data; + const [CurrIcon, setCurrIcon] = useState(randomPick(all_icons)); + const [CurrDisabled, setCurrDisabled] = useState(false); + const [ChosenAnswer, setChosenAnswer] = useState(''); + const [CurrentFailures, setCurrentFailures] = useState(0); + const [CurrentAttempts, setCurrentAttempts] = useState(0); + + const UpdateAnswer = (Answer: string) => { + setChosenAnswer(Answer); + setCurrDisabled(true); + }; + useEffect(() => { + const intervalId = setInterval(() => { + if (CurrentFailures >= maximum_failures) { + act('lose_game'); + return; + } + if (CurrentAttempts >= maximum_attempts) { + act('win_game'); + return; + } + setCurrentAttempts(CurrentAttempts + 1); + if (CurrIcon.direction !== ChosenAnswer) { + setCurrentFailures(CurrentFailures + 1); + } + const ListToPickFrom = all_icons.filter((icon) => icon !== CurrIcon); + setCurrIcon(randomPick(ListToPickFrom)); + setChosenAnswer(''); + setCurrDisabled(false); + }, 1000); + return () => clearInterval(intervalId); + }, [CurrIcon, ChosenAnswer, CurrDisabled]); + return ( + + + + +
+ +
+
+ +
+ + + {maximum_attempts - CurrentAttempts} + + + {maximum_failures - CurrentFailures} + + +
+
+ + +
+
+
+
+
+ ); +}; diff --git a/tools/UpdatePaths/Scripts/82537_food_trough.txt b/tools/UpdatePaths/Scripts/82537_food_trough.txt new file mode 100644 index 00000000000..e0a35d29e66 --- /dev/null +++ b/tools/UpdatePaths/Scripts/82537_food_trough.txt @@ -0,0 +1 @@ +/obj/structure/ore_container/gutlunch_trough : /obj/structure/ore_container/food_trough/gutlunch_trough {@OLD}