Rewrote fletching

This commit is contained in:
sirdabalot 2025-11-28 13:16:55 +00:00 committed by Ryan
parent 12f217f8f3
commit 8bdfc43fba
65 changed files with 1983 additions and 3084 deletions

View file

@ -1,12 +1,12 @@
package content.global.bots
import content.global.skill.fletching.log.LogCraftInfo
import content.global.skill.fletching.log.CraftItemWithLogScript
import core.game.bots.Script
import core.game.bots.SkillingBotAssembler
import core.game.node.entity.skill.Skills
import content.global.skill.fletching.Fletching
import content.global.skill.fletching.FletchingPulse
import core.game.node.item.Item
import org.rs09.consts.Items
import core.game.bots.SkillingBotAssembler
import core.game.bots.Script
class FletchingBankstander : Script(){
var state = State.FLETCHING
@ -17,7 +17,7 @@ class FletchingBankstander : Script(){
State.FLETCHING -> {
bot.inventory.add(Item(Items.KNIFE_946))
bot.inventory.add(Item(Items.LOGS_1511,27))
bot.pulseManager.run(FletchingPulse(bot, Item(Items.LOGS_1511),27, Fletching.FletchingItems.ARROW_SHAFT))
CraftItemWithLogScript(bot, LogCraftInfo.ARROW_SHAFT, 27).invoke()
State.BANKING
}

View file

@ -56,7 +56,7 @@ public final class PotteryPlugin extends UseWithHandler {
@Override
public boolean handle(final NodeUsageEvent event) {
final Player player = event.getPlayer();
new SkillDialogueHandler(player, SkillDialogue.FIVE_OPTION, (Object[]) getPottery(false)) {
new SkillDialogueHandler(player, SkillDialogue.FIVE_OPTION, getPottery(false)) {
@Override
public void create(final int amount, int index) {
@ -145,7 +145,7 @@ public final class PotteryPlugin extends UseWithHandler {
* @return the dialogue handler.
*/
public SkillDialogueHandler getSkillHandler(final Player player) {
return new SkillDialogueHandler(player, SkillDialogue.FIVE_OPTION, (Object[]) getPottery(true)) {
return new SkillDialogueHandler(player, SkillDialogue.FIVE_OPTION, getPottery(true)) {
@Override
public void create(final int amount, final int index) {

View file

@ -34,7 +34,7 @@ public class SnakeSkinPlugin extends UseWithHandler {
@Override
public boolean handle(final NodeUsageEvent event) {
final Player player = event.getPlayer();
new SkillDialogueHandler(player, SkillDialogue.FIVE_OPTION, (Object[]) getSkins()) {
new SkillDialogueHandler(player, SkillDialogue.FIVE_OPTION, getSkins()) {
@Override
public void create(final int amount, int index) {

View file

@ -0,0 +1,8 @@
package content.global.skill.fletching
object AchievementDiaryAttributeKeys {
/**
* This attribute signifies that the fletch of the magic shortbow is complete which is the first stage of getting the achievement
*/
const val FLETCHED_UNSTRUNG_MAGIC_SHORTBOW = "diary:seers:fletch-magic-short-bow"
}

View file

@ -0,0 +1,16 @@
package content.global.skill.fletching
import org.rs09.consts.Items
object Feathers {
val all = intArrayOf(
Items.FEATHER_314,
Items.STRIPY_FEATHER_10087,
Items.RED_FEATHER_10088,
Items.BLUE_FEATHER_10089,
Items.YELLOW_FEATHER_10090,
Items.ORANGE_FEATHER_10091
)
const val STANDARD = Items.FEATHER_314
}

View file

@ -1,355 +0,0 @@
package content.global.skill.fletching;
import core.game.node.item.Item;
import core.game.world.update.flag.context.Animation;
import java.util.HashMap;
public class Fletching {
public static HashMap<Integer, FletchingItems[]>logMap = new HashMap<>();
public static HashMap<Integer, Bolts> boltMap = new HashMap<>();
public static HashMap<Integer, Darts> dartMap = new HashMap<>();
public static HashMap<Integer, ArrowHeads> arrowHeadMap = new HashMap<>();
public static HashMap<Integer, GemBolts> gemMap = new HashMap<>();
public static HashMap<Integer, GemBolts> tipMap = new HashMap<>();
public static HashMap<Integer, String> stringMap = new HashMap<>();
public static HashMap<Integer, Limb> limbMap = new HashMap<>();
static{
Items[] itemsArray = Items.values();
int thisLength = itemsArray.length;
for(int x = 0; x < thisLength; x++){
Items item = itemsArray[x];
logMap.putIfAbsent(item.id, item.items);
}
Bolts[] boltArray = Bolts.values();
thisLength = boltArray.length;
for(int x = 0; x < thisLength; x++){
Bolts bolt = boltArray[x];
boltMap.putIfAbsent(bolt.unfinished,bolt);
}
Darts[] dartArray = Darts.values();
thisLength = dartArray.length;
for(int x = 0; x < thisLength; x++){
Darts dart = dartArray[x];
dartMap.putIfAbsent(dart.unfinished,dart);
}
ArrowHeads[] ahArray = ArrowHeads.values();
thisLength = ahArray.length;
for(int x = 0; x < thisLength; x++){
ArrowHeads arrowhead = ahArray[x];
arrowHeadMap.putIfAbsent(arrowhead.unfinished,arrowhead);
}
GemBolts[] gbArray = GemBolts.values();
thisLength = gbArray.length;
for(int x = 0; x < thisLength; x++){
GemBolts gem = gbArray[x];
gemMap.putIfAbsent(gem.gem,gem);
tipMap.putIfAbsent(gem.tip,gem);
}
String[] stringArray = String.values();
thisLength = stringArray.length;
for(int x = 0; x < thisLength; x++){
String bow = stringArray[x];
stringMap.putIfAbsent(bow.unfinished,bow);
}
Limb[] limbsArray = Limb.values();
thisLength = limbsArray.length;
for(int x = 0; x < thisLength; x++){
Limb limb = limbsArray[x];
limbMap.putIfAbsent(limb.stock, limb);
}
}
public static FletchingItems[] getEntries(int id){
return logMap.get(id);
}
public static boolean isLog(int id){
return logMap.get(id) != null;
}
public static boolean isBolt(int id){
return boltMap.get(id) != null;
}
public static boolean isDart(int id){
return dartMap.get(id) != null;
}
public static boolean isArrowHead(int id){
return arrowHeadMap.get(id) != null;
}
public static boolean isGemTip(int id){
return tipMap.get(id) != null;
}
public static Item[] getItems(int id){
FletchingItems[] entry = getEntries(id);
Item items[] = {};
switch(entry.length){
case 1:
items = new Item[] {new Item(entry[0].id)};
break;
case 2:
items = new Item[] {new Item(entry[0].id), new Item(entry[1].id)};
break;
case 3:
items = new Item[] {new Item(entry[0].id), new Item(entry[1].id), new Item(entry[2].id)};
break;
case 4:
items = new Item[] {new Item(entry[0].id), new Item(entry[1].id), new Item(entry[2].id), new Item(entry[3].id)};
break;
}
return items;
}
public enum Limb {
WOODEN_STOCK(9440,9420,9454,9, 12, new Animation(4436)),
OAK_STOCK(9442,9422,9456,24, 32, new Animation(4437)),
WILLOW_STOCK(9444,9423,9457,39, 44, new Animation(4438)),
TEAK_STOCK(9446,9425,9459,46, 54, new Animation(4439)),
MAPLE_STOCK(9448,9427,9461,54, 64, new Animation(4440)),
MAHOGANY_STOCK(9450,9429,9463,61, 82, new Animation(4441)),
YEW_STOCK(9452,9431,9465,69, 100, new Animation(4442));
public int stock, limb, product,level;
public double experience;
public Animation animation;
Limb(int stock, int limb, int product, int level, double experience, Animation animation) {
this.stock = stock;
this.limb = limb;
this.product = product;
this.level = level;
this.experience = experience;
this.animation = animation;
}
}
public enum String{
//Bows
SHORT_BOW((byte) 1,50,841,5, 5, new Animation(6678)),
LONG_BOW((byte) 1,48,839,10, 10, new Animation(6684)),
OAK_SHORTBOW((byte) 1,54,843,20, 16.5, new Animation(6679)),
OAK_LONGBOW((byte) 1,56,845,25, 25, new Animation(6685)),
WILLOW_SHORTBOW((byte) 1,60,849,35, 33.3, new Animation(6680)),
WILLOW_LONGBOW((byte) 1,58,847,40, 41.5, new Animation(6686)),
MAPLE_SHORTBOW((byte) 1,64,853,50, 50, new Animation(6681)),
MAPLE_LONGBOW((byte) 1,62,851,55, 58.3, new Animation(6687)),
YEW_SHORTBOW((byte) 1,68,857,65, 67.5, new Animation(6682)),
YEW_LONGBOW((byte) 1,66,855,70, 75, new Animation(6688)),
MAGIC_SHORTBOW((byte) 1,72,861,80, 83.3, new Animation(6683)),
MAGIC_LONGBOW((byte) 1,70,859,85, 91.5, new Animation(6689)),
OGRE_COMP_BOW((byte) 1,4825,4827,30, 45, new Animation(-1)),
//crossbows
BRONZE_CBOW((byte) 2,9454,9174,9, 6, new Animation(6671)),
BLURITE_CBOW((byte) 2,9456,9176,24, 16, new Animation(6672)),
IRON_CBOW((byte) 2,9457,9177,39, 22, new Animation(6673)),
STEEL_CBOW((byte) 2,9459,9179,46, 27, new Animation(6674)),
MITHIRIL_CBOW((byte) 2,9461,9181,54, 32, new Animation(6675)),
ADAMANT_CBOW((byte) 2,9463,9183,61, 41, new Animation(6676)),
RUNITE_CBOW((byte) 2,9465,9185,69, 50, new Animation(6677));
public int unfinished,product,string,level;
public final double experience;
public final Animation animation;
String(byte indicator, final int unfinished, final int product, final int level, final double experience, final Animation animation) {
this.unfinished = unfinished;
this.product = product;
this.level = level;
this.experience = experience;
this.animation = animation;
switch(indicator & 0xFF){
case 1:
this.string = org.rs09.consts.Items.BOW_STRING_1777;
break;
case 2:
this.string = org.rs09.consts.Items.CROSSBOW_STRING_9438;
break;
default:
break;
}
}
}
public enum GemBolts {
OPAL(877, org.rs09.consts.Items.OPAL_1609, 45, 879, 11, 1.6),
PEARL(9140, org.rs09.consts.Items.OYSTER_PEARL_411, 46, 880, 41, 3.2),
PEARLS(9140, org.rs09.consts.Items.OYSTER_PEARLS_413, 46, 880, 41, 3.2),
JADE(9139, org.rs09.consts.Items.JADE_1611, 9187, 9335, 26, 2.4),
RED_TOPAZ(9141, org.rs09.consts.Items.RED_TOPAZ_1613, 9188, 9336, 48, 3.9),
SAPPHIRE(9142, org.rs09.consts.Items.SAPPHIRE_1607, 9189, 9337, 56, 4.7),
EMERALD(9142, org.rs09.consts.Items.EMERALD_1605, 9190, 9338, 58, 5.5),
RUBY(9143, org.rs09.consts.Items.RUBY_1603, 9191, 9339, 63, 6.3),
DIAMOND(9143, org.rs09.consts.Items.DIAMOND_1601, 9192, 9340, 65, 7),
DRAGONSTONE(9144, org.rs09.consts.Items.DRAGONSTONE_1615, 9193, 9341, 71, 8.2),
ONYX(9144, org.rs09.consts.Items.ONYX_6573, 9194, 9342, 73, 9.4);
public int gem,tip,base,product,level;
public double experience;
GemBolts(int base, int gem, int tip, int product, int level, double experience){
this.gem = gem;
this.tip = tip;
this.base = base;
this.product = product;
this.level = level;
this.experience = experience;
}
}
public enum ArrowHeads {
BRONZE_ARROW(39, 882, 1, 1.3),
IRON_ARROW(40, 884, 15, 2.5),
STEEL_ARROW(41, 886, 30, 5),
MITHRIL_ARROW(42, 888, 45, 7.5),
ADAMANT_ARROW(43, 890, 60, 10),
RUNE_ARROW(44, 892, 75, 12.5),
DRAGON_ARROW(11237, 11212, 90, 15),
BROAD_ARROW(13278, 4160, 52, 15);
public int unfinished,finished,level;
public double experience;
ArrowHeads(int unfinished, int finished, int level, double experience){
this.unfinished = unfinished;
this.finished = finished;
this.level = level;
this.experience = experience;
}
public Item getFinished(){
return new Item(finished);
}
public Item getUnfinished(){
return new Item(unfinished);
}
}
public enum Darts{
BRONZE_DART(819, 806, 1, 1.8),
IRON_DART(820, 807, 22, 3.8),
STEEL_DART(821, 808, 37, 7.5),
MITHRIL_DART(822, 809, 52, 11.2),
ADAMANT_DART(823, 810, 67, 15),
RUNE_DART(824, 811, 81, 18.8),
DRAGON_DART(11232, 11230, 95, 25);
public int unfinished, finished, level;
public double experience;
Darts(int unfinished, int finished, int level, double experience){
this.unfinished = unfinished;
this.finished = finished;
this.level = level;
this.experience = experience;
}
public Item getFinished(){
return new Item(finished);
}
public Item getUnfinished(){
return new Item(unfinished);
}
}
public enum Bolts{
BRONZE_BOLT(9375, 877, 9, 0.5),
BLURITE_BOLT(9376, 9139, 24, 1),
IRON_BOLT(9377, 9140, 39, 1.5),
SILVER_BOLT(9382, 9145, 43, 2.5),
STEEL_BOLT(9378, 9141, 46, 3.5),
MITHRIL_BOLT(9379, 9142, 54, 5),
ADAMANTITE_BOLT(9380, 9143, 61, 7),
RUNITE_BOLT(9381, 9144, 69, 10),
BROAD_BOLT(13279, 13280, 55, 3);
public int unfinished, finished, level;
public double experience;
Bolts(int unfinished, int finished, int level, double experience){
this.unfinished = unfinished;
this.finished = finished;
this.level = level;
this.experience = experience;
}
public Item getFinished(){
return new Item(finished);
}
public Item getUnfinished(){
return new Item(unfinished);
}
}
private enum Items{
STANDARD(1511,FletchingItems.ARROW_SHAFT, FletchingItems.SHORT_BOW, FletchingItems.LONG_BOW, FletchingItems.WOODEN_STOCK),
ACHEY(2862, FletchingItems.OGRE_ARROW_SHAFT, FletchingItems.OGRE_COMP_BOW),
OAK(1521, FletchingItems.OAK_SHORTBOW, FletchingItems.OAK_LONGBOW, FletchingItems.OAK_STOCK),
WILLOW(1519, FletchingItems.WILLOW_SHORTBOW, FletchingItems.WILLOW_LONGBOW, FletchingItems.WILLOW_STOCK),
MAPLE(1517, FletchingItems.MAPLE_SHORTOW, FletchingItems.MAPLE_LONGBOW, FletchingItems.MAPLE_STOCK),
YEW(1515, FletchingItems.YEW_SHORTBOW, FletchingItems.YEW_LONGBOW, FletchingItems.YEW_STOCK),
MAGIC(1513, FletchingItems.MAGIC_SHORTBOW, FletchingItems.MAGIC_LONGBOW),
TEAK(6333, FletchingItems.TEAK_STOCK),
MAHOGANY(6332, FletchingItems.MAHOGANY_STOCK);
FletchingItems[] items;
int id;
Items(int id, FletchingItems item_1, FletchingItems item_2, FletchingItems item_3, FletchingItems item_4){
items = new FletchingItems[] {item_1, item_2, item_3, item_4};
this.id = id;
}
Items(int id, FletchingItems item_1, FletchingItems item_2, FletchingItems item_3){
items = new FletchingItems[] {item_1, item_2, item_3};
this.id = id;
}
Items(int id, FletchingItems item_1, FletchingItems item_2){
items = new FletchingItems[] {item_1, item_2};
this.id = id;
}
Items(int id, FletchingItems item_1){
items = new FletchingItems[] {item_1};
this.id = id;
}
}
public enum FletchingItems {
//Standard logs
ARROW_SHAFT(52, 5, 1, 15),
SHORT_BOW(50, 5, 5, 1),
LONG_BOW(48, 10, 10, 1),
WOODEN_STOCK(9440, 6, 9, 1),
//Achey logs
OGRE_ARROW_SHAFT(2864, 6.4, 5, 4),
OGRE_COMP_BOW(4825, 45, 30, 1),
//Oak logs
OAK_SHORTBOW(54, 16.5, 20, 1),
OAK_LONGBOW(56,25,25,1),
OAK_STOCK(9442, 16, 24, 1),
//Willow logs
WILLOW_SHORTBOW(60, 33.3, 35, 1),
WILLOW_LONGBOW(58, 41.5, 40, 1),
WILLOW_STOCK(9444, 22, 39, 1),
//Maple logs
MAPLE_SHORTOW(64, 50, 50, 1),
MAPLE_LONGBOW(62, 58.3, 55, 1),
MAPLE_STOCK(9448, 32, 54, 1),
//Yew logs
YEW_SHORTBOW(68, 67.5, 65, 1),
YEW_LONGBOW(66, 75, 70, 1),
YEW_STOCK(9452, 50, 69, 1),
//Magic logs
MAGIC_SHORTBOW(72, 83.3, 80,1),
MAGIC_LONGBOW(70, 91.5, 85, 1),
//Teak
TEAK_STOCK(9446, 27, 46,1),
//Mahogany
MAHOGANY_STOCK(9450, 41.0, 61, 1);
int id,level,amount,logId;
double experience;
FletchingItems(int id, double experience, int level, int amount){
this.id = id;
this.level = level;
this.amount = amount;
this.experience = experience;
}
public Item getItem(){
return new Item(id);
}
}
}

View file

@ -1,197 +0,0 @@
package content.global.skill.fletching
import content.data.Quests
import content.global.skill.fletching.items.arrow.ArrowHeadPulse
import content.global.skill.fletching.items.arrow.HeadlessArrowPulse
import content.global.skill.fletching.items.arrow.HeadlessOgreArrowPulse
import content.global.skill.fletching.items.bow.StringPulse
import content.global.skill.fletching.items.crossbow.LimbPulse
import core.api.*
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.net.packet.PacketRepository
import core.net.packet.context.ChildPositionContext
import core.net.packet.out.RepositionChild
import org.rs09.consts.Components
import org.rs09.consts.Items
import org.rs09.consts.Items.BLUE_FEATHER_10089
import org.rs09.consts.Items.FEATHER_314
import org.rs09.consts.Items.ORANGE_FEATHER_10091
import org.rs09.consts.Items.RED_FEATHER_10088
import org.rs09.consts.Items.STRIPY_FEATHER_10087
import org.rs09.consts.Items.YELLOW_FEATHER_10090
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import core.game.node.entity.player.Player
class FletchingListeners : InteractionListener {
val LIMBIDs = Fletching.Limb.values().map(Fletching.Limb::limb).toIntArray()
val STOCKIDs = Fletching.Limb.values().map(Fletching.Limb::stock).toIntArray()
val MITHRIL_BOLT = Items.MITHRIL_BOLTS_9142
val MITH_GRAPPLE_TIP = Items.MITH_GRAPPLE_TIP_9416
val ROPE = Items.ROPE_954
val MITH_GRAPPLE = Items.MITH_GRAPPLE_9418
val ROPE_GRAPPLE = Items.MITH_GRAPPLE_9419
val ARROW_SHAFT = Items.ARROW_SHAFT_52
val OGRE_ARROW_SHAFT = Items.OGRE_ARROW_SHAFT_2864
val FLETCHED_SHAFT = Items.HEADLESS_ARROW_53
val FLIGHTED_OGRE_ARROW = Items.FLIGHTED_OGRE_ARROW_2865
val UNFINISHED_ARROWS = Fletching.ArrowHeads.values().map(Fletching.ArrowHeads::unfinished).toIntArray()
val FEATHERS = intArrayOf(FEATHER_314,STRIPY_FEATHER_10087,RED_FEATHER_10088,BLUE_FEATHER_10089,YELLOW_FEATHER_10090,ORANGE_FEATHER_10091)
val UNSTRUNG_BOWS = Fletching.String.values().map(Fletching.String::unfinished).toIntArray()
val STRINGS = intArrayOf(Items.BOW_STRING_1777,Items.CROSSBOW_STRING_9438)
override fun defineListeners() {
onUseWith(IntType.ITEM,STRINGS,*UNSTRUNG_BOWS){ player, string, bow ->
val enum = Fletching.stringMap[bow.id] ?: return@onUseWith false
if (bow.id == Items.UNSTRUNG_COMP_BOW_4825) {
// You shouldn't be able to string a bow
if (getQuestStage(player, Quests.ZOGRE_FLESH_EATERS) < 8) {
player.packetDispatch.sendMessage("You must have started Zogre Flesh Eaters and asked Grish to string this.")
return@onUseWith true
}
}
if(enum.string != string.id){
player.sendMessage("That's not the right kind of string for this.")
return@onUseWith true
}
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, Item(enum.product)) {
override fun create(amount: Int, index: Int) {
player.pulseManager.run(StringPulse(player, string.asItem(), enum, amount))
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(string.asItem())
}
}
handler.open()
PacketRepository.send(RepositionChild::class.java, ChildPositionContext(player, Components.SKILL_MULTI1_309, 2, 215, 10))
return@onUseWith true
}
onUseWith(IntType.ITEM,ARROW_SHAFT,*FEATHERS){ player, shaft, feather ->
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(FLETCHED_SHAFT)) {
override fun create(amount: Int, index: Int) {
player.pulseManager.run(HeadlessArrowPulse(player, shaft.asItem(), Item(feather.id), amount))
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(FLETCHED_SHAFT)
}
}
handler.open()
return@onUseWith true
}
onUseWith(IntType.ITEM,OGRE_ARROW_SHAFT,*FEATHERS){ player, shaft, feather ->
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(FLIGHTED_OGRE_ARROW)) {
override fun create(amount: Int, index: Int) {
player.pulseManager.run(HeadlessOgreArrowPulse(player, shaft.asItem(), Item(feather.id, 4), amount))
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(FLIGHTED_OGRE_ARROW)
}
}
handler.open()
return@onUseWith true
}
onUseWith(IntType.ITEM,FLETCHED_SHAFT,*UNFINISHED_ARROWS){ player, shaft, unfinished ->
val head = Fletching.arrowHeadMap[unfinished.id] ?: return@onUseWith false
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, head.getFinished()) {
override fun create(amount: Int, index: Int) {
player.pulseManager.run(ArrowHeadPulse(player, shaft.asItem(), head, amount))
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(head.getUnfinished())
}
}
handler.open()
return@onUseWith true
}
onUseWith(IntType.ITEM,MITHRIL_BOLT,MITH_GRAPPLE_TIP){ player, bolt, tip ->
if(player.skills.getLevel(Skills.FLETCHING) < 59){
player.sendMessage("You need a fletching level of 59 to make this.")
return@onUseWith true
}
if(player.inventory.remove(Item(MITHRIL_BOLT,1),tip.asItem())){
player.inventory.add(Item(MITH_GRAPPLE))
}
return@onUseWith true
}
onUseWith(IntType.ITEM,ROPE,MITH_GRAPPLE){ player, rope, grapple ->
if(player.skills.getLevel(Skills.FLETCHING) < 59){
player.sendMessage("You need a fletching level of 59 to make this.")
return@onUseWith true
}
if(player.inventory.remove(rope.asItem(),grapple.asItem())){
player.inventory.add(Item(ROPE_GRAPPLE))
}
return@onUseWith true
}
onUseWith(IntType.ITEM,LIMBIDs,*STOCKIDs){ player, limb, stock ->
val limbEnum = Fletching.limbMap[stock.id] ?: return@onUseWith false
if(limbEnum.limb != limb.id){
player.sendMessage("That's not the right limb to attach to that stock.")
return@onUseWith true
}
val handler: SkillDialogueHandler = object : SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, Item(limbEnum.product)){
override fun create(amount: Int, index: Int) {
player.pulseManager.run(LimbPulse(player, stock.asItem(), limbEnum, amount))
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(stock.asItem())
}
}
handler.open()
PacketRepository.send(RepositionChild::class.java, ChildPositionContext(player, Components.SKILL_MULTI1_309, 2, 210, 10))
return@onUseWith true
}
/**
* (Long) Kebbit bolts don't need feathers and go 6 at a time so use their own interaction
*/
fun makeKebbitBolt(player : Player, ingredient : Item) : Boolean{
val longBolts = when(ingredient.id){
Items.KEBBIT_SPIKE_10105 -> false
Items.LONG_KEBBIT_SPIKE_10107 -> true
else -> return false
}
val level = if(longBolts) 42 else 26
if (getDynLevel(player, Skills.FLETCHING) < level){
sendMessage(player, "You need a fletching level of $level to create ${if (longBolts) "long " else ""}kebbit bolts.")
return true
}
val finalProduct = if(longBolts) Items.LONG_KEBBIT_BOLTS_10159 else Items.KEBBIT_BOLTS_10158
val xp = if(longBolts) 47.7 else 28.6 // source https://runescape.wiki/w/Fletching?oldid=1069981#Bolts_2
if(removeItem(player, ingredient.id)){
addItem(player, finalProduct, 6)
player.skills.addExperience(Skills.FLETCHING, xp)
animate(player, 885)
}
return true
}
onUseWith(IntType.ITEM, Items.CHISEL_1755, Items.KEBBIT_SPIKE_10105) { player, used, with ->
return@onUseWith makeKebbitBolt(player, with as Item)
}
onUseWith(IntType.ITEM, Items.CHISEL_1755, Items.LONG_KEBBIT_SPIKE_10107) { player, used, with ->
return@onUseWith makeKebbitBolt(player, with as Item)
}
}
}

View file

@ -1,131 +0,0 @@
package content.global.skill.fletching;
import content.global.skill.fletching.items.bolts.BoltPulse;
import content.global.skill.fletching.items.darts.DartPulse;
import org.rs09.consts.Items;
import core.game.dialogue.SkillDialogueHandler;
import core.game.dialogue.SkillDialogueHandler.SkillDialogue;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.net.packet.PacketRepository;
import core.net.packet.context.ChildPositionContext;
import core.net.packet.out.RepositionChild;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used to open the fletching dialogue.
* @author Ceikry
*/
@Initializable
public class FletchingPlugin extends UseWithHandler {
public FletchingPlugin() {
super(819,820,821,822,823,824,11232,9375,9376,9377,9382,9378,9379,9380,9381,13279,1511,1521,1519,1517,1515,1513,2862,6332,6333, Items.MAHOGANY_LOGS_6332);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
// Knife
addHandler(946, ITEM_TYPE, this);
// Feathers plus colored feathers
addHandler(314, ITEM_TYPE,this);
addHandler(10087, ITEM_TYPE, this);
addHandler(10088, ITEM_TYPE, this);
addHandler(10089, ITEM_TYPE, this);
addHandler(10090, ITEM_TYPE, this);
addHandler(10091, ITEM_TYPE, this);
return this;
}
@Override
public boolean handle(final NodeUsageEvent event) {
final Player player = event.getPlayer();
//handle darts
if(Fletching.isDart(event.getUsedItem().getId())){
final Fletching.Darts dart = Fletching.dartMap.get(event.getUsedItem().getId());
SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, dart.getFinished()) {
@Override
public void create(final int amount, int index) {
player.getPulseManager().run(new DartPulse(player, event.getUsedItem(), dart, amount));
}
@Override
public int getAll(int index) {
return player.getInventory().getAmount(event.getUsedItem());
}
};
handler.open();
return true;
}
//handle bolts
if(Fletching.isBolt(event.getUsedItem().getId()) || Fletching.isBolt(event.getUsedWith().getId())){
// figure out which of the used items is a bolt, and which is potentially a feather
final Fletching.Bolts bolt
= Fletching.isBolt(event.getUsedItem().getId())
? Fletching.boltMap.get(event.getUsedItem().getId())
: Fletching.boltMap.get(event.getUsedWith().getId());
final int featherId
= Fletching.isBolt(event.getUsedItem().getId())
? event.getUsedWith().getId()
: event.getUsedItem().getId();
final boolean hasFeather = (featherId == 314 || (featherId >= 10087 && featherId <= 10091));
if (hasFeather) {
SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, bolt.getFinished()) {
@Override
public void create(final int amount, int index) {
player.getPulseManager().run(new BoltPulse(player, event.getUsedItem(), bolt, new Item(featherId), amount));
}
@Override
public int getAll(int index) {
return player.getInventory().getAmount(event.getUsedItem());
}
};
handler.open();
return true;
}
return false;
}
//handle logs
if(Fletching.isLog(event.getUsedItem().getId()) && event.getUsedWith().getId() == 946) {
final Item log = event.getUsedItem();
Item[] items = Fletching.getItems(log.getId());
SkillDialogue dialLength = SkillDialogue.ONE_OPTION;
switch (items.length) {
case 2:
dialLength = SkillDialogue.TWO_OPTION;
break;
case 3:
dialLength = SkillDialogue.THREE_OPTION;
break;
case 4:
dialLength = SkillDialogue.FOUR_OPTION;
break;
}
SkillDialogueHandler handler = new SkillDialogueHandler(player, dialLength, items) {
@Override
public void create(final int amount, int index) {
final Fletching.FletchingItems item = Fletching.getEntries(log.getId())[index];
player.getPulseManager().run(new FletchingPulse(player, log, amount, item));
}
@Override
public int getAll(int index) {
return player.getInventory().getAmount(log);
}
};
handler.open();
return true;
}
return false;
}
}

View file

@ -1,145 +0,0 @@
package content.global.skill.fletching;
import core.tools.RandomFunction;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.world.map.zone.ZoneBorders;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.update.flag.context.Animation;
import core.tools.StringUtils;
import content.data.Quests;
/**
* fletching skill pulse
* @author ceik
*/
public final class FletchingPulse extends SkillPulse<Item> {
/**
* Seers bank zone borders for the diary task
*/
private static final ZoneBorders bankZone = new ZoneBorders(2721,3493,2730,3487);
/**
* Represents the animation used in this generic pulse.
*/
private static final Animation ANIMATION = new Animation(1248);
/**
* Represents the item we are fletching.
*/
private Fletching.FletchingItems fletch;
/**
* Represents the amount to fletch.
*/
private int amount = 0;
/**
* Represents the amount to arrows fletched (for ogre arrow shafts which is a random number from 2-6).
*/
private int finalAmount = 0;
/**
* Constructs a new {@code FletchingPulse.java} {@code Object}.
* @param player
* @param node
*/
public FletchingPulse(final Player player, final Item node, final int amount, final Fletching.FletchingItems fletch) {
super(player, node);
this.amount = amount;
this.fletch = fletch;
}
@Override
public boolean checkRequirements() {
if (player.getSkills().getLevel(Skills.FLETCHING) < fletch.level) {
player.getDialogueInterpreter().sendDialogue("You need a Fletching skill of " + fletch.level + " or above to make " + (StringUtils.isPlusN(fletch.getItem().getName().replace("(u)", "").trim()) ? "an" : "a") + " " + fletch.getItem().getName().replace("(u)", "").trim());
return false;
}
if (amount > player.getInventory().getAmount(node)) {
amount = player.getInventory().getAmount(node);
}
if (fletch == Fletching.FletchingItems.OGRE_ARROW_SHAFT) {
if (player.getQuestRepository().getQuest(Quests.BIG_CHOMPY_BIRD_HUNTING).getStage(player) == 0) {
player.getPacketDispatch().sendMessage("You must have started Big Chompy Bird Hunting to make those.");
return false;
}
}
if (fletch == Fletching.FletchingItems.OGRE_COMP_BOW) {
// Technically, this isn't supposed to show up till you've asked Grish.
if (player.getQuestRepository().getQuest(Quests.ZOGRE_FLESH_EATERS).getStage(player) < 8) {
player.getPacketDispatch().sendMessage("You must have started Zogre Flesh Eaters and asked Grish to make this.");
return false;
}
if (!player.getInventory().contains(2859, 1)) {
player.getPacketDispatch().sendMessage("You need to have Wolf Bones in order to make this.");
return false;
}
}
return true;
}
@Override
public void animate() {
player.animate(ANIMATION);
}
@Override
public boolean reward() {
if(bankZone.insideBorder(player) && fletch == Fletching.FletchingItems.MAGIC_SHORTBOW) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 2, 2);
}
if (getDelay() == 1) {
super.setDelay(4);
return false;
}
if (player.getInventory().remove(node)) {
final Item item = new Item(fletch.id,fletch.amount);
if ( fletch == Fletching.FletchingItems.OGRE_ARROW_SHAFT ) {
// The amount of shafts given is random; between two and six will be made.
finalAmount = RandomFunction.random(2,6);
item.setAmount(finalAmount);
}
if ( fletch == Fletching.FletchingItems.OGRE_COMP_BOW ) {
if (!player.getInventory().contains(2859, 1)) {
return false;
} else {
player.getInventory().remove(new Item(2859));
}
}
player.getInventory().add(item);
player.getSkills().addExperience(Skills.FLETCHING, fletch.experience, true);
String message = getMessage();
player.getPacketDispatch().sendMessage(message);
if (fletch.id == Fletching.FletchingItems.MAGIC_SHORTBOW.id
&& (new ZoneBorders(2721, 3489, 2724, 3493, 0).insideBorder(player)
|| new ZoneBorders(2727, 3487, 2730, 3490, 0).insideBorder(player))
&& !player.getAchievementDiaryManager().hasCompletedTask(DiaryType.SEERS_VILLAGE, 2, 2)) {
player.setAttribute("/save:diary:seers:fletch-magic-short-bow", true);
}
} else {
return true;
}
amount--;
return amount == 0;
}
/**
* Method used to get the message of the fletch.
* @return the message.
*/
public String getMessage() {
switch (fletch) {
case ARROW_SHAFT:
return "You carefully cut the wood into 15 arrow shafts.";
case OGRE_ARROW_SHAFT:
return "You carefully cut the wood into " + finalAmount + " arrow shafts.";
default:
return "You carefully cut the wood into " + (StringUtils.isPlusN(fletch.getItem().getName()) ? "an" : "a") + " " + fletch.getItem().getName().replace("(u)", "").trim() + ".";
}
}
}

View file

@ -1,69 +0,0 @@
package content.global.skill.fletching
import content.global.skill.fletching.Fletching.GemBolts
import content.global.skill.fletching.items.gem.GemBoltCutPulse
import content.global.skill.fletching.items.gem.GemBoltPulse
import core.api.amountInInventory
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.item.Item
import core.net.packet.PacketRepository
import core.net.packet.context.ChildPositionContext
import core.net.packet.out.RepositionChild
import org.rs09.consts.Items
import kotlin.math.min
class GemBoltListener : InteractionListener {
val gems = intArrayOf(
Items.OYSTER_PEARL_411,
Items.OYSTER_PEARLS_413,
Items.OPAL_1609,
Items.JADE_1611,
Items.RED_TOPAZ_1613,
Items.SAPPHIRE_1607,
Items.EMERALD_1605,
Items.RUBY_1603,
Items.DIAMOND_1601,
Items.DRAGONSTONE_1615,
Items.ONYX_6573
)
val boltBases = GemBolts.values().map { it.base }.toIntArray()
val boltTips = GemBolts.values().map { it.tip }.toIntArray()
override fun defineListeners() {
onUseWith(IntType.ITEM, Items.CHISEL_1755, *gems) { player, used, with ->
val gem = Fletching.gemMap[with.id] ?: return@onUseWith true
object : SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, Item(gem.gem)) {
override fun create(amount: Int, index: Int) {
player.pulseManager.run(GemBoltCutPulse(player, used as? Item, gem, amount))
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(gem.gem)
}
}.open()
return@onUseWith true
}
onUseWith(IntType.ITEM, boltBases, *boltTips) {player, used, with ->
val bolt = Fletching.tipMap[with.id] ?: return@onUseWith true
if (used.id != bolt.base || with.id != bolt.tip) return@onUseWith true
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(bolt.product)) {
override fun create(amount: Int, index: Int) {
player.pulseManager.run(GemBoltPulse(player, used as? Item, bolt, amount))
}
override fun getAll(index: Int): Int {
return min(amountInInventory(player, used.id), amountInInventory(player, with.id))
}
}
handler.open()
return@onUseWith true
}
}
}

View file

@ -0,0 +1,21 @@
package content.global.skill.fletching
import core.game.node.Node
import core.game.world.map.zone.ZoneBorders
object Zones {
val seersMagicShortbowAchievementZones = arrayOf(
ZoneBorders(2721, 3489, 2724, 3493, 0),
ZoneBorders(2727, 3487, 2730, 3490, 0),
ZoneBorders(2721, 3493, 2730, 3487)
)
fun inAnyZone(node: Node, zones: Array<ZoneBorders>): Boolean {
for (zone in zones) {
if (zone.insideBorder(node)) {
return true
}
}
return false
}
}

View file

@ -0,0 +1,24 @@
package content.global.skill.fletching.arrow
import org.rs09.consts.Items
enum class ArrowCraftInfo(val tipItemId: Int, val arrowItemId: Int, val level: Int, val experience: Double) {
BRONZE_ARROW(Items.BRONZE_ARROWTIPS_39, Items.BRONZE_ARROW_882, 1, 1.3),
IRON_ARROW(Items.IRON_ARROWTIPS_40, Items.IRON_ARROW_884, 15, 2.5),
STEEL_ARROW(Items.STEEL_ARROWTIPS_41, Items.STEEL_ARROW_886, 30, 5.0),
MITHRIL_ARROW(Items.MITHRIL_ARROWTIPS_42, Items.MITHRIL_ARROW_888, 45, 7.5),
ADAMANT_ARROW(Items.ADAMANT_ARROWTIPS_43, Items.ADAMANT_ARROW_890, 60, 10.0),
RUNE_ARROW(Items.RUNE_ARROWTIPS_44, Items.RUNE_ARROW_892, 75, 12.5),
DRAGON_ARROW(Items.DRAGON_ARROWTIPS_11237,Items.DRAGON_ARROW_11212, 90, 15.0),
BROAD_ARROW(Items.BROAD_ARROW_HEADS_13278, Items.BROAD_ARROW_4160, 52, 15.0);
companion object {
private val arrowCraftInfoByTipId = values().associateBy { it.tipItemId }
val arrowTipIds: IntArray = values().map { arrowCraftInfo: ArrowCraftInfo -> arrowCraftInfo.tipItemId }.toIntArray()
fun fromTipId(tipId: Int) : ArrowCraftInfo? {
return arrowCraftInfoByTipId[tipId]
}
}
}

View file

@ -0,0 +1,112 @@
package content.global.skill.fletching.arrow
import content.global.skill.fletching.Feathers
import core.api.*
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
@Suppress("unused") // Reflectively loaded
class ArrowListeners : InteractionListener {
private val arrowShaft = Items.ARROW_SHAFT_52
val headlessArrow = Items.HEADLESS_ARROW_53
companion object {
const val FLIGHTED_OGRE_ARROW_LEVEL = 5
fun sendLevelCheckFailDialog(player: Player, level: Int) {
sendDialogue(
player,
"You need a fletching level of $level to do this."
)
}
}
override fun defineListeners() {
onUseWith(IntType.ITEM, arrowShaft, *Feathers.all) { player, shaft, feather ->
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(headlessArrow)) {
override fun create(amount: Int, index: Int) {
if (!hasSpaceFor(player, Item(headlessArrow))) {
sendDialogue(player, "You do not have enough inventory space.")
return
}
HeadlessArrowCraftScript(player, feather.id, amount).invoke()
}
override fun getAll(index: Int): Int {
return amountInInventory(player, headlessArrow)
}
}
handler.open()
return@onUseWith true
}
onUseWith(IntType.ITEM, headlessArrow, *ArrowCraftInfo.arrowTipIds) { player, headlessArrow, arrowTip ->
val arrowCraftInfo = ArrowCraftInfo.fromTipId(arrowTip.id) ?: return@onUseWith false
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(arrowCraftInfo.arrowItemId)) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements()) return
TippedArrowCraftScript(player, arrowCraftInfo, amount).invoke()
}
private fun playerMeetsInitialRequirements(): Boolean {
if (arrowCraftInfo == ArrowCraftInfo.BROAD_ARROW && !getSlayerFlags(player).isBroadsUnlocked()) {
sendDialogue(player, "You need to unlock the ability to create broad arrows.")
return false
}
if (getDynLevel(player, Skills.FLETCHING) < arrowCraftInfo.level) {
sendLevelCheckFailDialog(player, arrowCraftInfo.level)
return false
}
if (!hasSpaceFor(player, Item(arrowCraftInfo.arrowItemId))) {
sendDialogue(player, "You do not have enough inventory space.")
return false
}
return true
}
override fun getAll(index: Int): Int {
return amountInInventory(player, arrowTip.id)
}
}
handler.open()
return@onUseWith true
}
onUseWith(IntType.ITEM, Items.OGRE_ARROW_SHAFT_2864, *Feathers.all) { player, ogreArrowShaft, feather ->
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(Items.FLIGHTED_OGRE_ARROW_2865)) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements()) return
FlightedOgreArrowCraftScript(player, feather.id, amount).invoke()
}
private fun playerMeetsInitialRequirements(): Boolean {
if (getDynLevel(player, Skills.FLETCHING) < FLIGHTED_OGRE_ARROW_LEVEL) {
sendLevelCheckFailDialog(player, FLIGHTED_OGRE_ARROW_LEVEL)
return false
}
if (!hasSpaceFor(player, Item(Items.FLIGHTED_OGRE_ARROW_2865))) {
sendDialogue(player, "You do not have enough inventory space.")
return false
}
return true
}
override fun getAll(index: Int): Int {
return amountInInventory(player, Items.OGRE_ARROW_SHAFT_2864)
}
}
handler.open()
return@onUseWith true
}
}
}

