From a0582072476cbac20ea2c15c9b090983d1255ecb Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 Aug 2025 05:30:53 +0200 Subject: [PATCH] replaces the health variable for fishes with integrity (#92192) ## About The Pull Request Because fish is an item, it inherits the use of integrity from objects, however it also has its own health variable. For consistency, ~~damaging its integrity should also lower its health and healing it should also recover its integrity. Fish has a max integrity that's double its health. I've also renamed `adjust_health` to `set_health` since it doesn't adjust the health by the provided value but sets it to said value.~~ I've scrapped the latter to instead use integrity. ## Why It's Good For The Game A small bit of consistency. If you shoot a fish with a laser gun, wouldn't it die? (cherry picked from commit 940d73aeae39047e259f87e689299e070e9eea6d) --- code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/traits/_traits.dm | 1 + code/_globalvars/traits/admin_tooling.dm | 1 + code/datums/components/aquarium.dm | 2 +- code/datums/components/fish_growth.dm | 3 +- code/datums/elements/fish_safe_storage.dm | 4 +- code/game/objects/items/stacks/tape.dm | 4 + .../modules/fishing/aquarium/fish_analyzer.dm | 2 +- code/modules/fishing/fish/_fish.dm | 83 +++++++++++-------- code/modules/fishing/fish/fish_evolution.dm | 2 +- code/modules/fishing/fish/fish_traits.dm | 10 +-- code/modules/fishing/fish/types/air_space.dm | 2 +- code/modules/fishing/fish/types/anadromous.dm | 2 +- code/modules/fishing/fish/types/freshwater.dm | 2 +- code/modules/fishing/fish/types/mining.dm | 4 +- code/modules/fishing/fish/types/rift.dm | 14 ++-- code/modules/fishing/fish/types/ruins.dm | 2 +- code/modules/fishing/fish/types/saltwater.dm | 2 +- code/modules/fishing/fish/types/station.dm | 6 +- code/modules/fishing/fish/types/syndicate.dm | 4 +- code/modules/fishing/fishing_minigame.dm | 4 +- .../reagents/drinks/drink_reagents.dm | 6 +- .../chemistry/reagents/toxin_reagents.dm | 2 +- code/modules/unit_tests/fish_unit_tests.dm | 6 +- tgui/packages/tgui/interfaces/Aquarium.tsx | 6 +- 25 files changed, 101 insertions(+), 75 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 38500df0291..2c318497811 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -943,6 +943,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NO_WORN_ICON "no_worn_icon" /// Items with this trait will not appear when examined. #define TRAIT_EXAMINE_SKIP "examine_skip" +/// Objects with this trait cannot be repaired with duct tape +#define TRAIT_DUCT_TAPE_UNREPAIRABLE "duct_tape_unrepairable" //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 820d77d60d5..ed88a572b33 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -156,6 +156,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( // SKYRAT EDIT ADDITON END - Synthetic wounds /obj = list( "TRAIT_CONTRABAND" = TRAIT_CONTRABAND, + "TRAIT_DUCT_TAPE_UNREPAIRABLE" = TRAIT_DUCT_TAPE_UNREPAIRABLE, "TRAIT_SPEED_POTIONED" = TRAIT_SPEED_POTIONED, "TRAIT_WALLMOUNTED" = TRAIT_WALLMOUNTED, ), diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 36024e9f818..f29d2937a98 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -28,6 +28,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( ), /obj = list( "TRAIT_CONTRABAND" = TRAIT_CONTRABAND, + "TRAIT_DUCT_TAPE_UNREPAIRABLE" = TRAIT_DUCT_TAPE_UNREPAIRABLE, "TRAIT_SPEED_POTIONED" = TRAIT_SPEED_POTIONED, ), /mob = list( diff --git a/code/datums/components/aquarium.dm b/code/datums/components/aquarium.dm index 576852a471e..fd442427bbb 100644 --- a/code/datums/components/aquarium.dm +++ b/code/datums/components/aquarium.dm @@ -617,7 +617,7 @@ "fish_happiness" = fish.get_happiness_value(), "fish_icon" = fish::icon, "fish_icon_state" = fish::icon_state, - "fish_health" = fish.health, + "fish_alive" = fish.status == FISH_ALIVE, )) continue .["propData"] += list(list( diff --git a/code/datums/components/fish_growth.dm b/code/datums/components/fish_growth.dm index f4c835045e8..380a82912b8 100644 --- a/code/datums/components/fish_growth.dm +++ b/code/datums/components/fish_growth.dm @@ -72,8 +72,7 @@ var/obj/item/fish/fishie = result fishie.breeding_wait = source.breeding_wait fishie.last_feeding = source.last_feeding - var/health_percent = source.health / initial(source.health) - fishie.adjust_health(fishie.health * health_percent) + fishie.update_integrity(fishie.max_integrity * source.get_integrity_percentage()) else result = new result_type (location) if(location != source.loc) diff --git a/code/datums/elements/fish_safe_storage.dm b/code/datums/elements/fish_safe_storage.dm index a5eb5c56131..92416789148 100644 --- a/code/datums/elements/fish_safe_storage.dm +++ b/code/datums/elements/fish_safe_storage.dm @@ -51,5 +51,5 @@ ///Keep delaying hunger and breeding while in stasis, and also heal them. fish.last_feeding += seconds_per_tick SECONDS fish.breeding_wait += seconds_per_tick SECONDS - if(fish.health < initial(fish.health) * 0.65) - fish.adjust_health(fish.health + 0.75 * seconds_per_tick) + if(fish.get_health_percentage() < 0.65) + fish.repair_damage(0.75 * seconds_per_tick) diff --git a/code/game/objects/items/stacks/tape.dm b/code/game/objects/items/stacks/tape.dm index d06b2250ed2..62ac35ec728 100644 --- a/code/game/objects/items/stacks/tape.dm +++ b/code/game/objects/items/stacks/tape.dm @@ -186,6 +186,10 @@ if(!isobj(interacting_with) || iseffect(interacting_with)) return NONE + if(HAS_TRAIT(interacting_with, TRAIT_DUCT_TAPE_UNREPAIRABLE)) + user.balloon_alert(user, "cannot be repaired with duct tape!") + return ITEM_INTERACT_BLOCKING + var/obj/item/object_to_repair = interacting_with var/object_is_damaged = object_to_repair.get_integrity() < object_to_repair.max_integrity diff --git a/code/modules/fishing/aquarium/fish_analyzer.dm b/code/modules/fishing/aquarium/fish_analyzer.dm index 95b6b0f16c1..a89ac1456a6 100644 --- a/code/modules/fishing/aquarium/fish_analyzer.dm +++ b/code/modules/fishing/aquarium/fish_analyzer.dm @@ -118,7 +118,7 @@ "fish_name" = fishie.name, "fish_icon" = fishie.icon, "fish_icon_state" = fishie.base_icon_state, - "fish_health" = fishie.status == FISH_DEAD ? 0 : PERCENT(fishie.health/initial(fishie.health)), + "fish_health" = fishie.status == FISH_DEAD ? 0 : PERCENT(fishie.get_health_percentage()), "fish_size" = fishie.size, "fish_weight" = fishie.weight, "fish_food" = fishie.food.name, diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm index e6b9bfe8ef5..d6a6c7cb030 100644 --- a/code/modules/fishing/fish/_fish.dm +++ b/code/modules/fishing/fish/_fish.dm @@ -37,6 +37,9 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( //we handle slowdowns internally, and the fish weight modifier from materials already contributes to it. material_flags = MATERIAL_EFFECTS|MATERIAL_AFFECT_STATISTICS|MATERIAL_COLOR|MATERIAL_ADD_PREFIX|MATERIAL_NO_SLOWDOWN|MATERIAL_NO_EDIBILITY + max_integrity = 200 + integrity_failure = 0.5 + /// Flags for fish variables that would otherwise be TRUE/FALSE var/fish_flags = FISH_FLAG_SHOW_IN_CATALOG|FISH_DO_FLOP_ANIM|FISH_FLAG_EXPERIMENT_SCANNABLE @@ -75,8 +78,6 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( ///icon used when the fish is dead, ifset. var/icon_state_dead - /// Current fish health. Dies at 0. - var/health = 100 /// The message shown when the fish dies. var/death_text = "%SRC dies." @@ -210,14 +211,14 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( RegisterSignal(src, COMSIG_ATOM_TEMPORARY_ANIMATION_START, PROC_REF(on_temp_animation)) check_flopping() if(status != FISH_DEAD) - ADD_TRAIT(src, TRAIT_UNCOMPOSTABLE, REF(src)) //Composting a food that is not real food wouldn't work anyway. + ADD_TRAIT(src, TRAIT_UNCOMPOSTABLE, REF(src)) //Compost fish only when it's dead. START_PROCESSING(SSobj, src) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_FISH_STASIS), PROC_REF(enter_stasis)) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_FISH_STASIS), PROC_REF(exit_stasis)) //Adding this because not all fish have the gore foodtype that makes them automatically eligible for dna infusion. - ADD_TRAIT(src, TRAIT_VALID_DNA_INFUSION, INNATE_TRAIT) + add_traits(list(TRAIT_DUCT_TAPE_UNREPAIRABLE, TRAIT_VALID_DNA_INFUSION), INNATE_TRAIT) //stops new fish from being able to reproduce right away. breeding_wait = world.time + (breeding_timeout * NEW_FISH_BREEDING_TIMEOUT_MULT) @@ -343,7 +344,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( /obj/item/fish/proc/on_fish_cooked(datum/source, cooking_time) SIGNAL_HANDLER SHOULD_NOT_OVERRIDE(TRUE) - adjust_health(0) + damage_fish(max_integrity) //Remove the blood from the reagents holder and reward the player with some extra nutriment added to the fish. var/datum/reagent/consumable/nutriment/protein/protein = reagents.has_reagent(/datum/reagent/consumable/nutriment/protein, check_subtypes = TRUE) @@ -376,7 +377,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( /obj/item/fish/proc/on_fish_cooked_again(datum/source, cooking_time) SIGNAL_HANDLER if(!HAS_TRAIT(src, TRAIT_FISH_SURVIVE_COOKING)) - adjust_health(0) + damage_fish(max_integrity) if(cooking_time >= FISH_SAFE_COOKING_DURATION) well_cooked() @@ -409,7 +410,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( return bites_amount++ var/bites_to_finish = weight / FISH_WEIGHT_BITE_DIVISOR - adjust_health(health - (initial(health) / bites_to_finish) * 3) + damage_fish((max_integrity / bites_to_finish) * 3) flinch_on_eat(eater, feeder) /obj/item/fish/proc/flinch_on_eat(mob/living/eater, mob/living/feeder) @@ -533,7 +534,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment()) warnings += "drowning" - var/health_ratio = health / initial(health) + var/health_ratio = get_health_percentage() switch(health_ratio) if(0 to 0.25) warnings += "dying" @@ -992,7 +993,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( switch(new_status) if(FISH_ALIVE) status = FISH_ALIVE - health = initial(health) // since the fishe has been revived + repair_damage(max_integrity) regenerate_bites(bites_amount) last_feeding = world.time //reset hunger check_flopping() @@ -1027,10 +1028,6 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( if(!isnum(var_value) || var_value == 0) return FALSE update_size_and_weight(size, var_value) - if(NAMEOF(src, health)) - if(!isnum(var_value)) - return FALSE - adjust_health(health) if(NAMEOF(src, fish_flags)) var/old_fish_flags = fish_flags fish_flags = var_value @@ -1204,33 +1201,47 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( return TRUE /obj/item/fish/proc/process_health(seconds_per_tick) - var/health_change_per_second = 0 + var/health_change = 0 if(!proper_environment()) - health_change_per_second -= 2.5 //Dying here + health_change -= 2.5 //Dying here var/starvation_mult = get_starvation_mult() if(starvation_mult) - health_change_per_second -= 0.25 * starvation_mult //Starving + health_change -= 0.25 * starvation_mult //Starving else - health_change_per_second += 0.5 //Slowly healing + health_change += 0.5 //Slowly healing if(HAS_TRAIT(src, TRAIT_FISH_ON_TESLIUM)) - health_change_per_second -= 0.65 + health_change -= 0.65 - adjust_health(health + health_change_per_second * seconds_per_tick) + if(!health_change) + return -/obj/item/fish/proc/adjust_health(amount) - if(status == FISH_DEAD || amount == health) + health_change *= seconds_per_tick + if(health_change < 0) + damage_fish(health_change) + else + repair_damage(health_change) + +///Used to damage this fish while it's still alive. Prevents the fish from taking damage beyond the integrity_failure threshold +/obj/item/fish/proc/damage_fish(amount) + if(status == FISH_DEAD || amount <= 0) return - var/pre_health = health - var/initial_health = initial(health) - health = clamp(amount, 0, initial_health) - if(health <= 0) - set_status(FISH_DEAD) + var/current_integrity = get_integrity() + take_damage(min(amount, current_integrity - max_integrity * integrity_failure), sound_effect = FALSE, armour_penetration = 100) + +/// fish dies when its integrity reaches 50% +/obj/item/fish/atom_break(damage_flag) + . = ..() + set_status(FISH_DEAD) + +/obj/item/fish/repair_damage(amount) + . = ..() + if(!. || !bites_amount) return - if(amount < pre_health || !bites_amount) - return - var/health_to_pre_health_diff = amount - pre_health - var/init_health_to_pre_diff = initial_health - pre_health - var/bites_to_recover = bites_amount * (health_to_pre_health_diff / init_health_to_pre_diff) + var/current_integrity = get_integrity() + var/old_integrity = current_integrity - amount + var/old_max_integrity_diff = max_integrity - old_integrity + var/percent = (max_integrity - current_integrity) / old_max_integrity_diff + var/bites_to_recover = bites_amount * percent regenerate_bites(bites_to_recover) /obj/item/fish/proc/regenerate_bites(amount) @@ -1240,6 +1251,12 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( bites_amount -= amount generate_fish_reagents(amount) +/// returns a value between 0 and 1 representing how much integrity the fish has before dying (atom_break) +/obj/item/fish/proc/get_health_percentage() + var/max_health = max_integrity * (1 - integrity_failure) + var/death_thres = max_integrity - max_health + return CLAMP01((get_integrity() - death_thres) / max_health) + /// Returns tracked_fish_by_type but flattened and without the items in the blacklist, also shuffled if shuffle is TRUE. /obj/item/fish/proc/get_aquarium_fishes(shuffle = FALSE, blacklist) . = list() @@ -1257,7 +1274,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( return FALSE if(!being_targeted && length(get_aquarium_fishes()) >= AQUARIUM_MAX_BREEDING_POPULATION) return FALSE - return !HAS_TRAIT(loc, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH) && health >= initial(health) * 0.8 && stable_population >= 1 && world.time >= breeding_wait + return !HAS_TRAIT(loc, TRAIT_STOP_FISH_REPRODUCTION_AND_GROWTH) && get_health_percentage() >= 0.8 && stable_population >= 1 && world.time >= breeding_wait /obj/item/fish/proc/try_to_reproduce() if(!loc || !HAS_TRAIT(loc, TRAIT_IS_AQUARIUM)) @@ -1490,7 +1507,7 @@ GLOBAL_LIST_INIT(fish_compatible_fluid_types, list( happiness_value += 2 if(bites_amount) // ouch happiness_value -= 2 - if(health < initial(health) * 0.6) + if(get_health_percentage() < 0.6) happiness_value -= 1 return clamp(happiness_value, FISH_SAD, FISH_VERY_HAPPY) diff --git a/code/modules/fishing/fish/fish_evolution.dm b/code/modules/fishing/fish/fish_evolution.dm index 37ed269970f..baff1c32916 100644 --- a/code/modules/fishing/fish/fish_evolution.dm +++ b/code/modules/fishing/fish/fish_evolution.dm @@ -56,7 +56,7 @@ GLOBAL_LIST_EMPTY(fishes_by_fish_evolution) /datum/fish_evolution/proc/growth_checks(obj/item/fish/source, seconds_per_tick, growth) SIGNAL_HANDLER SHOULD_CALL_PARENT(TRUE) - if(source.health < initial(source.health) * 0.5) + if(source.get_health_percentage() < 0.5) return COMPONENT_DONT_GROW if(source.get_hunger() >= 0.5) //too hungry to grow return COMPONENT_DONT_GROW diff --git a/code/modules/fishing/fish/fish_traits.dm b/code/modules/fishing/fish/fish_traits.dm index 4aad9b002f5..d81cde8f85d 100644 --- a/code/modules/fishing/fish/fish_traits.dm +++ b/code/modules/fishing/fish/fish_traits.dm @@ -187,7 +187,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) var/turf/turf = get_turf(source) var/light_amount = turf.get_lumcount() if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) - source.adjust_health(source.health - 0.5 * seconds_per_tick) + source.damage_fish(0.5 * seconds_per_tick) /datum/fish_trait/nocturnal/apply_to_mob(mob/living/basic/mob) . = ..() @@ -301,10 +301,10 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) for(var/trait in resistance_traits) if(HAS_TRAIT(victim, trait)) continue - victim.adjust_health(victim.health - 3 * seconds_per_tick) //the victim may heal a bit but this will quickly kill + victim.damage_fish(3 * seconds_per_tick) //the victim may heal a bit but this will quickly kill emulsified = TRUE if(emulsified) - source.adjust_health(source.health + 3 * seconds_per_tick) + source.repair_damage(3 * seconds_per_tick) source.sate_hunger() /datum/fish_trait/emulsijack/apply_to_mob(mob/living/basic/mob) @@ -487,7 +487,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) /datum/fish_trait/toxic/proc/damage_predator(obj/item/fish/source, seconds_per_tick) SIGNAL_HANDLER - source.adjust_health(source.health - 3 * seconds_per_tick) + source.damage_fish(3 * seconds_per_tick) /datum/fish_trait/toxic/proc/stop_damaging(obj/item/fish/source) SIGNAL_HANDLER @@ -543,7 +543,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits()) continue source.loc.visible_message(span_warning("[source] violently [pick("whips", "bites", "attacks", "slams")] [victim]")) var/damage = round(rand(4, 20) * (source.size / victim.size)) //smaller fishes take extra damage. - victim.adjust_health(victim.health - damage) + victim.damage_fish(damage) return /datum/fish_trait/lubed diff --git a/code/modules/fishing/fish/types/air_space.dm b/code/modules/fishing/fish/types/air_space.dm index 3da406d366c..f10be963fef 100644 --- a/code/modules/fishing/fish/types/air_space.dm +++ b/code/modules/fishing/fish/types/air_space.dm @@ -215,7 +215,7 @@ /obj/item/fish/baby_carp/proc/growth_checks(datum/source, seconds_per_tick, growth, result_path) 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. + if(get_health_percentage() <= 0.6 || hunger >= 0.6) //if too hurt or hungry, don't grow. return COMPONENT_DONT_GROW if(!loc || !HAS_TRAIT(loc, TRAIT_IS_AQUARIUM)) diff --git a/code/modules/fishing/fish/types/anadromous.dm b/code/modules/fishing/fish/types/anadromous.dm index a46ef055c62..c0026331563 100644 --- a/code/modules/fishing/fish/types/anadromous.dm +++ b/code/modules/fishing/fish/types/anadromous.dm @@ -47,7 +47,7 @@ average_size = 100 average_weight = 2000 breeding_timeout = 4 MINUTES - health = 150 + max_integrity = 300 beauty = FISH_BEAUTY_GOOD required_fluid_type = AQUARIUM_FLUID_ANADROMOUS random_case_rarity = FISH_RARITY_RARE diff --git a/code/modules/fishing/fish/types/freshwater.dm b/code/modules/fishing/fish/types/freshwater.dm index 01c51b59b69..56f4b4d56bc 100644 --- a/code/modules/fishing/fish/types/freshwater.dm +++ b/code/modules/fishing/fish/types/freshwater.dm @@ -188,7 +188,7 @@ average_weight = 10 sprite_width = 3 sprite_height = 1 - health = 50 + max_integrity = 100 feeding_frequency = 1.5 MINUTES required_temperature_min = MIN_AQUARIUM_TEMP+15 required_temperature_max = MIN_AQUARIUM_TEMP+20 diff --git a/code/modules/fishing/fish/types/mining.dm b/code/modules/fishing/fish/types/mining.dm index bc515d66745..4a701dd72cc 100644 --- a/code/modules/fishing/fish/types/mining.dm +++ b/code/modules/fishing/fish/types/mining.dm @@ -71,7 +71,7 @@ /obj/item/fish/chasm_crab/proc/growth_checks(datum/source, seconds_per_tick, growth, result_path) SIGNAL_HANDLER var/hunger = get_hunger() - if(health <= initial(health) * 0.6 || hunger >= 0.6) //if too hurt or hungry, don't grow. + if(get_health_percentage() <= 0.6 || hunger >= 0.6) //if too hurt or hungry, don't grow. anger += growth * 2 return COMPONENT_DONT_GROW @@ -124,7 +124,7 @@ random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS required_fluid_type = AQUARIUM_FLUID_ANY_WATER min_pressure = HAZARD_LOW_PRESSURE - health = 150 + max_integrity = 300 stable_population = 3 grind_results = list(/datum/reagent/bone_dust = 10) fillet_type = /obj/item/stack/sheet/bone diff --git a/code/modules/fishing/fish/types/rift.dm b/code/modules/fishing/fish/types/rift.dm index 38da61dff65..c716c336e11 100644 --- a/code/modules/fishing/fish/types/rift.dm +++ b/code/modules/fishing/fish/types/rift.dm @@ -28,7 +28,7 @@ average_weight = 1500 food = /datum/reagent/bluespace feeding_frequency = 10 MINUTES - health = 50 + max_integrity = 100 death_text = "%SRC splinters apart into shards!" random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS fillet_type = /obj/item/stack/ore/bluespace_crystal @@ -136,7 +136,8 @@ required_temperature_min = BODYTEMP_COLD_DAMAGE_LIMIT // you mean just like a human? that's odd... required_temperature_max = BODYTEMP_HEAT_DAMAGE_LIMIT food = /datum/reagent/blood - health = 600 // apex predator + max_integrity = 800 // apex predator + integrity_failure = 0.25 random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS fillet_type = /obj/item/food/fishmeat/fish_tail num_fillets = 1 @@ -339,7 +340,7 @@ for(var/mob/living/fallen_mob in falling_movables) visible_message(span_danger("[src] flattens like a pancake as [fallen_mob] lands on top of it!")) - adjust_health(initial(health) * 0.1) // very durable + damage_fish(max_integrity * integrity_failure * 0.9) // very "durable" AddElement(/datum/element/squish, 15 SECONDS) fallen_mob.Paralyze(0.5 SECONDS) playsound(src, 'sound/effects/cartoon_sfx/cartoon_splat.ogg', 75) @@ -367,7 +368,7 @@ food = /datum/reagent/silicon feeding_frequency = 30 SECONDS - health = 160 + max_integrity = 320 death_text = "%SRC calcifies." random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS fillet_type = /obj/item/stack/sheet/mineral/diamond @@ -429,7 +430,8 @@ sprite_width = 12 sprite_height = 13 - health = 500 + max_integrity = 750 + integrity_failure = 0.33 death_text = "%SRC decomposes." random_case_rarity = FISH_RARITY_NOPE // hand-tuned to be a your worst enemy @@ -521,7 +523,7 @@ death_text = span_big(span_alertalien("%SRC emits a horrendous wailing as it perishes!")) random_case_rarity = FISH_RARITY_NOPE - health = 250 + max_integrity = 500 average_size = 30 average_weight = 2000 fillet_type = /obj/item/food/fishmeat/quality diff --git a/code/modules/fishing/fish/types/ruins.dm b/code/modules/fishing/fish/types/ruins.dm index 627bb5136a8..83d890ea991 100644 --- a/code/modules/fishing/fish/types/ruins.dm +++ b/code/modules/fishing/fish/types/ruins.dm @@ -14,7 +14,7 @@ fishing_difficulty_modifier = 30 required_fluid_type = AQUARIUM_FLUID_ANY_WATER min_pressure = HAZARD_LOW_PRESSURE - health = 300 + max_integrity = 600 stable_population = 1 //This means they can only crossbreed. grind_results = list(/datum/reagent/bone_dust = 5, /datum/reagent/consumable/liquidgibs = 5) fillet_type = /obj/item/stack/sheet/bone diff --git a/code/modules/fishing/fish/types/saltwater.dm b/code/modules/fishing/fish/types/saltwater.dm index 522befdeb50..cf1f1fa889a 100644 --- a/code/modules/fishing/fish/types/saltwater.dm +++ b/code/modules/fishing/fish/types/saltwater.dm @@ -167,7 +167,7 @@ average_weight = 4000 breeding_timeout = 4.5 MINUTES feeding_frequency = 4 MINUTES - health = 180 + max_integrity = 360 beauty = FISH_BEAUTY_EXCELLENT random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS required_fluid_type = AQUARIUM_FLUID_SALTWATER diff --git a/code/modules/fishing/fish/types/station.dm b/code/modules/fishing/fish/types/station.dm index a6842daf318..40196c375ec 100644 --- a/code/modules/fishing/fish/types/station.dm +++ b/code/modules/fishing/fish/types/station.dm @@ -51,7 +51,7 @@ stable_population = 8 average_size = 20 average_weight = 400 - health = 50 + max_integrity = 100 breeding_timeout = 2.5 MINUTES fish_traits = list(/datum/fish_trait/parthenogenesis, /datum/fish_trait/no_mating) required_temperature_min = MIN_AQUARIUM_TEMP+10 @@ -82,7 +82,7 @@ random_case_rarity = FISH_RARITY_VERY_RARE required_fluid_type = AQUARIUM_FLUID_ANADROMOUS stable_population = 4 - health = 150 + max_integrity = 300 fillet_type = /obj/item/slime_extract/grey fish_traits = list(/datum/fish_trait/toxin_immunity, /datum/fish_trait/crossbreeder) favorite_bait = list( @@ -263,7 +263,7 @@ sprite_height = 4 average_size = 150 average_weight = 6000 - health = 125 + max_integrity = 250 feeding_frequency = 5 MINUTES breeding_timeout = 5 MINUTES random_case_rarity = FISH_RARITY_NOPE diff --git a/code/modules/fishing/fish/types/syndicate.dm b/code/modules/fishing/fish/types/syndicate.dm index 83147031c4d..1d290aa1e18 100644 --- a/code/modules/fishing/fish/types/syndicate.dm +++ b/code/modules/fishing/fish/types/syndicate.dm @@ -104,7 +104,7 @@ average_weight = 2500 breeding_timeout = 4.25 MINUTES feeding_frequency = 3 MINUTES - health = 180 + max_integrity = 360 beauty = FISH_BEAUTY_GREAT random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS required_fluid_type = AQUARIUM_FLUID_FRESHWATER @@ -236,7 +236,7 @@ average_weight = 3000 breeding_timeout = 5 MINUTES feeding_frequency = 4 MINUTES - health = 180 + max_integrity = 360 random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS beauty = FISH_BEAUTY_GREAT fishing_difficulty_modifier = 20 diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index 0d42be519c2..b9ff7d00664 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -512,7 +512,7 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) SIGNAL_HANDLER if(istype(reward)) var/damage = CEILING((world.time - start_time)/10 * FISH_DAMAGE_PER_SECOND, 1) - reward.adjust_health(reward.health - damage) + reward.damage_fish(damage) /datum/fishing_challenge/proc/get_difficulty() var/list/difficulty_holder = list(0) @@ -599,7 +599,7 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) deltimer(next_phase_timer) if((FISHING_MINIGAME_RULE_KILL in special_effects) && ispath(reward_path,/obj/item/fish)) var/obj/item/fish/fish = reward_path - var/wait_time = (initial(fish.health) / FISH_DAMAGE_PER_SECOND) SECONDS + var/wait_time = ((initial(fish.max_integrity) * (1 - initial(fish.integrity_failure))) / FISH_DAMAGE_PER_SECOND) SECONDS addtimer(CALLBACK(src, PROC_REF(win_anyway)), wait_time, TIMER_DELETE_ME) else if(ismovable(reward_path)) var/atom/movable/reward = reward_path diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index bb6697a3909..0be0ca2b75f 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -228,7 +228,7 @@ /datum/reagent/milk/used_on_fish(obj/item/fish/fish) if(HAS_TRAIT(fish, TRAIT_FISH_MADE_OF_BONE)) - fish.adjust_health(fish.health + initial(fish.health) * max(fish.get_hunger() * 0.5, 0.12)) + fish.repair_damage(fish.max_integrity * max(fish.get_hunger() * 0.5, 0.12)) fish.sate_hunger() return TRUE @@ -998,12 +998,12 @@ . = ..() if(IS_REVOLUTIONARY(drinker)) to_chat(drinker, span_warning("Antioxidants are weakening your radical spirit!")) - + /datum/reagent/consumable/grenadine/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) . = ..() if(IS_REVOLUTIONARY(drinker)) drinker.set_dizzy_if_lower(10 SECONDS * REM * seconds_per_tick) - if(drinker.getStaminaLoss() < 80) + if(drinker.getStaminaLoss() < 80) drinker.adjustStaminaLoss(12, required_biotype = affected_biotype) //The pomegranate stops free radicals! Har har. /datum/reagent/consumable/parsnipjuice diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index b652961b1e2..aef4e1cb596 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -1269,7 +1269,7 @@ /datum/reagent/toxin/bonehurtingjuice/used_on_fish(obj/item/fish/fish) if(HAS_TRAIT(fish, TRAIT_FISH_MADE_OF_BONE)) - fish.adjust_health(fish.health - 30) + fish.damage_fish(30) return TRUE /datum/reagent/toxin/bungotoxin diff --git a/code/modules/unit_tests/fish_unit_tests.dm b/code/modules/unit_tests/fish_unit_tests.dm index e70ef1a7eb6..7d9df1df417 100644 --- a/code/modules/unit_tests/fish_unit_tests.dm +++ b/code/modules/unit_tests/fish_unit_tests.dm @@ -472,11 +472,11 @@ REMOVE_TRAIT(gourmet, TRAIT_FISH_EATER, TRAIT_FISH_TESTING) fish.attack(gourmet, gourmet) - TEST_ASSERT(gourmet.has_reagent(/datum/reagent/consumable/nutriment/protein), "Human doesn't have ingested protein after eating fish") - TEST_ASSERT(gourmet.has_reagent(/datum/reagent/blood), "Human doesn't have ingested blood after eating fish") + TEST_ASSERT(gourmet.has_reagent(/datum/reagent/consumable/nutriment/protein), "Human hasn't ingested protein when eating fish") + TEST_ASSERT(gourmet.has_reagent(/datum/reagent/blood), "Human hasn't ingested blood when eating fish") TEST_ASSERT(gourmet.has_reagent(/datum/reagent/fishdummy), "Human doesn't have the reagent from /datum/fish_trait/dummy after eating fish") - TEST_ASSERT_EQUAL(fish.status, FISH_DEAD, "The fish is not dead, despite having sustained enough damage that it should. health: [fish.health]") + TEST_ASSERT_EQUAL(fish.status, FISH_DEAD, "The fish is not dead, despite having sustained enough damage that it should. health: [PERCENT(fish.get_health_percentage())]%") var/obj/item/organ/stomach/belly = gourmet.get_organ_slot(ORGAN_SLOT_STOMACH) belly.reagents.clear_reagents() diff --git a/tgui/packages/tgui/interfaces/Aquarium.tsx b/tgui/packages/tgui/interfaces/Aquarium.tsx index 2ab43d3fcda..cc6f75eec00 100644 --- a/tgui/packages/tgui/interfaces/Aquarium.tsx +++ b/tgui/packages/tgui/interfaces/Aquarium.tsx @@ -44,7 +44,7 @@ type FishData = { fish_happiness: number; fish_icon: string; fish_icon_state: string; - fish_health: number; + fish_alive: BooleanLike; }; type PropData = { @@ -129,8 +129,8 @@ const FishInfo = (props: FishInfoProps) => { > {fish.fish_name} - 0 ? -4 : 1}> - {fish.fish_health > 0 ? ( + + {fish.fish_alive ? ( ) : (