Files
Bubberstation/code/datums/components/happiness.dm
SkyratBot 68f4696e25 [MIRROR] You can now raise lobstrosities from chasms chrabs. (#29019)
* You can now raise lobstrosities from chasms chrabs. (#84969)

## About The Pull Request

Lobstrosities can now be raised from aquarium icemoon/lavaland chrabs.
First of all, you've to get a live chrab, an aquarium, and some fish
feed. Second, you place the chrab inside the aquarium and turn the
'allow breeding' settting on (should probably rename it to a more apt
name now). Keep the chrab well fed, and possibly with some friends and
props in the same aquarium until it develops into a hopefully calm
juveline lobstrosity and plops out of the aquarium (it can take some
time). From there you can tame it by feeding it its favorite food: arms
and lavaloop fish, and wait another dozen minutes for it to mature into
a fully grown lobstrosity.

Juveline lobstrosities are basically smaller and weaker lobstrosities,
if not slightly faster in some ways. Unlike their taller counterparts,
they can be tamed. Once done so, they'll retain their tamedness once
grown up. Regardless, tamed lobstrosities can be given the pet command
to fish for things by pointing at them. Thanks BenMatrix for the
profound fisher component, woo.

The chrab's weigth and size influence the growth speed of the first
stage faster, meaning bigger chrabs (may require crossbreeding) will
turn into juveline lobstrosities quickly. Amongst other things
influencing the resulting mob are fish traits:
Several traits have been given effects that apply to the mob, such as
nocturnal regeneration, being venomous or being able to fly akin space
carps. Also a new one that prevents the resulting lobstrosity from fully
developing

Now tested.

## Why It's Good For The Game
I'm building upon fishing and aquarium stuff, which has been an interest
of mine in a good while, though most of it doesn't have that many
practical uses, I'm slowly trying to make it cooler, and chasm chrabs
growing into lobstrosities is pretty much in line with the fluff texts
for the fish.

Eventually I'll have to add tips inside fishing toolboxes, otherwise
people won't know even half of it.

## Changelog

🆑
add: You can raise lobstrosities from chasm chrabs inside an aquarium
with the 'allow breeding' setting on. Keep the fish well fed, healthy
and not lonely if you don't want an hostile one.
add: Juveline lobstrosities (from chasms, plasma rivers, or aquariums,
xenobio too) can be tamed with arms and lavaloop fishes.
add: For lobstrosities grown from aquariums, they can have additional
effects based on the fish traits they had in the aquarium, like being
venomous or even flying.
/🆑

* You can now raise lobstrosities from chasms chrabs.

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2024-07-24 22:39:49 +05:30

162 lines
5.8 KiB
Plaintext

#define INSPECT_TIMER 10 SECONDS
#define PET_COOLDOWN 10 SECONDS
#define GROOM_COOLDOWN 30 SECONDS
/*
* A component that allows mobs to have happiness levels
*/
/datum/component/happiness
dupe_mode = COMPONENT_DUPE_UNIQUE //Prioritize the old comp over, which may have callbacks and stuff specific to the mob.
///our current happiness level
var/happiness_level
///our maximum happiness level
var/maximum_happiness
///happiness AI blackboard key
var/blackboard_key
///happiness when we get groomed
var/on_groom_change
///happiness when we get petted
var/on_petted_change
///happiness when we eat
var/on_eat_change
///percentages we should be calling back on
var/list/callback_percentages
///callback when our happiness changes
var/datum/callback/happiness_callback
///how long till we can inspect happiness again?
COOLDOWN_DECLARE(happiness_inspect)
///how long till we can pet it again?
COOLDOWN_DECLARE(pet_cooldown)
///how long till we can groom it again
COOLDOWN_DECLARE(groom_cooldown)
/datum/component/happiness/Initialize(maximum_happiness = 400, blackboard_key = BB_BASIC_HAPPINESS, on_groom_change = 200, on_eat_change = 300, on_petted_change = 30, callback_percentages = list(0, 25, 50, 75, 100), happiness_callback)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
src.maximum_happiness = maximum_happiness
src.blackboard_key = blackboard_key
src.on_groom_change = on_groom_change
src.on_petted_change = on_petted_change
src.on_eat_change = on_eat_change
src.happiness_callback = happiness_callback
src.callback_percentages = callback_percentages
ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type)
/datum/component/happiness/RegisterWithParent()
if(on_petted_change)
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_petted))
if(on_groom_change)
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
if(on_eat_change)
RegisterSignal(parent, COMSIG_MOB_ATE, PROC_REF(on_eat))
RegisterSignal(parent, COMSIG_SHIFT_CLICKED_ON, PROC_REF(view_happiness))
/datum/component/happiness/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_MOB_ATE))
happiness_callback = null
/datum/component/happiness/proc/on_eat(datum/source)
SIGNAL_HANDLER
increase_happiness_level(on_eat_change)
/datum/component/happiness/proc/on_clean(mob/living/source)
SIGNAL_HANDLER
if(!COOLDOWN_FINISHED(src, groom_cooldown))
return
var/mob/living/living_parent = parent
if (living_parent.stat != CONSCIOUS)
return
COOLDOWN_START(src, groom_cooldown, GROOM_COOLDOWN)
increase_happiness_level(on_groom_change)
/datum/component/happiness/proc/on_petted(datum/source, mob/living/petter, list/modifiers)
SIGNAL_HANDLER
if(!LAZYACCESS(modifiers, LEFT_CLICK) || petter.combat_mode)
return
var/mob/living/living_parent = parent
if (living_parent.stat != CONSCIOUS)
return
pet_animal()
/datum/component/happiness/proc/pet_animal()
if(!COOLDOWN_FINISHED(src, pet_cooldown))
return
increase_happiness_level(on_petted_change)
COOLDOWN_START(src, pet_cooldown, PET_COOLDOWN)
/datum/component/happiness/proc/increase_happiness_level(amount)
happiness_level = min(happiness_level + amount, maximum_happiness)
if(!HAS_TRAIT(parent, TRAIT_MOB_HIDE_HAPPINESS))
var/mob/living/living_parent = parent
new /obj/effect/temp_visual/heart(living_parent.loc)
living_parent.spin(spintime = 2 SECONDS, speed = 1)
START_PROCESSING(SSprocessing, src)
/datum/component/happiness/proc/view_happiness(mob/living/source, mob/living/clicker)
if(HAS_TRAIT(source, TRAIT_MOB_HIDE_HAPPINESS) || !istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !clicker.CanReach(source))
return
var/list/offset_to_add = get_icon_dimensions(source.icon)
var/y_position = offset_to_add["height"] + 1
var/obj/effect/overlay/happiness_overlay/hearts = new
hearts.pixel_y = y_position
hearts.set_hearts(happiness_level/maximum_happiness)
source.vis_contents += hearts
COOLDOWN_START(src, happiness_inspect, INSPECT_TIMER)
/datum/component/happiness/process()
var/mob/living/living_parent = parent
var/happiness_percentage = happiness_level/maximum_happiness
living_parent.ai_controller?.set_blackboard_key(blackboard_key, happiness_percentage)
var/check_percentage_in_list = round(happiness_percentage * 100, 1)
if(check_percentage_in_list in callback_percentages)
SEND_SIGNAL(parent, COMSIG_MOB_HAPPINESS_CHANGE, happiness_percentage)
happiness_callback?.Invoke(happiness_percentage)
if(happiness_level <= 0)
return PROCESS_KILL
var/modifier = living_parent.ai_controller?.blackboard[BB_BASIC_DEPRESSED] ? 2 : 1
happiness_level = max(0, happiness_level - modifier)
/obj/effect/overlay/happiness_overlay
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
vis_flags = VIS_INHERIT_DIR | VIS_INHERIT_PLANE
layer = ABOVE_HUD_PLANE
///how many hearts should we display
VAR_PRIVATE/hearts_percentage
///icon of our heart
var/heart_icon = 'icons/effects/effects.dmi'
/obj/effect/overlay/happiness_overlay/Initialize(mapload)
. = ..()
QDEL_IN(src, 5 SECONDS)
/obj/effect/overlay/happiness_overlay/proc/set_hearts(happiness_percentage)
hearts_percentage = happiness_percentage
update_appearance(UPDATE_OVERLAYS)
/obj/effect/overlay/happiness_overlay/update_overlays()
. = ..()
var/static/list/heart_positions = list(-13, -5, 3, 11)
var/display_amount = round(length(heart_positions) * hearts_percentage, 1)
for(var/index in 1 to length(heart_positions))
var/heart_icon_state = display_amount >= index ? "full_heart" : "empty_heart"
var/mutable_appearance/display_icon = mutable_appearance(icon = heart_icon, icon_state = heart_icon_state, layer = ABOVE_HUD_PLANE)
display_icon.pixel_x = heart_positions[index]
. += display_icon
#undef INSPECT_TIMER
#undef PET_COOLDOWN
#undef GROOM_COOLDOWN