basic gutlunchers and ashwalker ranching (#79508)

## About The Pull Request
this pr transforms gutlunchers into basic mobs and gives them a small
ranch that ashwalkers can manage. gutlunches come in various colors and
sizes! female gutlunches will come in different shades of red and males
will come in shades of blue. the child born will have a mix of his
parent's colors.
![the
farm](https://github.com/tgstation/tgstation/assets/138636438/41fdb1ed-e567-4c8d-bb83-b296f878c862)
female gutlunches can make various healing milk and medicine from its
udder. but it will need to consume ores before it can start making milk,
u can either feed it by hand or u can put ores in the wooden trough and
they will go eat from it whenever they get hungry. feeding it gold or
bluespace ore will improve the healing quality of the milk for a short
while

![trough](https://github.com/tgstation/tgstation/assets/138636438/b9c84d18-fdd8-476b-b779-bdfe49dd7e88)
the male gutlunchers are obedient pets. their stats vary from one
another in speed, attack and health. a male gutlunchers stats will
depend on the stats of his parents, the higher his parent's stats are
the better chances he has at rolling higher stats. so u can selectively
breed them to make sure they have the best stats possible. they will
listen to all ur commands and can mine walls or attack enemies if given
the command. also i wanted the farm to have wood fences so i added them
to the game, they cost 5 wood planks to make



## Why It's Good For The Game
refactors gutlunches into basic mobs. also i turned breeding into a
component so it can be applied to all animals and created a breed
command, pets that have this command and the component will go breed
with a partner u point at.

## Changelog
🆑
refactor: gutlunches have been refactored into basic mobs. please report
any bugs
add: ashwalkers have a small ranch they can manage
fix: wall tearer compnent wont runtime when interacting with mineral
walls
/🆑
This commit is contained in:
Ben10Omintrix
2023-11-13 01:20:19 -07:00
committed by GitHub
parent 10deb0f8cb
commit 7a44f10993
39 changed files with 1261 additions and 377 deletions
@@ -61,10 +61,11 @@
/turf/closed/indestructible/riveted/boss,
/area/ruin/unpowered/ash_walkers)
"al" = (
/obj/structure/stone_tile/surrounding_tile{
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 1
},
/turf/closed/mineral/volcanic/lava_land_surface,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"aq" = (
/obj/structure/stone_tile/block/cracked{
@@ -76,13 +77,11 @@
/turf/closed/mineral/volcanic/lava_land_surface,
/area/lavaland/surface/outdoors)
"ar" = (
/obj/structure/stone_tile/block/cracked{
dir = 4
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 9
},
/obj/structure/stone_tile{
dir = 4
},
/turf/closed/mineral/volcanic/lava_land_surface,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"as" = (
/turf/closed/wall/mineral/wood,
@@ -155,12 +154,6 @@
/obj/item/flashlight/flare/torch,
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"az" = (
/obj/structure/stone_tile/block{
dir = 4
},
/turf/closed/mineral/volcanic/lava_land_surface,
/area/lavaland/surface/outdoors)
"aF" = (
/obj/structure/stone_tile/block{
dir = 8
@@ -213,7 +206,7 @@
dir = 1
},
/obj/structure/stone_tile,
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck,
/mob/living/basic/mining/gutlunch/milk,
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"aR" = (
@@ -287,7 +280,7 @@
/obj/structure/stone_tile{
dir = 4
},
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen,
/mob/living/basic/mining/gutlunch/warrior,
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"bd" = (
@@ -331,13 +324,11 @@
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"bh" = (
/obj/structure/stone_tile/block{
dir = 4
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 5
},
/obj/structure/stone_tile{
dir = 8
},
/turf/closed/mineral/volcanic/lava_land_surface,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"bi" = (
/obj/structure/stone_tile/block/cracked{
@@ -520,15 +511,16 @@
/turf/closed/mineral/volcanic/lava_land_surface,
/area/lavaland/surface/outdoors)
"bJ" = (
/obj/structure/stone_tile/surrounding_tile,
/turf/closed/mineral/volcanic/lava_land_surface,
/obj/effect/mapping_helpers/no_lava,
/mob/living/basic/mining/gutlunch/milk,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"cp" = (
/obj/structure/stone_tile/cracked,
/obj/structure/stone_tile/block{
dir = 1
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 8
},
/turf/closed/mineral/volcanic/lava_land_surface,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"cF" = (
/obj/structure/stone_tile/block{
@@ -687,6 +679,12 @@
/obj/item/flashlight/flare/torch,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"fM" = (
/obj/effect/mapping_helpers/no_lava,
/mob/living/basic/mining/gutlunch/warrior,
/obj/item/flashlight/lantern,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"gi" = (
/obj/structure/table/optable,
/obj/structure/stone_tile{
@@ -758,6 +756,10 @@
/obj/effect/decal/cleanable/blood,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"mo" = (
/obj/structure/stone_tile/block,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"mp" = (
/obj/structure/stone_tile/surrounding/cracked,
/turf/open/misc/asteroid/basalt/lava_land_surface,
@@ -808,6 +810,16 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"qm" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/stone_tile/block/cracked{
dir = 8
},
/obj/structure/stone_tile/block/cracked{
dir = 4
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"qn" = (
/obj/item/storage/box/rxglasses,
/obj/structure/stone_tile{
@@ -821,6 +833,11 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"qH" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"qV" = (
/obj/structure/stone_tile/surrounding_tile{
dir = 8
@@ -882,6 +899,16 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"sz" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/stone_tile/block/cracked{
dir = 8
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"ty" = (
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"tY" = (
/obj/structure/stone_tile/block/cracked{
dir = 1
@@ -924,6 +951,13 @@
/obj/item/flashlight/flare/torch,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"vV" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 4
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"wB" = (
/obj/structure/stone_tile/block,
/obj/structure/stone_tile{
@@ -1047,6 +1081,14 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Dz" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/stone_tile{
dir = 8
},
/obj/structure/stone_tile,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Ee" = (
/obj/structure/stone_tile/block/cracked,
/obj/structure/stone_tile{
@@ -1119,9 +1161,16 @@
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"GW" = (
/obj/structure/stone_tile/surrounding_tile{
dir = 8
/obj/structure/stone_tile/cracked{
dir = 4
},
/obj/structure/closet/crate/internals,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
@@ -1177,6 +1226,18 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"JD" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/ore_container/gutlunch_trough,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Kg" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 10
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Kt" = (
/obj/structure/water_source/puddle{
pixel_x = -3;
@@ -1185,6 +1246,12 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"KQ" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/table/wood,
/obj/item/reagent_containers/cup/bucket/wooden,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"KR" = (
/obj/structure/stone_tile/block/cracked,
/obj/effect/mapping_helpers/no_lava,
@@ -1248,9 +1315,10 @@
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Oe" = (
/obj/structure/stone_tile/surrounding_tile/cracked,
/obj/structure/ore_box,
/obj/effect/mapping_helpers/no_lava,
/obj/structure/stone_tile{
dir = 8
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"OY" = (
@@ -1258,6 +1326,29 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Pk" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/corner/end/wooden_fence,
/obj/structure/railing/corner/end/flip/wooden_fence,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"PA" = (
/obj/effect/mapping_helpers/no_lava,
/mob/living/basic/mining/gutlunch/warrior,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"PK" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/stone_tile,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Rq" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/railing/wooden_fence{
dir = 6
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"RE" = (
/obj/structure/stone_tile/block/cracked{
dir = 1
@@ -1302,6 +1393,12 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Tl" = (
/obj/effect/mapping_helpers/no_lava,
/obj/structure/table/wood,
/obj/item/flashlight/lantern,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Tr" = (
/obj/machinery/hydroponics/soil,
/obj/structure/stone_tile/block{
@@ -1310,6 +1407,11 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"TC" = (
/obj/effect/mapping_helpers/no_lava,
/obj/item/flashlight/lantern,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"TO" = (
/obj/structure/stone_tile{
dir = 4
@@ -1337,17 +1439,8 @@
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Uh" = (
/obj/structure/stone_tile/cracked{
dir = 4
},
/obj/structure/closet/crate/internals,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/effect/mapping_helpers/no_lava,
/obj/structure/stone_tile/block,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"UI" = (
@@ -1384,6 +1477,12 @@
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"Zr" = (
/obj/structure/stone_tile/surrounding_tile/cracked,
/obj/structure/ore_box,
/obj/effect/mapping_helpers/no_lava,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
(1,1,1) = {"
aa
@@ -1639,8 +1738,8 @@ ak
ak
ak
IS
RH
Aj
Gv
ty
Nv
Kt
du
@@ -1770,10 +1869,10 @@ ak
ak
ak
ak
KR
Aj
eu
ah
Zr
Gv
qm
Gv
as
mm
cF
@@ -1793,9 +1892,9 @@ ak
ak
bI
Oe
Uh
ah
cp
Gv
qm
Gv
as
as
as
@@ -1804,20 +1903,20 @@ ak
cQ
"}
(20,1,1) = {"
aa
al
ar
az
az
az
bh
az
bC
bJ
ah
ah
ah
al
Gv
Gv
Gv
Gv
Gv
Gv
Gv
Gv
Gv
Gv
Dz
qm
Gv
ah
ah
bC
@@ -1825,3 +1924,289 @@ ah
ah
cR
"}
(21,1,1) = {"
ah
Gv
ar
cp
cp
cp
cp
cp
Kg
Gv
Gv
Gv
qm
Gv
ah
ah
ah
ah
ah
ah
"}
(22,1,1) = {"
ah
Gv
al
fM
Gv
Gv
TC
Gv
qH
KQ
Gv
Gv
qm
Gv
Gv
ah
ah
ah
ah
ah
"}
(23,1,1) = {"
ah
Gv
al
Gv
Gv
Gv
Gv
PA
qH
KQ
Gv
Gv
qm
Gv
PK
ah
ah
ah
ah
ah
"}
(24,1,1) = {"
ah
Gv
al
Gv
bJ
bJ
Gv
Gv
qH
Tl
Gv
Gv
qm
sz
Gv
ah
ah
ah
ah
ah
"}
(25,1,1) = {"
ah
Gv
al
bJ
Gv
Gv
Gv
Gv
qH
Gv
sz
sz
qm
Gv
Gv
ah
ah
ah
ah
ah
"}
(26,1,1) = {"
ah
Gv
al
Gv
bJ
bJ
Gv
Gv
Pk
sz
Gv
Oe
Gv
Gv
Gv
ah
ah
ah
aa
aa
"}
(27,1,1) = {"
ah
Gv
al
Gv
Gv
TC
Gv
Gv
qH
Gv
Dz
Oe
Gv
Gv
Gv
ah
ah
ah
aa
aa
"}
(28,1,1) = {"
ah
Gv
al
Gv
JD
Gv
Gv
Gv
qH
Gv
Gv
Gv
Gv
Dz
Gv
ah
ah
ah
aa
aa
"}
(29,1,1) = {"
ah
Gv
al
Gv
Gv
Gv
Gv
PA
qH
Gv
Gv
Gv
Gv
Gv
Gv
ah
ah
ah
aa
aa
"}
(30,1,1) = {"
ah
Gv
al
TC
Gv
PA
Gv
TC
qH
Gv
mo
ah
ah
ah
ah
ah
ah
aa
aa
aa
"}
(31,1,1) = {"
ah
Gv
bh
vV
vV
vV
vV
vV
Rq
Uh
ty
ah
ah
ah
ah
ah
ah
aa
aa
aa
"}
(32,1,1) = {"
ah
Gv
Gv
Gv
Gv
Gv
Gv
Gv
Gv
Gv
ty
ah
ah
aa
aa
aa
aa
aa
aa
aa
"}
(33,1,1) = {"
ah
ah
ah
ah
ah
ah
ah
ah
ah
ah
ah
ah
ah
aa
aa
aa
aa
aa
aa
aa
"}
@@ -68,7 +68,7 @@
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"p" = (
/obj/structure/material_stand,
/obj/structure/ore_container/material_stand,
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"q" = (
@@ -132,7 +132,7 @@
/turf/open/floor/fakebasalt,
/area/centcom/basketball)
"ie" = (
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen,
/mob/living/basic/mining/gutlunch/warrior,
/turf/open/floor/fakebasalt,
/area/centcom/basketball)
"ix" = (
@@ -609,7 +609,7 @@
/turf/open/lava/smooth/basketball,
/area/centcom/basketball)
"Fy" = (
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck,
/mob/living/basic/mining/gutlunch/milk,
/turf/open/floor/fakebasalt,
/area/centcom/basketball)
"FS" = (
@@ -33902,7 +33902,7 @@
/turf/open/floor/plating/snowed/smoothed/icemoon,
/area/icemoon/underground/explored)
"ksu" = (
/mob/living/simple_animal/hostile/asteroid/gutlunch,
/mob/living/basic/mining/gutlunch/warrior,
/turf/open/misc/asteroid/snow/icemoon,
/area/icemoon/underground/explored)
"ksC" = (
+6
View File
@@ -10,6 +10,12 @@
#define BB_PATH_TO_USE "BB_path_to_use"
///How close a mob must be for us to select it as a target, if that is less than how far we can maintain it as a target
#define BB_AGGRO_RANGE "BB_aggro_range"
///are we hungry? determined by the udder compnent
#define BB_CHECK_HUNGRY "BB_check_hungry"
///are we ready to breed?
#define BB_BREED_READY "BB_breed_ready"
///maximum kids we can have
#define BB_MAX_CHILDREN "BB_max_children"
/// Store a single or list of emotes at this key
#define BB_EMOTE_KEY "BB_emotes"
+3
View File
@@ -190,6 +190,9 @@
/// the bonfire we will light up
#define BB_MOOK_BONFIRE_TARGET "bonfire_target"
//gutlunch keys
///the trough we will eat from
#define BB_TROUGH_TARGET "trough_target"
//leaper keys
///key holds our volley ability
#define BB_LEAPER_VOLLEY "leaper_volley"
+2
View File
@@ -1352,5 +1352,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait given to a dragon who fails to defend their rifts
#define TRAIT_RIFT_FAILURE "fail_dragon_loser"
///trait determines if this mob can breed given by /datum/component/breeding
#define TRAIT_MOB_BREEDER "mob_breeder"
/// Trait given to mobs that we do not want to mindswap
#define TRAIT_NO_MINDSWAP "no_mindswap"
+35 -32
View File
@@ -2,74 +2,77 @@
* Find a compatible, living partner, if we're also alone.
*/
/datum/ai_behavior/find_partner
action_cooldown = 40 SECONDS
/// Range to look.
var/range = 7
/// Maximum number of children
var/max_children = 3
/datum/ai_behavior/find_partner/perform(seconds_per_tick, datum/ai_controller/controller, target_key, partner_types_key, child_types_key)
. = ..()
max_children = controller.blackboard[BB_MAX_CHILDREN] || max_children
var/mob/pawn_mob = controller.pawn
var/list/partner_types = controller.blackboard[partner_types_key]
var/list/child_types = controller.blackboard[child_types_key]
var/mob/living/living_pawn = controller.pawn
var/mob/living/partner
var/children = 0
for(var/mob/other in oview(range, pawn_mob))
if(other.stat != CONSCIOUS) //Check if it's conscious FIRST.
continue
var/is_child = is_type_in_list(other, child_types)
if(is_child) //Check for children SECOND.
children++
else if(is_type_in_list(other, partner_types))
if(other.ckey)
continue
else if(!is_child && other.gender == MALE && !(other.flags_1 & HOLOGRAM_1)) //Better safe than sorry ;_;
partner = other
//shyness check. we're not shy in front of things that share a faction with us.
else if(isliving(other) && !pawn_mob.faction_check_atom(other))
for(var/mob/living/other in oview(range, pawn_mob))
if(!pawn_mob.faction_check_atom(other))
finish_action(controller, FALSE)
return
if(partner && children < max_children)
controller.set_blackboard_key(target_key, partner)
if(children >= max_children)
finish_action(controller, FALSE)
return
if(other.stat != CONSCIOUS) //Check if it's conscious FIRST.
continue
if(is_type_in_list(other, child_types)) //Check for children SECOND.
children++
continue
if(!is_type_in_list(other, partner_types) || !HAS_TRAIT(other, TRAIT_MOB_BREEDER))
continue
if(other.ckey)
continue
if(other.gender != living_pawn.gender && !(other.flags_1 & HOLOGRAM_1)) //Better safe than sorry ;_;
controller.set_blackboard_key(target_key, other)
finish_action(controller, TRUE)
finish_action(controller, FALSE)
finish_action(controller, TRUE)
/**
* Reproduce.
*/
/datum/ai_behavior/make_babies
action_cooldown = 40 SECONDS
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH
/datum/ai_behavior/make_babies/setup(datum/ai_controller/controller, target_key, child_types_key)
. = ..()
var/atom/target = controller.blackboard[target_key]
if(!target)
return FALSE
set_movement_target(controller, target)
return TRUE
/datum/ai_behavior/make_babies/perform(seconds_per_tick, datum/ai_controller/controller, target_key, child_types_key)
. = ..()
var/mob/target = controller.blackboard[target_key]
if(!target || target.stat != CONSCIOUS)
if(QDELETED(target) || target.stat != CONSCIOUS)
finish_action(controller, FALSE, target_key)
return
var/child_type = pick_weight(controller.blackboard[child_types_key])
var/turf/turf_loc = get_turf(controller.pawn.loc)
if(turf_loc)
new child_type(turf_loc)
var/mob/living/basic/living_pawn = controller.pawn
living_pawn.set_combat_mode(FALSE)
living_pawn.melee_attack(target)
finish_action(controller, TRUE, target_key)
/datum/ai_behavior/make_babies/finish_action(datum/ai_controller/controller, succeeded, target_key)
. = ..()
controller.clear_blackboard_key(target_key)
if(!succeeded)
return
var/mob/living/living_pawn = controller.pawn
living_pawn.set_combat_mode(initial(living_pawn.combat_mode))
+9 -4
View File
@@ -3,11 +3,19 @@
*/
/datum/ai_planning_subtree/make_babies
var/chance = 5
operational_datums = list(/datum/component/breed)
/datum/ai_planning_subtree/make_babies/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
if(controller.pawn.gender != FEMALE || !SPT_PROB(chance, seconds_per_tick))
if(!SPT_PROB(chance, seconds_per_tick))
return
if(controller.blackboard_key_exists(BB_BABIES_TARGET))
controller.queue_behavior(/datum/ai_behavior/make_babies, BB_BABIES_TARGET, BB_BABIES_CHILD_TYPES)
return SUBTREE_RETURN_FINISH_PLANNING
if(controller.pawn.gender == FEMALE || !controller.blackboard[BB_BREED_READY])
return
var/partner_types = controller.blackboard[BB_BABIES_PARTNER_TYPES]
@@ -21,7 +29,4 @@
return
// Find target
if(controller.blackboard_key_exists(BB_BABIES_TARGET))
controller.queue_behavior(/datum/ai_behavior/make_babies, BB_BABIES_TARGET, BB_BABIES_CHILD_TYPES)
return SUBTREE_RETURN_FINISH_PLANNING
controller.queue_behavior(/datum/ai_behavior/find_partner, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES)
+17
View File
@@ -45,3 +45,20 @@
return
return corgi_pawn.access_card.GetAccess()
/datum/ai_controller/basic_controller/dog/puppy
blackboard = list(
BB_DOG_HARASS_HARM = TRUE,
BB_VISION_RANGE = AI_DOG_VISION_RANGE,
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/holding_object,
// With tongs in hand!
BB_TARGET_HELD_ITEM = /obj/item/kitchen/tongs,
)
planning_subtrees = list(
/datum/ai_planning_subtree/random_speech/dog,
/datum/ai_planning_subtree/pet_planning,
/datum/ai_planning_subtree/dog_harassment,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/flee_target,
)
@@ -81,6 +81,7 @@
/// Do we reset the target after attacking something, so we can check for status changes.
var/always_reset_target = FALSE
/datum/ai_behavior/hunt_target/setup(datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key)
. = ..()
var/atom/hunt_target = controller.blackboard[hunting_target_key]
@@ -123,10 +124,27 @@
controller.clear_blackboard_key(hunting_target_key)
/datum/ai_behavior/hunt_target/unarmed_attack_target
///do we toggle combat mode before interacting with the object?
var/switch_combat_mode = FALSE
/datum/ai_behavior/hunt_target/unarmed_attack_target/target_caught(mob/living/hunter, obj/structure/cable/hunted)
if(switch_combat_mode)
hunter.combat_mode = !(hunter.combat_mode)
hunter.UnarmedAttack(hunted, TRUE)
/datum/ai_behavior/hunt_target/unarmed_attack_target/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key)
. = ..()
if(!switch_combat_mode)
return
var/mob/living/living_pawn = controller.pawn
living_pawn.combat_mode = initial(living_pawn.combat_mode)
/datum/ai_behavior/hunt_target/unarmed_attack_target/switch_combat_mode
switch_combat_mode = TRUE
/datum/ai_behavior/hunt_target/unarmed_attack_target/reset_target
always_reset_target = TRUE
/datum/ai_behavior/hunt_target/use_ability_on_target
always_reset_target = TRUE
///the ability we will use
+76
View File
@@ -0,0 +1,76 @@
/*
* A component to allow us to breed
*/
/datum/component/breed
/// additional mobs we can breed with
var/list/can_breed_with
///path of the baby
var/baby_path
///time to wait after breeding
var/breed_timer
///AI key we set when we're ready to breed
var/breed_key = BB_BREED_READY
///are we ready to breed?
var/ready_to_breed = TRUE
///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_path, post_birth)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
if(ishuman(parent)) //sin detected
return COMPONENT_INCOMPATIBLE
if(!ispath(baby_path))
stack_trace("attempted to add a breeding component with invalid baby path!")
return
src.can_breed_with = can_breed_with
src.breed_timer = breed_timer
src.baby_path = baby_path
src.post_birth = post_birth
ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type)
/datum/component/breed/RegisterWithParent()
RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(breed_with_partner))
ADD_TRAIT(parent, TRAIT_MOB_BREEDER, REF(src))
var/mob/living/parent_mob = parent
parent_mob.ai_controller?.set_blackboard_key(breed_key, TRUE)
/datum/component/breed/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)
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
if(source.combat_mode)
return
if(!is_type_in_typecache(target, can_breed_with))
return
if(!HAS_TRAIT(target, TRAIT_MOB_BREEDER) || target.gender == source.gender)
return
if(!ready_to_breed)
source.balloon_alert(source, "not ready!")
return COMPONENT_HOSTILE_NO_ATTACK
var/turf/delivery_destination = get_turf(source)
var/mob/living/baby = new baby_path(delivery_destination)
new /obj/effect/temp_visual/heart(delivery_destination)
toggle_status(source)
addtimer(CALLBACK(src, PROC_REF(toggle_status), source), breed_timer)
post_birth?.Invoke(baby, target)
return COMPONENT_HOSTILE_NO_ATTACK
/datum/component/breed/proc/toggle_status(mob/living/source)
ready_to_breed = !ready_to_breed
source.ai_controller?.set_blackboard_key(BB_BREED_READY, ready_to_breed)
@@ -158,7 +158,37 @@
return SUBTREE_RETURN_FINISH_PLANNING
/**
* # Pet Command: targeted Ability
* # Breed command. breed with a partner!
*/
/datum/pet_command/point_targeting/breed
command_name = "Breed"
command_desc = "Command your pet to attempt to breed with a partner."
radial_icon = 'icons/mob/simple/animal.dmi'
radial_icon_state = "heart"
speech_commands = list("breed", "consummate")
/datum/pet_command/point_targeting/breed/set_command_target(mob/living/parent, atom/target)
if(isnull(target) || !isliving(target))
return
if(!HAS_TRAIT(parent, TRAIT_MOB_BREEDER) || !HAS_TRAIT(target, TRAIT_MOB_BREEDER))
return
if(isnull(parent.ai_controller))
return
if(!parent.ai_controller.blackboard[BB_BREED_READY] || isnull(parent.ai_controller.blackboard[BB_BABIES_PARTNER_TYPES]))
return
var/mob/living/living_target = target
if(!living_target.ai_controller?.blackboard[BB_BREED_READY])
return
return ..()
/datum/pet_command/point_targeting/breed/execute_action(datum/ai_controller/controller)
if(is_type_in_list(controller.blackboard[BB_CURRENT_PET_TARGET], controller.blackboard[BB_BABIES_PARTNER_TYPES]))
controller.queue_behavior(/datum/ai_behavior/make_babies, BB_CURRENT_PET_TARGET)
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
return SUBTREE_RETURN_FINISH_PLANNING
/**
* # Pet Command: Targetted Ability
* Tells a pet to use some kind of ability on the next thing you point at
*/
/datum/pet_command/point_targeting/use_ability
+7 -1
View File
@@ -15,7 +15,7 @@
/datum/component/torn_wall/Initialize()
. = ..()
if (!iswallturf(parent) || isindestructiblewall(parent))
if (!isclosedturf(parent) || isindestructiblewall(parent))
return COMPONENT_INCOMPATIBLE
/datum/component/torn_wall/RegisterWithParent()
@@ -53,6 +53,12 @@
return
var/turf/closed/wall/attached_wall = parent
playsound(attached_wall, 'sound/effects/meteorimpact.ogg', 100, vary = TRUE)
if(ismineralturf(attached_wall))
var/turf/closed/mineral/mineral_turf = attached_wall
mineral_turf.gets_drilled()
return
attached_wall.dismantle_wall(devastated = TRUE)
/// Fix it up on weld
+76 -46
View File
@@ -13,7 +13,8 @@
/datum/component/udder/Initialize(udder_type = /obj/item/udder, datum/callback/on_milk_callback, datum/callback/on_generate_callback, reagent_produced_typepath = /datum/reagent/consumable/milk)
if(!isliving(parent)) //technically is possible to drop this on carbons... but you wouldn't do that to me, would you?
return COMPONENT_INCOMPATIBLE
udder = new udder_type(null, parent, on_generate_callback, reagent_produced_typepath)
udder = new udder_type(null)
udder.add_features(parent, on_generate_callback, reagent_produced_typepath)
src.on_milk_callback = on_milk_callback
/datum/component/udder/RegisterWithParent()
@@ -70,14 +71,68 @@
var/mob/living/udder_mob
///optional proc to callback to when the udder generates milk
var/datum/callback/on_generate_callback
///do we require some food to generate milk?
var/require_consume_type
///how long does each food consumption allow us to make milk
var/require_consume_timer = 2 MINUTES
///hunger key we set to look for food
var/hunger_key = BB_CHECK_HUNGRY
/obj/item/udder/Initialize(mapload, udder_mob, on_generate_callback, reagent_produced_typepath = /datum/reagent/consumable/milk)
src.udder_mob = udder_mob
src.on_generate_callback = on_generate_callback
/obj/item/udder/proc/add_features(parent, callback, reagent = /datum/reagent/consumable/milk)
udder_mob = parent
on_generate_callback = callback
create_reagents(size, REAGENT_HOLDER_ALIVE)
src.reagent_produced_typepath = reagent_produced_typepath
reagent_produced_typepath = reagent
initial_conditions()
if(isnull(require_consume_type))
return
RegisterSignal(udder_mob, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_mob_consume))
RegisterSignal(udder_mob, COMSIG_ATOM_ATTACKBY, PROC_REF(on_mob_feed))
udder_mob.ai_controller?.set_blackboard_key(BB_CHECK_HUNGRY, TRUE)
/obj/item/udder/proc/on_mob_consume(datum/source, atom/feed)
SIGNAL_HANDLER
if(!istype(feed, require_consume_type))
return
INVOKE_ASYNC(src, PROC_REF(handle_consumption), feed)
return COMPONENT_HOSTILE_NO_ATTACK
/obj/item/udder/proc/on_mob_feed(datum/source, atom/used_item, mob/living/user)
SIGNAL_HANDLER
if(!istype(used_item, require_consume_type))
return
INVOKE_ASYNC(src, PROC_REF(handle_consumption), used_item, user)
return COMPONENT_NO_AFTERATTACK
/obj/item/udder/proc/handle_consumption(atom/movable/food, mob/user)
if(locate(food.type) in src)
if(user)
user.balloon_alert(user, "already full!")
return
playsound(udder_mob.loc,'sound/items/eatfood.ogg', 50, TRUE)
udder_mob.visible_message(span_notice("[udder_mob] gobbles up [food]!"), span_notice("You gobble up [food]!"))
var/atom/movable/final_food = food
if(isstack(food)) //if stack, only consume 1
var/obj/item/stack/food_stack = food
final_food = food_stack.split_stack(udder_mob, 1)
final_food.forceMove(src)
/obj/item/udder/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
if(!istype(arrived, require_consume_type))
return ..()
udder_mob.ai_controller?.set_blackboard_key(hunger_key, FALSE)
QDEL_IN(arrived, require_consume_timer)
return ..()
/obj/item/udder/Exited(atom/movable/gone, direction)
. = ..()
if(!istype(gone, require_consume_type))
return
udder_mob.ai_controller?.set_blackboard_key(hunger_key, TRUE)
/obj/item/udder/Destroy()
. = ..()
@@ -101,10 +156,13 @@
* Proc called every 2 seconds from SSMobs to add whatever reagent the udder is generating.
*/
/obj/item/udder/proc/generate()
if(prob(5))
reagents.add_reagent(reagent_produced_typepath, rand(5, 10), added_purity = 1)
if(on_generate_callback)
on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume)
if(!isnull(require_consume_type) && !(locate(require_consume_type) in src))
return
if(prob(95))
return
reagents.add_reagent(reagent_produced_typepath, rand(5, 10), added_purity = 1)
if(on_generate_callback)
on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume)
/**
* Proc called from attacking the component parent with the correct item, moves reagents into the glass basically.
@@ -125,48 +183,20 @@
/**
* # gutlunch udder subtype
*
* Used by gutlunches, and generates healing reagents instead of milk on eating gibs instead of a process. Starts empty!
* Female gutlunches (ahem, guthens if you will) make babies when their udder is full under processing, instead of milk generation
*/
/obj/item/udder/gutlunch
name = "nutrient sac"
/obj/item/udder/gutlunch/initial_conditions()
if(!udder_mob)
return
if(udder_mob.gender == FEMALE)
START_PROCESSING(SSobj, src)
RegisterSignal(udder_mob, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_mob_attacking))
/obj/item/udder/gutlunch/process(seconds_per_tick)
var/mob/living/simple_animal/hostile/asteroid/gutlunch/gutlunch = udder_mob
if(reagents.total_volume != reagents.maximum_volume)
return
if(gutlunch.make_babies())
reagents.clear_reagents()
//usually this would be a callback but this is a specifically gutlunch feature so fuck it, gutlunch specific proccall
gutlunch.regenerate_icons(reagents.total_volume, reagents.maximum_volume)
/**
* signal called on parent attacking an atom
*/
/obj/item/udder/gutlunch/proc/on_mob_attacking(mob/living/simple_animal/hostile/gutlunch, atom/target)
SIGNAL_HANDLER
if(is_type_in_typecache(target, gutlunch.wanted_objects)) //we eats
generate()
gutlunch.visible_message(span_notice("[udder_mob] slurps up [target]."))
qdel(target)
return COMPONENT_HOSTILE_NO_ATTACK //there is no longer a target to attack
require_consume_type = /obj/item/stack/ore
reagent_produced_typepath = /datum/reagent/medicine/mine_salve
/obj/item/udder/gutlunch/generate()
var/made_something = FALSE
if(prob(60))
. = ..()
if(!.)
return
if(locate(/obj/item/stack/ore/gold) in src)
reagents.add_reagent(/datum/reagent/consumable/cream, rand(2, 5), added_purity = 1)
made_something = TRUE
if(prob(45))
if(locate(/obj/item/stack/ore/bluespace_crystal) in src)
reagents.add_reagent(/datum/reagent/medicine/salglu_solution, rand(2,5))
made_something = TRUE
if(made_something && on_generate_callback)
if(on_generate_callback)
on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume)
+26
View File
@@ -0,0 +1,26 @@
/*
* A component to allow us to collect ore
*/
/datum/element/ore_collecting
/datum/element/ore_collecting/Attach(datum/target)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(collect_ore))
/datum/element/ore_collecting/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)
/datum/element/ore_collecting/proc/collect_ore(mob/living/source, atom/target)
SIGNAL_HANDLER
if(!istype(target, /obj/item/stack/ore))
return
var/atom/movable/movable_target = target
movable_target.forceMove(source)
return COMPONENT_HOSTILE_NO_ATTACK
+2 -4
View File
@@ -28,17 +28,15 @@
src.tear_time = tear_time
src.reinforced_multiplier = reinforced_multiplier
src.do_after_key = do_after_key
RegisterSignal(target, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attacked_wall))
RegisterSignals(target, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK), PROC_REF(on_attacked_wall))
/datum/element/wall_tearer/Detach(datum/source)
. = ..()
UnregisterSignal(source, COMSIG_LIVING_UNARMED_ATTACK)
UnregisterSignal(source, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_UNARMED_ATTACK))
/// Try to tear up a wall
/datum/element/wall_tearer/proc/on_attacked_wall(mob/living/tearer, atom/target, proximity_flag)
SIGNAL_HANDLER
if (!proximity_flag)
return NONE
if (DOING_INTERACTION_WITH_TARGET(tearer, target) || (!isnull(do_after_key) && DOING_INTERACTION(tearer, do_after_key)))
tearer.balloon_alert(tearer, "busy!")
return COMPONENT_HOSTILE_NO_ATTACK
@@ -39,3 +39,9 @@
name = "Pony"
icon_file = 'icons/mob/simple/animal.dmi'
json_config = 'code/datums/greyscale/json_configs/pony.json'
/datum/greyscale_config/gutlunch
name = "Gutlunch"
icon_file = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
json_config = 'code/datums/greyscale/json_configs/gutlunch.json'
@@ -0,0 +1,15 @@
{
"gutlunch": [
{
"type": "icon_state",
"icon_state": "gutlunch",
"blend_mode": "overlay",
"color_ids": [ 1 ]
},
{
"type": "icon_state",
"icon_state": "gutlunch_face",
"blend_mode": "overlay"
}
]
}
@@ -303,6 +303,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
@@ -0,0 +1,62 @@
///structure to contain ores
/obj/structure/ore_container
/obj/structure/ore_container/attackby(obj/item/ore, mob/living/carbon/human/user, list/modifiers)
if(istype(ore, /obj/item/stack/ore) && !user.combat_mode)
ore.forceMove(src)
return
return ..()
/obj/structure/ore_container/Entered(atom/movable/mover)
. = ..()
update_appearance(UPDATE_OVERLAYS)
/obj/structure/ore_container/Exited(atom/movable/mover)
. = ..()
update_appearance(UPDATE_OVERLAYS)
/obj/structure/ore_container/ui_interact(mob/user, datum/tgui/ui)
. = ..()
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "OreContainer")
ui.open()
/obj/structure/ore_container/ui_data(mob/user)
var/list/data = list()
data["ores"] = list()
for(var/obj/item/stack/ore/ore_item in contents)
data["ores"] += list(list(
"id" = REF(ore_item),
"name" = ore_item.name,
"amount" = ore_item.amount,
))
return data
/obj/structure/ore_container/ui_static_data(mob/user)
var/list/data = list()
data["ore_images"] = list()
for(var/obj/item/stack/ore_item as anything in subtypesof(/obj/item/stack/ore))
data["ore_images"] += list(list(
"name" = initial(ore_item.name),
"icon" = icon2base64(getFlatIcon(image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state)), no_anim=TRUE))
))
return data
/obj/structure/ore_container/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(. || !isliving(ui.user))
return TRUE
var/mob/living/customer = ui.user
var/obj/item/stack_to_move
switch(action)
if("withdraw")
if(isnull(params["reference"]))
return TRUE
stack_to_move = locate(params["reference"]) in contents
if(isnull(stack_to_move))
return TRUE
stack_to_move.forceMove(get_turf(customer))
return TRUE
+39 -7
View File
@@ -17,6 +17,8 @@
var/climbable = TRUE
///Initial direction of the railing.
var/ini_dir
///item released when deconstructed
var/item_deconstruct = /obj/item/stack/rods
/datum/armor/structure_railing
melee = 35
@@ -98,13 +100,11 @@
return TRUE
/obj/structure/railing/deconstruct(disassembled)
if(!(flags_1 & NODECONSTRUCT_1))
if (istype(src,/obj/structure/railing/corner)) // Corner railings only cost 1 rod
var/obj/item/stack/rods/rod = new /obj/item/stack/rods(drop_location(), 1)
transfer_fingerprints_to(rod)
else
var/obj/item/stack/rods/rod = new /obj/item/stack/rods(drop_location(), 2)
transfer_fingerprints_to(rod)
if((flags_1 & NODECONSTRUCT_1))
return ..()
var/rods_to_make = istype(src,/obj/structure/railing/corner) ? 1 : 2
var/obj/rod = new item_deconstruct(drop_location(), rods_to_make)
transfer_fingerprints_to(rod)
return ..()
///Implements behaviour that makes it possible to unanchor the railing.
@@ -156,3 +156,35 @@
/obj/structure/railing/proc/check_anchored(checked_anchored)
if(anchored == checked_anchored)
return TRUE
/obj/structure/railing/wooden_fence
name = "wooden fence"
desc = "wooden fence meant to keep animals in."
icon = 'icons/obj/structures.dmi'
icon_state = "wooden_railing"
item_deconstruct = /obj/item/stack/sheet/mineral/wood
plane = GAME_PLANE_FOV_HIDDEN
layer = ABOVE_MOB_LAYER
/obj/structure/railing/wooden_fence/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_change_layer))
adjust_dir_layer(dir)
/obj/structure/railing/wooden_fence/proc/on_change_layer(datum/source, old_dir, new_dir)
SIGNAL_HANDLER
adjust_dir_layer(new_dir)
/obj/structure/railing/wooden_fence/proc/adjust_dir_layer(direction)
var/new_layer = (direction & NORTH) ? MOB_LAYER : ABOVE_MOB_LAYER
layer = new_layer
/obj/structure/railing/corner/end/wooden_fence
icon = 'icons/obj/structures.dmi'
icon_state = "wooden_railing_corner"
/obj/structure/railing/corner/end/flip/wooden_fence
icon = 'icons/obj/structures.dmi'
icon_state = "wooden_railing_corner_flipped"
@@ -52,7 +52,7 @@
/datum/action/cooldown/mob_cooldown/burrow = BB_BURROW_ABILITY,
)
grant_actions_by_list(innate_actions)
AddElement(/datum/element/ore_collecting)
AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE)
AddComponent(/datum/component/ai_listen_to_weather)
AddComponent(\
@@ -67,17 +67,6 @@
RegisterSignal(src, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(block_bullets))
/mob/living/basic/mining/goldgrub/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
. = ..()
if(!.)
return
if(!proximity_flag)
return
if(istype(attack_target, /obj/item/stack/ore))
consume_ore(attack_target)
/mob/living/basic/mining/goldgrub/proc/block_bullets(datum/source, obj/projectile/hitting_projectile)
SIGNAL_HANDLER
@@ -135,12 +124,14 @@
max_eggs_held = 1,\
)
/mob/living/basic/mining/goldgrub/proc/consume_ore(obj/item/target_ore)
/mob/living/basic/mining/goldgrub/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
if(!istype(arrived, /obj/item/stack/ore))
return
playsound(src,'sound/items/eatfood.ogg', rand(10,50), TRUE)
target_ore.forceMove(src)
if(!can_lay_eggs)
return
if(!istype(target_ore, /obj/item/stack/ore/bluespace_crystal) || prob(60))
if(!istype(arrived, /obj/item/stack/ore/bluespace_crystal) || prob(60))
return
new /obj/item/food/egg/green/grub_egg(get_turf(src))
@@ -0,0 +1,40 @@
/obj/structure/ore_container/gutlunch_trough
name = "gutlunch trough"
desc = "The gutlunches will eat out of it!"
icon = 'icons/obj/structures.dmi'
icon_state = "gutlunch_trough"
density = TRUE
anchored = TRUE
///list of materials in the trough
var/list/list_of_materials = list()
/obj/structure/ore_container/gutlunch_trough/Entered(atom/movable/mover)
if(!istype(mover, /obj/item/stack/ore))
return ..()
if(list_of_materials[mover.type])
return ..()
list_of_materials[mover.type] = list("pixel_x" = rand(-5, 8), "pixel_y" = rand(-2, -7))
return ..()
/obj/structure/ore_container/gutlunch_trough/Exited(atom/movable/mover)
if(!istype(mover, /obj/item/stack/ore) || !isnull(locate(mover.type) in contents))
return ..()
list_of_materials -= mover.type
return ..()
/obj/structure/ore_container/gutlunch_trough/deconstruct(disassembled = TRUE)
if(flags_1 & NODECONSTRUCT_1)
return
new /obj/item/stack/sheet/mineral/wood(drop_location(), 5)
qdel(src)
/obj/structure/ore_container/gutlunch_trough/update_overlays()
. = ..()
for(var/ore_entry in list_of_materials)
var/obj/item/ore_item = ore_entry
var/image/ore_icon = image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state), layer = LOW_ITEM_LAYER)
var/list/pixel_positions = list_of_materials[ore_entry]
ore_icon.transform = ore_icon.transform.Scale(0.4, 0.4)
ore_icon.pixel_x = pixel_positions["pixel_x"]
ore_icon.pixel_y = pixel_positions["pixel_y"]
. += ore_icon
@@ -0,0 +1,167 @@
#define MAX_ATTACK_DIFFERENCE 3
#define MAX_LOWER_ATTACK 15
#define MINIMUM_POSSIBLE_SPEED 1
#define MAX_POSSIBLE_HEALTH 100
/mob/living/basic/mining/gutlunch
name = "gutlunch"
desc = "A scavenger that eats raw ores, often found alongside ash walkers. Produces a thick, nutritious milk."
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
icon_state = "gutlunch"
combat_mode = FALSE
icon_living = "gutlunch"
icon_dead = "gutlunch"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
basic_mob_flags = DEL_ON_DEATH
speak_emote = list("warbles", "quavers")
faction = list(FACTION_MINING, FACTION_ASHWALKER)
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently pushes aside"
response_disarm_simple = "gently push aside"
response_harm_continuous = "squishes"
response_harm_simple = "squish"
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
gold_core_spawnable = FRIENDLY_SPAWN
death_message = "is pulped into bugmash."
greyscale_config = /datum/greyscale_config/gutlunch
///possible colors we can have
var/list/possible_colors = list(COLOR_WHITE)
///can we breed?
var/can_breed = TRUE
/mob/living/basic/mining/gutlunch/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
if(greyscale_config)
set_greyscale(colors = list(pick(possible_colors)))
AddElement(/datum/element/ai_retaliate)
if(!can_breed)
return
AddComponent(\
/datum/component/breed,\
can_breed_with = typecacheof(list(/mob/living/basic/mining/gutlunch)),\
baby_path = /mob/living/basic/mining/gutlunch/grub,\
post_birth = CALLBACK(src, PROC_REF(after_birth)),\
breed_timer = 3 MINUTES,\
)
/mob/living/basic/mining/gutlunch/proc/pre_attack(mob/living/puncher, atom/target)
SIGNAL_HANDLER
if(!istype(target, /obj/structure/ore_container/gutlunch_trough))
return
var/obj/ore_food = locate(/obj/item/stack/ore) in target
if(isnull(ore_food))
balloon_alert(src, "no food!")
else
melee_attack(ore_food)
return COMPONENT_HOSTILE_NO_ATTACK
/mob/living/basic/mining/gutlunch/proc/after_birth(mob/living/basic/mining/gutlunch/grub/baby, mob/living/partner)
var/our_color = LAZYACCESS(atom_colours, FIXED_COLOUR_PRIORITY) || COLOR_GRAY
var/partner_color = LAZYACCESS(partner.atom_colours, FIXED_COLOUR_PRIORITY) || COLOR_GRAY
baby.add_atom_colour(BlendRGB(our_color, partner_color, 1), FIXED_COLOUR_PRIORITY)
var/atom/male_parent = (gender == MALE) ? src : partner
baby.inherited_stats = new(male_parent)
/mob/living/basic/mining/gutlunch/proc/roll_stats(input_attack, input_speed, input_health)
melee_damage_lower = rand(input_attack, min(MAX_LOWER_ATTACK, input_attack + MAX_ATTACK_DIFFERENCE))
melee_damage_upper = melee_damage_lower + MAX_ATTACK_DIFFERENCE
speed = rand(MINIMUM_POSSIBLE_SPEED, input_speed)
maxHealth = rand(input_health, MAX_POSSIBLE_HEALTH)
health = maxHealth
/mob/living/basic/mining/gutlunch/milk
name = "gubbuck"
gender = FEMALE
possible_colors = list("#E39FBB","#817178","#9d667d")
ai_controller = /datum/ai_controller/basic_controller/gutlunch/gutlunch_milk
///overlay we display when our udder is full!
var/mutable_appearance/full_udder
/mob/living/basic/mining/gutlunch/milk/Initialize(mapload)
. = ..()
var/datum/callback/milking_callback = CALLBACK(src, TYPE_PROC_REF(/atom/movable, update_overlays))
AddComponent(\
/datum/component/udder,\
udder_type = /obj/item/udder/gutlunch,\
on_milk_callback = milking_callback,\
on_generate_callback = milking_callback,\
)
full_udder = mutable_appearance(icon, "gl_full")
full_udder.color = LAZYACCESS(atom_colours, FIXED_COLOUR_PRIORITY) || COLOR_GRAY
/mob/living/basic/mining/gutlunch/warrior
name = "gunther"
gender = MALE
melee_damage_lower = 8
melee_damage_upper = 13
speed = 5
maxHealth = 70
health = 70
ai_controller = /datum/ai_controller/basic_controller/gutlunch/gutlunch_warrior
possible_colors = list("#6d77ff","#8578e4","#97b6f6")
//pet commands when we tame the gutluncher
var/static/list/pet_commands = list(
/datum/pet_command/idle,
/datum/pet_command/free,
/datum/pet_command/point_targeting/attack,
/datum/pet_command/point_targeting/breed,
/datum/pet_command/follow,
/datum/pet_command/point_targeting/fetch,
/datum/pet_command/mine_walls,
)
/mob/living/basic/mining/gutlunch/warrior/Initialize(mapload)
. = ..()
roll_stats(melee_damage_lower, speed, maxHealth)
AddComponent(/datum/component/obeys_commands, pet_commands)
AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE)
/mob/living/basic/mining/gutlunch/milk/update_overlays(new_udder_volume, max_udder_volume)
. = ..()
if(new_udder_volume != max_udder_volume)
return
. += full_udder
/mob/living/basic/mining/gutlunch/grub
name = "grublunch"
possible_colors = list("#cc9797", "#b74c4c")
can_breed = FALSE
gender = NEUTER
ai_controller = /datum/ai_controller/basic_controller/gutlunch/gutlunch_baby
///list of stats we inherited
var/datum/gutlunch_inherited_stats/inherited_stats
/mob/living/basic/mining/gutlunch/grub/Initialize(mapload)
. = ..()
transform = transform.Scale(0.6, 0.6)
AddComponent(\
/datum/component/growth_and_differentiation,\
growth_time = 3 MINUTES,\
growth_probability = 100,\
lower_growth_value = 0.5,\
upper_growth_value = 1,\
signals_to_kill_on = list(COMSIG_MOB_CLIENT_LOGIN),\
optional_checks = CALLBACK(src, PROC_REF(ready_to_grow)),\
optional_grow_behavior = CALLBACK(src, PROC_REF(determine_growth_path)),\
)
/mob/living/basic/mining/gutlunch/grub/proc/ready_to_grow()
return (stat == CONSCIOUS)
/mob/living/basic/mining/gutlunch/grub/proc/determine_growth_path()
var/final_type = prob(50) ? /mob/living/basic/mining/gutlunch/warrior : /mob/living/basic/mining/gutlunch/milk
var/mob/living/basic/mining/gutlunch/grown_mob = new final_type(get_turf(src))
if(grown_mob.gender == MALE && inherited_stats)
grown_mob.roll_stats(inherited_stats.attack, inherited_stats.speed, inherited_stats.health)
qdel(src)
#undef MAX_ATTACK_DIFFERENCE
#undef MAX_LOWER_ATTACK
#undef MINIMUM_POSSIBLE_SPEED
#undef MAX_POSSIBLE_HEALTH
@@ -0,0 +1,119 @@
/datum/ai_controller/basic_controller/gutlunch
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
/datum/ai_controller/basic_controller/gutlunch/gutlunch_warrior
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/mining/gutlunch/milk),
BB_BABIES_CHILD_TYPES = list(/mob/living/basic/mining/gutlunch/grub),
BB_MAX_CHILDREN = 5,
)
planning_subtrees = list(
/datum/ai_planning_subtree/target_retaliate/check_faction,
/datum/ai_planning_subtree/pet_planning,
/datum/ai_planning_subtree/make_babies,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
/datum/ai_planning_subtree/befriend_ashwalkers,
)
///find ashwalkers and add them to the list of masters
/datum/ai_planning_subtree/befriend_ashwalkers
/datum/ai_planning_subtree/befriend_ashwalkers/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
controller.queue_behavior(/datum/ai_behavior/befriend_ashwalkers)
/datum/ai_behavior/befriend_ashwalkers
action_cooldown = 5 SECONDS
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/befriend_ashwalkers/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
var/mob/living/living_pawn = controller.pawn
for(var/mob/living/potential_friend in oview(9, living_pawn))
if(!isashwalker(potential_friend))
continue
if((living_pawn.faction.Find(REF(potential_friend))))
continue
living_pawn.befriend(potential_friend)
to_chat(potential_friend, span_nicegreen("[living_pawn] looks at you with endearing eyes!"))
finish_action(controller, TRUE)
return
finish_action(controller, FALSE)
return
/datum/ai_controller/basic_controller/gutlunch/gutlunch_baby
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_FIND_MOM_TYPES = list(/mob/living/basic/mining/gutlunch/milk),
)
planning_subtrees = list(
/datum/ai_planning_subtree/target_retaliate,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/look_for_adult,
)
/datum/ai_controller/basic_controller/gutlunch/gutlunch_milk
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
)
planning_subtrees = list(
/datum/ai_planning_subtree/target_retaliate,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/find_and_hunt_target/food_trough
)
///consume food!
/datum/ai_planning_subtree/find_and_hunt_target/food_trough
target_key = BB_TROUGH_TARGET
hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/food_trough
finding_behavior = /datum/ai_behavior/find_hunt_target/food_trough
hunt_targets = list(/obj/structure/ore_container/gutlunch_trough)
hunt_chance = 75
hunt_range = 9
/datum/ai_planning_subtree/find_and_hunt_target/food_trough/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
if(!controller.blackboard[BB_CHECK_HUNGRY])
return
return ..()
/datum/ai_behavior/find_hunt_target/food_trough
/datum/ai_behavior/find_hunt_target/food_trough/valid_dinner(mob/living/basic/source, obj/target, radius)
if(isnull(target))
return FALSE
if(isnull(locate(/obj/item/stack/ore) in target))
return FALSE
return can_see(source, target, radius)
/datum/ai_behavior/hunt_target/unarmed_attack_target/food_trough
always_reset_target = TRUE
switch_combat_mode = TRUE
/datum/pet_command/mine_walls
command_name = "Mine"
command_desc = "Command your pet to mine down walls."
speech_commands = list("mine", "smash")
/datum/pet_command/mine_walls/try_activate_command(mob/living/commander)
var/mob/living/parent = weak_parent.resolve()
if(isnull(parent))
return
//no walls for us to mine
var/target_in_vicinity = locate(/turf/closed/mineral) in oview(9, parent)
if(isnull(target_in_vicinity))
return
return ..()
/datum/pet_command/mine_walls/execute_action(datum/ai_controller/controller)
if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET))
controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_CURRENT_PET_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING
controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_CURRENT_PET_TARGET)
@@ -0,0 +1,14 @@
///stats we inherit from the parent
/datum/gutlunch_inherited_stats
///attack we inherited
var/attack
///speed we inherited
var/speed
///health we inherited
var/health
/datum/gutlunch_inherited_stats/New(mob/living/basic/parent)
. = ..()
attack = parent.melee_damage_lower
speed = parent.speed
health = parent.maxHealth
@@ -107,7 +107,7 @@
ore_target.forceMove(src)
return COMPONENT_HOSTILE_NO_ATTACK
if(istype(target, /obj/structure/material_stand))
if(istype(target, /obj/structure/ore_container/material_stand))
if(held_ore)
held_ore.forceMove(target)
return COMPONENT_HOSTILE_NO_ATTACK
@@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(mook_commands, list(
target_key = BB_MATERIAL_STAND_TARGET
hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/material_stand
finding_behavior = /datum/ai_behavior/find_hunt_target
hunt_targets = list(/obj/structure/material_stand)
hunt_targets = list(/obj/structure/ore_container/material_stand)
hunt_range = 9
/datum/ai_planning_subtree/find_and_hunt_target/material_stand/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
@@ -83,6 +83,7 @@ GLOBAL_LIST_INIT(mook_commands, list(
/datum/ai_behavior/hunt_target/unarmed_attack_target/material_stand
required_distance = 0
always_reset_target = TRUE
switch_combat_mode = TRUE
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
///try to face the counter when depositing ores
@@ -1,5 +1,5 @@
///unique items that spawn at the mook village
/obj/structure/material_stand
/obj/structure/ore_container/material_stand
name = "material stand"
desc = "Is everyone free to use this thing?"
icon = 'icons/mob/simple/jungle/mook.dmi'
@@ -10,22 +10,8 @@
bound_width = 64
bound_height = 64
/obj/structure/material_stand/attackby(obj/item/ore, mob/living/carbon/human/user, list/modifiers)
if(istype(ore, /obj/item/stack/ore))
ore.forceMove(src)
return
return ..()
/obj/structure/material_stand/Entered(atom/movable/mover)
. = ..()
update_appearance(UPDATE_OVERLAYS)
/obj/structure/material_stand/Exited(atom/movable/mover)
. = ..()
update_appearance(UPDATE_OVERLAYS)
///put ore icons on the counter!
/obj/structure/material_stand/update_overlays()
/obj/structure/ore_container/material_stand/update_overlays()
. = ..()
for(var/obj/item/stack/ore/ore_item in contents)
var/image/ore_icon = image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state), layer = LOW_ITEM_LAYER)
@@ -34,52 +20,6 @@
ore_icon.pixel_y = rand(2, 4)
. += ore_icon
/obj/structure/material_stand/ui_interact(mob/user, datum/tgui/ui)
. = ..()
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "MaterialStand")
ui.open()
/obj/structure/material_stand/ui_data(mob/user)
var/list/data = list()
data["ores"] = list()
for(var/obj/item/stack/ore/ore_item in contents)
data["ores"] += list(list(
"id" = REF(ore_item),
"name" = ore_item.name,
"amount" = ore_item.amount,
))
return data
/obj/structure/material_stand/ui_static_data(mob/user)
var/list/data = list()
data["ore_images"] = list()
for(var/obj/item/stack/ore_item as anything in subtypesof(/obj/item/stack/ore))
data["ore_images"] += list(list(
"name" = initial(ore_item.name),
"icon" = icon2base64(getFlatIcon(image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state)), no_anim=TRUE))
))
return data
/obj/structure/material_stand/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(. || !isliving(usr))
return TRUE
var/mob/living/customer = usr
var/obj/item/stack_to_move
switch(action)
if("withdraw")
if(isnull(params["reference"]))
return TRUE
stack_to_move = locate(params["reference"]) in contents
if(isnull(stack_to_move))
return TRUE
stack_to_move.forceMove(get_turf(customer))
return TRUE
/obj/effect/landmark/mook_village
name = "mook village landmark"
icon_state = "x"
@@ -26,6 +26,8 @@
var/is_slow = FALSE
///Item slots that are available for this corgi to equip stuff into
var/list/strippable_inventory_slots = list()
///can this mob breed?
var/can_breed = TRUE
/mob/living/basic/pet/dog/corgi/Initialize(mapload)
. = ..()
@@ -34,6 +36,13 @@
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CORGI, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(on_tried_access))
RegisterSignals(src, list(COMSIG_BASICMOB_LOOK_ALIVE, COMSIG_BASICMOB_LOOK_DEAD), PROC_REF(on_appearance_change))
if(!can_breed)
return
AddComponent(\
/datum/component/breed,\
can_breed_with = typecacheof(list(/mob/living/basic/pet/dog/corgi)),\
baby_path = /mob/living/basic/pet/dog/corgi/puppy,\
)
/mob/living/basic/pet/dog/corgi/Destroy()
QDEL_NULL(inventory_head)
@@ -532,9 +541,11 @@
icon_dead = "puppy_dead"
density = FALSE
pass_flags = PASSMOB
ai_controller = /datum/ai_controller/basic_controller/dog/puppy
mob_size = MOB_SIZE_SMALL
collar_icon_state = "puppy"
strippable_inventory_slots = list(/datum/strippable_item/pet_collar, /datum/strippable_item/corgi_id) //puppies are too small to handle hats and back slot items
can_breed = FALSE
//PUPPY IAN! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/puppy/ian
@@ -1,128 +0,0 @@
//Gutlunches, passive mods that devour blood and gibs
/mob/living/simple_animal/hostile/asteroid/gutlunch
name = "gutlunch"
desc = "A scavenger that eats raw meat, often found alongside ash walkers. Produces a thick, nutritious milk."
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
icon_state = "gutlunch"
icon_living = "gutlunch"
icon_dead = "gutlunch"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
speak_emote = list("warbles", "quavers")
emote_hear = list("trills.")
emote_see = list("sniffs.", "burps.")
weather_immunities = list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE)
faction = list(FACTION_MINING, FACTION_ASHWALKER)
density = FALSE
speak_chance = 1
turns_per_move = 8
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
move_to_delay = 15
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently pushes aside"
response_disarm_simple = "gently push aside"
response_harm_continuous = "squishes"
response_harm_simple = "squish"
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
combat_mode = FALSE
gold_core_spawnable = FRIENDLY_SPAWN
stat_attack = HARD_CRIT
gender = NEUTER
stop_automated_movement = FALSE
stop_automated_movement_when_pulled = TRUE
stat_exclusive = TRUE
robust_searching = TRUE
search_objects = 3 //Ancient simplemob AI shitcode. This makes them ignore all other mobs.
del_on_death = TRUE
loot = list(/obj/effect/decal/cleanable/blood/gibs)
death_message = "is pulped into bugmash."
animal_species = /mob/living/simple_animal/hostile/asteroid/gutlunch
childtype = list(/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch = 100)
wanted_objects = list(/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/blood/gibs/, /obj/item/organ)
/mob/living/simple_animal/hostile/asteroid/gutlunch/Initialize(mapload)
. = ..()
if(wanted_objects.len)
AddComponent(/datum/component/udder, /obj/item/udder/gutlunch, CALLBACK(src, PROC_REF(regenerate_icons)), CALLBACK(src, PROC_REF(regenerate_icons)))
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
/mob/living/simple_animal/hostile/asteroid/gutlunch/CanAttack(atom/the_target) // Gutlunch-specific version of CanAttack to handle stupid stat_exclusive = true crap so we don't have to do it for literally every single simple_animal/hostile except the two that spawn in lavaland
if(!the_target || !isturf(the_target.loc)) // bail out on invalids
return FALSE
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
return FALSE
if(isliving(the_target))
var/mob/living/L = the_target
if(faction_check_atom(L) && !attack_same)
return FALSE
if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive)
return FALSE
return TRUE
if(isobj(the_target) && is_type_in_typecache(the_target, wanted_objects))
return TRUE
return FALSE
/mob/living/simple_animal/hostile/asteroid/gutlunch/regenerate_icons(new_udder_volume, max_udder_volume)
cut_overlays()
var/static/gutlunch_full_overlay
if(isnull(gutlunch_full_overlay))
gutlunch_full_overlay = iconstate2appearance(icon, "gl_full")
if(new_udder_volume == max_udder_volume)
add_overlay(gutlunch_full_overlay)
..()
//Male gutlunch. They're smaller and more colorful!
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck
name = "gubbuck"
gender = MALE
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck/Initialize(mapload)
. = ..()
add_atom_colour(pick("#E39FBB", "#D97D64", "#CF8C4A"), FIXED_COLOUR_PRIORITY)
update_transform(0.85)
//Lady gutlunch. They make the babby.
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen
name = "guthen"
gender = FEMALE
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch
name = "grublunch"
wanted_objects = list() //They don't eat.
gold_core_spawnable = NO_SPAWN
var/growth = 0
//Baby gutlunch
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch/Initialize(mapload)
. = ..()
add_atom_colour("#9E9E9E", FIXED_COLOUR_PRIORITY) //Somewhat hidden
update_transform(0.45)
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch/Life(seconds_per_tick = SSMOBS_DT, times_fired)
..()
growth++
if(growth > 50) //originally used a timer for this but it was more of a problem than it was worth.
growUp()
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch/proc/growUp()
var/mob/living/L
if(prob(45))
L = new /mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck(loc)
else
L = new /mob/living/simple_animal/hostile/asteroid/gutlunch/guthen(loc)
mind?.transfer_to(L)
L.faction = faction
L.setDir(dir)
L.Stun(20, ignore_canstun = TRUE)
visible_message(span_notice("[src] grows up into [L]."))
qdel(src)
@@ -51,10 +51,6 @@
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire,
/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead,
/mob/living/simple_animal/hostile/asteroid/elite/pandora,
/mob/living/simple_animal/hostile/asteroid/gutlunch,
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch,
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck,
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen,
/mob/living/simple_animal/hostile/asteroid/polarbear,
/mob/living/simple_animal/hostile/asteroid/polarbear/lesser,
/mob/living/simple_animal/hostile/asteroid/wolf,
Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 198 KiB

+7 -1
View File
@@ -990,6 +990,7 @@
#include "code\datums\components\bloodysoles.dm"
#include "code\datums\components\boomerang.dm"
#include "code\datums\components\boss_music.dm"
#include "code\datums\components\breeding.dm"
#include "code\datums\components\bullet_intercepting.dm"
#include "code\datums\components\bumpattack.dm"
#include "code\datums\components\burning.dm"
@@ -1399,6 +1400,7 @@
#include "code\datums\elements\noticable_organ.dm"
#include "code\datums\elements\obj_regen.dm"
#include "code\datums\elements\openspace_item_click_handler.dm"
#include "code\datums\elements\ore_collecting.dm"
#include "code\datums\elements\organ_set_bonus.dm"
#include "code\datums\elements\pet_bonus.dm"
#include "code\datums\elements\plant_backfire.dm"
@@ -2533,6 +2535,7 @@
#include "code\game\objects\structures\morgue.dm"
#include "code\game\objects\structures\mystery_box.dm"
#include "code\game\objects\structures\noticeboard.dm"
#include "code\game\objects\structures\ore_containers.dm"
#include "code\game\objects\structures\petrified_statue.dm"
#include "code\game\objects\structures\pinatas.dm"
#include "code\game\objects\structures\plasticflaps.dm"
@@ -4523,6 +4526,10 @@
#include "code\modules\mob\living\basic\lavaland\goliath\goliath_ai.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\goliath_trophy.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\tentacle.dm"
#include "code\modules\mob\living\basic\lavaland\gutlunchers\gutluncher_foodtrough.dm"
#include "code\modules\mob\living\basic\lavaland\gutlunchers\gutlunchers.dm"
#include "code\modules\mob\living\basic\lavaland\gutlunchers\gutlunchers_ai.dm"
#include "code\modules\mob\living\basic\lavaland\gutlunchers\gutlunchers_inherit_datum.dm"
#include "code\modules\mob\living\basic\lavaland\hivelord\hivelord.dm"
#include "code\modules\mob\living\basic\lavaland\hivelord\hivelord_ai.dm"
#include "code\modules\mob\living\basic\lavaland\hivelord\spawn_hivelord_brood.dm"
@@ -4841,7 +4848,6 @@
#include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\wendigo.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\curse_blob.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\gutlunch.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\mining_mobs.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\polarbear.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\wolf.dm"
@@ -19,7 +19,7 @@ type Data = {
ore_images: Ore_images[];
};
export const MaterialStand = (props, context) => {
export const OreContainer = (props, context) => {
const { act, data } = useBackend<Data>(context);
const { ores = [] } = data;
const [searchItem, setSearchItem] = useLocalState(context, 'searchItem', '');
@@ -27,7 +27,7 @@ export const MaterialStand = (props, context) => {
const ores_filtered =
searchItem.length > 0 ? ores.filter((ore) => search(ore)) : ores;
return (
<Window title="Material Stand" width={550} height={400}>
<Window title="Ore Container" width={550} height={400}>
<Window.Content>
<Stack fill vertical>
<Stack.Item>
@@ -0,0 +1,5 @@
/mob/living/simple_animal/hostile/asteroid/gutlunch : /mob/living/basic/mining/gutlunch{@OLD}
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch : /mob/living/basic/mining/gutlunch/grub{@OLD}
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck : /mob/living/basic/mining/gutlunch/milk{@OLD}
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen : /mob/living/basic/mining/gutlunch/warrior{@OLD}
@@ -0,0 +1 @@
/obj/structure/material_stand : /obj/structure/ore_container/material_stand{@OLD}