diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index d6e21d6d482..a9052e79e86 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -222,6 +222,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4), \
new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4), \
new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4), \
+ new/datum/stack_recipe("fish bag", /obj/item/storage/bag/fish, 4), \
null, \
new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/bruise_pack/improvised, 1, 2, 6), \
new/datum/stack_recipe("rag", /obj/item/reagent_containers/glass/rag, 1), \
diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm
index 0cb1fd92f97..417e5e451f7 100644
--- a/code/game/objects/items/weapons/storage/fancy.dm
+++ b/code/game/objects/items/weapons/storage/fancy.dm
@@ -395,7 +395,7 @@
med_bot_skin = "fish"
/obj/item/storage/firstaid/aquatic_kit/full
- desc = "It's a starter kit for an acquarium; includes 1 tank brush, 1 egg scoop, 1 fish net, and 1 container of fish food."
+ desc = "It's a starter kit for an aquarium; includes 1 tank brush, 1 egg scoop, 1 fish net, 1 container of fish food and 1 fish bag."
/obj/item/storage/firstaid/aquatic_kit/full/New()
..()
@@ -403,3 +403,4 @@
new /obj/item/fish_net(src)
new /obj/item/tank_brush(src)
new /obj/item/fishfood(src)
+ new /obj/item/storage/bag/fish(src)
diff --git a/code/modules/fish/fish_items.dm b/code/modules/fish/fish_items.dm
index bb31226f42a..ebab27e3af2 100644
--- a/code/modules/fish/fish_items.dm
+++ b/code/modules/fish/fish_items.dm
@@ -55,6 +55,21 @@
to_chat(viewers(user), "[user] is vigorously scrubbing [user.p_them()]self raw with the [name]! It looks like [user.p_theyre()] trying to commit suicide.")
return BRUTELOSS|FIRELOSS
+/obj/item/storage/bag/fish
+ name = "fish bag"
+ icon = 'icons/obj/fish_items.dmi'
+ icon_state = "bag"
+ storage_slots = 100
+ max_combined_w_class = 100
+ max_w_class = WEIGHT_CLASS_NORMAL
+ w_class = WEIGHT_CLASS_TINY
+ can_hold = list(
+ /obj/item/fish,
+ /obj/item/fish_eggs,
+ /obj/item/reagent_containers/food/snacks/shrimp,
+ )
+ resistance_flags = FLAMMABLE
+
//////////////////////////////////////////////
// Fish Items //
//////////////////////////////////////////////
diff --git a/code/modules/fish/fishtank.dm b/code/modules/fish/fishtank.dm
index d54e22c6fc4..12c5d243b52 100644
--- a/code/modules/fish/fishtank.dm
+++ b/code/modules/fish/fishtank.dm
@@ -130,23 +130,23 @@
//////////////////////////////
/obj/machinery/fishtank/update_icon()
- overlays.Cut()
+ cut_overlays()
//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"
+ add_overlay("over_egg")
if(lid_switch == 1) //Lid is closed, lid status light is red
- overlays += "over_lid_1"
+ add_overlay("over_lid_1")
else //Lid is open, lid status light is green
- overlays += "over_lid_0"
+ add_overlay("over_lid_0")
if(food_level > 5) //Food_level is high and isn't a concern yet
- overlays += "over_food_0"
+ add_overlay("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"
+ add_overlay("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
+ add_overlay("over_food_2")
+ add_overlay("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)
@@ -154,9 +154,23 @@
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]"
+ add_overlay("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]"
+ add_overlay("over_[tank_type]_half[water_type]")
+
+/obj/machinery/fishtank/wall/update_icon()
+ ..()
+ // Update fish overlay for wall tanks
+ var/num_fish = length(fish_list)
+ if(!num_fish)
+ return
+ switch(num_fish)
+ if(1 to 3)
+ add_overlay("over_tank_fish_33")
+ if(4 to 7)
+ add_overlay("over_tank_fish_66")
+ if(7 to INFINITY)
+ add_overlay("over_tank_fish_100")
//////////////////////////////
// PROCESS PROC //
@@ -187,16 +201,16 @@
//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 >= 0.2 && filth_level <=5) //Breeding is going to use extra food, and the filth_level shouldn't be too high
+ if(food_level >= 0.1 && 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
breed_fish()
- adjust_food_level(-0.2) //Remove extra food for the breeding process
+ adjust_food_level(-0.1) //Remove extra food for the breeding process
ate_food = 1
//Handle standard food and filth adjustments
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
- adjust_food_level(fish_count * -0.1)
+ if(food_level >= (fish_count * 0.05)) //If there is at least enough food to go around, feed all the fish
+ adjust_food_level(fish_count * -0.05)
else //Use up the last of the food
adjust_food_level(-food_level)
ate_food = 1
@@ -270,6 +284,7 @@
if(istype(fish_type, /datum/fish/glofish))
adjust_tank_light()
qdel(fish_type)
+ update_icon()
/obj/machinery/fishtank/proc/add_fish(datum/fish/fish_type = null)
//Check if we were passed a fish type
@@ -279,44 +294,69 @@
fish_count++ //Increase fish_count to reflect the introduction of a fish, so the everything else works fine
//Announce the new fish
visible_message("A new [fish_type.fish_name] has hatched in [src]!")
+ update_icon()
//Null type fish are dud eggs, give a message to inform the player
else
to_chat(usr, "The eggs disolve in the water. They were duds!")
-/obj/machinery/fishtank/proc/harvest_eggs(mob/user)
+/obj/machinery/fishtank/proc/harvest_eggs(mob/user, obj/item/storage/bag/fish/fish_bag)
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
+ var/duds = 0
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
+ if(egg != /obj/item/fish_eggs) // Don't harvest duds
+ egg = new egg(get_turf(user)) //Spawn the egg at the user's feet
+ if(fish_bag?.can_be_inserted(egg))
+ fish_bag.handle_item_insertion(egg)
+ else
+ duds++
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
+ if(duds)
+ to_chat(user, "[duds] egg\s [duds == 1 ? "was a dud" : "were duds"]!")
/obj/machinery/fishtank/proc/harvest_fish(mob/user)
if(fish_count <= 0) //Can't catch non-existant fish!
to_chat(user, "There are no fish in [src] to catch!")
return
- var/list/fish_names_list = list()
- for(var/datum/fish/fish_type in fish_list)
- fish_names_list += list("[fish_type.fish_name]" = fish_type)
- var/caught_fish = input("Select a fish to catch.", "Fishing") as null|anything in fish_names_list //Select a fish from the tank
+ var/list/fish_types = list()
+ var/list/fish_types_input = list()
+ for(var/datum/fish/F in fish_list) // Group up the fish first
+ fish_types[F.type] += list(F)
+ for(var/key in fish_types) // Then populate the list
+ var/datum/fish/fish_type = key
+ var/count = length(fish_types[key])
+ fish_types_input += list("[initial(fish_type.fish_name)][count > 1 ? " (x[count])" : ""]" = fish_types[key])
+ var/caught_fish = input("Select a fish to catch.", "Fishing") as null|anything in fish_types_input //Select a fish from the tank
if(fish_count <= 0)
to_chat(user, "There are no fish in [src] to catch!")
return
else if(caught_fish)
- user.visible_message("[user.name] harvests \a [caught_fish] from [src].", "You scoop \a [caught_fish] out of [src].")
- var/datum/fish/fish_type = fish_names_list[caught_fish]
- var/fish_item = fish_type.fish_item
+ var/list/fishes_of_type = fish_types_input[caught_fish]
+ var/datum/fish/fish_to_scoop = pick(fishes_of_type)
+ // Is the user holding a fish bag?
+ var/obj/item/storage/bag/fish_bag
+ if(istype(user.r_hand, /obj/item/storage/bag/fish))
+ fish_bag = user.r_hand
+ else if(istype(user.l_hand, /obj/item/storage/bag/fish))
+ fish_bag = user.l_hand
+ var/fish_name = fish_to_scoop.fish_name
+ // Move the fish in
+ var/fish_item = fish_to_scoop.fish_item
if(fish_item)
- new fish_item(get_turf(user)) //Spawn the appropriate fish_item at the user's feet.
- kill_fish(fish_type) //Kill the caught fish from the tank
- //Update the air for the turf, to avoid permanent atmos sealing with wall tanks
+ var/obj/item/I = new fish_item(get_turf(user))
+ if(fish_bag?.can_be_inserted(I))
+ fish_bag.handle_item_insertion(I)
+ user.visible_message("[user.name] scoops \a [fish_name] from [src].", "You scoop \a [fish_name] out of [src].")
+ kill_fish(fish_to_scoop) //Kill the caught fish from the tank
+
/obj/machinery/fishtank/proc/spill_water()
var/turf/simulated/T = get_turf(src)
switch(tank_type)
@@ -527,6 +567,8 @@
return ..()
/obj/machinery/fishtank/attack_hand(mob/user)
+ if(isAI(user))
+ return
user.changeNext_move(CLICK_CD_MELEE)
if(user.a_intent == INTENT_HARM)
playsound(get_turf(src), 'sound/effects/glassknock.ogg', 80, 1)
@@ -635,8 +677,14 @@
//Fish egg scoop
else if(istype(O, /obj/item/egg_scoop))
if(egg_count)
+ // Is the user holding a fish bag?
+ var/obj/item/storage/bag/fish_bag
+ if(istype(user.r_hand, /obj/item/storage/bag/fish))
+ fish_bag = user.r_hand
+ else if(istype(user.l_hand, /obj/item/storage/bag/fish))
+ fish_bag = user.l_hand
user.visible_message("[user.name] harvests some fish eggs from [src].", "You scoop the fish eggs out of [src].")
- harvest_eggs(user)
+ harvest_eggs(user, fish_bag)
else
user.visible_message("[user.name] fails to harvest any fish eggs from [src].", "There are no fish eggs in [src] to scoop out.")
//Fish net
diff --git a/icons/obj/fish_items.dmi b/icons/obj/fish_items.dmi
index 76a9486fee6..302e144ba24 100644
Binary files a/icons/obj/fish_items.dmi and b/icons/obj/fish_items.dmi differ