Files
Paradise/code/modules/fish/fishtank.dm
T
FalseIncarnate 9480b77514 Sushi Update
Adds multiple types of sushi, made from various ingredients including
rice, egg, fish, and fish eggs.
- Most sushi recipes are made via table-crafting, though Tamago Sushi
requires a grill to prepare.

Adds multiple new types of fish for the fish tanks! Their eggs can be
purchased in the CritterCare vendor.
- Catfish
- Will periodically reduce the filth level of the tank, helping keep it
clean while you are busy.
- Feederfish
- Will sometimes sacrifice itself to add food to the tank for other
fish. Will not sacrifice if it is the last fish, or if the food level is
sufficiently high
- Shrimp
- Salmon
- Electric Eel
- Glofish
- Will produce light if the the tank light is off.

Adds fish items for each fish you can raise!
- Most fish are simply weak weapons you can slap people with.
- Sharks and baby carp do slightly higher damage, and make a biting
sound on hit
- Sharks can have their teeth removed by using a wirecutter on them.
- Toothless sharks no longer do more damage than normal fish, nor do
they make the bite sound
- Shark teeth will be used in some future recipes
- Salmon and catfish can be cut into filets with a knife
- Shrimp and feederfish can be eaten raw, though they aren't very
filling
- Glofish, you guessed it, glow! They give off light like a weaker,
green-colored flashlight.
- Clownfish are slippery like banana peels! HONK!
- Electric eels do not zap people, but will be used in a future crafting
recipe or two for an improvised stun weapon.

Tweaked the rate at which filth will accumulate in a tank, so hopefully
it won't be a full time job to maintain a single goldfish.
- Tanks with no fish will get dirty at a lower rate than before, and
will not continue to get dirty if the filth_level is 7.5 or higher
- Previously: 25% chance to increase by 0.1
- Now: 15% chance to increase by 0.05
- Tanks with at least one fish now will get dirty slightly less often
- Previously: 25% chance to increase by 0.1 with a 30% chance to
increase by 0.1 per fish if they ate that cycle
- Now: 10% chance to increase by 0.1 with a 25% chance to increase by
0.1 per fish if they ate that cycle

Using a fish net on a fish tank will now let you select a fish to
remove, instead of selecting one at random.
- Catching a fish with the fish net will now remove it from the tank and
drop the appropriate fish item at your feet.

Added support for special cooking via cooker machines (deepfryer, cereal
maker, old candy maker, old oven)
- Only the deepfryer currently utilizes it (as the other machines aren't
used currently)
- Inserting specific items will cook them into a new item instead of
simply frying them!

New deepfryer recipes:
- Tofu can be deepfried into Fried Tofu!
- Raw sticks (from slicing potatoes) can be deepfried into a bag of
chips!
- Bananas can be deepfried into Fried Bananas! (old recipe still
possible)
- Corn can be deepfried into a bag of Corn Chips!
- This is the same as a bag of chips, except Space Mexican
- Shrimp can be deepfried into Fried Shrimp!

Began phase 1 of re-organizing/dividing food icons and code into
multiple files
- The existing icon file was nearing capacity, and the code file was
incredibly long
- This re-organization will make it easier for coders to find, edit, and
group similar/related foods together, without worrying about overfilling
the food icon file
- This means we can add way more foods in the future without worrying
about the icon being full!

Sprites courtesy of FullOfSkittles, with a few of my own horrendous
recolors/edits.
- Not all of the new sprites are currently used, but are planned for use
in a near-future PR to further expand the food options available.
2015-08-23 00:22:31 -04:00

720 lines
31 KiB
Plaintext

