Space dragons can now catch and eat fish (plus shark form and rift fishing) (#86582)

This commit is contained in:
Ghom
2024-11-11 00:43:40 -08:00
committed by Majkl-J
parent 4e1371a2e8
commit 58b9009ae5
22 changed files with 243 additions and 13 deletions
+1
View File
@@ -58,6 +58,7 @@
#define MEDAL_SISYPHUS "Sisyphus"
#define MEDAL_ARCHMAGE "Archmage"
#define MEDAL_CIGARETTES "Cigarettes"
#define MEDAL_SHARKDRAGON "Sharkdragon"
#define MEDAL_THEORETICAL_LIMITS "All Within Theoretical Limits"
//Skill medal hub IDs
+3
View File
@@ -965,6 +965,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
///A trait for mechs that were created through the normal construction process, and not spawned by map or other effects.
#define TRAIT_MECHA_CREATED_NORMALLY "trait_mecha_created_normally"
/// Stops a movable from being removed from the mob it's in by the content_barfer component.
#define TRAIT_NOT_BARFABLE "not_barfable"
///fish traits
#define TRAIT_FISH_STASIS "fish_stasis"
#define TRAIT_FISH_FLOPPING "fish_flopping"
+2
View File
@@ -69,6 +69,7 @@ GLOBAL_LIST_INIT(phobia_mobs, list(
)),
"carps" = typecacheof(list(
/mob/living/basic/carp,
/mob/living/basic/space_dragon,
)),
"conspiracies" = typecacheof(list(
/mob/living/basic/drone,
@@ -247,6 +248,7 @@ GLOBAL_LIST_INIT(phobia_objs, list(
/obj/item/clothing/mask/gas/carp,
/obj/item/cigarette/carp,
/obj/item/clothing/under/suit/carpskin,
/obj/item/fish/baby_carp,
/obj/item/food/cubancarp,
/obj/item/food/fishmeat/carp,
/obj/item/grenade/clusterbuster/spawner_spesscarp,
+3 -1
View File
@@ -57,11 +57,13 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_MOVE_PHASING" = TRAIT_MOVE_PHASING,
"TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN,
"TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING,
"TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE,
"TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN,
"TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM,
"TRAIT_NO_MANIFEST_CONTENTS_ERROR" = TRAIT_NO_MANIFEST_CONTENTS_ERROR,
"TRAIT_NO_MISSING_ITEM_ERROR" = TRAIT_NO_MISSING_ITEM_ERROR,
"TRAIT_NO_THROW_HITPUSH" = TRAIT_NO_THROW_HITPUSH,
"TRAIT_NOT_BARFABLE" = TRAIT_NOT_BARFABLE,
"TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE,
"TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT,
"TRAIT_ON_HIT_EFFECT" = TRAIT_ON_HIT_EFFECT,
"TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN,
@@ -234,7 +234,13 @@
icon_state = "sisyphus"
/datum/award/achievement/misc/cigarettes
name = "Unhealthy snacks"
name = "Unhealthy Snacks"
desc = "You were curious to taste it. And then another. You must have more!"
database_id = MEDAL_CIGARETTES
icon_state = "cigarettes"
/datum/award/achievement/misc/sharkdragon
name = "You're What You Eat"
desc = "Nutritionists often recommend a balanced and varied diet. However that clearly isn't the case for some creatures."
database_id = MEDAL_SHARKDRAGON
icon_state = "dragon_plus_fish"
@@ -9,6 +9,7 @@
return COMPONENT_INCOMPATIBLE
src.our_rod = our_rod || new(parent)
src.our_rod.internal = TRUE
ADD_TRAIT(src.our_rod, TRAIT_NOT_BARFABLE, REF(src))
RegisterSignal(src.our_rod, COMSIG_QDELETING, PROC_REF(on_rod_qdel))
if(!isgloves)
@@ -43,6 +44,7 @@
/datum/component/profound_fisher/Destroy()
our_rod.internal = FALSE
UnregisterSignal(our_rod, COMSIG_QDELETING)
REMOVE_TRAIT(our_rod, TRAIT_NOT_BARFABLE, REF(src))
our_rod = null
return ..()
+3 -1
View File
@@ -20,7 +20,9 @@
/datum/element/content_barfer/proc/barf_contents(mob/living/target)
SIGNAL_HANDLER
for(var/atom/movable/barfed_out in target)
for(var/atom/movable/barfed_out as anything in target)
if(HAS_TRAIT(barfed_out, TRAIT_NOT_BARFABLE))
continue
barfed_out.forceMove(target.loc)
if(prob(90))
step(barfed_out, pick(GLOB.alldirs))
+3
View File
@@ -71,3 +71,6 @@
UnregisterSignal(owner, COMSIG_QDELETING)
owner = null
/obj/item/toy/plush/carpplushie/dehy_carp/peaceful
mobtype = /mob/living/basic/carp/passive
+7
View File
@@ -88,6 +88,13 @@
cell_line = null
starting_reagent_purity = 0.3
///carp fillet, but without the toxin. Used by baby carps (fish item), which have a trait that handles the toxin already.
/obj/item/food/fishmeat/carp/no_tox
/obj/item/food/fishmeat/carp/no_tox/Initialize(mapload)
food_reagents -= /datum/reagent/toxin/carpotoxin
return ..()
/obj/item/food/fishmeat/moonfish
name = "moonfish fillet"
desc = "A fillet of moonfish."
@@ -111,6 +111,8 @@
healing_color = COLOR_BLUE, \
)
AddComponent(/datum/component/fishing_spot, /datum/fish_source/carp_rift)
gravity_aura = new(
/* host = */src,
/* range = */15,
@@ -112,7 +112,7 @@
var/icon/icon = icon('icons/mob/nonhuman-player/spacedragon.dmi', "spacedragon")
icon.Blend(COLOR_STRONG_VIOLET, ICON_MULTIPLY)
icon.Blend(icon('icons/mob/nonhuman-player/spacedragon.dmi', "overlay_base"), ICON_OVERLAY)
icon.Blend(icon('icons/mob/nonhuman-player/spacedragon.dmi', "spacedragon_overlay_base"), ICON_OVERLAY)
icon.Crop(10, 9, 54, 53)
icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE)
+4
View File
@@ -1304,6 +1304,10 @@
/obj/item/fish/proc/undo_petted()
fish_flags &= ~FISH_FLAG_PETTED
/obj/item/fish/update_atom_colour()
. = ..()
aquarium_vc_color = color || initial(aquarium_vc_color)
/// Returns random fish, using random_case_rarity probabilities.
/proc/random_fish_type(required_fluid)
var/static/probability_table
+12 -3
View File
@@ -427,6 +427,8 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
catalog_description = "This fish contains toxins. Feeding it to predatory fishes or people is not recommended."
diff_traits_inheritability = 25
reagents_to_add = list(/datum/reagent/toxin/tetrodotoxin = 1)
///The amount of venom injected if the fish has a stinger is multiplied by this value.
var/venom_mult = 1
/datum/fish_trait/toxic/apply_to_fish(obj/item/fish/fish)
. = ..()
@@ -438,13 +440,13 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
SIGNAL_HANDLER
if(!HAS_TRAIT(source, TRAIT_FISH_STINGER))
return
add_venom(source, /datum/reagent/toxin/tetrodotoxin, new_weight, mult = source.status == FISH_DEAD ? 0.1 : 0.25)
add_venom(source, reagents_to_add[1], new_weight, mult = (source.status == FISH_DEAD ? 0.1 : 0.25) * venom_mult)
/datum/fish_trait/toxic/proc/on_status_change(obj/item/fish/source)
SIGNAL_HANDLER
if(!HAS_TRAIT(source, TRAIT_FISH_STINGER))
return
change_venom_on_death(source, /datum/reagent/toxin/tetrodotoxin, 0.25, 0.1)
change_venom_on_death(source, reagents_to_add[1], 0.25 * venom_mult, 0.1 * venom_mult)
/datum/fish_trait/toxic/proc/on_eaten(obj/item/fish/source, obj/item/fish/predator)
if(HAS_TRAIT(predator, TRAIT_FISH_TOXIN_IMMUNE))
@@ -463,7 +465,14 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
/datum/fish_trait/toxic/apply_to_mob(mob/living/basic/mob)
. = ..()
mob.AddElement(/datum/element/venomous, /datum/reagent/toxin/tetrodotoxin, 0.5 * mob.mob_size)
mob.AddElement(/datum/element/venomous, reagents_to_add[1], 0.5 * mob.mob_size * venom_mult)
/datum/fish_trait/toxic/carpotoxin
name = "Carpotoxic"
catalog_description = "This fish contains carpotoxin. Definitely not safe for consumption."
diff_traits_inheritability = 50
reagents_to_add = list(/datum/reagent/toxin/carpotoxin = 4)
venom_mult = 6
/datum/fish_trait/toxin_immunity
name = "Toxin Immunity"
@@ -99,3 +99,85 @@
///It spins, and dimly glows in the dark.
/obj/item/fish/starfish/flop_animation()
DO_FLOATING_ANIM(src)
/obj/item/fish/baby_carp
name = "baby space carp"
desc = "A juvenile spawn of the dreaded space carp. Don't let the innocent looks fool you, they're aggressive little bastards."
icon_state = "baby_carp"
sprite_height = 3
sprite_width = 5
average_size = 35
average_weight = 550
stable_population = 7
required_fluid_type = AQUARIUM_FLUID_ANY_WATER
random_case_rarity = FISH_RARITY_VERY_RARE
required_temperature_min = 0
required_temperature_max = MIN_AQUARIUM_TEMP+200
safe_air_limits = null
fillet_type = /obj/item/food/fishmeat/carp/no_tox
fish_traits = list(
/datum/fish_trait/carnivore,
/datum/fish_trait/aggressive,
/datum/fish_trait/predator,
/datum/fish_trait/necrophage,
/datum/fish_trait/no_mating,
/datum/fish_trait/toxic/carpotoxin,
)
favorite_bait = list(
list(
FISH_BAIT_TYPE = FISH_BAIT_FOODTYPE,
FISH_BAIT_VALUE = MEAT,
),
)
disliked_bait = list(
list(
FISH_BAIT_TYPE = FISH_BAIT_FOODTYPE,
FISH_BAIT_VALUE = GRAIN|DAIRY,
),
)
beauty = FISH_BEAUTY_GREAT
/obj/item/fish/baby_carp/Initialize(mapload, apply_qualities = TRUE)
color = pick_weight(GLOB.carp_colors)
. = ..()
RegisterSignal(src, COMSIG_FISH_BEFORE_GROWING, PROC_REF(growth_checks))
RegisterSignal(src, COMSIG_FISH_FINISH_GROWING, PROC_REF(on_growth))
update_appearance(UPDATE_OVERLAYS)
/obj/item/fish/baby_carp/update_overlays()
. = ..()
var/mutable_appearance/eyes = mutable_appearance(icon, "baby_carp_eyes")
if(status == FISH_DEAD)
eyes.icon_state += "_dead"
else
eyes.appearance_flags = RESET_COLOR
. += eyes
///Determines the speed at which the carp grows based on how big it's
/obj/item/fish/baby_carp/update_size_and_weight(new_size = average_size, new_weight = average_weight)
. = ..()
var/growth_rate = 4.5 MINUTES
growth_rate *= clamp(size/average_size, 0.5, 2)
growth_rate *= clamp(weight/average_weight, 0.5, 2)
AddComponent(/datum/component/fish_growth, /mob/living/basic/carp/advanced, growth_rate)
/obj/item/fish/baby_carp/proc/growth_checks(datum/source, seconds_per_tick)
SIGNAL_HANDLER
var/hunger = CLAMP01((world.time - last_feeding) / feeding_frequency)
if(health <= initial(health) * 0.6 || hunger >= 0.6) //if too hurt or hungry, don't grow.
return COMPONENT_DONT_GROW
if(!isaquarium(loc))
return
var/obj/structure/aquarium/aquarium = loc
if(!aquarium.reproduction_and_growth) //the aquarium has breeding disabled
return COMPONENT_DONT_GROW
if(length(aquarium.get_fishes()) > AQUARIUM_MAX_BREEDING_POPULATION * 0.5) //check if there's enough room to maturate.
return COMPONENT_DONT_GROW
/obj/item/fish/baby_carp/proc/on_growth(datum/source, mob/living/basic/carp/result)
SIGNAL_HANDLER
//yes, this means that if we use a spraycan on the fish, the resulting space carp will be of spraycan color
result.set_greyscale(colors = list(color))
@@ -41,6 +41,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons())
/obj/item/fish/stingray = FISH_ICON_WEAPON,
/obj/item/fish/swordfish = FISH_ICON_WEAPON,
/obj/item/fish/zipzap = FISH_ICON_ELECTRIC,
/obj/item/knife/carp = FISH_ICON_WEAPON,
/obj/item/seeds/grass = FISH_ICON_SEED,
/obj/item/seeds/random = FISH_ICON_SEED,
/obj/item/storage/wallet = FISH_ICON_COIN,
@@ -193,6 +193,7 @@
fish_table = list(
// FISHING_DUD = 5, BUBBERSTATION CHANGE: NO DUDS. HOLY SHIT.
/obj/item/fish/starfish = 6,
/obj/item/fish/baby_carp = 6,
/obj/item/stack/ore/bluespace_crystal = 2,
/mob/living/basic/carp = 2,
)
@@ -580,6 +581,25 @@
var/picked_path = pick(seeds_to_draw_from)
return new picked_path(get_turf(fishing_spot))
/datum/fish_source/carp_rift
catalog_description = "Space Dragon Rifts"
radial_state = "carp"
fish_table = list(
FISHING_DUD = 3,
/obj/item/fish/baby_carp = 5,
/mob/living/basic/carp = 1,
/mob/living/basic/carp/passive = 1,
/mob/living/basic/carp/mega = 1,
/obj/item/clothing/head/fedora/carpskin = 1,
/obj/item/toy/plush/carpplushie = 1,
/obj/item/toy/plush/carpplushie/dehy_carp/peaceful = 1,
/obj/item/knife/carp = 1,
)
fish_counts = list(
/mob/living/basic/carp/mega = 2,
)
fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 18
/datum/fish_source/deepfryer
catalog_description = "Deep Fryers"
radial_state = "fryer"
@@ -96,6 +96,7 @@
AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("gnashes")))
AddComponent(/datum/component/regenerator, outline_colour = regenerate_colour)
AddComponent(/datum/component/profound_fisher)
if (tamer)
tamed(tamer, feedback = FALSE)
befriend(tamer)
@@ -62,6 +62,11 @@
/// Our wing flap action
var/datum/action/cooldown/mob_cooldown/wing_buffet/buffet
///Are currently sharkified or a plain space dragon?
var/shark_form = FALSE
///The amount of fish (weight) the space dragon has to eat to be sharkified and receive a cheevo for it.
var/fish_left = 15000 // 30 fish with a weight of 500.
/mob/living/basic/space_dragon/Initialize(mapload)
. = ..()
add_traits(list(TRAIT_SPACEWALK, TRAIT_FREE_HYPERSPACE_MOVEMENT, TRAIT_NO_FLOATING_ANIM, TRAIT_HEALS_FROM_CARP_RIFTS), INNATE_TRAIT)
@@ -70,6 +75,7 @@
AddElement(/datum/element/wall_tearer, tear_time = 4 SECONDS, reinforced_multiplier = 3, do_after_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION)
AddElement(/datum/element/door_pryer, pry_time = 4 SECONDS, interaction_key = DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION)
AddComponent(/datum/component/seethrough_mob)
AddComponent(/datum/component/profound_fisher, new /obj/item/fishing_rod/mob_fisher/dragon(src))
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
RegisterSignal(src, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed))
RegisterSignal(src, COMSIG_ATOM_PRE_EX_ACT, PROC_REF(on_exploded))
@@ -89,9 +95,33 @@
. = ..()
if(!isnull(chosen_colour))
return
if(client.get_award_status(/datum/award/achievement/misc/sharkdragon))
if(tgui_alert(src, "Shall you take the dragon form or the shark form?","Shark Form Unlocked", list("Dragon","Shark")) == "Shark")
sharkify()
rename_dragon()
select_colour()
/mob/living/basic/space_dragon/mind_initialize()
. = ..()
if(shark_form && mind.get_skill_level(/datum/skill/fishing) < SKILL_LEVEL_APPRENTICE)
mind.set_level(/datum/skill/fishing, SKILL_LEVEL_APPRENTICE, TRUE)
/mob/living/basic/space_dragon/proc/sharkify()
if(shark_form)
return
pixel_z -= 3
base_pixel_z -= 3
do_jitter_animation(150)
shark_form = TRUE
desc = "A piscine mutation of the fearsome leviathan whose flight defies modern physics. Said to be the other ultimate stage in the life cycle of the Space Carp."
icon_state = icon_state == icon_living ? "sharkdragon" : "sharkdragon_dead"
icon_living = "sharkdragon"
icon_dead = "sharkdragon_dead"
if(mind && mind.get_skill_level(/datum/skill/fishing) < SKILL_LEVEL_APPRENTICE)
mind.set_level(/datum/skill/fishing, SKILL_LEVEL_APPRENTICE, TRUE)
client?.give_award(/datum/award/achievement/misc/sharkdragon, src)
update_appearance()
/// Allows the space dragon to pick a funny name
/mob/living/basic/space_dragon/proc/rename_dragon()
var/chosen_name = sanitize_name(reject_bad_text(tgui_input_text(src, "What would you like your name to be?", "Choose Your Name", real_name, MAX_NAME_LEN)))
@@ -125,9 +155,9 @@
icon_state = icon_living
return
if (HAS_TRAIT(src, TRAIT_WING_BUFFET_TIRED))
icon_state = "spacedragon_gust_2"
icon_state = "[icon_living]_gust_2"
return
icon_state = "spacedragon_gust"
icon_state = "[icon_living]_gust"
/mob/living/basic/space_dragon/update_overlays()
. = ..()
@@ -139,7 +169,7 @@
else if (HAS_TRAIT(src, TRAIT_WING_BUFFET))
overlay_state = "overlay_gust"
var/mutable_appearance/overlay = mutable_appearance(icon, overlay_state)
var/mutable_appearance/overlay = mutable_appearance(icon, "[icon_living]_[overlay_state]")
overlay.appearance_flags = RESET_COLOR
. += overlay
@@ -157,6 +187,8 @@
if (DOING_INTERACTION(source, DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION))
balloon_alert(source, "busy!")
return COMPONENT_HOSTILE_NO_ATTACK
if(isfish(target))
INVOKE_ASYNC(src, PROC_REF(try_eat), target)
if (!isliving(target))
return
var/mob/living/living_target = target
@@ -166,14 +198,23 @@
return COMPONENT_HOSTILE_NO_ATTACK
/// Try putting something inside us
/mob/living/basic/space_dragon/proc/try_eat(mob/living/food)
/mob/living/basic/space_dragon/proc/try_eat(atom/movable/food)
balloon_alert(src, "swallowing...")
if (do_after(src, 3 SECONDS, target = food))
eat(food)
if(isliving(food))
eat(food)
else if(isfish(food))
eat_fish(food)
/// Succeed in putting something inside us
/mob/living/basic/space_dragon/proc/eat(mob/living/food)
adjust_health(-food.maxHealth * 0.25)
var/health_recovered = food.maxHealth * 0.25
if(shark_form)
if(istype(food, /mob/living/basic/carp))
health_recovered *= 1.75 // plus 7.5 points when eating advanced space carps (from the rift)
else
health_recovered *= 0.75 // minus 7.5 points when eating a human for example.
adjust_health(round(-health_recovered, 1))
if (QDELETED(food) || food.loc == src)
return FALSE
playsound(src, 'sound/effects/magic/demon_attack1.ogg', 60, TRUE)
@@ -182,6 +223,43 @@
food.forceMove(src)
return TRUE
/mob/living/basic/space_dragon/proc/eat_fish(obj/item/fish/fish)
//a standard fish weights about 500 units on average, rarely exceeds 2000 units, the amount healed is less than a one fiftyth of our total on average.
var/health_recovered = fish.weight * 0.014
if(shark_form)
health_recovered *= 2
else
fish_left -= fish.weight
if(fish_left <= 0)
addtimer(CALLBACK(src, PROC_REF(begin_sharkify)), 2 SECONDS)
fish_left = initial(fish_left) //prevent begin_sharkify from being called again by eating another fish.
adjust_health(round(-health_recovered, 1))
playsound(src, 'sound/effects/magic/demon_attack1.ogg', 40, TRUE)
visible_message(span_boldwarning("[src] swallows [fish] whole!"))
if(HAS_TRAIT(fish, TRAIT_YUCKY_FISH))
balloon_alert(src, "disgusting!")
to_chat(src, span_warning("that [fish.name] tasted awful, you feel like you're about to throw up..."))
addtimer(CALLBACK(src, PROC_REF(barf_contents)), 3 SECONDS)
qdel(fish)
/mob/living/basic/space_dragon/proc/begin_sharkify()
do_jitter_animation(300)
addtimer(CALLBACK(src, PROC_REF(sharkify)), 1.2 SECONDS)
visible_message(span_warning("[src] begins mutating!"))
/mob/living/basic/space_dragon/proc/barf_contents()
if(stat == DEAD)
return
new /obj/effect/decal/cleanable/vomit(loc)
playsound(src, 'sound/effects/splat.ogg', vol = 50, vary = TRUE)
visible_message(span_danger("[src] vomits up everything it ate so far!"))
for(var/atom/movable/eaten in src)
if(HAS_TRAIT(eaten, TRAIT_NOT_BARFABLE))
continue
eaten.forceMove(eaten.loc)
if(prob(90))
step(eaten, pick(GLOB.alldirs))
/mob/living/basic/space_dragon/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
if (isliving(arrived))
@@ -230,5 +308,10 @@
. = ..()
mind.add_antag_datum(/datum/antagonist/space_dragon)
/// The internal fishing rod of our space dragon
/obj/item/fishing_rod/mob_fisher/dragon
difficulty_modifier = -14
hook = /obj/item/fishing_hook/jaws
#undef REJECT_DARK_COLOUR_THRESHOLD
#undef DOAFTER_SOURCE_SPACE_DRAGON_INTERACTION
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 253 KiB