diff --git a/CHANGELOG b/CHANGELOG index 2f39ef816..6fc130d51 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -74,3 +74,4 @@ - Fix granting hp xp on controlled - Implemented HCIM Rework < --- ABOVE Released December 15, 2021 https://gitlab.com/2009scape/2009scape/-/tags/Dec-15-2021 ---- > +- Fishing and fishing trawler now use closer-to-empirical formulae. diff --git a/Server/src/main/java/core/game/node/entity/skill/fishing/Fish.java b/Server/src/main/java/core/game/node/entity/skill/fishing/Fish.java index 9afad3b80..3a8480039 100644 --- a/Server/src/main/java/core/game/node/entity/skill/fishing/Fish.java +++ b/Server/src/main/java/core/game/node/entity/skill/fishing/Fish.java @@ -9,35 +9,34 @@ import java.util.HashMap; * @author ceikry */ public enum Fish { - CRAYFISH(new Item(13435),1,10), - SHRIMP(new Item(317), 1, 10), - SARDINE(new Item(327), 5, 20), - KARAMBWANJI(new Item(3150), 5, 5), - HERRING(new Item(345), 10, 30), - ANCHOVIE(new Item(321), 15, 40), - MACKEREL(new Item(353), 16, 20), - TROUT(new Item(335), 20, 50), - COD(new Item(341), 23, 45), - PIKE(new Item(349), 25, 60), - SLIMY_EEL(new Item(3379), 28, 65), - SALMON(new Item(331), 30, 70), - FROG_SPAWN(new Item(5004), 33, 75), - TUNA(new Item(359), 35, 80), - RAINBOW_FISH(new Item(10138), 38, 80), - CAVE_EEL(new Item(5001), 38, 80), - LOBSTER(new Item(377), 40, 90), - BASS(new Item(363), 46, 100), - SWORDFISH(new Item(371), 50, 100), - LAVA_EEL(new Item(2148), 53, 100), - MONKFISH(new Item(7944), 62, 120), - KARAMBWAN(new Item(3142), 65, 105), - SHARK(new Item(383), 76, 110), - SEA_TURTLE(new Item(395), 79, 38), - MANTA_RAY(new Item(389), 81, 46), - SEAWEED(new Item(401), 16, 1), - CASKET(new Item(405), 16, 10), - OYSTER(new Item(407), 16, 10), - DARK_CRAB(new Item(14937), 85, 130); + CRAYFISH(new Item(13435),1, 10, 0.15, 0.5), + SHRIMP(new Item(317), 1, 10, 0.191, 0.5), + SARDINE(new Item(327), 5, 20, 0.148, 0.374), + KARAMBWANJI(new Item(3150), 5, 5, 0.4, 0.98), + HERRING(new Item(345), 10, 30, 0.129, 0.504), + ANCHOVIE(new Item(321), 15, 40, 0.098, 0.5), + MACKEREL(new Item(353), 16, 20, 0.055, 0.258), + TROUT(new Item(335), 20, 50, 0.246, 0.468), + COD(new Item(341), 23, 45, 0.063, 0.219), + PIKE(new Item(349), 25, 60, 0.14, 0.379), + SLIMY_EEL(new Item(3379), 28, 65, 0.117, 0.216), + SALMON(new Item(331), 30, 70, 0.156, 0.378), + FROG_SPAWN(new Item(5004), 33, 75, 0.164, 0.379), + TUNA(new Item(359), 35, 80, 0.109, 0.205), + RAINBOW_FISH(new Item(10138), 38, 80, 0.113, 0.254), + CAVE_EEL(new Item(5001), 38, 80, 0.145, 0.316), + LOBSTER(new Item(377), 40, 90, 0.16, 0.375), + BASS(new Item(363), 46, 100, 0.078, 0.16), + SWORDFISH(new Item(371), 50, 100, 0.105, 0.191), + LAVA_EEL(new Item(2148), 53, 100, 0.227, 0.379), + MONKFISH(new Item(7944), 62, 120, 0.293, 0.356), + KARAMBWAN(new Item(3142), 65, 105, 0.414, 0.629), + SHARK(new Item(383), 76, 110, 0.121, 0.16), + SEA_TURTLE(new Item(395), 79, 38, 0.0, 0.0), + MANTA_RAY(new Item(389), 81, 46, 0.0, 0.0), + SEAWEED(new Item(401), 16, 1, 0.63, 0.219), + CASKET(new Item(405), 16, 10, 0.63, 0.219), + OYSTER(new Item(407), 16, 10, 0.63, 0.219); /** * Constructs a new {@code Fish} {@code Object}. @@ -45,11 +44,16 @@ public enum Fish { * @param level the level. * @param experience the experience. */ - Fish(final Item item, final int level, final double experience, final int... npcs) { + Fish(final Item item, final int level, final double experience, final double lowChance, final double highChance, final int... npcs) { this.item = item; this.level = level; this.experience = experience; this.npcs = npcs; + // The chances are given in the table based on when the fish can first be caught. + // Linearly extrapolate the success chance at level 1. + // y = (x - x0) * ((y1 - y0) / (x1 - x0)) + y0 + this.lowChance = (1 - (double)level)*((highChance - lowChance) / (99.0 - (double)level)) + lowChance; + this.highChance = highChance; } public static HashMap fishMap = new HashMap<>(); @@ -70,6 +74,9 @@ public enum Fish { */ private final double experience; + private final double lowChance; + private final double highChance; + /** * The npc ids that give this fish. */ @@ -112,4 +119,8 @@ public enum Fish { public int[] getNpcs() { return npcs; } + + public double getSuccessChance(int level) { + return ((double)level - 1.0)*((highChance - lowChance) / (99.0 - 1.0)) + lowChance; + } } diff --git a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java index 303619c1b..ce7d9b51a 100644 --- a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java +++ b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingOption.java @@ -8,6 +8,8 @@ import core.game.world.update.flag.context.Animation; import core.tools.RandomFunction; import org.rs09.consts.Items; +import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; /** @@ -26,8 +28,7 @@ public enum FishingOption { BARB_HARPOON(new Item(10129), 35, Animation.create(618), null, "harpoon", Fish.TUNA, Fish.SWORDFISH), BIG_NET(new Item(305), 16, Animation.create(620), null, "net", Fish.MACKEREL, Fish.COD, Fish.BASS, Fish.SEAWEED), N_HARPOON(new Item(311), 76, Animation.create(618), null, "harpoon", Fish.SHARK), - H_NET(new Item(303), 1, Animation.create(621), null, "net", Fish.MONKFISH), - C_CAGE(new Item(301), 85, Animation.create(619), new Item[]{new Item(14943)}, "cage", Fish.DARK_CRAB), + H_NET(new Item(303), 62, Animation.create(621), null, "net", Fish.MONKFISH), KBWANJI_NET(new Item(Items.SMALL_FISHING_NET_303), 5, Animation.create(621), null, "net", Fish.KARAMBWANJI), KARAMBWAN_VES(new Item(Items.KARAMBWAN_VESSEL_3157), 65, Animation.create(1193), new Item[]{new Item(Items.RAW_KARAMBWANJI_3150)}, "fish", Fish.KARAMBWAN); @@ -84,6 +85,12 @@ public enum FishingOption { this.animation = animation; this.bait = bait; this.name = name; + Arrays.sort(fish, new Comparator() { + @Override + public int compare(Fish x, Fish y) { + return y.getLevel() - x.getLevel(); + } + }); this.fish = fish; } @@ -91,7 +98,7 @@ public enum FishingOption { * Method used to get a random {@link Fish}. * @return the {@link Fish}. */ - public Fish getRandomFish(final Player player) { + public Fish rollFish(final Player player) { if (this == BIG_NET) { switch (RandomFunction.randomize(100)) { case 0: @@ -102,14 +109,22 @@ public enum FishingOption { return Fish.SEAWEED; } } - if (this == LURE && player.getInventory().contains(10087, 1)) { - return Fish.RAINBOW_FISH; - } - Fish reward = fish[RandomFunction.randomize(fish.length)]; - if (reward.getLevel() > player.getSkills().getLevel(Skills.FISHING) || (reward == Fish.RAINBOW_FISH && !player.getInventory().contains(10087, 1))) { - reward = fish[0]; - } - return reward; + int visibleLevel = player.getSkills().getLevel(Skills.FISHING); + int invisibleLevel = visibleLevel + player.getFamiliarManager().getBoost(Skills.FISHING); + for(Fish f : fish) { + if(f.getLevel() > player.getSkills().getLevel(Skills.FISHING)) { + continue; + } + if(this == LURE && (player.getInventory().contains(Items.STRIPY_FEATHER_10087, 1) != (f == Fish.RAINBOW_FISH))) { + continue; + } + double chance = f.getSuccessChance(invisibleLevel); + //System.out.printf("rollFish: %s %s %s %s %s\n", player.getName(), f.getItem().getName(), f.getLowChance(), f.getHighChance(), chance); + if(RandomFunction.random(0.0, 1.0) < chance) { + return f; + } + } + return null; } /** diff --git a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java index 57d115c0c..7bf83f6ca 100644 --- a/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java +++ b/Server/src/main/java/core/game/node/entity/skill/fishing/FishingSpot.java @@ -13,7 +13,6 @@ public enum FishingSpot { CAGE_HARPOON(new int[] { 312, 321, 324, 333, 405, 1332, 1399, 3804, 5470, 7046}, FishingOption.CAGE, FishingOption.HARPOON), NET_HARPOON(new int[] { 313, 322, 334, 406, 1191, 1333, 1405, 1406, 3574, 3575, 5471, 7044 }, FishingOption.BIG_NET, FishingOption.N_HARPOON), HARPOON_NET(new int[] { 3848, 3849 }, FishingOption.HARPOON, FishingOption.H_NET, FishingOption.BARB_HARPOON), - CRAB_CAGE(new int[] {8665}, FishingOption.C_CAGE), SPOT_KBWANJI(new int[] {1174}, FishingOption.KBWANJI_NET), SPOT_KARAMBWAN(new int[] {1177}, FishingOption.KARAMBWAN_VES); @@ -80,4 +79,4 @@ public enum FishingSpot { return options; } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerInteractionHandler.kt b/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerInteractionHandler.kt index 11362f06e..d72c63bf7 100644 --- a/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerInteractionHandler.kt +++ b/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerInteractionHandler.kt @@ -173,11 +173,12 @@ class NetLootDialogue(player: Player? = null): DialoguePlugin(player){ } override fun handle(interfaceId: Int, buttonId: Int): Boolean { + val level = player.skills.getLevel(Skills.FISHING) when(buttonId){ - 1 -> TrawlerLoot.getLoot(rolls,true).forEach { + 1 -> TrawlerLoot.getLoot(level, rolls, true).forEach { if(!player.bank.add(it)) GroundItemManager.create(it,player) } - 2 -> TrawlerLoot.getLoot(rolls,false).forEach { + 2 -> TrawlerLoot.getLoot(level, rolls, false).forEach { if(!player.bank.add(it)) GroundItemManager.create(it,player) } } @@ -235,4 +236,4 @@ class NetRepairDialogue(player: Player? = null) : DialoguePlugin(player){ return intArrayOf(18237583) } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerSession.kt b/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerSession.kt index f0fb716dd..939467250 100644 --- a/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerSession.kt +++ b/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/FishingTrawlerSession.kt @@ -54,6 +54,11 @@ class FishingTrawlerSession(var region: DynamicRegion, val activity: FishingTraw var inactiveTicks = 0 fun start(pl: ArrayList){ + if(RandomFunction.roll(2)) { + region.setMusicId(38) + } else { + region.setMusicId(51) + } this.players.addAll(pl) isActive = true initHoles() @@ -277,4 +282,4 @@ class TrawlerLogoutPlugin : Plugin{ return Unit } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/TrawlerLoot.kt b/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/TrawlerLoot.kt index a8ef7ee0f..6c66cb09b 100644 --- a/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/TrawlerLoot.kt +++ b/Server/src/main/kotlin/rs09/game/content/activity/fishingtrawler/TrawlerLoot.kt @@ -1,5 +1,6 @@ package rs09.game.content.activity.fishingtrawler +import core.game.node.entity.skill.fishing.Fish import core.game.node.item.Item import core.game.node.item.WeightedChanceItem import core.tools.RandomFunction @@ -11,11 +12,36 @@ import org.rs09.consts.Items */ object TrawlerLoot { val junkItems = arrayOf(Items.BROKEN_ARMOUR_698, Items.BROKEN_ARROW_687, Items.OLD_BOOT_685, Items.BROKEN_GLASS_1469, Items.BROKEN_STAFF_689, Items.BUTTONS_688,Items.DAMAGED_ARMOUR_697, Items.RUSTY_SWORD_686, Items.EMPTY_POT_1931, Items.OYSTER_407) + val trawlerFish = arrayOf(Fish.MANTA_RAY, Fish.SEA_TURTLE, Fish.SHARK, Fish.SWORDFISH, Fish.LOBSTER, Fish.TUNA, Fish.ANCHOVIE, Fish.SARDINE, Fish.SHRIMP) + + fun rollTrawlerFish(fishLevel: Int): Item { + while(true) { + for(f in trawlerFish) { + if(f.level > fishLevel) { + continue + } + val lo = 0.6133 + val hi = 0.7852 + //val chance = RandomFunction.getSkillSuccessChance(lo, hi, fishLevel) + val chance = (fishLevel.toDouble() - 15.0)*((hi - lo) / (99.0 - 15.0)) + lo + if(RandomFunction.random(0.0, 1.0) < chance) { + return f.item + } + } + } + } + @JvmStatic - fun getLoot(rolls: Int, skipJunk: Boolean): ArrayList{ + fun getLoot(fishLevel: Int, rolls: Int, skipJunk: Boolean): ArrayList{ val loot = ArrayList() for(i in 0 until rolls){ - loot.add(RandomFunction.rollWeightedChanceTable(listOf(*lootTable))) + val item = RandomFunction.rollWeightedChanceTable(listOf(*lootTable)) + if(item.id == 0) { + val item = rollTrawlerFish(fishLevel) + loot.add(item) + } else { + loot.add(item) + } } if(skipJunk){ val removeList = ArrayList() @@ -28,15 +54,7 @@ object TrawlerLoot { } val lootTable = arrayOf( - WeightedChanceItem(Items.RAW_SHRIMPS_317,1,150), - WeightedChanceItem(Items.RAW_SARDINE_327,1,150), - WeightedChanceItem(Items.RAW_ANCHOVIES_321,1,150), - WeightedChanceItem(Items.RAW_TUNA_359,1,140), - WeightedChanceItem(Items.RAW_LOBSTER_377,1,140), - WeightedChanceItem(Items.RAW_SWORDFISH_371,1,130), - WeightedChanceItem(Items.RAW_SHARK_383,1,120), - WeightedChanceItem(Items.RAW_SEA_TURTLE_395,1,120), - WeightedChanceItem(Items.RAW_MANTA_RAY_389,1,120), + WeightedChanceItem(0,1,1430), WeightedChanceItem(Items.BROKEN_ARROW_687,1,70), WeightedChanceItem(Items.BROKEN_GLASS_1469,1,70), WeightedChanceItem(Items.BROKEN_STAFF_689,1,70), @@ -47,10 +65,10 @@ object TrawlerLoot { WeightedChanceItem(Items.EMPTY_POT_1931,1,50), WeightedChanceItem(Items.RUSTY_SWORD_686,1,50), //Inauthentic rewards - WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,40), - WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,40), + WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,7), + WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,7), WeightedChanceItem(Items.CASKET_405,1,60), WeightedChanceItem(Items.PIRATES_HAT_2651,1,2), WeightedChanceItem(Items.LUCKY_CUTLASS_7140,1,2) ) -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/fishing/FishingPulse.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/fishing/FishingPulse.kt index 8d3bfb1e7..30b3bd953 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/fishing/FishingPulse.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/fishing/FishingPulse.kt @@ -70,8 +70,9 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption? stop() return false } - if (player.skills.getLevel(Skills.FISHING) < fish!!.level) { - player.dialogueInterpreter.sendDialogue("You need a fishing level of " + fish!!.level + " to catch " + (if (fish == Fish.SHRIMP || fish == Fish.ANCHOVIE) "" else "a") + " " + fish!!.item.name.toLowerCase() + ".".trim { it <= ' ' }) + if (player.skills.getLevel(Skills.FISHING) < option!!.level) { + val f = option!!.fish[option!!.fish.size - 1] + player.dialogueInterpreter.sendDialogue("You need a fishing level of " + f.level + " to catch " + (if (f == Fish.SHRIMP || f == Fish.ANCHOVIE) "" else "a") + " " + f.item.name.toLowerCase() + ".".trim { it <= ' ' }) stop() return false } @@ -135,7 +136,6 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption? stop() return true } - fish = option!!.getRandomFish(player) } } return player.inventory.freeSlots() == 0 @@ -415,10 +415,8 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption? if (delay == 1) { return false } - val level = 1 + player.skills.getLevel(Skills.FISHING) + player.familiarManager.getBoost(Skills.FISHING) - val hostRatio = Math.random() * fish!!.level - val clientRatio = Math.random() * (level * 1.25 - fish!!.level) - return hostRatio < clientRatio + fish = option!!.rollFish(player) + return fish != null } companion object { @@ -441,8 +439,5 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption? * @param option The fishing option. */ init { - if (option != null) { - fish = option.getRandomFish(player) - } } } diff --git a/Server/src/main/kotlin/rs09/game/system/command/sets/MiscCommandSet.kt b/Server/src/main/kotlin/rs09/game/system/command/sets/MiscCommandSet.kt index 65ff7d150..3e4cdc5bf 100644 --- a/Server/src/main/kotlin/rs09/game/system/command/sets/MiscCommandSet.kt +++ b/Server/src/main/kotlin/rs09/game/system/command/sets/MiscCommandSet.kt @@ -302,7 +302,7 @@ class MiscCommandSet : CommandSet(Command.Privilege.ADMIN){ } else { args[1].toString().toInt() } - player.bank.add(*TrawlerLoot.getLoot(rolls,false).toTypedArray()) + player.bank.add(*TrawlerLoot.getLoot(player.skills.getLevel(Skills.FISHING), rolls, false).toTypedArray()) } define("fillbank"){player,_ ->