mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-20 21:40:27 -07:00
Pickpocket rewrite + 100% accurate success rate formula (Just have to plug in low and high values from a document I'll push later.)
This commit is contained in:
parent
3ebd9c2614
commit
8a6c8e899b
8 changed files with 370 additions and 217 deletions
|
|
@ -1,203 +0,0 @@
|
||||||
package core.game.node.entity.skill.thieving;
|
|
||||||
|
|
||||||
import core.game.node.entity.Entity;
|
|
||||||
import core.game.node.entity.combat.DeathTask;
|
|
||||||
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
|
|
||||||
import core.game.node.entity.npc.NPC;
|
|
||||||
import core.game.node.entity.player.Player;
|
|
||||||
import core.game.node.entity.player.link.audio.Audio;
|
|
||||||
import core.game.node.entity.player.link.diary.DiaryType;
|
|
||||||
import core.game.node.entity.skill.SkillPulse;
|
|
||||||
import core.game.node.entity.skill.Skills;
|
|
||||||
import core.game.node.entity.state.EntityState;
|
|
||||||
import core.game.node.item.GroundItemManager;
|
|
||||||
import core.game.node.item.Item;
|
|
||||||
import core.game.world.map.zone.ZoneBorders;
|
|
||||||
import core.game.world.update.flag.context.Animation;
|
|
||||||
import core.tools.RandomFunction;
|
|
||||||
import rs09.game.node.entity.skill.thieving.Pickpocket;
|
|
||||||
import rs09.game.world.GameWorld;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the pulse used to pickpocket an npc.
|
|
||||||
*
|
|
||||||
* @author Vexia
|
|
||||||
*/
|
|
||||||
public final class PickpocketPulse extends SkillPulse<NPC> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the animation specific to pickpocketing.
|
|
||||||
*/
|
|
||||||
private static final Animation ANIMATION = new Animation(881);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the npc animation.
|
|
||||||
*/
|
|
||||||
private static final Animation NPC_ANIM = new Animation(422);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the animation specific to pickpocketing.
|
|
||||||
*/
|
|
||||||
private static final Animation STUN_ANIMATION = new Animation(424);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the sound to send when failed.
|
|
||||||
*/
|
|
||||||
private static final Audio SOUND = new Audio(2727, 1, 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the pickpocket type.
|
|
||||||
*/
|
|
||||||
private final Pickpocket type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the tickets to be rewarded.
|
|
||||||
*/
|
|
||||||
private int ticks;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new {@code PickpocketPulse} {@code Object}.
|
|
||||||
*
|
|
||||||
* @param player the player.
|
|
||||||
* @param node the node.
|
|
||||||
* @param type the type.
|
|
||||||
*/
|
|
||||||
public PickpocketPulse(Player player, NPC node, final Pickpocket type) {
|
|
||||||
super(player, node);
|
|
||||||
this.type = type;
|
|
||||||
this.resetAnimation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkRequirements() {
|
|
||||||
if (!interactable() && !player.getLocks().isInteractionLocked()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (player.getSkills().getLevel(Skills.THIEVING) < type.getLevel()) {
|
|
||||||
player.getPacketDispatch().sendMessage("You need to be a level " + type.getLevel() + " thief in order to pick this pocket.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!hasInventorySpace()) {
|
|
||||||
player.getPacketDispatch().sendMessage("You do not have enough space in your inventory to pick this pocket.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
player.getLocks().lockInteractions(2);
|
|
||||||
player.faceTemporary(node, 2);
|
|
||||||
node.getWalkingQueue().reset();
|
|
||||||
node.getLocks().lockMovement(1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void animate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean reward() {
|
|
||||||
if (ticks == 0) {
|
|
||||||
player.animate(ANIMATION);
|
|
||||||
}
|
|
||||||
if (++ticks % 2 != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final boolean success = success();
|
|
||||||
if (success) {
|
|
||||||
player.getPacketDispatch().sendMessage(type.getRewardMessage().replace("@name", node.getName().toLowerCase()));
|
|
||||||
player.getSkills().addExperience(Skills.THIEVING, type.getExperience(), true);
|
|
||||||
List<Item> loot = type.getRandomLoot(player);
|
|
||||||
loot.stream().forEach(item -> {
|
|
||||||
if (!player.getInventory().add(item)) {
|
|
||||||
GroundItemManager.create(item, player.getLocation(), player);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (type == Pickpocket.GUARD && node.getId() == 9) {
|
|
||||||
player.getAchievementDiaryManager().finishTask(player, DiaryType.FALADOR, 1, 6);
|
|
||||||
}
|
|
||||||
if (type == Pickpocket.GUARD && node.getId() == 5920
|
|
||||||
&& new ZoneBorders(3202, 3459, 3224, 3470, 0).insideBorder(player)) {
|
|
||||||
player.getAchievementDiaryManager().finishTask(player, DiaryType.VARROCK, 1, 12);
|
|
||||||
}
|
|
||||||
player.getLocks().unlockInteraction();
|
|
||||||
} else {
|
|
||||||
node.animate(NPC_ANIM);
|
|
||||||
node.faceTemporary(player, 1);
|
|
||||||
node.sendChat(type.getForceMessage());
|
|
||||||
player.animate(STUN_ANIMATION);
|
|
||||||
player.getAudioManager().send(new Audio(1842));
|
|
||||||
player.getStateManager().set(EntityState.STUNNED, 4);
|
|
||||||
player.getAudioManager().send(SOUND);
|
|
||||||
player.setAttribute("thief-delay", GameWorld.getTicks() + 4);
|
|
||||||
player.getImpactHandler().manualHit(player, type.getStunDamage(), HitsplatType.NORMAL);
|
|
||||||
player.getPacketDispatch().sendMessage(type.getFailMessage().replace("@name", node.getName().toLowerCase()));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
super.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void message(int type) {
|
|
||||||
switch (type) {
|
|
||||||
case 0:
|
|
||||||
player.getPacketDispatch().sendMessage(this.type.getStartMessage().replace("@name", node.getName().toLowerCase()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the npc is interable.
|
|
||||||
*
|
|
||||||
* @return {@code True} if so.
|
|
||||||
*/
|
|
||||||
private boolean interactable() {
|
|
||||||
if (DeathTask.isDead(((Entity) node)) || ((NPC) node).isHidden(player) || !node.isActive() || player.getAttribute("thief-delay", 0) > GameWorld.getTicks()) {
|
|
||||||
return false;
|
|
||||||
} else if (player.inCombat()) {
|
|
||||||
player.getPacketDispatch().sendMessage("You can't pickpocket during combat.");
|
|
||||||
return false;
|
|
||||||
} else if (!hasInventorySpace()) {
|
|
||||||
player.getPacketDispatch().sendMessage("You don't have enough inventory space.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the pickpocket is a success.
|
|
||||||
*
|
|
||||||
* @return {@code True} if so.
|
|
||||||
*/
|
|
||||||
private boolean success() {
|
|
||||||
double level = player.getSkills().getLevel(Skills.THIEVING);
|
|
||||||
double req = type.getLevel();
|
|
||||||
double successChance = Math.ceil((level * 50 - req * 15) / req / 3 * 4);
|
|
||||||
int roll = RandomFunction.random(99);
|
|
||||||
if (RandomFunction.random(12) < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (successChance >= roll) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if player has enough inventory space to pickpocket npc.
|
|
||||||
* @return {@code True} if player has enough inventory space.
|
|
||||||
*/
|
|
||||||
private boolean hasInventorySpace() {
|
|
||||||
if (player.getInventory().isFull() && type.getLoot().length > 0) {
|
|
||||||
if (!(type.getLoot().length == 1 && player.getInventory().hasSpaceFor(
|
|
||||||
new Item(type.getLoot()[0].getId(), type.getLoot()[0].getMaximumAmount())))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
package core.game.node.entity.skill.thieving;
|
package core.game.node.entity.skill.thieving;
|
||||||
|
|
||||||
import core.cache.def.impl.NPCDefinition;
|
|
||||||
import core.cache.def.impl.ObjectDefinition;
|
import core.cache.def.impl.ObjectDefinition;
|
||||||
import core.game.interaction.OptionHandler;
|
import core.game.interaction.OptionHandler;
|
||||||
import core.game.node.Node;
|
import core.game.node.Node;
|
||||||
import core.game.node.entity.npc.NPC;
|
|
||||||
import core.game.node.entity.player.Player;
|
import core.game.node.entity.player.Player;
|
||||||
import core.game.node.object.GameObject;
|
import core.game.node.object.GameObject;
|
||||||
import core.plugin.Initializable;
|
import core.plugin.Initializable;
|
||||||
import core.plugin.Plugin;
|
import core.plugin.Plugin;
|
||||||
import rs09.game.node.entity.skill.thieving.Pickpocket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the plugin used to handle thieving options.
|
* Represents the plugin used to handle thieving options.
|
||||||
|
|
@ -21,8 +18,6 @@ public class ThievingOptionPlugin extends OptionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
public Plugin<Object> newInstance(Object arg) throws Throwable {
|
||||||
NPCDefinition.setOptionHandler("pick-pocket", this);
|
|
||||||
NPCDefinition.setOptionHandler("pickpocket", this);
|
|
||||||
ObjectDefinition.setOptionHandler("steal-from", this);
|
ObjectDefinition.setOptionHandler("steal-from", this);
|
||||||
ObjectDefinition.setOptionHandler("steal from", this);
|
ObjectDefinition.setOptionHandler("steal from", this);
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -31,10 +26,6 @@ public class ThievingOptionPlugin extends OptionHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(Player player, Node node, String option) {
|
public boolean handle(Player player, Node node, String option) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case "pick-pocket":
|
|
||||||
case "pickpocket":
|
|
||||||
player.getPulseManager().run(new PickpocketPulse(player, (NPC) node, Pickpocket.forNPC((NPC) node)));
|
|
||||||
break;
|
|
||||||
case "steal-from":
|
case "steal-from":
|
||||||
case "steal from":
|
case "steal from":
|
||||||
player.getPulseManager().run(new StallThiefPulse(player, (GameObject) node, Stall.forObject((GameObject) node)));
|
player.getPulseManager().run(new StallThiefPulse(player, (GameObject) node, Stall.forObject((GameObject) node)));
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
package core.tools;
|
package core.tools;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import core.game.node.entity.npc.drop.DropFrequency;
|
import core.game.node.entity.npc.drop.DropFrequency;
|
||||||
import core.game.node.item.ChanceItem;
|
import core.game.node.item.ChanceItem;
|
||||||
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 java.util.*;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a class used for random methods.
|
* Represents a class used for random methods.
|
||||||
* @author Vexia
|
* @author Vexia
|
||||||
|
|
@ -43,6 +44,20 @@ public class RandomFunction {
|
||||||
return Math.min(a, b) + (n == 0 ? 0 : random(n));
|
return Math.min(a, b) + (n == 0 ? 0 : random(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the chance of succeeding at a skilling event
|
||||||
|
* @param low - Success chance at level 1
|
||||||
|
* @param high - Success chance at level 99
|
||||||
|
* @param level - Level required
|
||||||
|
* @return percent chance of success
|
||||||
|
*/
|
||||||
|
public static double getSkillSuccessChance(double low, double high, int level) {
|
||||||
|
// 99 & 98 numbers should *not* be adjusted for level cap > 99
|
||||||
|
int value = (int)(Math.floor(low*( (99-level)/98.0 ) ) + Math.floor(high*((level-1)/98.0)) + 1);
|
||||||
|
return Math.min(Math.max(value / 256D, 0), 1) * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns either the supplied integer, or -1 times the supplied integer.
|
* Returns either the supplied integer, or -1 times the supplied integer.
|
||||||
* @param value the value.
|
* @param value the value.
|
||||||
|
|
@ -82,6 +97,10 @@ public class RandomFunction {
|
||||||
return RANDOM.nextInt(maxValue);
|
return RANDOM.nextInt(maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final double randomDouble(double min, double max){
|
||||||
|
return ThreadLocalRandom.current().nextDouble(min,max);
|
||||||
|
}
|
||||||
|
|
||||||
public static int nextInt(int val)
|
public static int nextInt(int val)
|
||||||
{
|
{
|
||||||
return random(val);
|
return random(val);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package rs09.game.content.global
|
||||||
|
|
||||||
|
import core.game.node.entity.player.Player
|
||||||
|
import core.game.node.item.Item
|
||||||
|
|
||||||
|
class WeightBasedTable : ArrayList<WeightedItem>() {
|
||||||
|
var totalWeight = 0.0
|
||||||
|
val guaranteedItems = ArrayList<WeightedItem>(5)
|
||||||
|
|
||||||
|
override fun add(element: WeightedItem): Boolean {
|
||||||
|
totalWeight += element.weight
|
||||||
|
return if(element.guaranteed) guaranteedItems.add(element)
|
||||||
|
else super.add(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun roll(player: Player): ArrayList<Item>{
|
||||||
|
val items= ArrayList<Item>(3)
|
||||||
|
var tempWeight = totalWeight
|
||||||
|
items.addAll(guaranteedItems.map { it.getItem() }.toList())
|
||||||
|
|
||||||
|
if(player.inventory.isFull){
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isNotEmpty()) {
|
||||||
|
for (item in shuffled()) {
|
||||||
|
tempWeight -= item.weight
|
||||||
|
if (tempWeight <= 0) {
|
||||||
|
items.add(item.getItem())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canRoll(player: Player): Boolean{
|
||||||
|
val guaranteed = guaranteedItems.map { it.getItem() }.toTypedArray()
|
||||||
|
return (player.inventory.hasSpaceFor(*guaranteed) && guaranteed.isNotEmpty()) || !player.inventory.isFull
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun create(vararg items: WeightedItem): WeightBasedTable{
|
||||||
|
val table = WeightBasedTable()
|
||||||
|
items.forEach {
|
||||||
|
table.add(it)
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package rs09.game.content.global
|
||||||
|
|
||||||
|
import core.game.node.item.Item
|
||||||
|
import core.tools.RandomFunction
|
||||||
|
|
||||||
|
class WeightedItem(var id: Int, var minAmt: Int, var maxAmt: Int, var weight: Double, var guaranteed: Boolean = false) {
|
||||||
|
fun getItem(): Item {
|
||||||
|
return Item(id,RandomFunction.random(minAmt,maxAmt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,7 +35,7 @@ object InteractionListeners {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun add(options: Array<out String>,type: Int,method: (Player, Node) -> Boolean){
|
fun add(options: Array<out String>,type: Int,method: (Player, Node) -> Boolean){
|
||||||
for(opt in options){
|
for(opt in options){
|
||||||
add(opt,type,method)
|
add(opt.toLowerCase(),type,method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
package rs09.game.node.entity.skill.thieving
|
||||||
|
|
||||||
|
import core.game.node.entity.player.Player
|
||||||
|
import core.game.node.entity.skill.Skills
|
||||||
|
import core.tools.RandomFunction
|
||||||
|
import org.rs09.consts.Items
|
||||||
|
import org.rs09.consts.NPCs
|
||||||
|
import rs09.game.content.global.WeightBasedTable
|
||||||
|
import rs09.game.content.global.WeightedItem
|
||||||
|
import java.util.stream.IntStream
|
||||||
|
|
||||||
|
enum class Pickpockets(val ids: IntArray, val requiredLevel: Int, val low: Double, val high: Double, val experience: Double, val stunDamageMin: Int, val stunDamageMax: Int, val stunTime: Int, val table: WeightBasedTable) {
|
||||||
|
MAN(intArrayOf(1, 2, 3, 4, 5, 6, 16, 24, 170, 3915), 1, 180.0, 240.0, 8.0, 1, 1,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,3,3,1.0,true)
|
||||||
|
)),
|
||||||
|
FARMER(intArrayOf(7, 1757, 1758), 10, 180.0, 240.0, 14.5, 1,1,5,WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,9,9,1.0,true),
|
||||||
|
WeightedItem(Items.POTATO_SEED_5318,1,1,1.0,true)
|
||||||
|
)),
|
||||||
|
MALE_HAM_MEMBER(intArrayOf(1714), 20, 117.0, 240.0, 22.5, 1,3,4, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,1,21,5.5),
|
||||||
|
WeightedItem(Items.TINDERBOX_590,1,1,5.0),
|
||||||
|
WeightedItem(Items.LOGS_1511,1,1,7.0),
|
||||||
|
WeightedItem(Items.UNCUT_JADE_1627,1,1,2.5),
|
||||||
|
WeightedItem(Items.UNCUT_OPAL_1625,1,1,2.5),
|
||||||
|
WeightedItem(Items.RAW_ANCHOVIES_321,1,1,7.0),
|
||||||
|
WeightedItem(Items.RAW_CHICKEN_2138,1,1,3.5),
|
||||||
|
WeightedItem(Items.HAM_CLOAK_4304,1,1,1.0),
|
||||||
|
WeightedItem(Items.HAM_HOOD_4302,1,1,1.0),
|
||||||
|
WeightedItem(Items.HAM_LOGO_4306,1,1,1.0),
|
||||||
|
WeightedItem(Items.HAM_ROBE_4300,1,1,1.0),
|
||||||
|
WeightedItem(Items.BOOTS_4310,1,1,1.0),
|
||||||
|
WeightedItem(Items.GLOVES_4308,1,1,1.0),
|
||||||
|
WeightedItem(Items.BRONZE_PICKAXE_1265,1,1,5.0),
|
||||||
|
WeightedItem(Items.IRON_PICKAXE_1267,1,1,5.0),
|
||||||
|
WeightedItem(Items.STEEL_PICKAXE_1269,1,1,2.5),
|
||||||
|
WeightedItem(Items.GRIMY_GUAM_199,1,1,2.0),
|
||||||
|
WeightedItem(Items.GRIMY_HARRALANDER_205,1,1,2.0),
|
||||||
|
WeightedItem(Items.GRIMY_KWUARM_213,1,1,2.0),
|
||||||
|
WeightedItem(Items.GRIMY_MARRENTILL_201,1,1,1.5),
|
||||||
|
WeightedItem(Items.RUSTY_SWORD_686,1,1,3.5),
|
||||||
|
WeightedItem(Items.BROKEN_ARMOUR_698,1,1,3.5),
|
||||||
|
WeightedItem(Items.BROKEN_STAFF_689,1,1,3.2),
|
||||||
|
WeightedItem(Items.BROKEN_ARROW_687,1,1,3.1)
|
||||||
|
)),
|
||||||
|
FEMALE_HAM_MEMBER(intArrayOf(1715), 15, 135.0, 240.0, 18.5, 1,3,4, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,1,21,5.5),
|
||||||
|
WeightedItem(Items.TINDERBOX_590,1,1,5.0),
|
||||||
|
WeightedItem(Items.LOGS_1511,1,1,7.0),
|
||||||
|
WeightedItem(Items.UNCUT_JADE_1627,1,1,2.5),
|
||||||
|
WeightedItem(Items.UNCUT_OPAL_1625,1,1,2.5),
|
||||||
|
WeightedItem(Items.RAW_ANCHOVIES_321,1,1,7.0),
|
||||||
|
WeightedItem(Items.RAW_CHICKEN_2138,1,1,3.5),
|
||||||
|
WeightedItem(Items.HAM_CLOAK_4304,1,1,1.0),
|
||||||
|
WeightedItem(Items.HAM_HOOD_4302,1,1,1.0),
|
||||||
|
WeightedItem(Items.HAM_LOGO_4306,1,1,1.0),
|
||||||
|
WeightedItem(Items.HAM_ROBE_4300,1,1,1.0),
|
||||||
|
WeightedItem(Items.BOOTS_4310,1,1,1.0),
|
||||||
|
WeightedItem(Items.GLOVES_4308,1,1,1.0),
|
||||||
|
WeightedItem(Items.BRONZE_PICKAXE_1265,1,1,5.0),
|
||||||
|
WeightedItem(Items.IRON_PICKAXE_1267,1,1,5.0),
|
||||||
|
WeightedItem(Items.STEEL_PICKAXE_1269,1,1,2.5),
|
||||||
|
WeightedItem(Items.GRIMY_GUAM_199,1,1,2.0),
|
||||||
|
WeightedItem(Items.GRIMY_HARRALANDER_205,1,1,2.0),
|
||||||
|
WeightedItem(Items.GRIMY_KWUARM_213,1,1,2.0),
|
||||||
|
WeightedItem(Items.GRIMY_MARRENTILL_201,1,1,1.5),
|
||||||
|
WeightedItem(Items.RUSTY_SWORD_686,1,1,3.5),
|
||||||
|
WeightedItem(Items.BROKEN_ARMOUR_698,1,1,3.5),
|
||||||
|
WeightedItem(Items.BROKEN_STAFF_689,1,1,3.2),
|
||||||
|
WeightedItem(Items.BROKEN_ARROW_687,1,1,3.1)
|
||||||
|
)),
|
||||||
|
WARRIOR(intArrayOf(15, 18), 25, 84.0, 240.0, 26.0, 2, 2, 5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,18,18,1.0,true)
|
||||||
|
)),
|
||||||
|
ROGUE(intArrayOf(187, 2267, 2268, 2269, 8122), 32, 74.0, 240.0,35.5, 2, 2, 5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,25,40,5.0,true),
|
||||||
|
WeightedItem(Items.JUG_OF_WINE_1993,1,1,6.0),
|
||||||
|
WeightedItem(Items.AIR_RUNE_556,8,8,8.0),
|
||||||
|
WeightedItem(Items.LOCKPICK_1523,1,1,5.0),
|
||||||
|
WeightedItem(Items.IRON_DAGGERP_1219,1,1,1.0)
|
||||||
|
)),
|
||||||
|
CAVE_GOBLIN(IntStream.rangeClosed(5752, 5768).toArray(), 36, 72.0, 240.0, 40.0, 1,1,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,30,30,6.5),
|
||||||
|
WeightedItem(Items.OIL_LAMP_4522,1,1,0.5),
|
||||||
|
WeightedItem(Items.BULLSEYE_LANTERN_4544,1,1,0.5),
|
||||||
|
WeightedItem(Items.UNLIT_TORCH_596,1,1,0.5),
|
||||||
|
WeightedItem(Items.TINDERBOX_590,1,1,0.5),
|
||||||
|
WeightedItem(Items.SWAMP_TAR_1939,1,1,0.5),
|
||||||
|
WeightedItem(Items.IRON_ORE_441,1,4,0.25)
|
||||||
|
)),
|
||||||
|
MASTER_FARMER(intArrayOf(2234, 2235, NPCs.MARTIN_THE_MASTER_GARDENER_3299), 38, 90.0, 240.0, 43.0, 3, 3, 5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.POTATO_SEED_5318,1,4,100.0),
|
||||||
|
WeightedItem(Items.HAMMERSTONE_SEED_5307,1,9,100.0),
|
||||||
|
WeightedItem(Items.ASGARNIAN_SEED_5308,1,6,95.0),
|
||||||
|
WeightedItem(Items.JUTE_SEED_5306,1,9,93.0),
|
||||||
|
WeightedItem(Items.YANILLIAN_SEED_5309,1,6,86.0),
|
||||||
|
WeightedItem(Items.KRANDORIAN_SEED_5310,1,6,80.0),
|
||||||
|
WeightedItem(Items.WILDBLOOD_SEED_5311,1,3,76.0),
|
||||||
|
WeightedItem(Items.MARIGOLD_SEED_5096,1,1,93.0),
|
||||||
|
WeightedItem(Items.NASTURTIUM_SEED_5098,1,1,90.0),
|
||||||
|
WeightedItem(Items.ROSEMARY_SEED_5097,1,1,78.0),
|
||||||
|
WeightedItem(Items.WOAD_SEED_5099,1,1,75.0),
|
||||||
|
WeightedItem(Items.LIMPWURT_SEED_5100,1,1,70.0),
|
||||||
|
WeightedItem(Items.REDBERRY_SEED_5101,1,1,50.0),
|
||||||
|
WeightedItem(Items.CADAVABERRY_SEED_5102,1,1,50.0),
|
||||||
|
WeightedItem(Items.DWELLBERRY_SEED_5103,1,1,50.0),
|
||||||
|
WeightedItem(Items.JANGERBERRY_SEED_5104,1,1,50.0),
|
||||||
|
WeightedItem(Items.WHITEBERRY_SEED_5105,1,1,50.0),
|
||||||
|
WeightedItem(Items.GUAM_SEED_5291,1,1,30.0),
|
||||||
|
WeightedItem(Items.MARRENTILL_SEED_5292,1,1,30.0),
|
||||||
|
WeightedItem(Items.TARROMIN_SEED_5293,1,1,30.0),
|
||||||
|
WeightedItem(Items.HARRALANDER_SEED_5294,1,1,30.0),
|
||||||
|
WeightedItem(Items.RANARR_SEED_5295,1,1,10.0),
|
||||||
|
WeightedItem(Items.TOADFLAX_SEED_5296,1,1,10.0),
|
||||||
|
WeightedItem(Items.IRIT_SEED_5297,1,1,10.0),
|
||||||
|
WeightedItem(Items.AVANTOE_SEED_5298,1,1,5.0),
|
||||||
|
WeightedItem(Items.KWUARM_SEED_5299,1,1,5.0),
|
||||||
|
WeightedItem(Items.SNAPDRAGON_SEED_5300,1,1,3.0),
|
||||||
|
WeightedItem(Items.CADANTINE_SEED_5301,1,1,3.0),
|
||||||
|
WeightedItem(Items.LANTADYME_SEED_5302,1,1,3.0),
|
||||||
|
WeightedItem(Items.DWARF_WEED_SEED_5303,1,1,3.0),
|
||||||
|
WeightedItem(Items.TORSTOL_SEED_5304,1,1,3.0)
|
||||||
|
)),
|
||||||
|
GUARD(intArrayOf(9, 32, 206, 296, 297, 298, 299, 344, 345, 346, 368, 678, 812, 9, 32, 296, 297, 298, 299, 2699, 2700, 2701, 2702, 2703, 3228, 3229, 3230, 3231, 3232, 3233, 3241, 3407, 3408, 4307, 4308, 4309, 4310, 4311, 5919, 5920), 40, 50.0, 240.0, 46.5, 2,2,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,30,30,1.0,true)
|
||||||
|
)),
|
||||||
|
FREMENNIK_CITIZEN(intArrayOf(2462), 45, 65.0, 240.0, 65.0, 2, 2, 5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,40,40,1.0,true)
|
||||||
|
)),
|
||||||
|
BEARDED_BANDIT(intArrayOf(1880, 1881, 6174), 45, 50.0, 240.0, 65.0, 5,5,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.ANTIPOISON4_2446,1,1,1.0),
|
||||||
|
WeightedItem(Items.LOCKPICK_1523,1,1,2.0),
|
||||||
|
WeightedItem(Items.COINS_995,1,1,4.0)
|
||||||
|
)),
|
||||||
|
DESERT_BANDIT(intArrayOf(1926, 1921), 53, 50.0, 240.0, 79.5, 3,3,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,50,1,3.0),
|
||||||
|
WeightedItem(Items.ANTIPOISON4_2446,1,1,1.0),
|
||||||
|
WeightedItem(Items.LOCKPICK_1523,1,1,1.0)
|
||||||
|
)),
|
||||||
|
KNIGHT_OF_ADROUGNE(intArrayOf(23, 26), 55, 50.0, 240.0, 84.3, 3,3,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,50,50,1.0,true)
|
||||||
|
)),
|
||||||
|
YANILLE_WATCHMAN(intArrayOf(34), 65, 137.5, 50.0, 240.0, 3,3,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,60,60,1.0,true),
|
||||||
|
WeightedItem(Items.BREAD_2309,1,1,1.0,true)
|
||||||
|
)),
|
||||||
|
MENAPHITE_THUG(intArrayOf(1905), 65, 50.0, 240.0, 137.5, 5,5,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,60,60,1.0,true)
|
||||||
|
)),
|
||||||
|
PALADIN(intArrayOf(20, 2256), 70, 50.0, 150.0,151.75, 3,3,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,80,80,1.0,true),
|
||||||
|
WeightedItem(Items.CHAOS_RUNE_562,2,2,1.0,true)
|
||||||
|
)),
|
||||||
|
GNOME(intArrayOf(66, 67, 68, 168, 169, 2249, 2250, 2251, 2371, 2649, 2650, 6002, 6004), 75, 8.0, 120.0, 198.5, 1,1,5, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,300,300,2.5),
|
||||||
|
WeightedItem(Items.EARTH_RUNE_557,1,1,3.5),
|
||||||
|
WeightedItem(Items.GOLD_ORE_445,1,1,1.0),
|
||||||
|
WeightedItem(Items.FIRE_ORB_569,1,1,5.0),
|
||||||
|
WeightedItem(Items.SWAMP_TOAD_2150,1,1,8.0),
|
||||||
|
WeightedItem(Items.KING_WORM_2162,1,1,9.0)
|
||||||
|
)),
|
||||||
|
HERO(intArrayOf(21), 80, 6.0, 100.0,273.3, 6,6,4, WeightBasedTable.create(
|
||||||
|
WeightedItem(Items.COINS_995,200,300,1.5),
|
||||||
|
WeightedItem(Items.DEATH_RUNE_560,2,2,1.0),
|
||||||
|
WeightedItem(Items.BLOOD_RUNE_565,1,1,0.5),
|
||||||
|
WeightedItem(Items.FIRE_ORB_569,1,1,2.5),
|
||||||
|
WeightedItem(Items.DIAMOND_1601,1,1,2.0),
|
||||||
|
WeightedItem(Items.GOLD_ORE_444,1,1,1.5),
|
||||||
|
WeightedItem(Items.JUG_OF_WINE_1993,1,1,3.0)
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val idMap = HashMap<Int,Pickpockets>(values().size * 5)
|
||||||
|
|
||||||
|
init {
|
||||||
|
values().forEach {
|
||||||
|
it.ids.forEach { id -> idMap[id] = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun forID(id: Int): Pickpockets? {
|
||||||
|
return idMap[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getSuccessChance(player: Player): Double{
|
||||||
|
return RandomFunction.getSkillSuccessChance(low,high,player.skills.getLevel(Skills.THIEVING))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
package rs09.game.node.entity.skill.thieving
|
||||||
|
|
||||||
|
import core.game.node.entity.combat.ImpactHandler
|
||||||
|
import core.game.node.entity.impl.Animator
|
||||||
|
import core.game.node.entity.player.Player
|
||||||
|
import core.game.node.entity.player.link.audio.Audio
|
||||||
|
import core.game.node.entity.skill.Skills
|
||||||
|
import core.game.node.entity.state.EntityState
|
||||||
|
import core.game.world.update.flag.context.Animation
|
||||||
|
import core.tools.RandomFunction
|
||||||
|
import org.rs09.consts.Items
|
||||||
|
import rs09.game.interaction.InteractionListener
|
||||||
|
import rs09.tools.secondsToTicks
|
||||||
|
|
||||||
|
class ThievingListeners : InteractionListener() {
|
||||||
|
|
||||||
|
private val PICKPOCKET_ANIM = Animation(881,Animator.Priority.HIGH)
|
||||||
|
private val NPC_ANIM = Animation(422)
|
||||||
|
private val STUN_ANIMATION = Animation(424,Animator.Priority.VERY_HIGH)
|
||||||
|
private val SOUND = Audio(2727, 1, 0)
|
||||||
|
|
||||||
|
override fun defineListeners() {
|
||||||
|
|
||||||
|
on(NPC,"pickpocket","pick-pocket"){player, node ->
|
||||||
|
val pickpocketData = Pickpockets.forID(node.id) ?: return@on false
|
||||||
|
var successMod = 0
|
||||||
|
|
||||||
|
if(player.inCombat()){
|
||||||
|
player.sendMessage("You can't pickpocket while in combat.")
|
||||||
|
return@on true
|
||||||
|
}
|
||||||
|
|
||||||
|
if(player.skills.getLevel(Skills.THIEVING) < pickpocketData.requiredLevel){
|
||||||
|
player.sendMessage("You need a Thieving level of ${pickpocketData.requiredLevel} to do that.")
|
||||||
|
return@on true
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!pickpocketData.table.canRoll(player)){
|
||||||
|
player.sendMessage("You don't have enough inventory space to do that.")
|
||||||
|
return@on true
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pickpocketData == Pickpockets.FEMALE_HAM_MEMBER || pickpocketData == Pickpockets.MALE_HAM_MEMBER){
|
||||||
|
successMod += getHAMItemCount(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(player.equipment.contains(Items.GLOVES_OF_SILENCE_10075,1)){
|
||||||
|
successMod += 3
|
||||||
|
}
|
||||||
|
|
||||||
|
player.animator.animate(PICKPOCKET_ANIM)
|
||||||
|
val chance = RandomFunction.randomDouble(1.0,100.0)
|
||||||
|
val failTreshold = pickpocketData.getSuccessChance(player) + successMod
|
||||||
|
|
||||||
|
if(chance > failTreshold){
|
||||||
|
player.stateManager.set(EntityState.STUNNED, secondsToTicks(pickpocketData.stunTime))
|
||||||
|
node.asNpc().face(player)
|
||||||
|
node.asNpc().animator.animate(NPC_ANIM)
|
||||||
|
player.animator.animate(STUN_ANIMATION)
|
||||||
|
player.audioManager.send(SOUND)
|
||||||
|
player.lock(secondsToTicks(pickpocketData.stunTime))
|
||||||
|
player.impactHandler.manualHit(node.asNpc(),RandomFunction.random(pickpocketData.stunDamageMin,pickpocketData.stunDamageMax),ImpactHandler.HitsplatType.NORMAL)
|
||||||
|
node.asNpc().face(null)
|
||||||
|
} else {
|
||||||
|
player.lock(2)
|
||||||
|
pickpocketData.table.roll(player).forEach { player.inventory.add(it) }
|
||||||
|
player.skills.addExperience(Skills.THIEVING,pickpocketData.experience)
|
||||||
|
}
|
||||||
|
|
||||||
|
return@on true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getHAMItemCount(player: Player): Int{
|
||||||
|
var counter = 0
|
||||||
|
for(item in player.equipment.toArray()){
|
||||||
|
item ?: continue
|
||||||
|
counter += when(item.id){
|
||||||
|
Items.HAM_LOGO_4306 -> 1
|
||||||
|
Items.HAM_ROBE_4300 -> 1
|
||||||
|
Items.HAM_HOOD_4302 -> 1
|
||||||
|
Items.HAM_CLOAK_4304 -> 1
|
||||||
|
Items.BOOTS_4310 -> 1
|
||||||
|
Items.GLOVES_4308 -> 1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return counter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue