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:
@@ -2438,7 +2438,7 @@
|
|||||||
"minAmount": "75",
|
"minAmount": "75",
|
||||||
"weight": "1.0",
|
"weight": "1.0",
|
||||||
"id": "556",
|
"id": "556",
|
||||||
"maxAmount": "5"
|
"maxAmount": "75"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "10",
|
"minAmount": "10",
|
||||||
@@ -19681,10 +19681,10 @@
|
|||||||
"maxAmount": "1"
|
"maxAmount": "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "110",
|
"minAmount": "30",
|
||||||
"weight": "5.0",
|
"weight": "5.0",
|
||||||
"id": "313",
|
"id": "313",
|
||||||
"maxAmount": "30"
|
"maxAmount": "110"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "1",
|
"minAmount": "1",
|
||||||
@@ -19846,10 +19846,10 @@
|
|||||||
"maxAmount": "1"
|
"maxAmount": "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "110",
|
"minAmount": "30",
|
||||||
"weight": "5.0",
|
"weight": "5.0",
|
||||||
"id": "313",
|
"id": "313",
|
||||||
"maxAmount": "30"
|
"maxAmount": "110"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "1",
|
"minAmount": "1",
|
||||||
@@ -48483,10 +48483,10 @@
|
|||||||
"maxAmount": "2"
|
"maxAmount": "2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "3",
|
"minAmount": "1",
|
||||||
"weight": "500.0",
|
"weight": "500.0",
|
||||||
"id": "7054",
|
"id": "7054",
|
||||||
"maxAmount": "1"
|
"maxAmount": "3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"minAmount": "1",
|
"minAmount": "1",
|
||||||
|
|||||||
@@ -491,10 +491,6 @@
|
|||||||
"item_id": "2347",
|
"item_id": "2347",
|
||||||
"loc_data": "{1,2934,3286,0,7209050}-{1,2579,3463,0,5242920}-{1,2975,3368,1,5898270}-{1,1953,4974,0,5898270}"
|
"loc_data": "{1,2934,3286,0,7209050}-{1,2579,3463,0,5242920}-{1,2975,3368,1,5898270}-{1,1953,4974,0,5898270}"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"item_id": "2351",
|
|
||||||
"loc_data": "{1,3062,3657,0,11141270}"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"item_id": "2357",
|
"item_id": "2357",
|
||||||
"loc_data": "{1,3192,9822,0,11141270}"
|
"loc_data": "{1,3192,9822,0,11141270}"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package content.global.ame.events.sandwichlady
|
|||||||
import core.game.node.item.Item
|
import core.game.node.item.Item
|
||||||
import org.rs09.consts.Items
|
import org.rs09.consts.Items
|
||||||
import core.game.interaction.InterfaceListener
|
import core.game.interaction.InterfaceListener
|
||||||
|
import content.global.ame.RandomEventManager
|
||||||
|
|
||||||
class SandwichLadyInterface : InterfaceListener {
|
class SandwichLadyInterface : InterfaceListener {
|
||||||
|
|
||||||
@@ -17,6 +18,11 @@ class SandwichLadyInterface : InterfaceListener {
|
|||||||
|
|
||||||
override fun defineInterfaceListeners() {
|
override fun defineInterfaceListeners() {
|
||||||
on(SANDWICH_INTERFACE){player, _, _, buttonID, _, _ ->
|
on(SANDWICH_INTERFACE){player, _, _, buttonID, _, _ ->
|
||||||
|
val event = RandomEventManager.getInstance(player)!!.event
|
||||||
|
if (event == null) {
|
||||||
|
player.interfaceManager.close()
|
||||||
|
return@on true
|
||||||
|
}
|
||||||
val item =
|
val item =
|
||||||
when(buttonID) {
|
when(buttonID) {
|
||||||
7 -> {Item(baguette)}
|
7 -> {Item(baguette)}
|
||||||
@@ -31,7 +37,7 @@ class SandwichLadyInterface : InterfaceListener {
|
|||||||
|
|
||||||
player.setAttribute("sandwich-lady:choice",item.id)
|
player.setAttribute("sandwich-lady:choice",item.id)
|
||||||
player.interfaceManager.close()
|
player.interfaceManager.close()
|
||||||
player.dialogueInterpreter.open(SandwichLadyDialogue(true), content.global.ame.RandomEventManager.getInstance(player)!!.event)
|
player.dialogueInterpreter.open(SandwichLadyDialogue(true), event)
|
||||||
return@on true
|
return@on true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,15 @@ import core.game.node.entity.Entity
|
|||||||
import core.game.node.entity.npc.NPC
|
import core.game.node.entity.npc.NPC
|
||||||
import content.global.ame.RandomEventNPC
|
import content.global.ame.RandomEventNPC
|
||||||
import core.api.utils.WeightBasedTable
|
import core.api.utils.WeightBasedTable
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
val ids = 425..430
|
|
||||||
|
|
||||||
class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){
|
class ShadeRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(425){
|
||||||
|
val ids = (425..430).toList()
|
||||||
override fun talkTo(npc: NPC) {}
|
override fun talkTo(npc: NPC) {}
|
||||||
override fun init() {
|
override fun init() {
|
||||||
super.init()
|
super.init()
|
||||||
val index = (player.properties.combatLevel / 20) - 1
|
val index = max(0, min(ids.size, (player.properties.combatLevel / 20) - 1))
|
||||||
val id = ids.toList()[index]
|
val id = ids[index]
|
||||||
this.transform(id)
|
this.transform(id)
|
||||||
this.attack(player)
|
this.attack(player)
|
||||||
sendChat("Leave this place!")
|
sendChat("Leave this place!")
|
||||||
|
|||||||
@@ -4,16 +4,15 @@ import core.game.node.entity.Entity
|
|||||||
import core.game.node.entity.npc.NPC
|
import core.game.node.entity.npc.NPC
|
||||||
import content.global.ame.RandomEventNPC
|
import content.global.ame.RandomEventNPC
|
||||||
import core.api.utils.WeightBasedTable
|
import core.api.utils.WeightBasedTable
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
val ids = 419..424
|
|
||||||
|
|
||||||
class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(419){
|
class ZombieRENPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(419){
|
||||||
|
val ids = (419..424).toList()
|
||||||
override fun talkTo(npc: NPC) {}
|
override fun talkTo(npc: NPC) {}
|
||||||
override fun init() {
|
override fun init() {
|
||||||
super.init()
|
super.init()
|
||||||
val index = (player.properties.combatLevel / 20) - 1
|
val index = max(0, min(ids.size, (player.properties.combatLevel / 20) - 1))
|
||||||
val id = ids.toList()[index]
|
val id = ids[index]
|
||||||
this.transform(id)
|
this.transform(id)
|
||||||
this.attack(player)
|
this.attack(player)
|
||||||
sendChat("Brainsssss!")
|
sendChat("Brainsssss!")
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class GenericItemSelect : InterfaceListener {
|
|||||||
|
|
||||||
onClose(GENERIC_ITEM_SELECT_IFACE) {player, _ ->
|
onClose(GENERIC_ITEM_SELECT_IFACE) {player, _ ->
|
||||||
removeAttribute(player, "itemselect-callback")
|
removeAttribute(player, "itemselect-callback")
|
||||||
|
removeAttribute(player, "itemselect-keepalive")
|
||||||
return@onClose true
|
return@onClose true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +57,11 @@ class GenericItemSelect : InterfaceListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
callback.invoke(slot, optionIndex)
|
callback.invoke(slot, optionIndex)
|
||||||
|
|
||||||
|
if (!getAttribute(player, "itemselect-keepalive", false)) {
|
||||||
removeAttribute (player, "itemselect-callback")
|
removeAttribute (player, "itemselect-callback")
|
||||||
|
removeAttribute (player, "itemselect-keepalive")
|
||||||
player.interfaceManager.closeSingleTab()
|
player.interfaceManager.closeSingleTab()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import core.plugin.Initializable;
|
|||||||
import core.plugin.Plugin;
|
import core.plugin.Plugin;
|
||||||
import core.game.ge.GrandExchangeOffer;
|
import core.game.ge.GrandExchangeOffer;
|
||||||
import core.game.ge.GrandExchangeRecords;
|
import core.game.ge.GrandExchangeRecords;
|
||||||
import content.region.kandarin.feldip.gutanoth.handlers.BogrogPouchSwapper;
|
|
||||||
import core.game.world.GameWorld;
|
import core.game.world.GameWorld;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,12 +131,20 @@ public class GrandExchangeInterface extends ComponentPlugin {
|
|||||||
if (slot < 0 || slot >= (inventory ? 28 : GEItemSet.values().length)) {
|
if (slot < 0 || slot >= (inventory ? 28 : GEItemSet.values().length)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GEItemSet set = GEItemSet.values()[slot];
|
|
||||||
Item item = inventory ? player.getInventory().get(slot) : new Item(set.getItemId());
|
Item item;
|
||||||
if (item == null) {
|
GEItemSet set;
|
||||||
return;
|
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 = GEItemSet.forId(item.getId())) == null) && !BogrogPouchSwapper.handle(player,opcode,slot,itemId)) {
|
|
||||||
|
if (opcode != 127 && inventory && set == null) {
|
||||||
player.getPacketDispatch().sendMessage("This isn't a set item.");
|
player.getPacketDispatch().sendMessage("This isn't a set item.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,15 +159,11 @@ class StockMarket : InterfaceListener {
|
|||||||
183 -> updateOfferValue(player, tempOffer, (GrandExchange.getRecommendedPrice(tempOffer.itemID) * 1.05).toInt())
|
183 -> updateOfferValue(player, tempOffer, (GrandExchange.getRecommendedPrice(tempOffer.itemID) * 1.05).toInt())
|
||||||
171 -> updateOfferValue(player, tempOffer, tempOffer.offeredValue - 1)
|
171 -> updateOfferValue(player, tempOffer, tempOffer.offeredValue - 1)
|
||||||
173 -> 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) {
|
if (player.interfaceManager.chatbox.id == 389) {
|
||||||
player.interfaceManager.openChatbox(Components.OBJDIALOG_389)
|
player.interfaceManager.openChatbox(Components.OBJDIALOG_389)
|
||||||
}
|
}
|
||||||
var s = value.toString()
|
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())
|
updateOfferValue(player, tempOffer, s.toInt())
|
||||||
setAttribute(player, "ge-temp", tempOffer)
|
setAttribute(player, "ge-temp", tempOffer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,14 +43,10 @@ public class DiangoReclaimInterface extends ComponentPlugin {
|
|||||||
if(curOpen != null){
|
if(curOpen != null){
|
||||||
curOpen.close(player);
|
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
|
//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
|
//only send items if there are some to send
|
||||||
if(reclaimables.length > 0) {
|
if(reclaimables.length > 0) {
|
||||||
@@ -68,18 +64,36 @@ public class DiangoReclaimInterface extends ComponentPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
|
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){
|
switch(opcode){
|
||||||
case 155: //interface item option 1 == take
|
case 155: //interface item option 1 == take
|
||||||
//add the clicked item to the player's inventory and refresh the interface
|
//add the clicked item to the player's inventory and refresh the interface
|
||||||
player.getInventory().add(reclaimables[slot]);
|
player.getInventory().add(reclaimItem);
|
||||||
refresh(player);
|
refresh(player);
|
||||||
break;
|
break;
|
||||||
case 196: //interface item option 2 == examine
|
case 196: //interface item option 2 == examine
|
||||||
//send the examine text for the item to the player
|
//send the examine text for the item to the player
|
||||||
player.getPacketDispatch().sendMessage(reclaimables[slot].getDefinition().getExamine());
|
player.getPacketDispatch().sendMessage(reclaimItem.getDefinition().getExamine());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
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
|
@Override
|
||||||
public boolean handle(Player player, Node node, String option) {
|
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) {
|
switch (option) {
|
||||||
case "take-egg":
|
case "take-egg":
|
||||||
if (inc == -1) {
|
if (inc == -1) {
|
||||||
@@ -54,6 +56,8 @@ public class IncubatorPlugin extends OptionHandler {
|
|||||||
GroundItemManager.create(egg.getProduct(),player);
|
GroundItemManager.create(egg.getProduct(),player);
|
||||||
}
|
}
|
||||||
player.removeAttribute("inc");
|
player.removeAttribute("inc");
|
||||||
|
player.removeAttribute(IncubatorState.ATTR_INCUBATOR_PRODUCT);
|
||||||
|
player.clearState("incubator");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case "inspect":
|
case "inspect":
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ public final class BuildOptionPlugin extends OptionHandler {
|
|||||||
}
|
}
|
||||||
Hotspot hotspot = player.getHouseManager().getHotspot(object);
|
Hotspot hotspot = player.getHouseManager().getHotspot(object);
|
||||||
if (hotspot == null || !isBuildable(player, object, hotspot)) {
|
if (hotspot == null || !isBuildable(player, object, hotspot)) {
|
||||||
|
//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.ERR, "Construction (building): " + hotspot + " : " + object + " chunkX = " + object.getLocation().getChunkX() + ", chunkY = " + object.getLocation().getChunkY());
|
log(this.getClass(), Log.WARN, "Construction (building): " + hotspot + " : " + object + " chunkX = " + object.getLocation().getChunkX() + ", chunkY = " + object.getLocation().getChunkY());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package content.global.skill.crafting;
|
package content.global.skill.crafting;
|
||||||
|
|
||||||
import static core.api.ContentAPIKt.*;
|
import static core.api.ContentAPIKt.*;
|
||||||
|
import core.api.InputType;
|
||||||
import core.cache.def.impl.ItemDefinition;
|
import core.cache.def.impl.ItemDefinition;
|
||||||
import core.game.component.Component;
|
import core.game.component.Component;
|
||||||
import core.game.dialogue.DialoguePlugin;
|
import core.game.dialogue.DialoguePlugin;
|
||||||
@@ -204,7 +205,7 @@ public final class LeatherCraftDialogue extends DialoguePlugin {
|
|||||||
if (hidee == null) {
|
if (hidee == null) {
|
||||||
return false;
|
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));
|
player.getPulseManager().run(new DragonCraftPulse(player, null, hidee, (int) value));
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class ToolLeprechaunInterface : InterfaceListener {
|
|||||||
player.dialogueInterpreter.sendDialogue("You don't have any of those stored.")
|
player.dialogueInterpreter.sendDialogue("You don't have any of those stored.")
|
||||||
} else {
|
} else {
|
||||||
if(amount == -2){
|
if(amount == -2){
|
||||||
sendInputDialogue(player, true, "Enter the amount:"){value ->
|
sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:"){value ->
|
||||||
var amt = value as Int
|
var amt = value as Int
|
||||||
if(amt > hasAmount){
|
if(amt > hasAmount){
|
||||||
amt = hasAmount
|
amt = hasAmount
|
||||||
|
|||||||
@@ -303,7 +303,13 @@ public final class HunterPlugin extends OptionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(Player player, Node node, String option) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -387,6 +387,8 @@ class LunarListeners : SpellListener("lunar"), Commands {
|
|||||||
var counter = 0
|
var counter = 0
|
||||||
override fun pulse(): Boolean {
|
override fun pulse(): Boolean {
|
||||||
removeAttribute(player, "spell:runes")
|
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)))
|
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
|
if(counter == 0) delay = animationDuration(STRING_JEWELLERY_ANIM) + 1
|
||||||
val item = playerJewellery[0]
|
val item = playerJewellery[0]
|
||||||
|
|||||||
@@ -41,8 +41,15 @@ public class StatRestoreSpell extends MagicSpell {
|
|||||||
public boolean cast(Entity entity, Node target) {
|
public boolean cast(Entity entity, Node target) {
|
||||||
final Player player = ((Player) entity);
|
final Player player = ((Player) entity);
|
||||||
Item item = ((Item) target);
|
Item item = ((Item) target);
|
||||||
final Potion potion = (Potion) Consumables.getConsumableById(item.getId()).getConsumable();
|
|
||||||
player.getInterfaceManager().setViewedTab(6);
|
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) {
|
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;
|
return false;
|
||||||
|
|||||||
@@ -6,22 +6,27 @@ import core.game.node.entity.state.State
|
|||||||
import core.game.system.task.Pulse
|
import core.game.system.task.Pulse
|
||||||
import org.json.simple.JSONObject
|
import org.json.simple.JSONObject
|
||||||
import core.api.*
|
import core.api.*
|
||||||
|
import core.tools.*
|
||||||
|
|
||||||
@PlayerState("incubator")
|
@PlayerState("incubator")
|
||||||
class IncubatorState(player: Player? = null) : State(player) {
|
class IncubatorState(player: Player? = null) : State(player) {
|
||||||
var egg: IncubatorEgg? = null
|
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 {
|
override fun newInstance(player: Player?): State {
|
||||||
return IncubatorState(player)
|
return IncubatorState(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun save(root: JSONObject) {
|
override fun save(root: JSONObject) {
|
||||||
if(ticksLeft <= 0) return
|
if(pulse == null) return
|
||||||
|
|
||||||
val data = JSONObject()
|
val data = JSONObject()
|
||||||
data.put("eggOrdinal",(egg?.ordinal ?: 0).toString())
|
data.put("eggOrdinal",(egg?.ordinal ?: 0).toString())
|
||||||
data.put("ticksLeft",ticksLeft.toString())
|
data.put("endTime", completionTimeMs.toString())
|
||||||
root.put("eggdata",data)
|
root.put("eggdata",data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +34,11 @@ class IncubatorState(player: Player? = null) : State(player) {
|
|||||||
if(_data.containsKey("eggdata")){
|
if(_data.containsKey("eggdata")){
|
||||||
val data = _data["eggdata"] as JSONObject
|
val data = _data["eggdata"] as JSONObject
|
||||||
egg = IncubatorEgg.values()[data["eggOrdinal"].toString().toInt()]
|
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)
|
setVarbit(player, 4277, 1)
|
||||||
pulse = object : Pulse(){
|
pulse = object : Pulse(){
|
||||||
override fun pulse(): Boolean {
|
override fun pulse(): Boolean {
|
||||||
if(ticksLeft-- <= 0){
|
if(System.currentTimeMillis() >= completionTimeMs){
|
||||||
player.setAttribute("/save:inc", egg!!.ordinal)
|
player.setAttribute(ATTR_INCUBATOR_PRODUCT, egg!!.ordinal)
|
||||||
player.sendMessage("Your " + egg!!.product.name.toLowerCase() + " has finished hatching.")
|
player.sendMessage("Your " + egg!!.product.name.toLowerCase() + " has finished hatching.")
|
||||||
pulse = null
|
pulse = null
|
||||||
return true
|
return true
|
||||||
@@ -50,4 +59,7 @@ 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
|
@Override
|
||||||
public boolean cast(final Entity entity, final Node target) {
|
public boolean cast(final Entity entity, final Node target) {
|
||||||
|
if (!(target instanceof GroundItem))
|
||||||
|
return false;
|
||||||
final GroundItem ground = (GroundItem) target;
|
final GroundItem ground = (GroundItem) target;
|
||||||
if (!canCast(entity, ground)) {
|
if (!canCast(entity, ground)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -171,6 +171,8 @@ object PlunderUtils {
|
|||||||
|
|
||||||
fun getDoor(player: Player) : Int
|
fun getDoor(player: Player) : Int
|
||||||
{
|
{
|
||||||
|
if (getRoom(player) == null)
|
||||||
|
return -1;
|
||||||
val room = getRoom(player)!!.room
|
val room = getRoom(player)!!.room
|
||||||
return PlunderData.doors[room - 1]
|
return PlunderData.doors[room - 1]
|
||||||
}
|
}
|
||||||
@@ -219,6 +221,10 @@ object PlunderUtils {
|
|||||||
|
|
||||||
fun getChestXp(player: Player): Double
|
fun getChestXp(player: Player): Double
|
||||||
{
|
{
|
||||||
|
if (getRoom(player) == null) {
|
||||||
|
expel(player, false)
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
val room = getRoom(player)!!.room
|
val room = getRoom(player)!!.room
|
||||||
return when(room)
|
return when(room)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -188,6 +188,10 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
on(SARCOPHAGUS, IntType.SCENERY, "open") { player, node ->
|
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.")
|
sendMessage(player, "You attempt to push open the massive lid.")
|
||||||
val strength = getDynLevel(player, Skills.STRENGTH)
|
val strength = getDynLevel(player, Skills.STRENGTH)
|
||||||
animate(player, PUSH_LID_START)
|
animate(player, PUSH_LID_START)
|
||||||
@@ -198,6 +202,10 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
|
|||||||
if(RandomFunction.random(125) > strength)
|
if(RandomFunction.random(125) > strength)
|
||||||
return false
|
return false
|
||||||
animate(player, PUSH_LID_FINISH)
|
animate(player, PUSH_LID_FINISH)
|
||||||
|
if (PlunderUtils.getRoom(player) == null) {
|
||||||
|
PlunderUtils.expel(player, false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
runTask(player, 3){
|
runTask(player, 3){
|
||||||
setVarbit(player, node.asScenery().definition.varbitID, 1)
|
setVarbit(player, node.asScenery().definition.varbitID, 1)
|
||||||
rewardXP(player, Skills.STRENGTH, PlunderUtils.getSarcophagusXp(player))
|
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 ->
|
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)
|
animate(player, OPEN_CHEST_ANIM)
|
||||||
runTask(player){
|
runTask(player){
|
||||||
if(RandomFunction.roll(25))
|
if(RandomFunction.roll(25))
|
||||||
@@ -268,8 +280,14 @@ class PyramidPlunderMinigame : InteractionListener, TickListener, LogoutListener
|
|||||||
if(RandomFunction.roll(rate))
|
if(RandomFunction.roll(rate))
|
||||||
{
|
{
|
||||||
val varbitId = node.asScenery().definition.varbitID
|
val varbitId = node.asScenery().definition.varbitID
|
||||||
|
val door = PlunderUtils.getDoor(player)
|
||||||
|
|
||||||
|
if (door == -1)
|
||||||
|
PlunderUtils.expel(player, false)
|
||||||
|
else
|
||||||
rewardXP(player, Skills.THIEVING, PlunderUtils.getDoorXp(player, rate == 3))
|
rewardXP(player, Skills.THIEVING, PlunderUtils.getDoorXp(player, rate == 3))
|
||||||
if(PlunderUtils.getDoor(player) == varbitId) {
|
|
||||||
|
if (door == varbitId) {
|
||||||
PlunderUtils.loadNextRoom(player)
|
PlunderUtils.loadNextRoom(player)
|
||||||
PlunderUtils.resetObjectVarbits(player)
|
PlunderUtils.resetObjectVarbits(player)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import core.game.node.item.Item
|
|||||||
import org.rs09.consts.Items
|
import org.rs09.consts.Items
|
||||||
import core.game.dialogue.DialogueFile
|
import core.game.dialogue.DialogueFile
|
||||||
import core.tools.END_DIALOGUE
|
import core.tools.END_DIALOGUE
|
||||||
|
import core.api.*
|
||||||
|
|
||||||
abstract class FarmerDialogue : DialogueFile() {
|
abstract class FarmerDialogue : DialogueFile() {
|
||||||
|
|
||||||
@@ -129,10 +130,11 @@ class BlinkinDialogue : FarmerDialogue() {
|
|||||||
40 -> playerl("Do you have any Ogleroots to feed the rabbits?").also { stage++ }
|
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++ }
|
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 -> {
|
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)
|
val price = Item(Items.COINS_995, 10 * amount)
|
||||||
if(price.amount <= 0){
|
if(price.amount <= 0){
|
||||||
return@setAttribute
|
return@sendInputDialogue
|
||||||
}
|
}
|
||||||
if(player!!.inventory.containsItem(price) && player!!.inventory.remove(price)) {
|
if(player!!.inventory.containsItem(price) && player!!.inventory.remove(price)) {
|
||||||
if(player!!.inventory.add(Item(Items.OGLEROOT_12624, amount))) {
|
if(player!!.inventory.add(Item(Items.OGLEROOT_12624, amount))) {
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ public final class KalphiteQueenNPC extends AbstractNPC {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (style == CombatStyle.MAGIC) {
|
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;
|
int index = 1;
|
||||||
if (states.length == 0) {
|
if (states.length == 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ public final class BedabinNomadDialogue extends DialoguePlugin {
|
|||||||
case 2:
|
case 2:
|
||||||
end();
|
end();
|
||||||
final Scenery door = RegionManager.getObject(new Location(3169, 3046, 0));
|
final Scenery door = RegionManager.getObject(new Location(3169, 3046, 0));
|
||||||
|
if (door.getId() != 2701)
|
||||||
SceneryBuilder.replace(door, door.transform(2701), 2);
|
SceneryBuilder.replace(door, door.transform(2701), 2);
|
||||||
player.getWalkingQueue().reset();
|
player.getWalkingQueue().reset();
|
||||||
player.getWalkingQueue().addPath(3169, 3046);
|
player.getWalkingQueue().addPath(3169, 3046);
|
||||||
|
|||||||
+4
-4
@@ -27,7 +27,7 @@ class EscapeCutscene(player: Player) : Cutscene(player) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
player.faceLocation(location(2616, 3167, 0))
|
player.faceLocation(location(56, 31, 0))
|
||||||
animate(player, 2098)
|
animate(player, 2098)
|
||||||
timedUpdate(4)
|
timedUpdate(4)
|
||||||
}
|
}
|
||||||
@@ -38,8 +38,8 @@ class EscapeCutscene(player: Player) : Cutscene(player) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
3 -> {
|
3 -> {
|
||||||
DoorActionHandler.handleAutowalkDoor(Jeremy, getScenery(2617, 3167, 0))
|
DoorActionHandler.handleAutowalkDoor(Jeremy, getObject(57, 31, 0))
|
||||||
player.faceLocation(location(2617, 3164, 0))
|
player.faceLocation(location(57, 28, 0))
|
||||||
timedUpdate(3)
|
timedUpdate(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class EscapeCutscene(player: Player) : Cutscene(player) {
|
|||||||
moveCamera(47, 20)
|
moveCamera(47, 20)
|
||||||
rotateCamera(45, 15)
|
rotateCamera(45, 15)
|
||||||
teleport(player, 47, 15)
|
teleport(player, 47, 15)
|
||||||
Jeremy.teleport(Location.create(2616, 3167, 0))
|
Jeremy.teleport(location(56, 31, 0))
|
||||||
timedUpdate(2)
|
timedUpdate(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import core.game.node.entity.npc.NPC;
|
|||||||
import core.game.node.entity.player.Player;
|
import core.game.node.entity.player.Player;
|
||||||
import core.plugin.Plugin;
|
import core.plugin.Plugin;
|
||||||
import core.plugin.ClassScanner;
|
import core.plugin.ClassScanner;
|
||||||
|
import kotlin.Unit;
|
||||||
|
|
||||||
|
import static core.api.ContentAPIKt.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the bogrog npc.
|
* 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.");
|
player.sendMessage("You need a Summoning level of at least 21 in order to do that.");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
InterfaceContainer.generateItems(player,player.getInventory().toArray(),new String[] {"Swap X","Swap 10","Swap 5","Swap 1","Value"}, 644,0,7,4,200);
|
sendItemSelect(player, new String[] { "Value", "Swap 1", "Swap 5", "Swap 10", "Swap X" }, true, (slot, index) -> {
|
||||||
player.getInterfaceManager().openSingleTab(new Component(644));
|
BogrogPouchSwapper.handle(player, index, slot);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-16
@@ -17,11 +17,11 @@ import kotlin.math.floor
|
|||||||
*/
|
*/
|
||||||
object BogrogPouchSwapper {
|
object BogrogPouchSwapper {
|
||||||
//Opcodes for item options
|
//Opcodes for item options
|
||||||
private const val OP_VALUE = 155
|
private const val OP_VALUE = 0
|
||||||
private const val OP_SWAP_1 = 196
|
private const val OP_SWAP_1 = 1
|
||||||
private const val OP_SWAP_5 = 124
|
private const val OP_SWAP_5 = 2
|
||||||
private const val OP_SWAP_10 = 199
|
private const val OP_SWAP_10 = 3
|
||||||
private const val OP_SWAP_X = 234
|
private const val OP_SWAP_X = 4
|
||||||
|
|
||||||
private const val SPIRIT_SHARD = 12183
|
private const val SPIRIT_SHARD = 12183
|
||||||
|
|
||||||
@@ -29,16 +29,16 @@ object BogrogPouchSwapper {
|
|||||||
private val GEBorders = ZoneBorders(3151,3501,3175,3477)
|
private val GEBorders = ZoneBorders(3151,3501,3175,3477)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun handle(player: Player, opcode: Int, slot: Int, itemID: Int): Boolean{
|
fun handle(player: Player, optionIndex: Int, slot: Int): Boolean{
|
||||||
if(GEBorders.insideBorder(player)) return false
|
val item = player.inventory.get(slot) ?: return false
|
||||||
return when(opcode){
|
return when(optionIndex){
|
||||||
OP_VALUE -> sendValue(player.inventory.get(slot).id,player)
|
OP_VALUE -> sendValue(item.id,player)
|
||||||
OP_SWAP_1 -> swap(player, 1, player.inventory.get(slot).id)
|
OP_SWAP_1 -> swap(player, 1, item.id)
|
||||||
OP_SWAP_5 -> swap(player, 5, player.inventory.get(slot).id)
|
OP_SWAP_5 -> swap(player, 5, item.id)
|
||||||
OP_SWAP_10 -> swap(player,10,player.inventory.get(slot).id)
|
OP_SWAP_10 -> swap(player, 10, item.id)
|
||||||
OP_SWAP_X -> true.also{
|
OP_SWAP_X -> true.also{
|
||||||
sendInputDialogue(player, true, "Enter the amount:"){value ->
|
sendInputDialogue(player, InputType.AMOUNT, "Enter the amount:"){value ->
|
||||||
swap(player, value as Int, player.inventory.get(slot).id)
|
swap(player, value as Int, item.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> false
|
else -> false
|
||||||
@@ -56,7 +56,6 @@ object BogrogPouchSwapper {
|
|||||||
amt = inInventory
|
amt = inInventory
|
||||||
player.inventory.remove(Item(itemID,amt))
|
player.inventory.remove(Item(itemID,amt))
|
||||||
player.inventory.add(Item(SPIRIT_SHARD, floor(value * amt).toInt()))
|
player.inventory.add(Item(SPIRIT_SHARD, floor(value * amt).toInt()))
|
||||||
player.interfaceManager.close(Component(644))
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ object BogrogPouchSwapper {
|
|||||||
return false
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import core.plugin.Initializable;
|
|||||||
import core.plugin.Plugin;
|
import core.plugin.Plugin;
|
||||||
import core.game.interaction.PluginInteraction;
|
import core.game.interaction.PluginInteraction;
|
||||||
import core.game.interaction.PluginInteractionManager;
|
import core.game.interaction.PluginInteractionManager;
|
||||||
|
import core.game.world.repository.Repository;
|
||||||
|
|
||||||
@Initializable
|
@Initializable
|
||||||
public class StairInteraction extends PluginInteraction {
|
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)) {
|
player.getPulseManager().run(new MovementPulse(player,object.getLocation().transform(0,2,0)) {
|
||||||
@Override
|
@Override
|
||||||
public boolean pulse() {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}, PulseType.STANDARD);
|
}, PulseType.STANDARD);
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ class ZaffPlugin : OptionHandler() {
|
|||||||
)
|
)
|
||||||
stage = 1
|
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())
|
ammount = getStoreFile().getInt(player.username.toLowerCase())
|
||||||
var amt = value as Int
|
var amt = value as Int
|
||||||
if(amt > maxStaffs - ammount) amt = maxStaffs - ammount
|
if(amt > maxStaffs - ammount) amt = maxStaffs - ammount
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ public final class CorporealBeastNPC extends NPCBehavior {
|
|||||||
GameWorld.getPulser().submit(new Pulse(2, corp) {
|
GameWorld.getPulser().submit(new Pulse(2, corp) {
|
||||||
@Override
|
@Override
|
||||||
public boolean pulse() {
|
public boolean pulse() {
|
||||||
|
if (npc.darkEnergyCore == null)
|
||||||
|
return true;
|
||||||
npc.darkEnergyCore.init();
|
npc.darkEnergyCore.init();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1543,6 +1543,7 @@ fun sendInputDialogue(player: Player, type: InputType, prompt: String, handler:
|
|||||||
}
|
}
|
||||||
|
|
||||||
player.setAttribute("runscript", handler)
|
player.setAttribute("runscript", handler)
|
||||||
|
player.setAttribute("input-type", type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1728,9 +1729,11 @@ fun runcs2 (player: Player, scriptId: Int, vararg arguments: Any) {
|
|||||||
* Opens a generic item selection prompt with a glowing background, with your own callback to handle the selection.
|
* Opens a generic item selection prompt with a glowing background, with your own callback to handle the selection.
|
||||||
* @param player the player we are openinig the prompt for
|
* @param player the player we are openinig the prompt for
|
||||||
* @param options the right-click options the items should have
|
* @param options the right-click options the items should have
|
||||||
|
* @param keepAlive whether or not the selection prompt should remain open for multiple interactions
|
||||||
* @param callback a callback to handle the selection. The parameters passed to the callback are the slot in the inventory of the selected item, and the 0-9 index of the option clicked.
|
* @param callback a callback to handle the selection. The parameters passed to the callback are the slot in the inventory of the selected item, and the 0-9 index of the option clicked.
|
||||||
**/
|
**/
|
||||||
fun sendItemSelect (player: Player, vararg options: String, callback: (slot: Int, optionIndex: Int) -> Unit) {
|
@JvmOverloads
|
||||||
|
fun sendItemSelect (player: Player, vararg options: String, keepAlive: Boolean = false, callback: (slot: Int, optionIndex: Int) -> Unit) {
|
||||||
player.interfaceManager.openSingleTab(Component(12))
|
player.interfaceManager.openSingleTab(Component(12))
|
||||||
val scriptArgs = arrayOf ((12 shl 16) + 18, 93, 4, 7, 0, -1, "", "", "", "", "", "", "", "", "")
|
val scriptArgs = arrayOf ((12 shl 16) + 18, 93, 4, 7, 0, -1, "", "", "", "", "", "", "", "", "")
|
||||||
for (i in 0 until kotlin.math.min(9, options.size))
|
for (i in 0 until kotlin.math.min(9, options.size))
|
||||||
@@ -1741,6 +1744,7 @@ fun sendItemSelect (player: Player, vararg options: String, callback: (slot: Int
|
|||||||
.build()
|
.build()
|
||||||
player.packetDispatch.sendIfaceSettings(settings, 18, 12, 0, 28)
|
player.packetDispatch.sendIfaceSettings(settings, 18, 12, 0, 28)
|
||||||
setAttribute(player, "itemselect-callback", callback)
|
setAttribute(player, "itemselect-callback", callback)
|
||||||
|
setAttribute(player, "itemselect-keepalive", keepAlive)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun announceIfRare(player: Player, item: Item) {
|
fun announceIfRare(player: Player, item: Item) {
|
||||||
@@ -2545,12 +2549,20 @@ fun logWithStack(origin: Class<*>, type: Log, message: String) {
|
|||||||
try {
|
try {
|
||||||
throw Exception(message)
|
throw Exception(message)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
log(origin, type, "${exceptionToString(e)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an exception as an argument, and sends back the complete exception with stack trace as a standard string. Useful for various things.
|
||||||
|
* @param e The exception you wish to convert.
|
||||||
|
* @return a string with the full stack trace of the exception
|
||||||
|
**/
|
||||||
|
fun exceptionToString (e: Exception) : String {
|
||||||
val sw = StringWriter()
|
val sw = StringWriter()
|
||||||
val pw = PrintWriter(sw)
|
val pw = PrintWriter(sw)
|
||||||
e.printStackTrace(pw)
|
e.printStackTrace(pw)
|
||||||
|
return sw.toString()
|
||||||
log(origin, type, "$sw")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package core.api.utils
|
||||||
|
|
||||||
|
class ConfigParseException (message: String) : Exception (message)
|
||||||
@@ -27,10 +27,26 @@ open class WeightBasedTable : ArrayList<WeightedItem>() {
|
|||||||
guaranteedItems.add(element)
|
guaranteedItems.add(element)
|
||||||
} else {
|
} else {
|
||||||
totalWeight += element.weight
|
totalWeight += element.weight
|
||||||
|
val randIndex = RandomFunction.random(0, size)
|
||||||
|
val end = this.size
|
||||||
super.add(element)
|
super.add(element)
|
||||||
|
|
||||||
|
val temp = this[randIndex]
|
||||||
|
this[randIndex] = element
|
||||||
|
this[end] = temp
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun roll(receiver: Entity? = null, rollCount: Int) : ArrayList<Item> {
|
||||||
|
val items = ArrayList<Item>()
|
||||||
|
|
||||||
|
for (i in 0 until rollCount)
|
||||||
|
items.addAll(roll(receiver))
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
open fun roll(receiver: Entity? = null): ArrayList<Item>{
|
open fun roll(receiver: Entity? = null): ArrayList<Item>{
|
||||||
val items = ArrayList<WeightedItem>()
|
val items = ArrayList<WeightedItem>()
|
||||||
items.addAll(guaranteedItems)
|
items.addAll(guaranteedItems)
|
||||||
@@ -40,7 +56,7 @@ open class WeightBasedTable : ArrayList<WeightedItem>() {
|
|||||||
}
|
}
|
||||||
else if (isNotEmpty()) {
|
else if (isNotEmpty()) {
|
||||||
var rngWeight = RandomFunction.randomDouble(totalWeight)
|
var rngWeight = RandomFunction.randomDouble(totalWeight)
|
||||||
for (item in shuffled()) {
|
for (item in this) {
|
||||||
rngWeight -= item.weight
|
rngWeight -= item.weight
|
||||||
if (rngWeight <= 0) {
|
if (rngWeight <= 0) {
|
||||||
items.add(item)
|
items.add(item)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ abstract class DialogueFile {
|
|||||||
this.player = player
|
this.player = player
|
||||||
this.npc = npc
|
this.npc = npc
|
||||||
this.interpreter = interpreter
|
this.interpreter = interpreter
|
||||||
|
interpreter.activeTopics.clear()
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,8 +142,9 @@ public final class DialogueInterpreter {
|
|||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogueFile file = dialogue.file;
|
DialogueFile file = dialogue.file;
|
||||||
if (!activeTopics.isEmpty()) {
|
if (!activeTopics.isEmpty() && buttonId >= 2) {
|
||||||
Topic<?> topic = activeTopics.get(buttonId - 2);
|
Topic<?> topic = activeTopics.get(buttonId - 2);
|
||||||
|
|
||||||
if (!topic.getSkipPlayer())
|
if (!topic.getSkipPlayer())
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ public abstract class DialoguePlugin implements Plugin<Player> {
|
|||||||
* @return {@code True} if the dialogue plugin succesfully opened.
|
* @return {@code True} if the dialogue plugin succesfully opened.
|
||||||
*/
|
*/
|
||||||
public boolean open(Object... args) {
|
public boolean open(Object... args) {
|
||||||
|
player.getDialogueInterpreter().activeTopics.clear();
|
||||||
if (args.length > 0 && args[0] instanceof NPC) {
|
if (args.length > 0 && args[0] instanceof NPC) {
|
||||||
npc = (NPC)args[0];
|
npc = (NPC)args[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package core.game.dialogue;
|
|
||||||
|
|
||||||
import core.plugin.Initializable;
|
|
||||||
import core.game.node.entity.player.Player;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the SimpleEntityMessage dialogue.
|
|
||||||
* @author 'Vexia
|
|
||||||
*/
|
|
||||||
@Initializable
|
|
||||||
public class SimpleEntityMessage extends DialoguePlugin {
|
|
||||||
|
|
||||||
public SimpleEntityMessage() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimpleEntityMessage(Player player) {
|
|
||||||
super(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] getIds() {
|
|
||||||
return new int[] { 8000 };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean handle(int interfaceId, int buttonId) {
|
|
||||||
end();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DialoguePlugin newInstance(Player player) {
|
|
||||||
|
|
||||||
return new SimpleEntityMessage(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean open(Object... args) {
|
|
||||||
String[] messages = new String[args.length];
|
|
||||||
for (int i = 0; i < messages.length; i++)
|
|
||||||
messages[i] = (String) args[i];
|
|
||||||
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, messages);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -51,7 +51,7 @@ public final class AbuseReport {
|
|||||||
CommandMapping.INSTANCE.get("mute").attemptHandling(player, new String[] {"mute", victim, "48h"});
|
CommandMapping.INSTANCE.get("mute").attemptHandling(player, new String[] {"mute", victim, "48h"});
|
||||||
}
|
}
|
||||||
player.getPacketDispatch().sendMessage("Thank-you, your abuse report has been received.");
|
player.getPacketDispatch().sendMessage("Thank-you, your abuse report has been received.");
|
||||||
Discord.INSTANCE.postPlayerAlert(victim, "Abuse Report - " + rule.name());
|
Discord.postPlayerAlert(victim, "Abuse Report - " + rule.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -267,7 +267,8 @@ public abstract class MovementPulse extends Pulse {
|
|||||||
}
|
}
|
||||||
else if(overrideMethod != null){
|
else if(overrideMethod != null){
|
||||||
loc = overrideMethod.invoke(mover,destination);
|
loc = overrideMethod.invoke(mover,destination);
|
||||||
if(loc == destination.getLocation()) loc = destinationFlag.getDestination(mover,destination);
|
if(loc == destination.getLocation() && destinationFlag != null) loc = destinationFlag.getDestination(mover,destination);
|
||||||
|
else if (loc == destination.getLocation()) loc = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
|
|||||||
@@ -197,6 +197,8 @@ public abstract class Node {
|
|||||||
* @param direction The direction to set.
|
* @param direction The direction to set.
|
||||||
*/
|
*/
|
||||||
public void setDirection(Direction direction) {
|
public void setDirection(Direction direction) {
|
||||||
|
if (direction == null)
|
||||||
|
return;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public final class NPCDropTables {
|
|||||||
*/
|
*/
|
||||||
public static final int[] MESSAGE_NPCS = { 50, 7133, 7134, 2881, 2882, 2883, 3200, 3340, 6247, 6203, 6260, 6222, 2745, 1160, 8133, 8610, 8611, 8612, 8613, 8614, 6204, 6206, 6208, 6261, 6263, 6265, 6223, 6225, 6227 };
|
public static final int[] MESSAGE_NPCS = { 50, 7133, 7134, 2881, 2882, 2883, 3200, 3340, 6247, 6203, 6260, 6222, 2745, 1160, 8133, 8610, 8611, 8612, 8613, 8614, 6204, 6206, 6208, 6261, 6263, 6265, 6223, 6225, 6227 };
|
||||||
|
|
||||||
public final NPCDropTable table = new NPCDropTable();
|
public NPCDropTable table = new NPCDropTable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The NPC definitions.
|
* The NPC definitions.
|
||||||
|
|||||||
@@ -317,6 +317,8 @@ public class Player extends Entity {
|
|||||||
|
|
||||||
public byte[] opCounts = new byte[255];
|
public byte[] opCounts = new byte[255];
|
||||||
|
|
||||||
|
public int invalidPacketCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code Player} {@code Object}.
|
* Constructs a new {@code Player} {@code Object}.
|
||||||
* @param details The player's details.
|
* @param details The player's details.
|
||||||
@@ -1386,4 +1388,12 @@ public class Player extends Entity {
|
|||||||
public void updateAppearance() {
|
public void updateAppearance() {
|
||||||
getUpdateMasks().register(EntityFlag.Appearance, this);
|
getUpdateMasks().register(EntityFlag.Appearance, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void incrementInvalidPacketCount() {
|
||||||
|
invalidPacketCount++;
|
||||||
|
if (invalidPacketCount >= 5) {
|
||||||
|
clear();
|
||||||
|
log(this.getClass(), Log.ERR, "Disconnecting " + getName() + " for having a high rate of invalid packets. Potential packet bot misbehaving, or simply really bad connection.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -643,6 +643,8 @@ class PlayerSaver (val player: Player){
|
|||||||
|
|
||||||
val varpData = JSONArray()
|
val varpData = JSONArray()
|
||||||
for ((index, value) in player.varpMap) {
|
for ((index, value) in player.varpMap) {
|
||||||
|
if (!(player.saveVarp[index] ?: false)) continue
|
||||||
|
|
||||||
val varpObj = JSONObject()
|
val varpObj = JSONObject()
|
||||||
varpObj["index"] = index.toString()
|
varpObj["index"] = index.toString()
|
||||||
varpObj["value"] = value.toString()
|
varpObj["value"] = value.toString()
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ public final class InterfaceManager {
|
|||||||
*/
|
*/
|
||||||
public void setViewedTab(int tabIndex) {
|
public void setViewedTab(int tabIndex) {
|
||||||
if (tabs[tabIndex] == null) {
|
if (tabs[tabIndex] == null) {
|
||||||
throw new IllegalStateException("Tab at index " + tabIndex + " is null!");
|
return;
|
||||||
}
|
}
|
||||||
currentTabIndex = tabIndex;
|
currentTabIndex = tabIndex;
|
||||||
switch (tabIndex) {
|
switch (tabIndex) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class StateRepository : StartupListener{
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun forKey(key: String, player: Player): State?{
|
fun forKey(key: String, player: Player): State?{
|
||||||
val state = states[key]
|
val state = states[key]
|
||||||
if(player.states[key] != null){
|
if(player.hasActiveState(key)){
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if(state != null){
|
if(state != null){
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public final class SceneryBuilder {
|
|||||||
remove = remove.getWrapper();
|
remove = remove.getWrapper();
|
||||||
Scenery current = LandscapeParser.removeScenery(remove);
|
Scenery current = LandscapeParser.removeScenery(remove);
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
log(SceneryBuilder.class, Log.ERR, "Object could not be replaced with " + construct + " - object to remove is invalid.");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (current.getRestorePulse() != null) {
|
if (current.getRestorePulse() != null) {
|
||||||
@@ -119,7 +118,6 @@ public final class SceneryBuilder {
|
|||||||
remove = remove.getWrapper();
|
remove = remove.getWrapper();
|
||||||
Scenery current = LandscapeParser.removeScenery(remove);
|
Scenery current = LandscapeParser.removeScenery(remove);
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
log(SceneryBuilder.class, Log.ERR, "Object could not be replaced with " + construct + " - object to remove is invalid.");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (current.getRestorePulse() != null) {
|
if (current.getRestorePulse() != null) {
|
||||||
|
|||||||
@@ -158,6 +158,12 @@ class Shop(val title: String, val stock: Array<ShopItem>, val general: Boolean =
|
|||||||
val isMainStock = getAttribute(player, "shop-main", true)
|
val isMainStock = getAttribute(player, "shop-main", true)
|
||||||
val cont = if (isMainStock) getAttribute<Container?>(player, "shop-cont", null) ?: return Item(-1,-1) else playerStock
|
val cont = if (isMainStock) getAttribute<Container?>(player, "shop-cont", null) ?: return Item(-1,-1) else playerStock
|
||||||
val item = cont[slot]
|
val item = cont[slot]
|
||||||
|
|
||||||
|
if (item == null) {
|
||||||
|
player.sendMessage("That item doesn't appear to be there anymore. Please try again.")
|
||||||
|
return Item(-1, -1)
|
||||||
|
}
|
||||||
|
|
||||||
val price = when(currency)
|
val price = when(currency)
|
||||||
{
|
{
|
||||||
Items.TOKKUL_6529 -> item.definition.getConfiguration(ItemConfigParser.TOKKUL_PRICE, 1)
|
Items.TOKKUL_6529 -> item.definition.getConfiguration(ItemConfigParser.TOKKUL_PRICE, 1)
|
||||||
@@ -173,6 +179,13 @@ class Shop(val title: String, val stock: Array<ShopItem>, val general: Boolean =
|
|||||||
{
|
{
|
||||||
val shopCont = getAttribute<Container?>(player, "shop-cont", null) ?: return Pair(null, Item(-1,-1))
|
val shopCont = getAttribute<Container?>(player, "shop-cont", null) ?: return Pair(null, Item(-1,-1))
|
||||||
val item = player.inventory[slot]
|
val item = player.inventory[slot]
|
||||||
|
|
||||||
|
if (item == null) {
|
||||||
|
player.debug("Inventory slot $slot does not contain an item!")
|
||||||
|
player.sendMessage("That item doesn't seem to be there anymore. Please try again.")
|
||||||
|
return Pair(null, Item(-1,-1))
|
||||||
|
}
|
||||||
|
|
||||||
val shopItemId = if (item.definition.isUnnoted) {
|
val shopItemId = if (item.definition.isUnnoted) {
|
||||||
item.id
|
item.id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe
|
|||||||
OP_BUY_1 -> shop.buy(player, slot, 1)
|
OP_BUY_1 -> shop.buy(player, slot, 1)
|
||||||
OP_BUY_5 -> shop.buy(player, slot, 5)
|
OP_BUY_5 -> shop.buy(player, slot, 5)
|
||||||
OP_BUY_10 -> shop.buy(player, slot, 10)
|
OP_BUY_10 -> shop.buy(player, slot, 10)
|
||||||
OP_BUY_X -> sendInputDialogue(player, true, "Enter the amount to buy:"){value ->
|
OP_BUY_X -> sendInputDialogue(player, InputType.AMOUNT, "Enter the amount to buy:"){value ->
|
||||||
val amt = value as Int
|
val amt = value as Int
|
||||||
shop.buy(player, slot, amt)
|
shop.buy(player, slot, amt)
|
||||||
}
|
}
|
||||||
@@ -226,6 +226,12 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe
|
|||||||
|
|
||||||
val shop = getAttribute<Shop?>(player, "shop", null) ?: return@on false
|
val shop = getAttribute<Shop?>(player, "shop", null) ?: return@on false
|
||||||
|
|
||||||
|
val itemInSlot = player.inventory[slot]
|
||||||
|
if (itemInSlot == null) {
|
||||||
|
player.sendMessage("That item doesn't appear to be there anymore. Please try again.")
|
||||||
|
return@on true
|
||||||
|
}
|
||||||
|
|
||||||
val (_,price) = shop.getSellPrice(player, slot)
|
val (_,price) = shop.getSellPrice(player, slot)
|
||||||
val def = itemDefinition(player.inventory[slot].id)
|
val def = itemDefinition(player.inventory[slot].id)
|
||||||
|
|
||||||
@@ -243,7 +249,7 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe
|
|||||||
OP_SELL_1 -> shop.sell(player, slot, 1)
|
OP_SELL_1 -> shop.sell(player, slot, 1)
|
||||||
OP_SELL_5 -> shop.sell(player, slot, 5)
|
OP_SELL_5 -> shop.sell(player, slot, 5)
|
||||||
OP_SELL_10 -> shop.sell(player, slot, 10)
|
OP_SELL_10 -> shop.sell(player, slot, 10)
|
||||||
OP_SELL_X -> sendInputDialogue(player, true, "Enter the amount to sell:"){value ->
|
OP_SELL_X -> sendInputDialogue(player, InputType.AMOUNT, "Enter the amount to sell:"){value ->
|
||||||
val amt = value as Int
|
val amt = value as Int
|
||||||
shop.sell(player, slot, amt)
|
shop.sell(player, slot, amt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,6 +258,10 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
|
|||||||
reject(player, "Usage: ::commands <lt>page<gt>")
|
reject(player, "Usage: ::commands <lt>page<gt>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (page > pages.size) {
|
||||||
|
reject(player, "That page number is too high, you don't have access to that many.")
|
||||||
|
}
|
||||||
|
|
||||||
for (i in 0..310) {
|
for (i in 0..310) {
|
||||||
player.packetDispatch.sendString("", Components.QUESTJOURNAL_SCROLL_275, i)
|
player.packetDispatch.sendString("", Components.QUESTJOURNAL_SCROLL_275, i)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ class MusicCommandSet : CommandSet(Privilege.STANDARD){
|
|||||||
* music player yet.
|
* music player yet.
|
||||||
*/
|
*/
|
||||||
define("playid"){player,arg ->
|
define("playid"){player,arg ->
|
||||||
|
if (arg.size < 2)
|
||||||
|
reject(player, "Needs more args.")
|
||||||
val id = arg[1].toIntOrNull()
|
val id = arg[1].toIntOrNull()
|
||||||
if(id != null){
|
if(id != null){
|
||||||
PacketRepository.send(MusicPacket::class.java, MusicContext(player, id))
|
PacketRepository.send(MusicPacket::class.java, MusicContext(player, id))
|
||||||
|
|||||||
@@ -257,6 +257,10 @@ public final class CommunicationInfo {
|
|||||||
*/
|
*/
|
||||||
public static void add(Player player, String contact) {
|
public static void add(Player player, String contact) {
|
||||||
CommunicationInfo info = player.getDetails().getCommunication();
|
CommunicationInfo info = player.getDetails().getCommunication();
|
||||||
|
if (contact.isEmpty()) {
|
||||||
|
player.sendMessage("Unable to find a player by that name. Please try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (WorldCommunicator.isEnabled()) {
|
if (WorldCommunicator.isEnabled()) {
|
||||||
MSPacketRepository.sendContactUpdate(player.getName(), contact, false, false, null);
|
MSPacketRepository.sendContactUpdate(player.getName(), contact, false, false, null);
|
||||||
return;
|
return;
|
||||||
@@ -291,6 +295,10 @@ public final class CommunicationInfo {
|
|||||||
* @param block If the contact should be removed from the block list.
|
* @param block If the contact should be removed from the block list.
|
||||||
*/
|
*/
|
||||||
public static void remove(Player player, String contact, boolean block) {
|
public static void remove(Player player, String contact, boolean block) {
|
||||||
|
if (contact.isEmpty()) {
|
||||||
|
player.sendMessage("Unable to find a player by that name. Please try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (WorldCommunicator.isEnabled()) {
|
if (WorldCommunicator.isEnabled()) {
|
||||||
MSPacketRepository.sendContactUpdate(player.getName(), contact, true, block, null);
|
MSPacketRepository.sendContactUpdate(player.getName(), contact, true, block, null);
|
||||||
return;
|
return;
|
||||||
@@ -326,6 +334,10 @@ public final class CommunicationInfo {
|
|||||||
* @param contact The contact to block.
|
* @param contact The contact to block.
|
||||||
*/
|
*/
|
||||||
public static void block(Player player, String contact) {
|
public static void block(Player player, String contact) {
|
||||||
|
if (contact.isEmpty()) {
|
||||||
|
player.sendMessage("Unable to find a player by that name. Please try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (WorldCommunicator.isEnabled()) {
|
if (WorldCommunicator.isEnabled()) {
|
||||||
MSPacketRepository.sendContactUpdate(player.getName(), contact, false, true, null);
|
MSPacketRepository.sendContactUpdate(player.getName(), contact, false, true, null);
|
||||||
return;
|
return;
|
||||||
@@ -352,6 +364,10 @@ public final class CommunicationInfo {
|
|||||||
* @param clanRank The clan rank to set.
|
* @param clanRank The clan rank to set.
|
||||||
*/
|
*/
|
||||||
public static void updateClanRank(Player player, String contact, ClanRank clanRank) {
|
public static void updateClanRank(Player player, String contact, ClanRank clanRank) {
|
||||||
|
if (contact.isEmpty()) {
|
||||||
|
player.sendMessage("Unable to find a player by that name. Please try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
CommunicationInfo info = player.getDetails().getCommunication();
|
CommunicationInfo info = player.getDetails().getCommunication();
|
||||||
Contact c = info.contacts.get(contact);
|
Contact c = info.contacts.get(contact);
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import org.json.simple.JSONArray
|
|||||||
import org.json.simple.JSONObject
|
import org.json.simple.JSONObject
|
||||||
import org.json.simple.parser.JSONParser
|
import org.json.simple.parser.JSONParser
|
||||||
import core.ServerConstants
|
import core.ServerConstants
|
||||||
import core.api.log
|
import core.api.*
|
||||||
import core.api.utils.NPCDropTable
|
import core.api.utils.*
|
||||||
import core.api.utils.WeightedItem
|
|
||||||
import core.tools.Log
|
import core.tools.Log
|
||||||
import core.tools.SystemLogger
|
import core.tools.SystemLogger
|
||||||
import java.io.FileReader
|
import java.io.FileReader
|
||||||
|
|
||||||
|
|
||||||
class DropTableParser {
|
class DropTableParser {
|
||||||
val parser = JSONParser()
|
val parser = JSONParser()
|
||||||
var reader: FileReader? = null
|
var reader: FileReader? = null
|
||||||
@@ -22,14 +22,22 @@ class DropTableParser {
|
|||||||
for(i in obj){
|
for(i in obj){
|
||||||
val tab = i as JSONObject
|
val tab = i as JSONObject
|
||||||
val ids = tab["ids"].toString().split(",")
|
val ids = tab["ids"].toString().split(",")
|
||||||
|
|
||||||
|
try {
|
||||||
|
val table = NPCDropTable()
|
||||||
|
parseTable(tab["main"] as JSONArray, table, false)
|
||||||
|
parseTable(tab["charm"] as JSONArray, table, false, true)
|
||||||
|
parseTable(tab["default"] as JSONArray, table, true)
|
||||||
|
|
||||||
for(n in ids){
|
for(n in ids){
|
||||||
val def = NPCDefinition.forId(n.toInt()).dropTables
|
val def = NPCDefinition.forId(n.toInt()).dropTables
|
||||||
def ?: continue
|
def ?: continue
|
||||||
parseTable(tab["main"] as JSONArray, def.table, false)
|
def.table = table
|
||||||
parseTable(tab["charm"] as JSONArray, def.table, false, true)
|
|
||||||
parseTable(tab["default"] as JSONArray,def.table,true)
|
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
} catch (e: ConfigParseException) {
|
||||||
|
log (this::class.java, Log.ERR, "Error parsing drop tables for NPC ${NPCDefinition.forId(ids[0].toInt()).name}: ${exceptionToString(e)}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log(this::class.java, Log.FINE, "Parsed $count drop tables.")
|
log(this::class.java, Log.FINE, "Parsed $count drop tables.")
|
||||||
}
|
}
|
||||||
@@ -40,6 +48,11 @@ class DropTableParser {
|
|||||||
val id = item["id"].toString().toInt()
|
val id = item["id"].toString().toInt()
|
||||||
val minAmount = item["minAmount"].toString().toInt()
|
val minAmount = item["minAmount"].toString().toInt()
|
||||||
val maxAmount = item["maxAmount"].toString().toInt()
|
val maxAmount = item["maxAmount"].toString().toInt()
|
||||||
|
|
||||||
|
if (minAmount > maxAmount) {
|
||||||
|
throw ConfigParseException("Table is invalid! Specified minimum amount is > specified maximum amount.")
|
||||||
|
}
|
||||||
|
|
||||||
val weight = item["weight"].toString().toDouble()
|
val weight = item["weight"].toString().toDouble()
|
||||||
val newItem = WeightedItem(id,minAmount,maxAmount,weight.toDouble(),isAlways)
|
val newItem = WeightedItem(id,minAmount,maxAmount,weight.toDouble(),isAlways)
|
||||||
if(isCharms) destTable.addToCharms(newItem)
|
if(isCharms) destTable.addToCharms(newItem)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package core.integrations.discord
|
package core.integrations.discord
|
||||||
|
|
||||||
import core.api.getItemName
|
import core.api.*
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.json.simple.JSONArray
|
import org.json.simple.JSONArray
|
||||||
@@ -11,13 +11,41 @@ import java.io.DataOutputStream
|
|||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
|
||||||
object Discord {
|
class Discord : TickListener {
|
||||||
|
override fun tick() {
|
||||||
|
if (!removeList.isEmpty()) {
|
||||||
|
pendingMessages.removeAll(removeList)
|
||||||
|
removeList.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pendingMessages.isEmpty() && !flushingPends) {
|
||||||
|
flushingPends = true
|
||||||
|
GlobalScope.launch {
|
||||||
|
try {
|
||||||
|
val count = pendingMessages.size
|
||||||
|
for (i in 0 until count) {
|
||||||
|
val (url, content) = pendingMessages[i]
|
||||||
|
sendJsonPost(url, content)
|
||||||
|
removeList.add(pendingMessages[i])
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
flushingPends = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
private const val COLOR_NEW_BUY_OFFER = 47789
|
private const val COLOR_NEW_BUY_OFFER = 47789
|
||||||
private const val COLOR_NEW_SALE_OFFER = 5752709
|
private const val COLOR_NEW_SALE_OFFER = 5752709
|
||||||
private const val COLOR_OFFER_UPDATE = 15588691
|
private const val COLOR_OFFER_UPDATE = 15588691
|
||||||
|
|
||||||
|
private val pendingMessages = ArrayList<Pair<String, String>>()
|
||||||
|
private var flushingPends = false
|
||||||
|
private val removeList = ArrayList<Pair<String, String>>()
|
||||||
|
|
||||||
fun postNewOffer(isSale: Boolean, itemId: Int, value: Int, qty: Int, user: String) {
|
fun postNewOffer(isSale: Boolean, itemId: Int, value: Int, qty: Int, user: String) {
|
||||||
if (ServerConstants.DISCORD_GE_WEBHOOK.isEmpty()) return
|
if (ServerConstants.DISCORD_GE_WEBHOOK.isEmpty()) return
|
||||||
@@ -43,6 +71,7 @@ object Discord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
fun postPlayerAlert(player: String, type: String) {
|
fun postPlayerAlert(player: String, type: String) {
|
||||||
if (ServerConstants.DISCORD_MOD_WEBHOOK.isEmpty()) return
|
if (ServerConstants.DISCORD_MOD_WEBHOOK.isEmpty()) return
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
@@ -152,6 +181,7 @@ object Discord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun sendJsonPost(url: String = ServerConstants.DISCORD_GE_WEBHOOK, data: String) {
|
private fun sendJsonPost(url: String = ServerConstants.DISCORD_GE_WEBHOOK, data: String) {
|
||||||
|
try {
|
||||||
val conn = URL(url).openConnection() as HttpURLConnection
|
val conn = URL(url).openConnection() as HttpURLConnection
|
||||||
conn.doOutput = true
|
conn.doOutput = true
|
||||||
conn.requestMethod = "POST"
|
conn.requestMethod = "POST"
|
||||||
@@ -165,5 +195,9 @@ object Discord {
|
|||||||
println(line)
|
println(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
pendingMessages.add(Pair(url, data))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,6 +92,9 @@ public final class MSPacketRepository {
|
|||||||
buffer.put(publicSetting);
|
buffer.put(publicSetting);
|
||||||
buffer.put(privateSetting);
|
buffer.put(privateSetting);
|
||||||
buffer.put(tradeSetting);
|
buffer.put(tradeSetting);
|
||||||
|
if (WorldCommunicator.getSession() != null)
|
||||||
WorldCommunicator.getSession().write(buffer);
|
WorldCommunicator.getSession().write(buffer);
|
||||||
|
else
|
||||||
|
player.sendMessage("Privacy settings unavailable at the moment. Please try again later.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,6 +74,7 @@ public final class GameReadEvent extends IoReadEvent {
|
|||||||
size = getPacketSize(buffer, opcode, header, last);
|
size = getPacketSize(buffer, opcode, header, last);
|
||||||
}
|
}
|
||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
|
session.getPlayer().incrementInvalidPacketCount();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (buffer.remaining() < size) {
|
if (buffer.remaining() < size) {
|
||||||
@@ -136,10 +137,6 @@ public final class GameReadEvent extends IoReadEvent {
|
|||||||
}
|
}
|
||||||
return buffer.getShort() & 0xFFFF;
|
return buffer.getShort() & 0xFFFF;
|
||||||
}
|
}
|
||||||
if(header == -3){
|
|
||||||
|
|
||||||
}
|
|
||||||
log(this.getClass(), Log.ERR, "Invalid packet [opcode=" + opcode + ", last=" + last + ", queued=" + usedQueuedBuffer + "], header=" + header+"!");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ public final class MSReadEvent extends IoReadEvent {
|
|||||||
}
|
}
|
||||||
return buffer.getShort() & 0xFFFF;
|
return buffer.getShort() & 0xFFFF;
|
||||||
}
|
}
|
||||||
log(this.getClass(), Log.ERR, "Invalid packet [opcode=" + opcode + ", last=" + last + ", queued=" + usedQueuedBuffer + "]!");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ object PacketProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Packet.ReportAbuse -> {
|
is Packet.ReportAbuse -> {
|
||||||
|
if (pkt.target.isNullOrEmpty()) {
|
||||||
|
sendMessage(pkt.player, "Invalid player name.")
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!GameWorld.accountStorage.checkUsernameTaken(pkt.target.lowercase())) {
|
if (!GameWorld.accountStorage.checkUsernameTaken(pkt.target.lowercase())) {
|
||||||
sendMessage(pkt.player, "Invalid player name.")
|
sendMessage(pkt.player, "Invalid player name.")
|
||||||
return
|
return
|
||||||
@@ -571,9 +575,9 @@ object PacketProcessor {
|
|||||||
player = pkt.player
|
player = pkt.player
|
||||||
} else if (pkt is Packet.UseWithGroundItem) {
|
} else if (pkt is Packet.UseWithGroundItem) {
|
||||||
val container = getLikelyContainerForIface(pkt.player, pkt.iface) ?: return
|
val container = getLikelyContainerForIface(pkt.player, pkt.iface) ?: return
|
||||||
item = container[pkt.slot]
|
item = container[pkt.slot] ?: return
|
||||||
itemId = pkt.usedId
|
itemId = pkt.usedId
|
||||||
node = GroundItemManager.get(pkt.withId, Location.create(pkt.x, pkt.y, pkt.player.location.z), pkt.player)
|
node = GroundItemManager.get(pkt.withId, Location.create(pkt.x, pkt.y, pkt.player.location.z), pkt.player) ?: return
|
||||||
nodeId = pkt.withId
|
nodeId = pkt.withId
|
||||||
type = IntType.GROUNDITEM
|
type = IntType.GROUNDITEM
|
||||||
player = pkt.player
|
player = pkt.player
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import core.tools.StringUtils
|
|||||||
import core.tools.SystemLogger
|
import core.tools.SystemLogger
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
import java.nio.BufferUnderflowException
|
||||||
|
|
||||||
enum class Decoders530(val opcode: Int) {
|
enum class Decoders530(val opcode: Int) {
|
||||||
/******************************************
|
/******************************************
|
||||||
@@ -635,8 +636,13 @@ enum class Decoders530(val opcode: Int) {
|
|||||||
COMMAND(44) {
|
COMMAND(44) {
|
||||||
override fun decode(player: Player, buffer: IoBuffer): Packet {
|
override fun decode(player: Player, buffer: IoBuffer): Packet {
|
||||||
if (buffer.toByteBuffer().remaining() > 1) {
|
if (buffer.toByteBuffer().remaining() > 1) {
|
||||||
|
try {
|
||||||
val message = buffer.string.lowercase()
|
val message = buffer.string.lowercase()
|
||||||
return Packet.Command(player, message)
|
return Packet.Command(player, message)
|
||||||
|
} catch (e: BufferUnderflowException) {
|
||||||
|
player.sendMessage("Something went wrong there! Please try again.")
|
||||||
|
return Packet.NoProcess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Packet.NoProcess()
|
return Packet.NoProcess()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ object Login {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Pair(AuthResponse.Success, info)
|
return Pair(AuthResponse.Success, info)
|
||||||
|
} catch (buf: BufferUnderflowException) {
|
||||||
|
//some issue in either the data they sent us or how we read it, either way out of scope of this class's handling.
|
||||||
|
return Pair(AuthResponse.UnexpectedError, null)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log(this::class.java, Log.ERR, "Exception encountered during login packet parsing! See stack trace below.")
|
log(this::class.java, Log.ERR, "Exception encountered during login packet parsing! See stack trace below.")
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package core.net.packet.`in`
|
package core.net.packet.`in`
|
||||||
|
|
||||||
import core.api.sendDialogue
|
import core.api.*
|
||||||
import core.game.node.entity.player.Player
|
import core.game.node.entity.player.Player
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,6 +13,8 @@ object RunScript {
|
|||||||
fun processInput(player: Player, value: Any, script: ((Any) -> Boolean)) {
|
fun processInput(player: Player, value: Any, script: ((Any) -> Boolean)) {
|
||||||
if (value is Int && value <= 0) return
|
if (value is Int && value <= 0) return
|
||||||
|
|
||||||
|
val type = player.getAttribute("input-type", InputType.NUMERIC)
|
||||||
|
|
||||||
var input = value
|
var input = value
|
||||||
|
|
||||||
if (player.getAttribute("parseamount", false)) {
|
if (player.getAttribute("parseamount", false)) {
|
||||||
@@ -26,10 +28,18 @@ object RunScript {
|
|||||||
input = input.replace("k", "000").replace("m", "000000")
|
input = input.replace("k", "000").replace("m", "000000")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == InputType.NUMERIC || type == InputType.AMOUNT)
|
||||||
|
input = input.toString().toIntOrNull() ?: input
|
||||||
|
|
||||||
try {
|
try {
|
||||||
script(input)
|
script(input)
|
||||||
} catch (_: NumberFormatException) {
|
} catch (_: NumberFormatException) {
|
||||||
sendDialogue(player, "That number's a bit large, don't you think?")
|
sendDialogue(player, "That number's a bit large, don't you think?")
|
||||||
|
} catch (_: ClassCastException) {
|
||||||
|
sendDialogue(player, "Something went wrong here. Try again.")
|
||||||
|
} finally {
|
||||||
|
removeAttribute(player, "runscript")
|
||||||
|
removeAttribute(player, "input-type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ public final class StringUtils {
|
|||||||
* @return The string.
|
* @return The string.
|
||||||
*/
|
*/
|
||||||
public static String longToString(long l) {
|
public static String longToString(long l) {
|
||||||
|
try {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char ac[] = new char[32];
|
char ac[] = new char[32];
|
||||||
while (l != 0L) {
|
while (l != 0L) {
|
||||||
@@ -417,6 +418,9 @@ public final class StringUtils {
|
|||||||
ac[11 - i++] = VALID_CHARS[(int) (l1 - l * 37L)];
|
ac[11 - i++] = VALID_CHARS[(int) (l1 - l * 37L)];
|
||||||
}
|
}
|
||||||
return new String(ac, 12 - i, i);
|
return new String(ac, 12 - i, i);
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user