Exception fixes

Fixed a bug that could occasionally cause the sandwich lady interface to become unresponsive
Fixed an issue that could cause shade random events to not spawn for max-level players
Fixed an issue that could cause zombie random events to not spawn for max-level players
Fixed a widespread book issue that resulted from not resetting the current page index when closing a book, and then trying to open another book with less pages.
Converted bogrog pouch swap to the generic item select interface, and removed relevant code from the grand exchange code
Fixed an issue that could occasionally prevent exchange of item sets
Fixed an issue with Diango's reclaim interface that could result in items other than the ones you clicked being claimed
Made incubation moderately more reliable, and incubation timers now pass even while offline
Fixed an issue that prevented the leather crafting dialogue from accepting tokenized amounts (e.g. 100k)
Fixed an issue that prevented the tool leprechaun interface from allowing tokenized amounts
Fixed an issue that prevented players from using tokenized amounts in the ogleroot purchase dialogue for vinesweeper
Fixed an issue that prevented Zaff's batttlestaff dialogue from accepting tokenized amounts
Fixed an issue that prevented shop buy-x options from accepting tokenized amounts
Various shop-related exception fixes
Added some ingame player messages for when a Hunter "catch" option isn't being handled properly
Fixed some exceptions being thrown by lunar spells
Pyramid Plunder is now better at detecting when a player is in the minigame erroneously and kicking them out
Fixed an issue that would lead to incorrect Kalphite Queen behavior when killing her with multiple players in the room
Fixed an issue that could cause the Bedabin Nomad's dialogue to hang during Tourist Trap
Fixed several more issues with Fight Arena cutscenes
Fixed an issue that could prevent the dwarf dialogue from opening while trying to enter the mountain shortcut before finishing Fishing Contest
Fixed an issue that could cause dialogue option hangs in certain unusual circumstances
Fixed an issue that could result in non-movement for interactions where the override location was the same as the target node's location and there was no destination flag set
Fixed an issue where setting invalid node data could cause issues with NPC rendering
Server can now detect when a session is sending up multiple invalid packets and automatically disconnect the player
Fixed an issue that could lead to unintended saving of varps/varbits
Fixed an issue that could cause some interactions in shops to silently fail. The user will now receive a relevant message when these situations occur
Users may now find they could occasionally receive a very snarky response when incorrectly using commands
Users now receive messages when they try to make use of unimplemented friends/clan/etc features.
Errors in string parsing will no longer result in "dead" inputs when attempting to add friends/update clan ranks/etc
Fixed an issue that could lead to loss of some alerts in the Discord integration. Discord integration will now detect problems and queue the failed messages to be resent later.
Added more safety checks to item-on-grounditem packet handling to prevent throwing exceptions
Exceptions in string parsing for command packets will now inform the user that something went wrong, and ask them to try again.
Improved drop table parsing and fixed incorrect drop tables
This commit is contained in:
Ceikry
2023-07-17 08:12:57 +00:00
committed by Ryan
parent 0372937353
commit 845d8b383b
61 changed files with 547 additions and 337 deletions
@@ -3,6 +3,7 @@ package content.global.ame.events.sandwichlady
import core.game.node.item.Item
import org.rs09.consts.Items
import core.game.interaction.InterfaceListener
import content.global.ame.RandomEventManager
class SandwichLadyInterface : InterfaceListener {
@@ -17,6 +18,11 @@ class SandwichLadyInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(SANDWICH_INTERFACE){player, _, _, buttonID, _, _ ->
val event = RandomEventManager.getInstance(player)!!.event
if (event == null) {
player.interfaceManager.close()
return@on true
}
val item =
when(buttonID) {
7 -> {Item(baguette)}
@@ -31,8 +37,8 @@ class SandwichLadyInterface : InterfaceListener {
player.setAttribute("sandwich-lady:choice",item.id)
player.interfaceManager.close()
player.dialogueInterpreter.open(SandwichLadyDialogue(true), content.global.ame.RandomEventManager.getInstance(player)!!.event)
player.dialogueInterpreter.open(SandwichLadyDialogue(true), event)
return@on true
}
}
}
}
@@ -4,16 +4,15 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable
val ids = 425..430
import kotlin.math.*
class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){
val ids = (425..430).toList()
override fun talkTo(npc: NPC) {}
override fun init() {
super.init()
val index = (player.properties.combatLevel / 20) - 1
val id = ids.toList()[index]
val index = max(0, min(ids.size, (player.properties.combatLevel / 20) - 1))
val id = ids[index]
this.transform(id)
this.attack(player)
sendChat("Leave this place!")
@@ -29,4 +28,4 @@ class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(4
super.tick()
if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
}
}
}
@@ -4,16 +4,15 @@ import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import content.global.ame.RandomEventNPC
import core.api.utils.WeightBasedTable
val ids = 419..424
import kotlin.math.*
class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(419){
val ids = (419..424).toList()
override fun talkTo(npc: NPC) {}
override fun init() {
super.init()
val index = (player.properties.combatLevel / 20) - 1
val id = ids.toList()[index]
val index = max(0, min(ids.size, (player.properties.combatLevel / 20) - 1))
val id = ids[index]
this.transform(id)
this.attack(player)
sendChat("Brainsssss!")
@@ -29,4 +28,4 @@ class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(
super.tick()
if(!player.viewport.currentPlane.npcs.contains(this)) this.clear()
}
}
}
@@ -190,4 +190,4 @@ class Page(vararg lines: BookLine) {
class BookLine(
val message: String,
val child: Int
)
)
@@ -30,6 +30,7 @@ class GenericItemSelect : InterfaceListener {
onClose(GENERIC_ITEM_SELECT_IFACE) {player, _ ->
removeAttribute(player, "itemselect-callback")
removeAttribute(player, "itemselect-keepalive")
return@onClose true
}
}
@@ -56,7 +57,11 @@ class GenericItemSelect : InterfaceListener {
}
callback.invoke(slot, optionIndex)
removeAttribute (player, "itemselect-callback")
player.interfaceManager.closeSingleTab()
if (!getAttribute(player, "itemselect-keepalive", false)) {
removeAttribute (player, "itemselect-callback")
removeAttribute (player, "itemselect-keepalive")
player.interfaceManager.closeSingleTab()
}
}
}
@@ -18,7 +18,6 @@ import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.ge.GrandExchangeOffer;
import core.game.ge.GrandExchangeRecords;
import content.region.kandarin.feldip.gutanoth.handlers.BogrogPouchSwapper;
import core.game.world.GameWorld;
/**
@@ -132,12 +131,20 @@ public class GrandExchangeInterface extends ComponentPlugin {
if (slot < 0 || slot >= (inventory ? 28 : GEItemSet.values().length)) {
return;
}
GEItemSet set = GEItemSet.values()[slot];
Item item = inventory ? player.getInventory().get(slot) : new Item(set.getItemId());
if (item == null) {
return;
}
if (opcode != 127 && inventory && ((set = GEItemSet.forId(item.getId())) == null) && !BogrogPouchSwapper.handle(player,opcode,slot,itemId)) {
Item item;
GEItemSet set;
if (inventory) {
item = player.getInventory().get(slot);
if (item == null) return;
set = GEItemSet.forId(item.getId());
if (set == null) return;
} else {
set = GEItemSet.values()[slot];
item = new Item(set.getItemId());
}
if (opcode != 127 && inventory && set == null) {
player.getPacketDispatch().sendMessage("This isn't a set item.");
return;
}
@@ -159,15 +159,11 @@ class StockMarket : InterfaceListener {
183 -> updateOfferValue(player, tempOffer, (GrandExchange.getRecommendedPrice(tempOffer.itemID) * 1.05).toInt())
171 -> updateOfferValue(player, tempOffer, tempOffer.offeredValue - 1)
173 -> updateOfferValue(player, tempOffer, tempOffer.offeredValue + 1)
185 -> sendInputDialogue(player, false, "Enter the amount:"){value ->
185 -> sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:"){value ->
if (player.interfaceManager.chatbox.id == 389) {
player.interfaceManager.openChatbox(Components.OBJDIALOG_389)
}
var s = value.toString()
s = s.replace("k", "000")
s = s.replace("K", "000")
s = s.replace("m", "000000")
s = s.replace("M", "000000")
updateOfferValue(player, tempOffer, s.toInt())
setAttribute(player, "ge-temp", tempOffer)
}
@@ -43,14 +43,10 @@ public class DiangoReclaimInterface extends ComponentPlugin {
if(curOpen != null){
curOpen.close(player);
}
Item[] reclaimables = getEligibleItems(player);
player.setAttribute("diango-reclaimables", reclaimables);
//filter out items the player already has in their bank, inventory, or equipped
Item[] reclaimables = ITEMS.stream().filter(Objects::nonNull)
.filter(item -> !player.getEquipment().containsItem(item) && !player.getInventory().containsItem(item) && !player.getBank().containsItem(item)
&& (item.getId() != 14654
|| (!(inInventory(player, 14655, 1) || inEquipment(player, 14656, 1)) && player.getAttribute("sotr:purchased",false))
))
.toArray(Item[]::new);
//only send items if there are some to send
if(reclaimables.length > 0) {
@@ -68,18 +64,36 @@ public class DiangoReclaimInterface extends ComponentPlugin {
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
Item[] reclaimables = ITEMS.stream().filter(Objects::nonNull).filter(item -> !player.getEquipment().containsItem(item) && !player.getInventory().containsItem(item) && !player.getBank().containsItem(item)).toArray(Item[]::new);
Item[] reclaimables = player.getAttribute("diango-reclaimables", null);
if (reclaimables == null)
reclaimables = getEligibleItems(player);
Item reclaimItem = reclaimables[slot];
if (reclaimItem == null) {
player.sendMessage("Something went wrong there. Please try again.");
return true;
}
switch(opcode){
case 155: //interface item option 1 == take
//add the clicked item to the player's inventory and refresh the interface
player.getInventory().add(reclaimables[slot]);
player.getInventory().add(reclaimItem);
refresh(player);
break;
case 196: //interface item option 2 == examine
//send the examine text for the item to the player
player.getPacketDispatch().sendMessage(reclaimables[slot].getDefinition().getExamine());
player.getPacketDispatch().sendMessage(reclaimItem.getDefinition().getExamine());
break;
}
return false;
}
public static Item[] getEligibleItems (Player player) {
return ITEMS.stream().filter(Objects::nonNull)
.filter(item -> !player.getEquipment().containsItem(item) && !player.getInventory().containsItem(item) && !player.getBank().containsItem(item)
&& (item.getId() != 14654
|| (!(inInventory(player, 14655, 1) || inEquipment(player, 14656, 1)) && player.getAttribute("sotr:purchased",false))
))
.toArray(Item[]::new);
}
}
@@ -34,7 +34,9 @@ public class IncubatorPlugin extends OptionHandler {
@Override
public boolean handle(Player player, Node node, String option) {
int inc = player.getAttribute("inc", -1);
int inc = player.getAttribute(IncubatorState.ATTR_INCUBATOR_PRODUCT, -1);
if (inc == -1)
inc = player.getAttribute("inc", -1); //deprecated, only here to avoid data loss
switch (option) {
case "take-egg":
if (inc == -1) {
@@ -54,6 +56,8 @@ public class IncubatorPlugin extends OptionHandler {
GroundItemManager.create(egg.getProduct(),player);
}
player.removeAttribute("inc");
player.removeAttribute(IncubatorState.ATTR_INCUBATOR_PRODUCT);
player.clearState("incubator");
}
return true;
case "inspect":
@@ -66,8 +66,8 @@ public final class BuildOptionPlugin extends OptionHandler {
}
Hotspot hotspot = player.getHouseManager().getHotspot(object);
if (hotspot == null || !isBuildable(player, object, hotspot)) {
log(this.getClass(), Log.ERR, "Construction (building): " + hotspot + " : " + object + " chunkX = " + object.getLocation().getChunkX() + ", chunkY = " + object.getLocation().getChunkY());
//log demoted from ERR to WARN June 16, 2023 -> It's the effect of an already-known issue. Reduced visibility to clean up server logs while still making the issue apparent in dev environs
log(this.getClass(), Log.WARN, "Construction (building): " + hotspot + " : " + object + " chunkX = " + object.getLocation().getChunkX() + ", chunkY = " + object.getLocation().getChunkY());
return true;
}
@@ -181,4 +181,4 @@ public final class BuildOptionPlugin extends OptionHandler {
}
}
}
@@ -1,6 +1,7 @@
package content.global.skill.crafting;
import static core.api.ContentAPIKt.*;
import core.api.InputType;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.dialogue.DialoguePlugin;
@@ -204,7 +205,7 @@ public final class LeatherCraftDialogue extends DialoguePlugin {
if (hidee == null) {
return false;
}
sendInputDialogue(player, true, "Enter the amount:", (value) -> {
sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:", (value) -> {
player.getPulseManager().run(new DragonCraftPulse(player, null, hidee, (int) value));
return Unit.INSTANCE;
});
@@ -181,7 +181,7 @@ class ToolLeprechaunInterface : InterfaceListener {
player.dialogueInterpreter.sendDialogue("You don't have any of those stored.")
} else {
if(amount == -2){
sendInputDialogue(player, true, "Enter the amount:"){value ->
sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:"){value ->
var amt = value as Int
if(amt > hasAmount){
amt = hasAmount
@@ -303,7 +303,13 @@ public final class HunterPlugin extends OptionHandler {
@Override
public boolean handle(Player player, Node node, String option) {
BNetTypes.forNpc((NPC) node).handle(player, (NPC) node);
BNetTypes type = BNetTypes.forNpc((NPC) node);
if (type == null) {
player.sendMessage("There seems to be something wrong with this catch option.");
player.sendMessage("Please submit a detailed bug report on gitlab.");
return true;
}
type.handle(player, (NPC) node);
return true;
}
@@ -387,6 +387,8 @@ class LunarListeners : SpellListener("lunar"), Commands {
var counter = 0
override fun pulse(): Boolean {
removeAttribute(player, "spell:runes")
if (playerJewellery.isEmpty())
return true
requires(player, 80, arrayOf(Item(Items.ASTRAL_RUNE_9075, 2), Item(Items.EARTH_RUNE_557, 10), Item(Items.WATER_RUNE_555, 5)))
if(counter == 0) delay = animationDuration(STRING_JEWELLERY_ANIM) + 1
val item = playerJewellery[0]
@@ -41,10 +41,17 @@ public class StatRestoreSpell extends MagicSpell {
public boolean cast(Entity entity, Node target) {
final Player player = ((Player) entity);
Item item = ((Item) target);
final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable();
player.getInterfaceManager().setViewedTab(6);
if (Consumables.getConsumableById(item.getId()) == null) {
player.getPacketDispatch().sendMessage("You can only cast this spell on a potion.");
return false;
}
final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable();
if (potion == null) {
player.getPacketDispatch().sendMessage("You can only cast this spell on a potion.");
player.getPacketDispatch().sendMessage("You can only cast this spell on a potion.");
return false;
}
if (!item.getDefinition().isTradeable() || !isRestore(potion)) {
@@ -6,22 +6,27 @@ import core.game.node.entity.state.State
import core.game.system.task.Pulse
import org.json.simple.JSONObject
import core.api.*
import core.tools.*
@PlayerState("incubator")
class IncubatorState(player: Player? = null) : State(player) {
var egg: IncubatorEgg? = null
var ticksLeft = 0
var completionTimeMs = 0L
fun setTicksLeft (ticks: Int) {
completionTimeMs = System.currentTimeMillis() + (ticksToSeconds(ticks) * 1000)
}
override fun newInstance(player: Player?): State {
return IncubatorState(player)
}
override fun save(root: JSONObject) {
if(ticksLeft <= 0) return
if(pulse == null) return
val data = JSONObject()
data.put("eggOrdinal",(egg?.ordinal ?: 0).toString())
data.put("ticksLeft",ticksLeft.toString())
data.put("endTime", completionTimeMs.toString())
root.put("eggdata",data)
}
@@ -29,7 +34,11 @@ class IncubatorState(player: Player? = null) : State(player) {
if(_data.containsKey("eggdata")){
val data = _data["eggdata"] as JSONObject
egg = IncubatorEgg.values()[data["eggOrdinal"].toString().toInt()]
ticksLeft = data["ticksLeft"].toString().toInt()
if (data.containsKey("ticksLeft"))
completionTimeMs = System.currentTimeMillis() + ticksToSeconds(data["ticksLeft"].toString().toInt() * 1000)
else
completionTimeMs = data["endTime"].toString().toLong()
}
}
@@ -39,8 +48,8 @@ class IncubatorState(player: Player? = null) : State(player) {
setVarbit(player, 4277, 1)
pulse = object : Pulse(){
override fun pulse(): Boolean {
if(ticksLeft-- <= 0){
player.setAttribute("/save:inc", egg!!.ordinal)
if(System.currentTimeMillis() >= completionTimeMs){
player.setAttribute(ATTR_INCUBATOR_PRODUCT, egg!!.ordinal)
player.sendMessage("Your " + egg!!.product.name.toLowerCase() + " has finished hatching.")
pulse = null
return true
@@ -49,5 +58,8 @@ class IncubatorState(player: Player? = null) : State(player) {
}
}
}
companion object {
const val ATTR_INCUBATOR_PRODUCT = "/save:incubator:egg-product"
}
}
@@ -96,6 +96,8 @@ public final class TelekineticGrabSpell extends MagicSpell {
@Override
public boolean cast(final Entity entity, final Node target) {
if (!(target instanceof GroundItem))
return false;
final GroundItem ground = (GroundItem) target;
if (!canCast(entity, ground)) {
return false;
@@ -171,6 +171,8 @@ object PlunderUtils {
fun getDoor(player: Player) : Int
{
if (getRoom(player) == null)
return -1;
val room = getRoom(player)!!.room
return PlunderData.doors[room - 1]
}
@@ -219,6 +221,10 @@ object PlunderUtils {
fun getChestXp(player: Player): Double
{
if (getRoom(player) == null) {
expel(player, false)
return 0.0
}
val room = getRoom(player)!!.room
return when(room)
{
@@ -188,6 +188,10 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
}
on(SARCOPHAGUS, IntType.SCENERY, "open") { player, node ->
if (PlunderUtils.getRoom(player) == null) {
PlunderUtils.expel(player, false)
return@on true
}
sendMessage(player, "You attempt to push open the massive lid.")
val strength = getDynLevel(player, Skills.STRENGTH)
animate(player, PUSH_LID_START)
@@ -198,6 +202,10 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
if(RandomFunction.random(125) > strength)
return false
animate(player, PUSH_LID_FINISH)
if (PlunderUtils.getRoom(player) == null) {
PlunderUtils.expel(player, false)
return true
}
runTask(player, 3){
setVarbit(player, node.asScenery().definition.varbitID, 1)
rewardXP(player, Skills.STRENGTH, PlunderUtils.getSarcophagusXp(player))
@@ -220,6 +228,10 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
}
on(Scenery.GRAND_GOLD_CHEST_16473, IntType.SCENERY, "search") { player, node ->
if (PlunderUtils.getRoom(player) == null) {
PlunderUtils.expel(player, false)
return@on true
}
animate(player, OPEN_CHEST_ANIM)
runTask(player){
if(RandomFunction.roll(25))
@@ -268,8 +280,14 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
if(RandomFunction.roll(rate))
{
val varbitId = node.asScenery().definition.varbitID
rewardXP(player, Skills.THIEVING, PlunderUtils.getDoorXp(player, rate == 3))
if(PlunderUtils.getDoor(player) == varbitId) {
val door = PlunderUtils.getDoor(player)
if (door == -1)
PlunderUtils.expel(player, false)
else
rewardXP(player, Skills.THIEVING, PlunderUtils.getDoorXp(player, rate == 3))
if (door == varbitId) {
PlunderUtils.loadNextRoom(player)
PlunderUtils.resetObjectVarbits(player)
} else {
@@ -4,6 +4,7 @@ import core.game.node.item.Item
import org.rs09.consts.Items
import core.game.dialogue.DialogueFile
import core.tools.END_DIALOGUE
import core.api.*
abstract class FarmerDialogue : DialogueFile() {
@@ -129,10 +130,11 @@ class BlinkinDialogue : FarmerDialogue() {
40 -> playerl("Do you have any Ogleroots to feed the rabbits?").also { stage++ }
41 -> npcl("I sure do. They'll cost ya 10 gold each. Any ya leave with will be returned to us, but ya'll get yer money back for 'em. How many do ya want?").also { stage++ }
42 -> {
player!!.setAttribute("runscript") { amount: Int ->
sendInputDialogue(player!!, InputType.AMOUNT, "Enter an amount:") { value ->
val amount = value as Int
val price = Item(Items.COINS_995, 10 * amount)
if(price.amount <= 0){
return@setAttribute
return@sendInputDialogue
}
if(player!!.inventory.containsItem(price) && player!!.inventory.remove(price)) {
if(player!!.inventory.add(Item(Items.OGLEROOT_12624, amount))) {
@@ -315,7 +315,7 @@ public final class KalphiteQueenNPC extends AbstractNPC {
return;
}
if (style == CombatStyle.MAGIC) {
BattleState[] states = new BattleState[entity.getViewport().getCurrentPlane().getPlayers().size()];
BattleState[] states = new BattleState[entity.getViewport().getCurrentPlane().getPlayers().size() + 1];
int index = 1;
if (states.length == 0) {
return;
@@ -94,7 +94,8 @@ public final class BedabinNomadDialogue extends DialoguePlugin {
case 2:
end();
final Scenery door = RegionManager.getObject(new Location(3169, 3046, 0));
SceneryBuilder.replace(door, door.transform(2701), 2);
if (door.getId() != 2701)
SceneryBuilder.replace(door, door.transform(2701), 2);
player.getWalkingQueue().reset();
player.getWalkingQueue().addPath(3169, 3046);
player.getPacketDispatch().sendMessage("You walk into the tent.");
@@ -27,7 +27,7 @@ class EscapeCutscene(player: Player) : Cutscene(player) {
}
1 -> {
player.faceLocation(location(2616, 3167, 0))
player.faceLocation(location(56, 31, 0))
animate(player, 2098)
timedUpdate(4)
}
@@ -38,8 +38,8 @@ class EscapeCutscene(player: Player) : Cutscene(player) {
}
3 -> {
DoorActionHandler.handleAutowalkDoor(Jeremy, getScenery(2617, 3167, 0))
player.faceLocation(location(2617, 3164, 0))
DoorActionHandler.handleAutowalkDoor(Jeremy, getObject(57, 31, 0))
player.faceLocation(location(57, 28, 0))
timedUpdate(3)
}
@@ -67,7 +67,7 @@ class EscapeCutscene(player: Player) : Cutscene(player) {
moveCamera(47, 20)
rotateCamera(45, 15)
teleport(player, 47, 15)
Jeremy.teleport(Location.create(2616, 3167, 0))
Jeremy.teleport(location(56, 31, 0))
timedUpdate(2)
}
@@ -12,6 +12,9 @@ import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
import kotlin.Unit;
import static core.api.ContentAPIKt.*;
/**
* Handles the bogrog npc.
@@ -46,8 +49,10 @@ public final class BogrogPlugin extends OptionHandler {
player.sendMessage("You need a Summoning level of at least 21 in order to do that.");
return;
} else {
InterfaceContainer.generateItems(player,player.getInventory().toArray(),new String[] {"Swap X","Swap 10","Swap 5","Swap 1","Value"}, 644,0,7,4,200);
player.getInterfaceManager().openSingleTab(new Component(644));
sendItemSelect(player, new String[] { "Value", "Swap 1", "Swap 5", "Swap 10", "Swap X" }, true, (slot, index) -> {
BogrogPouchSwapper.handle(player, index, slot);
return Unit.INSTANCE;
});
}
}
@@ -17,11 +17,11 @@ import kotlin.math.floor
*/
object BogrogPouchSwapper {
//Opcodes for item options
private const val OP_VALUE = 155
private const val OP_SWAP_1 = 196
private const val OP_SWAP_5 = 124
private const val OP_SWAP_10 = 199
private const val OP_SWAP_X = 234
private const val OP_VALUE = 0
private const val OP_SWAP_1 = 1
private const val OP_SWAP_5 = 2
private const val OP_SWAP_10 = 3
private const val OP_SWAP_X = 4
private const val SPIRIT_SHARD = 12183
@@ -29,16 +29,16 @@ object BogrogPouchSwapper {
private val GEBorders = ZoneBorders(3151,3501,3175,3477)
@JvmStatic
fun handle(player: Player, opcode: Int, slot: Int, itemID: Int): Boolean{
if(GEBorders.insideBorder(player)) return false
return when(opcode){
OP_VALUE -> sendValue(player.inventory.get(slot).id,player)
OP_SWAP_1 -> swap(player, 1, player.inventory.get(slot).id)
OP_SWAP_5 -> swap(player, 5, player.inventory.get(slot).id)
OP_SWAP_10 -> swap(player,10,player.inventory.get(slot).id)
fun handle(player: Player, optionIndex: Int, slot: Int): Boolean{
val item = player.inventory.get(slot) ?: return false
return when(optionIndex){
OP_VALUE -> sendValue(item.id,player)
OP_SWAP_1 -> swap(player, 1, item.id)
OP_SWAP_5 -> swap(player, 5, item.id)
OP_SWAP_10 -> swap(player, 10, item.id)
OP_SWAP_X -> true.also{
sendInputDialogue(player, true, "Enter the amount:"){value ->
swap(player, value as Int, player.inventory.get(slot).id)
sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:"){value ->
swap(player, value as Int, item.id)
}
}
else -> false
@@ -56,7 +56,6 @@ object BogrogPouchSwapper {
amt = inInventory
player.inventory.remove(Item(itemID,amt))
player.inventory.add(Item(SPIRIT_SHARD, floor(value * amt).toInt()))
player.interfaceManager.close(Component(644))
return true
}
@@ -66,7 +65,7 @@ object BogrogPouchSwapper {
return false
}
player.sendMessage("Bogrog will give you $value shards for that.")
player.sendMessage("Bogrog will give you ${floor(value).toInt()} shards for that.")
return true
}
@@ -80,4 +79,4 @@ object BogrogPouchSwapper {
if(isScroll) shardQuantity /= 20.0
return shardQuantity
}
}
}
@@ -10,6 +10,7 @@ import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.interaction.PluginInteraction;
import core.game.interaction.PluginInteractionManager;
import core.game.world.repository.Repository;
@Initializable
public class StairInteraction extends PluginInteraction {
@@ -33,7 +34,12 @@ public class StairInteraction extends PluginInteraction {
player.getPulseManager().run(new MovementPulse(player,object.getLocation().transform(0,2,0)) {
@Override
public boolean pulse() {
player.getDialogueInterpreter().open(npc_id,new NPC(npc_id));
NPC n = Repository.findNPC(npc_id);
if (n == null) {
player.sendMessage("Are you in a world without NPCs? What did you do?");
return true;
}
player.getDialogueInterpreter().open(npc_id, n);
return true;
}
}, PulseType.STANDARD);
@@ -387,7 +387,7 @@ class ZaffPlugin : OptionHandler() {
)
stage = 1
}
1 -> end().also { sendInputDialogue(player, InputType.NUMERIC, "Enter an amount:"){ value ->
1 -> end().also { sendInputDialogue(player, InputType.AMOUNT, "Enter an amount:"){ value ->
ammount = getStoreFile().getInt(player.username.toLowerCase())
var amt = value as Int
if(amt > maxStaffs - ammount) amt = maxStaffs - ammount
@@ -163,6 +163,8 @@ public final class CorporealBeastNPC extends NPCBehavior {
GameWorld.getPulser().submit(new Pulse(2, corp) {
@Override
public boolean pulse() {
if (npc.darkEnergyCore == null)
return true;
npc.darkEnergyCore.init();
return true;
}