diff --git a/.gitignore b/.gitignore
index 50416bde6..4daf3c49b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,4 +42,5 @@ gradle
.idea
.idea/
Server/worldprops/
-Management-Server/managementprops/
\ No newline at end of file
+Management-Server/managementprops/
+/Development-Client/
\ No newline at end of file
diff --git a/Server/build.gradle b/Server/build.gradle
index 505344a91..cc0a72780 100644
--- a/Server/build.gradle
+++ b/Server/build.gradle
@@ -28,7 +28,7 @@ dependencies {
implementation 'io.github.classgraph:classgraph:4.8.98'
implementation 'org.jetbrains.kotlin:kotlin-reflect'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
- implementation files("libs/ConstLib-1.0.jar")
+ implementation files("libs/ConstLib-1.2.jar")
implementation files("libs/PrimitiveExtensions-1.0.jar")
}
diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json
index 7ffc459ac..3e93b4770 100644
--- a/Server/data/configs/item_configs.json
+++ b/Server/data/configs/item_configs.json
@@ -139147,35 +139147,25 @@
},
{
"id": "14651",
- "examine": "Passed down from the super egg defending bunny knights.",
+ "examine": "Mysterious blueprints written in an alien language.",
"destroy": "true",
- "destroy_message": "
WARNING: This item CAN NOT be re-obtained.",
- "requirements": "{0,40}",
+ "destroy_message": " WARNING: You will have to reobtain this item the hard way.",
+ "requirements": "",
"durability": null,
- "weight": "0.4",
- "attack_speed": "4",
- "weapon_interface": "12",
- "render_anim": "326",
- "equipment_slot": "3",
- "fun_weapon": "true",
- "name": "Eggscalibur",
- "archery_ticket_price": "0",
- "bonuses": "-100,-100,-50,0,0,0,0,0,0,0,0,-10,0,0,0"
+ "weight": "0.1",
+ "name": "Ancient Blueprints",
+ "archery_ticket_price": "0"
},
{
- "name": "Super Egg",
+ "name": "Ring of the Star Sprite",
"id": "14652",
- "examine": "SUPER. EGG. SUPER. EGG.",
+ "examine": "A stardust-infused dragonstone ring.",
"destroy": "true",
- "destroy_message": "You dare destroy I?! THE ALL MIGHTY AND POWERFUL SUPER EGG?!",
+ "destroy_message": "You can get another by bringing the materials along with the blueprint to a Star Sprite.",
"durability": null,
- "weight": "0.4",
- "attack_speed": "4",
- "weapon_interface": "12",
- "render_anim": "182",
- "equipment_slot": "3",
- "fun_weapon": "true",
+ "weight": "0.1",
+ "equipment_slot": "12",
"archery_ticket_price": "0",
- "bonuses": "-100,-100,-50,0,0,0,0,0,0,0,0,-10,0,0,0"
+ "bonuses": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
}
]
\ No newline at end of file
diff --git a/Server/libs/ConstLib-1.0.jar b/Server/libs/ConstLib-1.2.jar
similarity index 71%
rename from Server/libs/ConstLib-1.0.jar
rename to Server/libs/ConstLib-1.2.jar
index ae01341e3..e8679d136 100644
Binary files a/Server/libs/ConstLib-1.0.jar and b/Server/libs/ConstLib-1.2.jar differ
diff --git a/Server/src/main/java/core/game/node/entity/player/link/TeleportManager.java b/Server/src/main/java/core/game/node/entity/player/link/TeleportManager.java
index bed9736b9..d3933cfe2 100644
--- a/Server/src/main/java/core/game/node/entity/player/link/TeleportManager.java
+++ b/Server/src/main/java/core/game/node/entity/player/link/TeleportManager.java
@@ -668,25 +668,7 @@ public class TeleportManager {
@Override
public void start() {
- player = ((Player) entity);
- if (TutorialSession.getExtension(player).getStage() < TutorialSession.MAX_STAGE) {
- stop();
- return;
- }
- if (player.getSavedData().getGlobalData().getMinigameTeleportDelay() > System.currentTimeMillis()) {
- long milliseconds = player.getSavedData().getGlobalData().getMinigameTeleportDelay() - System.currentTimeMillis();
- int minutes = (int) Math.round(milliseconds / 60000);
- if (minutes > 30) {
- player.getSavedData().getGlobalData().setMinigameTeleportDelay(System.currentTimeMillis() + 600000);
- milliseconds = player.getSavedData().getGlobalData().getMinigameTeleportDelay() - System.currentTimeMillis();
- minutes = (int) Math.round(milliseconds / 60000);
- }
- if (minutes != 0) {
- player.getPacketDispatch().sendMessage("You need to wait another " + minutes + " " + (minutes == 1 ? "minute" : "minutes") + " to use the finder again.");
- stop();
- return;
- }
- }
+
super.start();
}
@@ -694,7 +676,7 @@ public class TeleportManager {
public void stop() {
super.stop();
entity.getAnimator().forceAnimation(new Animation(-1));
- player.graphics(new Graphics(-1));
+ entity.graphics(new Graphics(-1));
}
};
}
diff --git a/Server/src/main/java/core/net/JS5Queue.java b/Server/src/main/java/core/net/JS5Queue.java
index 7dbe80ce0..b08d1b10a 100644
--- a/Server/src/main/java/core/net/JS5Queue.java
+++ b/Server/src/main/java/core/net/JS5Queue.java
@@ -1,39 +1,66 @@
package core.net;
-import core.game.system.task.TaskExecutor;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Handles the JS5 queue for a session.
- * @author Emperor
+ * @author Techdaan
*/
public final class JS5Queue {
- /**
- * The queued JS5 requests.
- */
- private final Map queue = new HashMap<>();
+ public static AtomicBoolean RUNNING = new AtomicBoolean(true);
+
+ private static final Js5QueueHandler handler = new Js5QueueHandler();
+
+ private static class Js5QueueHandler extends Thread {
+ private final LinkedBlockingDeque requests = new LinkedBlockingDeque<>();
+
+ @Override
+ public void run() {
+ while (RUNNING.get()) {
+ try {
+ Js5Request request = requests.take();
+
+ JS5Queue queue = request.queue;
+
+ if (queue.session.isActive()) {
+ queue.session.write(new int[]{request.index, request.archive, request.priority ? 1 : 0});
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ static {
+ try {
+ handler.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static class Js5Request {
+ private final JS5Queue queue;
+ private final int index;
+ private final int archive;
+ private final boolean priority;
+
+ public Js5Request(JS5Queue queue, int index, int archive, boolean priority) {
+ this.queue = queue;
+ this.index = index;
+ this.archive = archive;
+ this.priority = priority;
+ }
+ }
/**
* The I/O session.
*/
private final IoSession session;
- /**
- * If the queue has been scheduled for release.
- */
- private boolean scheduledRelease;
-
- /**
- * The lock object.
- */
- private Lock lock = new ReentrantLock();
-
/**
* Constructs a new {@code JS5Queue} {@code Object}.
* @param session The I/O session.
@@ -44,53 +71,18 @@ public final class JS5Queue {
/**
* Queues a JS-5 request.
+ * Timers:
+ * 1000ms queue up files for this long
+ * 100ms release a file from the queue
+ *
* @param container The container.
* @param archive The archive.
* @param highPriority If the request is high priority.
+ *
*/
public void queue(int container, int archive, boolean highPriority) {
- try {
- lock.tryLock(1000L, TimeUnit.MILLISECONDS);
- } catch (Exception e){
- e.printStackTrace();
- lock.unlock();
- return;
- }
- int key = container << 16 | archive;
- if (queue.containsKey(key)) {
- // SystemLogger.logErr("Queue already contained request " + container
- // + "," + archive + " > " + (container << 16 | archive) + ".");
- }
- queue.put(key, highPriority);
- lock.unlock();
- release();
- }
-
- /**
- * Releases the queue.
- */
- public void release() {
- lock.lock();
- if (!scheduledRelease) {
- scheduledRelease = true;
- TaskExecutor.getExecutor().schedule(new Runnable() {
- @Override
- public void run() {
- lock.lock();
- for (Integer hash : queue.keySet()) {
- try {
- session.write(new int[] { hash >> 16 & 0xFF, hash & 0xFFFF, queue.get(hash) ? 1 : 0 });
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
- queue.clear();
- scheduledRelease = false;
- lock.unlock();
- }
- }, 100, TimeUnit.MILLISECONDS);
- }
- lock.unlock();
+ Js5Request request = new Js5Request(this, container, archive, highPriority);
+ handler.requests.add(request);
}
/**
@@ -101,20 +93,5 @@ public final class JS5Queue {
return session;
}
- /**
- * Gets the scheduledRelease.
- * @return the scheduledRelease
- */
- public boolean isScheduledRelease() {
- return scheduledRelease;
- }
-
- /**
- * Sets the scheduledRelease.
- * @param scheduledRelease the scheduledRelease to set.
- */
- public void setScheduledRelease(boolean scheduledRelease) {
- this.scheduledRelease = scheduledRelease;
- }
}
\ No newline at end of file
diff --git a/Server/src/main/kotlin/rs09/game/content/activity/communityevents/SuperEggEaster2020.kt b/Server/src/main/kotlin/rs09/game/content/activity/communityevents/SuperEggEaster2020.kt
deleted file mode 100644
index 4969f2885..000000000
--- a/Server/src/main/kotlin/rs09/game/content/activity/communityevents/SuperEggEaster2020.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package rs09.game.content.activity.communityevents
-
-import core.game.node.item.Item
-import core.game.world.map.Location
-import org.rs09.consts.Items
-import rs09.game.interaction.InteractionListener
-import rs09.game.system.config.GroundSpawnLoader
-
-class SuperEggEaster2020 : InteractionListener() {
- override fun defineListeners() {
- val egg = GroundSpawnLoader.GroundSpawn(-1,Item(14652,1),Location.create(2926, 3480, 0)).init()
-
- onDig(Location.create(2188, 3281, 0)){player ->
- val hasKey = player.getAttribute("easter2020:key",false)
- if(!hasKey){
- player.inventory.add(Item(Items.KEY_11039))
- player.dialogueInterpreter.sendDialogue("You dig and find an ancient key!")
- player.setAttribute("/save:easter2020:key",true)
- } else {
- player.sendMessage("You dig and find nothing.")
- }
- }
-
- on(14652, ITEM,"unlock"){player, node ->
- val item = node.asItem()
-
- if(player.inventory.contains(Items.KEY_11039,1)){
- player.dialogueInterpreter.sendDialogue("As you approach the egg you feel a great sense of unease.","You feel as though some ancient force lurks within the egg.","The key in your pocket begins to pull towards the egg...")
- player.dialogueInterpreter.addAction { pl, _ ->
- if(!pl.getAttribute("2020superegg",false)){
- pl.dialogueInterpreter.sendDialogue("However...","The egg does not recognize your essence.","You have been rejected.")
- } else {
- pl.dialogueInterpreter.sendDialogue("The egg recognizes your essence.","Visions of ancient Easterian knowledge fill your mind.","An ancient Easterian relic lurks within the egg.")
- pl.dialogueInterpreter.addAction { p, _ ->
- player.inventory.remove(Item(Items.KEY_11039))
- player.dialogueInterpreter.sendItemMessage(14651,"You pull from within the egg an ancient weapon.")
- player.inventory.add(Item(14651))
- }
- }
- }
-
- } else {
- player.dialogueInterpreter.sendDialogue("You approach the egg but you sense that it rejects you.")
- }
-
- return@on true
- }
-
- }
-}
-
-
diff --git a/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/ShootingStarMiningPulse.kt b/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/ShootingStarMiningPulse.kt
index dac8fa0a3..b51717e83 100644
--- a/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/ShootingStarMiningPulse.kt
+++ b/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/ShootingStarMiningPulse.kt
@@ -1,5 +1,6 @@
package rs09.game.content.global.worldevents.shootingstar
+import api.ContentAPI
import core.game.content.global.worldevents.shootingstar.ScoreboardManager
import core.game.node.`object`.Scenery
import core.game.node.entity.player.Player
@@ -7,8 +8,11 @@ import core.game.node.entity.skill.SkillPulse
import core.game.node.entity.skill.Skills
import core.game.node.entity.skill.gather.SkillingTool
import core.game.node.item.Item
+import core.tools.RandomFunction
+import org.rs09.consts.Items
import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository
+import rs09.tools.stringtools.colorize
/**
* The pulse used to handle mining shooting stars.
@@ -71,9 +75,32 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
if (ShootingStarOptionHandler.getStarDust(player) < 200) {
player.inventory.add(Item(ShootingStarOptionHandler.STAR_DUST, 1))
}
+ if(!ContentAPI.inInventory(player, Items.ANCIENT_BLUEPRINT_14651) && !ContentAPI.inBank(player, Items.ANCIENT_BLUEPRINT_14651)){
+ rollBlueprint(player)
+ }
return false
}
+ fun rollBlueprint(player: Player){
+ val chance = when(star.level){
+ ShootingStarType.LEVEL_9 -> 250
+ ShootingStarType.LEVEL_8 -> 500
+ ShootingStarType.LEVEL_7 -> 750
+ ShootingStarType.LEVEL_6 -> 1000
+ ShootingStarType.LEVEL_5 -> 2000
+ ShootingStarType.LEVEL_4 -> 3000
+ ShootingStarType.LEVEL_3 -> 4000
+ ShootingStarType.LEVEL_2 -> 5000
+ ShootingStarType.LEVEL_1 -> 10000
+ }
+
+ if(RandomFunction.roll(chance)){
+ ContentAPI.addItemOrDrop(player, Items.ANCIENT_BLUEPRINT_14651, 1)
+ ContentAPI.sendMessage(player, colorize("%RWhile mining the star you find an ancient-looking blueprint."))
+ ContentAPI.sendNews("${player.username} found an Ancient Blueprint while mining a shooting star!")
+ }
+ }
+
override fun message(type: Int) {
when (type) {
0 -> player.packetDispatch.sendMessage("You swing your pickaxe at the rock...")
diff --git a/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/StarSpriteDialogue.kt b/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/StarSpriteDialogue.kt
index 2944989b0..dfb237cb2 100644
--- a/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/StarSpriteDialogue.kt
+++ b/Server/src/main/kotlin/rs09/game/content/global/worldevents/shootingstar/StarSpriteDialogue.kt
@@ -1,9 +1,18 @@
package rs09.game.content.global.worldevents.shootingstar
+import api.Container
+import api.ContentAPI
import core.game.content.dialogue.DialoguePlugin
+import core.game.content.dialogue.FacialExpression
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.item.Item
+import core.tools.RandomFunction
+import org.rs09.consts.Items
+import rs09.game.node.entity.state.newsys.states.ShootingStarState
+import rs09.tools.END_DIALOGUE
+import rs09.tools.secondsToTicks
+import rs09.tools.stringtools.colorize
import java.util.concurrent.TimeUnit
/**
@@ -55,6 +64,12 @@ class StarSpriteDialogue(player: Player? = null) : DialoguePlugin(player) {
if (player.getSavedData().getGlobalData().getStarSpriteDelay() > System.currentTimeMillis() || !player.getInventory().contains(ShootingStarOptionHandler.STAR_DUST, 1)) {
npc("Hello, strange creature.")
stage = 0
+ } else if (ContentAPI.inInventory(player, Items.ANCIENT_BLUEPRINT_14651) && !ContentAPI.getAttribute(player, "star-ring:bp-shown", false)) {
+ npcl(FacialExpression.NEUTRAL, "I see you got ahold of a blueprint of those silly old rings we used to make.")
+ stage = 1000
+ } else if (ContentAPI.inInventory(player, Items.ANCIENT_BLUEPRINT_14651) && ContentAPI.getAttribute(player, "star-ring:bp-shown", false)) {
+ playerl(FacialExpression.HALF_ASKING, "So about those rings...")
+ stage = 2000
} else {
npc("Thank you for helping me out of here.")
stage = 50
@@ -166,6 +181,7 @@ class StarSpriteDialogue(player: Player? = null) : DialoguePlugin(player) {
}
41 -> end()
50 -> {
+ val wearingRing = ContentAPI.inEquipment(player, Items.RING_OF_THE_STAR_SPRITE_14652)
val dust = if (player.getInventory().getAmount(ShootingStarOptionHandler.STAR_DUST) > 200) 200 else player.getInventory().getAmount(ShootingStarOptionHandler.STAR_DUST)
if (player.getInventory().remove(Item(ShootingStarOptionHandler.STAR_DUST, dust))) {
val cosmicRunes = (Math.ceil(0.76 * dust) * AMPLIFIER).toInt()
@@ -178,11 +194,61 @@ class StarSpriteDialogue(player: Player? = null) : DialoguePlugin(player) {
player.getInventory().add(Item(COINS, coins), player)
npc("I have rewarded you by making it so you can mine", "extra ore for the next 15 minutes. Also, have $cosmicRunes", "cosmic runes, $astralRunes astral runes, $goldOre gold ore and $coins", "coins.")
player.getSavedData().getGlobalData().setStarSpriteDelay(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1))
- player.registerState("shooting-star").init()
+ player.registerState("shooting-star")?.init()
+
+ if(wearingRing){
+ val item = intArrayOf(Items.COSMIC_RUNE_564, Items.ASTRAL_RUNE_9075, Items.GOLD_ORE_445, Items.COINS_995).random()
+ val amount = when(item){
+ Items.COSMIC_RUNE_564 -> cosmicRunes
+ Items.ASTRAL_RUNE_9075 -> astralRunes
+ Items.GOLD_ORE_445 -> goldOre
+ Items.COINS_995 -> coins
+ else -> 0
+ }
+ rollForRingBonus(player, item, amount)
+ }
+ }
+
+ if(!ContentAPI.inInventory(player, Items.ANCIENT_BLUEPRINT_14651) && !ContentAPI.inBank(player, Items.ANCIENT_BLUEPRINT_14651) && RandomFunction.roll(500)){
+ ContentAPI.addItemOrDrop(player, Items.ANCIENT_BLUEPRINT_14651, 1)
+ ContentAPI.sendMessage(player, colorize("%RThe Star Sprite dropped what looks like some ancient piece of paper and you pick it up."))
+ ContentAPI.sendNews("${player.username} found an Ancient Blueprint while mining a shooting star!")
}
stage = 52
}
52 -> end()
+
+ //Inauthentic ring-based dialogue
+ 1000 -> playerl(FacialExpression.ASKING, "Oh, you mean this?").also { stage++ }
+ 1001 -> player.dialogueInterpreter.sendItemMessage(Items.ANCIENT_BLUEPRINT_14651, "You show the blueprint to the Star Sprite.").also { stage++ }
+ 1002 -> npcl(FacialExpression.ASKING, "Yeah, that's the one, alright!").also { stage++ }
+ 1003 -> npcl(FacialExpression.NEUTRAL, "I'll tell you what.. if you can get ahold of the resources needed to make one, I'm sure me or one of my kin would craft it for you.").also { stage++ }
+ 1004 -> playerl(FacialExpression.ASKING, "You'd just do that for me? For free?").also { stage++ }
+ 1005 -> npcl(FacialExpression.NEUTRAL, "I don't see why not. We used to make these for fun and hand them out to adventurers all the time.").also { stage++ }
+ 1006 -> playerl(FacialExpression.ASKING, "Well, thanks! So.. what do we need to make one?").also { stage++ }
+ 1007 -> npcl(FacialExpression.NEUTRAL, "Looking at the blueprint here...").also { stage++ }
+ 1008 -> npcl(FacialExpression.NEUTRAL, "Yes, it seems we need a ring mould, a silver bar, a cut dragonstone and 200 stardust. Oh, and make sure to bring this blueprint with you.").also { stage++ }
+ 1009 -> playerl(FacialExpression.FRIENDLY, "Thanks, I'll get right on it!").also { stage++ }
+ 1010 -> playerl(FacialExpression.ASKING, "So just to make sure I've got it right, I need a ring mould, a silver bar, a cut dragonstone and 200 stardust, as well as this blueprint?").also { stage++ }
+ 1011 -> npcl(FacialExpression.NEUTRAL, "Yeah, you've got it, human. Any of my kin should be able to do this for you.").also { stage++; ContentAPI.setAttribute(player, "/save:star-ring:bp-shown", true) }
+ 1012 -> playerl(FacialExpression.FRIENDLY, "Thanks!").also { stage = END_DIALOGUE }
+
+ 2000 -> npcl(FacialExpression.NEUTRAL, "Yes, did you bring the components to make it, human?").also { stage++ }
+ 2001 -> if(ContentAPI.inInventory(player, Items.DRAGONSTONE_1615,1) && ContentAPI.inInventory(player, Items.RING_MOULD_1592, 1) && ContentAPI.inInventory(player, Items.STARDUST_13727, 200) && ContentAPI.inInventory(player, Items.SILVER_BAR_2355, 1)){
+ playerl(FacialExpression.FRIENDLY, "Yes, I have them right here, friend.").also { stage++ }
+ } else {
+ playerl(FacialExpression.HALF_GUILTY, "I'm afraid not, what did I need again?").also { stage = 2100 }
+ }
+ 2002 -> npcl(FacialExpression.NEUTRAL, "Excellent, give me just a moment here...").also { stage++ }
+ 2003 -> sendDialogue("You watch as the Star Sprite casts some strange spell.").also { stage++ }
+ 2004 -> if(ContentAPI.removeItem(player, Items.SILVER_BAR_2355, Container.INVENTORY) && ContentAPI.removeItem(player, Items.DRAGONSTONE_1615, Container.INVENTORY) && ContentAPI.removeItem(player, Item(Items.STARDUST_13727, 200), Container.INVENTORY)){
+ ContentAPI.addItem(player, Items.RING_OF_THE_STAR_SPRITE_14652)
+ player.dialogueInterpreter.sendItemMessage(Items.RING_OF_THE_STAR_SPRITE_14652, "The Star Sprite hands you a strange ring.").also { stage++ }
+ } else end()
+ 2005 -> npcl(FacialExpression.NEUTRAL, "There you go, I hope you enjoy it!").also { stage++ }
+ 2006 -> playerl(FacialExpression.FRIENDLY, "Thank you!").also { stage = END_DIALOGUE }
+
+ 2100 -> npcl(FacialExpression.NEUTRAL, "A ring mould, a cut dragonstone, a silver bar and 200 stardust.").also { stage = END_DIALOGUE }
}
return true
}
@@ -191,4 +257,18 @@ class StarSpriteDialogue(player: Player? = null) : DialoguePlugin(player) {
return intArrayOf(8091)
}
+ fun rollForRingBonus(player: Player, bonusId: Int, bonusBaseAmt: Int){
+ if(RandomFunction.roll(3)){
+ val state = player.states["shooting-star"] as? ShootingStarState ?: return
+ state.ticksLeft += secondsToTicks(TimeUnit.MINUTES.toSeconds(5).toInt())
+ ContentAPI.sendMessage(player, colorize("%RYour ring shines dimly as if imbued with energy."))
+ } else if(RandomFunction.roll(5)){
+ ContentAPI.addItem(player, bonusId, bonusBaseAmt)
+ ContentAPI.sendMessage(player, colorize("%RYour ring shines brightly as if surging with energy and then fades out."))
+ } else if(RandomFunction.roll(25)){
+ player.savedData.globalData.starSpriteDelay = 0L
+ ContentAPI.sendMessage(player, colorize("%RYour ring vibrates briefly as if surging with power, and then stops."))
+ }
+ }
+
}
\ No newline at end of file
diff --git a/Server/src/main/kotlin/rs09/game/interaction/item/StarRingListener.kt b/Server/src/main/kotlin/rs09/game/interaction/item/StarRingListener.kt
new file mode 100644
index 000000000..d59350e4f
--- /dev/null
+++ b/Server/src/main/kotlin/rs09/game/interaction/item/StarRingListener.kt
@@ -0,0 +1,85 @@
+package rs09.game.interaction.item
+
+import api.ContentAPI
+import core.game.node.entity.player.Player
+import core.game.node.entity.player.link.TeleportManager
+import core.game.node.entity.skill.Skills
+import core.game.world.map.Location
+import org.rs09.consts.Items
+import rs09.game.content.dialogue.DialogueFile
+import rs09.game.content.global.worldevents.WorldEvents
+import rs09.game.content.global.worldevents.shootingstar.ShootingStar
+import rs09.game.content.global.worldevents.shootingstar.ShootingStarEvent
+import rs09.game.interaction.InteractionListener
+import java.util.concurrent.TimeUnit
+
+class StarRingListener : InteractionListener(){
+
+ val RING = Items.RING_OF_THE_STAR_SPRITE_14652
+
+ override fun defineListeners() {
+ on(RING, ITEM, "rub", "operate"){player, node ->
+ val star = WorldEvents.get("shooting-stars") as? ShootingStarEvent
+
+ if(star == null) ContentAPI.sendDialogue(player, "There is currently no active star.").also { return@on true }
+
+ if(ContentAPI.getAttribute(player, "ring-next-tele", 0L) > System.currentTimeMillis()){
+ ContentAPI.sendDialogue(player, "The ring is still recharging.")
+ return@on true
+ }
+
+ val condition: (Player) -> Boolean = when(star?.star!!.location.toLowerCase()){
+ "canifis bank" -> { p -> p.questRepository.isComplete("Priest in Peril")}
+ "crafting guild" -> {p -> ContentAPI.hasLevelStat(p, Skills.CRAFTING, 40) }
+ "south crandor mining site" -> {p -> p.questRepository.isComplete("Dragon Slayer")}
+ else -> {_ -> true}
+ }
+
+ if(!condition.invoke(player) || player.skullManager.isWilderness){
+ ContentAPI.sendDialogue(player, "Magical forces prevent your teleportation.")
+ return@on true
+ }
+
+ val shouldWarn = when(star.star.location){
+ "North Edgeville mining site",
+ "Southern wilderness mine",
+ "Pirates' Hideout mine",
+ "Lava Maze mining site",
+ "Mage Arena bank" -> true
+ else -> false
+ }
+
+ ContentAPI.openDialogue(player, RingDialogue(shouldWarn, star.star))
+
+ return@on true
+ }
+ }
+
+ internal class RingDialogue(val shouldWarn: Boolean, val star: ShootingStar) : DialogueFile(){
+ override fun handle(componentID: Int, buttonID: Int) {
+ if(shouldWarn){
+ when(stage) {
+ 0 -> dialogue("WARNING: That mining site is located in the wilderness.").also { stage++ }
+ 1 -> player!!.dialogueInterpreter.sendOptions("Continue?","Yes","No").also { stage++ }
+ 2 -> when(buttonID){
+ 1 -> teleport(player!!, star).also { end() }
+ 2 -> end()
+ }
+ }
+ } else {
+ when(stage){
+ 0 -> player!!.dialogueInterpreter.sendOptions("Teleport to the Star?", "Yes", "No").also { stage++ }
+ 1 -> when(buttonID){
+ 1 -> teleport(player!!, star).also { end() }
+ 2 -> end()
+ }
+ }
+ }
+ }
+
+ fun teleport(player: Player, star: ShootingStar){
+ ContentAPI.teleport(player, star.crash_locations[star.location]!!.transform(0, -1, 0), TeleportManager.TeleportType.MINIGAME)
+ ContentAPI.setAttribute(player, "/save:ring-next-tele", System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1))
+ }
+ }
+}
\ No newline at end of file
diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt
index cb7695613..e8427ea64 100644
--- a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt
+++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt
@@ -1,5 +1,6 @@
package rs09.game.node.entity.skill.gather.mining
+import api.ContentAPI
import core.cache.def.impl.ItemDefinition
import core.game.container.impl.EquipmentContainer
import core.game.content.dialogue.FacialExpression
@@ -173,16 +174,16 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul
if (!isMiningEssence) {
var chance = 282
var altered = false
- if (Item(player.equipment.getId(12)).name.toLowerCase().contains("ring of wealth")) {
+ if (Item(player.equipment.getId(12)).name.toLowerCase().contains("ring of wealth") || ContentAPI.inEquipment(player, Items.RING_OF_THE_STAR_SPRITE_14652)) {
chance = (chance / 1.5).toInt()
altered = true
}
val necklace = player.equipment[EquipmentContainer.SLOT_AMULET]
- if (necklace != null && necklace.id > 1705 && necklace.id < 1713) {
+ if (necklace != null && necklace.id in 1705..1713) {
chance = (chance / 1.5).toInt()
altered = true
}
- if (RandomFunction.random(chance) == chance / 2) {
+ if (RandomFunction.roll(chance)) {
val gem = RandomFunction.rollChanceTable(true, *GEM_REWARDS)[0]
player.packetDispatch.sendMessage("You find a " + gem.name + "!")
if (!player.inventory.add(gem, player)) {