Merge branch 'fishing-trawler-fixes' into 'master'

Fishing and fishing trawler now use closer-to-empirical formulae.

See merge request 2009scape/2009scape!348
This commit is contained in:
Ceikry 2021-12-17 00:39:45 +00:00
commit b4f3224287
9 changed files with 117 additions and 72 deletions

View file

@ -74,3 +74,4 @@
- Fix granting hp xp on controlled - Fix granting hp xp on controlled
- Implemented HCIM Rework - Implemented HCIM Rework
< --- ABOVE Released December 15, 2021 https://gitlab.com/2009scape/2009scape/-/tags/Dec-15-2021 ---- > < --- ABOVE Released December 15, 2021 https://gitlab.com/2009scape/2009scape/-/tags/Dec-15-2021 ---- >
- Fishing and fishing trawler now use closer-to-empirical formulae.

View file

@ -9,35 +9,34 @@ import java.util.HashMap;
* @author ceikry * @author ceikry
*/ */
public enum Fish { public enum Fish {
CRAYFISH(new Item(13435),1,10), CRAYFISH(new Item(13435),1, 10, 0.15, 0.5),
SHRIMP(new Item(317), 1, 10), SHRIMP(new Item(317), 1, 10, 0.191, 0.5),
SARDINE(new Item(327), 5, 20), SARDINE(new Item(327), 5, 20, 0.148, 0.374),
KARAMBWANJI(new Item(3150), 5, 5), KARAMBWANJI(new Item(3150), 5, 5, 0.4, 0.98),
HERRING(new Item(345), 10, 30), HERRING(new Item(345), 10, 30, 0.129, 0.504),
ANCHOVIE(new Item(321), 15, 40), ANCHOVIE(new Item(321), 15, 40, 0.098, 0.5),
MACKEREL(new Item(353), 16, 20), MACKEREL(new Item(353), 16, 20, 0.055, 0.258),
TROUT(new Item(335), 20, 50), TROUT(new Item(335), 20, 50, 0.246, 0.468),
COD(new Item(341), 23, 45), COD(new Item(341), 23, 45, 0.063, 0.219),
PIKE(new Item(349), 25, 60), PIKE(new Item(349), 25, 60, 0.14, 0.379),
SLIMY_EEL(new Item(3379), 28, 65), SLIMY_EEL(new Item(3379), 28, 65, 0.117, 0.216),
SALMON(new Item(331), 30, 70), SALMON(new Item(331), 30, 70, 0.156, 0.378),
FROG_SPAWN(new Item(5004), 33, 75), FROG_SPAWN(new Item(5004), 33, 75, 0.164, 0.379),
TUNA(new Item(359), 35, 80), TUNA(new Item(359), 35, 80, 0.109, 0.205),
RAINBOW_FISH(new Item(10138), 38, 80), RAINBOW_FISH(new Item(10138), 38, 80, 0.113, 0.254),
CAVE_EEL(new Item(5001), 38, 80), CAVE_EEL(new Item(5001), 38, 80, 0.145, 0.316),
LOBSTER(new Item(377), 40, 90), LOBSTER(new Item(377), 40, 90, 0.16, 0.375),
BASS(new Item(363), 46, 100), BASS(new Item(363), 46, 100, 0.078, 0.16),
SWORDFISH(new Item(371), 50, 100), SWORDFISH(new Item(371), 50, 100, 0.105, 0.191),
LAVA_EEL(new Item(2148), 53, 100), LAVA_EEL(new Item(2148), 53, 100, 0.227, 0.379),
MONKFISH(new Item(7944), 62, 120), MONKFISH(new Item(7944), 62, 120, 0.293, 0.356),
KARAMBWAN(new Item(3142), 65, 105), KARAMBWAN(new Item(3142), 65, 105, 0.414, 0.629),
SHARK(new Item(383), 76, 110), SHARK(new Item(383), 76, 110, 0.121, 0.16),
SEA_TURTLE(new Item(395), 79, 38), SEA_TURTLE(new Item(395), 79, 38, 0.0, 0.0),
MANTA_RAY(new Item(389), 81, 46), MANTA_RAY(new Item(389), 81, 46, 0.0, 0.0),
SEAWEED(new Item(401), 16, 1), SEAWEED(new Item(401), 16, 1, 0.63, 0.219),
CASKET(new Item(405), 16, 10), CASKET(new Item(405), 16, 10, 0.63, 0.219),
OYSTER(new Item(407), 16, 10), OYSTER(new Item(407), 16, 10, 0.63, 0.219);
DARK_CRAB(new Item(14937), 85, 130);
/** /**
* Constructs a new {@code Fish} {@code Object}. * Constructs a new {@code Fish} {@code Object}.
@ -45,11 +44,16 @@ public enum Fish {
* @param level the level. * @param level the level.
* @param experience the experience. * @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.item = item;
this.level = level; this.level = level;
this.experience = experience; this.experience = experience;
this.npcs = npcs; 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<Integer,Fish> fishMap = new HashMap<>(); public static HashMap<Integer,Fish> fishMap = new HashMap<>();
@ -70,6 +74,9 @@ public enum Fish {
*/ */
private final double experience; private final double experience;
private final double lowChance;
private final double highChance;
/** /**
* The npc ids that give this fish. * The npc ids that give this fish.
*/ */
@ -112,4 +119,8 @@ public enum Fish {
public int[] getNpcs() { public int[] getNpcs() {
return npcs; return npcs;
} }
public double getSuccessChance(int level) {
return ((double)level - 1.0)*((highChance - lowChance) / (99.0 - 1.0)) + lowChance;
}
} }

View file

@ -8,6 +8,8 @@ import core.game.world.update.flag.context.Animation;
import core.tools.RandomFunction; import core.tools.RandomFunction;
import org.rs09.consts.Items; import org.rs09.consts.Items;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap; 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), 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), 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), 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), H_NET(new Item(303), 62, 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),
KBWANJI_NET(new Item(Items.SMALL_FISHING_NET_303), 5, Animation.create(621), null, "net", Fish.KARAMBWANJI), 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); 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.animation = animation;
this.bait = bait; this.bait = bait;
this.name = name; this.name = name;
Arrays.sort(fish, new Comparator<Fish>() {
@Override
public int compare(Fish x, Fish y) {
return y.getLevel() - x.getLevel();
}
});
this.fish = fish; this.fish = fish;
} }
@ -91,7 +98,7 @@ public enum FishingOption {
* Method used to get a random {@link Fish}. * Method used to get a random {@link Fish}.
* @return the {@link Fish}. * @return the {@link Fish}.
*/ */
public Fish getRandomFish(final Player player) { public Fish rollFish(final Player player) {
if (this == BIG_NET) { if (this == BIG_NET) {
switch (RandomFunction.randomize(100)) { switch (RandomFunction.randomize(100)) {
case 0: case 0:
@ -102,14 +109,22 @@ public enum FishingOption {
return Fish.SEAWEED; return Fish.SEAWEED;
} }
} }
if (this == LURE && player.getInventory().contains(10087, 1)) { int visibleLevel = player.getSkills().getLevel(Skills.FISHING);
return Fish.RAINBOW_FISH; int invisibleLevel = visibleLevel + player.getFamiliarManager().getBoost(Skills.FISHING);
} for(Fish f : fish) {
Fish reward = fish[RandomFunction.randomize(fish.length)]; if(f.getLevel() > player.getSkills().getLevel(Skills.FISHING)) {
if (reward.getLevel() > player.getSkills().getLevel(Skills.FISHING) || (reward == Fish.RAINBOW_FISH && !player.getInventory().contains(10087, 1))) { continue;
reward = fish[0]; }
} if(this == LURE && (player.getInventory().contains(Items.STRIPY_FEATHER_10087, 1) != (f == Fish.RAINBOW_FISH))) {
return reward; 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;
} }
/** /**

View file

@ -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), 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), 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), 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_KBWANJI(new int[] {1174}, FishingOption.KBWANJI_NET),
SPOT_KARAMBWAN(new int[] {1177}, FishingOption.KARAMBWAN_VES); SPOT_KARAMBWAN(new int[] {1177}, FishingOption.KARAMBWAN_VES);
@ -80,4 +79,4 @@ public enum FishingSpot {
return options; return options;
} }
} }

View file

@ -173,11 +173,12 @@ class NetLootDialogue(player: Player? = null): DialoguePlugin(player){
} }
override fun handle(interfaceId: Int, buttonId: Int): Boolean { override fun handle(interfaceId: Int, buttonId: Int): Boolean {
val level = player.skills.getLevel(Skills.FISHING)
when(buttonId){ when(buttonId){
1 -> TrawlerLoot.getLoot(rolls,true).forEach { 1 -> TrawlerLoot.getLoot(level, rolls, true).forEach {
if(!player.bank.add(it)) GroundItemManager.create(it,player) 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) if(!player.bank.add(it)) GroundItemManager.create(it,player)
} }
} }
@ -235,4 +236,4 @@ class NetRepairDialogue(player: Player? = null) : DialoguePlugin(player){
return intArrayOf(18237583) return intArrayOf(18237583)
} }
} }

View file

@ -54,6 +54,11 @@ class FishingTrawlerSession(var region: DynamicRegion, val activity: FishingTraw
var inactiveTicks = 0 var inactiveTicks = 0
fun start(pl: ArrayList<Player>){ fun start(pl: ArrayList<Player>){
if(RandomFunction.roll(2)) {
region.setMusicId(38)
} else {
region.setMusicId(51)
}
this.players.addAll(pl) this.players.addAll(pl)
isActive = true isActive = true
initHoles() initHoles()
@ -277,4 +282,4 @@ class TrawlerLogoutPlugin : Plugin<Player>{
return Unit return Unit
} }
} }

View file

@ -1,5 +1,6 @@
package rs09.game.content.activity.fishingtrawler 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.Item
import core.game.node.item.WeightedChanceItem import core.game.node.item.WeightedChanceItem
import core.tools.RandomFunction import core.tools.RandomFunction
@ -11,11 +12,36 @@ import org.rs09.consts.Items
*/ */
object TrawlerLoot { 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 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 @JvmStatic
fun getLoot(rolls: Int, skipJunk: Boolean): ArrayList<Item>{ fun getLoot(fishLevel: Int, rolls: Int, skipJunk: Boolean): ArrayList<Item>{
val loot = ArrayList<Item>() val loot = ArrayList<Item>()
for(i in 0 until rolls){ 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){ if(skipJunk){
val removeList = ArrayList<Item>() val removeList = ArrayList<Item>()
@ -28,15 +54,7 @@ object TrawlerLoot {
} }
val lootTable = arrayOf( val lootTable = arrayOf(
WeightedChanceItem(Items.RAW_SHRIMPS_317,1,150), WeightedChanceItem(0,1,1430),
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(Items.BROKEN_ARROW_687,1,70), WeightedChanceItem(Items.BROKEN_ARROW_687,1,70),
WeightedChanceItem(Items.BROKEN_GLASS_1469,1,70), WeightedChanceItem(Items.BROKEN_GLASS_1469,1,70),
WeightedChanceItem(Items.BROKEN_STAFF_689,1,70), WeightedChanceItem(Items.BROKEN_STAFF_689,1,70),
@ -47,10 +65,10 @@ object TrawlerLoot {
WeightedChanceItem(Items.EMPTY_POT_1931,1,50), WeightedChanceItem(Items.EMPTY_POT_1931,1,50),
WeightedChanceItem(Items.RUSTY_SWORD_686,1,50), WeightedChanceItem(Items.RUSTY_SWORD_686,1,50),
//Inauthentic rewards //Inauthentic rewards
WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,40), WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,7),
WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,40), WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,7),
WeightedChanceItem(Items.CASKET_405,1,60), WeightedChanceItem(Items.CASKET_405,1,60),
WeightedChanceItem(Items.PIRATES_HAT_2651,1,2), WeightedChanceItem(Items.PIRATES_HAT_2651,1,2),
WeightedChanceItem(Items.LUCKY_CUTLASS_7140,1,2) WeightedChanceItem(Items.LUCKY_CUTLASS_7140,1,2)
) )
} }

View file

@ -70,8 +70,9 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
stop() stop()
return false return false
} }
if (player.skills.getLevel(Skills.FISHING) < fish!!.level) { if (player.skills.getLevel(Skills.FISHING) < option!!.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 <= ' ' }) 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() stop()
return false return false
} }
@ -135,7 +136,6 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
stop() stop()
return true return true
} }
fish = option!!.getRandomFish(player)
} }
} }
return player.inventory.freeSlots() == 0 return player.inventory.freeSlots() == 0
@ -415,10 +415,8 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
if (delay == 1) { if (delay == 1) {
return false return false
} }
val level = 1 + player.skills.getLevel(Skills.FISHING) + player.familiarManager.getBoost(Skills.FISHING) fish = option!!.rollFish(player)
val hostRatio = Math.random() * fish!!.level return fish != null
val clientRatio = Math.random() * (level * 1.25 - fish!!.level)
return hostRatio < clientRatio
} }
companion object { companion object {
@ -441,8 +439,5 @@ class FishingPulse(player: Player?, npc: NPC, private val option: FishingOption?
* @param option The fishing option. * @param option The fishing option.
*/ */
init { init {
if (option != null) {
fish = option.getRandomFish(player)
}
} }
} }

View file

@ -302,7 +302,7 @@ class MiscCommandSet : CommandSet(Command.Privilege.ADMIN){
} else { } else {
args[1].toString().toInt() 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,_ -> define("fillbank"){player,_ ->