View file

@ -0,0 +1,88 @@
package content.global.skill.fletching.arrow
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
import kotlin.math.min
/**
* Defines the queueScript for creating a flighted ogre arrow
* @author 'Vexia
* @param player the player.
* @param idOfFeatherUsed the feather to attach to the shaft.
* @param sets the amount of sets to complete.
*/
class FlightedOgreArrowCraftScript(
private val player: Player,
private val idOfFeatherUsed: Int,
private val sets: Int
) {
private val flightedOgreArrow = Items.FLIGHTED_OGRE_ARROW_2865
private val ogreArrowShaft = Items.OGRE_ARROW_SHAFT_2864
private val maximumFlightedOgreArrowsCraftableInOneStage = 6
private val feathersPerArrow = 4
private val initialDelay = 1
private val subsequentDelay = 3
private fun getAmountToCraftForThisStage(shaftsInInventory: Int, feathersInInventory: Int): Int {
val limitOfCraftableArrowsDueToFeathers = feathersInInventory / feathersPerArrow
val totalCraftableArrows = min(shaftsInInventory, limitOfCraftableArrowsDueToFeathers)
return if (totalCraftableArrows > maximumFlightedOgreArrowsCraftableInOneStage) {
maximumFlightedOgreArrowsCraftableInOneStage
} else {
totalCraftableArrows
}
}
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < ArrowListeners.FLIGHTED_OGRE_ARROW_LEVEL) {
ArrowListeners.sendLevelCheckFailDialog(player, ArrowListeners.FLIGHTED_OGRE_ARROW_LEVEL)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
val featherAmount = amountInInventory(player, idOfFeatherUsed)
val shaftAmount = amountInInventory(player, ogreArrowShaft)
val amountToCraft = getAmountToCraftForThisStage(shaftAmount, featherAmount)
if (
removeItemsIfPlayerHasEnough(
player,
Item(ogreArrowShaft, amountToCraft),
Item(idOfFeatherUsed, amountToCraft * feathersPerArrow)
)
) {
when (amountToCraft) {
1 -> sendMessage(player, "You attach $feathersPerArrow feathers to a shaft.")
else -> {
sendMessage(
player,
"You attach ${amountToCraft * feathersPerArrow} feathers to $amountToCraft arrow shafts."
)
}
}
rewardXP(player, Skills.FLETCHING, amountToCraft.toDouble())
addItem(player, flightedOgreArrow, amountToCraft)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= sets - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,76 @@
package content.global.skill.fletching.arrow
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
import kotlin.math.min
/**
* Defines the queueScript for creating a headless arrow
* @author 'Vexia
* @param player the player.
* @param idOfFeatherUsed the feather to attach to the shaft.
* @param sets the amount of sets to complete.
*/
class HeadlessArrowCraftScript(
private val player: Player,
private val idOfFeatherUsed: Int,
private val sets: Int
) {
private val headlessArrow = Items.HEADLESS_ARROW_53
private val arrowShaft = Items.ARROW_SHAFT_52
private val maximumHeadlessArrowsCraftableInOneStage = 15
private val initialDelay = 1
private val subsequentDelay = 3
private fun getAmountToCraftForThisStage(shaftsInInventory: Int, feathersInInventory: Int): Int {
val smallerItemAmount = min(shaftsInInventory, feathersInInventory)
return if (smallerItemAmount > maximumHeadlessArrowsCraftableInOneStage) {
maximumHeadlessArrowsCraftableInOneStage
} else {
smallerItemAmount
}
}
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
val featherAmount = amountInInventory(player, idOfFeatherUsed)
val shaftAmount = amountInInventory(player, arrowShaft)
val amountToCraft = getAmountToCraftForThisStage(shaftAmount, featherAmount)
if (
removeItemsIfPlayerHasEnough(
player,
Item(arrowShaft, amountToCraft),
Item(idOfFeatherUsed, amountToCraft)
)
) {
when (amountToCraft) {
1 -> sendMessage(player, "You attach a feather to a shaft.")
else -> {
sendMessage(player, "You attach feathers to $amountToCraft arrow shafts.")
}
}
rewardXP(player, Skills.FLETCHING, amountToCraft.toDouble())
addItem(player, headlessArrow, amountToCraft)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= sets - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,79 @@
package content.global.skill.fletching.arrow
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
import kotlin.math.min
/**
* Represents the arrow head pulse to complete the headless arrow.
* @author 'Vexia
* @param player the player.
* @param arrowCraftInfo provides information about the arrow we're crafting.
* @param sets the amount of sets to complete.
*/
class TippedArrowCraftScript(
private val player: Player,
private val arrowCraftInfo: ArrowCraftInfo,
private val sets: Int
) {
private val headlessArrow = Items.HEADLESS_ARROW_53
private val maximumArrowsCraftableInOneStage = 15
private val initialDelay = 1
private val subsequentDelay = 3
private fun getAmountToCraftForThisStage(headlessArrowsInInventory: Int, tipsInInventory: Int): Int {
val smallerItemAmount = min(headlessArrowsInInventory, tipsInInventory)
return if (smallerItemAmount > maximumArrowsCraftableInOneStage) {
maximumArrowsCraftableInOneStage
} else {
smallerItemAmount
}
}
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < arrowCraftInfo.level) {
ArrowListeners.sendLevelCheckFailDialog(player, arrowCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
val tipsInInventory = amountInInventory(player, arrowCraftInfo.tipItemId)
val headlessArrowsInInventory = amountInInventory(player, headlessArrow)
val amountToCraft = getAmountToCraftForThisStage(headlessArrowsInInventory, tipsInInventory)
if (
removeItemsIfPlayerHasEnough(
player,
Item(headlessArrow, amountToCraft),
Item(arrowCraftInfo.tipItemId, amountToCraft)
)
) {
when (amountToCraft) {
1 -> sendMessage(player, "You attach an arrow head to an arrow shaft.")
else -> {
sendMessage(player, "You attach arrow heads to $amountToCraft arrow shafts.")
}
}
rewardXP(player, Skills.FLETCHING, arrowCraftInfo.experience * amountToCraft)
addItem(player, arrowCraftInfo.arrowItemId, amountToCraft)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= sets - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,39 @@
package content.global.skill.fletching.bolts
import org.rs09.consts.Items
/**
* Provides information pertaining to crafting different bolts
* @property unfinishedBoltItemId the unfinished bolt (unf) Item id used to craft the dart.
* @property finishedItemId the resulting finished bolt Item id.
* @property level the level required to craft.
* @property experience the experience gained by crafting.
*/
enum class BoltCraftInfo(
val unfinishedBoltItemId: Int,
val finishedItemId: Int,
val level: Int,
val experience: Double
) {
BRONZE_BOLT(Items.BRONZE_BOLTS_UNF_9375, Items.BRONZE_BOLTS_877, 9, 0.5),
BLURITE_BOLT(Items.BLURITE_BOLTS_UNF_9376, Items.BLURITE_BOLTS_9139, 24, 1.0),
IRON_BOLT(Items.IRON_BOLTS_UNF_9377, Items.IRON_BOLTS_9140, 39, 1.5),
SILVER_BOLT(Items.SILVER_BOLTS_UNF_9382, Items.SILVER_BOLTS_9145, 43, 2.5),
STEEL_BOLT(Items.STEEL_BOLTS_UNF_9378, Items.STEEL_BOLTS_9141, 46, 3.5),
MITHRIL_BOLT(Items.MITHRIL_BOLTS_UNF_9379, Items.MITHRIL_BOLTS_9142, 54, 5.0),
ADAMANTITE_BOLT(Items.ADAMANT_BOLTSUNF_9380, Items.ADAMANT_BOLTS_9143, 61, 7.0),
RUNITE_BOLT(Items.RUNITE_BOLTS_UNF_9381, Items.RUNE_BOLTS_9144, 69, 10.0),
BROAD_BOLT(Items.UNFINISHED_BROAD_BOLTS_13279, Items.BROAD_TIPPED_BOLTS_13280, 55, 3.0);
companion object {
private val boltCraftInfoByUnfinishedBoltIds = values().associateBy { it.unfinishedBoltItemId }
val unfinishedBoltIds: IntArray = BoltCraftInfo.values()
.map { unfinishedBoltToBoltMapping: BoltCraftInfo -> unfinishedBoltToBoltMapping.unfinishedBoltItemId }
.toIntArray()
fun fromUnfinishedBoltId(unfinishedBoltId: Int): BoltCraftInfo? {
return boltCraftInfoByUnfinishedBoltIds[unfinishedBoltId]
}
}
}

View file

@ -0,0 +1,79 @@
package content.global.skill.fletching.bolts
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import kotlin.math.min
/**
* Represents the bolt pulse class to make bolts.
* @author ceik
* @param player the player.
* @param boltCraftInfo contains information about what bolt we're crafting
* @param feather the feather we're using to craft
* @param sets the amount of sets to craft
*/
class BoltCraftScript(
private val player: Player,
private val boltCraftInfo: BoltCraftInfo,
private val feather: Item,
private val sets: Int
) {
private val maximumBoltsCraftableInOneStage = 10
private val initialDelay = 1
private val subsequentDelay = 3
private fun getAmountToCraftForThisSet(feathersInInventory: Int, unfinishedBoltsInInventory: Int): Int {
val smallerItemAmount = min(feathersInInventory, unfinishedBoltsInInventory)
return if (smallerItemAmount > maximumBoltsCraftableInOneStage) {
maximumBoltsCraftableInOneStage
} else {
smallerItemAmount
}
}
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < boltCraftInfo.level) {
BoltListeners.sendLevelCheckFailDialog(player, boltCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
val featherAmount = amountInInventory(player, feather.id)
val unfinishedBoltAmount = amountInInventory(player, boltCraftInfo.unfinishedBoltItemId)
val amountToCraft = getAmountToCraftForThisSet(featherAmount, unfinishedBoltAmount)
if (
removeItemsIfPlayerHasEnough(
player,
Item(feather.id, amountToCraft),
Item(boltCraftInfo.unfinishedBoltItemId, amountToCraft)
)
) {
when (amountToCraft) {
1 -> sendMessage(player, "You attach a feather to a bolt.")
else -> {
sendMessage(player, "You fletch $amountToCraft bolts")
}
}
rewardXP(player, Skills.FLETCHING, boltCraftInfo.experience * amountToCraft)
addItem(player, boltCraftInfo.finishedItemId, amountToCraft)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= sets - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,65 @@
package content.global.skill.fletching.bolts
import content.global.skill.fletching.Feathers
import core.api.*
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import kotlin.math.min
@Suppress("unused") // Reflectively loaded
class BoltListeners : InteractionListener {
override fun defineListeners() {
onUseWith(IntType.ITEM, Feathers.all, *BoltCraftInfo.unfinishedBoltIds) { player, feather, unfinishedBolt ->
val boltCraftInfo = BoltCraftInfo.fromUnfinishedBoltId(unfinishedBolt.id) ?: return@onUseWith false
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(
player,
SkillDialogue.MAKE_SET_ONE_OPTION,
Item(boltCraftInfo.finishedItemId)
) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements()) return
BoltCraftScript(player, boltCraftInfo, feather.asItem(), amount).invoke()
}
private fun playerMeetsInitialRequirements(): Boolean {
if (boltCraftInfo == BoltCraftInfo.BROAD_BOLT && !getSlayerFlags(player).isBroadsUnlocked()) {
sendDialogue(player, "You need to unlock the ability to create broad bolts.")
return false
}
if (getDynLevel(player, Skills.FLETCHING) < boltCraftInfo.level) {
sendLevelCheckFailDialog(player, boltCraftInfo.level)
return false
}
if (!hasSpaceFor(player, Item(boltCraftInfo.finishedItemId))) {
sendDialogue(player, "You do not have enough inventory space.")
return false
}
return true
}
override fun getAll(index: Int): Int {
return min(
amountInInventory(player, feather.id),
amountInInventory(player, unfinishedBolt.id)
)
}
}
handler.open()
return@onUseWith true
}
}
companion object {
fun sendLevelCheckFailDialog(player: Player, level: Int) {
sendDialogue(
player,
"You need a fletching level of $level in order to do this."
)
}
}
}

View file

@ -0,0 +1,80 @@
package content.global.skill.fletching.crossbow
import core.api.getDynLevel
import core.api.hasSpaceFor
import core.api.sendDialogue
import core.api.sendMessage
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.net.packet.PacketRepository
import core.net.packet.context.ChildPositionContext
import core.net.packet.out.RepositionChild
import org.rs09.consts.Components
@Suppress("unused") // Reflectively loaded
class LimbingListener : InteractionListener {
override fun defineListeners() {
onUseWith(
IntType.ITEM,
UnfinishedCrossbowCraftInfo.limbIds,
*UnfinishedCrossbowCraftInfo.stockIds
) { player, limb, stock ->
val unfinishedCrossbowCraftInfo = UnfinishedCrossbowCraftInfo.forStockId(stock.id) ?: return@onUseWith false
if (unfinishedCrossbowCraftInfo.limbItemId != limb.id) {
sendMessage(player, "That's not the right limb to attach to that stock.")
return@onUseWith true
}
val handler: SkillDialogueHandler = object : SkillDialogueHandler(
player,
SkillDialogue.ONE_OPTION,
Item(unfinishedCrossbowCraftInfo.unstrungCrossbowItemId)
) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements()) return
LimbingScript(player, unfinishedCrossbowCraftInfo, amount).invoke()
}
private fun playerMeetsInitialRequirements(): Boolean {
if (getDynLevel(player, Skills.FLETCHING) < unfinishedCrossbowCraftInfo.level) {
sendLevelCheckFailDialog(player, unfinishedCrossbowCraftInfo.level)
return false
}
if (!hasSpaceFor(player, Item(unfinishedCrossbowCraftInfo.unstrungCrossbowItemId))) {
sendDialogue(player, "You do not have enough inventory space.")
return false
}
return true
}
override fun getAll(index: Int): Int {
return player.inventory.getAmount(stock.asItem())
}
}
handler.open()
fixTextOverlappingTheCrossbowIcon(player)
return@onUseWith true
}
}
private fun fixTextOverlappingTheCrossbowIcon(player: Player) {
PacketRepository.send(
RepositionChild::class.java,
ChildPositionContext(player, Components.SKILL_MULTI1_309, 2, 210, 10)
)
}
companion object {
fun sendLevelCheckFailDialog(player: Player, level: Int) {
sendDialogue(
player,
"You need a fletching level of $level to attach these limbs."
)
}
}
}

View file

@ -0,0 +1,56 @@
package content.global.skill.fletching.crossbow
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
/**
* The queue script for attaching limbs.
* @author Ceikry
* @param player The player
* @param unfinishedCrossbowCraftInfo info about the unfinished (unstrung) crossbow we're crafting
* @param amount to create
*/
class LimbingScript(
private val player: Player,
private val unfinishedCrossbowCraftInfo: UnfinishedCrossbowCraftInfo,
private val amount: Int
) {
private val initialDelay = 1
private val subsequentDelay = 6
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < unfinishedCrossbowCraftInfo.level) {
LimbingListener.sendLevelCheckFailDialog(player, unfinishedCrossbowCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
if (
removeItemsIfPlayerHasEnough(
player,
Item(unfinishedCrossbowCraftInfo.stockItemId),
Item(unfinishedCrossbowCraftInfo.limbItemId)
)
) {
addItem(player, unfinishedCrossbowCraftInfo.unstrungCrossbowItemId, 1)
rewardXP(player, Skills.FLETCHING, unfinishedCrossbowCraftInfo.experience)
sendMessage(player, "You attach the metal limbs to the stock.")
animate(player, unfinishedCrossbowCraftInfo.animation)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= amount - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,55 @@
package content.global.skill.fletching.crossbow
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
/**
* Provides information pertaining to crafting different unfinished (unstrung) crossbows
* @author 'Vexia
* @param stockItemId item id of the stock.
* @param limbItemId item id of the limb.
* @param unstrungCrossbowItemId item id of the product.
* @param level the level.
* @param experience the experience.
* @param animation the animation.
*/
enum class UnfinishedCrossbowCraftInfo
(
val stockItemId: Int,
val limbItemId: Int,
val unstrungCrossbowItemId: Int,
val level: Int,
val experience: Double,
val animation: Animation
) {
WOODEN_STOCK(Items.WOODEN_STOCK_9440, Items.BRONZE_LIMBS_9420, Items.BRONZE_CBOW_U_9454, 9, 12.0, Animation(4436)),
OAK_STOCK(Items.OAK_STOCK_9442, Items.BLURITE_LIMBS_9422, Items.BLURITE_CROSSBOW_9176, 24, 32.0, Animation(4437)),
WILLOW_STOCK(Items.WILLOW_STOCK_9444, Items.IRON_LIMBS_9423, Items.IRON_CBOW_U_9457, 39, 44.0, Animation(4438)),
TEAK_STOCK(Items.TEAK_STOCK_9446, Items.STEEL_LIMBS_9425, Items.STEEL_CBOW_U_9459, 46, 54.0, Animation(4439)),
MAPLE_STOCK(Items.MAPLE_STOCK_9448, Items.MITHRIL_LIMBS_9427, Items.MITHRIL_CBOW_U_9461, 54, 64.0, Animation(4440)),
MAHOGANY_STOCK(
Items.MAHOGANY_STOCK_9450,
Items.ADAMANTITE_LIMBS_9429,
Items.ADAMANT_CBOW_U_9463,
61,
82.0,
Animation(4441)
),
YEW_STOCK(Items.YEW_STOCK_9452, Items.RUNITE_LIMBS_9431, Items.RUNITE_CBOW_U_9465, 69, 100.0, Animation(4442));
companion object {
private val unfinishedCrossbowCraftInfoByStockId = values().associateBy { it.stockItemId }
val limbIds: IntArray =
values().map { unfinishedCrossbowCraftInfo: UnfinishedCrossbowCraftInfo -> unfinishedCrossbowCraftInfo.limbItemId }
.toIntArray()
val stockIds: IntArray =
values().map { unfinishedCrossbowCraftInfo: UnfinishedCrossbowCraftInfo -> unfinishedCrossbowCraftInfo.stockItemId }
.toIntArray()
fun forStockId(stockId: Int): UnfinishedCrossbowCraftInfo? {
return unfinishedCrossbowCraftInfoByStockId[stockId]
}
}
}

View file

@ -0,0 +1,36 @@
package content.global.skill.fletching.darts
import org.rs09.consts.Items
/**
* Provides information pertaining to crafting different darts
* @author 'Vexia
* @property tipItemId the tip Item id used to craft the dart.
* @property dartItemId the resulting dart Item id.
* @property level the level required to craft.
* @property experience the experience gained by crafting.
*/
enum class DartCraftInfo(
val tipItemId: Int,
val dartItemId: Int,
val level: Int,
val experience: Double) {
BRONZE_DART(Items.BRONZE_DART_TIP_819, Items.BRONZE_DART_806, 1, 1.8),
IRON_DART(Items.IRON_DART_TIP_820, Items.IRON_DART_807, 22, 3.8),
STEEL_DART(Items.STEEL_DART_TIP_821, Items.STEEL_DART_808, 37, 7.5),
MITHRIL_DART(Items.MITHRIL_DART_TIP_822, Items.MITHRIL_DART_809, 52, 11.2),
ADAMANT_DART(Items.ADAMANT_DART_TIP_823, Items.ADAMANT_DART_810, 67, 15.0),
RUNE_DART(Items.RUNE_DART_TIP_824, Items.RUNE_DART_811, 81, 18.8),
DRAGON_DART(Items.DRAGON_DART_TIP_11232, Items.DRAGON_DART_11230, 95, 25.0);
companion object {
private val dartCraftInfoByTipIds = values().associateBy { it.tipItemId }
val tipIDs: IntArray = values().map { dartCraftInfo: DartCraftInfo -> dartCraftInfo.tipItemId }.toIntArray()
fun fromTipID(dartTipId: Int): DartCraftInfo? {
return dartCraftInfoByTipIds[dartTipId]
}
}
}

View file

@ -0,0 +1,78 @@
package content.global.skill.fletching.darts
import content.global.skill.fletching.Feathers
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import kotlin.math.min
/**
* Represents the queueScript to craft a dart.
* @author ceikry
* @param player the player.
* @param dartCraftInfo contains info about the dart we're crafting.
* @param sets count of sets to make
*/
class DartCraftScript(
private val player: Player,
private val dartCraftInfo: DartCraftInfo,
private var sets: Int
) {
private val initialDelay = 1
private val subsequentDelay = 3
private val maximumDartsCraftableInOneStage = 10
private fun getAmountToCraftForThisStage(feathersInInventory: Int, dartTipsInInventory: Int): Int {
val smallerItemAmount = min(feathersInInventory, dartTipsInInventory)
return if (smallerItemAmount > maximumDartsCraftableInOneStage) {
maximumDartsCraftableInOneStage
} else {
smallerItemAmount
}
}
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < dartCraftInfo.level) {
DartListeners.sendLevelCheckFailDialog(player, dartCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
val dartTipsInInventory = amountInInventory(player, dartCraftInfo.tipItemId)
val feathersInInventory = amountInInventory(player, Feathers.STANDARD)
val amountToCraft = getAmountToCraftForThisStage(feathersInInventory, dartTipsInInventory)
if (
removeItemsIfPlayerHasEnough(
player,
Item(Feathers.STANDARD, amountToCraft),
Item(dartCraftInfo.tipItemId, amountToCraft)
)
) {
when (amountToCraft) {
1 -> sendMessage(player, "You attach a feather to a dart.")
else -> {
sendMessage(player, "You attach feathers to $amountToCraft darts.")
}
}
rewardXP(player, Skills.FLETCHING, dartCraftInfo.experience * amountToCraft)
addItem(player, dartCraftInfo.dartItemId, amountToCraft)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= sets - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,59 @@
package content.global.skill.fletching.darts
import content.data.Quests
import content.global.skill.fletching.Feathers
import core.api.*
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import kotlin.math.min
@Suppress("unused") // Reflectively loaded
class DartListeners : InteractionListener {
override fun defineListeners() {
onUseWith(IntType.ITEM, Feathers.STANDARD, *DartCraftInfo.tipIDs) { player, feather, dartTip ->
val dartCraftInfo = DartCraftInfo.fromTipID(dartTip.id) ?: return@onUseWith false
val handler: SkillDialogueHandler =
object :
SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(dartCraftInfo.dartItemId)) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements()) return
DartCraftScript(player, dartCraftInfo, amount).invoke()
}
private fun playerMeetsInitialRequirements(): Boolean {
if (getDynLevel(player, Skills.FLETCHING) < dartCraftInfo.level) {
sendLevelCheckFailDialog(player, dartCraftInfo.level)
return false
}
if (!isQuestComplete(player, Quests.THE_TOURIST_TRAP)) {
sendDialogue(player, "You need to have completed Tourist Trap to fletch darts.")
return false
}
if (!hasSpaceFor(player, Item(dartCraftInfo.dartItemId))) {
sendDialogue(player, "You do not have enough inventory space.")
return false
}
return true
}
override fun getAll(index: Int): Int {
return min(
amountInInventory(player, feather.id),
amountInInventory(player, dartTip.id)
)
}
}
handler.open()
return@onUseWith true
}
}
companion object {
fun sendLevelCheckFailDialog(player: Player, level: Int) {
sendDialogue(player, "You need a fletching level of $level to do this.")
}
}
}

View file

@ -0,0 +1,77 @@
package content.global.skill.fletching.gem
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import kotlin.math.min
/**
* Represents the attaching of a gem tip to a premade bolt.
* @author Ceikry
* @param player the player.
* @param gemBoltCraftInfo crafting info for adding the gem to the bolt
* @param sets the number of sets to craft.
*/
class AttachGemTipToBoltScript(
private val player: Player,
private val gemBoltCraftInfo: GemBoltsCraftInfo,
private val sets: Int
) {
private val initialDelay = 1
private val subsequentDelay = 3
private val maximumGemBoltsCraftableInOneStage = 10
private fun getAmountToCraftForThisPulse(untippedBoltsInInventory: Int, tipsInInventory: Int): Int {
val smallerItemAmount = min(untippedBoltsInInventory, tipsInInventory)
return if (smallerItemAmount > maximumGemBoltsCraftableInOneStage) {
maximumGemBoltsCraftableInOneStage
} else {
smallerItemAmount
}
}
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < gemBoltCraftInfo.level) {
GemBoltListeners.sendGemTipAttachLevelCheckFailDialog(player, gemBoltCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
val untippedBoltsInInventory = amountInInventory(player, gemBoltCraftInfo.untippedBoltItemId)
val tipsInInventory = amountInInventory(player, gemBoltCraftInfo.tipItemId)
val amountToCraft = getAmountToCraftForThisPulse(untippedBoltsInInventory, tipsInInventory)
if (
removeItemsIfPlayerHasEnough(
player,
Item(gemBoltCraftInfo.untippedBoltItemId, amountToCraft),
Item(gemBoltCraftInfo.tipItemId, amountToCraft)
)
) {
when (amountToCraft) {
1 -> sendMessage(player, "You attach the tip to the bolt.")
else -> {
sendMessage(player, "You fletch $amountToCraft bolts.")
}
}
rewardXP(player, Skills.FLETCHING, gemBoltCraftInfo.experience * amountToCraft)
addItem(player, gemBoltCraftInfo.tippedBoltItemId, amountToCraft)
} else {
return@queueScript stopExecuting(player)
}
if (stage >= sets - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
}

View file

@ -0,0 +1,79 @@
package content.global.skill.fletching.gem
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
/**
* Represents the queue script for cutting gems into bolt tips
* @author Ceikry
* @param player the player.
* @param gemBoltCraftInfo represents the crafting info for the gem we're cutting.
* @param amount the amount to make.
*/
class CutGemsIntoBoltTipsScript(
private val player: Player,
private val gemBoltCraftInfo: GemBoltsCraftInfo,
private val amount: Int
) {
private val initialDelay = 1
private val craftDelay = 5
private val animationDelay = 6
private var craftingFinished = false
private fun invokeAnimationLoop() {
queueScript(player, 0) {
if (craftingFinished) {
return@queueScript stopExecuting(player)
}
animate(player, gemBoltCraftInfo.gemCutAnimationId)
return@queueScript delayScript(player, animationDelay)
}
}
private fun invokeCraftLoop() {
queueScript(player, 0) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < gemBoltCraftInfo.level) {
craftingFinished = true
GemBoltListeners.sendGemTipCutLevelCheckFailDialog(player, gemBoltCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
val amountOfTipsToCraft = when (gemBoltCraftInfo) {
GemBoltsCraftInfo.PEARLS -> 24
GemBoltsCraftInfo.PEARL -> 6
GemBoltsCraftInfo.ONYX -> 24
else -> 12
}
if (removeItem(player, Item(gemBoltCraftInfo.gemItemId))) {
addItem(player, gemBoltCraftInfo.tipItemId, amountOfTipsToCraft)
rewardXP(player, Skills.FLETCHING, gemBoltCraftInfo.experience)
} else {
craftingFinished = true
return@queueScript stopExecuting(player)
}
if (stage >= amount - 1) {
craftingFinished = true
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, craftDelay, true)
}
}
fun invoke() {
queueScript(player, initialDelay) {
invokeAnimationLoop()
invokeCraftLoop()
return@queueScript stopExecuting(player)
}
}
}

View file

@ -0,0 +1,90 @@
package content.global.skill.fletching.gem
import core.api.amountInInventory
import core.api.getDynLevel
import core.api.hasSpaceFor
import core.api.sendDialogue
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
import kotlin.math.min
@Suppress("unused") // Reflectively loaded
class GemBoltListeners : InteractionListener {
override fun defineListeners() {
onUseWith(IntType.ITEM, Items.CHISEL_1755, *GemBoltsCraftInfo.gemIds) { player, _, gem ->
val gemBoltCraftInfo = GemBoltsCraftInfo.forGemId(gem.id) ?: return@onUseWith true
object : SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, Item(gemBoltCraftInfo.gemItemId)) {
override fun create(amount: Int, index: Int) {
if (getDynLevel(player, Skills.FLETCHING) < gemBoltCraftInfo.level) {
sendGemTipCutLevelCheckFailDialog(player, gemBoltCraftInfo.level)
return
}
CutGemsIntoBoltTipsScript(player, gemBoltCraftInfo, amount).invoke()
}
override fun getAll(index: Int): Int {
return amountInInventory(player, gemBoltCraftInfo.gemItemId)
}
}.open()
return@onUseWith true
}
onUseWith(
IntType.ITEM,
GemBoltsCraftInfo.untippedBoltIds,
*GemBoltsCraftInfo.boltTipIds
) { player, untippedBolt, boltTip ->
val bolt = GemBoltsCraftInfo.forTipId(boltTip.id) ?: return@onUseWith false
if (untippedBolt.id != bolt.untippedBoltItemId) return@onUseWith false
val handler: SkillDialogueHandler =
object : SkillDialogueHandler(player, SkillDialogue.MAKE_SET_ONE_OPTION, Item(bolt.tippedBoltItemId)) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements()) return
AttachGemTipToBoltScript(player, bolt, amount).invoke()
}
private fun playerMeetsInitialRequirements(): Boolean {
if (getDynLevel(player, Skills.FLETCHING) < bolt.level) {
sendGemTipAttachLevelCheckFailDialog(player, bolt.level)
return false
}
if (!hasSpaceFor(player, Item(bolt.tippedBoltItemId))) {
sendDialogue(player, "You do not have enough inventory space.")
return false
}
return true
}
override fun getAll(index: Int): Int {
return min(amountInInventory(player, untippedBolt.id), amountInInventory(player, boltTip.id))
}
}
handler.open()
return@onUseWith true
}
}
companion object {
fun sendGemTipCutLevelCheckFailDialog(player: Player, level: Int) {
sendDialogue(
player,
"You need a Fletching level of $level or above to do that."
)
}
fun sendGemTipAttachLevelCheckFailDialog(player: Player, level: Int) {
sendDialogue(
player,
"You need a Fletching level of $level or above to do that."
)
}
}
}

View file

@ -0,0 +1,106 @@
package content.global.skill.fletching.gem
import org.rs09.consts.Items
/**
* Provides information pertaining to crafting different gem tipped bolts
* @property untippedBoltItemId the base untipped bolt item id
* @property gemItemId the gem item id used to craft the bolt tips
* @property gemCutAnimationId the animation to play when the player cuts the gem
* @property tipItemId the item id of the resulting bolt tips
* @property tippedBoltItemId the item id of the finished gem-tipped bolt
* @property level the required level to craft the gem tipped bolt or tips themselves
* @property experience gained creating one set of gem tips, or per bolt tipped
*/
enum class GemBoltsCraftInfo(
var untippedBoltItemId: Int,
var gemItemId: Int,
var gemCutAnimationId: Int,
var tipItemId: Int,
var tippedBoltItemId: Int,
var level: Int,
var experience: Double
) {
OPAL(Items.BRONZE_BOLTS_877, Items.OPAL_1609, 890, Items.OPAL_BOLT_TIPS_45, Items.OPAL_BOLTS_879, 11, 1.6),
JADE(Items.BLURITE_BOLTS_9139, Items.JADE_1611, 891, Items.JADE_BOLT_TIPS_9187, Items.JADE_BOLTS_9335, 26, 2.4),
PEARL(Items.IRON_BOLTS_9140, Items.OYSTER_PEARL_411, 4470, Items.PEARL_BOLT_TIPS_46, Items.PEARL_BOLTS_880, 41, 3.2),
PEARLS(
Items.IRON_BOLTS_9140,
Items.OYSTER_PEARLS_413,
4470,
Items.PEARL_BOLT_TIPS_46,
Items.PEARL_BOLTS_880,
41,
3.2
),
RED_TOPAZ(
Items.STEEL_BOLTS_9141,
Items.RED_TOPAZ_1613,
892,
Items.TOPAZ_BOLT_TIPS_9188,
Items.TOPAZ_BOLTS_9336,
48,
3.9
),
SAPPHIRE(
Items.MITHRIL_BOLTS_9142,
Items.SAPPHIRE_1607,
888,
Items.SAPPHIRE_BOLT_TIPS_9189,
Items.SAPPHIRE_BOLTS_9337,
56,
4.7
),
EMERALD(
Items.MITHRIL_BOLTS_9142,
Items.EMERALD_1605,
889,
Items.EMERALD_BOLT_TIPS_9190,
Items.EMERALD_BOLTS_9338,
58,
5.5
),
RUBY(Items.ADAMANT_BOLTS_9143, Items.RUBY_1603, 887, Items.RUBY_BOLT_TIPS_9191, Items.RUBY_BOLTS_9339, 63, 6.3),
DIAMOND(
Items.ADAMANT_BOLTS_9143,
Items.DIAMOND_1601,
886,
Items.DIAMOND_BOLT_TIPS_9192,
Items.DIAMOND_BOLTS_9340,
65,
7.0
),
DRAGONSTONE(
Items.RUNE_BOLTS_9144,
Items.DRAGONSTONE_1615,
885,
Items.DRAGON_BOLT_TIPS_9193,
Items.DRAGON_BOLTS_9341,
71,
8.2
),
ONYX(Items.RUNE_BOLTS_9144, Items.ONYX_6573, 2717, Items.ONYX_BOLT_TIPS_9194, Items.ONYX_BOLTS_9342, 73, 9.4);
companion object {
private val gemBoltCraftInfoByGemId = values().associateBy { it.gemItemId }
private val gemBoltCraftInfoByBoltTipId = values().associateBy { it.tipItemId }
val untippedBoltIds: IntArray =
values().map { gemBoltsCraftInfo: GemBoltsCraftInfo -> gemBoltsCraftInfo.untippedBoltItemId }.distinct()
.toIntArray()
val gemIds: IntArray =
values().map { gemBoltsCraftInfo: GemBoltsCraftInfo -> gemBoltsCraftInfo.gemItemId }.toIntArray()
val boltTipIds: IntArray =
values().map { gemBoltsCraftInfo: GemBoltsCraftInfo -> gemBoltsCraftInfo.tipItemId }.toIntArray()
fun forGemId(gemId: Int): GemBoltsCraftInfo? {
return gemBoltCraftInfoByGemId[gemId]
}
fun forTipId(tipId: Int): GemBoltsCraftInfo? {
return gemBoltCraftInfoByBoltTipId[tipId]
}
}
}

View file

@ -0,0 +1,67 @@
package content.global.skill.fletching.grapple
import core.api.*
import core.game.interaction.Clocks
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
@Suppress("unused") // Reflectively loaded
class GrappleListeners : InteractionListener {
private val mithrilBolt = Items.MITHRIL_BOLTS_9142
private val mithrilGrappleTip = Items.MITH_GRAPPLE_TIP_9416
private val rope = Items.ROPE_954
private val mithrilGrapple = Items.MITH_GRAPPLE_9418
private val mithrilGrappleWithRope = Items.MITH_GRAPPLE_9419
override fun defineListeners() {
onUseWith(IntType.ITEM, mithrilBolt, mithrilGrappleTip) { player, bolt, tip ->
if (getDynLevel(player, Skills.FLETCHING) < 59) {
sendMessage(player, "You need a fletching level of 59 to make this.")
return@onUseWith true
}
queueScript(player, 0) { _ ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (removeItemsIfPlayerHasEnough(
player,
Item(mithrilBolt, 1),
tip.asItem()
)
) {
addItem(player, mithrilGrapple, 1)
}
delayClock(player, Clocks.SKILLING, 3)
return@queueScript stopExecuting(player)
}
return@onUseWith true
}
onUseWith(IntType.ITEM, rope, mithrilGrapple) { player, rope, grapple ->
if (getDynLevel(player, Skills.FLETCHING) < 59) {
sendMessage(player, "You need a fletching level of 59 to make this.")
return@onUseWith true
}
queueScript(player, 0) { _ ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (removeItemsIfPlayerHasEnough(
player,
rope.asItem(),
grapple.asItem()
)
) {
addItem(player, mithrilGrappleWithRope, 1)
}
delayClock(player, Clocks.SKILLING, 3)
return@queueScript stopExecuting(player)
}
return@onUseWith true
}
}
}

View file

@ -1,123 +0,0 @@
/*
package core.game.node.entity.skill.fletching.items.arrow;
import org.crandor.game.node.item.Item;
*/
/**
* Represents the enum storing the arrow head information.
* @author 'Vexia
* @note brutal arrows after quest.
*//*
public enum ArrowHead {
BRONZE_ARROW(new Item(39), new Item(882), 1, 2.6),
IRON_ARROW(new Item(40), new Item(884), 15, 3.8),
STEEL_ARROW(new Item(41), new Item(886), 30, 6.3),
MITHRIL_ARROW(new Item(42), new Item(888), 45, 8.8),
ADAMANT_ARROW(new Item(43), new Item(890), 60, 10),
RUNE_ARROW(new Item(44), new Item(892), 75, 13.8),
DRAGON_ARROW(new Item(11237), new Item(11212), 90, 16.3),
BROAD_ARROW(new Item(13278), new Item(4160), 52, 10);
*/
/**
* Constructs a new {@code ArrowHead.java} {@code Object}.
* @param item the item.
* @param product the product.
* @param level the level.
* @param experience the experience.
*//*
ArrowHead(Item item, Item product, int level, double experience) {
this.item = item;
this.product = product;
this.level = level;
this.experience = experience;
}
*/
/**
* Represents the arrow tip.
*//*
private final Item item;
*/
/**
* Represents the product item.
*//*
private final Item product;
*/
/**
* Represents the level required.
*//*
private final int level;
*/
/**
* Represents the experience gained.
*//*
private final double experience;
*/
/**
* Gets the item.
* @return The item.
*//*
public Item getTips() {
return item;
}
*/
/**
* Gets the product.
* @return The product.
*//*
public Item getProduct() {
return product;
}
*/
/**
* Gets the level.
* @return The level.
*//*
public int getLevel() {
return level;
}
*/
/**
* Gets the experience.
* @return The experience.
*//*
public double getExperience() {
return experience;
}
*/
/**
* Gets the arrow head.
* @param item the item.
* @return the arrow head.
*//*
public static ArrowHead forItem(final Item item) {
for (ArrowHead arrow : ArrowHead.values()) {
if (arrow.getTips().getId() == item.getId()) {
return arrow;
}
}
return null;
}
}
*/

View file

@ -1,110 +0,0 @@
package content.global.skill.fletching.items.arrow;
import content.global.skill.slayer.SlayerManager;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import content.global.skill.fletching.Fletching;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import static core.api.ContentAPIKt.*;
/**
* Represents the arrow head pulse to complete the headless arrow.
* @author 'Vexia
*/
public class ArrowHeadPulse extends SkillPulse<Item> {
/**
* Represents the headless arrow item.
*/
private static final Item HEADLESS_ARROW = new Item(53);
/**
* Represents the arrow head.
*/
private final Fletching.ArrowHeads arrow;
/**
* Represents the sets to do.
*/
private int sets;
/**
* Constructs a new {@code ArrowHeadPulse.java} {@code Object}.
* @param player the player.
* @param node the node.
* @param arrow the arrow.
* @param sets the sets.
*/
public ArrowHeadPulse(final Player player, final Item node, final Fletching.ArrowHeads arrow, final int sets) {
super(player, node);
this.arrow = arrow;
this.sets = sets;
}
@Override
public boolean checkRequirements() {
if (arrow.unfinished == 4160) {
if (!SlayerManager.getInstance(player).flags.isBroadsUnlocked()) {
player.getDialogueInterpreter().sendDialogue("You need to unlock the ability to create broad arrows.");
return false;
}
}
if (player.getSkills().getLevel(Skills.FLETCHING) < arrow.level) {
player.getDialogueInterpreter().sendDialogue("You need a fletching level of " + arrow.level + " to do this.");
return false;
}
if (!hasSpaceFor(player, arrow.getFinished())) {
sendDialogue(player, "You do not have enough inventory space.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
if (getDelay() == 1) {
super.setDelay(3);
}
Item tip = arrow.getUnfinished();
int tipAmount = player.getInventory().getAmount(arrow.unfinished);
int shaftAmount = player.getInventory().getAmount(HEADLESS_ARROW);
if (tipAmount >= 15 && shaftAmount >= 15) {
HEADLESS_ARROW.setAmount(15);
tip.setAmount(15);
player.getPacketDispatch().sendMessage("You attach arrow heads to 15 arrow shafts.");
} else {
int amount = tipAmount > shaftAmount ? shaftAmount : tipAmount;
HEADLESS_ARROW.setAmount(amount);
tip.setAmount(amount);
player.getPacketDispatch().sendMessage(amount == 1 ? "You attach an arrow head to an arrow shaft." : "You attach arrow heads to " + amount + " arrow shafts.");
}
if (player.getInventory().remove(HEADLESS_ARROW, tip)) {
player.getSkills().addExperience(Skills.FLETCHING, arrow.experience * tip.getAmount(), true);
Item product = arrow.getFinished();
product.setAmount(tip.getAmount());
player.getInventory().add(product);
}
HEADLESS_ARROW.setAmount(1);
tip.setAmount(1);
if (!player.getInventory().containsItem(HEADLESS_ARROW)) {
return true;
}
if (!player.getInventory().containsItem(tip)) {
return true;
}
sets--;
return sets == 0;
}
@Override
public void message(int type) {
}
}

View file

@ -1,145 +0,0 @@
package content.global.skill.fletching.items.arrow;
import org.rs09.consts.Items;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import static core.api.ContentAPIKt.*;
/**
* Represents the arrow pulse for creating unfinished arrows.
* @author 'Vexia
*/
public final class HeadlessArrowPulse extends SkillPulse<Item> {
/**
* Represents the headless arrow item.
*/
private final Item HEADLESS_ARROW = new Item(Items.HEADLESS_ARROW_53);
/**
* Represents the arrow shaft item.
*/
private final Item ARROW_SHAFT = new Item(Items.ARROW_SHAFT_52);
/**
* Represents the feather items.
*/
private static final Item[] FEATHER = new Item[] {
new Item(Items.FEATHER_314),
new Item(Items.STRIPY_FEATHER_10087),
new Item(Items.RED_FEATHER_10088),
new Item(Items.BLUE_FEATHER_10089),
new Item(Items.YELLOW_FEATHER_10090),
new Item(Items.ORANGE_FEATHER_10091)
};
/**
* The feather being used.
*/
private Item feather;
/**
* Represents the amount to make.
*/
private int sets;
/**
* Represents if we should use sets, meaning we have 15 & 15 arrow shafts and feathers.
*/
private boolean useSets = false;
/**
* Constructs a new {@code ArrowPulse.java} {@code Object}.
* @param player the player.
* @param node the node.
*/
public HeadlessArrowPulse(Player player, Item node, Item feather, int sets) {
super(player, node);
this.sets = sets;
this.feather = feather;
}
@Override
public boolean checkRequirements() {
if (!player.getInventory().containsItem(ARROW_SHAFT)) {
player.getDialogueInterpreter().sendDialogue("You don't have any arrow shafts.");
return false;
}
if (feather == null || !player.getInventory().containsItem(feather)) {
player.getDialogueInterpreter().sendDialogue("You don't have any feathers.");
return false;
}
if (player.getInventory().contains(ARROW_SHAFT.getId(), 15) && player.getInventory().contains(feather.getId(), 15)) {
useSets = true;
} else {
useSets = false;
}
if (!hasSpaceFor(player, HEADLESS_ARROW.asItem())) {
sendDialogue(player, "You do not have enough inventory space.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
int featherAmount = player.getInventory().getAmount(feather);
int shaftAmount = player.getInventory().getAmount(ARROW_SHAFT);
if (getDelay() == 1) {
super.setDelay(3);
}
if (featherAmount >= 15 && shaftAmount >= 15) {
feather.setAmount(15);
ARROW_SHAFT.setAmount(15);
player.getPacketDispatch().sendMessage("You attach feathers to 15 arrow shafts.");
} else {
int amount = Math.min(featherAmount, shaftAmount);
feather.setAmount(amount);
ARROW_SHAFT.setAmount(amount);
player.getPacketDispatch().sendMessage(amount == 1
? "You attach a feathers to a shaft." : "You attach feathers to " + amount + " arrow shafts.");
}
if (player.getInventory().remove(feather, ARROW_SHAFT)) {
HEADLESS_ARROW.setAmount(feather.getAmount());
player.getSkills().addExperience(Skills.FLETCHING, HEADLESS_ARROW.getAmount(), true);
player.getInventory().add(HEADLESS_ARROW);
}
HEADLESS_ARROW.setAmount(1);
feather.setAmount(1);
ARROW_SHAFT.setAmount(1);
if (!player.getInventory().containsItem(ARROW_SHAFT)) {
return true;
}
if (!player.getInventory().containsItem(feather)) {
return true;
}
sets--;
return sets <= 0;
}
@Override
public void message(int type) {
}
/**
* Gets the feather item.
* @return the item.
*/
private Item getFeather() {
int length = FEATHER.length;
for (int i = 0; i < length; i++) {
Item f = FEATHER[i];
if (player.getInventory().containsItem(f)) {
return f;
}
}
return null;
}
}

View file

@ -1,131 +0,0 @@
package content.global.skill.fletching.items.arrow;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import core.game.node.item.Item;
import org.rs09.consts.Items;
import static core.api.ContentAPIKt.hasSpaceFor;
import static core.api.ContentAPIKt.sendDialogue;
/**
* Represents the arrow pulse for creating unfinished ogre arrows.
* @author 'Vexia
*/
public final class HeadlessOgreArrowPulse extends SkillPulse<Item> {
/**
* Represents the headless ogre arrow item.
*/
private final Item HEADLESS_ARROW = new Item(Items.FLIGHTED_OGRE_ARROW_2865);
/**
* Represents the ogre arrow shaft item.
*/
private final Item ARROW_SHAFT = new Item(Items.OGRE_ARROW_SHAFT_2864);
/**
* Represents the feather items.
*/
private static final Item[] FEATHER = new Item[] {
new Item(Items.FEATHER_314, 4),
};
/**
* The feather being used.
*/
private Item feather;
/**
* Represents the amount to make.
*/
private int sets;
/**
* Constructs a new {@code ArrowPulse.java} {@code Object}.
* @param player the player.
* @param node the node.
*/
public HeadlessOgreArrowPulse(Player player, Item node, Item feather, int sets) {
super(player, node);
this.sets = sets;
this.feather = feather;
}
@Override
public boolean checkRequirements() {
if (!player.getInventory().containsItem(ARROW_SHAFT)) {
player.getDialogueInterpreter().sendDialogue("You don't have any arrow shafts.");
return false;
}
if (feather == null || !player.getInventory().containsItem(feather)) {
player.getDialogueInterpreter().sendDialogue("You don't have any feathers.");
return false;
}
if (!hasSpaceFor(player, HEADLESS_ARROW.asItem())) {
sendDialogue(player, "You do not have enough inventory space.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
int featherAmount = player.getInventory().getAmount(feather);
int shaftAmount = player.getInventory().getAmount(ARROW_SHAFT);
if (getDelay() == 1) {
super.setDelay(3);
}
if (featherAmount >= 24 && shaftAmount >= 6) {
feather.setAmount(24);
ARROW_SHAFT.setAmount(6);
player.getPacketDispatch().sendMessage("You attach 24 feathers to 6 ogre arrow shafts.");
} else {
int amount = Math.min(featherAmount / 4, shaftAmount);
feather.setAmount(amount*4);
ARROW_SHAFT.setAmount(amount);
player.getPacketDispatch().sendMessage(amount == 1
? "You attach a feathers to a shaft." : "You attach " + amount * 4 + " feathers to " + amount + " ogre arrow shafts.");
}
if (player.getInventory().remove(feather, ARROW_SHAFT)) {
HEADLESS_ARROW.setAmount(ARROW_SHAFT.getAmount());
player.getSkills().addExperience(Skills.FLETCHING, HEADLESS_ARROW.getAmount(), true);
player.getInventory().add(HEADLESS_ARROW);
}
HEADLESS_ARROW.setAmount(1);
feather.setAmount(1);
ARROW_SHAFT.setAmount(1);
if (!player.getInventory().containsItem(ARROW_SHAFT)) {
return true;
}
if (!player.getInventory().containsItem(feather)) {
return true;
}
sets--;
return sets <= 0;
}
@Override
public void message(int type) {
}
/**
* Gets the feather item.
* @return the item.
*/
private Item getFeather() {
int length = FEATHER.length;
for (int i = 0; i < length; i++) {
Item f = FEATHER[i];
if (player.getInventory().containsItem(f)) {
return f;
}
}
return null;
}
}

View file

@ -1,123 +0,0 @@
/*
package core.game.node.entity.skill.fletching.items.bolts;
import org.crandor.game.node.item.Item;
*/
/**
* Represents an enum of bolts.
* @author 'Vexia
*//*
public enum Bolt {
BRONZE_BOLT(new Item(9375), new Item(877), 9, 0.5),
BLURITE_BOLT(new Item(9376), new Item(9139), 24, 1),
IRON_BOLT(new Item(9377), new Item(9140), 39, 1.5),
SILVER_BOLT(new Item(9382), new Item(9145), 43, 2.5),
STEEL_BOLT(new Item(9378), new Item(9141), 46, 3.5),
MITHRIL_BOLT(new Item(9379), new Item(9142), 54, 5),
ADAMANTITE_BOLT(new Item(9380), new Item(9143), 61, 7),
RUNITE_BOLT(new Item(9381), new Item(9144), 69, 10),
BROAD_BOLT(new Item(13279), new Item(13280), 55, 3);
*/
/**
* The item required.
*//*
private final Item item;
*/
/**
* The product recieved.
*//*
private final Item product;
*/
/**
* The level required.
*//*
private final int level;
*/
/**
* The experience gained.
*//*
private final double experience;
*/
/**
* Constructs a new {@code Bolt} {@code Object}.
* @param item the item.
* @param product the product.
* @param level the level.
* @param experience the experienece.
*//*
Bolt(Item item, Item product, int level, double experience) {
this.item = item;
this.product = product;
this.level = level;
this.experience = experience;
}
*/
/**
* Gets the item.
* @return The item.
*//*
public Item getItem() {
return item;
}
*/
/**
* Gets the product.
* @return The product.
*//*
public Item getProduct() {
return product;
}
*/
/**
* Gets the level.
* @return The level.
*//*
public int getLevel() {
return level;
}
*/
/**
* Gets the experience.
* @return The experience.
*//*
public double getExperience() {
return experience;
}
*/
/**
* Method used to get the bolt for the item.
* @param item the item.
* @return the bolt.
*//*
public static Bolt forItem(final Item item) {
for (Bolt bolt : Bolt.values()) {
if (bolt.getItem().getId() == item.getId()) {
return bolt;
}
}
return null;
}
}
*/

View file

@ -1,130 +0,0 @@
package content.global.skill.fletching.items.bolts;
import content.global.skill.slayer.SlayerManager;
import org.rs09.consts.Items;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import content.global.skill.fletching.Fletching;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
/**
* Represents the bolt pulse class to make bolts.
* @author ceik
*/
public final class BoltPulse extends SkillPulse<Item> {
/**
* Represents the feather item.
*/
private Item feather;
/**
* Represents possible feather Items
*/
private static final Item[] FEATHER = new Item[] {
new Item(Items.FEATHER_314),
new Item(Items.STRIPY_FEATHER_10087),
new Item(Items.RED_FEATHER_10088),
new Item(Items.BLUE_FEATHER_10089),
new Item(Items.YELLOW_FEATHER_10090),
new Item(Items.ORANGE_FEATHER_10091)
};
/**
* Represents the bolt.
*/
private final Fletching.Bolts bolt;
/**
* Represents the sets to do.
*/
private int sets;
/**
* Represents if we're using sets.
*/
private boolean useSets = false;
/**
* Constructs a new {@code BoltPulse.java} {@code Object}.
* @param player the player.
* @param node the node.
*/
public BoltPulse(Player player, Item node, final Fletching.Bolts bolt, final Item feather, final int sets) {
super(player, node);
this.bolt = bolt;
this.sets = sets;
this.feather = feather;
}
@Override
public boolean checkRequirements() {
if (bolt.getUnfinished().getId() == 13279) {
if (!SlayerManager.getInstance(player).flags.isBroadsUnlocked()) {
player.getDialogueInterpreter().sendDialogue("You need to unlock the ability to create broad bolts.");
return false;
}
}
if (player.getSkills().getLevel(Skills.FLETCHING) < bolt.level) {
player.getDialogueInterpreter().sendDialogue("You need a fletching level of " + bolt.level + " in order to do this.");
return false;
}
if (!player.getInventory().containsItem(feather)) {
return false;
}
if (!player.getInventory().containsItem(bolt.getUnfinished())) {
return false;
}
if (!player.getInventory().hasSpaceFor(bolt.getFinished())) {
player.getDialogueInterpreter().sendDialogue("You do not have enough inventory space.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
int featherAmount = player.getInventory().getAmount(feather);
int boltAmount = player.getInventory().getAmount(bolt.unfinished);
if (getDelay() == 1) {
super.setDelay(3);
}
final Item unfinished = bolt.getUnfinished();
if (featherAmount >= 10 && boltAmount >= 10) {
feather.setAmount(10);
unfinished.setAmount(10);
player.getPacketDispatch().sendMessage("You fletch 10 bolts.");
} else {
int amount = featherAmount > boltAmount ? boltAmount : featherAmount;
feather.setAmount(amount);
unfinished.setAmount(amount);
player.getPacketDispatch().sendMessage(amount == 1 ? "You attach a feather to a bolt." : "You fletch " + amount + " bolts");
}
if (player.getInventory().remove(feather, unfinished)) {
Item product = bolt.getFinished();
product.setAmount(feather.getAmount());
player.getSkills().addExperience(Skills.FLETCHING, product.getAmount() * bolt.experience, true);
player.getInventory().add(product);
}
feather.setAmount(1);
if (!player.getInventory().containsItem(feather)) {
return true;
}
if (!player.getInventory().containsItem(bolt.getUnfinished())) {
return true;
}
sets--;
return sets <= 0;
}
@Override
public void message(int type) {
}
}

View file

@ -1,136 +0,0 @@
/*
package core.game.node.entity.skill.fletching.items.bow;
import org.crandor.game.node.item.Item;
import org.crandor.game.world.update.flag.context.Animation;
*/
/**
* Represents the enum of stringing bows.
* @author 'Vexia
*//*
public enum StringBow {
SHORT_BOW(new Item(50), new Item(841), 5, 5, new Animation(6678)),
LONG_BOW(new Item(48), new Item(839), 10, 10, new Animation(6684)),
OAK_SHORTBOW(new Item(54), new Item(843), 20, 16.5, new Animation(6679)),
OAK_LONGBOW(new Item(56), new Item(845), 25, 25, new Animation(6685)),
WILLOW_SHORTBOW(new Item(60), new Item(849), 35, 33.3, new Animation(6680)),
WILLOW_LONGBOW(new Item(58), new Item(847), 40, 41.5, new Animation(6686)),
MAPLE_SHORTBOW(new Item(64), new Item(853), 50, 50, new Animation(6681)),
MAPLE_LONGBOW(new Item(62), new Item(851), 55, 58.3, new Animation(6687)),
YEW_SHORTBOW(new Item(68), new Item(857), 65, 66, new Animation(6682)),
YEW_LONGBOW(new Item(66), new Item(855), 70, 75, new Animation(6688)),
MAGIC_SHORTBOW(new Item(72), new Item(861), 80, 83.3, new Animation(6683)),
MAGIC_LONGBOW(new Item(70), new Item(859), 85, 91.5, new Animation(6689));
StringBow(final Item item, final Item product, final int level, final double experience, final Animation animation) {
this.item = item;
this.product = product;
this.level = level;
this.experience = experience;
this.animation = animation;
}
*/
/**
* The item required.
*//*
private final Item item;
*/
/**
* The item product.
*//*
private final Item product;
*/
/**
* The level required.
*//*
private final int level;
*/
/**
* The experience required.
*//*
private final double experience;
*/
/**
* The animation of stringing.
*//*
private final Animation animation;
*/
/**
* Gets the item.
* @return The item.
*//*
public Item getItem() {
return item;
}
*/
/**
* Gets the product.
* @return The product.
*//*
public Item getProduct() {
return product;
}
*/
/**
* Gets the level.
* @return The level.
*//*
public int getLevel() {
return level;
}
*/
/**
* Gets the experience.
* @return The experience.
*//*
public double getExperience() {
return experience;
}
*/
/**
* Method used to get the animation.
* @return the animation.
*//*
public Animation getAnimation() {
return animation;
}
*/
/**
* Method used to get the string bow for the item.
* @param item the item.
* @return the string bow.
*//*
public static StringBow forItem(final int id) {
for (StringBow bw : StringBow.values()) {
if (bw.getItem().getId() == id) {
return bw;
}
}
return null;
}
}*/

View file

@ -1,103 +0,0 @@
package content.global.skill.fletching.items.bow;
import core.game.node.entity.player.info.LogType;
import core.game.node.entity.player.info.PlayerMonitor;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.world.map.zone.ZoneBorders;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import content.global.skill.fletching.Fletching;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import static core.api.ContentAPIKt.amountInInventory;
/**
* Represents the skill pulse of stringing.
*
* @author Ceikry
*/
public class StringPulse extends SkillPulse<Item> {
/**
* Represents the string bow.
*/
private final Fletching.String bow;
/**
* The amount.
*/
private int amount;
private int initialAmount;
private int processedAmount;
/**
* Constructs a new {@code StringbowPlugin.java} {@code Object}.
*
* @param player the player.
* @param node the node.
*/
public StringPulse(Player player, Item node, final Fletching.String bow, int amount) {
super(player, node);
this.bow = bow;
this.amount = amount;
this.initialAmount = amountInInventory(player, node.getId());
this.processedAmount = 0;
}
@Override
public boolean checkRequirements() {
if (getDelay() == 1) {
setDelay(2);
}
if (player.getSkills().getLevel(Skills.FLETCHING) < bow.level) {
player.getDialogueInterpreter().sendDialogue("You need a fletching level of " + bow.level + " to string this bow.");
return false;
}
if (!player.getInventory().containsItem(new Item(bow.unfinished))) {
return false;
}
if (!player.getInventory().containsItem(new Item(bow.string))) {
player.getDialogueInterpreter().sendDialogue("You seem to have run out of bow strings.");
return false;
}
animate();
return true;
}
@Override
public void animate() {
player.animate(bow.animation);
}
@Override
public boolean reward() {
if (player.getInventory().remove(new Item(bow.unfinished), new Item(bow.string))) {
player.getInventory().add(new Item(bow.product));
player.getSkills().addExperience(Skills.FLETCHING, bow.experience, true);
player.getPacketDispatch().sendMessage("You add a string to the bow.");
processedAmount++;
if (processedAmount > initialAmount) {
PlayerMonitor.log(player, LogType.DUPE_ALERT, "fletched item (" + player.getName() + ", " + bow.unfinished + "): initialAmount " + initialAmount + ", processedAmount " + processedAmount);
}
if (bow == Fletching.String.MAGIC_SHORTBOW
&& (new ZoneBorders(2721, 3489, 2724, 3493, 0).insideBorder(player)
|| new ZoneBorders(2727, 3487, 2730, 3490, 0).insideBorder(player))
&& player.getAttribute("diary:seers:fletch-magic-short-bow", false)) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 2, 2);
}
}
if (!player.getInventory().containsItem(new Item(bow.string)) || !player.getInventory().containsItem(new Item(bow.unfinished))) {
return true;
}
amount--;
return amount == 0;
}
@Override
public void message(int type) {
}
}

View file

@ -1,97 +0,0 @@
/*
package core.game.node.entity.skill.fletching.items.crossbow;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import org.crandor.game.node.entity.player.Player;
import org.crandor.game.node.item.Item;
*/
/**
* Represents the skill pulse of stringing.
* @author 'Vexia
*//*
public class CrossbowPulse extends SkillPulse<Item> {
*/
/**
* Represents the bow string item.
*//*
private final Item BOW_STRING = new Item(9438);
*/
/**
* Represents the string bow.
*//*
private final StringCross bow;
*/
/**
* Represents the amount.
*//*
private int amount;
*/
/**
* Constructs a new {@code StringcrossbowPlugin.java} {@code Object}.
* @param player the player.
* @param node the node.
*//*
public CrossbowPulse(Player player, Item node, final StringCross bow, int amount) {
super(player, node);
this.bow = bow;
this.amount = amount;
}
@Override
public boolean checkRequirements() {
if (player.getSkills().getLevel(Skills.FLETCHING) < bow.getLevel()) {
player.getDialogueInterpreter().sendDialogue("You need a fletching level of " + bow.getLevel() + " to string this crossbow.");
return false;
}
if (!player.getInventory().containsItem(BOW_STRING)) {
player.getDialogueInterpreter().sendDialogue("You seem to have run out of bow strings.");
return false;
}
return true;
}
@Override
public void animate() {
player.animate(bow.getAnimation());
}
@Override
public boolean reward() {
if (getDelay() == 1) {
super.setDelay(5);
return false;
}
if (player.getInventory().remove(bow.getItem(), BOW_STRING)) {
player.getInventory().add(bow.getProduct());
player.getSkills().addExperience(Skills.FLETCHING, bow.getExperience(), true);
player.getPacketDispatch().sendMessage("You add a string to the crossbow.");
}
if (!player.getInventory().containsItem(BOW_STRING) || !player.getInventory().containsItem(bow.getItem())) {
return true;
}
amount--;
return amount == 0;
}
@Override
public void message(int type) {
switch (type) {
case 0:
break;
case 1:
break;
}
}
}*/

View file

@ -1,128 +0,0 @@
package content.global.skill.fletching.items.crossbow;
import core.game.node.item.Item;
import core.game.world.update.flag.context.Animation;
/**
* Represents the enum for limbs.
* @author 'Vexia
*/
public enum Limb {
WOODEN_STOCK(new Item(9440), new Item(9420), new Item(9454), 9, 12, new Animation(4436)),
OAK_STOCK(new Item(9442), new Item(9422), new Item(9176), 24, 32, new Animation(4437)),
WILLOW_STOCK(new Item(9444), new Item(9423), new Item(9457), 39, 44, new Animation(4438)),
TEAK_STOCK(new Item(9446), new Item(9425), new Item(9459), 46, 54, new Animation(4439)),
MAPLE_STOCK(new Item(9448), new Item(9427), new Item(9461), 54, 64, new Animation(4440)),
MAHOGANY_STOCK(new Item(9450), new Item(9429), new Item(9463), 61, 82, new Animation(4441)),
YEW_STOCK(new Item(9452), new Item(9431), new Item(9465), 69, 100, new Animation(4442));
/**
* Constructs a new {@code StringcrosbowPlugin.java} {@code Object}.
* @param stock the stock.
* @param limb the limb.
* @param product the product.
* @param level the level.
* @param experience the experience.
* @param animation the animation.
*/
Limb(Item stock, Item limb, Item product, int level, double experience, Animation animation) {
this.stock = stock;
this.limb = limb;
this.product = product;
this.level = level;
this.experience = experience;
this.animation = animation;
}
/**
* The stock.
*/
private final Item stock;
/**
* The limb.
*/
private final Item limb;
/**
* The product.
*/
private final Item product;
/**
* The level.
*/
private final int level;
/**
* The experience.
*/
private final double experience;
/**
* The animation.
*/
private final Animation animation;
/**
* Gets the stock.
* @return The stock.
*/
public Item getStock() {
return stock;
}
/**
* Gets the limb.
* @return The limb.
*/
public Item getLimb() {
return limb;
}
/**
* Gets the product.
* @return The product.
*/
public Item getProduct() {
return product;
}
/**
* Gets the level.
* @return The level.
*/
public int getLevel() {
return level;
}
/**
* Gets the experience.
* @return The experience.
*/
public double getExperience() {
return experience;
}
/**
* Gets the animation.
* @return The animation.
*/
public Animation getAnimation() {
return animation;
}
/**
* Method used to get the {@link Limb} for the item.
* @param item the item.
* @return the limb.
*/
public static Limb forItems(final Item item, final Item second) {
for (Limb l : Limb.values()) {
if (l.getLimb().getId() == item.getId() && l.getStock().getId() == second.getId() || l.getLimb().getId() == second.getId() && l.getStock().getId() == item.getId()) {
return l;
}
}
return null;
}
}

View file

@ -1,52 +0,0 @@
package content.global.skill.fletching.items.crossbow
import core.game.node.entity.player.Player
import core.game.node.entity.skill.SkillPulse
import core.game.node.entity.skill.Skills
import content.global.skill.fletching.Fletching
import core.game.node.item.Item
/**
* Represents the skill pulse of attaching limbs.
* @author Ceikry
*/
class LimbPulse(player: Player?, node: Item, private val limb: Fletching.Limb, private var amount: Int) : SkillPulse<Item?>(player, node) {
override fun checkRequirements(): Boolean {
if (player.skills.getLevel(Skills.FLETCHING) < limb.level) {
player.dialogueInterpreter.sendDialogue("You need a fletching level of " + limb.level + " to attach these limbs.")
return false
}
if (!player.inventory.containsItem(Item(limb.limb))) {
player.dialogueInterpreter.sendDialogue("That's not the correct limb to attach.")
return false
}
if(!player.inventory.containsItem(Item(limb.stock))){
player.dialogueInterpreter.sendDialogue("That's not the correct stock for that limb.")
return false
}
return player.inventory.containsItem(Item(limb.stock))
}
override fun animate() {
player.animate(limb.animation)
}
override fun reward(): Boolean {
if (delay == 1) {
super.setDelay(6)
return false
}
if (player.inventory.remove(Item(limb.stock), Item(limb.limb))) {
player.inventory.add(Item(limb.product))
player.skills.addExperience(Skills.FLETCHING, limb.experience, true)
player.packetDispatch.sendMessage("You attach the metal limbs to the stock.")
}
if (!player.inventory.containsItem(Item(limb.limb))) {
return true
}
amount--
return amount == 0
}
override fun message(type: Int) {}
}

View file

@ -1,139 +0,0 @@
/*
package core.game.node.entity.skill.fletching.items.crossbow;
import org.crandor.game.node.item.Item;
import org.crandor.game.world.update.flag.context.Animation;
*/
/**
* Represents the enum of stringing crossbows.
* @author 'Vexia
*//*
public enum StringCross {
BRONZE_CBOW(new Item(9454), new Item(9174), 9, 6, new Animation(6671)),
BLURITE_CBOW(new Item(9456), new Item(9176), 24, 16, new Animation(6672)),
IRON_CBOW(new Item(9457), new Item(9177), 39, 22, new Animation(6673)),
STEEL_CBOW(new Item(9459), new Item(9179), 46, 27, new Animation(6674)),
MITHIRIL_CBOW(new Item(9461), new Item(9181), 54, 32, new Animation(6675)),
ADAMANT_CBOW(new Item(9463), new Item(9183), 61, 41, new Animation(6676)),
RUNITE_CBOW(new Item(9465), new Item(9185), 69, 50, new Animation(6677));
*/
/**
* Constructs a new {@code StringcrossbowPlugin.java} {@code Object}.
* @param item the item.
* @param product the product.
* @param level the level.
* @param experience the experience.
*//*
StringCross(final Item item, final Item product, final int level, final double experience, final Animation animation) {
this.item = item;
this.product = product;
this.level = level;
this.experience = experience;
this.animation = animation;
}
*/
/**
* The item required.
*//*
private final Item item;
*/
/**
* The item product.
*//*
private final Item product;
*/
/**
* The level required.
*//*
private final int level;
*/
/**
* The experience required.
*//*
private final double experience;
*/
/**
* The animation of stringing.
*//*
private final Animation animation;
*/
/**
* Gets the item.
* @return The item.
*//*
public Item getItem() {
return item;
}
*/
/**
* Gets the product.
* @return The product.
*//*
public Item getProduct() {
return product;
}
*/
/**
* Gets the level.
* @return The level.
*//*
public int getLevel() {
return level;
}
*/
/**
* Gets the experience.
* @return The experience.
*//*
public double getExperience() {
return experience;
}
*/
/**
* Method used to get the animation.
* @return the animation.
*//*
public Animation getAnimation() {
return animation;
}
*/
/**
* Method used to get the string bow for the item.
* @param item the item.
* @return the string bow.
*//*
public static StringCross forItem(final Item item) {
for (StringCross bw : StringCross.values()) {
if (bw.getItem().getId() == item.getId()) {
return bw;
}
}
return null;
}
}
*/

View file

@ -1,96 +0,0 @@
package content.global.skill.fletching.items.darts;
import core.game.node.item.Item;
/**
* Represents the enum to hold dart info.
* @author 'Vexia
*/
public enum Dart {
BRONZE_DART(new Item(819), new Item(806), 1, 1.8),
IRON_DART(new Item(820), new Item(807), 22, 3.8),
STEEL_DART(new Item(821), new Item(808), 37, 7.5),
MITHRIL_DART(new Item(822), new Item(809), 52, 11.2),
ADAMANT_DART(new Item(823), new Item(810), 67, 15),
RUNE_DART(new Item(824), new Item(811), 81, 18.8),
DRAGON_DART(new Item(11232), new Item(11230), 95, 25);
/**
* Constructs a new {@code Dart} {@code Object}.
* @param item the item.
* @param product the product.
* @param level the level.
* @param experience the experience.
*/
Dart(final Item item, final Item product, final int level, final double experience) {
this.item = item;
this.product = product;
this.level = level;
this.experience = experience;
}
/**
* Represents the item required.
*/
private final Item item;
/**
* Represents the product gained.
*/
private final Item product;
/**
* Represents the level required.
*/
private final int level;
/**
* Represents the experience gained.
*/
private final double experience;
/**
* Gets the item.
* @return The item.
*/
public Item getItem() {
return item;
}
/**
* Gets the product.
* @return The product.
*/
public Item getProduct() {
return product;
}
/**
* Gets the level.
* @return The level.
*/
public int getLevel() {
return level;
}
/**
* Gets the experience.
* @return The experience.
*/
public double getExperience() {
return experience;
}
/**
* Method used to get the dart for the item.
* @param item the item.
* @return the dart.
*/
public static Dart forItem(final Item item) {
for (Dart dart : Dart.values()) {
if (dart.getItem().getId() == item.getId()) {
return dart;
}
}
return null;
}
}

View file

@ -1,105 +0,0 @@
package content.global.skill.fletching.items.darts;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import content.global.skill.fletching.Fletching;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import static core.api.ContentAPIKt.*;
import content.data.Quests;
/**
* Represents the dart pulse.
* @author ceikry
*/
public final class DartPulse extends SkillPulse<Item> {
/**
* Represents the feather item.
*/
private static final Item FEATHER = new Item(314);
/**
* Represents the dart.
*/
private final Fletching.Darts dart;
/**
* Represents the sets to make.
*/
private int sets;
/**
* Constructs a new {@code DartPulse.java} {@code Object}.
* @param player the player.
* @param node the node.
*/
public DartPulse(Player player, Item node, Fletching.Darts dart, int sets) {
super(player, node);
this.dart = dart;
this.sets = sets;
}
@Override
public boolean checkRequirements() {
if (player.getSkills().getLevel(Skills.FLETCHING) < dart.level) {
player.getDialogueInterpreter().sendDialogue("You need a fletching level of " + dart.level + " to do this.");
return false;
}
if (!player.getQuestRepository().isComplete(Quests.THE_TOURIST_TRAP)){
player.getDialogueInterpreter().sendDialogue("You need to have completed Tourist Trap to fletch darts.");
return false;
}
if (!hasSpaceFor(player, dart.getFinished())) {
sendDialogue(player, "You do not have enough inventory space.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
if (getDelay() == 1) {
super.setDelay(3);
}
final Item unfinished = dart.getUnfinished();
final int dartAmount = player.getInventory().getAmount(unfinished);
final int featherAmount = player.getInventory().getAmount(FEATHER);
if (dartAmount >= 10 && featherAmount >= 10) {
FEATHER.setAmount(10);
unfinished.setAmount(10);
player.getPacketDispatch().sendMessage("You attach feathers to 10 darts.");
} else {
int amount = featherAmount > dartAmount ? dartAmount : featherAmount;
FEATHER.setAmount(amount);
unfinished.setAmount(amount);
player.getPacketDispatch().sendMessage(amount == 1 ? "You attach a feather to a dart." : "You attach feathers to " + amount + " darts.");
}
if (player.getInventory().remove(FEATHER, unfinished)) {
Item product = dart.getFinished();
product.setAmount(FEATHER.getAmount());
player.getSkills().addExperience(Skills.FLETCHING, dart.experience * product.getAmount(), true);
player.getInventory().add(product);
}
FEATHER.setAmount(1);
if (!player.getInventory().containsItem(FEATHER)) {
return true;
}
if (!player.getInventory().containsItem(dart.getUnfinished())) {
return true;
}
sets--;
return sets == 0;
}
@Override
public void message(int type) {
}
}

View file

@ -1,101 +0,0 @@
package content.global.skill.fletching.items.gem;
import core.game.node.item.Item;
/**
* Represents gems to cut into bolt tips.
* @author 'Vexia
* @date 01/12/2013
*/
public enum Gem {
OPAL(new Item(1609), new Item(45, 12), 11, 1.5),
JADE(new Item(1611), new Item(9187, 12), 26, 2.4),
RED_TOPAZ(new Item(1613), new Item(9188, 12), 48, 3.9),
SAPPHIRE(new Item(1607), new Item(9189, 12), 56, 4),
EMERALD(new Item(1605), new Item(9190, 12), 58, 5.5),
RUBY(new Item(1603), new Item(9191, 12), 63, 6.3),
DIAMOND(new Item(1601), new Item(9192, 12), 65, 7),
DRAGONSTONE(new Item(1615), new Item(9193, 12), 71, 8.2),
ONYX(new Item(6573), new Item(9194, 24), 73, 9.4);
/**
* Constructs a new {@code Gem.java} {@code Object}.
* @param gem the gem.
* @param bolt the bolt.
* @param level the level.
* @param experience the experience.
*/
Gem(Item gem, Item bolt, int level, double experience) {
this.gem = gem;
this.bolt = bolt;
this.level = level;
this.experience = experience;
}
/**
* Represents the gem.
*/
private final Item gem;
/**
* Represents the bolt.
*/
private final Item bolt;
/**
* Represents the level required.
*/
private final int level;
/**
* Represents the experience gained.
*/
private final double experience;
/**
* Gets the gem.
* @return The gem.
*/
public Item getGem() {
return gem;
}
/**
* Gets the bolt.
* @return The bolt.
*/
public Item getBolt() {
return bolt;
}
/**
* Gets the level.
* @return The level.
*/
public int getLevel() {
return level;
}
/**
* Gets the experience.
* @return The experience.
*/
public double getExperience() {
return experience;
}
/**
* Method used to get a gem for the item.
* @param item the item.
* @return the gem.
*/
public static Gem forItem(final Item item) {
for (Gem gem : values()) {
if (gem.getGem().getId() == item.getId()) {
return gem;
}
}
return null;
}
}

View file

@ -1,144 +0,0 @@
/*
package core.game.node.entity.skill.fletching.items.gem;
import org.crandor.game.node.item.Item;
*/
/**
* Represents a gem bolt.
* @author 'Vexia
* @date 01/12/2013
*//*
public enum GemBolt {
OPAL(new Item(877, 10), new Item(45, 10), new Item(879, 10), 11, 1.5),
PEARL(new Item(9140, 10), new Item(46, 10), new Item(880, 10), 41, 3.2),
JADE(new Item(9139, 10), new Item(9187, 10), new Item(9335, 10), 26, 2.4),
RED_TOPAZ(new Item(9141, 10), new Item(9188, 10), new Item(9336, 10), 48, 3.9),
SAPPHIRE(new Item(9142, 10), new Item(9189, 10), new Item(9337, 10), 56, 4),
EMERALD(new Item(9142, 10), new Item(9190, 10), new Item(9338, 10), 58, 5.5),
RUBY(new Item(9143, 10), new Item(9191, 10), new Item(9339, 10), 63, 6.3),
DIAMOND(new Item(9143, 10), new Item(9192, 10), new Item(9340, 10), 65, 7),
DRAGONSTONE(new Item(9144, 10), new Item(9193, 10), new Item(9341, 10), 71, 8.2),
ONYX(new Item(9144, 10), new Item(9194, 10), new Item(9342, 10), 73, 9.4);
*/
/**
* Constructs a new {@code GemBolt} {@code Object}.
* @param base the base.
* @param tip the tip.
* @param level the level.
* @param experience the experience.
*//*
GemBolt(Item base, Item tip, Item product, int level, double experience) {
this.base = base;
this.tip = tip;
this.product = product;
this.level = level;
this.experience = experience;
}
*/
/**
* Represents the base item.
*//*
private final Item base;
*/
/**
* Represents the tip to attach.
*//*
private final Item tip;
*/
/**
* Represents the product.
*//*
private final Item product;
*/
/**
* Represents the level.
*//*
private final int level;
*/
/**
* Represents the experience.
*//*
private final double experience;
*/
/**
* Gets the base.
* @return The base.
*//*
public Item getBase() {
return base;
}
*/
/**
* Gets the tip.
* @return The tip.
*//*
public Item getTip() {
return tip;
}
*/
/**
* Gets the product.
* @return The product.
*//*
public Item getProduct() {
return product;
}
*/
/**
* Gets the level.
* @return The level.
*//*
public int getLevel() {
return level;
}
*/
/**
* Gets the experience.
* @return The experience.
*//*
public double getExperience() {
return experience;
}
*/
/**
* Method used to get the gem bolt from the id.
* @param boltt the boltt.
* @param tip the tip.
* @return the bolt.
*//*
public static GemBolt forItems(final Item boltt, final Item tip) {
for (GemBolt bolt : values()) {
if (bolt.getBase().getId() == boltt.getId() && bolt.getTip().getId() == tip.getId() || bolt.getBase().getId() == tip.getId() && bolt.getTip().getId() == boltt.getId()) {
return bolt;
}
}
return null;
}
}
*/

View file

@ -1,68 +0,0 @@
package content.global.skill.fletching.items.gem
import core.game.node.entity.player.Player
import core.game.node.entity.skill.SkillPulse
import core.game.node.entity.skill.Skills
import content.global.skill.fletching.Fletching.GemBolts
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
/**
* Represents the gem cutting pulse(gem to bolt).
* @author Ceikry
*/
class GemBoltCutPulse
/**
* Constructs a new `GemCutPulse.java` `Object`.
* @param player the player.
* @param node the node.
* @param amount the amount.
*/(player: Player?, node: Item?,
/**
* Represents the gem we're cutting.
*/
private val gem: GemBolts,
/**
* Represents the amount to make.
*/
private var amount: Int) : SkillPulse<Item?>(player, node) {
/**
* Represents the ticks passed.
*/
private var ticks = 0
override fun checkRequirements(): Boolean {
if (player.skills.getLevel(Skills.FLETCHING) < gem.level) {
player.dialogueInterpreter.sendDialogue("You need a Fletching level of " + gem.level + " or above to do that.")
return false
}
return player.inventory.containsItem(Item(gem.gem))
}
override fun animate() {
if (ticks % 6 == 0) {
player.animate(ANIMATION)
}
}
override fun reward(): Boolean {
if (++ticks % 5 != 0) {
return false
}
val reward = if (gem.gem == Items.OYSTER_PEARLS_413) Item(gem.tip, 24) else Item(gem.tip, 12)
if (player.inventory.remove(Item(gem.gem))) {
player.inventory.add(reward)
player.skills.addExperience(Skills.FLETCHING, gem.experience, true)
}
amount--
return amount <= 0
}
companion object {
/**
* Represents the cutting animation.
*/
private val ANIMATION = Animation(6702)
}
}

View file

@ -1,91 +0,0 @@
package content.global.skill.fletching.items.gem;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import content.global.skill.fletching.Fletching;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
/**
* Represents the attaching of a gem bolt to a premade bolt.
* @author Ceikry
*/
public final class GemBoltPulse extends SkillPulse<Item> {
/**
* Represents the gem bolt being made.
*/
private Fletching.GemBolts bolt;
/**
* Represents the sets to make.
*/
private int sets = 0;
/**
* Represents the ticks passed.
*/
private int ticks;
/**
* Constructs a new {@code GemBoltPulse} {@code Object}.
* @param player the player.
* @param node the node.
* @param sets the sets.
*/
public GemBoltPulse(Player player, Item node, Fletching.GemBolts bolt, int sets) {
super(player, node);
this.bolt = bolt;
this.sets = sets;
}
@Override
public boolean checkRequirements() {
if (player.getSkills().getLevel(Skills.FLETCHING) < bolt.level) {
player.getDialogueInterpreter().sendDialogue("You need a Fletching level of " + bolt.level + " or above to do that.");
return false;
}
if (!player.getInventory().containsItem(new Item(bolt.base)) || !player.getInventory().containsItem(new Item(bolt.tip))) {
return false;
}
if (!player.getInventory().hasSpaceFor(new Item(bolt.product))){
player.getDialogueInterpreter().sendDialogue("You do not have enough inventory space.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
if (++ticks % 3 != 0) {
return false;
}
int baseAmount = player.getInventory().getAmount(bolt.base);
int tipAmount = player.getInventory().getAmount(bolt.tip);
Item base = new Item(bolt.base);
Item tip = new Item(bolt.tip);
Item product = new Item(bolt.product);
if(baseAmount >= 10 && tipAmount >= 10){
base.setAmount(10);
tip.setAmount(10);
product.setAmount(10);
} else {
int amount = baseAmount > tipAmount ? tipAmount : baseAmount;
base.setAmount(amount);
tip.setAmount(amount);
product.setAmount(amount);
}
if (player.getInventory().remove(base,tip)) {
player.getInventory().add(product);
player.getSkills().addExperience(Skills.FLETCHING, bolt.experience * product.getAmount(), true);
player.getPacketDispatch().sendMessage(product.getAmount() == 1 ? "You attach the tip to the bolt." : "You fletch " + product.getAmount() + " bolts.");
}
sets--;
return sets <= 0;
}
}

View file

@ -1,85 +0,0 @@
package content.global.skill.fletching.items.grapple;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
/**
* Represents the skill pulse used to create a mith grapple.
* @author 'Vexia
* @date 21/12/2013
*/
public final class GrapplePulse extends SkillPulse<Item> {
/**
* Represents the mith grapple tip.
*/
private static final Item MITH_GRAPPLE = new Item(9418);
/**
* Represents the mithril grapple tio.
*/
private static final Item GRAPPLE_TIP = new Item(9416);
/**
* Represents the mithril bolt.
*/
private static final Item MITHRIL_BOLT = new Item(9142);
/**
* Represents the amount of the grapple to make.
*/
private int amount;
/**
* Constructs a new {@code GrapplePulse} {@code Object}.
* @param player the player.
* @param node the node.
* @param amount the amount.
*/
public GrapplePulse(Player player, Item node, int amount) {
super(player, node);
this.amount = amount;
}
@Override
public boolean checkRequirements() {
int inventoryAmount = player.getInventory().getAmount(GRAPPLE_TIP);
if (amount > inventoryAmount) {
amount = inventoryAmount;
}
if (!player.getInventory().containsItem(GRAPPLE_TIP) || !player.getInventory().containsItem(MITHRIL_BOLT)) {
return false;
}
if (player.getSkills().getLevel(Skills.FLETCHING) < 59) {
player.getDialogueInterpreter().sendDialogue("You need a fletching level of at least 59 in order to do this.");
return false;
}
return true;
}
@Override
public void animate() {
}
@Override
public boolean reward() {
if (getDelay() == 1) {
setDelay(3);
return false;
}
if (player.getInventory().remove(GRAPPLE_TIP) && player.getInventory().remove(MITHRIL_BOLT)) {
player.getInventory().add(MITH_GRAPPLE);
player.getSkills().addExperience(Skills.FLETCHING, 5, true);
}
amount--;
return amount < 1;
}
@Override
public void message(int type) {
}
}

View file

@ -0,0 +1,113 @@
package content.global.skill.fletching.log
import content.global.skill.fletching.AchievementDiaryAttributeKeys
import content.global.skill.fletching.Zones
import content.global.skill.fletching.log.GrammarHelpers.aOrAn
import content.global.skill.fletching.log.GrammarHelpers.makeFriendlyName
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import core.tools.RandomFunction
import org.rs09.consts.Items
/**
* Represents the queueScript used to craft things by carving a log
* @author ceik
* @param player the player.
* @param logCraftInfo crafting info about what we're making out of the log
* @param amount iterations of craft to run
*/
class CraftItemWithLogScript(
private val player: Player,
private val logCraftInfo: LogCraftInfo,
private val amount: Int
) {
private val initialDelay = 1
// src https://gitlab.com/2009scape/2009scape/-/merge_requests/1960#note_2702231552
private val subsequentDelay = 3
private val carveLogAnimation = Animation(1248)
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < logCraftInfo.level) {
LogCraftableListeners.sendLevelCheckFailDialog(player, logCraftInfo)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
if (removeItem(player, logCraftInfo.logItemId.asItem())) {
player.animate(carveLogAnimation)
val finishedItemName = makeFriendlyName(Item(logCraftInfo.finishedItemId).name)
val amountToCraft = when (logCraftInfo) {
LogCraftInfo.OGRE_ARROW_SHAFT -> RandomFunction.random(2, 6)
LogCraftInfo.ARROW_SHAFT -> 15
else -> 1
}
if (logCraftInfo == LogCraftInfo.OGRE_COMP_BOW) {
if (!removeItem(player, Items.WOLF_BONES_2859)) {
return@queueScript stopExecuting(player)
}
}
sendCraftMessageToPlayer(amountToCraft, finishedItemName)
addItem(player, logCraftInfo.finishedItemId, amountToCraft)
rewardXP(player, Skills.FLETCHING, logCraftInfo.experience)
if (logCraftInfo == LogCraftInfo.MAGIC_SHORTBOW) {
handleSeersMagicShortbowAchievement()
}
} else {
return@queueScript stopExecuting(player)
}
if (stage >= amount - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
private fun handleSeersMagicShortbowAchievement() {
if (Zones.inAnyZone(player, Zones.seersMagicShortbowAchievementZones) &&
!player.achievementDiaryManager.hasCompletedTask(DiaryType.SEERS_VILLAGE, 2, 2)
) {
setAttribute(
player,
"/save:${AchievementDiaryAttributeKeys.FLETCHED_UNSTRUNG_MAGIC_SHORTBOW}",
true
)
}
}
private fun sendCraftMessageToPlayer(amountToCraft: Int, finishedItemName: String) {
when (logCraftInfo) {
LogCraftInfo.ARROW_SHAFT -> sendMessage(
player,
"You carefully cut the wood into $amountToCraft arrow shafts."
)
LogCraftInfo.OGRE_ARROW_SHAFT -> sendMessage(
player,
"You carefully cut the wood into $amountToCraft arrow shafts."
)
else -> sendMessage(
player,
"You carefully cut the wood into ${aOrAn(finishedItemName)} $finishedItemName."
)
}
}
}

View file

@ -0,0 +1,20 @@
package content.global.skill.fletching.log
import core.tools.StringUtils
object GrammarHelpers {
fun makeFriendlyName(name: String): String {
return name.replace("(u)", "").trim { it <= ' ' }
}
/**
* Returns "a" or "an" depending on whether the word begins with a vowel
*/
@Suppress("GrazieInspection")
fun aOrAn(word: String): String {
return when (StringUtils.isPlusN(word)) {
true -> "an"
false -> "a"
}
}
}

View file

@ -0,0 +1,63 @@
package content.global.skill.fletching.log
import org.rs09.consts.Items
/**
* Provides information pertaining to crafting different items from logs
* @property logItemId the log item id that can be used to craft this item
* @property finishedItemId the resulting finished bolt Item id.
* @property level the level required to craft.
* @property experience the experience gained by crafting.
*/
enum class LogCraftInfo(val logItemId: Int, val finishedItemId: Int, val experience: Double, val level: Int) {
ARROW_SHAFT(Items.LOGS_1511, Items.ARROW_SHAFT_52, 5.0, 1),
SHORT_BOW(Items.LOGS_1511, Items.SHORTBOW_U_50, 5.0, 5),
LONG_BOW(Items.LOGS_1511, Items.LONGBOW_U_48, 10.0, 10),
WOODEN_STOCK(Items.LOGS_1511, Items.WOODEN_STOCK_9440, 6.0, 9),
OGRE_ARROW_SHAFT(Items.ACHEY_TREE_LOGS_2862, Items.OGRE_ARROW_SHAFT_2864, 6.4, 5),
OGRE_COMP_BOW(Items.ACHEY_TREE_LOGS_2862, Items.UNSTRUNG_COMP_BOW_4825, 45.0, 30),
OAK_SHORTBOW(Items.OAK_LOGS_1521, Items.OAK_SHORTBOW_U_54, 16.5, 20),
OAK_LONGBOW(Items.OAK_LOGS_1521, Items.OAK_LONGBOW_U_56, 25.0, 25),
OAK_STOCK(Items.OAK_LOGS_1521, Items.OAK_STOCK_9442, 16.0, 24),
WILLOW_SHORTBOW(Items.WILLOW_LOGS_1519, Items.WILLOW_SHORTBOW_U_60, 33.3, 35),
WILLOW_LONGBOW(Items.WILLOW_LOGS_1519, Items.WILLOW_LONGBOW_U_58, 41.5, 40),
WILLOW_STOCK(Items.WILLOW_LOGS_1519, Items.WILLOW_STOCK_9444, 22.0, 39),
MAPLE_SHORTBOW(Items.MAPLE_LOGS_1517, Items.MAPLE_SHORTBOW_U_64, 50.0, 50),
MAPLE_LONGBOW(Items.MAPLE_LOGS_1517, Items.MAPLE_LONGBOW_U_62, 58.3, 55),
MAPLE_STOCK(Items.MAPLE_LOGS_1517, Items.MAPLE_STOCK_9448, 32.0, 54),
YEW_SHORTBOW(Items.YEW_LOGS_1515, Items.YEW_SHORTBOW_U_68, 67.5, 65),
YEW_LONGBOW(Items.YEW_LOGS_1515, Items.YEW_LONGBOW_U_66, 75.0, 70),
YEW_STOCK(Items.YEW_LOGS_1515, Items.YEW_STOCK_9452, 50.0, 69),
MAGIC_SHORTBOW(Items.MAGIC_LOGS_1513, Items.MAGIC_SHORTBOW_U_72, 83.3, 80),
MAGIC_LONGBOW(Items.MAGIC_LOGS_1513, Items.MAGIC_LONGBOW_U_70, 91.5, 85),
TEAK_STOCK(Items.TEAK_LOGS_6333, Items.TEAK_STOCK_9446, 27.0, 46),
MAHOGANY_STOCK(Items.MAHOGANY_LOGS_6332, Items.MAHOGANY_STOCK_9450, 41.0, 61);
companion object {
val logIds: IntArray = LogCraftInfo.values().map { logCraftInfo: LogCraftInfo -> logCraftInfo.logItemId }.distinct().toIntArray()
private val logCraftablesByLogId = associateCraftInfoByLogIds()
private fun associateCraftInfoByLogIds(): Map<Int, List<LogCraftInfo>> {
val map = HashMap<Int, List<LogCraftInfo>>()
for (logId in logIds) {
map[logId] = LogCraftInfo.values().filter { logCraftInfo: LogCraftInfo -> logCraftInfo.logItemId == logId }
}
return map
}
fun forLogId(logId: Int): List<LogCraftInfo>? {
return logCraftablesByLogId[logId]
}
}
}

View file

@ -0,0 +1,83 @@
package content.global.skill.fletching.log
import content.data.Quests
import content.global.skill.fletching.log.GrammarHelpers.aOrAn
import content.global.skill.fletching.log.GrammarHelpers.makeFriendlyName
import core.api.*
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
@Suppress("unused") // Reflectively loaded
class LogCraftableListeners : InteractionListener {
override fun defineListeners() {
onUseWith(IntType.ITEM, Items.KNIFE_946, *LogCraftInfo.logIds) { player, knife, log ->
val applicableCraftInfosForLog = LogCraftInfo.forLogId(log.id) ?: return@onUseWith false
val craftableItems =
applicableCraftInfosForLog.map { logCraftable -> Item(logCraftable.finishedItemId) }.toTypedArray()
val handler: SkillDialogueHandler = object : SkillDialogueHandler(
player,
SkillDialogue.forLength(applicableCraftInfosForLog.size),
*craftableItems
) {
override fun create(amount: Int, index: Int) {
if (!playerMeetsInitialRequirements(applicableCraftInfosForLog[index])) return
CraftItemWithLogScript(player, applicableCraftInfosForLog[index], amount).invoke()
}
private fun playerMeetsInitialRequirements(logCraftInfo: LogCraftInfo): Boolean {
if (getDynLevel(player, Skills.FLETCHING) < logCraftInfo.level) {
sendLevelCheckFailDialog(player, logCraftInfo)
return false
}
if (logCraftInfo == LogCraftInfo.OGRE_ARROW_SHAFT &&
!isQuestStarted(player, Quests.BIG_CHOMPY_BIRD_HUNTING)
) {
sendDialogue(player, "You must have started ${Quests.BIG_CHOMPY_BIRD_HUNTING} to make those.")
return false
}
if (logCraftInfo == LogCraftInfo.OGRE_COMP_BOW) {
if (getQuestStage(player, Quests.ZOGRE_FLESH_EATERS) < 8) {
sendMessage(
player,
"You must have started Zogre Flesh Eaters and asked Grish to string this."
)
return false
}
if (amountInInventory(player, Items.WOLF_BONES_2859) < 1) {
sendMessage(player, "You need to have Wolf Bones in order to make this.")
return false
}
}
return true
}
override fun getAll(index: Int): Int {
return amountInInventory(player, log.id)
}
}
handler.open()
return@onUseWith true
}
}
companion object {
fun sendLevelCheckFailDialog(player: Player, logCraftInfo: LogCraftInfo) {
val finishedItem = Item(logCraftInfo.finishedItemId)
val friendlyCraftedItemName = makeFriendlyName(finishedItem.name)
sendDialogue(
player,
"You need a Fletching skill of ${logCraftInfo.level} or above to make ${
aOrAn(
friendlyCraftedItemName
)
} $friendlyCraftedItemName."
)
}
}
}

View file

@ -0,0 +1,71 @@
package content.global.skill.fletching.stringing
import content.global.skill.fletching.AchievementDiaryAttributeKeys
import content.global.skill.fletching.Zones
import content.global.skill.fletching.stringing.StringableCraftInfo.Companion.applicableStringId
import core.api.*
import core.game.interaction.Clocks
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
/**
* Represents queueScript to string a bow/crossbow
* @author Ceikry
* @param player the player.
* @param stringableCraftInfo contains crafting information about what we're stringing
* @param amount the amount of items to string
*/
class StringItemScript(
private val player: Player,
private val stringableCraftInfo: StringableCraftInfo,
private var amount: Int
) {
private val initialDelay = 1
private val subsequentDelay = 2
fun invoke() {
queueScript(player, initialDelay) { stage ->
if (!clockReady(player, Clocks.SKILLING)) return@queueScript keepRunning(player)
if (getDynLevel(player, Skills.FLETCHING) < stringableCraftInfo.level) {
StringingListeners.sendLevelCheckFailDialogue(player, stringableCraftInfo.level)
return@queueScript stopExecuting(player) // Check each iteration since dynLevel can change (status effects ending, skill assist session end...)
}
if (
removeItemsIfPlayerHasEnough(
player,
Item(stringableCraftInfo.unstrungItemId),
Item(stringableCraftInfo.applicableStringId)
)
) {
player.animate(stringableCraftInfo.animation)
addItem(player, stringableCraftInfo.strungItemId, 1)
rewardXP(player, Skills.FLETCHING, stringableCraftInfo.experience)
sendMessage(player, "You add a string to the bow.")
if (stringableCraftInfo == StringableCraftInfo.MAGIC_SHORTBOW) {
handleSeersMagicShortbowAchievement()
}
} else {
return@queueScript stopExecuting(player)
}
if (stage >= amount - 1) {
return@queueScript stopExecuting(player)
}
return@queueScript delayClock(player, Clocks.SKILLING, subsequentDelay, true)
}
}
private fun handleSeersMagicShortbowAchievement() {
if (Zones.inAnyZone(player, Zones.seersMagicShortbowAchievementZones) &&
getAttribute(player, AchievementDiaryAttributeKeys.FLETCHED_UNSTRUNG_MAGIC_SHORTBOW, false)
) {
player.achievementDiaryManager.finishTask(player, DiaryType.SEERS_VILLAGE, 2, 2)
}
}
}

View file

@ -0,0 +1,66 @@
package content.global.skill.fletching.stringing
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
/**
* Provides information pertaining to crafting different strung items
* @property isCrossbow is this enum for a crossbow?
* @property unstrungItemId the unstrung item Id
* @property strungItemId the resulting strung item Id
* @property level the level required to string the item
* @property experience experience gained from stringing
* @property animation the stringing animation to play
*/
enum class StringableCraftInfo(
val isCrossbow: Boolean,
val unstrungItemId: Int,
val strungItemId: Int,
val level: Int,
val experience: Double,
val animation: Animation
) {
SHORT_BOW(false, Items.SHORTBOW_U_50, Items.SHORTBOW_841, 5, 5.0, Animation(6678)),
LONG_BOW(false, Items.LONGBOW_U_48, Items.LONGBOW_839, 10, 10.0, Animation(6684)),
OAK_SHORTBOW(false, Items.OAK_SHORTBOW_U_54, Items.OAK_SHORTBOW_843, 20, 16.5, Animation(6679)),
OAK_LONGBOW(false, Items.OAK_LONGBOW_U_56, Items.OAK_LONGBOW_845, 25, 25.0, Animation(6685)),
OGRE_COMP_BOW(false, Items.UNSTRUNG_COMP_BOW_4825, Items.COMP_OGRE_BOW_4827, 30, 45.0, Animation(-1)),
WILLOW_SHORTBOW(false, Items.WILLOW_SHORTBOW_U_60, Items.WILLOW_SHORTBOW_849, 35, 33.3, Animation(6680)),
WILLOW_LONGBOW(false, Items.WILLOW_LONGBOW_U_58, Items.WILLOW_LONGBOW_847, 40, 41.5, Animation(6686)),
MAPLE_SHORTBOW(false, Items.MAPLE_SHORTBOW_U_64, Items.MAPLE_SHORTBOW_853, 50, 50.0, Animation(6681)),
MAPLE_LONGBOW(false, Items.MAPLE_LONGBOW_U_62, Items.MAPLE_LONGBOW_851, 55, 58.3, Animation(6687)),
YEW_SHORTBOW(false, Items.YEW_SHORTBOW_U_68, Items.YEW_SHORTBOW_857, 65, 67.5, Animation(6682)),
YEW_LONGBOW(false, Items.YEW_LONGBOW_U_66, Items.YEW_LONGBOW_855, 70, 75.0, Animation(6688)),
MAGIC_SHORTBOW(false, Items.MAGIC_SHORTBOW_U_72, Items.MAGIC_SHORTBOW_861, 80, 83.3, Animation(6683)),
MAGIC_LONGBOW(false, Items.MAGIC_LONGBOW_U_70, Items.MAGIC_LONGBOW_859, 85, 91.5, Animation(6689)),
BRONZE_CBOW(true, Items.BRONZE_CBOW_U_9454, Items.BRONZE_CROSSBOW_9174, 9, 6.0, Animation(6671)),
BLURITE_CBOW(true, Items.BLURITE_CBOW_U_9456, Items.BLURITE_CROSSBOW_9176, 24, 16.0, Animation(6672)),
IRON_CBOW(true, Items.IRON_CBOW_U_9457, Items.IRON_CROSSBOW_9177, 39, 22.0, Animation(6673)),
STEEL_CBOW(true, Items.STEEL_CBOW_U_9459, Items.STEEL_CROSSBOW_9179, 46, 27.0, Animation(6674)),
MITHIRIL_CBOW(true, Items.MITHRIL_CBOW_U_9461, Items.MITH_CROSSBOW_9181, 54, 32.0, Animation(6675)),
ADAMANT_CBOW(true, Items.ADAMANT_CBOW_U_9463, Items.ADAMANT_CROSSBOW_9183, 61, 41.0, Animation(6676)),
RUNITE_CBOW(true, Items.RUNITE_CBOW_U_9465, Items.RUNE_CROSSBOW_9185, 69, 50.0, Animation(6677));
companion object {
val unstrungBowIds: IntArray = values().map { stringableCraftInfo: StringableCraftInfo -> stringableCraftInfo.unstrungItemId }.toIntArray()
val stringItemIds: IntArray = intArrayOf(Items.BOW_STRING_1777,Items.CROSSBOW_STRING_9438)
private val stringableCraftInfoByUnstrungItemId = values().associateBy { it.unstrungItemId }
fun forUnstrungBowItemId(unstrungItemId: Int): StringableCraftInfo? {
return stringableCraftInfoByUnstrungItemId[unstrungItemId]
}
/**
* Returns the item id that should be used for stringing this enums unstrung bow
*/
val StringableCraftInfo.applicableStringId: Int
get() {
return when {
this.isCrossbow -> Items.CROSSBOW_STRING_9438
else -> Items.BOW_STRING_1777
}
}
}
}

View file

@ -0,0 +1,69 @@
package content.global.skill.fletching.stringing
import content.data.Quests
import content.global.skill.fletching.stringing.StringableCraftInfo.Companion.applicableStringId
import core.api.*
import core.game.dialogue.SkillDialogueHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.net.packet.PacketRepository
import core.net.packet.context.ChildPositionContext
import core.net.packet.out.RepositionChild
import org.rs09.consts.Components
@Suppress("unused") // Reflectively loaded
class StringingListeners : InteractionListener {
override fun defineListeners() {
onUseWith(
IntType.ITEM,
StringableCraftInfo.stringItemIds,
*StringableCraftInfo.unstrungBowIds
) { player, string, unstrungBow ->
val stringableCraftInfo = StringableCraftInfo.forUnstrungBowItemId(unstrungBow.id) ?: return@onUseWith false
if (string.id != stringableCraftInfo.applicableStringId) {
sendMessage(player, "That's not the right kind of string for this.")
return@onUseWith true
}
if (stringableCraftInfo == StringableCraftInfo.OGRE_COMP_BOW && getQuestStage(player, Quests.ZOGRE_FLESH_EATERS) < 8) {
sendMessage(player, "You must have started Zogre Flesh Eaters and asked Grish to string this.")
return@onUseWith true
}
val handler: SkillDialogueHandler =
object :
SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, Item(stringableCraftInfo.strungItemId)) {
override fun create(amount: Int, index: Int) {
if (getDynLevel(player, Skills.FLETCHING) < stringableCraftInfo.level) {
sendLevelCheckFailDialogue(player, stringableCraftInfo.level)
return
}
StringItemScript(player, stringableCraftInfo, amount).invoke()
}
override fun getAll(index: Int): Int {
return amountInInventory(player, string.id)
}
}
handler.open()
fixSpacingBetweenTextAndCraftedItemIcon(player)
return@onUseWith true
}
}
private fun fixSpacingBetweenTextAndCraftedItemIcon(player: Player) {
PacketRepository.send(
RepositionChild::class.java,
ChildPositionContext(player, Components.SKILL_MULTI1_309, 2, 215, 10)
)
}
companion object {
fun sendLevelCheckFailDialogue(player: Player, level: Int) {
sendDialogue(
player,
"You need a fletching level of $level to string this bow."
)
}
}
}

View file

@ -61,8 +61,7 @@ class GrindItemPlugin : UseWithHandler(233) {
override fun reward(): Boolean {
if (node.id == Items.FISHING_BAIT_313) {
var quantity = 0
quantity = if (amountInInventory(player, FISHING_BAIT) >= 10) {
val quantity: Int = if (amountInInventory(player, FISHING_BAIT) >= 10) {
10
} else {
amountInInventory(player, FISHING_BAIT)

View file

@ -1,14 +1,14 @@
package content.global.skill.magic
import core.api.hasLineOfSight
import core.api.log
import core.game.event.SpellCastEvent
import core.api.*
import core.game.interaction.MovementPulse
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.SpellBookManager
import core.tools.Log
import core.tools.SystemLogger
import core.game.interaction.*
import core.game.world.map.path.Pathfinder
import core.tools.Log
object SpellListeners {
val castMap = HashMap<String,(Player, Node?) -> Unit>()
@ -44,7 +44,7 @@ object SpellListeners {
range = next.first
method = next.second ?: return
}
player.scripts.removeWeakScripts()
if (type in intArrayOf (SpellListener.NPC, SpellListener.OBJECT, SpellListener.PLAYER, SpellListener.GROUND_ITEM)) {
player.pulseManager.run (object : MovementPulse (player, node, Pathfinder.SMART) {
override fun pulse() : Boolean {

View file

@ -6,6 +6,7 @@ import content.data.consumables.*
import content.data.skill.SkillingTool
import content.global.handlers.iface.ge.StockMarket
import content.global.skill.slayer.SlayerEquipmentFlags
import content.global.skill.slayer.SlayerFlags
import content.global.skill.slayer.SlayerManager
import content.global.skill.slayer.Tasks
import content.global.skill.summoning.familiar.BurdenBeast
@ -343,6 +344,24 @@ fun <T> removeItem(player: Player, item: T, container: Container = Container.INV
}
}
/**
* Remove items in a players inventory
* Checks that the player has enough first
* @param player
* @param items the items to remove
*/
fun removeItemsIfPlayerHasEnough(player: Player, vararg items: Item): Boolean {
for (item in items) {
if (amountInInventory(player, item.id) >= 1) continue
return false
}
for (item in items) {
if (removeItem(player, item)) continue
return false
}
return true
}
/**
* Add an item to the given player's given container
* @param player the player whose container to modify
@ -1948,12 +1967,16 @@ fun setQuestStage(player: Player, quest: Quests, stage: Int) {
}
/**
* Check if a quest is in progress
* Check if a quests' stage for a given player is (inclusively) between the provided start and end stage
*/
fun isQuestInProgress(player: Player, quest: Quests, startStage: Int, endStage: Int): Boolean {
return player.questRepository.getStage(quest) in startStage..endStage
}
fun isQuestStarted(player: Player, quest: Quests): Boolean {
return getQuestStage(player, quest) > 0
}
/**
* Check if a quest is complete
*/
@ -2454,7 +2477,11 @@ fun getSlayerTip(player: Player): Array<out String> {
* @return the task flags as Int.
*/
fun getSlayerTaskFlags(player: Player): Int {
return SlayerManager.getInstance(player).flags.taskFlags
return getSlayerFlags(player).taskFlags
}
fun getSlayerFlags(player: Player): SlayerFlags {
return SlayerManager.getInstance(player).flags
}
/**
@ -2982,10 +3009,14 @@ fun queueScript(entity: Entity, delay: Int = 1, strength: QueueStrength = QueueS
* @param entity the entity whose clock we are updating
* @param clock the clock we are updating. Please use [core.game.interaction.Clocks] for this argument.
* @param ticks the number of ticks to delay by
* @param delayScript whether to delay the script by the number of ticks passed in.
* @return always returns false so this can be used as a script return value.
**/
fun delayClock(entity: Entity, clock: Int, ticks: Int) : Boolean {
fun delayClock(entity: Entity, clock: Int, ticks: Int, delayScript: Boolean = false) : Boolean {
entity.clocks[clock] = getWorldTicks() + ticks
if (delayScript) {
return delayScript(entity, ticks)
}
return false
}

View file

@ -19,25 +19,11 @@ open class SkillDialogueHandler(
/**
* Represents the skill dialogue type.
*/
val type: SkillDialogue?, vararg data: Any) {
val type: SkillDialogue?,
/**
* Gets the player.
* @return The player.
* The items that can be created through this dialog.
*/
/**
* Gets the type.
* @return The type.
*/
/**
* Gets the passed data.
* @return the data.
*/
/**
* Represents the object data passed through.
*/
val data: Array<Any>
vararg val items: Item) {
/**
* Method used to open a skill dialogue.
@ -70,7 +56,7 @@ open class SkillDialogueHandler(
* @return the amount.
*/
open fun getAll(index: Int): Int {
return player.inventory.getAmount(data[0] as Item)
return player.inventory.getAmount(items[0])
}
/**
@ -107,7 +93,7 @@ open class SkillDialogueHandler(
private val length: Int) {
ONE_OPTION(309, 5, 1) {
override fun display(player: Player, handler: SkillDialogueHandler) {
val item = handler.data[0] as Item
val item = handler.items[0]
player.packetDispatch.sendString("<br><br><br><br>" + item.name, 309, 6)
player.packetDispatch.sendItemZoomOnInterface(item.id, 160, 309, 2)
PacketRepository.send(RepositionChild::class.java, ChildPositionContext(player, 309, 6, 60, 20))
@ -125,7 +111,7 @@ open class SkillDialogueHandler(
},
MAKE_SET_ONE_OPTION(582, 4, 1) {
override fun display(player: Player, handler: SkillDialogueHandler) {
val item = handler.data[0] as Item
val item = handler.items[0]
// Send item + item name to interface
player.packetDispatch.sendItemZoomOnInterface(item.id, 160, 582, 2)
@ -163,8 +149,8 @@ open class SkillDialogueHandler(
override fun display(player: Player, handler: SkillDialogueHandler) {
var item: Item
player.interfaceManager.openChatbox(306)
for (i in handler.data.indices) {
item = handler.data[i] as Item
for (i in handler.items.indices) {
item = handler.items[i]
player.packetDispatch.sendString("<br><br><br><br>" + handler.getName(item), 303, 7 + i)
player.packetDispatch.sendItemZoomOnInterface(item.id, 160, 303, 2 + i)
}
@ -190,11 +176,11 @@ open class SkillDialogueHandler(
},
THREE_OPTION(304, 8, 3) {
override fun display(player: Player, handler: SkillDialogueHandler) {
var item: Item? = null
var item: Item?
for (i in 0..2) {
item = handler.data[i] as Item
item = handler.items[i]
player.packetDispatch.sendItemZoomOnInterface(item.id, 135, 304, 2 + i)
player.packetDispatch.sendString("<br><br><br><br>" + item!!.name, 304, 304 - 296 + i * 4)
player.packetDispatch.sendString("<br><br><br><br>" + item.name, 304, 304 - 296 + i * 4)
}
}
@ -219,10 +205,10 @@ open class SkillDialogueHandler(
},
FOUR_OPTION(305, 9, 4) {
override fun display(player: Player, handler: SkillDialogueHandler) {
var item: Item? = null
var item: Item?
for (i in 0..3) {
item = handler.data[i] as Item
player.packetDispatch.sendItemZoomOnInterface(item!!.id, 135, 305, 2 + i)
item = handler.items[i]
player.packetDispatch.sendItemZoomOnInterface(item.id, 135, 305, 2 + i)
player.packetDispatch.sendString("<br><br><br><br>" + item.name, 305, 305 - 296 + i * 4)
}
}
@ -255,8 +241,8 @@ open class SkillDialogueHandler(
override fun display(player: Player, handler: SkillDialogueHandler) {
var item: Item
player.interfaceManager.openChatbox(306)
for (i in handler.data.indices) {
item = handler.data[i] as Item
for (i in handler.items.indices) {
item = handler.items[i]
player.packetDispatch.sendString("<br><br><br><br>" + handler.getName(item), 306, 10 + 4 * i)
player.packetDispatch.sendItemZoomOnInterface(item.id, 160, 306, 2 + i)
PacketRepository.send(RepositionChild::class.java, ChildPositionContext(player, 306, 2 + i, positions[i][0], positions[i][1]))
@ -361,14 +347,4 @@ open class SkillDialogueHandler(
*/
const val SKILL_DIALOGUE = 3 shl 16
}
/**
* Constructs a new `SkillDialogueHandler` `Object`.
* @param player the player.
* @param type the type.
* @param data the data.
*/
init {
this.data = data as Array<Any>
}
}

View file

@ -164,6 +164,7 @@ object InteractionListeners {
@JvmStatic
fun run(id: Int, player: Player, node: Node, isEquip: Boolean): Boolean{
player.scripts.removeWeakScripts()
player.dispatch(InteractionEvent(node, if(isEquip) "equip" else "unequip"))
if(isEquip){
return equipListeners["equip:$id"]?.invoke(player,node) ?: true
@ -174,6 +175,7 @@ object InteractionListeners {
@JvmStatic
fun run(used: Node, with: Node, type: IntType, player: Player): Boolean{
player.scripts.removeWeakScripts()
val flag = when(type){
IntType.NPC, IntType.PLAYER -> DestinationFlag.ENTITY
IntType.SCENERY -> DestinationFlag.OBJECT
@ -224,6 +226,8 @@ object InteractionListeners {
@JvmStatic
fun run(id: Int, type: IntType, option: String, player: Player, node: Node): Boolean{
player.scripts.removeWeakScripts()
val flag = when(type){
IntType.PLAYER -> DestinationFlag.ENTITY
IntType.GROUNDITEM -> DestinationFlag.ITEM

View file

@ -1,6 +1,7 @@
package core.game.interaction
import core.api.*
import core.game.bots.AIPlayer
import core.game.node.Node
import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
@ -10,10 +11,10 @@ import core.game.node.scenery.Scenery
import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.map.path.Pathfinder
import core.game.bots.AIPlayer
import core.tools.Log
import java.io.PrintWriter
import java.io.StringWriter
import java.lang.Integer.max
import java.io.*
class ScriptProcessor(val entity: Entity) {
private var apScript: Script<*>? = null
@ -90,11 +91,8 @@ class ScriptProcessor(val entity: Entity) {
}
fun processQueue() : Boolean {
var strongInQueue = false
var softInQueue = false
var anyExecuted = false
strongInQueue = hasTypeInQueue(QueueStrength.STRONG)
softInQueue = hasTypeInQueue(QueueStrength.SOFT)
val strongInQueue = hasTypeInQueue(QueueStrength.STRONG)
if (strongInQueue) {
if (entity is Player) {

View file

@ -78,7 +78,7 @@ public abstract class Entity extends Node {
/**
* The pulse manager.
*/
private final PulseManager pulseManager = new PulseManager();
private final PulseManager pulseManager = new PulseManager(this);
/**
* The impact handler.

View file

@ -17,6 +17,12 @@ import java.util.HashMap;
*/
public final class PulseManager {
private final Entity entity;
public PulseManager(Entity entity) {
this.entity = entity;
}
/**
* The movement pulse.
*/
@ -61,6 +67,9 @@ public final class PulseManager {
}
public void clear() {
entity.scripts.removeWeakScripts();
entity.scripts.removeNormalScripts();
currentPulses.forEach((type, pulse) -> {
if (type != PulseType.STRONG && pulse != null) pulse.stop();
});
@ -70,6 +79,9 @@ public final class PulseManager {
* Clears the pulses.
*/
public boolean clear(PulseType pulseType) {
entity.scripts.removeWeakScripts();
entity.scripts.removeNormalScripts();
Pulse pulse = currentPulses.get(pulseType);
if (pulse != null) {

View file

@ -1,5 +1,10 @@
package core.game.system.command.sets
import core.api.animate
import core.api.delayScript
import core.api.queueScript
import core.api.stopExecuting
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
@ -27,23 +32,26 @@ class AnimationCommandSet : CommandSet(Privilege.ADMIN) {
player.animate(animation)
}
/**
* Force the player to play animation <Animation ID>
*/
define("anims", Privilege.ADMIN, "::anim <lt>Animation ID<gt>", "Plays the animation with the given ID."){ player, args ->
define("anims", Privilege.ADMIN, "::anims <From Animation ID> <To Animation ID> <(opt) Duration Per Animation>", "Plays animations from the From ID to the To ID, with a delay of 3 between animations, unless specified otherwise"){ player, args ->
if (args.size < 3) {
reject(player, "Syntax error: ::anim <Animation ID>")
reject(player, "Syntax error: ::anims <From Animation ID> <To Animation ID> <(opt) Duration Per Animation>")
}
val animation = args[1].toInt()
val animationFrom = args[1].toInt()
val animationTo = args[2].toInt()
GameWorld.Pulser.submit(object : Pulse(3, player) {
var someId = animation
override fun pulse(): Boolean {
player.animate(Animation.create(someId))
someId += 1
return someId >= animationTo
val animationDelay = (args.getOrNull(3) ?: "3").toInt()
queueScript(player, 1, QueueStrength.STRONG) { stage: Int ->
val animationId = animationFrom + stage
animate(player, animationId, true)
notify(player, "Playing animation $animationId")
if (animationId == animationTo) {
return@queueScript stopExecuting(player)
}
return@queueScript delayScript(player, animationDelay)
}
})
}
/**