//////////////////////////////
// Fish Tanks! //
//////////////////////////////
/obj/machinery/fishtank
name = "placeholder tank"
desc = "So generic, it might as well have no description at all."
icon = 'icons/obj/fish_items.dmi'
icon_state = "tank1"
density = 0
anchored = 0
throwpass = 0
var/tank_type = "" // Type of aquarium, used for icon updating
var/water_capacity = 0 // Number of units the tank holds (varies with tank type)
var/water_level = 0 // Number of units currently in the tank (new tanks start empty)
var/light_switch = 0 // 0 = off, 1 = on (off by default)
var/filth_level = 0.0 // How dirty the tank is (max 10)
var/lid_switch = 0 // 0 = open, 1 = closed (open by default)
var/max_fish = 0 // How many fish the tank can support (varies with tank type, 1 fish per 50 units sounds reasonable)
var/food_level = 0 // Amount of fishfood floating in the tank (max 10)
var/fish_count = 0 // Number of fish in the tank
var/list/fish_list = null // Tracks the current types of fish in the tank
var/egg_count = 0 // How many fish eggs can be harvested from the tank (capped at the max_fish value)
var/list/egg_list = null // Tracks the current types of harvestable eggs in the tank
var/has_lid = 0 // 0 if the tank doesn't have a lid/light, 1 if it does
var/max_health = 0 // Can handle a couple hits
var/cur_health = 0 // Current health, starts at max_health
var/leaking = 0 // 0 if not leaking, 1 if minor leak, 2 if major leak (not leaking by default)
var/shard_count = 0 // Number of glass shards to salvage when broken (1 less than the number of sheets to build the tank)
/obj/machinery/fishtank/bowl
name = "fish bowl"
desc = "A small bowl capable of housing a single fish, commonly found on desks. This one has a tiny treasure chest in it!"
icon_state = "bowl1"
density = 0 // Small enough to not block stuff
anchored = 0 // Small enough to move even when filled
throwpass = 1 // Just like at the county fair, you can't seem to throw the ball in to win the goldfish
pass_flags = PASSTABLE // Small enough to pull onto a table
tank_type = "bowl"
water_capacity = 50 // Not very big, therefore it can't hold much
max_fish = 1 // What a lonely fish
has_lid = 0
max_health = 15 // Not very sturdy
cur_health = 15
shard_count = 0 // No salvageable shards
/obj/machinery/fishtank/tank
name = "fish tank"
desc = "A large glass tank designed to house aquatic creatures. Contains an integrated water circulation system."
icon = 'icons/obj/fish_items.dmi'
icon_state = "tank1"
density = 1
anchored = 1
throwpass = 1 // You can throw objects over this, despite it's density, because it's short enough.
tank_type = "tank"
water_capacity = 200 // Decent sized, holds almost 2 full buckets
max_fish = 4 // Room for a few fish
has_lid = 1
max_health = 50 // Average strength, will take a couple hits from a toolbox.
cur_health = 50
shard_count = 2
/obj/machinery/fishtank/wall
name = "wall aquarium"
desc = "This aquarium is massive! It completely occupies the same space as a wall, and looks very sturdy too!"
icon_state = "wall1"
density = 1
anchored = 1
throwpass = 0 // This thing is the size of a wall, you can't throw past it.
tank_type = "wall"
water_capacity = 500 // This thing fills an entire tile, it holds a lot.
max_fish = 10 // Plenty of room for a lot of fish
has_lid = 1
max_health = 100 // This thing is a freaking wall, it can handle abuse.
cur_health = 100
shard_count = 3
//////////////////////////////
// VERBS & PROCS //
//////////////////////////////
/obj/machinery/fishtank/verb/toggle_lid_verb()
set name = "Toggle Tank Lid"
set category = "Object"
set src in view(1)
toggle_lid(usr)
/obj/machinery/fishtank/proc/toggle_lid(var/mob/living/user)
lid_switch = !lid_switch
update_icon()
/obj/machinery/fishtank/verb/toggle_light_verb()
set name = "Toggle Tank Light"
set category = "Object"
set src in view(1)
toggle_light(usr)
/obj/machinery/fishtank/proc/toggle_light(var/mob/living/user)
light_switch = !light_switch
if(light_switch)
set_light(2,2,"#a0a080")
else
set_light(0)
//////////////////////////////
// NEW() PROCS //
//////////////////////////////
/obj/machinery/fishtank/New()
..()
fish_list = new/list()
egg_list = new/list()
if(!has_lid) //Tank doesn't have a lid/light, remove the verbs for then
verbs -= /obj/machinery/fishtank/verb/toggle_lid_verb
verbs -= /obj/machinery/fishtank/verb/toggle_light_verb
/obj/machinery/fishtank/tank/New()
..()
if(prob(5)) //5% chance to get the castle decoration
icon_state = "tank2"
//////////////////////////////
// ICON PROCS //
//////////////////////////////
/obj/machinery/fishtank/update_icon()
overlays.Cut()
//Update Alert Lights
if(has_lid) //Skip the alert lights for aquariums that don't have lids (fishbowls)
if(egg_count > 0) //There is at least 1 egg to harvest
overlays += "over_egg"
if(lid_switch == 1) //Lid is closed, lid status light is red
overlays += "over_lid_1"
else //Lid is open, lid status light is green
overlays += "over_lid_0"
if(food_level > 5) //Food_level is high and isn't a concern yet
overlays += "over_food_0"
else if(food_level > 2) //Food_level is starting to get low, but still above the breeding threshold
overlays += "over_food_1"
else //Food_level is below breeding threshold, or fully consumed, feed the fish!
overlays += "over_food_2"
overlays += "over_leak_[leaking]" //Green if we aren't leaking, light blue and slow blink if minor link, dark blue and rapid flashing for major leak
//Update water overlay
if(water_level == 0) return //Skip the rest of this if there is no water in the aquarium
var/water_type = "_clean" //Default to clean water
if(filth_level > 5) water_type = "_dirty" //Show dirty water above filth_level 5 (breeding threshold)
if(water_level > (water_capacity * 0.85)) //Show full if the water_level is over 85% of water_capacity
overlays += "over_[tank_type]_full[water_type]"
else if(water_level > (water_capacity * 0.35)) //Show half-full if the water_level is over 35% of water_capacity
overlays += "over_[tank_type]_half[water_type]"
return
//////////////////////////////
// PROCESS PROC //
//////////////////////////////
//Stops atmos from passing wall tanks, since they are effectively full-windows.
/obj/machinery/fishtank/wall/CanAtmosPass(var/turf/T)
return 0
/obj/machinery/fishtank/process()
//Start by counting fish in the tank
fish_count = 0
for(var/fish in fish_list)
if(fish)
fish_count ++
//Check if the water level can support the current number of fish
if((fish_count * 50) > water_level)
if(prob(50)) //Not enough water for all the fish, chance to kill one
kill_fish() //Chance passed, kill a random fish
filth_level += 2 //Dead fish raise the filth level quite a bit, reflect this
//Check filth_level
check_filth_level()
if(filth_level == 10 && fish_count > 0) //This tank is nasty and possibly unsuitable for fish if any are in it
if(prob(30)) //Chance for a fish to die each cycle while the tank is this nasty
kill_fish() //Kill a random fish, don't raise filth level since we're at cap already
//Check breeding conditions
if(fish_count >=2 && egg_count < max_fish) //Need at least 2 fish to breed, but won't breed if there are as many eggs as max_fish
if(food_level > 2 && filth_level <=5) //Breeding is going to use extra food, and the filth_level shouldn't be too high
if(prob(((fish_count - 2) * 5)+10)) //Chances increase with each additional fish, 10% base + 5% per additional fish
egg_count ++ //A new set of eggs were laid, increase egg_count
egg_list.Add(select_egg_type()) //Add the new egg to the egg_list for storage
food_level -= 2 //Remove extra food for the breeding process
//Handle standard food and filth adjustments
check_food_level()
var/ate_food = 0
if(food_level > 0 && prob(50)) //Chance for the fish to eat some food
if(food_level >= (fish_count * 0.1)) //If there is at least enough food to go around, feed all the fish
food_level -= fish_count * 0.1
else //Use up the last of the food
food_level = 0
ate_food = 1
check_food_level()
if(water_level > 0) //Don't dirty the tank if it has no water
if(fish_count == 0) //If the tank has no fish, algae growth can occur
if(filth_level < 7.5 && prob(15)) //Algae growth is a low chance and cannot exceed filth_level of 7.5
filth_level += 0.05 //Algae growth is slower than fish filth build-up
else if(filth_level < 10 && prob(10)) //Chance for the tank to get dirtier if the filth_level isn't 10
if(ate_food && prob(25)) //If they ate this cycle, there is an additional chance they make a bigger mess
filth_level += fish_count * 0.1
else //If they didn't make the big mess, make a little one
filth_level += 0.1
check_filth_level()
//Handle special interactions
handle_special_interactions()
//Handle water leakage from damage
if(water_level > 0) //Can't leak water if there is no water in the tank
if(leaking == 2) //At or below 25% health, the tank will lose 10 water_level per cycle (major leak)
water_level -= 10
else if(leaking == 1) //At or below 50% health, the tank will lose 1 water_level per cycle (minor leak)
water_level -= 1
check_water_level()
//////////////////////////////
// SUPPORT PROCS //
//////////////////////////////
/obj/machinery/fishtank/proc/handle_special_interactions()
var/glo_light = 0
for(var/fish in fish_list)
switch(fish)
if("catfish") //Catfish have a small chance of cleaning some filth since they are a bottom-feeder
if((filth_level > 0) && prob(30))
filth_level -= 0.1
if("feederfish") //Feeder fish have a small chance of sacrificing themselves to produce some food
if(fish_count < 2) //Don't sacrifice the last fish, there's nothing to eat it
continue
if(food_level <= 5 && prob(25))
kill_fish("feederfish") //Kill the fish to reflect it's sacrifice, but don't increase the filth_level
food_level += 1 //The corpse became food for the other fish, ecology at it's finest
if("glofish")
glo_light++
if(!light_switch && (glo_light > 0))
set_light(2,glo_light,"#99FF66")
check_food_level()
check_filth_level()
check_water_level()
/obj/machinery/fishtank/proc/check_water_level()
if(water_level < 0) //Water_level cannot be negative, set it to 0 if it is
water_level = 0
if(water_level > water_capacity) //Water_level cannot exceed capacity, set it to capacity if it does
water_level = water_capacity
update_icon()
/obj/machinery/fishtank/proc/check_filth_level()
if(filth_level < 0) //Filth_level cannot be negative, set it to 0 if it is
filth_level = 0
if(filth_level > 10) //Filth_level cannot exceed 10 (cap), set it to 10 if it does
filth_level = 10
/obj/machinery/fishtank/proc/check_food_level()
if(food_level < 0) //Food_level cannot be negative, set it to 0 if it is
food_level = 0
if(food_level > 10) //Food_level cannot exceed 10 (cap), set it to 10 if it does
food_level = 10
/obj/machinery/fishtank/proc/check_health()
//Max value check
if(cur_health > max_health) //Cur_health cannot exceed max_health, set it to max_health if it does
cur_health = max_health
//Leaking status check
if(cur_health <= (max_health * 0.25)) //Major leak at or below 25% health (-10 water/cycle)
leaking = 2
else if(cur_health <= (max_health * 0.5)) //Minor leak at or below 50% health (-1 water/cycle)
leaking = 1
else //Not leaking above 50% health
leaking = 0
//Destruction check
if(cur_health <= 0) //The tank is broken, destroy it
destroy()
/obj/machinery/fishtank/proc/kill_fish(var/type = null)
//Check if we were passed a fish to kill, otherwise kill a random one
if(type)
fish_list.Remove(type) //Kill a fish of the specified type
fish_count -- //Lower fish_count to reflect the death of a fish, so the everything else works fine
else
fish_list.Remove(pick(fish_list)) //Kill a random fish
fish_count -- //Lower fish_count to reflect the death of a fish, so the everything else works fine
/obj/machinery/fishtank/proc/add_fish(var/type = null)
//Check if we were passed a fish type
if(type)
fish_list.Add("[type]") //Add a fish of the specified type
fish_count ++ //Increase fish_count to reflect the introduction of a fish, so the everything else works fine
//Announce the new fish
src.visible_message("A new [type] has hatched in \the [src]!")
//Null type fish are dud eggs, give a message to inform the player
else
usr << "The eggs disolve in the water. They were duds!"
/obj/machinery/fishtank/proc/select_egg_type()
var/fish = pick(fish_list) //Select a fish from the fish in the tank
if(prob(25)) //25% chance to be a dud (blank) egg
fish = "dud"
var/obj/item/fish_eggs/egg_path = null //Create empty variable to receive the egg_path
egg_path = fish_eggs_list[fish] //Locate the corresponding path from fish_eggs_list that matches the fish
if(!egg_path) //The fish wasn't located in the fish_eggs_list, potentially due to a typo, so return a dud egg
return /obj/item/fish_eggs
else //The fish was located in the fish_eggs_list, so return the proper egg
return egg_path
/obj/machinery/fishtank/proc/harvest_eggs(var/mob/user)
if(!egg_count) //Can't harvest non-existant eggs
return
if(egg_count > max_fish) //Make sure the number of eggs doesn't exceed the max_fish for the tank
egg_count = max_fish //If you somehow exceeded the cap, set the egg_count to max, destroy the excess later
while(egg_count > 0) //Loop until you've harvested all the eggs
var/obj/item/fish_eggs/egg = pick(egg_list) //Select an egg at random
egg = new egg(get_turf(user)) //Spawn the egg at the user's feet
egg_list.Remove(egg) //Remove the egg from the egg_list
egg_count -- //Decrease the egg_count and begin again
egg_list.Cut() //Destroy any excess eggs, clearing the egg_list
/obj/machinery/fishtank/proc/harvest_fish(var/mob/user)
if(!fish_count) //Can't catch non-existant fish!
usr << "There are no fish in \the [src] to catch!"
return
var/caught_fish
caught_fish = input("Select a fish to catch.", "Fishing", caught_fish) in fish_list //Select a fish from the tank
if(caught_fish)
var/dead_fish = null
dead_fish = fish_items_list[caught_fish] //Locate the appropriate fish_item for the caught fish
if(!dead_fish) //No fish_item found, possibly due to typo or not being listed. Do nothing.
return
kill_fish(caught_fish) //Kill the caught fish from the tank
user.visible_message("[user.name] harvests \a [caught_fish] from \the [src].", "You scoop \a [caught_fish] out of \the [src].")
new dead_fish(get_turf(user)) //Spawn the appropriate fish_item at the user's feet.
/obj/machinery/fishtank/proc/destroy(var/deconstruct = 0)
var/turf/T = get_turf(src) //Store the tank's turf for atmos updating after deletion of tank
if(!deconstruct) //Check if we are deconstructing or breaking the tank
var/shards_left = shard_count
while(shards_left > 0) //Produce the appropriate number of glass shards
new /obj/item/weapon/shard(get_turf(src))
shards_left --
if(water_level) //Spill any water that was left in the tank when it broke
spill_water()
else //We are deconstructing, make glass sheets instead of shards
var/sheets = shard_count + 1 //Deconstructing it salvages all the glass used to build the tank
new /obj/item/stack/sheet/glass(get_turf(src), sheets) //Produce the appropriate number of glass sheets, in a single stack
qdel(src) //QDel the tank and it's contents
T.air_update_turf(1) //Update the air for the turf, to avoid permanent atmos sealing with wall tanks
/obj/machinery/fishtank/proc/spill_water()
switch(tank_type)
if("bowl") //Fishbowl: Wets it's own tile
var/turf/T = get_turf(src)
if(!istype(T, /turf/simulated)) return
var/turf/simulated/S = T
S.MakeSlippery()
if("tank") //Fishtank: Wets it's own tile and the 4 adjacent tiles (cardinal directions)
var/turf/ST = get_turf(src)
if(istype(ST, /turf/simulated))
var/turf/simulated/ST2 = ST
ST2.MakeSlippery()
var/list/L = ST.CardinalTurfs()
for(var/turf/T in L)
if(!istype(T, /turf/simulated)) continue
var/turf/simulated/S = T
S.MakeSlippery()
if("wall") //Wall-tank: Wets it's own tile and the surrounding 8 tiles (3x3 square)
for(var/turf/T in trange(1, src.loc))
if(!istype(T, /turf/simulated)) continue
var/turf/simulated/S = T
S.MakeSlippery()
////////////////////////////// Note from FalseIncarnate:
// EXAMINE PROC // This proc is massive, messy, and probably could be handled better.
////////////////////////////// Feel free to try cleaning it up if you think of a better way to do it.
/obj/machinery/fishtank/examine()
..()
var/examine_message = ""
//Approximate water level
if(water_level == 0)
examine_message += "\The [src] is empty! "
else if(water_level < water_capacity * 0.1)
examine_message += "\The [src] is nearly empty! "
else if(water_level <= water_capacity * 0.25)
examine_message += "\The [src] is about one-quarter filled. "
else if(water_level <= water_capacity * 0.5)
examine_message += "\The [src] is about half filled. "
else if(water_level <= water_capacity * 0.75)
examine_message += "\The [src] is about three-quarters filled. "
else if(water_level < water_capacity)
examine_message += "\The [src] is nearly full! "
else if (water_level == water_capacity)
examine_message += "\The [src] is full! "
//Approximate filth level
if(filth_level == 0)
examine_message += "[src] is spotless! "
else if(filth_level <= 2.5)
examine_message += "[src] looks like the glass has been smudged. "
else if(filth_level <= 5) //This is the breeding threshold
examine_message += "[src] has some algae growth in it. "
else if(filth_level <= 7.5)
examine_message += "[src] has a lot of algae growth in it. "
else if(filth_level < 10)
examine_message += "[src] is getting hard to see into! Someone should clean it soon! "
else if(filth_level == 10)
examine_message += "[src] is absolutely disgusting! Someone should clean it NOW! "
//Approximate food level
if(!fish_count) //Check if there are fish in the tank
if(food_level > 0) //Don't report a tank that has neither fish nor food in it
examine_message += "There's some food in [src], but no fish! "
else //We've got fish, report the food level
if(food_level == 0)
examine_message += "The fish look very hungry! "
else if(food_level < 2)
examine_message += "The fish are nibbling on the last of their food. "
else if(food_level < 10) //Breeding is possible
examine_message += "The fish seem happy! "
else if(food_level == 10)
examine_message += "There is a solid layer of fish food at the top. "
//Report the number of harvestable eggs
if(egg_count) //Don't bother if there isn't any eggs
examine_message += "There are [egg_count] eggs able to be harvested! "
//Report the number and types of live fish if there is water in the tank
if(fish_count == 0)
examine_message += "\The [src] doesn't contain any live fish. "
else
//Build a message reporting the types of fish
var/fish_num = fish_count
var/message = "You spot "
while(fish_num > 0)
if(fish_count > 1 && fish_num == 1) //If there were at least 2 fish, and this is the last one, add "and" to the message
message += "and "
message += "a [fish_list[fish_num]]"
fish_num --
if(fish_num > 0) //There's more fish, add a comma to the message
message +=", "
message +="." //No more fish, end the message with a period
//Display the number of fish and previously constructed message
examine_message += "\The [src] contains [fish_count] live fish. [message] "
//Report lid state for tanks and wall-tanks
if(has_lid) //Only report if the tank actually has a lid
//Report lid state
if(lid_switch)
examine_message += "The lid is closed. "
else
examine_message += "The lid is open. "
//Report if the tank is leaking/cracked
if(water_level > 0) //Tank has water, so it's actually leaking
if(leaking == 1) examine_message += "\The [src] is leaking."
if(leaking == 2) examine_message += "\The [src] is leaking profusely!"
else //No water, report the cracks instead
if(leaking == 1) examine_message += "\The [src] is cracked."
if(leaking == 2) examine_message += "\The [src] is nearly shattered!"
//Finally, report the full examine_message constructed from the above reports
usr << "[examine_message]"
//////////////////////////////
// ATACK PROCS //
//////////////////////////////
/obj/machinery/fishtank/attack_animal(mob/living/simple_animal/M as mob)
if(istype(M, /mob/living/simple_animal/pet/cat))
if(M.a_intent == "help") //Cats can try to fish in open tanks on help intent
if(lid_switch) //Can't fish in a closed tank. Fishbowls are ALWAYS open.
M.visible_message("[M.name] stares at into \the [src] while sitting perfectly still.", "The lid is closed, so you stare into \the [src] intently.")
else
if(fish_count) //Tank must actually have fish to try catching one
M.visible_message("[M.name] leaps up onto \the[src] and attempts to fish through the opening!", "You jump up onto \the [src] and begin fishing through the opening!")
spawn(10)
if(water_level && prob(45)) //If there is water, there is a chance the cat will slip, Syndicat will spark like E-N when this happens
M.visible_message("[M.name] slipped and got soaked!", "You slipped and got soaked!")
if(istype(M, /mob/living/simple_animal/pet/cat/Syndi))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
else //No water or didn't slip, get that fish!
M.visible_message("[M.name] catches and devours a live fish!", "You catch and devour a live fish, yum!")
kill_fish() //Kill a random fish
M.health = M.maxHealth //Eating fish heals the predator
else
usr << "There are no fish in [src]!"
else
attack_generic(M, M.harm_intent_damage)
else if(istype(M, /mob/living/simple_animal/hostile/bear))
if(M.a_intent == "help") //Bears can try to fish in open tanks on help intent
if(lid_switch) //Can't fish in a closed tank. Fishbowls are ALWAYS open.
M.visible_message("[M.name] scrapes it's claws along \the [src]'s lid.", "The lid is closed, so you scrape your claws against \the [src]'s lid.")
else
if(fish_count) //Tank must actually have fish to try catching one
M.visible_message("[M.name] reaches into \the[src] and attempts to fish through the opening!", "You reach into \the [src] and begin fishing through the opening!")
spawn(5)
if(water_level && prob(5)) //Bears are good at catching fish, only a 5% chance to fail
M.visible_message("[M.name] swipes at the water!", "You just barely missed that fish!")
else //No water or didn't slip, get that fish!
M.visible_message("[M.name] catches and devours a live fish!", "You catch and devour a live fish, yum!")
kill_fish() //Kill a random fish
M.health = M.maxHealth //Eating fish heals the predator
else
usr << "There are no fish in [src]!"
else
attack_generic(M, M.harm_intent_damage)
else
if(M.melee_damage_upper > 0) //If the simple_animal has a melee_damage_upper defined, use that for the damage
attack_generic(M, M.melee_damage_upper)
else if(M.a_intent == "harm") //Let any simple_animal try to break tanks when on harm intent
if(M.harm_intent_damage <= 0) return //If it doesn't do damage, don't bother with the attack
attack_generic(M, M.harm_intent_damage)
check_health()
/obj/machinery/fishtank/attack_alien(mob/living/user as mob)
if(islarva(user)) return
attack_generic(user, 15)
/obj/machinery/fishtank/attack_slime(mob/living/user as mob)
var/mob/living/carbon/slime/S = user
if (!S.is_adult)
return
attack_generic(user, rand(10, 15))
/obj/machinery/fishtank/attack_hand(mob/user as mob)
if(HULK in user.mutations)
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
user.visible_message("<span class='danger'>[user] smashes through [src]!</span>")
destroy()
else if (usr.a_intent == "harm")
user.changeNext_move(CLICK_CD_MELEE)
playsound(get_turf(src), 'sound/effects/glassknock.ogg', 80, 1)
usr.visible_message("<span class='danger'>[usr.name] bangs against the [src.name]!</span>", \
"<span class='danger'>You bang against the [src.name]!</span>", \
"You hear a banging sound.")
else
user.changeNext_move(CLICK_CD_MELEE)
playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1)
usr.visible_message("[usr.name] taps on the [src.name].", \
"You tap on the [src.name].", \
"You hear a knocking sound.")
return
/obj/machinery/fishtank/proc/hit(var/damage, var/sound_effect = 1)
cur_health = max(0, cur_health - damage)
if(sound_effect)
playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
check_health()
/obj/machinery/fishtank/proc/attack_generic(mob/living/user as mob, damage = 0) //used by attack_alien, attack_animal, and attack_slime
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src)
cur_health -= damage
if(cur_health <= 0)
user.visible_message("<span class='danger'>[user] smashes through \the [src]!</span>")
destroy()
else //for nicer text~
user.visible_message("<span class='danger'>[user] smashes into \the [src]!</span>")
playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
check_health()
/obj/machinery/fishtank/attackby(var/obj/item/O, var/mob/user as mob)
//Welders repair damaged tanks on help intent, damage on all others
if(istype(O, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/W = O
if(user.a_intent == "help")
if(W.isOn())
if(cur_health < max_health)
usr << "You repair some of the cracks on \the [src]."
cur_health += 20
check_health()
else
usr << "There is no damage to fix!"
else
if(cur_health < max_health)
usr << "[W.name] must on to repair this damage."
else
user.changeNext_move(CLICK_CD_MELEE)
hit(W.force)
return
//Open reagent containers add and remove water
if(O.is_open_container())
if(istype(O, /obj/item/weapon/reagent_containers/glass))
if(lid_switch)
usr << "Open the lid on \the [src] first!"
return
var/obj/item/weapon/reagent_containers/glass/C = O
//Containers with any reagents will get dumped in
if(C.reagents.total_volume)
var/water_value = 0
water_value += C.reagents.get_reagent_amount("water") //Water is full value
water_value += C.reagents.get_reagent_amount("holywater") *1.1 //Holywater is (somehow) better. Who said religion had to make sense?
water_value += C.reagents.get_reagent_amount("tonic") * 0.25 //Tonic water is 25% value
water_value += C.reagents.get_reagent_amount("sodawater") * 0.50 //Sodawater is 50% value
water_value += C.reagents.get_reagent_amount("fishwater") * 0.75 //Fishwater is 75% value, to account for the fish poo
water_value += C.reagents.get_reagent_amount("ice") * 0.80 //Ice is 80% value
var/message = ""
if(!water_value) //The container has no water value, clear everything in it
message = "The filtration process removes everything, leaving the water level unchanged."
C.reagents.clear_reagents()
else
if(water_level == water_capacity)
usr << "[src] is already full!"
return
else
message = "The filtration process purifies the water, raising the water level."
water_level += water_value
if(water_level == water_capacity)
message += " You filled \the [src] to the brim!"
if(water_level > water_capacity)
message += " You overfilled \the [src] and some water runs down the side, wasted."
C.reagents.clear_reagents()
check_water_level()
user.visible_message("[user.name] pours the contents of [C.name] into \the [src].", "[message]")
return
//Empty containers will scoop out water, filling the container as much as possible from the water_level
else
if(water_level == 0)
usr << "[src] is empty!"
else
if(water_level >= C.volume) //Enough to fill the container completely
C.reagents.add_reagent("fishwater", C.volume)
water_level -= C.volume
user.visible_message("[user.name] scoops out some water from \the [src].", "You completely fill [C.name] from \the [src].")
else //Fill the container as much as possible with the water_level
C.reagents.add_reagent("fishwater", water_level)
water_level = 0
user.visible_message("[user.name] scoops out some water from \the [src].", "You fill [C.name] with the last of the water in \the [src].")
check_water_level()
return
//Wrenches can deconstruct empty tanks, but not tanks with any water. Kills any fish left inside and destroys any unharvested eggs in the process
if(istype(O, /obj/item/weapon/wrench))
if(water_level == 0)
usr << "<span class='notice'>Now disassembling [src].</span>"
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
if(do_after(user,50))
destroy(1)
else
usr << "[src] must be empty before you disassemble it!"
return
//Fish eggs
else if(istype(O, /obj/item/fish_eggs))
var/obj/item/fish_eggs/egg = O
//Don't add eggs if there is no water (they kinda need that to live)
if(water_level == 0)
usr << "[src] has no water; [egg.name] won't hatch without water!"
else
//Don't add eggs if the tank already has the max number of fish
if(fish_count >= max_fish)
usr << "[src] can't hold any more fish."
else
add_fish(egg.fish_type)
qdel(egg)
return
//Fish food
else if(istype(O, /obj/item/weapon/fishfood))
//Only add food if there is water and it isn't already full of food
if(water_level)
if(food_level < 10)
if(fish_count == 0)
user.visible_message("[user.name] shakes some fish food into the empty [src]... How sad.", "You shake some fish food into the empty [src]... If only it had fish.")
else
user.visible_message("[user.name] feeds the fish in \the [src]. The fish look excited!", "You feed the fish in \the [src]. They look excited!")
food_level += 10
else
usr << "[src] already has plenty of food in it. You decide to not add more."
else
usr << "[src] doesn't have any water in it. You should fill it with water first."
check_food_level()
return
//Fish egg scoop
else if(istype(O, /obj/item/weapon/egg_scoop))
if(egg_count)
user.visible_message("[user.name] harvests some fish eggs from \the [src].", "You scoop the fish eggs out of \the [src].")
harvest_eggs(user)
else
user.visible_message("[user.name] fails to harvest any fish eggs from \the [src].", "There are no fish eggs in \the [src] to scoop out.")
return
//Fish net
if(istype(O, /obj/item/weapon/fish_net))
harvest_fish(user)
return
//Tank brush
if(istype(O, /obj/item/weapon/tank_brush))
if(filth_level == 0)
usr << "[src] is already spotless!"
else
filth_level = 0
user.visible_message("[user.name] scrubs the inside of \the [src], cleaning the filth.", "You scrub the inside of \the [src], cleaning the filth.")
else if(O && O.force)
user.visible_message("<span class='danger'>\The [src] has been attacked by [user.name] with \the [O]!</span>")
hit(O.force)
return