From 1c6c506936cc28e15aeeea96eb06a9529ad988cd Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:13:29 +0300 Subject: [PATCH] Raptor Rework - Ranching and Companionship (#93564) --- _maps/map_files/Mining/Lavaland.dmm | 1782 ++++++++--------- code/__DEFINES/ai/ai_blackboard.dm | 1 + code/__DEFINES/basic_mobs.dm | 79 +- code/__DEFINES/dcs/signals/signals_food.dm | 3 + .../signals/signals_mob/signals_mob_basic.dm | 5 + .../signals/signals_mob/signals_mob_carbon.dm | 3 + .../signals/signals_mob/signals_mob_living.dm | 3 + code/__DEFINES/dcs/signals/signals_object.dm | 6 + code/__HELPERS/atoms.dm | 6 +- code/__HELPERS/mobs.dm | 10 +- code/datums/ai/babies/babies_subtrees.dm | 8 +- .../basic_ai_behaviors/find_parent.dm | 23 +- .../basic_mobs/basic_subtrees/find_parent.dm | 8 +- .../basic_subtrees/simple_find_target.dm | 9 +- .../basic_targeting_strategy.dm | 3 + .../dont_target_friends.dm | 2 +- code/datums/ai/dog/dog_controller.dm | 2 +- code/datums/components/breeding.dm | 13 +- code/datums/components/happiness.dm | 51 +- code/datums/components/healing_touch.dm | 20 +- code/datums/components/proficient_miner.dm | 47 +- code/datums/components/riding/riding_mob.dm | 60 +- .../components/riding/riding_vehicle.dm | 5 +- code/datums/elements/basic_eating.dm | 58 +- code/datums/elements/raptor_food.dm | 87 + code/datums/storage/storage.dm | 14 +- .../effects/spawners/random/lavaland_mobs.dm | 40 +- code/game/objects/items/food/meatslab.dm | 12 + code/game/objects/items/stacks/bscrystal.dm | 1 + code/modules/fishing/fish/types/mining.dm | 1 + code/modules/mining/lavaland/ash_flora.dm | 15 +- code/modules/mining/ores_coins.dm | 4 + code/modules/mob/living/basic/drone/_drone.dm | 1 + .../mob/living/basic/farm_animals/bee/_bee.dm | 1 + .../living/basic/lavaland/raptor/_raptor.dm | 723 ++++--- .../basic/lavaland/raptor/baby_raptor.dm | 102 - .../lavaland/raptor/raptor_ai_behavior.dm | 17 +- .../lavaland/raptor/raptor_ai_controller.dm | 42 +- .../lavaland/raptor/raptor_ai_subtrees.dm | 28 +- .../basic/lavaland/raptor/raptor_color.dm | 439 ++++ .../basic/lavaland/raptor/raptor_dex.dm | 86 +- .../basic/lavaland/raptor/raptor_egg.dm | 90 +- .../lavaland/raptor/raptor_inheritance.dm | 118 +- code/modules/mob/living/basic/snails/snail.dm | 1 + .../mob/living/carbon/human/human_helpers.dm | 1 + code/modules/mob/living/inhand_holder.dm | 14 +- code/modules/mob/living/living.dm | 3 +- code/modules/mob/living/living_defines.dm | 2 + .../computers/item/role_tablet_presets.dm | 1 + .../file_system/programs/raptordex.dm | 61 + code/modules/movespeed/modifiers/items.dm | 6 + code/modules/movespeed/modifiers/mobs.dm | 4 +- icons/mob/actions/actions_animal.dmi | Bin 20357 -> 16962 bytes icons/mob/clothing/back/pets_back.dmi | Bin 0 -> 8794 bytes icons/mob/simple/lavaland/raptor_baby.dmi | Bin 1445 -> 6837 bytes icons/mob/simple/lavaland/raptor_big.dmi | Bin 8689 -> 33714 bytes tgstation.dme | 4 +- tgui/packages/tgui/interfaces/RaptorDex.tsx | 104 +- 58 files changed, 2608 insertions(+), 1621 deletions(-) create mode 100644 code/datums/elements/raptor_food.dm delete mode 100644 code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm create mode 100644 code/modules/mob/living/basic/lavaland/raptor/raptor_color.dm create mode 100644 code/modules/modular_computers/file_system/programs/raptordex.dm create mode 100644 icons/mob/clothing/back/pets_back.dmi diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index a5993035d49..b9022006c5e 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -82,12 +82,6 @@ /obj/item/clothing/glasses/meson, /turf/open/floor/iron/dark, /area/mine/storage/public) -"as" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "av" = ( /obj/machinery/computer/arcade/orion_trail{ dir = 4 @@ -99,16 +93,14 @@ /obj/structure/cable, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"aF" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) -"aH" = ( -/obj/structure/railing{ - dir = 10 +"aI" = ( +/obj/effect/turf_decal/sand/plating/volcanic, +/obj/structure/railing/corner/end/flip{ + dir = 4 }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) +/obj/structure/marker_beacon/purple, +/turf/open/floor/plating/lavaland_atmos, +/area/lavaland/surface/outdoors) "aM" = ( /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "lavaland_living_east_maint" @@ -153,20 +145,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plating, /area/mine/maintenance/service) -"aX" = ( -/obj/effect/turf_decal/sand/plating/volcanic, -/obj/structure/railing{ - dir = 9 - }, -/turf/open/floor/plating/lavaland_atmos, -/area/lavaland/surface/outdoors) -"ba" = ( -/obj/structure/chair/sofa/middle{ - dir = 1; - color = "#AA4A44" - }, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "bb" = ( /obj/structure/closet/crate/internals, /obj/item/tank/internals/emergency_oxygen, @@ -184,13 +162,6 @@ dir = 4 }, /area/mine/laborcamp/production) -"be" = ( -/obj/machinery/door/airlock/external/glass{ - name = "Raptor Ranch External Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/turf/open/floor/plating/lavaland_atmos, -/area/mine/lobby/raptor) "bf" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth_large, @@ -220,6 +191,13 @@ }, /turf/open/floor/iron/edge, /area/mine/lounge) +"bx" = ( +/obj/structure/railing{ + dir = 1 + }, +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "by" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/siding/wideplating_new{ @@ -234,10 +212,10 @@ }, /turf/open/floor/plating, /area/mine/maintenance/production) -"bE" = ( -/obj/structure/table/wood, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) +"bD" = ( +/obj/structure/railing/corner, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "bH" = ( /obj/structure/table, /obj/item/book/manual/chef_recipes{ @@ -296,6 +274,10 @@ /obj/machinery/mining_weather_monitor/directional/north, /turf/open/floor/iron/dark/smooth_edge, /area/mine/production) +"bY" = ( +/obj/effect/spawner/random/lavaland_mob/raptor/young, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "cb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -470,6 +452,10 @@ dir = 4 }, /area/mine/lounge) +"cO" = ( +/obj/effect/spawner/random/lavaland_mob/raptor/young, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "cQ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/airalarm/directional/south, @@ -629,19 +615,6 @@ /obj/structure/lattice/catwalk/mining, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) -"dF" = ( -/obj/structure/table/wood, -/obj/item/food/meat/slab, -/obj/item/food/meat/slab{ - pixel_x = 6; - pixel_y = 5 - }, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) -"dI" = ( -/obj/machinery/light/small/directional/east, -/turf/open/floor/plating/lavaland_atmos, -/area/mine/lobby/raptor) "dJ" = ( /obj/structure/lattice/catwalk, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -682,6 +655,10 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"eb" = ( +/obj/effect/spawner/structure/window/reinforced, +/turf/open/floor/plating, +/area/lavaland/surface/outdoors) "ee" = ( /obj/machinery/shower/directional/south, /obj/machinery/door/window/right/directional/south, @@ -712,6 +689,13 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"ev" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/structure/ore_container/food_trough/raptor_trough, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "ey" = ( /obj/structure/lattice/catwalk/mining, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -781,12 +765,6 @@ dir = 8 }, /area/mine/cafeteria) -"eL" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "eN" = ( /obj/structure/chair/wood{ dir = 1 @@ -834,9 +812,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plating, /area/mine/laborcamp/security/maintenance) -"fa" = ( -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "fb" = ( /obj/structure/railing/corner{ dir = 4 @@ -899,6 +874,24 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) +"fw" = ( +/obj/effect/turf_decal/trimline/yellow/filled/arrow_cw{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/red/filled/arrow_cw{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/yellow/filled/mid_joiner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/red/filled/mid_joiner{ + dir = 4 + }, +/obj/structure/tank_holder/extinguisher, +/turf/open/floor/iron/dark/textured_corner{ + dir = 8 + }, +/area/mine/production) "fx" = ( /obj/structure/railing, /obj/effect/turf_decal/stripes/line{ @@ -917,6 +910,13 @@ /obj/item/radio/intercom/directional/west, /turf/open/floor/iron/dark, /area/mine/production) +"fB" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing{ + dir = 1 + }, +/turf/open/lava/smooth/lava_land_surface, +/area/lavaland/surface/outdoors) "fD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -1288,10 +1288,6 @@ /obj/structure/sign/poster/official/cleanliness/directional/north, /turf/open/floor/iron/freezer, /area/mine/living_quarters) -"hl" = ( -/obj/structure/tank_holder/extinguisher, -/turf/open/misc/asteroid/basalt/lava_land_surface, -/area/lavaland/surface/outdoors) "hn" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 9 @@ -1345,6 +1341,12 @@ /obj/structure/lattice/catwalk, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"hA" = ( +/obj/structure/railing{ + dir = 8 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "hB" = ( /obj/structure/cable, /obj/machinery/light/directional/north, @@ -1410,13 +1412,6 @@ /obj/structure/stone_tile, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"hM" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/obj/machinery/light/directional/south, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "hR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1516,10 +1511,6 @@ /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/mine/lobby/raptor) "io" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1592,6 +1583,16 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) +"iL" = ( +/obj/item/reagent_containers/cup/bucket/wooden{ + pixel_y = 12; + pixel_x = 10 + }, +/obj/structure/chair/plastic{ + dir = 4 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "iN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1713,10 +1714,6 @@ }, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) -"jt" = ( -/obj/structure/fireplace, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "jw" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -1761,11 +1758,6 @@ }, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) -"jJ" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "jL" = ( /obj/structure/stone_tile/surrounding_tile, /obj/structure/stone_tile/surrounding_tile{ @@ -1815,13 +1807,6 @@ dir = 8 }, /area/mine/production) -"jX" = ( -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "ka" = ( /obj/structure/table, /obj/machinery/newscaster/directional/north, @@ -1832,19 +1817,9 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) -"kf" = ( -/obj/structure/railing{ - dir = 9 - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "kg" = ( /turf/closed/wall/r_wall, /area/mine/laborcamp) -"ki" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating/lavaland_atmos, -/area/mine/lobby/raptor) "kk" = ( /obj/structure/stone_tile/block{ dir = 8 @@ -1883,6 +1858,11 @@ /obj/structure/cable, /turf/open/floor/plating, /area/mine/maintenance/living/north) +"kz" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing, +/turf/open/lava/smooth/lava_land_surface, +/area/lavaland/surface/outdoors) "kB" = ( /obj/structure/stone_tile/surrounding_tile, /obj/structure/stone_tile/surrounding_tile{ @@ -2024,6 +2004,13 @@ /obj/effect/turf_decal/tile/brown/fourcorners, /turf/open/floor/iron/dark, /area/mine/production) +"lf" = ( +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/ore_container/food_trough/raptor_trough, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "lg" = ( /obj/machinery/computer/order_console/mining, /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -2198,7 +2185,10 @@ name = "Mining Shuttle Airlock" }, /obj/effect/mapping_helpers/airlock/access/any/supply/mining, -/obj/effect/mapping_helpers/airlock/access/any/supply/mining, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/line, /turf/open/floor/iron/dark/textured_large, /area/mine/production) "lN" = ( @@ -2328,17 +2318,6 @@ }, /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/mine/lobby/raptor) "ml" = ( /obj/structure/stone_tile/block/cracked{ dir = 8 @@ -2752,12 +2731,6 @@ /obj/effect/spawner/random/trash/food_packaging, /turf/open/floor/iron/checker, /area/mine/laborcamp) -"nO" = ( -/obj/structure/railing{ - dir = 4 - }, -/turf/open/misc/asteroid/basalt/lava_land_surface, -/area/lavaland/surface/outdoors) "nP" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/portable_atmospherics/scrubber, @@ -2889,6 +2862,13 @@ /obj/effect/turf_decal/trimline/brown/filled/line, /turf/open/floor/iron/dark/textured_large, /area/mine/production) +"ow" = ( +/obj/structure/railing{ + dir = 1 + }, +/obj/structure/flora/ash/fireblossom, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "oy" = ( /obj/structure/lattice/catwalk/mining, /obj/structure/railing{ @@ -2935,15 +2915,6 @@ /obj/effect/turf_decal/trimline/green/filled/line, /turf/open/floor/iron/dark, /area/mine/laborcamp) -"oO" = ( -/obj/machinery/door/airlock/external/glass{ - name = "Mining External Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, -/turf/open/floor/plating/lavaland_atmos, -/area/mine/lobby/raptor) "oS" = ( /obj/machinery/door/airlock/external/glass{ name = "Mining External Airlock" @@ -3090,12 +3061,6 @@ }, /turf/open/floor/plating, /area/mine/laborcamp) -"pF" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "pH" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -3121,10 +3086,6 @@ /obj/structure/sign/poster/official/cleanliness/directional/north, /turf/open/floor/iron/freezer, /area/mine/laborcamp/quarters) -"pM" = ( -/obj/structure/bookcase/random/reference, -/turf/open/floor/wood, -/area/mine/lobby/raptor) "pO" = ( /obj/machinery/shower/directional/south, /obj/machinery/door/window/left/directional/south, @@ -3284,11 +3245,6 @@ }, /turf/open/floor/iron/dark, /area/mine/laborcamp/security) -"qB" = ( -/obj/machinery/smartfridge/drying/rack, -/obj/item/food/cheese/firm_cheese, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "qH" = ( /obj/machinery/door/airlock{ id_tag = "miningbathroomprivate"; @@ -3348,35 +3304,6 @@ }, /turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) -"rf" = ( -/obj/machinery/airalarm/directional/north, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) -"rj" = ( -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = -1; - pixel_x = 5 - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = 9; - pixel_x = 8 - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = 9; - pixel_x = 2 - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?" - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "rm" = ( /obj/structure/sign/warning/gas_mask/directional/west, /obj/effect/decal/cleanable/dirt, @@ -3390,6 +3317,10 @@ }, /turf/open/floor/iron/smooth, /area/mine/laborcamp) +"rt" = ( +/obj/structure/flora/ash/leaf_shroom, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "rv" = ( /obj/effect/turf_decal/trimline/brown/filled/line, /turf/open/floor/iron/dark/smooth_edge{ @@ -3418,13 +3349,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/service) -"rB" = ( -/obj/structure/chair/sofa/corner{ - dir = 1; - color = "#AA4A44" - }, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "rF" = ( /turf/closed/wall/r_wall, /area/mine/maintenance/labor) @@ -3495,11 +3419,6 @@ /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/mine/lobby/raptor) "se" = ( /turf/open/floor/iron/dark/textured_large, /area/mine/eva) @@ -3596,10 +3515,6 @@ "sO" = ( /turf/open/floor/plating, /area/mine/maintenance/service) -"sQ" = ( -/obj/structure/ore_container/food_trough/raptor_trough, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "sR" = ( /obj/machinery/light/small/directional/west, /obj/effect/decal/cleanable/dirt, @@ -3662,6 +3577,12 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/carpet, /area/mine/living_quarters) +"td" = ( +/obj/structure/railing/corner/end{ + dir = 8 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "te" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -3672,13 +3593,6 @@ dir = 4 }, /area/mine/cafeteria) -"tf" = ( -/obj/structure/chair/sofa/corner{ - dir = 8; - color = "#AA4A44" - }, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "tg" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/door/airlock/maintenance{ @@ -3868,10 +3782,6 @@ }, /turf/open/floor/iron/white/smooth_edge, /area/mine/cafeteria) -"uw" = ( -/obj/effect/spawner/random/lavaland_mob/raptor, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "ux" = ( /obj/machinery/door/airlock{ id_tag = "miningdorm1"; @@ -3882,6 +3792,14 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron, /area/mine/living_quarters) +"uy" = ( +/obj/effect/turf_decal/sand/plating/volcanic, +/obj/structure/railing/corner/end{ + dir = 8 + }, +/obj/structure/marker_beacon/purple, +/turf/open/floor/plating/lavaland_atmos, +/area/lavaland/surface/outdoors) "uC" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/siding/wideplating_new{ @@ -4034,12 +3952,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plating, /area/mine/hydroponics) -"vr" = ( -/obj/structure/railing{ - dir = 1 - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "vu" = ( /obj/structure/bed/medical/emergency, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -4071,6 +3983,21 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/mine/laborcamp/production) +"vC" = ( +/obj/effect/turf_decal/trimline/yellow/filled/arrow_ccw{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/arrow_ccw{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/yellow/filled/mid_joiner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/mid_joiner{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured_corner, +/area/mine/production) "vD" = ( /turf/closed/wall, /area/mine/laborcamp/security/maintenance) @@ -4108,14 +4035,6 @@ /obj/item/cigbutt, /turf/open/floor/iron/smooth, /area/mine/laborcamp) -"vM" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "vN" = ( /obj/machinery/computer/records/security, /obj/structure/cable, @@ -4167,12 +4086,6 @@ /obj/effect/turf_decal/siding/wideplating_new, /turf/open/floor/iron/checker, /area/mine/laborcamp) -"wa" = ( -/obj/machinery/camera/autoname/directional/north{ - network = list("mine") - }, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "wb" = ( /obj/structure/chair{ dir = 8 @@ -4304,6 +4217,14 @@ /obj/item/seeds/banana, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"wR" = ( +/obj/effect/turf_decal/sand/plating/volcanic, +/obj/structure/marker_beacon/purple, +/obj/structure/railing/corner/end/flip{ + dir = 8 + }, +/turf/open/floor/plating/lavaland_atmos, +/area/lavaland/surface/outdoors) "wT" = ( /obj/structure/cable, /obj/effect/turf_decal/loading_area{ @@ -4655,7 +4576,7 @@ /turf/open/floor/plating, /area/mine/maintenance/service) "ze" = ( -/turf/open/misc/ashplanet/rocky, +/turf/closed/mineral/random/high_chance, /area/lavaland/surface/outdoors) "zf" = ( /obj/machinery/door/airlock{ @@ -4810,13 +4731,6 @@ /obj/structure/cable, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"zX" = ( -/obj/structure/chair/wood{ - dir = 1 - }, -/obj/machinery/light/directional/south, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "Ae" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -4832,13 +4746,6 @@ }, /turf/open/floor/plating, /area/mine/laborcamp/production) -"Ah" = ( -/obj/machinery/microwave{ - pixel_y = 6 - }, -/obj/structure/table/wood, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "Ai" = ( /obj/structure/stone_tile/cracked{ dir = 1 @@ -4875,10 +4782,10 @@ /turf/open/floor/iron/dark/textured_large, /area/mine/production) "Av" = ( -/obj/structure/railing{ - dir = 9 +/obj/structure/railing/corner{ + dir = 8 }, -/turf/open/misc/asteroid/basalt/lava_land_surface, +/turf/open/misc/hay/lavaland, /area/lavaland/surface/outdoors) "Ax" = ( /obj/item/pickaxe, @@ -4902,13 +4809,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/mine/laborcamp) -"AF" = ( -/obj/structure/lattice/catwalk/mining, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/lava/smooth/lava_land_surface, -/area/lavaland/surface/outdoors) "AI" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -4955,6 +4855,13 @@ "AX" = ( /turf/open/floor/plating, /area/mine/laborcamp/security/maintenance) +"AY" = ( +/obj/structure/railing{ + dir = 1 + }, +/obj/effect/spawner/random/lavaland_mob/raptor/baby, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "Bb" = ( /obj/machinery/camera/autoname/directional/east{ network = list("mine") @@ -5086,31 +4993,6 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) -"Cn" = ( -/obj/structure/table/wood, -/obj/item/plate{ - pixel_x = 6; - pixel_y = 7 - }, -/obj/item/plate{ - pixel_x = -6; - pixel_y = -6 - }, -/obj/item/reagent_containers/cup/glass/mug/tea{ - pixel_x = 8; - pixel_y = -3 - }, -/obj/effect/turf_decal/siding/wood/end{ - dir = 8 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) -"Cv" = ( -/obj/effect/turf_decal/sand/plating/volcanic, -/obj/structure/marker_beacon/purple, -/obj/effect/turf_decal/sand/plating/volcanic, -/turf/open/floor/plating/lavaland_atmos, -/area/lavaland/surface/outdoors) "Cz" = ( /obj/machinery/door/airlock/medical/glass{ name = "Infirmary" @@ -5176,8 +5058,21 @@ }, /area/mine/living_quarters) "CM" = ( -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/dark/textured_large, +/obj/effect/turf_decal/trimline/yellow/filled/arrow_ccw{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/arrow_ccw{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/yellow/filled/mid_joiner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/mid_joiner{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured_corner{ + dir = 4 + }, /area/mine/production) "CO" = ( /turf/open/floor/iron/textured_large, @@ -5209,9 +5104,6 @@ /obj/structure/curtain, /turf/open/floor/iron/freezer, /area/mine/living_quarters) -"CV" = ( -/turf/closed/wall/mineral/iron, -/area/mine/lobby/raptor) "CX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -5225,6 +5117,19 @@ /obj/structure/lattice/catwalk/mining, /turf/open/lava/smooth/lava_land_surface, /area/lavaland/surface/outdoors) +"Db" = ( +/obj/machinery/door/airlock/external/glass{ + name = "Mining Shuttle Airlock" + }, +/obj/effect/mapping_helpers/airlock/access/any/supply/mining, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured_large, +/area/lavaland/surface/outdoors) "Dd" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -5317,6 +5222,12 @@ /obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance, /turf/open/floor/plating, /area/mine/maintenance/public/north) +"DT" = ( +/obj/structure/railing{ + dir = 5 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "DV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -5476,12 +5387,6 @@ dir = 1 }, /area/mine/production) -"EP" = ( -/obj/structure/railing{ - dir = 4 - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "EQ" = ( /turf/open/floor/iron/smooth_edge{ dir = 8 @@ -5536,12 +5441,6 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"Fo" = ( -/obj/effect/turf_decal/siding/wood/end{ - dir = 4 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "Fp" = ( /obj/structure/table, /obj/machinery/recharger, @@ -5551,11 +5450,17 @@ /turf/open/floor/iron/dark, /area/mine/laborcamp/security) "Fr" = ( -/obj/machinery/door/airlock/external/glass{ - name = "Mining Shuttle Airlock" +/obj/effect/turf_decal/trimline/yellow/filled/corner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/yellow/filled/corner, +/obj/effect/turf_decal/trimline/red/filled/corner, +/obj/effect/turf_decal/trimline/red/filled/corner{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured_edge{ + dir = 4 }, -/obj/effect/mapping_helpers/airlock/access/any/supply/mining, -/turf/open/floor/iron/dark/textured_large, /area/mine/production) "Fs" = ( /obj/effect/turf_decal/sand/plating/volcanic, @@ -5600,10 +5505,6 @@ "FH" = ( /turf/closed/wall, /area/lavaland/surface/outdoors) -"FI" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "FL" = ( /obj/structure/disposalpipe/segment, /obj/machinery/light/small/directional/west, @@ -5616,6 +5517,13 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"FP" = ( +/obj/effect/turf_decal/sand/plating/volcanic, +/obj/structure/railing{ + dir = 1 + }, +/turf/open/floor/plating/lavaland_atmos, +/area/lavaland/surface/outdoors) "FT" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 1 @@ -5731,9 +5639,6 @@ dir = 8 }, /area/mine/production) -"GG" = ( -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "GH" = ( /obj/machinery/door/airlock/glass{ name = "Arrival Lounge" @@ -5743,12 +5648,6 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron, /area/mine/lounge) -"GI" = ( -/obj/structure/rack, -/obj/item/stack/sheet/mineral/wood/fifty, -/obj/item/lighter, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "GL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -5759,6 +5658,20 @@ dir = 4 }, /area/mine/production) +"GO" = ( +/obj/structure/railing{ + dir = 6 + }, +/obj/structure/table/wood, +/obj/item/raptor_dex, +/obj/item/raptor_dex{ + pixel_y = 7 + }, +/obj/item/raptor_dex{ + pixel_y = 13 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "GR" = ( /obj/structure/stone_tile/block/cracked{ dir = 4 @@ -6144,9 +6057,10 @@ /area/mine/laborcamp) "Jg" = ( /obj/effect/turf_decal/sand/plating/volcanic, -/obj/structure/railing{ - dir = 10 +/obj/structure/railing/corner/end{ + dir = 4 }, +/obj/structure/marker_beacon/purple, /turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) "Jh" = ( @@ -6406,41 +6320,6 @@ /obj/structure/girder, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"Km" = ( -/obj/structure/rack, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?" - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = 9 - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = 9; - pixel_x = 2 - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = 6 - }, -/obj/item/food/grown/grass/fairy{ - name = "weird hay"; - desc = "Somehow, somewhere, this tells you it should increase your friendship level with your animals. Too bad that doesn't work, right?"; - pixel_y = 6; - pixel_x = 9 - }, -/obj/item/crowbar/large, -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "Kn" = ( /obj/machinery/telecomms/relay/preset/mining, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -6534,12 +6413,6 @@ }, /turf/open/floor/iron/checker, /area/mine/cafeteria) -"KO" = ( -/obj/structure/railing{ - dir = 8 - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "KV" = ( /obj/structure/table, /obj/machinery/light/directional/east, @@ -6560,6 +6433,12 @@ }, /turf/open/floor/iron, /area/mine/living_quarters) +"KY" = ( +/obj/structure/railing/corner/end/flip{ + dir = 8 + }, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "KZ" = ( /obj/structure/stone_tile/slab/cracked{ dir = 4 @@ -6661,15 +6540,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/storage) -"Lv" = ( -/obj/machinery/power/apc/auto_name/directional/south, -/obj/structure/cable, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/turf_decal/siding/wood, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "Lw" = ( /obj/effect/turf_decal/sand/plating/volcanic, /obj/effect/turf_decal/stripes/line{ @@ -6800,6 +6670,23 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"Mb" = ( +/obj/effect/turf_decal/trimline/yellow/filled/arrow_cw{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/red/filled/arrow_cw{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/yellow/filled/mid_joiner{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/red/filled/mid_joiner{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured_corner{ + dir = 1 + }, +/area/mine/production) "Mc" = ( /obj/structure/chair/wood/wings, /obj/machinery/light/small/directional/east, @@ -6827,10 +6714,6 @@ dir = 8 }, /area/mine/lounge) -"Mf" = ( -/obj/item/kirbyplants/random, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "Mr" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, @@ -7050,6 +6933,12 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth_large, /area/mine/laborcamp/production) +"NA" = ( +/obj/structure/railing, +/obj/structure/table/wood, +/obj/item/flashlight/lantern/on, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "NC" = ( /obj/structure/gulag_vent, /turf/open/misc/asteroid/basalt/lava_land_surface, @@ -7074,7 +6963,11 @@ /turf/open/floor/iron/dark, /area/mine/production) "NK" = ( -/turf/open/misc/ashplanet/ash, +/obj/structure/railing{ + dir = 8 + }, +/obj/structure/railing/corner, +/turf/open/misc/hay/lavaland, /area/lavaland/surface/outdoors) "NL" = ( /obj/structure/railing, @@ -7085,13 +6978,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/mine/laborcamp/security/maintenance) -"NP" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/cable, -/turf/open/floor/plating/lavaland_atmos, -/area/mine/lobby/raptor) "NR" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -7101,9 +6987,6 @@ dir = 1 }, /area/mine/laborcamp/production) -"NS" = ( -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "NT" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7198,13 +7081,6 @@ }, /turf/open/floor/iron, /area/mine/lounge) -"Oo" = ( -/obj/structure/railing{ - dir = 5 - }, -/obj/item/reagent_containers/cup/bucket/wooden, -/turf/open/misc/hay/lavaland, -/area/lavaland/surface/outdoors) "Op" = ( /obj/structure/stone_tile/slab, /turf/open/misc/asteroid/basalt/lava_land_surface, @@ -7226,16 +7102,6 @@ dir = 4 }, /area/mine/laborcamp/security) -"OE" = ( -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/chair/wood{ - dir = 1 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "OH" = ( /obj/item/storage/fancy/cigarettes/cigpack_robust{ pixel_x = -8; @@ -7251,6 +7117,10 @@ }, /turf/open/floor/iron/smooth, /area/mine/laborcamp) +"OL" = ( +/obj/structure/railing, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "OM" = ( /obj/structure/table, /obj/machinery/power/apc/auto_name/directional/east, @@ -7282,17 +7152,6 @@ /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/mine/lobby/raptor) "OZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -7316,13 +7175,6 @@ /obj/effect/turf_decal/stripes/corner, /turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) -"Pe" = ( -/obj/structure/lattice/catwalk/mining, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating/lavaland_atmos, -/area/lavaland/surface/outdoors) "Pi" = ( /obj/machinery/light/small/directional/south, /obj/effect/turf_decal/trimline/red/filled/line, @@ -7361,12 +7213,6 @@ /obj/effect/spawner/structure/window, /turf/open/floor/plating, /area/mine/cafeteria) -"Pn" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating/lavaland_atmos, -/area/lavaland/surface/outdoors) "Po" = ( /obj/structure/table, /obj/item/paper/guides/jobs/security/labor_camp, @@ -7673,23 +7519,6 @@ /obj/structure/easel, /turf/open/misc/hay/lavaland, /area/lavaland/surface/outdoors) -"Rj" = ( -/obj/machinery/suit_storage_unit/mining, -/obj/effect/turf_decal/trimline/brown/filled/line{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/iron/dark/smooth_edge{ - dir = 8 - }, -/area/mine/eva) -"Rm" = ( -/obj/structure/bed, -/obj/effect/spawner/random/bedsheet, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "Ro" = ( /obj/effect/turf_decal/loading_area, /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -7774,13 +7603,6 @@ /obj/structure/lattice/catwalk, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"RO" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating, -/area/mine/eva) "RV" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -7842,11 +7664,6 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"Sj" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "Sm" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/effect/turf_decal/siding/yellow, @@ -7860,14 +7677,6 @@ }, /turf/open/floor/iron/dark, /area/mine/hydroponics) -"Sp" = ( -/obj/structure/easel, -/obj/item/canvas/fortyfive_twentyseven, -/obj/item/canvas/thirtysix_twentyfour, -/obj/item/canvas/twentythree_nineteen, -/obj/item/paint_palette, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "Sq" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/structure/cable, @@ -8013,6 +7822,12 @@ dir = 1 }, /area/mine/production) +"Tk" = ( +/obj/structure/railing{ + dir = 6 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "To" = ( /obj/structure/table, /obj/machinery/reagentgrinder, @@ -8049,23 +7864,12 @@ dir = 4 }, /area/mine/production) -"Tt" = ( -/obj/item/kirbyplants/random, -/obj/effect/turf_decal/siding/wood/end{ - dir = 4 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "Tu" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/mine/laborcamp) -"Tw" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "Tx" = ( /obj/machinery/light/small/directional/north, /obj/effect/decal/cleanable/dirt, @@ -8203,6 +8007,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/mine/laborcamp/quarters) +"Um" = ( +/obj/structure/flora/ash/tall_shroom, +/turf/open/misc/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) "Un" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -8245,10 +8053,6 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"Uz" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "UD" = ( /obj/structure/toilet{ dir = 8 @@ -8336,10 +8140,6 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"Vd" = ( -/obj/structure/railing, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "Ve" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/textured_large, @@ -8351,6 +8151,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/textured_large, /area/mine/laborcamp) +"Vg" = ( +/obj/structure/railing, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "Vh" = ( /obj/machinery/door/airlock/external/glass{ name = "Mining External Airlock" @@ -8461,15 +8265,6 @@ }, /turf/open/floor/iron/checker, /area/mine/laborcamp) -"VI" = ( -/obj/effect/spawner/random/food_or_drink/donkpockets, -/obj/effect/spawner/random/food_or_drink/donkpockets{ - pixel_x = 6; - pixel_y = 5 - }, -/obj/structure/table/wood, -/turf/open/floor/carpet/red, -/area/mine/lobby/raptor) "VJ" = ( /obj/structure/closet/crate, /obj/item/food/mint, @@ -8492,12 +8287,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/labor) -"VP" = ( -/obj/effect/turf_decal/siding/wood/end{ - dir = 8 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "VS" = ( /obj/machinery/hydroponics/constructable, /obj/effect/decal/cleanable/dirt, @@ -8507,12 +8296,6 @@ /obj/item/seeds/potato, /turf/open/floor/iron/dark, /area/mine/laborcamp) -"VU" = ( -/obj/structure/railing/corner/end{ - dir = 8 - }, -/turf/open/misc/asteroid/basalt/lava_land_surface, -/area/lavaland/surface/outdoors) "VX" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line{ @@ -8539,6 +8322,15 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/storage) +"Wf" = ( +/obj/structure/railing{ + dir = 4 + }, +/obj/structure/railing/corner{ + dir = 8 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "Wg" = ( /obj/structure/girder, /obj/effect/turf_decal/sand/plating/volcanic, @@ -8546,15 +8338,22 @@ /area/mine/lounge) "Wh" = ( /obj/structure/railing{ - dir = 8 + dir = 10 }, -/turf/open/misc/asteroid/basalt/lava_land_surface, +/obj/structure/table/wood, +/obj/item/soap/deluxe, +/obj/item/soap/deluxe{ + pixel_y = 6 + }, +/obj/item/soap/deluxe{ + pixel_y = 11 + }, +/turf/open/misc/hay/lavaland, /area/lavaland/surface/outdoors) "Wk" = ( -/obj/structure/railing{ - dir = 1 - }, -/turf/open/misc/asteroid/basalt/lava_land_surface, +/obj/structure/railing, +/obj/effect/spawner/random/lavaland_mob/raptor/young, +/turf/open/misc/hay/lavaland, /area/lavaland/surface/outdoors) "Wl" = ( /obj/machinery/door/airlock/external/glass{ @@ -8575,12 +8374,6 @@ dir = 1 }, /area/mine/laborcamp/security) -"Wq" = ( -/obj/structure/railing{ - dir = 5 - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) "Wt" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /obj/structure/disposalpipe/segment, @@ -8746,9 +8539,12 @@ dir = 4 }, /area/mine/production) -"Xk" = ( -/obj/effect/spawner/random/lavaland_mob/raptor, -/turf/open/misc/hay/lavaland, +"Xl" = ( +/obj/structure/railing{ + dir = 9 + }, +/obj/effect/turf_decal/sand/plating/volcanic, +/turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) "Xp" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -8822,6 +8618,12 @@ dir = 1 }, /area/mine/lounge) +"XG" = ( +/obj/structure/railing{ + dir = 10 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "XH" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -8844,7 +8646,21 @@ pixel_x = -32; pixel_y = 0 }, -/turf/open/floor/iron/dark/textured_large, +/obj/effect/turf_decal/trimline/yellow/filled/arrow_ccw{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/arrow_ccw{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/yellow/filled/mid_joiner{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/mid_joiner{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured_edge{ + dir = 8 + }, /area/mine/production) "XP" = ( /obj/structure/stone_tile/cracked, @@ -8936,8 +8752,6 @@ /area/mine/lounge) "Yg" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, /turf/open/floor/iron/dark/textured_large, /area/mine/eva) "Yk" = ( @@ -9023,14 +8837,6 @@ /obj/structure/barricade/wooden, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"YP" = ( -/obj/structure/bookcase/random/reference, -/obj/effect/turf_decal/siding/wood, -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) "YR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -9114,10 +8920,6 @@ }, /turf/open/floor/iron/smooth, /area/mine/laborcamp/production) -"Zs" = ( -/obj/structure/closet/secure_closet/personal/cabinet, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "Zt" = ( /turf/closed/wall, /area/mine/laborcamp) @@ -9143,6 +8945,12 @@ /obj/effect/turf_decal/sand/plating/volcanic, /turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) +"Zy" = ( +/obj/structure/railing/corner/end/flip{ + dir = 4 + }, +/turf/open/misc/hay/lavaland, +/area/lavaland/surface/outdoors) "Zz" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -9157,18 +8965,6 @@ dir = 8 }, /area/mine/lounge) -"ZB" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/effect/turf_decal/siding/wood, -/turf/open/floor/wood/large, -/area/mine/lobby/raptor) -"ZF" = ( -/obj/effect/turf_decal/sand/plating/volcanic, -/obj/effect/turf_decal/sand/plating/volcanic, -/turf/open/floor/plating/lavaland_atmos, -/area/lavaland/surface/outdoors) "ZH" = ( /obj/structure/closet/secure_closet/labor_camp_security, /obj/effect/turf_decal/trimline/red/filled/line{ @@ -9177,13 +8973,6 @@ /obj/structure/extinguisher_cabinet/directional/west, /turf/open/floor/iron/dark, /area/mine/laborcamp/security) -"ZL" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/chair/wood, -/obj/structure/cable, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "ZM" = ( /obj/structure/railing{ dir = 8 @@ -9215,17 +9004,6 @@ /obj/effect/mapping_helpers/airlock/access/any/engineering/maintenance, /turf/open/floor/plating, /area/mine/maintenance/public/north) -"ZU" = ( -/obj/structure/railing{ - dir = 6 - }, -/turf/open/misc/hay/lavaland, -/area/mine/lobby/raptor) -"ZX" = ( -/obj/structure/table/wood, -/obj/item/knife, -/turf/open/floor/wood/parquet, -/area/mine/lobby/raptor) "ZY" = ( /turf/closed/mineral/random/volcanic, /area/lavaland/surface/outdoors/unexplored) @@ -42633,8 +42411,8 @@ Hj pU BP pU -NK -ze +ai +ai pU pU aj @@ -42889,9 +42667,9 @@ EL EL pU pU -ze +ai BP -ze +ai pU pU aj @@ -43146,8 +42924,8 @@ pU pU pU pU -ze -ze +ai +ai pU pU aj @@ -44946,8 +44724,8 @@ aj aj aj aj -NK -NK +ze +ze pU aj aj @@ -45461,7 +45239,7 @@ aj aj pU BP -ze +ai pU pU aj @@ -45717,7 +45495,7 @@ aj aj aj pU -NK +ai pU pU pU @@ -47494,11 +47272,11 @@ WB wt jw fA -Le +NU Le NU Le -Le +NU BP BP BP @@ -47516,7 +47294,7 @@ aj aj pU pU -NK +ai BP ze pU @@ -47752,7 +47530,7 @@ Jl rv TJ RW -cc +vC XM CM lM @@ -47772,10 +47550,10 @@ aj aj aj pU +ai ze ze -ze -ze +ai aj aj aj @@ -48009,9 +47787,9 @@ GF lb Yl Le -Le +fw Fr -Le +Mb Le BP BP @@ -48031,7 +47809,7 @@ aj pU BP ze -NK +ze pU aj aj @@ -48266,10 +48044,10 @@ Ra oh pK NU -BP -BP -BP -JD +eb +Db +eb +FH BP BP BP @@ -48286,8 +48064,8 @@ pU aj aj pU -NK -NK +ai +ai pU pU aj @@ -48524,7 +48302,7 @@ mT pK pU BP -ZF +BP BP JD BP @@ -48780,9 +48558,9 @@ Yg li dK pU -Cv BP -Cv +aI +BP zk mc mc @@ -49037,8 +48815,8 @@ Yg TQ dK pU -aX -BP +pU +FP Jg pU pU @@ -49290,14 +49068,14 @@ YD pK Ob IL -Rj +IL KV pK aj +aj yV -BP fK -pU +aj pU pU pU @@ -49547,12 +49325,12 @@ NU pK pK dK -RO +dK pK pK aj +aj yV -tF NL aj aj @@ -49804,12 +49582,12 @@ NU ai pU pU -Pn +pU pU aj aj +aj yV -tF NL aj aj @@ -50061,12 +49839,12 @@ pU pU pU pU -AF +aj aj aj pU +aj yV -tF NL aj aj @@ -50318,12 +50096,12 @@ pU aj aj aj -AF +aj aj pU aj +aj yV -tF NL aj pU @@ -50340,7 +50118,7 @@ pU pU pU pU -ze +ai ze ze pU @@ -50575,13 +50353,13 @@ aj aj aj aj -AF aj aj aj -zs -tF -de +aj +aj +fB +kz aj aj aj @@ -50596,8 +50374,8 @@ aj pU pU pU +ai ze -NK ze BP pU @@ -50832,30 +50610,30 @@ aj aj aj aj -AF aj aj aj -ct +aj +aj +FP +wR +pU +aj +aj +aj +aj +aj +aj +aj +aj +aj +pU +pU +pU +ai BP -ct -pU -aj -aj -aj -aj -aj -aj -aj -aj -aj -pU -pU -pU -ze -BP -NK -ze +ai +ai pU pU pU @@ -51089,12 +50867,12 @@ ai ai pU pU -AF +pU +pU aj aj -aj -BP -BP +pU +uy BP pU pU @@ -51108,10 +50886,10 @@ aj pU pU pU +ai ze -ze -NK -ze +ai +ai lP pU pU @@ -51346,11 +51124,11 @@ ai ai ai ai -Pn -AF -AF -AF -Pe +pU +pU +pU +pU +pU BP BP BP @@ -51366,10 +51144,10 @@ lt Ri eN pU -ze -ze -ze -ze +ai +ai +ai +ai pU pU aj @@ -51607,10 +51385,8 @@ ai pU pU pU -AF -BP -BP -BP +pU +pU BP ct pU @@ -51618,6 +51394,8 @@ pU pU pU pU +pU +BP lt Ns lt @@ -51625,7 +51403,7 @@ pU pU pU pU -ze +ai pU pU aj @@ -51861,21 +51639,21 @@ aj aj ai ai -CV -CV -ki -NP -ki -CV -CV -CV -lt pU pU pU pU pU pU +pU +pU +pU +pU +pU +pU +pU +BP +BP lt pU lP @@ -52117,19 +51895,11 @@ aj aj aj aj -CV -CV -Km -qB -eL -Ah -VI -ZX -ki -Ns +aj +pU +pU lt pU -BP pU pU pU @@ -52138,6 +51908,14 @@ pU pU pU pU +rt +pU +pU +pU +pU +pU +pU +pU pU pU aj @@ -52374,25 +52152,25 @@ aj aj aj aj -CV -GG -jX -Tw -eL -aF -pF -dF -ki -lt -lt +aj +aj +pU +Ns lt pU +BP +pU +pU pU pU BP -NK -NK -ze +pU +lt +Ns +lt +UI +pU +pU pU pU pU @@ -52628,28 +52406,28 @@ pU ai ai ai -pU +ai +aj +aj aj aj -CV -Sp -OE -as -ZL -Cn -zX -CV -CV pU +pU +lt lt pU pU pU pU -ze -NK -ze BP +Xl +lf +XG +hA +lf +NK +FH +pU pU pU pU @@ -52887,27 +52665,24 @@ ai ai ai ai +ai +aj +aj pU -CV -GG -Tt -fa -eL -ZB -GG -CV +pU +lt pU pU pU +pU +pU +BP +AY +pU +OL lP -pU -BP -pU -ze -NK -pU -UI -pU +lt +Vg pU pU pU @@ -52919,6 +52694,9 @@ aj aj aj aj +aj +aj +aj "} (171,1,1) = {" aa @@ -53145,34 +52923,34 @@ aj ai ai ai -CV -wa -rB -fa -eL -Lv -CV -CV -CV -ct +ai pU pU pU pU +lP pU -ze +BP pU -pU -lt -lt -lt UI +ct +ow +Az +OL pU -aj +pU +Vg pU pU aj +aj +aj +aj +aj +aj +aj pU +aj pU aj aj @@ -53400,29 +53178,25 @@ aj aj aj aj -pU ai -CV -jt -ba -fa -jJ -ZB -be -dI -oO -BP -pU -BP -pU -pU +ai +ai pU +UI ct -BP +pU +pU +pU +pU +pU lt lt -Ns +up +UI +OL +bY lt +Vg lt pU pU @@ -53430,7 +53204,11 @@ pU pU pU pU -pU +aj +aj +aj +aj +aj aj aj "} @@ -53659,36 +53437,36 @@ aj aj aj aj -CV -GG -tf -fa -Sj -ZB -CV -CV -CV -ct -pU -pU pU pU pU BP +pU +pU +pU +pU +lt +lt +lt +td +pU +KY +lt +lt Av Wh -Wh -CV -ki -ki -CV -CV -ki -ki -CV -CV +lt pU pU +pU +pU +pU +aj +aj +pU +pU +aj +aj aj "} (174,1,1) = {" @@ -53916,37 +53694,37 @@ aj aj aj aj -CV -rf -VP -fa -Sj -ZB -Mf -CV -hl +aj +aj pU +pU +pU +BP +pU +pU +lt +Ns lt lt pU pU lt lt -up +lt +NA lt pU -vr -sQ -NS -Vd -NS -NS -sQ -NS -CV +pU +aj +aj pU pU aj +aj +aj +aj +aj +aj "} (175,1,1) = {" aa @@ -54173,37 +53951,37 @@ aj aj aj aj -CV -GI -vM -FI -jJ -Fo -hM -CV -CV -Ns -lt +aj +aj +pU +pU +pU +pU +pU +pU pU pU lt +Zy lt +xW +pU lt -up +bD +GO pU pU -vr -il -NS -Vd -NS -NS -il -NS -ki pU aj aj +aj +aj +aj +aj +aj +aj +aj +aj "} (176,1,1) = {" aa @@ -54430,36 +54208,36 @@ aj aj aj aj -CV -pM -YP -GG -Uz -Uz -Uz -Zs -ki -lt -lt +aj +pU +pU +pU +pU +pU +pU pU pU pU lt -pU +bx +lt +Vg +lt +lt Wk -UI -ct -vr -NS -NS -Vd -NS -NS -NS -NS -ki +lt pU pU +pU +pU +aj +aj +aj +aj +aj +aj +aj +aj aj "} (177,1,1) = {" @@ -54685,38 +54463,38 @@ pU pU pU pU -aj -aj -CV -CV -YP -GG -fa -fa -Rm -bE -ki +pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +ct +lt +iL +up +cO +Vg +lt +lt +Vg lt pU pU pU pU +aj +aj +aj +aj +aj pU -pU -Wk -pU -lt -Wq -EP -NS -ZU -NS -NS -EP -EP -CV -CV -pU +aj +aj aj "} (178,1,1) = {" @@ -54943,36 +54721,36 @@ pU pU pU pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +lt +Pb +up +lt +Vg +Ns +Az +Vg +pU +pU +pU +pU +pU +aj +aj +aj +aj +aj aj aj -CV -CV -ki -ki -ki -CV -CV -CV -lt -pU -pU -lt -pU -pU -pU -VU -Xk -lt -NS -NS -NS -NS -NS -uw -NS -NS -NS -ki pU aj "} @@ -55201,9 +54979,6 @@ pU pU pU pU -aj -aj -aj pU pU pU @@ -55214,24 +54989,27 @@ pU pU pU Ns -Az +lt +DT +ev +Tk +ej +ev +Wf +FH +pU +pU pU pU -lt -lt -lt -NS -mk -sa -NS -NS -NS -OW -sa -NS -ki aj aj +pU +pU +pU +aj +aj +pU +aj "} (180,1,1) = {" aa @@ -55468,26 +55246,26 @@ pU pU pU pU -pU -pU -lt lt pU -xW lt lt lt -NS -NS -uw -NS -NS -NS -NS -NS -NS -ki +Um pU +pU +pU +pU +pU +aj +aj +pU +pU +pU +pU +pU +aj +aj aj "} (181,1,1) = {" @@ -55728,22 +55506,22 @@ pU pU pU pU -lt pU pU -Wk -lt -lt -kf -KO -NS -aH -NS -NS -KO -KO -CV -CV +pU +pU +pU +pU +pU +pU +aj +aj +aj +pU +pU +pU +aj +aj pU aj "} @@ -55980,6 +55758,7 @@ pU pU pU pU +UI pU pU pU @@ -55988,19 +55767,18 @@ pU pU pU pU -Wk pU -ct -vr -NS -rj -Vd -NS -NS -NS -NS -ki pU +pU +pU +aj +aj +pU +pU +pU +pU +pU +aj aj aj "} @@ -56243,23 +56021,23 @@ pU pU pU pU -lt -lt -Wk pU pU -vr -il -NS -Vd -NS -NS -il -NS -ki pU pU pU +pU +pU +pU +pU +pU +pU +aj +aj +aj +aj +aj +pU "} (184,1,1) = {" aa @@ -56499,23 +56277,23 @@ pU pU pU pU -lt -Ns -lt -up -Pb -pU -vr -sQ -NS -Vd -NS -NS -sQ -NS -CV pU pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +aj +aj +pU +pU +aj aj "} (185,1,1) = {" @@ -56756,22 +56534,22 @@ pU pU pU pU -lt -lt -BP -Oo -ej -nO -CV -ki -ki -CV -CV -ki -ki -CV -CV pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +pU +aj +pU +aj +aj aj aj "} @@ -57015,12 +56793,6 @@ pU pU pU pU -ct -BP -pU -pU -pU -lt pU pU pU @@ -57031,6 +56803,12 @@ pU pU pU aj +aj +aj +aj +aj +aj +aj "} (187,1,1) = {" aa @@ -57273,19 +57051,19 @@ pU pU pU pU -lt -pU -pU -lt -Ns -lt -lt pU pU pU pU pU pU +pU +pU +aj +aj +aj +aj +aj aj aj "} @@ -57529,17 +57307,17 @@ pU pU pU pU -lt -lt -lt -pU -lt -lt -lt -lt -lt pU pU +pU +pU +pU +pU +pU +pU +pU +aj +aj aj aj aj @@ -57787,15 +57565,15 @@ pU pU pU pU -Ns pU pU -UI -lt -lt -Ns -lt pU +pU +pU +pU +pU +pU +aj aj aj aj @@ -58049,8 +57827,8 @@ pU pU pU pU -lt -lt +pU +pU pU aj aj diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index ebcd71345ee..f8392dfc171 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -81,6 +81,7 @@ #define BB_BASIC_MOB_CURRENT_TARGET "BB_basic_current_target" #define BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION "BB_basic_current_target_hiding_location" #define BB_TARGETING_STRATEGY "targeting_strategy" +#define BB_HUNT_TARGETING_STRATEGY "hunt_targeting_strategy" ///some behaviors that check current_target also set this on deep crit mobs #define BB_BASIC_MOB_EXECUTION_TARGET "BB_basic_execution_target" ///Blackboard key for a whitelist typecache of "things we can target while trying to move" diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index a07997d40d2..5b1d0283c56 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -39,40 +39,83 @@ #define MOOK_ATTACK_ACTIVE 2 #define MOOK_ATTACK_STRIKE 3 -///keeps track of how many gutlunches are born +/// Keeps track of how many gutlunches are born GLOBAL_VAR_INIT(gutlunch_count, 0) -///Pet customization settings saved for every client +/// Pet customization settings saved for every client GLOBAL_LIST_EMPTY(customized_pets) -//raptor defines +// Raptor defines +/// Raptor chick, tiny and very frail +#define RAPTOR_BABY "baby" +/// Raptor youngling, cannot be ridden and has reduced stats, but can hunt by itself just fine +#define RAPTOR_YOUNG "young" +/// Fully grown adult raptor +#define RAPTOR_ADULT "adult" -#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" +/// Innate raptor offsets +#define RAPTOR_INNATE_SOURCE "raptor_innate" +// Growth values +/// How much does meal complexity affect our growth? +#define RAPTOR_MEAL_COMPLEXITY_GROWTH_FACTOR 5 +/// Base value for raptor growth from meat +#define RAPTOR_GROWTH_BASE_MEAT 10 +/// Base value for raptor growth from ash flora +#define RAPTOR_GROWTH_BASE_PLANT 5 +/// How much growth progress raptors need to accumulate to fully grow into an adult +#define RAPTOR_GROWTH_REQUIRED 100 +/// Minimum random growth value a baby raptor can gain per second +#define RAPTOR_BABY_GROWTH_LOWER 0.5 +/// Maximum random growth value a baby raptor can gain per second +#define RAPTOR_BABY_GROWTH_UPPER 0.8 +/// How long it takes for a raptor egg to grow up, in seconds +#define RAPTOR_EGG_GROWTH_PROGRESS 100 +/// How much happiness percentage affects our growth speed +#define RAPTOR_GROWTH_HAPPINESS_MULTIPLIER 0.005 // Full happiness increases growth rate by 50% + +/// Damage boost per happiness percent +#define RAPTOR_HAPPINESS_DAMAGE_BOOST 0.05 + +// Raptor inheritance stats +/// Maximum amount of traits a raptor can inherit +#define RAPTOR_TRAIT_INHERIT_AMOUNT 2 +/// Minimum modifier to base attack values a raptor can get +#define RAPTOR_INHERIT_MIN_ATTACK -5 +/// Maximum modifier to base attack values a raptor can get #define RAPTOR_INHERIT_MAX_ATTACK 5 +/// Minimum modifier to the base health value a raptor can get +#define RAPTOR_INHERIT_MIN_HEALTH -30 +/// Maximum modifier to the base health value a raptor can get #define RAPTOR_INHERIT_MAX_HEALTH 30 +/// Minimum modifier to base speed values a raptor can get +#define RAPTOR_INHERIT_MIN_SPEED -0.66 +/// Maximum modifier to base speed values a raptor can get +#define RAPTOR_INHERIT_MAX_SPEED 0.66 +/// Minimum modifier a raptor can get to their modifiers, such as ability effect and growth speed +#define RAPTOR_INHERIT_MIN_MODIFIER -0.25 +/// Maximum modifier a raptor can get to their modifiers, such as ability effect and growth speed +#define RAPTOR_INHERIT_MAX_MODIFIER 0.25 +/// Genetic drift for raptors, aka min/max value from the cap that stats can receive when breeding +#define RAPTOR_GENETIC_DRIFT 0.2 -///this mob suffers depression +/// This mob suffers depression #define BB_BASIC_DEPRESSED "basic_depressed" -///this mob will care for its young +/// This mob will care for its young #define BB_RAPTOR_MOTHERLY "raptor_motherly" -///this mob will be playful around their owners +/// This mob will be playful around their owners #define BB_RAPTOR_PLAYFUL "raptor_playful" -///this mob will flee combat when it feels threatened +/// This mob will flee combat when it feels threatened #define BB_RAPTOR_COWARD "raptor_coward" -///our raptor baby target we will take care of +/// Our raptor baby target we will take care of #define BB_RAPTOR_BABY "raptor_baby" -///the raptor we will heal up +/// The raptor we will heal up #define BB_INJURED_RAPTOR "injured_raptor" -///the cooldown for next time we eat +/// The cooldown for next time we eat #define BB_RAPTOR_EAT_COOLDOWN "raptor_eat_cooldown" -///our trough target +/// Our trough target #define BB_RAPTOR_TROUGH_TARGET "raptor_trough_target" +/// HP level at which we'll flee from attackers +#define BB_RAPTOR_FLEE_THRESHOLD "raptor_flee_threshold" #define MAX_RAPTOR_POP 64 diff --git a/code/__DEFINES/dcs/signals/signals_food.dm b/code/__DEFINES/dcs/signals/signals_food.dm index 0041076802c..2122f57add8 100644 --- a/code/__DEFINES/dcs/signals/signals_food.dm +++ b/code/__DEFINES/dcs/signals/signals_food.dm @@ -74,6 +74,9 @@ ///Sent to the newly spawned object when it's baked in an oven. #define COMSIG_ITEM_BAKED_RESULT "item_baked_result" +/// From /datum/element/basic_eating/finish_eating() : (mob/living/eater, mob/living/feeder) +#define COMSIG_ITEM_EATEN_BY_BASIC_MOB "item_eaten_by_basic_mob" + ///Called on the result spawned during decomposition: (obj/decomposed) #define COMSIG_OBJ_DECOMPOSITION_RESULT "obj_decomposition_result" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm index 01df92ebcc2..83084005dd5 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm @@ -28,3 +28,8 @@ #define COMSIG_BASICMOB_MUTATED "basicmob_mutated" ///cancel further mutation modifications to the mob such as shiny mutation. #define MUTATED_NO_FURTHER_MUTATIONS (1 << 0) + +/// from /mob/living/basic/raptor/proc/change_growth_stage() : (new_stage, prev_stage) +#define COMSIG_RAPTOR_GROWTH_STAGE_CHANGE "raptor_growth_stage_change" + /// Cancel raptor growth + #define COMPONENT_CANCEL_RAPTOR_GROWTH (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index 67d69dc5b05..fd57e4283da 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -182,3 +182,6 @@ //from base of [/obj/effect/particle_effect/fluid/smoke/proc/smoke_mob]: (seconds_per_tick) #define COMSIG_CARBON_EXPOSED_TO_SMOKE "carbon_exposed_to_smoke" + +/// From /mob/living/carbon/human/proc/update_mob_height() : (old_height) +#define COMSIG_HUMAN_HEIGHT_UPDATED "human_height_updated" 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 e57699a34a9..40d0f1ae3bd 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -365,3 +365,6 @@ #define COMSIG_LIVING_DROP_LOOT "living_drop_loot" /// Prevent loot from being dropped #define COMPONENT_NO_LOOT_DROP (1<<0) + +/// From /mob/living/proc/mob_pickup() : (mob/living/user, obj/item/mob_holder/holder) +#define COMSIG_LIVING_SCOOPED_UP "living_scooped_up" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 8c221d28d1d..1cceb5e624b 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -637,3 +637,9 @@ /// Sent from /obj/machinert/console/camera_advanced/attack_hand() : (mob/eye/camera/remote/new_camera) #define COMSIG_ADVANCED_CAMERA_EYE_CREATED "advanced_camera_eye_created" + +/// Sent from /obj/item/mob_holder/purple_raptor/proc/toggle_wings() : (mob/living/carbon/human/user) +#define COMSIG_RAPTOR_WINGS_OPENED "raptor_wings_opened" + +/// Sent from /obj/item/mob_holder/purple_raptor/proc/toggle_wings() : (mob/living/carbon/human/user) +#define COMSIG_RAPTOR_WINGS_CLOSED "raptor_wings_closed" diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm index dfe731eddfe..bf304813b24 100644 --- a/code/__HELPERS/atoms.dm +++ b/code/__HELPERS/atoms.dm @@ -370,14 +370,14 @@ rough example of the "cone" made by the 3 dirs checked /// Returns an x and y value require to reverse the transformations made to center an oversized icon /atom/proc/get_oversized_icon_offsets() - if (pixel_x == 0 && pixel_y == 0) + if (!base_pixel_x && !base_pixel_y && !base_pixel_w && !base_pixel_z) return list("x" = 0, "y" = 0) var/list/icon_dimensions = get_icon_dimensions(icon) var/icon_width = icon_dimensions["width"] var/icon_height = icon_dimensions["height"] return list( - "x" = icon_width > ICON_SIZE_X && pixel_x != 0 ? (icon_width - ICON_SIZE_X) * 0.5 : 0, - "y" = icon_height > ICON_SIZE_Y && pixel_y != 0 ? (icon_height - ICON_SIZE_Y) * 0.5 : 0, + "x" = icon_width > ICON_SIZE_X && (base_pixel_x || base_pixel_w) ? (icon_width - ICON_SIZE_X) * 0.5 : 0, + "y" = icon_height > ICON_SIZE_Y && (base_pixel_y || base_pixel_z) ? (icon_height - ICON_SIZE_Y) * 0.5 : 0, ) /// Helper for easily adding blood from INSIDE a mob to an atom (NOT blood ON the mob) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index b1210932f47..a93f3d7402a 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -205,8 +205,10 @@ GLOBAL_LIST_INIT(skin_tone_names, list( * @param {icon} icon - The icon file of the cog. Default: 'icons/effects/progressbar.dmi' * * @param {iconstate} iconstate - The icon state of the cog. Default: "Cog" + * + * @param {mob} bar_override - Mob which should see the bar instead of the user */ -/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE, icon = 'icons/effects/progressbar.dmi', iconstate = "cog") +/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE, icon = 'icons/effects/progressbar.dmi', iconstate = "cog", mob/bar_override = null) if(!user) return FALSE if(!isnum(delay)) @@ -240,11 +242,11 @@ GLOBAL_LIST_INIT(skin_tone_names, list( var/datum/cogbar/cog if(progress) - if(user.client) - progbar = new(user, delay, target || user) + if(user.client || bar_override?.client) + progbar = new(bar_override || user, delay, target || user) if(!hidden && delay >= 1 SECONDS) - cog = new(user, icon, iconstate) + cog = new(bar_override || user, icon, iconstate) SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN) diff --git a/code/datums/ai/babies/babies_subtrees.dm b/code/datums/ai/babies/babies_subtrees.dm index 60ca7dc8193..7cadd1e8c55 100644 --- a/code/datums/ai/babies/babies_subtrees.dm +++ b/code/datums/ai/babies/babies_subtrees.dm @@ -3,10 +3,12 @@ */ /datum/ai_planning_subtree/make_babies operational_datums = list(/datum/component/breed) - ///chance to make babies + /// Chance to make babies var/chance = 5 - ///make babies behavior we will use + /// Make babies behavior we will use var/datum/ai_behavior/reproduce_behavior = /datum/ai_behavior/make_babies + /// Find partner behavior we will use + var/datum/ai_behavior/partner_behavior = /datum/ai_behavior/find_partner /datum/ai_planning_subtree/make_babies/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() @@ -25,4 +27,4 @@ return // Find target - controller.queue_behavior(/datum/ai_behavior/find_partner, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES) + controller.queue_behavior(partner_behavior, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm index 07b4845f027..31735f99231 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm @@ -4,21 +4,32 @@ /datum/ai_behavior/find_mom/perform(seconds_per_tick, datum/ai_controller/controller, mom_key, ignore_mom_key, found_mom) var/mob/living_pawn = controller.pawn - var/list/mom_types = controller.blackboard[mom_key] var/list/all_moms = list() + var/list/mom_types = controller.blackboard[mom_key] var/list/ignore_types = controller.blackboard[ignore_mom_key] if(!length(mom_types)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED for(var/mob/mother in oview(look_range, living_pawn)) - if(!is_type_in_list(mother, mom_types)) - continue - if(is_type_in_list(mother, ignore_types)) //so the not permanent baby and the permanent baby subtype dont followed each other - continue - all_moms += mother + if (is_possible_mom(mother, mom_types, ignore_types)) + all_moms += mother if(length(all_moms)) controller.set_blackboard_key(found_mom, pick(all_moms)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + +/datum/ai_behavior/find_mom/proc/is_possible_mom(mob/mother, list/mom_types, list/ignore_types) + if(!is_type_in_list(mother, mom_types)) + return FALSE + if(is_type_in_list(mother, ignore_types)) // so the not permanent baby and the permanent baby subtype dont followed each other + return FALSE + return TRUE + +/datum/ai_behavior/find_mom/raptor/is_possible_mom(mob/mother, list/mom_types, list/ignore_types) + . = ..() + if (!. || !istype(mother, /mob/living/basic/raptor)) + return FALSE + var/mob/living/basic/raptor/raptor = mother + return raptor.growth_stage == RAPTOR_ADULT 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 ef44df82f78..7b35053ff38 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_parent.dm @@ -7,7 +7,7 @@ var/mob/baby = controller.pawn if(QDELETED(target)) - controller.queue_behavior(/datum/ai_behavior/find_mom, BB_FIND_MOM_TYPES, BB_IGNORE_MOM_TYPES, BB_FOUND_MOM) + find_mom(controller) return if(get_dist(target, baby) > minimum_distance) @@ -23,3 +23,9 @@ controller.queue_behavior(/datum/ai_behavior/perform_emote, "dances around their parent!") return SUBTREE_RETURN_FINISH_PLANNING + +/datum/ai_planning_subtree/look_for_adult/proc/find_mom(datum/ai_controller/controller) + controller.queue_behavior(/datum/ai_behavior/find_mom, BB_FIND_MOM_TYPES, BB_IGNORE_MOM_TYPES, BB_FOUND_MOM) + +/datum/ai_planning_subtree/look_for_adult/raptor/find_mom(datum/ai_controller/controller) + controller.queue_behavior(/datum/ai_behavior/find_mom/raptor, BB_FIND_MOM_TYPES, BB_FOUND_MOM) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm index f80ffcc155e..52524852961 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm @@ -1,10 +1,12 @@ /datum/ai_planning_subtree/simple_find_target /// Variable to store target in var/target_key = BB_BASIC_MOB_CURRENT_TARGET + /// Targeting strategy key to use + var/strategy_key = BB_TARGETING_STRATEGY /datum/ai_planning_subtree/simple_find_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) . = ..() - controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, strategy_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) // Prevents finding a target if a human is nearby /datum/ai_planning_subtree/simple_find_target/not_while_observed @@ -21,4 +23,7 @@ /datum/ai_planning_subtree/simple_find_target/increased_range /datum/ai_planning_subtree/simple_find_target/increased_range/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) - controller.queue_behavior(/datum/ai_behavior/find_potential_targets/bigger_range, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/find_potential_targets/bigger_range, target_key, strategy_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + +/datum/ai_planning_subtree/simple_find_target/hunt + strategy_key = BB_HUNT_TARGETING_STRATEGY diff --git a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm index 6848d5d323d..227b4f2fc28 100644 --- a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm +++ b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm @@ -154,3 +154,6 @@ if(!istype(target) || target.has_status_effect(/datum/status_effect/gutted)) return FALSE return ..() + +/datum/targeting_strategy/basic/exact_match + check_factions_exactly = TRUE diff --git a/code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm b/code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm index 41c01ca9158..268b4ca8842 100644 --- a/code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm +++ b/code/datums/ai/basic_mobs/targeting_strategies/dont_target_friends.dm @@ -16,7 +16,7 @@ if(!(target.resistance_flags & INDESTRUCTIBLE)) return TRUE - if(target in living_mob.ai_controller.blackboard[BB_FRIENDS_LIST]) + if(isliving(target) && (target in living_mob.ai_controller.blackboard[BB_FRIENDS_LIST])) return FALSE return ..() diff --git a/code/datums/ai/dog/dog_controller.dm b/code/datums/ai/dog/dog_controller.dm index 0aaaede44cb..cb17546bfbb 100644 --- a/code/datums/ai/dog/dog_controller.dm +++ b/code/datums/ai/dog/dog_controller.dm @@ -25,7 +25,7 @@ // With tongs in hand! BB_TARGET_HELD_ITEM = /obj/item/kitchen/tongs, BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/pet/dog), - BB_BABIES_CHILD_TYPES = list(/mob/living/basic/pet/dog/corgi), + BB_BABIES_CHILD_TYPES = list(/mob/living/basic/pet/dog/corgi/puppy), ) planning_subtrees = list( diff --git a/code/datums/components/breeding.dm b/code/datums/components/breeding.dm index 6c323ed835d..2ecb58d89be 100644 --- a/code/datums/components/breeding.dm +++ b/code/datums/components/breeding.dm @@ -2,17 +2,17 @@ * A component to allow us to breed */ /datum/component/breed - /// additional mobs we can breed with + /// Additional mobs we can breed with var/list/can_breed_with - ///weighted list of the possible baby types + /// Weighted list of the possible baby types var/list/baby_paths - ///time to wait after breeding + /// Time to wait after breeding var/breed_timer - ///AI key we set when we're ready to breed + /// AI key we set when we're ready to breed var/breed_key = BB_BREED_READY - ///are we ready to breed? + /// Are we ready to breed? var/ready_to_breed = TRUE - ///callback after we give birth to the child + /// Callback after we give birth to the child var/datum/callback/post_birth /datum/component/breed/Initialize(list/can_breed_with = list(), breed_timer = 40 SECONDS, baby_paths = list(), post_birth) @@ -44,7 +44,6 @@ REMOVE_TRAIT(parent, TRAIT_MOB_BREEDER, REF(src)) post_birth = null - /datum/component/breed/proc/breed_with_partner(mob/living/source, mob/living/target) SIGNAL_HANDLER diff --git a/code/datums/components/happiness.dm b/code/datums/components/happiness.dm index 95d3b0d1f42..791b9b32b7c 100644 --- a/code/datums/components/happiness.dm +++ b/code/datums/components/happiness.dm @@ -62,7 +62,7 @@ /datum/component/happiness/proc/on_eat(datum/source) SIGNAL_HANDLER - increase_happiness_level(on_eat_change) + change_happiness_level(on_eat_change) /datum/component/happiness/proc/on_clean(mob/living/source) SIGNAL_HANDLER @@ -74,7 +74,7 @@ return NONE COOLDOWN_START(src, groom_cooldown, GROOM_COOLDOWN) - increase_happiness_level(on_groom_change) + change_happiness_level(on_groom_change) return COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP /datum/component/happiness/proc/on_petted(datum/source, mob/living/petter, list/modifiers) @@ -91,42 +91,55 @@ /datum/component/happiness/proc/pet_animal() if(!COOLDOWN_FINISHED(src, pet_cooldown)) return - increase_happiness_level(on_petted_change) + change_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) - if(!HAS_TRAIT(parent, TRAIT_MOB_HIDE_HAPPINESS)) - var/mob/living/living_parent = parent +/datum/component/happiness/proc/change_happiness_level(amount) + var/old_happiness = happiness_level + happiness_level = clamp(happiness_level + amount, 0, maximum_happiness) + var/happiness_percentage = happiness_level / maximum_happiness + var/old_percentage = old_happiness / maximum_happiness + + var/old_threshold = 0 + var/new_threshold = 0 + for(var/check_percentage in callback_percentages) + if (check_percentage <= old_percentage) + old_threshold = check_percentage + if (check_percentage <= happiness_percentage) + new_threshold = check_percentage + + if (old_threshold != new_threshold) + SEND_SIGNAL(parent, COMSIG_MOB_HAPPINESS_CHANGE, happiness_percentage) + happiness_callback?.Invoke(happiness_percentage) + + var/mob/living/living_parent = parent + living_parent.ai_controller?.set_blackboard_key(blackboard_key, happiness_percentage) + + if(!HAS_TRAIT(parent, TRAIT_MOB_HIDE_HAPPINESS) && amount > 0) new /obj/effect/temp_visual/heart(living_parent.loc) living_parent.spin(spintime = 2 SECONDS, speed = 1) - START_PROCESSING(SSprocessing, src) + + if (happiness_level > 0) + START_PROCESSING(SSprocessing, src) /datum/component/happiness/proc/view_happiness(mob/living/source, mob/living/clicker) if(HAS_TRAIT(source, TRAIT_MOB_HIDE_HAPPINESS) || !istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !source.IsReachableBy(clicker)) return var/y_position = source.get_cached_height() + 1 var/obj/effect/overlay/happiness_overlay/hearts = new + hearts.pixel_w -= source.base_pixel_x + source.base_pixel_w hearts.pixel_y = y_position - hearts.set_hearts(happiness_level/maximum_happiness) + 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/mob/living/living_parent = parent var/modifier = living_parent.ai_controller?.blackboard[BB_BASIC_DEPRESSED] ? 2 : 1 - happiness_level = max(0, happiness_level - modifier) + change_happiness_level(-modifier) /obj/effect/overlay/happiness_overlay mouse_opacity = MOUSE_OPACITY_TRANSPARENT diff --git a/code/datums/components/healing_touch.dm b/code/datums/components/healing_touch.dm index 07f04cba01d..bd611558b6e 100644 --- a/code/datums/components/healing_touch.dm +++ b/code/datums/components/healing_touch.dm @@ -45,6 +45,8 @@ var/required_modifier /// Callback to run after healing a mob var/datum/callback/after_healed + /// Callback to run to get a multiplier for our healing value + var/datum/callback/healing_multiplier /datum/component/healing_touch/Initialize( heal_brute = 20, @@ -65,6 +67,7 @@ heal_color = COLOR_HEALING_CYAN, required_modifier = null, datum/callback/after_healed = null, + datum/callback/healing_multiplier = null, ) if (!isliving(parent)) return COMPONENT_INCOMPATIBLE @@ -87,6 +90,7 @@ src.heal_color = heal_color src.required_modifier = required_modifier src.after_healed = after_healed + src.healing_multiplier = healing_multiplier RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_healing)) // Players RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(try_healing)) // NPCs @@ -190,15 +194,21 @@ if (complete_text) healer.visible_message(span_notice("[format_string(complete_text, healer, target)]")) + var/mult = 1 + if (healing_multiplier) + mult = healing_multiplier.Invoke(healer, target) + if (mult == 0) + return + var/healed = target.heal_overall_damage( - brute = heal_brute, - burn = heal_burn, - stamina = heal_stamina, + brute = heal_brute * mult, + burn = heal_burn * mult, + stamina = heal_stamina * mult, required_bodytype = required_bodytype, updating_health = FALSE, ) - healed += target.adjustOxyLoss(-heal_oxy, updating_health = FALSE, required_biotype = valid_biotypes) - healed += target.adjustToxLoss(-heal_tox, updating_health = FALSE, required_biotype = valid_biotypes) + healed += target.adjustOxyLoss(-heal_oxy * mult, updating_health = FALSE, required_biotype = valid_biotypes) + healed += target.adjustToxLoss(-heal_tox * mult, updating_health = FALSE, required_biotype = valid_biotypes) if (healed <= 0) return diff --git a/code/datums/components/proficient_miner.dm b/code/datums/components/proficient_miner.dm index cdc3b65871b..cd9d02b1bd5 100644 --- a/code/datums/components/proficient_miner.dm +++ b/code/datums/components/proficient_miner.dm @@ -1,11 +1,17 @@ /// Component given to mobs that can mine when moving /datum/component/proficient_miner + /// Toolspeed for mining, 0 will cause it to instamine rock + var/mining_speed = 0 + /// Should we pass the do_after visuals to our rider if we are a mob? + var/pass_driver = FALSE /// Last tick when we bumpmined. Prevents diagonal bumpnining being thrice as fast as normal var/last_bumpmine_tick = -1 -/datum/component/proficient_miner/Initialize() +/datum/component/proficient_miner/Initialize(mining_speed = 0, pass_driver = FALSE) if (!ismovable(parent)) return COMPONENT_INCOMPATIBLE + src.mining_speed = mining_speed + src.pass_driver = pass_driver /datum/component/proficient_miner/RegisterWithParent() RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump)) @@ -26,12 +32,37 @@ return var/turf/closed/mineral/mineral_wall = target - if(!istype(mineral_wall, /turf/closed/mineral/gibtonite)) - last_bumpmine_tick = world.time - mineral_wall.gets_drilled(source) + if(istype(mineral_wall, /turf/closed/mineral/gibtonite)) + var/turf/closed/mineral/gibtonite/gibtonite_wall = mineral_wall + if(gibtonite_wall.stage != GIBTONITE_UNSTRUCK) + return + + if(user && mining_speed > 0) + INVOKE_ASYNC(src, PROC_REF(slow_mine), user, target) return - var/turf/closed/mineral/gibtonite/gibtonite_wall = mineral_wall - if(gibtonite_wall.stage == GIBTONITE_UNSTRUCK) - last_bumpmine_tick = world.time - mineral_wall.gets_drilled(source) + last_bumpmine_tick = world.time + mineral_wall.gets_drilled(source) + +/datum/component/proficient_miner/proc/slow_mine(mob/living/user, turf/closed/mineral/mineral_wall) + if(TIMER_COOLDOWN_RUNNING(mineral_wall, REF(user))) //prevents mining turfs in progress + return + + var/mining_delay = mineral_wall.tool_mine_speed * mining_speed + TIMER_COOLDOWN_START(mineral_wall, REF(user), mining_delay) + var/static/list/mine_sounds = list('sound/effects/pickaxe/picaxe1.ogg', 'sound/effects/pickaxe/picaxe2.ogg', 'sound/effects/pickaxe/picaxe3.ogg') + playsound(user, pick(mine_sounds), 50) + + var/mob/living/driver = null + if (pass_driver && length(user.buckled_mobs)) + driver = user.buckled_mobs[1] + + if(!do_after(user, mining_delay, mineral_wall, bar_override = driver)) + TIMER_COOLDOWN_END(mineral_wall, REF(user)) //if we fail we can start again immediately + return + + if (mining_delay > MIN_TOOL_SOUND_DELAY) + playsound(user, pick(mine_sounds), 50) + + if(istype(mineral_wall)) + mineral_wall.gets_drilled(driver || user) diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index 45e2b789ba5..a27e05915a4 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -119,8 +119,7 @@ return COMPONENT_DRIVER_BLOCK_MOVE var/mob/living/living_parent = parent step(living_parent, direction) - var/datum/movespeed_modifier/slowdown = get_cached_movespeed_modifier(living_parent.get_move_intent_slowdown()) - var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown - slowdown?.multiplicative_slowdown : vehicle_move_delay + var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown : vehicle_move_delay if(HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW! switch(HAS_TRAIT(user, TRAIT_PRIMITIVE) ? SANITY_LEVEL_GREAT : user.mob_mood?.sanity_level) if(SANITY_LEVEL_GREAT) @@ -133,6 +132,8 @@ modified_move_delay *= 1.1 if(SANITY_LEVEL_INSANE) modified_move_delay *= 1.2 + if(NSCOMPONENT(direction) && EWCOMPONENT(direction)) + modified_move_delay = FLOOR(modified_move_delay * sqrt(2), world.tick_lag) COOLDOWN_START(src, vehicle_move_cooldown, modified_move_delay) return ..() @@ -675,18 +676,11 @@ force_dismount(buckled_mob, throw_range = 2, gentle = TRUE) /datum/component/riding/creature/raptor/get_rider_offsets_and_layers(pass_index, mob/offsetter) - if(!SSmapping.is_planetary()) - return list( - TEXT_NORTH = list(-1, 7), - TEXT_SOUTH = list(2, 10), - TEXT_EAST = list(0, 7), - TEXT_WEST = list(0, 7), - ) return list( - TEXT_NORTH = list(0, 7), - TEXT_SOUTH = list(0, 10), - TEXT_EAST = list(-3, 9), - TEXT_WEST = list(3, 9), + TEXT_NORTH = list(-1, 7), + TEXT_SOUTH = list(2, 10), + TEXT_EAST = list(0, 7), + TEXT_WEST = list(0, 7), ) /datum/component/riding/creature/raptor/get_parent_offsets_and_layers() @@ -705,3 +699,43 @@ /datum/component/riding/creature/raptor/combat ai_behavior_while_ridden = RIDING_PAUSE_AI_MOVEMENT + +/datum/component/riding/creature/raptor/healer/vehicle_mob_buckle(mob/living/ridden, mob/living/rider, force) + RegisterSignal(rider, COMSIG_MOB_STATCHANGE, PROC_REF(on_buckled_stat_change)) + return ..() + +/datum/component/riding/creature/raptor/healer/vehicle_mob_unbuckle(mob/living/formerly_ridden, mob/living/former_rider, force) + UnregisterSignal(former_rider, COMSIG_MOB_STATCHANGE) + return ..() + +/datum/component/riding/creature/raptor/healer/proc/on_buckled_stat_change(mob/living/source, new_stat, old_stat) + SIGNAL_HANDLER + + var/mob/living/basic/raptor/raptor = source.buckled + if (!istype(raptor)) // what + UnregisterSignal(source, COMSIG_MOB_STATCHANGE) + return + + // Heal the owner and flee whatever might've attacked them + if (new_stat == CONSCIOUS || new_stat == DEAD || old_stat != CONSCIOUS || !raptor.ai_controller) + ADD_TRAIT(raptor, TRAIT_AI_PAUSED, REF(src)) + return + + REMOVE_TRAIT(raptor, TRAIT_AI_PAUSED, REF(src)) + // Rip bozo, but you're not our friend + if (source in raptor.ai_controller.blackboard[BB_FRIENDS_LIST]) + raptor.ai_controller.set_blackboard_key(BB_INJURED_RAPTOR, source) + + for (var/mob/living/possible_hostile in view(5, raptor)) + if (possible_hostile.stat || possible_hostile.invisibility > raptor.see_invisible || source.faction_check_atom(possible_hostile)) + continue + raptor.ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEE_TARGET, possible_hostile) + break + +/datum/component/riding/creature/raptor/small/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(-1, 5), + TEXT_SOUTH = list(2, 8), + TEXT_EAST = list(0, 5), + TEXT_WEST = list(0, 5), + ) diff --git a/code/datums/components/riding/riding_vehicle.dm b/code/datums/components/riding/riding_vehicle.dm index 5f314dd36a6..91e282a14e8 100644 --- a/code/datums/components/riding/riding_vehicle.dm +++ b/code/datums/components/riding/riding_vehicle.dm @@ -97,7 +97,10 @@ return step(movable_parent, direction) - COOLDOWN_START(src, vehicle_move_cooldown, vehicle_move_delay) + var/move_delay = vehicle_move_delay + if(NSCOMPONENT(direction) && EWCOMPONENT(direction)) + move_delay = FLOOR(move_delay * sqrt(2), world.tick_lag) + COOLDOWN_START(src, vehicle_move_cooldown, move_delay) if(QDELETED(src)) return diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index a0f5a2cedef..8b011823e16 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -16,10 +16,12 @@ var/drinking /// If true, we put food in our tummy instead of deleting it var/add_to_contents - /// Types the animal can eat. + /// If true, when add_to_contents would put the item into contents but when used for healing, the item is consumed instead + var/consume_healing + /// Types the animal can eat. Can be an assoc list with amount to heal/damage the mob by var/list/food_types -/datum/element/basic_eating/Attach(datum/target, heal_amt = 0, damage_amount = 0, damage_type = null, drinking = FALSE, add_to_contents = FALSE, food_types = list()) +/datum/element/basic_eating/Attach(datum/target, heal_amt = 0, damage_amount = 0, damage_type = null, drinking = FALSE, add_to_contents = FALSE, consume_healing = TRUE, food_types = list()) . = ..() if(!isliving(target)) @@ -31,6 +33,7 @@ src.damage_type = damage_type src.drinking = drinking src.add_to_contents = add_to_contents + src.consume_healing = consume_healing src.food_types = food_types RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(try_feed)) @@ -66,7 +69,8 @@ /datum/element/basic_eating/proc/try_eating(mob/living/eater, atom/target, mob/living/feeder) if(!is_type_in_list(target, food_types)) return FALSE - if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target, feeder) & COMSIG_MOB_CANCEL_EAT) + var/list/effect_mult = list() + if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target, feeder, effect_mult) & COMSIG_MOB_CANCEL_EAT) return FALSE if(add_to_contents && !ismovable(target)) return FALSE @@ -76,22 +80,44 @@ else eat_verb = pick("bite","chew","nibble","gnaw","gobble","chomp") - if (heal_amt > 0) - var/healed = heal_amt && eater.health < eater.maxHealth - eater.heal_overall_damage(heal_amt) + var/best_match = null + var/best_value = 0 + for (var/food_path in food_types) + // Not an assoc list + if (isnull(food_types[food_path])) + break + if (istype(target, food_path) && (!best_match || ispath(food_path, best_match))) + best_match = food_path + best_value = food_types[food_path] + + var/to_heal = heal_amt + var/to_damage = damage_amount + + if (best_match) + to_heal = 0 + to_damage = 0 + if (best_value > 0) + to_heal = best_value + else if (best_value < 0) + to_damage = -best_value + + for (var/mult in effect_mult) + to_heal *= mult + to_damage *= mult + + if (to_heal > 0) + var/healed = eater.heal_overall_damage(to_heal) eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target][healed ? ", restoring some health" : ""].")) - - else if (damage_amount > 0 && damage_type) - eater.apply_damage(damage_amount, damage_type) - eater.visible_message(span_notice("[eater] [eat_verb]s [target], and seems to hurt itself."), span_notice("You [eat_verb] [target], hurting yourself in the process.")) - + else if (to_damage > 0 && damage_type) + var/damaged = eater.apply_damage(to_damage, damage_type) + eater.visible_message(span_notice("[eater] [eat_verb]s [target][damaged ? ", and seems to hurt [eater.p_themselves()]!" : "."]"), span_notice("You [eat_verb] [target][damaged ? ", hurting yourself in the process" : ""].")) else eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target].")) - finish_eating(eater, target, feeder) + finish_eating(eater, target, feeder, to_heal) return TRUE -/datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target, mob/living/feeder) +/datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target, mob/living/feeder, to_heal) set waitfor = FALSE if(drinking) playsound(eater.loc,'sound/items/drink.ogg', rand(10,50), TRUE) @@ -104,10 +130,12 @@ var/obj/item/stack/food_stack = target final_target = food_stack.split_stack(1) - eater.log_message("has eaten [target], [add_to_contents ? "swallowing it" : "destroying it"]!", LOG_ATTACK) + var/devour = add_to_contents && !to_heal + eater.log_message("has eaten [target], [devour ? "swallowing it" : "destroying it"]!", LOG_ATTACK) - if (add_to_contents) + if (devour) var/atom/movable/movable_target = final_target movable_target.forceMove(eater) else qdel(final_target) + diff --git a/code/datums/elements/raptor_food.dm b/code/datums/elements/raptor_food.dm new file mode 100644 index 00000000000..514509eaaba --- /dev/null +++ b/code/datums/elements/raptor_food.dm @@ -0,0 +1,87 @@ +/// Element which influences raptor children upon owner's consumption as food +/datum/element/raptor_food + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// Flat damage modifier + var/attack_modifier = null + /// Flat health modifier + var/health_modifier = null + /// Speed modifier + var/speed_modifier = null + /// Primary ability stat modifier + /// Multiplier equates to 1 + this + var/ability_modifier = null + /// Growth rate modifier + /// Multiplier equates to 1 + this + var/growth_modifier = null + /// Personality traits the child may get + var/list/personality_traits = null + /// Offspring color probability modifiers + var/list/color_chances = null + +/datum/element/raptor_food/Attach(obj/item/target, attack_modifier, health_modifier, speed_modifier, ability_modifier, growth_modifier, list/personality_traits, list/color_chances) + . = ..() + if (!isitem(target)) + return ELEMENT_INCOMPATIBLE + src.attack_modifier = attack_modifier + src.health_modifier = health_modifier + src.speed_modifier = speed_modifier + src.ability_modifier = ability_modifier + src.growth_modifier = growth_modifier + src.personality_traits = personality_traits + src.color_chances = color_chances + RegisterSignal(target, COMSIG_ITEM_EATEN_BY_BASIC_MOB, PROC_REF(on_eaten)) + RegisterSignal(target, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more)) + +/datum/element/raptor_food/Detach(datum/source, ...) + UnregisterSignal(source, list(COMSIG_ITEM_EATEN_BY_BASIC_MOB, COMSIG_ATOM_EXAMINE_MORE)) + return ..() + +/datum/element/raptor_food/proc/on_examine_more(obj/item/source, mob/examiner, list/examine_list) + SIGNAL_HANDLER + + if (!istype(examiner.buckled, /mob/living/basic/raptor)) + return + + // Just to check for priority + var/strognest_effect = max(attack_modifier, health_modifier, speed_modifier, ability_modifier, growth_modifier, 0) + + // Only personality or color probability effects, or just pure negatives + if (strognest_effect == 0) + examine_list += span_notice("You reckon this would have unique effects on your raptor's offspring if you fed it to them...") + return + + if (strognest_effect == attack_modifier) + examine_list += span_notice("You reckon this would have make your raptor's offspring stronger if you fed it to them...") + else if (strognest_effect == health_modifier) + examine_list += span_notice("You reckon this would have make your raptor's offspring tougher if you fed it to them...") + else if (strognest_effect == speed_modifier) + examine_list += span_notice("You reckon this would have make your raptor's offspring faster if you fed it to them...") + else if (strognest_effect == ability_modifier) + examine_list += span_notice("You reckon this would have make your raptor's offspring more capable if you fed it to them...") + else if (strognest_effect == growth_modifier) + examine_list += span_notice("You reckon this would have make your raptor's offspring grow faster if you fed it to them...") + +/datum/element/raptor_food/proc/on_eaten(obj/item/source, mob/living/eater, mob/living/feeder) + SIGNAL_HANDLER + + if (!istype(eater, /mob/living/basic/raptor)) + return + + var/mob/living/basic/raptor/raptor = eater + var/list/our_food = raptor.inherited_stats.foods_eaten[source.type] + if (our_food) + our_food["amount"] += 1 + return + + raptor.inherited_stats.foods_eaten[source.type] = list( + "amount" = 1, + "attack" = attack_modifier, + "health" = health_modifier, + "speed" = speed_modifier, + "ability" = ability_modifier, + "growth" = growth_modifier, + "traits" = personality_traits?.Copy(), + "color_chances" = color_chances?.Copy(), + ) + diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 51a6cd5e463..4c36ed6394f 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -791,8 +791,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return NONE if(istype(over_object, /atom/movable/screen/inventory/hand)) - if(real_location.loc != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) + if(parent.loc != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) return NONE + if(isitem(parent)) var/obj/item/item_parent = parent if(!item_parent.can_mob_unequip(user)) @@ -803,15 +804,20 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) parent.add_fingerprint(user) return COMPONENT_CANCEL_MOUSEDROP_ONTO - if(ismob(over_object)) - if(over_object != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) + if(over_object == user) + if(!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING)) return NONE + if(isliving(parent) && user.pulling == parent) + var/mob/living/as_living = parent + if(as_living.can_be_held) + return + parent.add_fingerprint(user) INVOKE_ASYNC(src, PROC_REF(open_storage), user) return COMPONENT_CANCEL_MOUSEDROP_ONTO - if(istype(over_object, /atom/movable/screen)) + if(istype(over_object, /atom/movable/screen) || ismob(over_object)) return NONE if(!user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH)) diff --git a/code/game/objects/effects/spawners/random/lavaland_mobs.dm b/code/game/objects/effects/spawners/random/lavaland_mobs.dm index 4c6cf035324..4fa771c7d77 100644 --- a/code/game/objects/effects/spawners/random/lavaland_mobs.dm +++ b/code/game/objects/effects/spawners/random/lavaland_mobs.dm @@ -55,11 +55,41 @@ desc = "Chance to spawn a rare shiny version." icon = 'icons/mob/simple/lavaland/raptor_big.dmi' icon_state = "raptor_red" + pixel_x = -12 loot = list( - /mob/living/basic/raptor/red = 20, - /mob/living/basic/raptor/white = 20, - /mob/living/basic/raptor/purple = 20, - /mob/living/basic/raptor/green = 20, - /mob/living/basic/raptor/yellow = 20, + /mob/living/basic/raptor/red = 25, + /mob/living/basic/raptor/white = 25, + /mob/living/basic/raptor/purple = 25, + /mob/living/basic/raptor/green = 25, + /mob/living/basic/raptor/yellow = 25, + /mob/living/basic/raptor/blue = 25, /mob/living/basic/raptor/black = 1, ) + +/obj/effect/spawner/random/lavaland_mob/raptor/young + name = "random raptor youngling" + icon_state = "young_red" + loot = list( + /mob/living/basic/raptor/young/red = 25, + /mob/living/basic/raptor/young/white = 25, + /mob/living/basic/raptor/young/purple = 25, + /mob/living/basic/raptor/young/green = 25, + /mob/living/basic/raptor/young/yellow = 25, + /mob/living/basic/raptor/young/blue = 25, + /mob/living/basic/raptor/young/black = 1, + ) + +/obj/effect/spawner/random/lavaland_mob/raptor/baby + name = "random raptor chick" + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + icon_state = "baby_red" + pixel_x = 0 + loot = list( + /mob/living/basic/raptor/baby/red = 25, + /mob/living/basic/raptor/baby/white = 25, + /mob/living/basic/raptor/baby/purple = 25, + /mob/living/basic/raptor/baby/green = 25, + /mob/living/basic/raptor/baby/yellow = 25, + /mob/living/basic/raptor/baby/blue = 25, + /mob/living/basic/raptor/baby/black = 1, + ) diff --git a/code/game/objects/items/food/meatslab.dm b/code/game/objects/items/food/meatslab.dm index 01c4c4b8f7a..55fa78c3295 100644 --- a/code/game/objects/items/food/meatslab.dm +++ b/code/game/objects/items/food/meatslab.dm @@ -211,6 +211,10 @@ foodtypes = RAW | MEAT | BUGS blood_decal_type = /obj/effect/decal/cleanable/insectguts +/obj/item/food/meat/slab/bugmeat/Initialize(mapload) + . = ..() + AddElement(/datum/element/raptor_food, health_modifier = 2, color_chances = string_list(list(/datum/raptor_color/green = 2))) + /obj/item/food/meat/slab/mouse name = "mouse meat" desc = "A slab of mouse meat. Best not eat it raw." @@ -337,6 +341,10 @@ tastes = list("meat" = 1) foodtypes = RAW | MEAT | TOXIC +/obj/item/food/meat/slab/goliath/Initialize(mapload) + . = ..() + AddElement(/datum/element/raptor_food, attack_modifier = 0.5, speed_modifier = -0.05, color_chances = string_list(list(/datum/raptor_color/red = 5))) + /obj/item/food/meat/slab/goliath/burn() visible_message(span_notice("[src] finishes cooking!")) new /obj/item/food/meat/steak/goliath(loc) @@ -569,6 +577,10 @@ trash_type = null tastes = list("meat" = 1, "rock" = 1) +/obj/item/food/meat/steak/goliath/Initialize(mapload) + . = ..() + AddElement(/datum/element/raptor_food, attack_modifier = 1, speed_modifier = -0.075, color_chances = string_list(list(/datum/raptor_color/red = 7))) + /obj/item/food/meat/steak/gondola name = "gondola steak" tastes = list("meat" = 1, "tranquility" = 1) diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm index 1082d682c4f..349316a2c8a 100644 --- a/code/game/objects/items/stacks/bscrystal.dm +++ b/code/game/objects/items/stacks/bscrystal.dm @@ -28,6 +28,7 @@ . = ..() pixel_x = rand(-5, 5) pixel_y = rand(-5, 5) + AddElement(/datum/element/raptor_food, ability_modifier = 0.05, attack_modifier = 0.5, color_chances = string_list(list(/datum/raptor_color/black = 1))) /obj/item/stack/ore/bluespace_crystal/get_part_rating() return 1 diff --git a/code/modules/fishing/fish/types/mining.dm b/code/modules/fishing/fish/types/mining.dm index 14e5ce9810b..c5b1f36b87f 100644 --- a/code/modules/fishing/fish/types/mining.dm +++ b/code/modules/fishing/fish/types/mining.dm @@ -205,6 +205,7 @@ sound_on_success = 'sound/items/weapons/parry.ogg',\ effect_on_success = /obj/effect/temp_visual/guardian/phase,\ ) + AddElement(/datum/element/raptor_food, attack_modifier = 1.5, growth_modifier = -0.075) /obj/item/fish/lavaloop/get_fish_taste() return list("chewy fish" = 2) diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index d9e6b3c16c8..7242c24be29 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -230,6 +230,10 @@ wine_power = 50 foodtypes = FRUIT +/obj/item/food/grown/ash_flora/cactus_fruit/Initialize(mapload) + . = ..() + AddElement(/datum/element/raptor_food, growth_modifier = 0.1, ability_modifier = -0.05) + /obj/item/food/grown/ash_flora/seraka name = "seraka cap" desc = "Small, deeply flavourful mushrooms originally native to Tizira." @@ -237,6 +241,10 @@ seed = /obj/item/seeds/lavaland/seraka wine_power = 40 +/obj/item/food/grown/ash_flora/seraka/Initialize(mapload) + . = ..() + AddElement(/datum/element/raptor_food, ability_modifier = 0.1) + /obj/item/food/grown/ash_flora/fireblossom name = "fire blossom" desc = "A flower from a fire blossom." @@ -245,7 +253,12 @@ seed = /obj/item/seeds/lavaland/fireblossom wine_power = 40 -//SEEDS +/obj/item/food/grown/ash_flora/fireblossom/Initialize(mapload) + . = ..() + // Fire flowers make fireproof raptors + AddElement(/datum/element/raptor_food, color_chances = string_list(list(/datum/raptor_color/blue = 5))) + +// SEEDS /obj/item/seeds/lavaland name = "lavaland seeds" diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 159711837e9..621b516254b 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -215,6 +215,10 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ scan_state = "rock_diamond" merge_type = /obj/item/stack/ore/diamond +/obj/item/stack/ore/diamond/Initialize(mapload) + . = ..() + AddElement(/datum/element/raptor_food, speed_modifier = 0.05, health_modifier = -1, color_chances = string_list(list(/datum/raptor_color/yellow = 3))) + /obj/item/stack/ore/diamond/five amount = 5 diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index 10d7ccc442a..d595dc5196b 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -48,6 +48,7 @@ lighting_cutoff_blue = 25 can_be_held = TRUE worn_slot_flags = ITEM_SLOT_HEAD + inhand_holder_type = /obj/item/mob_holder/drone /// `TRUE` if we have picked our visual appearance, `FALSE` otherwise (default) var/picked = FALSE /// Stored drone color, restored when unhacked diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm index 29f5e436d4f..4f0fd61f1ba 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm @@ -80,6 +80,7 @@ if(beegent) reee[beegent.type] = 5 holder.AddComponentFrom(SOURCE_EDIBLE_INNATE, /datum/component/edible, reee, null, BEE_FOODGROUPS, 10, 0, list("bee"), null, 10) + SEND_SIGNAL(src, COMSIG_LIVING_SCOOPED_UP, picker, holder) picker.visible_message(span_warning("[picker] scoops up [src]!")) picker.put_in_hands(holder) diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 174180cec33..2a772d7e262 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -1,12 +1,3 @@ -GLOBAL_LIST_INIT(raptor_growth_paths, list( - /mob/living/basic/raptor/baby_raptor/red = list(RAPTOR_PURPLE, RAPTOR_WHITE), - /mob/living/basic/raptor/baby_raptor/white = list(RAPTOR_GREEN, RAPTOR_PURPLE), - /mob/living/basic/raptor/baby_raptor/purple = list(RAPTOR_GREEN, RAPTOR_WHITE), - /mob/living/basic/raptor/baby_raptor/yellow = list(RAPTOR_GREEN, RAPTOR_RED), - /mob/living/basic/raptor/baby_raptor/green = list(RAPTOR_RED, RAPTOR_YELLOW), - /mob/living/basic/raptor/baby_raptor/blue = list(RAPTOR_RED, RAPTOR_PURPLE) -)) - GLOBAL_LIST_INIT(raptor_inherit_traits, list( BB_BASIC_DEPRESSED = "Depressed", BB_RAPTOR_MOTHERLY = "Motherly", @@ -16,23 +7,25 @@ GLOBAL_LIST_INIT(raptor_inherit_traits, list( GLOBAL_LIST_EMPTY(raptor_population) -#define HAPPINESS_BOOST_DAMPENER 0.3 - -/// Innate raptor offsets -#define RAPTOR_INNATE_SOURCE "raptor_innate" - /mob/living/basic/raptor name = "raptor" desc = "A trusty, powerful steed. Taming it might prove difficult..." icon = 'icons/mob/simple/lavaland/raptor_big.dmi' - speed = 2 + icon_state = "raptor_red" + base_icon_state = "raptor" + pixel_w = -12 + base_pixel_w = -12 + speed = 0.5 mob_biotypes = MOB_ORGANIC|MOB_BEAST - maxHealth = 270 - health = 270 + maxHealth = 200 + health = 200 melee_damage_lower = 10 melee_damage_upper = 15 combat_mode = TRUE mob_size = MOB_SIZE_LARGE + head_icon = 'icons/mob/clothing/back/pets_back.dmi' + worn_slot_flags = ITEM_SLOT_BACK + held_w_class = WEIGHT_CLASS_BULKY unsuitable_atmos_damage = 0 minimum_survivable_temperature = BODYTEMP_COLD_ICEBOX_SAFE maximum_survivable_temperature = INFINITY @@ -45,14 +38,13 @@ GLOBAL_LIST_EMPTY(raptor_population) /obj/item/food/meat/slab/chicken = 4, /obj/item/stack/sheet/bone = 2, ) - ai_controller = /datum/ai_controller/basic_controller/raptor - ///can this mob breed + // AI controller is set by our color + ai_controller = null + /// Can this raptor breed? var/can_breed = TRUE - ///should we change offsets on direction change? + /// 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 + /// Pet commands when we tame the raptor var/static/list/pet_commands = list( /datum/pet_command/breed, /datum/pet_command/idle, @@ -62,24 +54,47 @@ GLOBAL_LIST_EMPTY(raptor_population) /datum/pet_command/follow, /datum/pet_command/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 + /// Can we wear a collar? If so, what is our icon state prefix for it? + var/collar_state = "raptor" + /// Raptor color datum assigned to this raptor, this is a singleton + var/datum/raptor_color/raptor_color = null + /// Are we an adult, youngling or baby? + var/growth_stage = RAPTOR_ADULT + /// Our current growth progress towards the next stage if we're a youngling or a baby + var/growth_progress = 0 + /// Probability of getting progress in the baby phase each second + var/growth_probability = 80 + /// Food types that we can consume + var/static/list/food_types = list( + /obj/item/stack/ore = 0, + /obj/item/food/meat = 15, + /obj/item/food/meat/slab = 25, + /obj/item/food/meat/slab/spider = -15, // Toxic meats + /obj/item/food/meat/slab/xeno = -15, + /obj/item/food/meat/steak = 50, + /obj/item/food/grown/ash_flora = 10, + /obj/item/fish = 15, + /obj/item/organ = 25, + ) + /// Inheritance datum we store our genetic data in + var/datum/raptor_inheritance/inherited_stats = null + /// Current happiness value of the raptor + var/happiness_percentage = 0 - -/mob/living/basic/raptor/Initialize(mapload) +/mob/living/basic/raptor/Initialize(mapload, datum/raptor_color/color_type, datum/raptor_inheritance/passed_stats) . = ..() - if(SSmapping.is_planetary()) - change_offsets = FALSE - icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi' + inherited_stats = passed_stats || new(src) + // First thing as to go before tameable in change_growth_stage() + AddElement(/datum/element/basic_eating, food_types = food_types) + raptor_color = GLOB.raptor_colors[color_type || raptor_color || pick(GLOB.raptor_colors)] + raptor_color.setup_raptor(src) - AddElement(/datum/element/wears_collar) - add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE), INNATE_TRAIT) + if (growth_stage == RAPTOR_ADULT) + raptor_color.setup_adult(src) + else + change_growth_stage(growth_stage, RAPTOR_ADULT) + + add_traits(list(TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE, TRAIT_MINING_AOE_IMMUNE), INNATE_TRAIT) AddElement(\ /datum/element/crusher_loot,\ trophy_type = /obj/item/crusher_trophy/raptor_feather,\ @@ -87,15 +102,364 @@ GLOBAL_LIST_EMPTY(raptor_population) drop_immediately = FALSE,\ ) - if(!mapload) + if (!mapload) GLOB.raptor_population += REF(src) - AddComponent(/datum/component/obeys_commands, pet_commands) + AddComponent(/datum/component/obeys_commands, pet_commands, list(0, -base_pixel_w)) AddElement(\ /datum/element/change_force_on_death,\ move_resist = MOVE_RESIST_DEFAULT,\ ) + RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(on_eat)) + RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(on_pre_eat)) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/ai_flee_while_injured, stop_fleeing_at = 0.5, start_fleeing_below = 0.2) + + if (can_breed) + add_breeding_component() + + // Babies handle it in their change_growth_stage + if (growth_stage != RAPTOR_BABY) + update_blackboard() + + AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW) + RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change)) + RegisterSignal(src, COMSIG_LIVING_SCOOPED_UP, PROC_REF(on_picked_up)) + adjust_offsets(dir) + add_happiness_component() + +/mob/living/basic/raptor/Destroy() + raptor_color = null + GLOB.raptor_population -= REF(src) + return ..() + +/mob/living/basic/raptor/death(gibbed) + . = ..() + GLOB.raptor_population -= REF(src) + +/mob/living/basic/raptor/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE) + if(!iscarbon(target)) + return + return ..() + +/mob/living/basic/raptor/proc/on_dir_change(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + adjust_offsets(new_dir) + +/mob/living/basic/raptor/proc/adjust_offsets(direction) + if (!change_offsets) + return + + switch (direction) + if (NORTH, SOUTH) + add_offsets(RAPTOR_INNATE_SOURCE, w_add = 0, animate = FALSE) + if (EAST, SOUTHEAST, NORTHEAST) + add_offsets(RAPTOR_INNATE_SOURCE, w_add = -8, animate = FALSE) + if (WEST, SOUTHWEST, NORTHWEST) + add_offsets(RAPTOR_INNATE_SOURCE, w_add = 8, animate = FALSE) + +/mob/living/basic/raptor/examine(mob/user) + . = ..() + if (stat == DEAD) + return + + switch (health / maxHealth) + if (0 to 0.2) + . += span_italics(span_bolddanger("[p_They()] [p_are()] gruesomly wounded, barely staying up on [p_their()] feet!")) + if (0.2 to 0.4) + . += span_danger("[p_They()] [p_have()] heavy injuries and open wounds all around [p_their()] body!") + if (0.4 to 0.6) + . += span_warning("[p_They()] [p_are()] noticeably hurt, limping from [p_their()] cuts and bruises.") + if (0.6 to 0.8) + . += span_warning("[p_They()] [p_are()] visibly injured, a few bruises and cuts showing between [p_their()] feathers.") + if (0.8 to 0.999) + . += span_notice("[p_They()] [p_have()] a few minor bruises and scratches.") + +/mob/living/basic/raptor/Life(seconds_per_tick, times_fired) + . = ..() + if (growth_stage != RAPTOR_BABY || HAS_TRAIT(src, TRAIT_STASIS) || stat == DEAD) + return + if (!SPT_PROB(growth_probability * (1 + happiness_percentage * RAPTOR_GROWTH_HAPPINESS_MULTIPLIER), seconds_per_tick)) + return + growth_progress += rand(RAPTOR_BABY_GROWTH_LOWER, RAPTOR_BABY_GROWTH_UPPER) + if (growth_progress >= RAPTOR_GROWTH_REQUIRED) + change_growth_stage(RAPTOR_YOUNG) + growth_progress = 0 + +/mob/living/basic/raptor/early_melee_attack(atom/target, list/modifiers, ignore_cooldown) + . = ..() + if(!.) + return FALSE + if(!istype(target, /obj/structure/ore_container/food_trough/raptor_trough)) + return TRUE + var/obj/ore_food = locate(/obj/item/stack/ore) in target + if(isnull(ore_food)) + balloon_alert(src, "no food!") + else + UnarmedAttack(ore_food, TRUE, modifiers) + return FALSE + +/mob/living/basic/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) + if (!combat_mode && istype(target, /mob/living/basic/raptor)) + var/mob/living/basic/raptor/possible_baby = target + if (possible_baby.growth_stage == RAPTOR_BABY) + return target.attack_hand(src, list(LEFT_CLICK = TRUE)) + return ..() + +/mob/living/basic/raptor/proc/add_breeding_component() + var/static/list/partner_types = typecacheof(list(/mob/living/basic/raptor)) + var/static/list/baby_types = list(/obj/item/food/egg = 1) ///raptor_egg = 1) + AddComponent(\ + /datum/component/breed, \ + can_breed_with = partner_types, \ + baby_paths = baby_types, \ + breed_timer = 3 MINUTES, \ + post_birth = CALLBACK(src, PROC_REF(egg_inherit)), \ + ) + +/mob/living/basic/raptor/proc/add_happiness_component() + var/static/list/percentage_callbacks = list(0, 15, 25, 35, 50, 75, 90, 100) + // Higher happiness cap so it decays slower, about 15 minutes from full to zero + AddComponent(\ + /datum/component/happiness, \ + maximum_happiness = 900, \ + on_petted_change = 50, \ + on_groom_change = 200, \ + on_eat_change = 150, \ + callback_percentages = percentage_callbacks,\ + happiness_callback = CALLBACK(src, PROC_REF(happiness_change)),\ + ) + +/mob/living/basic/raptor/proc/happiness_change(percent_value) + var/attack_boost = round((percent_value - happiness_percentage) * RAPTOR_HAPPINESS_DAMAGE_BOOST, 1) + melee_damage_lower += attack_boost + melee_damage_upper += attack_boost + happiness_percentage = percent_value + +/mob/living/basic/raptor/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked) + // Most colors will redirect shots to their rider as to increase their own survivability, and only tank melee attacks + if (raptor_color.redirect_shots && length(buckled_mobs)) + return buckled_mobs[1].projectile_hit(hitting_projectile, def_zone, piercing_hit, blocked) + return ..() + +/// Pass our genetic data to the egg +/mob/living/basic/raptor/proc/egg_inherit(obj/item/food/egg/raptor_egg/baby_egg, mob/living/basic/raptor/partner) + var/datum/raptor_inheritance/child_genes = new() + child_genes.set_parents(src, partner) + baby_egg.inherited_stats = child_genes + baby_egg.child_color = get_child_color(partner) + // Halve our food modifiers every time we breed + for (var/food_type in inherited_stats.foods_eaten) + var/list/stat_mods = inherited_stats.foods_eaten[food_type] + stat_mods["amount"] /= 2 + stat_mods["attack"] /= 2 + stat_mods["health"] /= 2 + stat_mods["speed"] /= 2 + stat_mods["ability"] /= 2 + stat_mods["growth"] /= 2 + var/list/trait_list = stat_mods["traits"] + for (var/i in 1 to ceil(length(trait_list) / 2)) + trait_list -= pick(trait_list) + + var/list/color_chances = stat_mods["color_chances"] + for (var/datum/raptor_color/color_type as anything in color_chances) + color_chances[color_type] = floor(color_chances[color_type] / 2) + if (!color_chances[color_type]) + color_chances -= color_type + +/mob/living/basic/raptor/proc/get_child_color(mob/living/basic/raptor/partner) + if (raptor_color == partner.raptor_color) + return raptor_color.type + + if (raptor_color.guaranteed_crossbreeds[partner.raptor_color.type]) + return raptor_color.guaranteed_crossbreeds[partner.raptor_color.type] + + // This should be redundant as they should be mirroring eachother, but just in case + if (partner.raptor_color.guaranteed_crossbreeds[raptor_color.type]) + return partner.raptor_color.guaranteed_crossbreeds[raptor_color.type] + + // We've got all the colors in our family tree and aren't rolling a guarantee, bingo + if (length(inherited_stats.parent_colors | partner.inherited_stats.parent_colors | raptor_color.type | partner.raptor_color.type) == length(GLOB.raptor_colors)) + return /datum/raptor_color/black + + var/list/prob_list = list() + for (var/datum/raptor_color/color_type as anything in GLOB.raptor_colors) + prob_list[color_type] = color_type::spawn_chance + + var/amount_eaten = 0 + for (var/food_type in inherited_stats.foods_eaten) + var/list/stat_mods = inherited_stats.foods_eaten[food_type] + amount_eaten += stat_mods["amount"] + + for (var/food_type in inherited_stats.foods_eaten) + var/list/stat_mods = inherited_stats.foods_eaten[food_type] + var/list/color_chances = stat_mods["color_chances"] + for (var/datum/raptor_color/color_type as anything in color_chances) + prob_list[color_type] += floor(color_chances[color_type] * stat_mods["amount"]) + + return pick_weight(prob_list) + +/mob/living/basic/raptor/proc/on_picked_up(mob/living/basic/raptor/source, mob/living/user, obj/item/mob_holder/holder) + SIGNAL_HANDLER + // Our inventory code sucks so we have to do this + holder.icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + holder.icon_state = icon_state + holder.alternate_worn_layer = HEAD_LAYER + holder.pixel_w = 0 + holder.pixel_z = 0 + holder.base_pixel_w = 0 + holder.base_pixel_z = 0 + +/mob/living/basic/raptor/proc/on_pre_eat(datum/source, obj/item/potential_food, list/effect_mult) + SIGNAL_HANDLER + + if (isorgan(potential_food)) + var/obj/item/organ/guts = potential_food + if (!(guts.organ_flags & ORGAN_EDIBLE) || !(guts.organ_flags & ORGAN_ORGANIC)) + return COMSIG_MOB_CANCEL_EAT + + if (happiness_percentage) + effect_mult += happiness_percentage * RAPTOR_GROWTH_HAPPINESS_MULTIPLIER + +/mob/living/basic/raptor/proc/on_eat(datum/source, atom/food, mob/living/feeder) + SIGNAL_HANDLER + + if (!istype(food, /obj/item/food)) + return + + var/obj/item/food/meal = food + var/is_flora = istype(meal, /obj/item/food/grown/ash_flora) + var/is_meat = (meal.foodtypes & (MEAT|GORE)) + // Babies cannot gain growth from eating meat, only plants, but they get some passively + if ((!is_meat || growth_stage == RAPTOR_BABY) && !is_flora) + return + + if (growth_stage == RAPTOR_ADULT) + return + + // Better meals make your raptor grow faster + var/growth_value = meal.crafting_complexity * RAPTOR_MEAL_COMPLEXITY_GROWTH_FACTOR + (is_flora ? RAPTOR_GROWTH_BASE_PLANT : RAPTOR_GROWTH_BASE_MEAT) + growth_progress += growth_value * (1 + inherited_stats.growth_modifier) * (1 + happiness_percentage * RAPTOR_GROWTH_HAPPINESS_MULTIPLIER) + if (growth_progress >= RAPTOR_GROWTH_REQUIRED) + change_growth_stage(growth_stage == RAPTOR_BABY ? RAPTOR_YOUNG : RAPTOR_ADULT) + growth_progress = 0 + +/// Changes the raptor to a new growth stage. Only should be done forwards, or on raptor init as the first thing before everything else +/// Sorry for the monolith, but splitting it up results in even worse looking code with a ton of duplicate calls and assignments +/// And making a *second* datum is just insanity +/mob/living/basic/raptor/proc/change_growth_stage(new_stage, prev_stage = growth_stage) + if (new_stage == prev_stage) + return FALSE + + if (SEND_SIGNAL(src, COMSIG_RAPTOR_GROWTH_STAGE_CHANGE, new_stage, prev_stage) & COMPONENT_CANCEL_RAPTOR_GROWTH) + return FALSE + + growth_stage = new_stage + + // Visuals + switch (new_stage) + if (RAPTOR_BABY) + name = "baby raptor" + desc = "Will this grow into something useful?" + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + base_icon_state = "baby" + base_pixel_w = 0 + mob_size = MOB_SIZE_TINY + if (RAPTOR_YOUNG) + name = "raptor youngling" + desc = "A young raptor that can grow into a robust, trusty steed. Rather naive at such an age, it shouldn't be too hard to tame." + icon = 'icons/mob/simple/lavaland/raptor_big.dmi' + base_icon_state = "young" + base_pixel_w = initial(base_pixel_w) + mob_size = MOB_SIZE_HUMAN + if (RAPTOR_ADULT) + name = "raptor" + desc = initial(desc) + icon = 'icons/mob/simple/lavaland/raptor_big.dmi' + base_icon_state = "raptor" + base_pixel_w = initial(base_pixel_w) + mob_size = initial(mob_size) + + can_be_held = initial(density) + density = initial(density) + move_resist = initial(move_resist) + can_breed = initial(can_breed) + change_offsets = initial(change_offsets) + + if (new_stage == RAPTOR_ADULT) + // Adults need to be tamed with skill rather than snacks + qdel(GetComponent(/datum/component/tameable)) + else // Make us teeny-tiny + can_be_held = TRUE + density = FALSE + can_breed = FALSE + move_resist = MOVE_RESIST_DEFAULT + change_offsets = FALSE + + if (prev_stage == RAPTOR_ADULT) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15, unique = TRUE) + + if (change_offsets) + adjust_offsets(dir) + else + remove_offsets(RAPTOR_INNATE_SOURCE, FALSE) + + if (can_breed) + add_breeding_component() + else + qdel(GetComponent(/datum/component/breed)) + + var/obj/item/mob_holder/holder = null + if (istype(loc, /obj/item/mob_holder)) + holder = loc + if (!can_be_held) + holder.release() + holder = null + + if (collar_state) + RemoveElement(/datum/element/wears_collar, collar_icon = 'icons/mob/simple/lavaland/raptor_big.dmi', collar_icon_state = "[collar_state]_") + + if (new_stage == RAPTOR_BABY) + collar_state = null + var/list/friends = ai_controller?.blackboard[BB_FRIENDS_LIST] + if (friends) + friends = friends.Copy() + QDEL_NULL(ai_controller) + ai_controller = new /datum/ai_controller/basic_controller/baby_raptor(src) + for (var/old_friend in friends) + ai_controller.insert_blackboard_key_lazylist(BB_FRIENDS_LIST, old_friend) + update_blackboard() + held_w_class = WEIGHT_CLASS_SMALL + worn_slot_flags = NONE + holder?.update_weight_class(held_w_class) + else + collar_state = base_icon_state + AddElement(/datum/element/wears_collar, collar_icon = 'icons/mob/simple/lavaland/raptor_big.dmi', collar_icon_state = "[collar_state]_") + if (prev_stage == RAPTOR_BABY) + var/list/friends = ai_controller?.blackboard[BB_FRIENDS_LIST] + if (friends) + friends = friends.Copy() + QDEL_NULL(ai_controller) + ai_controller = new raptor_color.ai_controller(src) + for (var/old_friend in friends) + ai_controller.insert_blackboard_key_lazylist(BB_FRIENDS_LIST, old_friend) + update_blackboard() + held_w_class = WEIGHT_CLASS_BULKY + worn_slot_flags = ITEM_SLOT_BACK + holder?.update_weight_class(held_w_class) + + // And finish the setup on our color's side + switch (new_stage) + if (RAPTOR_BABY) + raptor_color.setup_baby(src) + if (RAPTOR_YOUNG) + raptor_color.setup_young(src) + if (RAPTOR_ADULT) + raptor_color.setup_adult(src) + return TRUE + +/mob/living/basic/raptor/proc/update_blackboard() var/static/list/display_emote = list( BB_EMOTE_SAY = list("Chirp chirp chirp!", "Kweh!", "Bwark!"), BB_EMOTE_SEE = list("shakes its feathers!", "stretches!", "flaps its wings!", "pecks at the ground!"), @@ -110,235 +474,110 @@ GLOBAL_LIST_EMPTY(raptor_population) ) ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, display_emote) - inherited_stats = new - inherit_properties() - var/list/my_food = string_list(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) + var/static/list/preferred_foods = typecacheof(list( + /obj/item/food/meat, + /obj/item/food/grown/ash_flora, + )) - typecacheof(list( // Don't seek out toxic foods + /obj/item/food/meat/slab/spider, + /obj/item/food/meat/slab/xeno, + )) - if(can_breed) - add_breeding_component() + ai_controller.set_blackboard_key(BB_BASIC_FOODS, preferred_foods) - 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/raptor/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE) - if(!iscarbon(target)) - return - return ..() - -/mob/living/basic/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/raptor/proc/on_dir_change(datum/source, old_dir, new_dir) - SIGNAL_HANDLER - adjust_offsets(new_dir) - -/mob/living/basic/raptor/proc/adjust_offsets(direction) - if (!change_offsets) - return - - switch (direction) - if (NORTH) - add_offsets(RAPTOR_INNATE_SOURCE, w_add = -8, animate = FALSE) - if (SOUTH) - add_offsets(RAPTOR_INNATE_SOURCE, w_add = 0, animate = FALSE) - if (EAST, SOUTHEAST, NORTHEAST) - add_offsets(RAPTOR_INNATE_SOURCE, w_add = -20, animate = FALSE) - if (WEST, SOUTHWEST, NORTHWEST) - add_offsets(RAPTOR_INNATE_SOURCE, w_add = -5, animate = FALSE) - -/mob/living/basic/raptor/early_melee_attack(atom/target, list/modifiers, ignore_cooldown) - . = ..() - if(!.) - return FALSE - if(!istype(target, /obj/structure/ore_container/food_trough/raptor_trough)) - return TRUE - - var/obj/ore_food = locate(/obj/item/stack/ore) in target - - if(isnull(ore_food)) - balloon_alert(src, "no food!") - else - UnarmedAttack(ore_food, TRUE, modifiers) - return FALSE - -/mob/living/basic/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) - if(!combat_mode && istype(target, /mob/living/basic/raptor/baby_raptor)) - target.attack_hand(src, list(LEFT_CLICK = TRUE)) - return - return ..() - -/mob/living/basic/raptor/death(gibbed) - . = ..() - GLOB.raptor_population -= REF(src) - -/mob/living/basic/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/raptor/proc/egg_inherit(obj/item/food/egg/raptor_egg/baby_egg, mob/living/basic/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/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) + for(var/trait in GLOB.raptor_inherit_traits) + var/should_inherit = (trait in inherited_stats.personality_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/raptor/proc/add_breeding_component() - var/static/list/partner_types = typecacheof(list(/mob/living/basic/raptor)) - var/static/list/baby_types = list(/obj/item/food/egg/raptor_egg = 1) - AddComponent(\ - /datum/component/breed,\ - can_breed_with = typecacheof(list(/mob/living/basic/raptor)),\ - baby_paths = baby_types,\ - post_birth = CALLBACK(src, PROC_REF(egg_inherit)),\ - breed_timer = 3 MINUTES,\ - ) - - -/mob/living/basic/raptor/Destroy() - QDEL_NULL(inherited_stats) - return ..() +// Raptor types for mappers to use /mob/living/basic/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 - ridable_component = /datum/component/riding/creature/raptor/combat - 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 ruthless aggression." - child_path = /mob/living/basic/raptor/baby_raptor/red + raptor_color = /datum/raptor_color/red /mob/living/basic/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/raptor/baby_raptor/purple - -/mob/living/basic/raptor/purple/Initialize(mapload) - . = ..() - create_storage( - max_specific_storage = WEIGHT_CLASS_NORMAL, - max_total_storage = 10, - storage_type = /datum/storage/raptor_storage, - ) + raptor_color = /datum/raptor_color/purple /mob/living/basic/raptor/green - name = "green raptor" icon_state = "raptor_green" - icon_living = "raptor_green" - icon_dead = "raptor_green_dead" - maxHealth = 400 - health = 400 - 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 punishment than its peers." - child_path = /mob/living/basic/raptor/baby_raptor/green - -/mob/living/basic/raptor/green/Initialize(mapload) - . = ..() - AddComponent(/datum/component/proficient_miner) + raptor_color = /datum/raptor_color/green /mob/living/basic/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/raptor/baby_raptor/white - -/mob/living/basic/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/raptor)),\ - ) + raptor_color = /datum/raptor_color/white /mob/living/basic/raptor/black - name = "black raptor" icon_state = "raptor_black" - icon_living = "raptor_black" - icon_dead = "raptor_black_dead" - maxHealth = 400 - health = 400 - speed = 1.5 - 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/raptor/baby_raptor/black + raptor_color = /datum/raptor_color/black /mob/living/basic/raptor/yellow - name = "yellow raptor" icon_state = "raptor_yellow" - icon_living = "raptor_yellow" - icon_dead = "raptor_yellow_dead" - speed = 1.5 - 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/raptor/baby_raptor/yellow + raptor_color = /datum/raptor_color/yellow /mob/living/basic/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/raptor/baby_raptor/blue + raptor_color = /datum/raptor_color/blue -/mob/living/basic/raptor/blue/Initialize(mapload) - . = ..() - AddComponent(\ - /datum/component/udder,\ - udder_type = /obj/item/udder/raptor,\ - ) +/mob/living/basic/raptor/young + growth_stage = RAPTOR_YOUNG -/datum/storage/raptor_storage - animated = FALSE - insert_on_attack = FALSE +/mob/living/basic/raptor/young/red + icon_state = "young_red" + raptor_color = /datum/raptor_color/red -/datum/storage/raptor_storage/on_mousedropped_onto(datum/source, obj/item/dropping, mob/user) - ..() - return NONE +/mob/living/basic/raptor/young/purple + icon_state = "young_purple" + raptor_color = /datum/raptor_color/purple -#undef HAPPINESS_BOOST_DAMPENER -#undef RAPTOR_INNATE_SOURCE +/mob/living/basic/raptor/young/green + icon_state = "young_green" + raptor_color = /datum/raptor_color/green + +/mob/living/basic/raptor/young/white + icon_state = "young_white" + raptor_color = /datum/raptor_color/white + +/mob/living/basic/raptor/young/black + icon_state = "young_black" + raptor_color = /datum/raptor_color/black + +/mob/living/basic/raptor/young/yellow + icon_state = "young_yellow" + raptor_color = /datum/raptor_color/yellow + +/mob/living/basic/raptor/young/blue + icon_state = "young_blue" + raptor_color = /datum/raptor_color/blue + +/mob/living/basic/raptor/baby + icon = 'icons/mob/simple/lavaland/raptor_baby.dmi' + growth_stage = RAPTOR_BABY + +/mob/living/basic/raptor/baby/red + icon_state = "baby_red" + raptor_color = /datum/raptor_color/red + +/mob/living/basic/raptor/baby/purple + icon_state = "baby_purple" + raptor_color = /datum/raptor_color/purple + +/mob/living/basic/raptor/baby/green + icon_state = "baby_green" + raptor_color = /datum/raptor_color/green + +/mob/living/basic/raptor/baby/white + icon_state = "baby_white" + raptor_color = /datum/raptor_color/white + +/mob/living/basic/raptor/baby/black + icon_state = "baby_black" + raptor_color = /datum/raptor_color/black + +/mob/living/basic/raptor/baby/yellow + icon_state = "baby_yellow" + raptor_color = /datum/raptor_color/yellow + +/mob/living/basic/raptor/baby/blue + icon_state = "baby_blue" + raptor_color = /datum/raptor_color/blue diff --git a/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm deleted file mode 100644 index 06d9fed8470..00000000000 --- a/code/modules/mob/living/basic/lavaland/raptor/baby_raptor.dm +++ /dev/null @@ -1,102 +0,0 @@ -/mob/living/basic/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/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/raptor/baby_raptor/add_happiness_component() - AddComponent(/datum/component/happiness, on_petted_change = 100) - -/mob/living/basic/raptor/baby_raptor/proc/check_grow() - return (stat != DEAD) - -/mob/living/basic/raptor/baby_raptor/proc/ready_to_grow() - var/mob/living/basic/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/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/raptor/black - roll_rate = 10 - -/mob/living/basic/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/raptor/red - -/mob/living/basic/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/raptor/purple - -/mob/living/basic/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/raptor/white - -/mob/living/basic/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/raptor/yellow - -/mob/living/basic/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/raptor/green - -/mob/living/basic/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/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 index a412fceeb12..777a76de1a6 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_behavior.dm @@ -8,7 +8,10 @@ return (source != target && target.health < target.maxHealth) /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 + if (!can_see(source, target, radius) || target.stat == DEAD || !istype(target, /mob/living/basic/raptor)) + return FALSE + var/mob/living/basic/raptor/raptor = target + return raptor.growth_stage == RAPTOR_BABY /datum/ai_behavior/hunt_target/interact_with_target/reset_target_combat_mode_off/care_for_young @@ -21,3 +24,15 @@ /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/find_injured_rider/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, types_to_hunt, hunt_range) + var/mob/living/living_mob = controller.pawn + if (!length(living_mob.buckled_mobs) || !isliving(living_mob.buckled_mobs[1])) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + var/mob/living/rider = living_mob.buckled_mobs[1] + if (rider.stat == CONSCIOUS || rider.stat == DEAD || rider.health >= rider.maxHealth) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED + + controller.set_blackboard_key(hunting_target_key, rider) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED 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 index 27cd4d005f8..2f1353bfc79 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm @@ -9,8 +9,8 @@ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/raptor), - BB_BABIES_CHILD_TYPES = list(/mob/living/basic/raptor/baby_raptor), BB_MAX_CHILDREN = 5, + BB_RAPTOR_FLEE_THRESHOLD = 0.25, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -19,6 +19,7 @@ /datum/ai_planning_subtree/escape_captivity, /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_rider, /datum/ai_planning_subtree/find_and_hunt_target/heal_raptors, /datum/ai_planning_subtree/random_speech/blackboard, /datum/ai_planning_subtree/pet_planning, @@ -26,6 +27,42 @@ /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_food, + /datum/ai_planning_subtree/find_and_hunt_target/care_for_young, + /datum/ai_planning_subtree/make_babies, + /datum/ai_planning_subtree/express_happiness, + /datum/ai_planning_subtree/find_and_hunt_target/play_with_owner/raptor, + ) + +/// Angry raptors with no faction check on retaliation +/datum/ai_controller/basic_controller/raptor/aggressive + blackboard = list( + BB_INTERACTIONS_WITH_OWNER = list( + "pecks", + "nuzzles", + "wags their tail against", + "playfully leans against" + ), + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/exact_match, + BB_HUNT_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/raptor), + BB_MAX_CHILDREN = 5, + BB_RAPTOR_FLEE_THRESHOLD = 0.1, + ) + + planning_subtrees = list( + /datum/ai_planning_subtree/escape_captivity, + /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/hunt, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/find_and_hunt_target/raptor_trough, + /datum/ai_planning_subtree/find_food, /datum/ai_planning_subtree/find_and_hunt_target/care_for_young, /datum/ai_planning_subtree/make_babies, /datum/ai_planning_subtree/express_happiness, @@ -55,7 +92,6 @@ blackboard = list( BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, BB_FIND_MOM_TYPES = list(/mob/living/basic/raptor), - BB_IGNORE_MOM_TYPES = list(/mob/living/basic/raptor/baby_raptor), ) ai_movement = /datum/ai_movement/basic_avoidance @@ -67,5 +103,5 @@ /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, + /datum/ai_planning_subtree/look_for_adult/raptor, ) 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 index 06697d60b94..66f08924023 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm @@ -11,19 +11,41 @@ return return ..() +/datum/ai_planning_subtree/find_and_hunt_target/heal_rider + target_key = BB_INJURED_RAPTOR + hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/heal_raptor + finding_behavior = /datum/ai_behavior/find_injured_rider + hunt_targets = list(/mob/living/carbon/human) + +/datum/ai_planning_subtree/find_and_hunt_target/heal_rider/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_BASIC_MOB_HEALER]) + 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]) + if(controller.blackboard[BB_RAPTOR_COWARD]) + return ..() + + var/mob/living/basic/raptor/raptor = controller.pawn + if (raptor.health <= raptor.maxHealth * controller.blackboard[BB_RAPTOR_FLEE_THRESHOLD]) + return ..() + + if (!length(raptor.buckled_mobs)) return - return ..() + + var/mob/living/buckled_to = raptor.buckled_mobs[1] + // Flee if our owner is badly injured and out + if (buckled_to.stat != CONSCIOUS && buckled_to.stat != DEAD) + return ..() /datum/ai_planning_subtree/find_and_hunt_target/care_for_young target_key = BB_RAPTOR_BABY hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/reset_target_combat_mode_off/care_for_young finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_baby - hunt_targets = list(/mob/living/basic/raptor/baby_raptor) + hunt_targets = list(/mob/living/basic/raptor) hunt_chance = 75 hunt_range = 9 diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_color.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_color.dm new file mode 100644 index 00000000000..486e54519bb --- /dev/null +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_color.dm @@ -0,0 +1,439 @@ +GLOBAL_LIST_INIT(raptor_colors, init_raptor_colors()) + +/proc/init_raptor_colors() + var/list/colors = list() + for (var/datum/raptor_color/color_type as anything in subtypesof(/datum/raptor_color)) + colors[color_type] = new color_type() + return colors + +/datum/raptor_color + /// Color name used for raptor name and icon + var/color = "error" + /// RaptorDex description for the raptor + var/description = "Report this!" + /// Raptor's health + var/health = 220 + /// Raptor's speed + var/speed = 0.5 + // Minimal and maximal damage for the raptor + var/melee_damage_lower = 10 + var/melee_damage_upper = 15 + /// Does this raptor redirect projectile hits onto its rider? + var/redirect_shots = TRUE + /// Rideable component type to assign to the raptor + var/rideable_component = /datum/component/riding/creature/raptor + /// Guaranteed cross-breeding colors, other parent color -> child color + var/guaranteed_crossbreeds = list() + /// Type of AI controller the raptor uses + var/datum/ai_controller/ai_controller = /datum/ai_controller/basic_controller/raptor + /// Chance that a newborn baby raptor will be of this color + var/spawn_chance = 33 + +/// Shared proc, only called once on raptor init for color-specific traits and properties +/datum/raptor_color/proc/setup_raptor(mob/living/basic/raptor/raptor) + if (raptor.ai_controller) + CRASH("setup_raptor called on a raptor ([raptor]) with a present AI controller! This is most likely a result of a second call to setup_raptor.") + raptor.ai_controller = new ai_controller(raptor) + +/datum/raptor_color/proc/setup_adult(mob/living/basic/raptor/raptor) + var/datum/raptor_inheritance/stats = raptor.inherited_stats + var/real_health = health + stats.health_modifier + // If we grow up while damaged, keep the damage percentage the same + raptor.health *= real_health / raptor.maxHealth + raptor.maxHealth = real_health + // -0.33 ~ 0.33 gets rounded to 0 rather than +-0.5 + var/speed_mod = clamp(round(abs(stats.speed_modifier - 0.08), 0.5) * sign(stats.speed_modifier), -0.5, 0.5) + raptor.set_varspeed(speed - speed_mod) + raptor.melee_damage_lower = melee_damage_lower + stats.attack_modifier + raptor.melee_damage_upper = melee_damage_upper + stats.attack_modifier + if (rideable_component) + raptor.AddElement(/datum/element/ridable, rideable_component) + setup_appearance(raptor) + +/datum/raptor_color/proc/setup_young(mob/living/basic/raptor/raptor) + var/datum/raptor_inheritance/stats = raptor.inherited_stats + var/real_health = health + stats.health_modifier + raptor.health *= real_health / 2 / raptor.maxHealth + raptor.maxHealth = real_health / 2 + var/speed_mod = clamp(round(abs(stats.speed_modifier - 0.08), 0.5) * sign(stats.speed_modifier), -0.5, 0.5) + raptor.set_varspeed(speed - speed_mod) + raptor.melee_damage_lower = floor((melee_damage_lower + stats.attack_modifier) / 2) + raptor.melee_damage_upper = floor((melee_damage_upper + stats.attack_modifier) / 2) + setup_appearance(raptor) + +/datum/raptor_color/proc/setup_baby(mob/living/basic/raptor/raptor) + var/datum/raptor_inheritance/stats = raptor.inherited_stats + var/real_health = health + stats.health_modifier + raptor.health *= real_health / 8 / raptor.maxHealth + raptor.maxHealth = real_health / 8 + var/speed_mod = clamp(round(abs(stats.speed_modifier - 0.08), 0.5) * sign(stats.speed_modifier), -0.5, 0.5) + raptor.set_varspeed(speed + 4.5 - speed_mod) + raptor.melee_damage_lower = floor((melee_damage_lower + stats.attack_modifier) / 3) + raptor.melee_damage_upper = floor((melee_damage_upper + stats.attack_modifier) / 3) + setup_appearance(raptor) + +/datum/raptor_color/proc/setup_appearance(mob/living/basic/raptor/raptor) + raptor.name = "[color] [raptor.name]" + raptor.icon_state = "[raptor.base_icon_state]_[color]" + raptor.held_state = "[raptor.base_icon_state]_[color]" + raptor.icon_living = "[raptor.base_icon_state]_[color]" + raptor.icon_dead = "[raptor.base_icon_state]_[color]_dead" + raptor.update_appearance() + +/datum/raptor_color/red + color = "red" + 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 ruthless aggression." + melee_damage_lower = 15 + melee_damage_upper = 20 + health = 300 + rideable_component = /datum/component/riding/creature/raptor/combat + redirect_shots = FALSE + guaranteed_crossbreeds = list( + /datum/raptor_color/green = /datum/raptor_color/yellow, + /datum/raptor_color/blue = /datum/raptor_color/purple, + ) + // Doesn't care for your excuses for friendly fire + ai_controller = /datum/ai_controller/basic_controller/raptor/aggressive + +/datum/raptor_color/purple + color = "purple" + description = "A small, nimble breed, these raptors have been bred as travel companions rather than mounts, capable of storing the owner's possessions and helping them escape from danger unscathed." + health = 140 // smol + rideable_component = /datum/component/riding/creature/raptor/small + guaranteed_crossbreeds = list( + /datum/raptor_color/green = /datum/raptor_color/white, + /datum/raptor_color/yellow = /datum/raptor_color/blue, + ) + +/datum/raptor_color/purple/setup_raptor(mob/living/basic/raptor/raptor) + . = ..() + RegisterSignal(raptor, COMSIG_MOVABLE_PREBUCKLE, PROC_REF(on_pre_buckle)) + raptor.inhand_holder_type = /obj/item/mob_holder/purple_raptor + +/datum/raptor_color/purple/proc/on_pre_buckle(mob/living/basic/raptor/source, mob/living/potential_rider, force = FALSE, ride_check_flags = NONE) + SIGNAL_HANDLER + + if (!ishuman(potential_rider)) + return COMPONENT_BLOCK_BUCKLE + + var/mob/living/carbon/human/rider = potential_rider + if (rider.mob_height > HUMAN_HEIGHT_SHORTEST) + to_chat(rider, span_warning("Your tall stature will crush [source] were you attempt to ride [source.p_them()]!")) + return COMPONENT_BLOCK_BUCKLE + +// Purple raptors never "fully" grow up, and remain usable as backpacks +/datum/raptor_color/purple/setup_adult(mob/living/basic/raptor/raptor) + raptor.base_pixel_w = initial(raptor.base_pixel_w) + raptor.can_be_held = TRUE + raptor.density = FALSE + raptor.move_resist = MOVE_RESIST_DEFAULT + raptor.change_offsets = FALSE + raptor.remove_offsets(RAPTOR_INNATE_SOURCE, FALSE) + raptor.held_w_class = WEIGHT_CLASS_BULKY + . = ..() + // Non-shorties cannot ride these, so we gotta keep em tameable through food + raptor.AddComponent(/datum/component/tameable, food_types = raptor.food_types, tame_chance = 25, bonus_tame_chance = 15, unique = TRUE) + if (raptor.atom_storage) + return + // A bit bigger (23 vs 21) than a backpack at max size, a bit less by default + var/storage_volume = floor(19 * (1 + raptor.inherited_stats.ability_modifier)) + raptor.create_storage( + max_total_storage = storage_volume, + max_slots = storage_volume, + storage_type = /datum/storage/raptor_storage, + ) + +/datum/raptor_color/purple/setup_young(mob/living/basic/raptor/raptor) + . = ..() + if (raptor.atom_storage) + return + var/storage_volume = floor(19 * (1 + raptor.inherited_stats.ability_modifier)) + raptor.create_storage( + max_total_storage = storage_volume, + max_slots = storage_volume, + storage_type = /datum/storage/raptor_storage, + ) + +/obj/item/mob_holder/purple_raptor + /// Wings action granted to whoever is wearing us on their back + var/datum/action/innate/raptor_wings/flight_action = null + + /// Are our wings open? + var/wings_open = FALSE + /// Wings underlay added to the owner, because human rendering code is a mess + var/mutable_appearance/wings_underlay = null + /// Our drift force + var/drift_force = 2 NEWTONS + /// Our stabilizing force + var/stabilizer_force = 4.5 NEWTONS + +/obj/item/mob_holder/purple_raptor/Initialize(mapload, mob/living/held_mob, worn_state, head_icon, lh_icon, rh_icon, worn_slot_flags) + . = ..() + + var/mob/living/basic/raptor/raptor = held_mob + if (raptor.growth_stage == RAPTOR_BABY) + return + + // Create a mirror storage for our raptor when picked up to handle interactions + var/datum/storage/raptor_storage = create_storage( + max_total_storage = held_mob.atom_storage.max_total_storage, + max_slots = held_mob.atom_storage.max_slots, + storage_type = /datum/storage/raptor_storage, + ) + raptor_storage.set_real_location(held_mob) + raptor_storage.insert_on_attack = TRUE + + if (raptor.growth_stage != RAPTOR_ADULT) + return + + flight_action = new(src) + + AddComponent( \ + /datum/component/jetpack, \ + TRUE, \ + drift_force, \ + stabilizer_force, \ + COMSIG_RAPTOR_WINGS_OPENED, \ + COMSIG_RAPTOR_WINGS_CLOSED, \ + null, \ + CALLBACK(src, PROC_REF(can_fly)), \ + CALLBACK(src, PROC_REF(can_fly)), \ + ) + +/obj/item/mob_holder/purple_raptor/Destroy() + if (ishuman(loc) && wings_open) + toggle_wings(loc) + QDEL_NULL(flight_action) + return ..() + +/obj/item/mob_holder/purple_raptor/equipped(mob/user, slot, initial) + . = ..() + if ((slot & ITEM_SLOT_BACK) && ishuman(user) && flight_action) + flight_action.Grant(held_mob) + flight_action.GiveAction(user) + +/obj/item/mob_holder/purple_raptor/dropped(mob/user, silent) + . = ..() + if (wings_open) + toggle_wings(user) + // Removed in Destroy() + if (flight_action) + flight_action.Remove(held_mob) + flight_action.HideFrom(user) + +/obj/item/mob_holder/purple_raptor/proc/on_weight_updated(mob/living/carbon/human/source) + SIGNAL_HANDLER + + if (source.mob_height <= HUMAN_HEIGHT_SHORTEST && !HAS_TRAIT(source, TRAIT_FAT)) + source.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow) + source.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor) + else + source.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor) + source.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow) + +/obj/item/mob_holder/purple_raptor/proc/can_fly() + var/mob/living/carbon/human/user = loc + if (!istype(user) || user.stat || user.body_position == LYING_DOWN || isnull(user.client)) + return FALSE + + if (user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS)) + return FALSE + + var/turf/location = get_turf(user) + if (!istype(location)) + return FALSE + + var/datum/gas_mixture/environment = location.return_air() + if (environment?.return_pressure() >= HAZARD_LOW_PRESSURE + 10) + return TRUE + + to_chat(user, span_warning("The atmosphere is too thin for you to fly!")) + return FALSE + +/obj/item/mob_holder/purple_raptor/proc/toggle_wings(mob/living/carbon/human/user) + // In case something goes wrong + if (!istype(user)) + wings_open = FALSE + worn_icon_state = icon_state + SEND_SIGNAL(src, COMSIG_RAPTOR_WINGS_CLOSED, user) + STOP_PROCESSING(SSprocessing, src) + return + + if (!wings_open && !can_fly()) + return + + wings_open = !wings_open + worn_icon_state = "[icon_state][wings_open ? "_wings_out" : ""]" + user.update_worn_back() + + // Raptors won't have the best of times keeping up tall humans or fatties up in the air + var/struggling = HAS_TRAIT(user, TRAIT_FAT) || user.mob_height > HUMAN_HEIGHT_SHORTEST + if (wings_open) + wings_underlay = user.apply_height_offsets(mutable_appearance(worn_icon, "raptor_purple_wings", -BODY_BEHIND_LAYER, user), UPPER_BODY) + user.add_overlay(wings_underlay) + user.physiology.stun_mod *= 2 + user.add_traits(list(TRAIT_MOVE_FLOATING, TRAIT_IGNORING_GRAVITY, TRAIT_NOGRAV_ALWAYS_DRIFT), REF(src)) + if (struggling) + user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow) + else + user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor) + user.AddElement(/datum/element/forced_gravity, 0) + passtable_on(user, REF(src)) + to_chat(user, span_notice("You begin gently hovering above ground as [held_mob] on your back starts furiously flapping [held_mob.p_their()] wings[struggling ? ", struggling to keep you up in the air" : ""]!")) + user.set_resting(FALSE, TRUE) + user.refresh_gravity() + START_PROCESSING(SSprocessing, src) + RegisterSignals(user, list(COMSIG_HUMAN_HEIGHT_UPDATED, SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)), PROC_REF(on_weight_updated)) + SEND_SIGNAL(src, COMSIG_RAPTOR_WINGS_OPENED, user) + return + + user.cut_overlay(wings_underlay) + QDEL_NULL(wings_underlay) + user.physiology.stun_mod *= 0.5 + user.remove_traits(list(TRAIT_MOVE_FLOATING, TRAIT_IGNORING_GRAVITY, TRAIT_NOGRAV_ALWAYS_DRIFT), REF(src)) + user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow) + user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor) + user.RemoveElement(/datum/element/forced_gravity, 0) + passtable_off(user, REF(src)) + to_chat(user, span_notice("You settle gently back onto the ground[struggling ? ", [held_mob] on your back breathing out a sigh of releif" : ""]...")) + user.refresh_gravity() + STOP_PROCESSING(SSprocessing, src) + UnregisterSignal(user, list(COMSIG_HUMAN_HEIGHT_UPDATED, SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT))) + SEND_SIGNAL(src, COMSIG_RAPTOR_WINGS_CLOSED, user) + +/obj/item/mob_holder/purple_raptor/process(seconds_per_tick) + if (!can_fly()) + toggle_wings(loc) + return PROCESS_KILL + +/datum/storage/raptor_storage + animated = FALSE + insert_on_attack = FALSE // should flip when worn on the back + +/datum/storage/raptor_storage/on_mousedropped_onto(datum/source, obj/item/dropping, mob/user) + return NONE + +/datum/action/innate/raptor_wings + name = "Toggle Flight" + check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_IMMOBILE | AB_CHECK_INCAPACITATED + button_icon = 'icons/mob/actions/actions_animal.dmi' + button_icon_state = "raptor_wings" + +/datum/action/innate/raptor_wings/Activate() + var/obj/item/mob_holder/purple_raptor/holder = target + var/mob/living/carbon/human/user = holder.loc + if (istype(user) && user.get_item_by_slot(ITEM_SLOT_BACK) == holder) + holder.toggle_wings(user) + +/datum/raptor_color/green + color = "green" + 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 punishment than its peers." + health = 400 + // redirect_shots = FALSE // Need to figure out if I want this or not here + guaranteed_crossbreeds = list( + /datum/raptor_color/purple = /datum/raptor_color/white, + /datum/raptor_color/red = /datum/raptor_color/yellow, + ) + +/datum/raptor_color/green/setup_adult(mob/living/basic/raptor/raptor) + . = ..() + var/ability_scale = 1 - INVERSE_LERP(RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER, raptor.inherited_stats.ability_modifier) + var/mining_mod = round(ability_scale * 0.1, 0.025) + if (ability_scale >= 0.75) + mining_mod = 0 + raptor.AddComponent(/datum/component/proficient_miner, mining_mod, TRUE) + +/datum/raptor_color/white + color = "white" + 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, and rescue its owner in case of an emergency." + rideable_component = /datum/component/riding/creature/raptor/healer + guaranteed_crossbreeds = list( + /datum/raptor_color/blue = /datum/raptor_color/green, + /datum/raptor_color/yellow = /datum/raptor_color/red, + ) + +/datum/raptor_color/white/setup_young(mob/living/basic/raptor/raptor) + . = ..() + raptor.AddComponent( \ + /datum/component/healing_touch, \ + heal_brute = melee_damage_upper * 0.75 * (1 + raptor.inherited_stats.ability_modifier), \ + heal_burn = melee_damage_upper * 0.75 * (1 + raptor.inherited_stats.ability_modifier), \ + heal_time = 0, \ + valid_targets_typecache = typecacheof(list(/mob/living/basic/raptor)), \ + ) + +/datum/raptor_color/white/setup_adult(mob/living/basic/raptor/raptor) + . = ..() + qdel(raptor.GetComponent(/datum/component/healing_touch)) + raptor.AddComponent( \ + /datum/component/healing_touch, \ + heal_brute = melee_damage_upper * (1 + raptor.inherited_stats.ability_modifier), \ + heal_burn = melee_damage_upper * (1 + raptor.inherited_stats.ability_modifier), \ + heal_time = 0, \ + valid_targets_typecache = typecacheof(list(/mob/living/basic/raptor, /mob/living/carbon/human)), \ + extra_checks = CALLBACK(src, PROC_REF(heal_checks)), \ + healing_multiplier = CALLBACK(src, PROC_REF(heal_multiplier)), \ + ) + +/datum/raptor_color/white/proc/heal_checks(mob/living/healer, mob/living/target) + if (istype(target, /mob/living/basic/raptor)) + return TRUE + // Only heal raptors, or critted rider + if (target.stat == CONSCIOUS || target.stat == DEAD) + return FALSE + return target.buckled == healer + +/datum/raptor_color/white/proc/heal_multiplier(mob/living/healer, mob/living/target) + if (istype(target, /mob/living/basic/raptor)) + return 1 + // The healing is slow so this is fine + return 0.67 + +/datum/raptor_color/yellow + color = "yellow" + 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." + speed = 0 + guaranteed_crossbreeds = list( + /datum/raptor_color/purple = /datum/raptor_color/blue, + /datum/raptor_color/white = /datum/raptor_color/red, + ) + +/datum/raptor_color/blue + color = "blue" + description = "Covered in tough, lava-resistant feathers with thick insulated fur underneath, this breed is capable of marching through lava and fire alike." + guaranteed_crossbreeds = list( + /datum/raptor_color/red = /datum/raptor_color/purple, + /datum/raptor_color/white = /datum/raptor_color/green, + ) + +/datum/raptor_color/blue/setup_raptor(mob/living/basic/raptor/raptor) + . = ..() + raptor.add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_NOFIRE_SPREAD), INNATE_TRAIT) + +/datum/raptor_color/black + color = "black" + 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." + health = 400 + speed = 0 + melee_damage_lower = 20 + melee_damage_upper = 25 + redirect_shots = FALSE + rideable_component = /datum/component/riding/creature/raptor/combat + ai_controller = /datum/ai_controller/basic_controller/raptor/aggressive + spawn_chance = 1 // 1 in 150 chance without modifiers + +/datum/raptor_color/black/setup_raptor(mob/living/basic/raptor/raptor) + . = ..() + raptor.add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_NOFIRE_SPREAD), INNATE_TRAIT) + +/datum/raptor_color/black/setup_adult(mob/living/basic/raptor/raptor) + . = ..() + // Slightly worse than greens at this + var/ability_scale = 1 - INVERSE_LERP(RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER, raptor.inherited_stats.ability_modifier) + var/mining_mod = round(ability_scale * 0.2, 0.025) + if (ability_scale >= 0.8) + mining_mod = 0 + raptor.AddComponent(/datum/component/proficient_miner, mining_mod, TRUE) diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm index e7224e29d87..90595dd942a 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_dex.dm @@ -1,62 +1,64 @@ /obj/item/raptor_dex - name = "raptor Dex" + name = "RaptorDex" 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 + /// Raptor scan data we have stored + var/list/scan_data = list("raptor_scan" = FALSE) /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/raptor/my_raptor = raptor.resolve() - - data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, frame = 1)) - 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 = ICON_SIZE_Y * 0.5 - data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE)) - 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/ui_data(mob/user) + return scan_data /obj/item/raptor_dex/interact_with_atom(atom/attacked_atom, mob/living/user) if(!istype(attacked_atom, /mob/living/basic/raptor)) return NONE - raptor = WEAKREF(attacked_atom) + var/mob/living/basic/raptor/my_raptor = attacked_atom + var/datum/movespeed_modifier/intent_mod = my_raptor.get_move_intent_slowdown() + + scan_data = list() + scan_data["raptor_scan"] = TRUE + scan_data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, dir = SOUTH, frame = 1)) + scan_data["raptor_attack"] = my_raptor.melee_damage_lower + scan_data["raptor_health"] = my_raptor.health + scan_data["raptor_max_health"] = my_raptor.maxHealth + scan_data["raptor_speed"] = my_raptor.speed + intent_mod?.multiplicative_slowdown + scan_data["raptor_color"] = my_raptor.name + scan_data["raptor_gender"] = my_raptor.gender + scan_data["raptor_description"] = my_raptor.raptor_color.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 = ICON_SIZE_Y * 0.5 + scan_data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE)) + qdel(display) + + var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats + if(!isnull(inherit)) + scan_data["inherited_attack"] = inherit.attack_modifier + scan_data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK + scan_data["inherited_health"] = inherit.health_modifier + scan_data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH + scan_data["inherited_speed"] = inherit.speed_modifier + scan_data["inherited_speed_max"] = RAPTOR_INHERIT_MAX_SPEED + scan_data["inherited_ability"] = inherit.ability_modifier + scan_data["inherited_ability_max"] = RAPTOR_INHERIT_MAX_MODIFIER + scan_data["inherited_growth"] = inherit.growth_modifier + scan_data["inherited_growth_max"] = RAPTOR_INHERIT_MAX_MODIFIER + + scan_data["inherited_traits"] = list() + for(var/index in inherit.personality_traits) + scan_data["inherited_traits"] += GLOB.raptor_inherit_traits[index] + playsound(src, 'sound/mobs/non-humanoids/orbie/orbie_send_out.ogg', 20) - balloon_alert(user, "scanned") + balloon_alert(my_raptor, "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 index 29e6a7b9c28..698dafac6c2 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_egg.dm @@ -1,58 +1,52 @@ /obj/item/food/egg/raptor_egg + name = "raptor egg" + desc = "An uneven egg with a rough, thick shell." 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 + resistance_flags = LAVA_PROOF|FIRE_PROOF + /// Color typepath of the child we spawn + var/datum/raptor_color/child_color = /datum/raptor_color + /// Inheritance data to pass onto the child + var/datum/raptor_inheritance/inherited_stats = null + /// Current growth progress + var/growth_progress = 0 + /// Minimum growth progress per second + var/min_growth_rate = 0.5 + /// Maximum growth progress per second + var/max_growth_rate = 1 /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/raptor/dad, mob/living/basic/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_subtypesof = list() - var/static/list/all_subtypes = subtypesof(/mob/living/basic/raptor/baby_raptor) - for(var/path in all_subtypes) - var/mob/living/basic/raptor/baby_raptor/raptor_path = path - if(!prob(initial(raptor_path.roll_rate))) - continue - valid_subtypesof += raptor_path - add_growth_component(pick(valid_subtypesof)) - -/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/raptor/baby) - if(!istype(baby)) - return - QDEL_NULL(baby.inherited_stats) - baby.inherited_stats = inherited_stats - inherited_stats = null + START_PROCESSING(SSobj, src) /obj/item/food/egg/raptor_egg/Destroy() + STOP_PROCESSING(SSobj, src) QDEL_NULL(inherited_stats) return ..() + +/obj/item/food/egg/raptor_egg/examine(mob/user) + . = ..() + if (growth_progress >= RAPTOR_EGG_GROWTH_PROGRESS) + . += span_boldnotice("Its noticeably shaking, ready to hatch!") + +/obj/item/food/egg/raptor_egg/process(seconds_per_tick) + if (!isturf(loc) || length(GLOB.raptor_population) >= MAX_RAPTOR_POP) + return + + var/growth_value = rand(min_growth_rate, max_growth_rate) * seconds_per_tick * (1 + inherited_stats.growth_modifier) + // Slower growth off hot lavaland + if (!SSmapping.level_trait(z, ZTRAIT_ASHSTORM)) + growth_value *= 0.75 + // Faster growth in hot hot lava + if (islava(loc)) + growth_value *= 1.5 + + growth_progress += growth_value + // Don't hatch on lava though, or the chick will die instantly + if (growth_progress < RAPTOR_EGG_GROWTH_PROGRESS || islava(loc)) + return + + visible_message(span_notice("[src] hatches with a quiet cracking sound.")) + new /mob/living/basic/raptor(loc, child_color, inherited_stats) + inherited_stats = null + qdel(src) diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm index 4f72e37a4cf..8c3e0ec8b3e 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_inheritance.dm @@ -1,31 +1,97 @@ -#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 + /// Inherited parent personality traits + var/list/personality_traits = list() + /// Flat damage modifier + var/attack_modifier = 0 + /// Flat health modifier + var/health_modifier = 0 + /// Speed modifier, not randomized by default + var/speed_modifier = 0 + /// Primary ability stat modifier, not randomized by default + /// Multiplier equates to 1 + this + var/ability_modifier = 0 + /// Growth rate modifier, not randomized by default + /// Multiplier equates to 1 + this + var/growth_modifier = 0 + /// Foods eaten that can affect our child's stats -> stats they modify + var/list/foods_eaten = list() + /// List of all colors in our family tree + var/list/parent_colors = list() -/datum/raptor_inheritance/New(datum/raptor_inheritance/father, datum/raptor_inheritance/mother) +// Owner being set will randomize the stats as it means we're spawned not via an egg +// otherwise wait for set_parents call to inherit genetics +/datum/raptor_inheritance/New(mob/living/basic/raptor/owner) . = ..() - 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)) + if (!owner) 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 + attack_modifier = rand(RAPTOR_INHERIT_MIN_ATTACK * 0.5, RAPTOR_INHERIT_MAX_ATTACK * 0.5) + health_modifier = rand(RAPTOR_INHERIT_MIN_HEALTH * 0.5, RAPTOR_INHERIT_MAX_HEALTH * 0.5) + var/list/traits_to_pick = GLOB.raptor_inherit_traits.Copy() + for(var/i in 1 to rand(1, RAPTOR_TRAIT_INHERIT_AMOUNT)) + personality_traits += pick_n_take(traits_to_pick) + +/datum/raptor_inheritance/proc/set_parents(mob/living/basic/raptor/mother, mob/living/basic/raptor/father) + var/datum/raptor_inheritance/mom_stats = mother.inherited_stats + var/datum/raptor_inheritance/dad_stats = father.inherited_stats + + parent_colors = mom_stats.parent_colors | dad_stats.parent_colors | mother.raptor_color.type | father.raptor_color.type + + var/list/traits_to_pick = list() + // + so shared traits have double the weight + for (var/raptor_trait in mom_stats.personality_traits + dad_stats.personality_traits) + if (!traits_to_pick[raptor_trait]) + traits_to_pick[raptor_trait] = 0 + traits_to_pick[raptor_trait] += 1 + + var/attack_mod = 0 + var/health_mod = 0 + var/speed_mod = 0 + var/ability_mod = 0 + var/growth_mod = 0 + var/amount_eaten = 0 + + for (var/food_type in foods_eaten) + var/list/stat_mods = foods_eaten[food_type] + amount_eaten += stat_mods["amount"] + + for (var/food_type in foods_eaten) + var/list/stat_mods = foods_eaten[food_type] + // First multiply stats themselves, then multiply to get a proportion of this food from amount_eaten + var/amount = stat_mods["amount"] ** 2 + // Eating other foods reduces the effects of a specific one + attack_mod += stat_mods["attack"] / amount_eaten * amount + health_mod += stat_mods["health"] / amount_eaten * amount + speed_mod += stat_mods["speed"] / amount_eaten * amount + ability_mod += stat_mods["ability"] / amount_eaten * amount + growth_mod += stat_mods["growth"] / amount_eaten * amount + var/list/trait_list = stat_mods["traits"] + for (var/raptor_trait in trait_list) + if (!traits_to_pick[raptor_trait]) + traits_to_pick[raptor_trait] = 0 + traits_to_pick[raptor_trait] += trait_list[raptor_trait] * stat_mods["amount"] + + // If we don't clamp these, RNG and drift can get wildly out of control and result in polar values + // and this way we at most get twice the minimum/maximum value, so at least half the rand spread is within the clamp values + attack_mod = clamp(attack_mod, RAPTOR_INHERIT_MIN_ATTACK, RAPTOR_INHERIT_MAX_ATTACK) + health_mod = clamp(health_mod, RAPTOR_INHERIT_MIN_HEALTH, RAPTOR_INHERIT_MAX_HEALTH) + speed_mod = clamp(speed_mod, RAPTOR_INHERIT_MIN_SPEED, RAPTOR_INHERIT_MAX_SPEED) + ability_mod = clamp(ability_mod, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER) + growth_mod = clamp(growth_mod, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER) + + attack_modifier = rand((min(mom_stats.attack_modifier, dad_stats.attack_modifier) + min(0, attack_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_ATTACK, (max(mom_stats.attack_modifier, dad_stats.attack_modifier) + max(0, attack_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_ATTACK) + health_modifier = rand((min(mom_stats.health_modifier, dad_stats.health_modifier) + min(0, health_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_HEALTH, (max(mom_stats.health_modifier, dad_stats.health_modifier) + max(0, health_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_HEALTH) + speed_modifier = rand((min(mom_stats.speed_modifier, dad_stats.speed_modifier) + min(0, speed_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_SPEED, (max(mom_stats.speed_modifier, dad_stats.speed_modifier) + max(0, speed_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_SPEED) + ability_modifier = rand((min(mom_stats.ability_modifier, dad_stats.ability_modifier) + min(0, ability_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_MODIFIER, (max(mom_stats.ability_modifier, dad_stats.ability_modifier) + max(0, ability_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_MODIFIER) + growth_modifier = rand((min(mom_stats.growth_modifier, dad_stats.growth_modifier) + min(0, growth_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_MODIFIER, (max(mom_stats.growth_modifier, dad_stats.growth_modifier) + max(0, growth_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_MODIFIER) + + for(var/i in 1 to min(length(traits_to_pick), RAPTOR_TRAIT_INHERIT_AMOUNT)) + var/chosen_trait = pick_weight(traits_to_pick) + traits_to_pick -= chosen_trait + personality_traits += chosen_trait + + attack_modifier = clamp(attack_modifier, RAPTOR_INHERIT_MIN_ATTACK, RAPTOR_INHERIT_MAX_ATTACK) + health_modifier = clamp(health_modifier, RAPTOR_INHERIT_MIN_HEALTH, RAPTOR_INHERIT_MAX_HEALTH) + speed_modifier = clamp(speed_modifier, RAPTOR_INHERIT_MIN_SPEED, RAPTOR_INHERIT_MAX_SPEED) + ability_modifier = clamp(ability_modifier, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER) + growth_modifier = clamp(growth_modifier, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER) diff --git a/code/modules/mob/living/basic/snails/snail.dm b/code/modules/mob/living/basic/snails/snail.dm index 0cbdaf9f113..5c8ea912ee4 100644 --- a/code/modules/mob/living/basic/snails/snail.dm +++ b/code/modules/mob/living/basic/snails/snail.dm @@ -81,6 +81,7 @@ /mob/living/basic/snail/mob_pickup(mob/living/user) var/obj/item/mob_holder/snail/holder = new(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags) + SEND_SIGNAL(src, COMSIG_LIVING_SCOOPED_UP, user, holder) var/display_message = "[user] [HAS_TRAIT(src, TRAIT_MOVE_FLOATING) ? "scoops up [src]" : "peels [src] off the ground"]!" user.visible_message(span_warning(display_message)) user.put_in_hands(holder) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 9406dda88d4..f11eece642a 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -280,6 +280,7 @@ mob_height = dna?.species?.update_species_heights(src) || base_mob_height if(old_height != mob_height) regenerate_icons() + SEND_SIGNAL(src, COMSIG_HUMAN_HEIGHT_UPDATED, old_height) /** * Makes a full copy of src and returns it. diff --git a/code/modules/mob/living/inhand_holder.dm b/code/modules/mob/living/inhand_holder.dm index f7f76700d53..509d4e4f004 100644 --- a/code/modules/mob/living/inhand_holder.dm +++ b/code/modules/mob/living/inhand_holder.dm @@ -8,8 +8,6 @@ slot_flags = NONE /// Mob inside of us var/mob/living/held_mob - /// True if we've started being destroyed - var/destroying = FALSE lefthand_file = 'icons/mob/inhands/clothing/hats_lefthand.dmi' righthand_file = 'icons/mob/inhands/clothing/hats_righthand.dmi' body_parts_covered = HEAD @@ -31,9 +29,9 @@ return ..() /obj/item/mob_holder/Destroy() - destroying = TRUE - if(held_mob) + if(held_mob?.loc == src) release() + held_mob = null return ..() /obj/item/mob_holder/proc/insert_mob(mob/living/new_prisoner) @@ -78,11 +76,10 @@ /obj/item/mob_holder/proc/release(display_messages = TRUE) if(!held_mob) - if(!destroying) + if(!QDELETED(src)) qdel(src) return FALSE var/mob/living/released_mob = held_mob - held_mob = null // stops the held mob from being release()'d twice. if(isliving(loc)) var/mob/living/captor = loc if(display_messages) @@ -93,7 +90,7 @@ released_mob.setDir(SOUTH) if(display_messages) released_mob.visible_message(span_warning("[released_mob] uncurls!")) - if(!destroying) + if(!QDELETED(src)) qdel(src) return TRUE @@ -159,3 +156,6 @@ if(. || !held_mob) // Another interaction was performed return tool.melee_attack_chain(user, held_mob, modifiers) //Interact with the mob with our tool + +/obj/item/mob_holder/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return TRUE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 7938b8f5447..9d86aa3eb06 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1965,7 +1965,8 @@ GLOBAL_LIST_EMPTY(fire_appearances) return ..() /mob/living/proc/mob_pickup(mob/living/user) - var/obj/item/mob_holder/holder = new(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags) + var/obj/item/mob_holder/holder = new inhand_holder_type(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags) + SEND_SIGNAL(src, COMSIG_LIVING_SCOOPED_UP, user, holder) user.visible_message(span_warning("[user] scoops up [src]!")) user.put_in_hands(holder) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index cc8934a755a..8b85214bbdd 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -204,6 +204,8 @@ var/icon/head_icon = 'icons/mob/clothing/head/pets_head.dmi' /// icon_state for holding mobs. var/held_state = "" + /// Typepath of the holder created when we're picked up + var/inhand_holder_type = /obj/item/mob_holder ///If combat mode is on or not var/combat_mode = FALSE diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index 43341cfbc16..8f046748514 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -259,6 +259,7 @@ greyscale_colors = "#927444#8b4c31#4c202d" starting_programs = list( /datum/computer_file/program/skill_tracker, + /datum/computer_file/program/raptordex, ) /obj/item/modular_computer/pda/bitrunner diff --git a/code/modules/modular_computers/file_system/programs/raptordex.dm b/code/modules/modular_computers/file_system/programs/raptordex.dm new file mode 100644 index 00000000000..b54e847ce1f --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/raptordex.dm @@ -0,0 +1,61 @@ +/datum/computer_file/program/raptordex + filename = "raptordex" + filedesc = "RaptorDex" + downloader_category = PROGRAM_CATEGORY_DEVICE + program_open_overlay = "bountyboard" + extended_desc = "Scan and analyze raptor genes." + size = 2 + tgui_id = "RaptorDex" + program_icon = "crow" + can_run_on_flags = PROGRAM_PDA + /// Raptor scan data we have stored + var/list/scan_data = list("raptor_scan" = FALSE) + +/datum/computer_file/program/raptordex/tap(atom/tapped_atom, mob/living/user, list/modifiers) + if(!istype(tapped_atom, /mob/living/basic/raptor)) + return FALSE + + var/mob/living/basic/raptor/my_raptor = tapped_atom + var/datum/movespeed_modifier/intent_mod = my_raptor.get_move_intent_slowdown() + + scan_data = list() + scan_data["raptor_scan"] = TRUE + scan_data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, dir = SOUTH, frame = 1)) + scan_data["raptor_attack"] = my_raptor.melee_damage_lower + scan_data["raptor_health"] = my_raptor.health + scan_data["raptor_max_health"] = my_raptor.maxHealth + scan_data["raptor_speed"] = my_raptor.speed + intent_mod?.multiplicative_slowdown + scan_data["raptor_color"] = my_raptor.name + scan_data["raptor_gender"] = my_raptor.gender + scan_data["raptor_description"] = my_raptor.raptor_color.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 = ICON_SIZE_Y * 0.5 + scan_data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE)) + qdel(display) + + var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats + if(!isnull(inherit)) + scan_data["inherited_attack"] = inherit.attack_modifier + scan_data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK + scan_data["inherited_health"] = inherit.health_modifier + scan_data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH + scan_data["inherited_speed"] = inherit.speed_modifier + scan_data["inherited_speed_max"] = RAPTOR_INHERIT_MAX_SPEED + scan_data["inherited_ability"] = inherit.ability_modifier + scan_data["inherited_ability_max"] = RAPTOR_INHERIT_MAX_MODIFIER + scan_data["inherited_growth"] = inherit.growth_modifier + scan_data["inherited_growth_max"] = RAPTOR_INHERIT_MAX_MODIFIER + + scan_data["inherited_traits"] = list() + for(var/index in inherit.personality_traits) + scan_data["inherited_traits"] += GLOB.raptor_inherit_traits[index] + + playsound(computer, 'sound/mobs/non-humanoids/orbie/orbie_send_out.ogg', 20) + my_raptor.balloon_alert(user, "scanned") + return TRUE + +/datum/computer_file/program/raptordex/ui_data(mob/user) + return scan_data diff --git a/code/modules/movespeed/modifiers/items.dm b/code/modules/movespeed/modifiers/items.dm index 1f988f50c57..a94dc9ade5e 100644 --- a/code/modules/movespeed/modifiers/items.dm +++ b/code/modules/movespeed/modifiers/items.dm @@ -11,6 +11,12 @@ /datum/movespeed_modifier/jetpack/wings multiplicative_slowdown = -0.3 +/datum/movespeed_modifier/jetpack/raptor + multiplicative_slowdown = 0.2 + +/datum/movespeed_modifier/jetpack/raptor/slow + multiplicative_slowdown = 1 + /datum/movespeed_modifier/die_of_fate multiplicative_slowdown = 1 diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index 8a3adfde01c..f3107b31af3 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -163,10 +163,10 @@ variable = TRUE /datum/movespeed_modifier/goliath_mount - multiplicative_slowdown = -26 + multiplicative_slowdown = -27.5 /datum/movespeed_modifier/goldgrub_mount - multiplicative_slowdown = -3 + multiplicative_slowdown = -4.5 /datum/movespeed_modifier/settler multiplicative_slowdown = 0.2 diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi index b0b58b463f545bced676fe73f1db88d82cc42d2b..fa6d350e7b47f952f1491e5eeaf470a8fd4fa19e 100644 GIT binary patch literal 16962 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 R)ENK(002ovPDHLkV1jmEOfUcd literal 20357 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 L-cu=6G7J1as2VPs literal 0 HcmV?d00001 diff --git a/icons/mob/simple/lavaland/raptor_baby.dmi b/icons/mob/simple/lavaland/raptor_baby.dmi index f892a3cb84fab0f2c13a79b124dfcd2862c88299..861ea55efd4208c9a2a7ca800a443b36ad1516d9 100644 GIT binary patch literal 6837 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 literal 1445 zcmZ8fdoJ{bhIBSft_JCWt zoJ-Bo(>J$0WPx$>y#!>{(&@)geg*c~44)FTQDBadF~!LVW1#PzV|(&Zyq&lH;q$3B zwe|X@j)`g-9WX=&CZHxYarjQ*Y)`F}N7N$48*Nd`B>SRIL68em;akhIbicr4)P*Em zVpM!`R9q|sl18W~^HLr#|2dDrBN?+o2$z_AEyEy4gCI+QG!O~50 zEX#jBR~Eu|{QWV32FYMq&mBQOwU4MjJu^D^rN3IHrG$NB##1e+7=Mz+fDdZ#jFYgj~#B)Vkfr8AKPDg~zXvecvuKd?>641&-e zC`VR_<;Gi{6O-iU;Ks+;p^8CLN8Bx~rOmf-PRj2_(zK5BLLjnQ?x+)fX$0O~R^ptw zI%wMqv*p7-mGy9OdK4RW z+}VHf)5b!CID&li1^5CLO;P4^U)h+1FYroxlONG6T;$g_MZjJa_0cX>r_|iN&I~!| zT4|Wn25lrYw+wIBj>+hzU)lM@IY?_1x^H)<1>IZ*cS7>eqlbCx##|Mj7E8>QLm<`1 zW%w66#_t_RHtF~s6uK%RkeZ4T?Y70r(TzB@*gyu4$ir4{SBta>4L-0*79XxCkW`wK z3$2yxpIC=VFGKf{43?yl_BXG|GR%%6mA}R4m^Fxpz?Rf5O{JOqZ6|1c3Qsdu2hQyX zQ>qJq;aFsq_8wu4e?!X~Zk?)zjftV>97CYdj0+nUOcWdJ@yZ3*%~1;iM$=f^@;n7V z+~Q|;<1^ydxXRN>lIqVcckI{(D~L=gVhq0q;9C*@3EE0r;RAl=djleXsGKBC=2{}D z8yqm2p7qUhn$~=gExy(To7#xUjy83;e_CWG;DDmP-K=P)FdJYk!x{KJWPK2cd8TfG4&B zqO1F5h2^V9JL%yQ9#Bi&I%%F2(Wj@?153rKYM3j+a~ZnKPTurSM=^j`OO4k@eq5d+ zLA#-0g9}`h{%COv$qlPb2n_I+5&mmU;Zb7 z%|Es#-u~@6fY&QuO-=mcGRqU19E_#X)^`?X53t*oZ7F1xScUiwk1j4F- z!2$cg5^Kw*C0*@>F>O-%j=|Ro6Z2rkNNhwYV>j__DRz4TiCHo0MP48wSUu2o0L&80k3WcQyZEDS+dX2I3r&YPvCg}TT z7FOHyKeCtG^H<(4x8uiX%n<2ud`ptSH9hnj$$)uIUzb+UB9=TxxkZ4|*)bXE+iZ?zkcFcRu$h^vDGeG*~8{S5J!8$*4PG`Wvw rBOC^z>(4LU0PouW~B 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×o}EljmxWm}c0W_!H=u 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

)X+AQv)`5!<>$gl^J+u zy1dND?}i?yX155@-1KK856fx_$1g`Hn{A`gfw4QKN8J31p=a%qzGUvtEGWYc{ zeZTfCVZT3P8lHmP^o(d@P7Vl*kP~Yt*OY+JrBZphKcti(t@z>=p!$%R- zjgAx|_-0VAKfR@0<*Z8g+~buW20YYBnH*)4y(ydpX#}MDkTRdnrh#x>B#x`(qWI#) z)cZag3e@~@S<)361{t~&mRIHKo=@HQ%S=>J=|EB1AC&gdiaQ%5=L;g<)v9;|Z3gLnb@B~&YugrQT zaA(2WLjo;^&SYooAqAckM|+wKCQ?3><*X1g(}M0r>`A04739xVVpUqcceYp}g|7C?B(OZ%w>ti(&RUwbhnJ@JW* z?^cE%y1?$?JuaL?zrv7h`ohFq9?L$fcf(|rvtU{i|KF+FlQ#Z57S0dWCQMroyBv8i ooM(f(?H#`!h0V<4-A^T~*S+gSRya=xha%EeH&A { const { act, data } = useBackend(); const { + raptor_scan, raptor_attack, raptor_health, + raptor_max_health, raptor_speed, raptor_image, raptor_gender, @@ -37,21 +48,39 @@ export const RaptorDex = (props) => { inherited_attack_max, inherited_health, inherited_health_max, + inherited_speed, + inherited_speed_max, + inherited_ability, + inherited_ability_max, + inherited_growth, + inherited_growth_max, raptor_happiness, inherited_traits, raptor_description, raptor_color, } = data; + + if (!raptor_scan) { + return ( + + + No scan data present. + + + ); + } + return ( - + + {' '} -

+
{ }} />
+
+ {raptor_description} +
- {raptor_health} + {raptor_health} / {raptor_max_health} {raptor_attack} - {10 - raptor_speed} + {Math.round(10 / Math.max(raptor_speed, 0.5))} - {raptor_gender} + {capitalizeFirst(raptor_gender)}
@@ -84,12 +116,9 @@ export const RaptorDex = (props) => { value={inherited_health} maxValue={inherited_health_max} ranges={{ - good: [0.7 * inherited_health_max, inherited_health_max], - average: [ - 0.4 * inherited_health_max, - inherited_health_max, - ], - bad: [-Infinity, inherited_health_max], + good: [0.5 * inherited_health_max, Infinity], + average: [0, inherited_health_max * 0.5], + bad: [-Infinity, 0], }} /> @@ -98,12 +127,42 @@ export const RaptorDex = (props) => { value={inherited_attack} maxValue={inherited_attack_max} ranges={{ - good: [0.7 * inherited_attack_max, inherited_attack_max], - average: [ - 0.4 * inherited_attack_max, - inherited_attack_max, - ], - bad: [-Infinity, inherited_attack_max], + good: [0.5 * inherited_attack_max, Infinity], + average: [0, inherited_attack_max * 0.5], + bad: [-Infinity, 0], + }} + /> + + + + + + + + + @@ -113,7 +172,7 @@ export const RaptorDex = (props) => {
{
-
- {raptor_description} -
);