Rewrote Pyramid Plunder Minigame, features improved authenticity amongst other improvements

This commit is contained in:
Ceikry 2022-04-05 03:12:28 +00:00 committed by Ryan
parent 24b28d84fd
commit 1f68dbaed0
44 changed files with 1303 additions and 1657 deletions

View file

@ -830,6 +830,12 @@ public class SceneryDefinition extends Definition<Scenery> {
}
}
}
if(childrenIds != null) {
for (int i = 0; i < childrenIds.length; ++i) {
SceneryDefinition def = forId(childrenIds[i]);
def.configFileId = configFileId;
}
}
if (anInt3855 == -1) {
anInt3855 = clipType == 0 ? 0 : 1;
}

View file

@ -2,7 +2,6 @@ package core.cache.def.impl;
import core.cache.Cache;
import core.game.node.entity.player.Player;
import rs09.game.system.SystemLogger;
import rs09.game.world.GameWorld;
import java.nio.ByteBuffer;
@ -70,18 +69,18 @@ public final class VarbitDefinition {
* @return The definition.
*/
public static VarbitDefinition forObjectID(int id) {
return forId(id,10);
return forId(id);
}
public static VarbitDefinition forNPCID(int id){
return forId(id,10);
return forId(id);
}
public static VarbitDefinition forItemID(int id){
return forId(id,30);
return forId(id);
}
public static VarbitDefinition forId(int id, int shiftAmount){
public static VarbitDefinition forId(int id){
/*VarbitDefinition def = MAPPING.get(id);
if (def != null) {
return def;

View file

@ -1,133 +0,0 @@
package core.game.content.activity.pyramidplunder;
import core.game.content.activity.ActivityManager;
import core.game.content.dialogue.DialoguePlugin;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
/**
* Handles Guardian mummy dialogue.
* @author Originally Emperor, completely redone by Ceikry.
*/
public final class GuardMummyDialogue extends DialoguePlugin {
/**
* If the player successfully caught the evil twin.
* Will remain unused until the quest is implemented. (if ever)
*/
//private int type;
/**
* Constructs a new {@code GuardMummyDialogue} {@code Object}.
*/
public GuardMummyDialogue() {super();}
public GuardMummyDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new GuardMummyDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
if(args.length > 1){
switch((int) args[1]){
case 0:
npc("You! How did you get into this place?");
stage = 50;
break;
case 1:
player("I know what I'm doing - let's get on with it.");
stage = 10;
break;
}
} else {
npc("Errr");
}
/*type = args.length == 1 ? 0 : (Integer) args[1];
if (type == 1) {
player("I know what I'm doing - let's get on with it.");
} else {
npc("You! How did you get in?");
}*/
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch(stage){
case 10:
npc("Fine, I'll take you to the first room now...");
stage = 60;
break;
case 50:
player("I could ask you the same thing.");
stage = 51;
break;
case 51:
npc("Nevermind that. I suppose since you're here I can tell", "you how to play.");
stage = 52;
break;
case 52:
npc("In each room there are urns, a chest, and a sarcophagus.");
stage = 53;
break;
case 53:
npc("The urns contain artifacts based on the room that you are","currently in. The chest contains valuable artifacts but is","sometimes trapped. The sarcophagus has one of my","brothers in it. And lots of artifacts.");
stage = 54;
break;
case 54:
player("Anything else I should know?");
stage = 55;
break;
case 55:
npc("Yes, each room requires more thieving knowledge than the"," last. And be careful not to die.");
stage = 56;
break;
case 56:
player("Oh, yes, dying. Not good. Well I suppose that covers it?");
stage = 57;
break;
case 57:
npc("Yep.");
stage = 58;
break;
case 58:
end();
break;
case 60:
end();
ActivityManager.start(player, "Pyramid plunder", false);
break;
}
/*switch (stage++) {
case 0:
if (type == 1) {
npc("Fine, I'll take you to the first room now...");
} else {
System.out.println("TODO:2");
}
return true;
case 1:
if (type == 1) {
end();
ActivityManager.start(player, "Pyramid plunder", false);
} else {
System.out.println("TODO:3");
}
return true;
}*/
return false;
}
@Override
public int[] getIds() {
return new int[] { 4476, 4477 };
}
}

View file

@ -1,41 +0,0 @@
package core.game.content.activity.pyramidplunder;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
/**
* Object wrapper for pyramid plunder nodes
* @author ceik
*/
public class PlunderObject extends Scenery {
private transient Player player;
private static int thisId;
public static int snakeId, openId;
public PlunderObject(Scenery obj){
super(obj.getId(),obj.getLocation(),obj.getRotation(),obj.getDirection());
this.thisId = obj.getId();
switch(thisId){
case 16501:
this.snakeId = 16509;
this.openId = 16505;
break;
case 16502:
this.snakeId = 16510;
this.openId = 16506;
break;
case 16503:
this.snakeId = 16511;
this.openId = 16507;
break;
case 16495:
this.openId = 16496;
break;
case 16473:
this.openId = 16474;
break;
}
}
}

View file

@ -1,29 +0,0 @@
package core.game.content.activity.pyramidplunder;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import java.util.HashMap;
/**
* Manages what objects a specific player has interacted with in pyramid plunder.
* @author ceik
*/
public class PlunderObjectManager{
public static HashMap<Location,Boolean> openedMap = new HashMap<>();
public static HashMap<Location, Boolean> charmedMap = new HashMap<>();
int originalIndex;
public boolean resetObjectsFor(Player player){
//Completely clear the mapping and reset objects
openedMap.clear();
charmedMap.clear();
return true;
}
public void registerOpened(PlunderObject object){
openedMap.putIfAbsent(object.getLocation(),true);
}
public void registerCharmed(PlunderObject object) { charmedMap.putIfAbsent(object.getLocation(),true);}
}

View file

@ -1,375 +0,0 @@
package core.game.content.activity.pyramidplunder;
import core.game.content.global.action.ClimbActionHandler;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.ImpactHandler;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.world.map.Location;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import kotlin.Unit;
import rs09.game.Varp;
import rs09.game.content.activity.pyramidplunder.PlunderSession;
/**
* Defines the zones for the pyramid plunder rooms and their interactions
* @author ceik
*/
@Initializable
public class PlunderZones implements Plugin<Object> {
private final PlunderZone[] ROOMS = {
new PlunderZone("plunder:room1", 1,1923, 4464, 1932, 4474),
new PlunderZone("plunder:room2", 2,1925, 4449, 1941, 4458),
new PlunderZone("plunder:room3", 3,1941, 4421, 1954, 4432),
new PlunderZone("plunder:room4", 4,1949, 4464, 1959, 4477),
new PlunderZone("plunder:room5", 5,1968, 4420, 1978, 4436),
new PlunderZone("plunder:room6", 6,1969, 4452, 1980, 4473),
new PlunderZone("plunder:room7", 7,1923, 4424, 1931, 4439),
new PlunderZone("plunder:room8", 8, 1950, 4442, 1969, 4455)
};
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for(PlunderZone room : ROOMS){
ZoneBuilder.configure(room);
}
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
public class PlunderZone extends MapZone {
PyramidPlunderRoom room;
Location entrance;
private final Animation[] animations = new Animation[] { new Animation(2247), new Animation(2248), new Animation(1113), new Animation(2244) };
final int swx, swy, nex, ney;
final String name;
final int roomnum;
public PlunderZone(final String name, final int roomnum, final int swx, final int swy, final int nex, final int ney) {
super(name, true);
this.name = name;
this.swx = swx;
this.swy = swy;
this.nex = nex;
this.ney = ney;
this.roomnum = roomnum;
switch(roomnum){
case 1:
room = PyramidPlunderRoom.ROOM_1;
break;
case 2:
room = PyramidPlunderRoom.ROOM_2;
break;
case 3:
room = PyramidPlunderRoom.ROOM_3;
break;
case 4:
room = PyramidPlunderRoom.ROOM_4;
break;
case 5:
room = PyramidPlunderRoom.ROOM_5;
break;
case 6:
room = PyramidPlunderRoom.ROOM_6;
break;
case 7:
room = PyramidPlunderRoom.ROOM_7;
break;
case 8:
room = PyramidPlunderRoom.ROOM_8;
}
}
@Override
public void configure() {
ZoneBorders borders = new ZoneBorders(swx, swy, nex, ney,0);
register(borders);
}
@Override
public boolean enter(Entity e){
if(e instanceof Player && ((Player) e).getLocation().getZ() == 0) {
e.asPlayer().getPacketDispatch().sendMessage("<col=7f03ff>Room: " + (roomnum) + " Level required: " + (21 + ((roomnum - 1) * 10)));
e.asPlayer().getPlunderObjectManager().resetObjectsFor(e.asPlayer());
PlunderSession session = e.asPlayer().getAttribute("plunder-session",null);
if(session != null){
session.resetVars();
}
e.asPlayer().logoutListeners.put("plunder-logout", player -> {
player.setLocation(Location.create(3288, 2801, 0));
return Unit.INSTANCE;
});
updateRoomVarp(e.asPlayer());
}
return true;
}
@Override
public boolean leave(Entity e, boolean logout) {
e.asPlayer().logoutListeners.remove("plunder-logout");
return super.leave(e, logout);
}
public void updateRoomVarp(Player player){
Varp varp = player.varpManager.get(822);
varp.setVarbit(0,room.reqLevel);
varp.setVarbit(9,roomnum);
player.getPacketDispatch().sendVarp(varp);
}
public boolean checkRequirements(Player player, PyramidPlunderRoom room){
int requiredLevel = room.reqLevel;
int playerLevel = player.getSkills().getLevel(Skills.THIEVING);
return playerLevel >= requiredLevel;
}
public void rollSceptre(Player player){
if(RandomFunction.random(1000) == 451){
if(!player.getInventory().isFull()) {
player.getInventory().add(new Item(9044));
player.getPacketDispatch().sendMessage("<col=7f03ff>You find a strange object.");
} else {
player.getBank().add(new Item(9044));
player.getPacketDispatch().sendMessage("<col=7f03ff>You sense that something has appeared in your bank.");
}
}
}
public final boolean success(final Player player, final int skill) {
double level = player.getSkills().getLevel(skill);
double successChance = Math.ceil((level * 50 - room.reqLevel) / room.reqLevel / 3 * 4);
int roll = RandomFunction.random(99);
if (successChance >= roll) {
return true;
}
return false;
}
public void reward(Player player, int objid){
Item[][] ARTIFACTS = { {new Item(9032),new Item(9036), new Item(9026)}, {new Item(9042), new Item(9030), new Item(9038)}, {new Item(9040), new Item(9028), new Item(9034)} };
rollSceptre(player);
switch(objid){
case 16517: // Spear
player.getSkills().addExperience(Skills.THIEVING, (30 + (roomnum * 20)), true);
break;
case 16503:
case 16502:
case 16501: // Urns
player.getSkills().addExperience(Skills.THIEVING, (25 + (roomnum * 20)), true);
player.getInventory().add(ARTIFACTS[((int)Math.floor((double) roomnum / 3))][RandomFunction.random(3)]);
break;
case 16473: // Chest
player.getInventory().add(ARTIFACTS[RandomFunction.random(1, 3)][RandomFunction.random(3)]);
player.getPacketDispatch().sendMessage("And you find an artifact!");
player.getSkills().addExperience(Skills.THIEVING, (40 + (roomnum * 20)));
break;
case 16495: // Sarcophagus
player.getPacketDispatch().sendMessage("You find some loot inside.");
player.getInventory().add(ARTIFACTS[RandomFunction.random(0,3)][RandomFunction.random(3)]);
player.getSkills().addExperience(Skills.STRENGTH,50 + (roomnum * 20));
break;
}
}
@Override
public boolean interact(Entity e, Node target, Option option) {
final Player player = e instanceof Player ? e.asPlayer() : null;
String optionName = option.getName().toLowerCase();
if(target instanceof NPC){
if(target.getName().contains("Guardian")) {
if (optionName.equals("talk-to")) {
player.getDialogueInterpreter().open(target.getId(), target.asNpc(), 0);
} else {
player.getDialogueInterpreter().open(target.getId(), target.asNpc(), 1);
}
}
if(optionName.equals("attack")){
player.getProperties().getCombatPulse().attack(target);
}
return true;
}
PlunderObject object = target instanceof Scenery ? new PlunderObject(target.asScenery()) : null;
PlunderObjectManager manager = player.getPlunderObjectManager();
if(object == null || manager == null) return super.interact(e, target, option);
boolean alreadyOpened = manager.openedMap.getOrDefault(object.getLocation(),false);
boolean charmed = manager.charmedMap.getOrDefault(object.getLocation(),false);
boolean success = success(player, Skills.THIEVING);
PlunderSession session = player.getAttribute("plunder-session",null);
if(session == null){
return false;
}
switch (object.getId()) {
case 16517: //Spear trap
if(!checkRequirements(player,room)){
player.getPacketDispatch().sendMessage("You need to be at least level " + room.reqLevel + " thieving.");
return true;
}
player.getLocks().lockInteractions(2);
player.animate(animations[success ? 1 : 0]);
if (success) {
player.getPacketDispatch().sendMessage("You successfully pass the spears.");
int moveX = player.getLocation().getX();
int moveY = player.getLocation().getY();
Location moveto = new Location(moveX + room.spearX, moveY + room.spearY);
player.getProperties().setTeleportLocation(moveto);
//player.moveStep();
} else {
player.getPacketDispatch().sendMessage("You fail to pass the spears.");
}
return true;
case 16503:
case 16502:
case 16501: // Urns
if (optionName.equals("search")) {
if (!checkRequirements(player,room)){
player.getPacketDispatch().sendMessage("You need to be at least level " + room.reqLevel + " thieving.");
return true;
}
if (alreadyOpened){
player.getPacketDispatch().sendMessage("You've already looted this.");
return true;
}
player.animate(animations[success ? 1 : 0]);
player.getLocks().lockInteractions(2);
if (!alreadyOpened && (success || charmed)) {
player.getPacketDispatch().sendMessage("You successfully search the urn...");
SceneryBuilder.replace(target.asScenery(), target.asScenery().transform(object.openId), 5);
manager.registerOpened(object);
reward(player,object.getId());
} else {
player.getPacketDispatch().sendMessage("You failed and got bit by a snake.");
player.getImpactHandler().manualHit(player,RandomFunction.random(2,8), ImpactHandler.HitsplatType.NORMAL);
}
} else if(optionName.equals("check for snakes")){
if(charmed){
player.getPacketDispatch().sendMessage("You already checked for snakes.");
} else {
player.getPacketDispatch().sendMessage("You check the urn for snakes...");
SceneryBuilder.replace(target.asScenery(), target.asScenery().transform(object.snakeId), 5);
}
}
return true;
case 16509:
case 16510:
case 16511: // Snake urns
if(optionName.equals("search") && player.getInventory().containsItem(new Item(4605))){
player.animate(new Animation(1877));
player.getPacketDispatch().sendMessage("You charm the snake into docility.");
manager.registerCharmed(object);
} else {
player.getImpactHandler().manualHit(player, RandomFunction.random(2, 8), ImpactHandler.HitsplatType.NORMAL);
player.getPacketDispatch().sendMessage("The snake bites you.");
}
return true;
case 16473: // Chest
if(optionName.equals("search")) {
boolean willSpawnSwarm = (RandomFunction.random(1,20) == 10);
if(!checkRequirements(player,room)){
player.getPacketDispatch().sendMessage("You need at least level " + room.reqLevel + " thieving to loot this.");
return true;
}
if (alreadyOpened){
player.getPacketDispatch().sendMessage("You've already looted this.");
return true;
}
player.getPacketDispatch().sendMessage("You search the chest...");
player.animate(animations[1]);
player.getLocks().lockInteractions(2);
if(willSpawnSwarm) {
player.getPacketDispatch().sendMessage("A swarm flies out!");
PyramidPlunderSwarmNPC swarm = new PyramidPlunderSwarmNPC(2001,player.getLocation(),player);
swarm.setRespawn(false);
swarm.setAggressive(true);
swarm.init();
} else {
reward(player,object.getId());
}
session.setChestOpen(true);
session.updateOverlay();
manager.registerOpened(object);
//ObjectBuilder.replace(target.asObject(), target.asObject().transform(object.openId), 5);
}
return true;
case 16495: //Sarcophagus
if(optionName.equals("open")) {
if (!checkRequirements(player,room)){
player.getPacketDispatch().sendMessage("You need to be at least level " + room.reqLevel + " thieving.");
return true;
}
if (alreadyOpened){
player.getPacketDispatch().sendMessage("You've already looted this.");
return true;
}
boolean willSpawnMummy = (RandomFunction.random(1,5) == 3);
player.animate(animations[1]);
player.getPacketDispatch().sendMessage("You open the sarcophagus and....");
if(willSpawnMummy) {
player.getPacketDispatch().sendMessage("A mummy crawls out!");
PyramidPlunderMummyNPC mummy = new PyramidPlunderMummyNPC(1958, player.getLocation(),player);
mummy.setRespawn(false);
mummy.setAggressive(true);
mummy.init();
} else {
reward(player,object.getId());
}
session.setCoffinOpen(true);
session.updateOverlay();
manager.registerOpened(object);
//ObjectBuilder.replace(target.asObject(), target.asObject().transform(object.openId), 5);
}
return true;
case 16475: //doors
if(optionName.equals("pick-lock") && roomnum < 8) {
if (!checkRequirements(player,room)){
player.getPacketDispatch().sendMessage("You need to be at least level " + room.reqLevel + " thieving.");
return true;
}
player.animate(animations[1]);
player.getLocks().lockInteractions(2);
boolean doesOpen = success(player, Skills.THIEVING);
if (doesOpen) {
PyramidPlunderRoom nextRoom = PyramidPlunderRoom.forRoomNum(roomnum + 1);
player.getPacketDispatch().sendMessage("The door opens!");
int index = room.doorLocations.indexOf(object.getLocation());
if(session.getCorrectDoorIndex() == index){
player.getProperties().setTeleportLocation(nextRoom.entrance);
} else {
session.setDoorOpen(index);
session.updateOverlay();
}
} else {
player.getPacketDispatch().sendMessage("You fail to unlock the door.");
}
} else if(roomnum == 8) {
ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_UP, Location.create(3288, 2801, 0));
}
return true;
case 16476:
player.getDialogueInterpreter().sendDialogue("This door doesn't seem to lead","anywhere.");
return true;
default:
return super.interact(e, target, option);
}
}
}
}

View file

@ -1,108 +0,0 @@
package core.game.content.activity.pyramidplunder;
import static api.ContentAPIKt.*;
import core.cache.def.impl.NPCDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.game.content.global.action.ClimbActionHandler;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the pyramid plunder options.
* @author Emperor
*/
public final class PyramidOptionHandler extends OptionHandler {
/**
* The guardian room location.
*/
private static final Location GUARDIAN_ROOM = Location.create(1968, 4420, 2);
/**
* The empty room location.
*/
private static final Location EMPTY_ROOM = Location.create(1934, 4450, 2);
/**
* The current entrance.
*/
private static int currentEntrance;
/**
* The last entrance switch made.
*/
private static long lastEntranceSwitch;
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(16484).getHandlers().put("option:search", this);
SceneryDefinition.forId(16485).getHandlers().put("option:search", this);
SceneryDefinition.forId(16487).getHandlers().put("option:search", this);
SceneryDefinition.forId(16488).getHandlers().put("option:search", this);
SceneryDefinition.forId(16490).getHandlers().put("option:search", this);
SceneryDefinition.forId(16491).getHandlers().put("option:search", this);
SceneryDefinition.forId(16493).getHandlers().put("option:search", this);
SceneryDefinition.forId(16494).getHandlers().put("option:enter", this);
SceneryDefinition.forId(16458).getHandlers().put("option:leave tomb", this);
SceneryDefinition.forId(16459).getHandlers().put("option:leave tomb", this);
NPCDefinition.forId(4476).getHandlers().put("option:start-minigame", this);
NPCDefinition.forId(4476).getHandlers().put("option:talk-to",this);
return null;
}
@Override
public boolean handle(Player player, Node node, String option) {
if (node instanceof Scenery) {
Location destination = EMPTY_ROOM;
Scenery object = (Scenery) node;
boolean willBePushed = (RandomFunction.random(10) > 3);
if (object.getId() == 16458 || object.getId() == 16459) {
ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_UP, Location.create(3288, 2801, 0));
player.getPlunderObjectManager().resetObjectsFor(player);
return true;
}
if (System.currentTimeMillis() - lastEntranceSwitch > 15 * 60 * 1000) {
currentEntrance = RandomFunction.random(4);
lastEntranceSwitch = System.currentTimeMillis();
}
int entrance = (object.getId() - 16483) / 3;
int value = 0;
if (entrance == currentEntrance) {
destination = GUARDIAN_ROOM;
value = 4;
}
player.getConfigManager().set(704, value);
player.getPacketDispatch().sendMessage("You use your thieving skills to search the stone panel.");
if(entrance == currentEntrance && willBePushed){
player.lock();
player.animate(new Animation(7299));
submitWorldPulse(new Pulse(4, player){
@Override
public boolean pulse() {
player.unlock();
return true;
}
});
} else {
ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_UP, destination, "You find a door! You open it.");
}
//ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_UP, destination, "You find a door! You open it.");
} else if (node instanceof NPC) {
if (option.equals("talk-to")) {
player.getDialogueInterpreter().open(node.getId(), node, 0);
} else {
player.getDialogueInterpreter().open(node.getId(), node, 1);
}
}
return true;
}
}

View file

@ -1,94 +0,0 @@
package core.game.content.activity.pyramidplunder;
import core.game.content.activity.ActivityPlugin;
import core.game.node.entity.Entity;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.plugin.Initializable;
import rs09.game.content.activity.pyramidplunder.PlunderSession;
import rs09.plugin.ClassScanner;
/**
* Handles the Pyramid plunder activity.
* @author Emperor
*/
@Initializable
public final class PyramidPlunderActivity extends ActivityPlugin {
/**
* The room locations.
*/
public static Location[] ROOM_LOCATIONS = { Location.create(1927, 4477, 0) };
/**
* The mummy NPC.
*/
private static NPC mummy;
/**
* Constructs a new {@code PyramidPlunderActivity} {@code Object}.
*/
public PyramidPlunderActivity() {
super("Pyramid plunder", false, true, false);
}
@Override
public boolean start(Player player, boolean login, Object... args) {
enterRoom(player, 0);
return true;
}
@Override
public boolean enter(Entity e) {
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
((Player) e).getInterfaceManager().closeOverlay();
PlunderSession session = (PlunderSession) e.asPlayer().getAttribute("plunder-session",null);
if(session != null){
session.setActive(false);
}
((Player) e).removeAttribute("plunder-session");
}
return super.leave(e, logout);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public void register() {
ClassScanner.definePlugin(new GuardMummyDialogue());
ClassScanner.definePlugin(new PyramidOptionHandler());
mummy = NPC.create(4476, Location.create(1968, 4427, 2));
mummy.init();
registerRegion(7749);
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public void configure() {
}
/**
* Enters a room.
* @param player The player.
* @param index The index.
*/
public void enterRoom(Player player, int index) {
player.lock(1);
player.getProperties().setTeleportLocation(ROOM_LOCATIONS[index]);
new PlunderSession(player).init();
}
}

View file

@ -15,8 +15,8 @@ public final class PyramidPlunderMummyNPC extends PyramidPlunderNPC {
*/
private static final int[] IDS = new int[] { 1958 };
public PyramidPlunderMummyNPC(int id, Location location, Player player) {
super(id, location, player);
public PyramidPlunderMummyNPC(Location location, Player player) {
super(IDS[0], location, player);
}
@Override

View file

@ -1,341 +0,0 @@
/*
package core.game.content.activity.pyramidplunder;
import org.crandor.cache.def.impl.ObjectDefinition;
import org.crandor.game.content.global.action.ClimbActionHandler;
import core.game.node.entity.skill.Skills;
import org.crandor.game.interaction.OptionHandler;
import org.crandor.game.node.Node;
import org.crandor.game.node.entity.combat.ImpactHandler;
import org.crandor.game.node.entity.player.Player;
import org.crandor.game.node.item.Item;
import org.crandor.game.node.object.ObjectBuilder;
import org.crandor.game.world.GameWorld;
import org.crandor.game.world.map.Location;
import org.crandor.game.world.map.zone.ZoneMonitor;
import org.crandor.game.world.update.flag.context.Animation;
import org.crandor.plugin.InitializablePlugin;
import org.crandor.plugin.Plugin;
import org.crandor.tools.RandomFunction;
*/
/**
* Handle pyramid plunder object interactions
* @author ceik
*//*
*/
/**
* PyramidPlunderOptions defines interactions for pyramid plunder
* Copyright (C) 2020 2009scape, et. al
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the modified GNU General Public License
* as published by the Free Software Foundation and included in this repository; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*//*
@InitializablePlugin
public final class PyramidPlunderOptions extends OptionHandler {
Item[][] ARTIFACTS = { {new Item(9032),new Item(9036), new Item(9026)}, {new Item(9042), new Item(9030), new Item(9038)}, {new Item(9040), new Item(9028), new Item(9034)} };
private static final Animation[] animations = new Animation[] { new Animation(2247), new Animation(2248), new Animation(1113), new Animation(2244) };
int reqLevel;
//Player player;
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ObjectDefinition.forId(16517).getConfigurations().put("option:pass",this);
ObjectDefinition.forId(16503).getConfigurations().put("option:search",this);
ObjectDefinition.forId(16502).getConfigurations().put("option:search",this);
ObjectDefinition.forId(16501).getConfigurations().put("option:search",this);
ObjectDefinition.forId(16501).getConfigurations().put("option:check for snakes",this);
ObjectDefinition.forId(16502).getConfigurations().put("option:check for snakes",this);
ObjectDefinition.forId(16503).getConfigurations().put("option:check for snakes",this);
ObjectDefinition.forId(16473).getConfigurations().put("option:search",this);
ObjectDefinition.forId(16495).getConfigurations().put("option:open",this);
ObjectDefinition.forId(16475).getConfigurations().put("option:pick-lock",this);
ObjectDefinition.forId(16509).getConfigurations().put("option:search",this);
ObjectDefinition.forId(16510).getConfigurations().put("option:search",this);
ObjectDefinition.forId(16511).getConfigurations().put("option:search",this);
return this;
}
public void rollSceptre(Player player){
if(RandomFunction.random(1000) == 451){
if(!player.getInventory().isFull()) {
player.getInventory().add(new Item(9044));
player.getPacketDispatch().sendMessage("<col=7f03ff>You find a strange object.");
} else {
player.getBank().add(new Item(9044));
player.getPacketDispatch().sendMessage("<col=7f03ff>You sense that something has appeared in your bank.");
}
}
}
public final boolean success(final Player player, final int skill) {
double level = player.getSkills().getLevel(skill);
double successChance = Math.ceil((level * 50 - reqLevel) / reqLevel / 3 * 4);
int roll = RandomFunction.random(99);
if (successChance >= roll) {
return true;
}
return false;
}
@Override
public boolean handle(Player player, Node node, String option) {
PlunderObjectManager manager = player.getPlunderObjectManager();
int NPCDeathTime = GameWorld.getTicks() + (1000 / 6);
Location room_entrance[] = {new Location(1927,4477), new Location(1927,4453), new Location(1943,4421), new Location(1954,4477), new Location(1974,4420), new Location(1977,4471), new Location(1927, 4424), new Location(1965,4444)};
int level = player.getSkills().getLevel(Skills.THIEVING);
int room = 0;
int spearX = 0;
int spearY = 0;
double droom = 0.0;
ZoneMonitor zmon = player.getZoneMonitor();
if(zmon.isInZone("plunder:room1")){
room = 1;
reqLevel = 21;
spearX = 0;
spearY = -2;
} else if(zmon.isInZone("plunder:room2")){
room = 2;
reqLevel = 31;
spearX = 2;
spearY = 0;
} else if(zmon.isInZone("plunder:room3")){
room = 3;
reqLevel = 41;
spearX = 0;
spearY = 2;
} else if(zmon.isInZone("plunder:room4")){
room = 4;
reqLevel = 51;
spearX = 0;
spearY = -2;
} else if(zmon.isInZone("plunder:room5")){
room = 5;
reqLevel = 61;
spearX = 0;
spearY = 2;
} else if(zmon.isInZone("plunder:room6")){
room = 6;
reqLevel = 71;
spearX = 0;
spearY = -2;
} else if(zmon.isInZone("plunder:room7")){
room = 7;
reqLevel = 81;
spearX = 0;
spearY = 2;
} else if(zmon.isInZone("plunder:room8")){
room = 8;
reqLevel = 91;
spearX = -2;
spearY = 0;
}
PlunderObject object = new PlunderObject(node.asObject().getId(),node.asObject().getLocation(),player);
droom = (double) room;
switch (object.getId()) {
case 16517:
if (option.equalsIgnoreCase("pass")) {
if (reqLevel > level){
player.getPacketDispatch().sendMessage("You need to be at least level " + reqLevel + " thieving.");
break;
}
boolean success = success(player, Skills.THIEVING);
player.animate(animations[success ? 1 : 0]);
if (success) {
player.getPacketDispatch().sendMessage("You successfully pass the spears.");
player.getSkills().addExperience(Skills.THIEVING, 30 + (room * 20), true);
int moveX = player.getLocation().getX();
int moveY = player.getLocation().getY();
Location moveto = new Location(moveX + spearX, moveY + spearY);
player.getProperties().setTeleportLocation(moveto);
//player.moveStep();
} else {
player.getPacketDispatch().sendMessage("You fail to pass the spears.");
}
}
break;
case 16503:
case 16502:
case 16501:
if (option.equalsIgnoreCase("search")) {
if (reqLevel > level){
player.getPacketDispatch().sendMessage("You need to be at least level " + reqLevel + " thieving.");
break;
}
if (manager.objectList.contains(object) ? manager.objectList.get(manager.objectList.indexOf(object)).playerOpened : false){
player.getPacketDispatch().sendMessage("You've already looted this.");
break;
}
boolean success = success(player, Skills.THIEVING);
player.animate(animations[success ? 1 : 0]);
player.lock(2);
if (manager.objectList.contains(object) ? manager.objectList.get(manager.objectList.indexOf(object)).snakeCharmed : success) {
player.getPacketDispatch().sendMessage("You successfully search the urn...");
player.getSkills().addExperience(Skills.THIEVING, 25 + (room * 20), true);
player.getInventory().add(ARTIFACTS[((int)Math.floor(droom / 3))][RandomFunction.random(3)]);
rollSceptre(player);
if(!manager.objectList.contains(object)) {
object.playerOpened = true;
manager.register(object);
} else {
manager.objectList.get(manager.objectList.indexOf(object)).playerOpened = true;
}
switch(object.getId()){
case 16501:
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16505), 5);
break;
case 16502:
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16506), 5);
break;
case 16503:
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16507), 5);
break;
}
} else {
player.getPacketDispatch().sendMessage("You failed and got bit by a snake.");
player.getImpactHandler().manualHit(player,RandomFunction.random(2,8), ImpactHandler.HitsplatType.NORMAL);
}
} else if(option.equalsIgnoreCase("check for snakes")){
if(manager.objectList.contains(object) && manager.objectList.get(manager.objectList.indexOf(object)).snakeCharmed){
player.getPacketDispatch().sendMessage("You already checked for snakes.");
} else {
player.getPacketDispatch().sendMessage("You check the urn for snakes...");
if (!manager.objectList.contains(object)) {
manager.register(object);
}
manager.originalIndex = manager.objectList.indexOf(object);
switch(object.getId()){
case 16501:
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16509), 5);
break;
case 16502:
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16510), 5);
break;
case 16503:
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16511), 5);
break;
}
}
}
break;
case 16509:
case 16510:
case 16511:
if(option.equalsIgnoreCase("search") && player.getInventory().containsItem(new Item(4605))){
player.animate(new Animation(1877));
player.getPacketDispatch().sendMessage("You charm the snake into docility.");
if(!manager.objectList.contains(manager.objectList.get(manager.originalIndex))) {
object.snakeCharmed = true;
manager.register(object);
} else {
manager.objectList.get(manager.originalIndex).snakeCharmed = true;
}
} else {
player.getImpactHandler().manualHit(player, RandomFunction.random(2, 8), ImpactHandler.HitsplatType.NORMAL);
player.getPacketDispatch().sendMessage("The snake bites you.");
}
break;
case 16473:
if(option.equalsIgnoreCase("search")) {
boolean willSpawnSwarm = (RandomFunction.random(1,20) == 10);
if (reqLevel > level){
player.getPacketDispatch().sendMessage("You need to be at least level " + reqLevel + " thieving.");
break;
}
if (manager.objectList.contains(object) ? manager.objectList.get(manager.objectList.indexOf(object)).playerOpened : false){
player.getPacketDispatch().sendMessage("You've already looted this.");
break;
}
player.getPacketDispatch().sendMessage("You search the chest...");
player.animate(animations[1]);
player.lock(2);
if(willSpawnSwarm) {
player.getPacketDispatch().sendMessage("A swarm flies out!");
PyramidPlunderSwarmNPC swarm = new PyramidPlunderSwarmNPC(2001,player.getLocation(),player);
swarm.setRespawn(false);
swarm.setAggressive(true);
swarm.init();
} else {
player.getInventory().add(ARTIFACTS[RandomFunction.random(1, 3)][RandomFunction.random(3)]);
rollSceptre(player);
player.getPacketDispatch().sendMessage("And you find an artifact!");
player.getSkills().addExperience(Skills.THIEVING, 40 + (room * 20));
}
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16474), 5);
if(!manager.objectList.contains(object)) {
object.playerOpened = true;
manager.register(object);
} else {
manager.objectList.get(manager.objectList.indexOf(object)).playerOpened = true;
}
}
break;
case 16495:
if(option.equalsIgnoreCase("open")) {
if (reqLevel > level){
player.getPacketDispatch().sendMessage("You need to be at least level " + reqLevel + " thieving.");
break;
}
if (manager.objectList.contains(object) ? manager.objectList.get(manager.objectList.indexOf(object)).playerOpened : false){
player.getPacketDispatch().sendMessage("You've already looted this.");
break;
}
boolean willSpawnMummy = (RandomFunction.random(1,5) == 3);
player.animate(animations[1]);
player.getPacketDispatch().sendMessage("You open the sarcophagus and....");
if(willSpawnMummy) {
player.getPacketDispatch().sendMessage("A mummy crawls out!");
PyramidPlunderMummyNPC mummy = new PyramidPlunderMummyNPC(1958, player.getLocation(),player);
mummy.setRespawn(false);
mummy.setAggressive(true);
mummy.init();
} else {
player.getPacketDispatch().sendMessage("You find some loot inside.");
player.getInventory().add(ARTIFACTS[RandomFunction.random(0,3)][RandomFunction.random(3)]);
rollSceptre(player);
player.getSkills().addExperience(Skills.STRENGTH,50 + (room * 20));
}
ObjectBuilder.replace(node.asObject(), node.asObject().transform(16496), 5);
if(!manager.objectList.contains(object)) {
object.playerOpened = true;
manager.register(object);
} else {
manager.objectList.get(manager.objectList.indexOf(object)).playerOpened = true;
}
}
break;
case 16475:
if(option.equals("pick-lock") && room < 8) {
if (reqLevel > level){
player.getPacketDispatch().sendMessage("You need to be at least level " + reqLevel + " thieving.");
break;
}
player.animate(animations[1]);
player.lock(2);
boolean doesOpen = success(player, Skills.THIEVING);
if (doesOpen) {
player.getPacketDispatch().sendMessage("The door opens!");
player.getProperties().setTeleportLocation(room_entrance[room]);
} else {
player.getPacketDispatch().sendMessage("You fail to unlock the door.");
}
} else if(room == 8) {
ClimbActionHandler.climb(player, ClimbActionHandler.CLIMB_UP, Location.create(3288, 2801, 0));
}
break;
}
return true;
}
}*/

View file

@ -1,40 +0,0 @@
package core.game.content.activity.pyramidplunder;
import core.game.world.map.Location;
import java.util.Arrays;
import java.util.List;
//defines room properties for pyramid plunder
//@author ceik
public enum PyramidPlunderRoom {
ROOM_1(1, 21, 0, -2,new Location(1927,4477), new Location[] {Location.create(1924, 4472, 0), Location.create(1931, 4472, 0), Location.create(1932, 4466, 0),Location.create(1923, 4466, 0)}),
ROOM_2(2, 31, 2, 0,new Location(1927,4453), new Location[] {Location.create(1937, 4459, 0),Location.create(1941, 4456, 0),Location.create(1937, 4448, 0),Location.create(1932, 4450, 0)}),
ROOM_3(3, 41, 0, 2,new Location(1943,4421), new Location[] {Location.create(1946, 4433, 0),Location.create(1955, 4430, 0),Location.create(1954, 4424, 0),Location.create(1949, 4422, 0)}),
ROOM_4(4, 51, 0, -2,new Location(1954,4477), new Location[] {Location.create(1957, 4472, 0),Location.create(1960, 4468, 0),Location.create(1959, 4465, 0),Location.create(1949, 4465, 0)}),
ROOM_5(5, 61, 0, 2,new Location(1974,4420), new Location[] {Location.create(1969, 4427, 0),Location.create(1967, 4432, 0),Location.create(1973, 4437, 0),Location.create(1979, 4430, 0)}),
ROOM_6(6, 71, 0, -2,new Location(1977,4471), new Location[] {Location.create(1980, 4458, 0),Location.create(1976, 4453, 0),Location.create(1974, 4453, 0),Location.create(1969, 4460, 0)}),
ROOM_7(7, 81, 0, 2,new Location(1927, 4424), new Location[] {Location.create(1923, 4432, 0),Location.create(1925, 4440, 0),Location.create(1929, 4440, 0),Location.create(1931, 4432, 0)}),
ROOM_8(8, 91, -2, 0,new Location(1965,4444), new Location[] {Location.create(1952, 4447, 0),Location.create(1953, 4445, 0),Location.create(1957, 4444, 0),Location.create(1962, 4448, 0)});
public final int roomNum, reqLevel, spearX, spearY;
Location entrance;
public final List<Location> doorLocations;
PyramidPlunderRoom(int roomNum, int reqLevel, int spearX, int spearY, Location entrance, Location[] door_locations){
this.roomNum = roomNum;
this.reqLevel = reqLevel;
this.spearX = spearX;
this.spearY = spearY;
this.entrance = entrance;
this.doorLocations = Arrays.asList(door_locations);
}
public static PyramidPlunderRoom forRoomNum(int roomNum){
for(PyramidPlunderRoom room : PyramidPlunderRoom.values()){
if(room.roomNum == roomNum){
return room;
}
}
return null;
}
}

View file

@ -15,8 +15,8 @@ public final class PyramidPlunderSwarmNPC extends PyramidPlunderNPC {
*/
private static final int[] IDS = new int[] { 2001 };
public PyramidPlunderSwarmNPC(int id, Location location, Player player) {
super(id, location, player);
public PyramidPlunderSwarmNPC(Location location, Player player) {
super(IDS[0], location, player);
}
@Override

View file

@ -11,119 +11,7 @@ import rs09.game.world.GameWorld
import java.lang.Integer.min
import kotlin.collections.HashMap
object CulinomancerShop : LoginListener {
// Our shop mappings - shops are individualized due to the differing items based on player's QP.
// Maps player UID -> shop
private val foodShops = HashMap<Int, Shop>()
private val gearShops = HashMap<Int, Shop>()
//Open methods for the shops - should check player's QP and whether they already have a container generated
@JvmStatic fun openShop(player: Player, food: Boolean)
{
getShop(player, food).open(player)
}
//Retrieve a player's shop - should generate the shop if it does not exist.
fun getShop(player: Player, food: Boolean) : Shop
{
val uid = player.details.uid
val points = player.questRepository.points
val tier = (points / 18)
if(tier != getAttribute(player, "culino-tier", 0)) //If player tier has changed
{
foodShops.remove(uid) //Clear the previous shops, so they can regenerate with the new tier
gearShops.remove(uid)
}
return if(food) {
val shop = foodShops[uid] ?: Shop("Culinomancer's Chest Tier $tier", generateFoodStock(points),false)
foodShops[uid] = shop
shop
} else {
val shop = gearShops[uid] ?: Shop("Culinomancer's Chest Tier $tier", generateGearStock(points), false)
gearShops[uid] = shop
shop
}
}
//Generate default food stock based on an amount of total QP.
private fun generateFoodStock(points: Int) : Array<Item>
{
val stock = Array(foodStock.size) { Item(0, 0) }
val maxQty = when(val qpTier = (points / 18) - 1)
{
0,1,2,3,4 -> 1 + qpTier
else -> qpTier + (qpTier + (qpTier - 5)) //5 = 10, 6 = 13, 7 = 15, etc
}
for((index,item) in foodStock.withIndex())
{
stock[index].id = item.id
stock[index].amount = if(item.id == Items.PIZZA_BASE_2283) 1 else maxQty
}
return stock
}
//Generate default gear stock based on an amount of total QP.
private fun generateGearStock(points: Int): Array<Item>
{
val stock = Array(gearStock.size) { Item(0,0) }
val qpTier = (points/18)
for((index, item) in stock.withIndex()) item.id = gearStock[index]
for(i in 0 until min(qpTier, 10))
{
stock[i].amount = 30
stock[i + 10].amount = 5
}
return stock
}
//Default gear shop stock
private val gearStock = arrayOf(
Items.GLOVES_7453,
Items.GLOVES_7454,
Items.GLOVES_7455,
Items.GLOVES_7456,
Items.GLOVES_7457,
Items.GLOVES_7458,
Items.GLOVES_7459,
Items.GLOVES_7460,
Items.GLOVES_7461,
Items.GLOVES_7462,
Items.WOODEN_SPOON_7433,
Items.EGG_WHISK_7435,
Items.SPORK_7437,
Items.SPATULA_7439,
Items.FRYING_PAN_7441,
Items.SKEWER_7443,
Items.ROLLING_PIN_7445,
Items.KITCHEN_KNIFE_7447,
Items.MEAT_TENDERISER_7449,
Items.CLEAVER_7451
)
//Default food shop stock
private val foodStock = arrayOf(
Item(Items.CHOCOLATE_BAR_1973,1),
Item(Items.CHEESE_1985, 1),
Item(Items.TOMATO_1982, 1),
Item(Items.COOKING_APPLE_1955, 1),
Item(Items.GRAPES_1987, 1),
Item(Items.POT_OF_FLOUR_1933, 1),
Item(Items.PIZZA_BASE_2283, 1),
Item(Items.EGG_1944, 1),
Item(Items.BUCKET_OF_MILK_1927, 1),
Item(Items.POT_OF_CREAM_2130, 1),
Item(Items.PAT_OF_BUTTER_6697, 1),
Item(Items.SPICE_2007, 1),
Item(Items.PIE_DISH_2313, 1),
Item(Items.CAKE_TIN_1887, 1),
Item(Items.BOWL_1923, 1),
Item(Items.JUG_1935, 1),
Item(Items.EMPTY_POT_1931, 1),
Item(Items.EMPTY_CUP_1980, 1),
Item(Items.BUCKET_1925, 1)
)
class CulinomancerShop : LoginListener {
//Enable the chest if the player has 18 quest points or more
override fun login(player: Player) {
if(player.questRepository.points >= 18){
@ -144,4 +32,112 @@ object CulinomancerShop : LoginListener {
player.logoutListeners["culino-restock"] = {restockPulse.stop()}
}
}
companion object {
// Our shop mappings - shops are individualized due to the differing items based on player's QP.
// Maps player UID -> shop
private val foodShops = HashMap<Int, Shop>()
private val gearShops = HashMap<Int, Shop>()
//Open methods for the shops - should check player's QP and whether they already have a container generated
@JvmStatic
fun openShop(player: Player, food: Boolean) {
getShop(player, food).open(player)
}
//Retrieve a player's shop - should generate the shop if it does not exist.
fun getShop(player: Player, food: Boolean): Shop {
val uid = player.details.uid
val points = player.questRepository.points
val tier = (points / 18)
if (tier != getAttribute(player, "culino-tier", 0)) //If player tier has changed
{
foodShops.remove(uid) //Clear the previous shops, so they can regenerate with the new tier
gearShops.remove(uid)
}
return if (food) {
val shop = foodShops[uid] ?: Shop("Culinomancer's Chest Tier $tier", generateFoodStock(points), false)
foodShops[uid] = shop
shop
} else {
val shop = gearShops[uid] ?: Shop("Culinomancer's Chest Tier $tier", generateGearStock(points), false)
gearShops[uid] = shop
shop
}
}
//Generate default food stock based on an amount of total QP.
private fun generateFoodStock(points: Int): Array<Item> {
val stock = Array(foodStock.size) { Item(0, 0) }
val maxQty = when (val qpTier = (points / 18) - 1) {
0, 1, 2, 3, 4 -> 1 + qpTier
else -> qpTier + (qpTier + (qpTier - 5)) //5 = 10, 6 = 13, 7 = 15, etc
}
for ((index, item) in foodStock.withIndex()) {
stock[index].id = item.id
stock[index].amount = if (item.id == Items.PIZZA_BASE_2283) 1 else maxQty
}
return stock
}
//Generate default gear stock based on an amount of total QP.
private fun generateGearStock(points: Int): Array<Item> {
val stock = Array(gearStock.size) { Item(0, 0) }
val qpTier = (points / 18)
for ((index, item) in stock.withIndex()) item.id = gearStock[index]
for (i in 0 until min(qpTier, 10)) {
stock[i].amount = 30
stock[i + 10].amount = 5
}
return stock
}
//Default gear shop stock
private val gearStock = arrayOf(
Items.GLOVES_7453,
Items.GLOVES_7454,
Items.GLOVES_7455,
Items.GLOVES_7456,
Items.GLOVES_7457,
Items.GLOVES_7458,
Items.GLOVES_7459,
Items.GLOVES_7460,
Items.GLOVES_7461,
Items.GLOVES_7462,
Items.WOODEN_SPOON_7433,
Items.EGG_WHISK_7435,
Items.SPORK_7437,
Items.SPATULA_7439,
Items.FRYING_PAN_7441,
Items.SKEWER_7443,
Items.ROLLING_PIN_7445,
Items.KITCHEN_KNIFE_7447,
Items.MEAT_TENDERISER_7449,
Items.CLEAVER_7451
)
//Default food shop stock
private val foodStock = arrayOf(
Item(Items.CHOCOLATE_BAR_1973, 1),
Item(Items.CHEESE_1985, 1),
Item(Items.TOMATO_1982, 1),
Item(Items.COOKING_APPLE_1955, 1),
Item(Items.GRAPES_1987, 1),
Item(Items.POT_OF_FLOUR_1933, 1),
Item(Items.PIZZA_BASE_2283, 1),
Item(Items.EGG_1944, 1),
Item(Items.BUCKET_OF_MILK_1927, 1),
Item(Items.POT_OF_CREAM_2130, 1),
Item(Items.PAT_OF_BUTTER_6697, 1),
Item(Items.SPICE_2007, 1),
Item(Items.PIE_DISH_2313, 1),
Item(Items.CAKE_TIN_1887, 1),
Item(Items.BOWL_1923, 1),
Item(Items.JUG_1935, 1),
Item(Items.EMPTY_POT_1931, 1),
Item(Items.EMPTY_CUP_1980, 1),
Item(Items.BUCKET_1925, 1)
)
}
}

View file

@ -1,138 +0,0 @@
package core.game.interaction.item;
import core.cache.def.impl.ItemDefinition;
import core.plugin.Initializable;
import core.game.content.dialogue.DialoguePlugin;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import rs09.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.plugin.Plugin;
/**
* Adds functionality to the pharoah's scepter
* @author ceik
*/
@Initializable
public final class PharoahSceptre extends OptionHandler {
private static final Graphics GRAPHICS = new Graphics(308, 100, 50);
private static final Animation ANIMATION = new Animation(714);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
new SceptreDialog().init();
ItemDefinition.forId(9044).getHandlers().put("option:teleport",this);
ItemDefinition.forId(9046).getHandlers().put("option:teleport",this);
ItemDefinition.forId(9048).getHandlers().put("option:teleport",this);
ItemDefinition.forId(9050).getHandlers().put("option:teleport",this);
return this;
}
@Override
public boolean handle(Player player, Node node, String string){
Item item = node.asItem();
if(string.equals("teleport")){
switch(item.getId()) {
case 9044:
case 9046:
case 9048:
player.getDialogueInterpreter().open(325128389);
return true;
case 9050:
player.getPacketDispatch().sendMessage("You have used up all the charges on this sceptre.");
return true;
}
}
return true;
}
public final class SceptreDialog extends DialoguePlugin {
public SceptreDialog() {
/**
* empty
*/
}
public SceptreDialog(Player player){super(player);}
@Override
public DialoguePlugin newInstance(Player player){ return new SceptreDialog(player);}
@Override
public boolean open(Object... args){
//Item item = (Item) args[0];
player.getPacketDispatch().sendMessage("" + args[0]);
interpreter.sendOptions("Teleport to:","Jalsavrah","Jaleustrophos","Jaldraocht","Nowhere");
return true;
}
public void teleport(Location location, Player player){
player.lock();
player.visualize(ANIMATION, GRAPHICS);
player.getImpactHandler().setDisabledTicks(4);
GameWorld.getPulser().submit(new Pulse(4, player) {
@Override
public boolean pulse() {
player.unlock();
player.getProperties().setTeleportLocation(location);
player.getAnimator().reset();
return true;
}
});
}
@Override
public boolean handle(int interfaceId, int buttonId){
if (player.isTeleBlocked()) {
player.sendMessage("A magical force has stopped you from teleporting.");
return false;
}
switch(buttonId){
case 1:
teleport(Location.create(3289,2786,0), player);
stage = 10;
break;
case 2:
teleport(Location.create(3342,2827,0),player);
stage = 10;
break;
case 3:
teleport(Location.create(3233,2902,0),player);
stage = 10;
break;
case 4:
stage = 20;
break;
}
switch(stage){
case 10:
if(player.getInventory().containsItem(new Item(9044))){
player.getInventory().remove(new Item(9044));
player.getInventory().add(new Item(9046));
player.getPacketDispatch().sendMessage("<col=7f03ff>Your Pharoah's Sceptre has 2 charges remaining.");
end();
} else if (player.getInventory().containsItem(new Item(9046))){
player.getInventory().remove(new Item(9046));
player.getInventory().add(new Item(9048));
player.getPacketDispatch().sendMessage("<col=7f03ff>Your Pharoah's Sceptre has 1 charge remaining.");
end();
} else if (player.getInventory().containsItem(new Item(9048))){
player.getInventory().remove(new Item(9048));
player.getInventory().add(new Item(9050));
player.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has used its last charge.");
end();
}
stage = 20;
break;
case 20:
end();
break;
}
return true;
}
public int[] getIds() { return new int[] {325128389};}
}
}

View file

@ -0,0 +1,110 @@
package core.game.interaction.item
import api.EquipmentSlot
import api.openDialogue
import api.sendMessage
import rs09.game.world.GameWorld.Pulser
import rs09.game.content.activity.pyramidplunder.PyramidPlunderMinigame.Companion.GUARDIAN_ROOM
import core.plugin.Initializable
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.Items
import rs09.game.content.dialogue.DialogueFile
import rs09.game.interaction.InteractionListener
import rs09.tools.END_DIALOGUE
/**
* Adds functionality to the pharoah's scepter
* @author ceik
*/
class PharoahSceptre : InteractionListener() {
override fun defineListeners() {
val SCEPTRES = intArrayOf(Items.PHARAOHS_SCEPTRE_9044, Items.PHARAOHS_SCEPTRE_9046, Items.PHARAOHS_SCEPTRE_9048, Items.PHARAOHS_SCEPTRE_9050)
on(SCEPTRES, ITEM, "teleport", "operate"){player, node ->
val sceptre = node.asItem()
if(sceptre.id == SCEPTRES.last())
{
sendMessage(player, "You have used up all the charges on this sceptre.")
return@on true
}
openDialogue(player, SceptreDialog())
return@on true
}
}
class SceptreDialog : DialogueFile() {
fun teleport(location: Location?, player: Player) {
player.lock()
player.visualize(ANIMATION, GRAPHICS)
player.impactHandler.disabledTicks = 4
Pulser.submit(object : Pulse(4, player) {
override fun pulse(): Boolean {
player.unlock()
player.properties.teleportLocation = location
player.animator.reset()
return true
}
})
}
override fun handle(componentID: Int, buttonID: Int) {
if (player!!.isTeleBlocked) {
player!!.sendMessage("A magical force has stopped you from teleporting.")
return
}
when (stage) {
0 -> options("Jalsavrah", "Jaleustrophos", "Jaldraocht", "Nowhere").also { stage++ }
1 -> {
end()
when (buttonID) {
1 -> {
teleport(GUARDIAN_ROOM, player!!)
}
2 -> {
teleport(Location.create(3342, 2827, 0), player!!)
}
3 -> {
teleport(Location.create(3233, 2902, 0), player!!)
}
4 -> return
}
//This sucks but I'm too lazy to fix it.
if (player!!.equipment.containsItem(Item(9044))) {
player!!.equipment.replace(Item(9046), EquipmentSlot.WEAPON.ordinal)
player!!.packetDispatch.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has 2 charges remaining.")
} else if (player!!.equipment.containsItem(Item(9046))) {
player!!.equipment.replace(Item(9048), EquipmentSlot.WEAPON.ordinal)
player!!.packetDispatch.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has 1 charge remaining.")
} else if (player!!.equipment.containsItem(Item(9048))) {
player!!.equipment.replace(Item(9050), EquipmentSlot.WEAPON.ordinal)
player!!.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has used its last charge.")
} else if (player!!.inventory.containsItem(Item(9050))) {
player!!.inventory.remove(Item(9050))
player!!.inventory.add(Item(9048))
player!!.packetDispatch.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has 2 charges remaining.")
} else if (player!!.inventory.containsItem(Item(9048))) {
player!!.inventory.remove(Item(9048))
player!!.inventory.add(Item(9046))
player!!.packetDispatch.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has 1 charge remaining.")
} else if (player!!.inventory.containsItem(Item(9046))) {
player!!.inventory.remove(Item(9046))
player!!.inventory.add(Item(9044))
player!!.sendMessage("<col=7f03ff>Your Pharoah's Sceptre has used its last charge.")
}
}
}
}
}
companion object {
private val GRAPHICS = Graphics(715)
private val ANIMATION = Animation(714)
}
}

View file

@ -2,7 +2,6 @@ package core.game.interaction.`object`
import api.getUsedOption
import core.game.world.map.RegionManager.getObject
import core.game.content.global.shop.CulinomancerShop.openShop
import core.plugin.Initializable
import core.game.interaction.OptionHandler
import core.plugin.Plugin
@ -24,7 +23,7 @@ class CulinoChestListener : InteractionListener() {
override fun defineListeners() {
on(CULINO_CHEST, SCENERY, "buy-items","buy-food"){player, _ ->
openShop(player, food = getUsedOption(player).toLowerCase() == "buy-food")
CulinomancerShop.openShop(player, food = getUsedOption(player).toLowerCase() == "buy-food")
return@on true
}

View file

@ -1,49 +0,0 @@
package core.game.node.entity.npc.city.sophanem;
import core.plugin.Initializable;
import core.game.content.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
/**
* Stand-in until we get the real dialogue for Tarik
* @author ceik
*/
@Initializable
public class TarikDialogue extends DialoguePlugin {
public TarikDialogue() {
/**
* Empty
*/
}
public TarikDialogue(Player player){super(player);}
@Override
public DialoguePlugin newInstance(Player player) {
return new TarikDialogue(player);
}
@Override
public boolean open(Object... args){
npc("I found this crazy looking pyramid here.","I can't seem to figure out what it's for.","Maybe you should head inside?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId){
switch(stage){
case 0:
player("Oh, alright...");
stage = 1;
break;
case 1:
end();
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 4478 };
}
}

View file

@ -6,9 +6,7 @@ import core.game.container.ContainerType;
import core.game.container.impl.BankContainer;
import core.game.container.impl.EquipmentContainer;
import core.game.container.impl.InventoryListener;
import core.game.content.activity.pyramidplunder.PlunderObjectManager;
import core.game.content.dialogue.DialogueInterpreter;
import core.game.content.ttrail.TreasureTrailManager;
import core.game.interaction.Interaction;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState;
@ -22,7 +20,6 @@ import core.game.node.entity.player.info.RenderInfo;
import core.game.node.entity.player.info.Rights;
import core.game.node.entity.player.info.UIDInfo;
import core.game.node.entity.player.info.login.LoginConfiguration;
import core.game.node.entity.player.info.login.PlayerParser;
import core.game.node.entity.player.link.*;
import core.game.node.entity.player.link.appearance.Appearance;
import core.game.node.entity.player.link.audio.AudioManager;
@ -66,15 +63,12 @@ import core.tools.RandomFunction;
import core.tools.StringUtils;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.json.simple.JSONObject;
import org.rs09.consts.Items;
import rs09.GlobalStats;
import rs09.ServerConstants;
import rs09.game.VarpManager;
import rs09.game.ge.GrandExchangeRecords;
import rs09.game.node.entity.combat.CombatSwingHandler;
import rs09.game.node.entity.combat.equipment.EquipmentDegrader;
import rs09.game.node.entity.player.info.login.PlayerSaveParser;
import rs09.game.node.entity.player.info.login.PlayerSaver;
import rs09.game.node.entity.skill.runecrafting.PouchManager;
import rs09.game.node.entity.state.newsys.State;
@ -242,11 +236,6 @@ public class Player extends Entity {
*/
private final FamiliarManager familiarManager = new FamiliarManager(this);
/**
* Pyramid Plunder Object Manager
*/
private final PlunderObjectManager plunderObjectManager = new PlunderObjectManager();
/**
* The config manager.
*/
@ -376,6 +365,7 @@ public class Player extends Entity {
if (force) {
Repository.getDisconnectionQueue().remove(getName());
}
GameWorld.getLogoutListeners().forEach((it) -> it.logout(this));
setPlaying(false);
getWalkingQueue().reset();
GameWorld.getLogoutListeners().forEach((it) -> it.logout(this));
@ -1250,8 +1240,6 @@ public class Player extends Entity {
return ironmanManager;
}
public PlunderObjectManager getPlunderObjectManager() {return plunderObjectManager;}
/**
* Gets the emoteManager.
* @return the emoteManager.

View file

@ -414,4 +414,9 @@ public final class PacketDispatch {
public void sendScriptConfigs(int id, int value, String type, Object... params) {
PacketRepository.send(CSConfigPacket.class, new CSConfigContext(player, id, value, type, params));
}
public void resetInterface(int id)
{
PacketRepository.send(ResetInterface.class, new InterfaceContext(player, 0, 0, id, false));
}
}

View file

@ -0,0 +1,15 @@
package core.net.packet.out;
import core.net.packet.IoBuffer;
import core.net.packet.OutgoingPacket;
import core.net.packet.context.InterfaceContext;
public class ResetInterface implements OutgoingPacket<InterfaceContext> {
@Override
public void send(InterfaceContext ic) {
IoBuffer buffer = new IoBuffer(149);
buffer.putShort(ic.getPlayer().getInterfaceManager().getPacketCount(1));
buffer.putInt(ic.getInterfaceId());
ic.getPlayer().getSession().write(buffer);
}
}

View file

@ -50,7 +50,7 @@ public class RandomFunction {
* @return true if you hit the roll, false otherwise
*/
public static boolean roll(int chance){
return random(chance) == chance / 2;
return random(chance + 1) == chance / 2;
}
/**

View file

@ -261,7 +261,7 @@ abstract class Cutscene(val player: Player) {
clearNPCs()
player.unhook(CUTSCENE_DEATH_HOOK)
player.logoutListeners.remove("cutscene")
RandomEventManager.getInstance(player)!!.enabled = false
RandomEventManager.getInstance(player)!!.enabled = true
return true
}
}

View file

@ -439,7 +439,7 @@ fun getAudio(id: Int, volume: Int = 10, delay: Int = 1): Audio {
* @param type the type of hit splat to use, ImpactHandler.HitsplatType is an enum containing these options.
*/
fun impact(entity: Entity, amount: Int, type: ImpactHandler.HitsplatType) {
fun impact(entity: Entity, amount: Int, type: ImpactHandler.HitsplatType = ImpactHandler.HitsplatType.NORMAL) {
entity.impactHandler.manualHit(entity, amount, type)
}
@ -855,7 +855,7 @@ fun getVarpValue(player: Player, varpIndex: Int): Int{
*/
fun getVarbitValue(player: Player, varpIndex: Int, offset: Int): Int {
return player.varpManager.get(varpIndex).getVarbitValue(offset)
return player.varpManager.get(varpIndex).getVarbitValue(offset) ?: 0
}
/**

View file

@ -7,37 +7,28 @@ import core.game.node.entity.player.Player
* @author Ceikry
*/
class Varp(val index: Int) {
val varbits = ArrayList<Varbit>()
val varbits = HashMap<Int, Int>()
var save = false
fun setVarbit(offset: Int, value: Int): Varp{
for(vb in varbits){
if (vb.offset == offset){
varbits.remove(vb)
break
}
}
varbits.add(Varbit(value,offset))
varbits[offset] = value
return this
}
fun getValue(): Int{
var config = 0
for(varbit in varbits){
config = config or (varbit.value shl varbit.offset)
for((index,value) in varbits.entries){
config = config or (value shl index)
}
return config
}
fun getVarbit(offset: Int): Varbit?{
for(varbit in varbits){
if(varbit.offset == offset) return varbit
}
return null
fun getVarbit(offset: Int): Int?{
return getVarbitValue(offset)
}
fun getVarbitValue(offset: Int): Int{
return getVarbit(offset)?.value ?: 0
fun getVarbitValue(offset: Int): Int {
return varbits[offset] ?: 0
}
fun send(player: Player){
@ -50,19 +41,15 @@ class Varp(val index: Int) {
}
fun clearBitRange(first : Int, last : Int){
for(varbit in varbits){
if(varbit.offset in first..last){
varbit.value = 0
}
}
for(i in first..last) varbits.remove(i)
}
fun getBitRangeValue(first: Int, last: Int): Int{
var product = 0
for(varbit in varbits){
if(varbit.offset in first..last){
product = product or (varbit.value shl varbit.offset)
}
for (i in first..last)
{
val value = varbits[i] ?: 0
product = product or (value shl i)
}
return product
}

View file

@ -26,7 +26,7 @@ class VarpManager(val player: Player) {
fun set(index: Int, value: Int){
get(index).varbits.clear()
get(index).varbits.add(Varbit(value,0))
get(index).varbits[0] = value
get(index).send(player)
}
@ -35,7 +35,14 @@ class VarpManager(val player: Player) {
}
fun setVarbit(varbitIndex: Int, value: Int){
PacketRepository.send(core.net.packet.out.Varbit::class.java, VarbitContext(player, varbitIndex, value))
val def = VarbitDefinition.forId(varbitIndex)
get(def.configId).setVarbit(def.bitShift, value)
get(def.configId).send(player)
}
fun getVarbit(varbitIndex: Int){
val def = VarbitDefinition.forId(varbitIndex)
get(def.configId).getVarbit(def.bitShift)
}
fun flagSave(index: Int){
@ -70,7 +77,7 @@ class VarpManager(val player: Player) {
val bitArray = JSONArray()
for(varbit in varp.varbits){
val varbitobj = JSONObject()
varbitobj.put("offset",varbit.offset.toString())
varbitobj.put("offset",varbit.key.toString())
varbitobj.put("value",varbit.value.toString())
bitArray.add(varbitobj)
}

View file

@ -60,7 +60,7 @@ enum class AFUBeacon(val title: String, val fmLevel: Int, val varpId: Int, val o
}
fun getState(player: Player): BeaconState{
return BeaconState.values()[player.varpManager.get(varpId).getVarbit(offset)?.value ?: 0]
return BeaconState.values()[player.varpManager.get(varpId).getVarbit(offset) ?: 0]
}
}

View file

@ -123,7 +123,7 @@ class AFURepairClimbHandler : InteractionListener() {
}
fun isRepaired(player: Player): Boolean{
return player.varpManager.get(varp).getVarbit(offset)?.value == 1
return player.varpManager.get(varp).getVarbit(offset) == 1
}
}

View file

@ -18,7 +18,7 @@ class BlastFurnaceInterfaceListener : InterfaceListener() {
on(Components.BLAST_FURNACE_BAR_STOCK_28){ player, _, _, buttonID, _, _ ->
val bar = BFBars.forId(buttonID) ?: return@on false
val isAll = buttonID == bar.allButtonId
val playerAmt = player.varpManager.get(bar.varpIndex).getVarbitValue(bar.offset)
val playerAmt = player.varpManager.get(bar.varpIndex).getVarbitValue(bar.offset) ?: 0
if(playerAmt == 0) return@on true
var amtToWithdraw = if(isAll) playerAmt else 1

View file

@ -0,0 +1,74 @@
package rs09.game.content.activity.pyramidplunder
import api.setAttribute
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.NPCs
import rs09.tools.END_DIALOGUE
@Initializable
class GuardianMummyDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
npcl(FacialExpression.OLD_NOT_INTERESTED, "*sigh* Not another one.")
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> playerl(FacialExpression.HALF_ASKING, "Another what?").also { stage++ }
1 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Another 'archaeologist'. I'm not going to let you plunder my master's tomb you know.").also { stage++ }
2 -> playerl(FacialExpression.NEUTRAL, "That's a shame. Have you got anything else I could do while I'm here?").also { stage++ }
3 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "If it will keep you out of mischief I suppose I could set something up for you... I have a few rooms full of some things you humans might consider valuable, do you want to give it a go?").also { stage++ }
4 -> player.dialogueInterpreter.sendOptions("Play Pyramid Plunder?", "That sounds like fun; what do I do?", "Not right now.", "I know what I'm doing, so let's get on with it.").also { stage++ }
5 -> when(buttonId)
{
1 -> playerl(FacialExpression.FRIENDLY, "That sounds like fun; what do I do?").also { stage = 10 }
2 -> playerl(FacialExpression.NEUTRAL, "Not right now.").also { stage = END_DIALOGUE }
3 -> playerl(FacialExpression.ANNOYED, "I know what I'm doing, so let's get on with it.").also { stage = 100 }
}
10 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "You have five minutes to explore the treasure rooms and collect as many artefacts as you can. The artefacts are in the urns, chests and sarcophagi found in each room.").also { stage++ }
11 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "There are eight treasure rooms, each subsequent room requires higher thieving skills to both enter the room and thieve from the urns and other containers.").also { stage++ }
12 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "The rewards also become more lucrative the further into the tomb you go. You will also have to deactivate a trap in order to enter the main part of each room.").also { stage++ }
13 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "When you want to move onto the next room you need to find the correct door first.").also { stage++ }
14 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "There are four possible exits... you must open the door before finding out whether it is the exit or not. Opening the doors require picking their locks. Having a lockpick will make this easier.").also { stage++ }
15 -> player.dialogueInterpreter.sendOptions("Do you have any more questions?", "How do I leave the game?", "How do I get the artefacts?", "What do I do with the artefacts I collect?", "I'm ready to give it a go now.").also { stage++ }
16 -> when(buttonId)
{
1 -> playerl(FacialExpression.FRIENDLY, "How do I leave the game?").also { stage = 20 }
2 -> playerl(FacialExpression.FRIENDLY, "How do I get the artefacts?").also { stage = 30 }
3 -> playerl(FacialExpression.FRIENDLY, "What do I do with the artefacts?").also { stage = 40 }
4 -> playerl(FacialExpression.FRIENDLY, "I'm ready to give it a go now.").also { stage = 100 }
}
20 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "If at any point you decide you need to leave just use a glowing door. The game will end and you will be taken out of the pyramid").also { stage = 15 }
30 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "The artefacts are in the urns, chests and sarcophagi. Urns contain snakes that guard them. The sarcophagi take some strength to open. They take a while to open.").also { stage++ }
31 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Of course, Mummies have been known to take a nap in the sarcophagi, so beware. The golden chests generally contain better artefacts, but are also trapped with scarabs!").also { stage = 15 }
40 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "There are a number of different artefacts, of three main types. The least valuable are the pottery statuettes and scarabs, and the ivory combs.").also { stage++ }
41 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Next are the stone scarabs, statuettes and seals, and finally the gold versions of those artefacts. They are not old, but are well made.").also { stage++ }
42 -> playerl(FacialExpression.HALF_ASKING, "What do I do with artefacts once I've collected them?").also { stage++ }
43 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "That Simon Simpleton, I mean Templeton, will probably give you some money for them. He couldn't spot a real artefact if it came up to him and bit him in the face.").also { stage++ }
44 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "He usually slinks about near the pyramid north-east of Sophanem. I expect he's trying to get some poor fools to steal things from that pyramid as well.").also { stage = 15 }
100 -> npcl(FacialExpression.OLD_NOT_INTERESTED, "Alright, fine.").also { stage++ }
101 -> {
end()
PyramidPlunderMinigame.join(player)
setAttribute(player, "/save:pp:mummy-spoken-to", true)
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.GUARDIAN_MUMMY_4476)
}
override fun newInstance(player: Player?): DialoguePlugin {
return GuardianMummyDialogue(player)
}
}

View file

@ -0,0 +1,45 @@
package rs09.game.content.activity.pyramidplunder
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.world.map.Direction
import core.game.world.map.Location
import org.rs09.consts.Items
/**
* An object that simply contains Pyramid Plunder data.
*/
object PlunderData {
val playerLocations = HashMap<Player, PlunderRoom>()
val players = ArrayList<Player>()
val doorVarbits = arrayOf(2366, 2367, 2368, 2369)
val doors = Array(8){doorVarbits[0]}
val timeLeft = HashMap<Player, Int>()
val pyramidEntranceVarbits = arrayOf(2371,2372,2373,2374)
var currentEntrance = pyramidEntranceVarbits.random()
var nextEntranceSwitch = 0L
val mummy = NPC(4476, Location.create(1968, 4428, 2)).also { it.isNeverWalks = true; it.init() }
val artifacts = arrayOf(
arrayOf(Items.IVORY_COMB_9026, Items.POTTERY_SCARAB_9032, Items.POTTERY_STATUETTE_9036),
arrayOf(Items.STONE_SCARAB_9030, Items.STONE_STATUETTE_9038, Items.STONE_SEAL_9042),
arrayOf(Items.GOLDEN_SCARAB_9028, Items.GOLDEN_STATUETTE_9034, Items.GOLD_SEAL_9040)
)
val rooms = arrayOf(
PlunderRoom(1, Location.create(1927, 4477, 0), Location.create(1929, 4469, 0), Direction.SOUTH),
PlunderRoom(2, Location.create(1954, 4477, 0), Location.create(1955, 4467, 0), Direction.SOUTH),
PlunderRoom(3, Location.create(1977, 4471, 0), Location.create(1975, 4458, 0), Direction.SOUTH),
PlunderRoom(4, Location.create(1927, 4453, 0), Location.create(1937, 4454, 0), Direction.EAST),
PlunderRoom(5, Location.create(1965, 4444, 0), Location.create(1955, 4449, 0), Direction.WEST),
PlunderRoom(6, Location.create(1927, 4424, 0), Location.create(1925, 4433, 0), Direction.NORTH),
PlunderRoom(7, Location.create(1943, 4421, 0), Location.create(1950, 4427, 0), Direction.NORTH),
PlunderRoom(8, Location.create(1974, 4420, 0), Location.create(1971, 4431, 0), Direction.NORTH)
)
}
/**
* A simple way to represent a pyramid plunder room.
*/
data class PlunderRoom(val room: Int, val entrance: Location, val mummyLoc: Location, val spearDirection: Direction)

View file

@ -1,89 +0,0 @@
package rs09.game.content.activity.pyramidplunder
import core.game.component.Component
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.tools.RandomFunction
import org.rs09.consts.Components
import rs09.game.world.GameWorld
class PlunderSession(val player: Player) {
var door1Open: Boolean = false
var door2Open: Boolean = false
var door3Open: Boolean = false
var door4Open: Boolean = false
var chestHidden: Boolean = false
var chestOpen: Boolean = false
var coffinHidden: Boolean = false
var coffinOpen: Boolean = false
var timeCounter: Int = 1
var correctDoorIndex: Int = RandomFunction.random(1000) % 4
var isActive = false
fun init(){
player.setAttribute("plunder-session",this)
GameWorld.Pulser.submit(PlunderPulse(player))
player.interfaceManager.openOverlay(Component(Components.NTK_OVERLAY_428))
isActive = true
}
fun updateOverlay(){
player.configManager.set(821,getConfig())
}
fun resetVars(){
chestOpen = false
chestHidden = false
coffinHidden = false
coffinOpen = false
door1Open = false
door2Open = false
door3Open = false
door4Open = false
correctDoorIndex = RandomFunction.random(1000) % 4
}
fun getConfig(): Int{
var config = 0
if(coffinOpen) config = 1
if(coffinHidden) config = (config or (1 shl 1))
if(chestOpen) config = (config or (1 shl 2))
if(chestHidden) config = (config or (1 shl 3))
if(door1Open) config = (config or (1 shl 9))
if(door2Open) config = (config or (1 shl 10))
if(door3Open) config = (config or (1 shl 11))
if(door4Open) config = (config or (1 shl 12))
return (config or (timeCounter shl 25))
}
fun setDoorOpen(index: Int){
when(index){
0 -> door1Open = true
1 -> door2Open = true
2 -> door3Open = true
3 -> door4Open = true
}
}
class PlunderPulse(val player: Player) : Pulse(){
var ticks = 0
var overlayConfig = 0
val session: PlunderSession? = player.getAttribute("plunder-session",null)
override fun pulse(): Boolean {
session ?: return false
if(ticks++ % 8 == 0){
session.timeCounter++
session.updateOverlay()
}
if(session.timeCounter > 63){
player.properties.teleportLocation = Location.create(3286, 2803, 0)
player.dialogueInterpreter.sendDialogue("You ran out of time and the mummy kicked you","out.")
player.configManager.set(822,0)
player.configManager.set(821,0)
}
return session.timeCounter > 63 || !session.isActive
}
}
}

View file

@ -0,0 +1,302 @@
package rs09.game.content.activity.pyramidplunder
import api.*
import core.game.component.Component
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.world.map.Direction
import core.game.world.map.Location
import core.tools.RandomFunction
import org.rs09.consts.Components
import org.rs09.consts.Items
/**
* A collection of methods needed for Pyramid Plunder.
*/
object PlunderUtils {
fun hasPlayer(player: Player): Boolean
{
return PlunderData.playerLocations[player] != null
}
fun registerPlayer(player: Player)
{
PlunderData.players.add(player)
PlunderData.timeLeft[player] = 500 //5 minutes
}
fun unregisterPlayer(player: Player)
{
PlunderData.players.remove(player)
PlunderData.playerLocations.remove(player)
PlunderData.timeLeft.remove(player)
}
fun expel(player: Player, summonMummy: Boolean)
{
teleport(player, Location.create(3288, 2802, 0))
unregisterPlayer(player)
resetOverlay(player)
resetObjectVarbits(player)
if(!summonMummy)
{
sendDialogue(player, "You've run out of time and the guardian mummy has thrown you out.")
}
else
{
sendDialogue(player, "You've been expelled by the guardian mummy.")
}
}
fun decrementTimeRemaining() : ArrayList<Player>
{
val timesUp = ArrayList<Player>()
PlunderData.timeLeft.forEach { player, left ->
if(left <= 0) timesUp.add(player)
PlunderData.timeLeft[player] = left - 1
updateOverlay(player)
}
return timesUp
}
fun loadNextRoom(player: Player)
{
val current = PlunderData.playerLocations[player]
val next: PlunderRoom = if(current == null)
getRoom(1)
else
getRoom(current.room + 1)
if(PlunderData.playerLocations.filter { it.value == next }.isEmpty()) //if no one is in the next room
{
PlunderData.doors[next.room - 1] = PlunderData.doorVarbits.random() //reshuffle the next room's exit door
}
teleport(player, next.entrance)
PlunderData.playerLocations[player] = next
}
fun getRoom(number: Int) : PlunderRoom
{
return PlunderData.rooms[number - 1]
}
fun getRoom(player: Player): PlunderRoom?
{
return PlunderData.playerLocations[player]
}
fun getRoomLevel(player: Player): Int
{
return 11 + (10 * getRoom(player)!!.room)
}
fun getSpearDestination(player: Player): Location
{
val room = getRoom(player)!!
return when(room.spearDirection)
{
Direction.NORTH -> player.location.transform(0, 3, 0)
Direction.SOUTH -> player.location.transform(0, -3, 0)
Direction.WEST -> player.location.transform(-3, 0, 0)
Direction.EAST -> player.location.transform(3, 0, 0)
else -> player.location
}
}
fun getUrnXp(player: Player, check: Boolean): Double
{
val room = getRoom(player)!!.room
return if(check)
{
when(room)
{
1 -> 20.0
2 -> 30.0
3 -> 50.0
4 -> 70.0
5 -> 100.0
6 -> 150.0
7 -> 225.0
8 -> 275.0
else -> 0.0
}
}
else
{
when(room)
{
1 -> 60.0
2 -> 90.0
3 -> 150.0
4 -> 215.0
5 -> 300.0
6 -> 450.0
7 -> 675.0
8 -> 825.0
else -> 0.0
}
}
}
fun resetObjectVarbits(player: Player)
{
var varp = player.varpManager.get(821)
varp.clear()
varp.send(player)
varp = player.varpManager.get(820)
varp.clear()
varp.send(player)
PlunderData.doorVarbits.forEach { player.varpManager.setVarbit(it, 0) }
}
fun openOverlay(player: Player)
{
player.interfaceManager.openOverlay(Component(Components.NTK_OVERLAY_428))
updateOverlay(player)
}
fun updateOverlay(player: Player)
{
player.varpManager.setVarbit(2375, 500 - (PlunderData.timeLeft[player] ?: 0))
player.varpManager.setVarbit(2376, 11 + (getRoom(player)!!.room * 10))
player.varpManager.setVarbit(2377, getRoom(player)!!.room)
}
fun resetOverlay(player: Player)
{
player.varpManager.setVarbit(2375, 0)
player.packetDispatch.resetInterface(Components.NTK_OVERLAY_428)
player.interfaceManager.closeOverlay()
}
fun getDoor(player: Player) : Int
{
val room = getRoom(player)!!.room
return PlunderData.doors[room - 1]
}
fun rollSceptre(player: Player): Boolean
{
val room = getRoom(player)!!.room
val chance = when(room)
{
1 -> 1500
2 -> 1350
3 -> 1250
4 -> 1150
else -> 1000
}
if(RandomFunction.roll(chance))
{
expel(player, true)
runTask(player, 2)
{
addItemOrDrop(player, Items.PHARAOHS_SCEPTRE_9050)
sendNews("${player.username} has received a Pharaoh's Sceptre while doing Pyramid Plunder!")
}
return true
}
return false
}
fun getSarcophagusXp(player: Player) : Double
{
val room = getRoom(player)!!.room
return when(room)
{
1 -> 20.0
2 -> 30.0
3 -> 50.0
4 -> 70.0
5 -> 100.0
6 -> 150.0
7 -> 225.0
8 -> 275.0
else -> 0.0
}
}
fun getChestXp(player: Player): Double
{
val room = getRoom(player)!!.room
return when(room)
{
1 -> 60.0
2 -> 90.0
3 -> 150.0
4 -> 215.0
5 -> 300.0
6 -> 450.0
7 -> 675.0
8 -> 825.0
else -> 0.0
} * 0.66
}
fun getDoorXp(player: Player, lockpick: Boolean) : Double
{
val room = getRoom(player)!!.room
var reward = when(room)
{
1 -> 60.0
2 -> 90.0
3 -> 150.0
4 -> 215.0
5 -> 300.0
6 -> 450.0
7 -> 675.0
8 -> 825.0
else -> 0.0
} * 0.66
if(lockpick)
reward /= 2.0
return reward
}
fun rollArtifact(player: Player, tier: Int) : Int
{
//tier 1 -> urn
//tier 2 -> sarcophagus
//tier 3 -> chest
val room = getRoom(player)!!.room
val divisor = (room * 2) * (tier * 35)
val goldRate = divisor / 650
val stoneRate = divisor / 250
val roll = RandomFunction.RANDOM.nextDouble()
if(goldRate > roll)
return PlunderData.artifacts[2].random()
if(stoneRate > roll)
return PlunderData.artifacts[1].random()
return PlunderData.artifacts[0].random()
}
fun checkEntranceSwitch()
{
if(System.currentTimeMillis() > PlunderData.nextEntranceSwitch)
{
PlunderData.currentEntrance = PlunderData.pyramidEntranceVarbits.random()
PlunderData.nextEntranceSwitch = System.currentTimeMillis() + (60000 * 15)
}
}
fun checkEntrance(door: Node): Boolean
{
return door.asScenery().definition.varbitID == PlunderData.currentEntrance
}
fun rollUrnSuccess(player: Player, charmed: Boolean = false): Boolean
{
val level = getDynLevel(player, Skills.THIEVING)
val room = getRoom(player)!!.room
return RandomFunction.random(level) > (room * if(charmed) 2 else 4)
}
}

View file

@ -0,0 +1,385 @@
package rs09.game.content.activity.pyramidplunder
import api.*
import core.game.content.activity.pyramidplunder.PyramidPlunderMummyNPC
import core.game.content.activity.pyramidplunder.PyramidPlunderSwarmNPC
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.entity.state.EntityState
import core.game.system.task.Pulse
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.tools.RandomFunction
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import org.rs09.consts.Scenery
import rs09.game.content.dialogue.DialogueFile
import rs09.game.interaction.InteractionListener
/**
* The "controller" class for pyramid plunder. Handles per-tick updates, logout hooks, and defines interaction listeners for the minigame.
* @author Ceikry
*/
class PyramidPlunderMinigame : InteractionListener(), TickListener, LogoutListener {
override fun tick() {
val playersToExpel = PlunderUtils.decrementTimeRemaining()
playersToExpel.forEach {player -> PlunderUtils.expel(player, false) }
PlunderUtils.checkEntranceSwitch()
}
override fun logout(player: Player) {
if(PlunderUtils.hasPlayer(player))
{
player.location = Location.create(3288, 2802, 0)
PlunderUtils.unregisterPlayer(player)
}
}
override fun defineListeners() {
val CHECK_ANIM = 3572
val URN_CHECK = 4340
val URN_BIT = 4341
val URN_SUCCESS = 4342
val PUSH_LID_START = 4343
val PUSH_LID_LOOP = 4344
val PUSH_LID_FINISH = 4345
val CHARM_ANIM = 1877
val OPEN_CHEST_ANIM = 536
val SPEAR_OBJ_ANIM = 459
val SNAKE_URN_ANIM = 4335
val SEALED_URNS = intArrayOf(Scenery.URN_16501, Scenery.URN_16502, Scenery.URN_16503)
val OPEN_URNS = intArrayOf(Scenery.URN_16505, Scenery.URN_16506, Scenery.URN_16507)
val SNAKE_URNS = intArrayOf(Scenery.URN_16509, Scenery.URN_16510, Scenery.URN_16511)
val CHARMED_SNAKES = intArrayOf(Scenery.URN_16513, Scenery.URN_16514, Scenery.URN_16515)
val ENTRANCES = intArrayOf(16484, 16487, 16490, 16493) //All Scenery.AN_ANONYMOUS_LOOKING_DOOR_16484/etc
val SARCOPHAGUS = Scenery.SARCOPHAGUS_16495
on(Scenery.SPEARTRAP_16517, SCENERY, "pass"){player, node ->
val anim = Animation(CHECK_ANIM)
val duration = animationDuration(anim)
if(player.skills.getStaticLevel(Skills.THIEVING) < PlunderUtils.getRoomLevel(player))
{
sendDialogue(player, "You need a Thieving level of ${PlunderUtils.getRoomLevel(player)} to do that.")
return@on true
}
val spearDir = PlunderUtils.getRoom(player)!!.spearDirection
val pastSpears = (spearDir == Direction.NORTH && player.location.y > node.location.y)
|| (spearDir == Direction.SOUTH && player.location.y < node.location.y)
|| (spearDir == Direction.EAST && player.location.x > node.location.x)
|| (spearDir == Direction.WEST && player.location.x < node.location.x)
if(pastSpears)
{
sendDialogue(player, "I have no reason to do that.")
return@on true
}
animate(player, anim)
sendMessage(player, "You carefully try to temporarily disable the trap.")
player.pulseManager.run(object : Pulse(duration) {
override fun pulse(): Boolean {
if(RandomFunction.roll(5))
{
val dest = PlunderUtils.getSpearDestination(player)
player.walkingQueue.reset()
player.walkingQueue.addPath(dest.x,dest.y)
rewardXP(player, Skills.THIEVING, 10.0)
return true
}
if(RandomFunction.roll(20))
{
animateScenery(node.asScenery(), SPEAR_OBJ_ANIM)
impact(player, RandomFunction.random(1,5))
sendChat(player, "Ouch!")
sendMessage(player, "You fail to disable the trap.")
return true
}
animate(player, anim)
return false
}
})
return@on true
}
on(intArrayOf(*SEALED_URNS, *SNAKE_URNS), SCENERY, "search") { player, node ->
animate(player, URN_CHECK)
player.faceLocation(node.location)
player.lock()
runTask(player, 1) {
player.unlock()
if(!PlunderUtils.rollUrnSuccess(player))
{
animate(player, URN_BIT)
sendMessage(player, "You've been bitten by something moving around in the urn.")
impact(player, RandomFunction.random(1,5))
player.stateManager.register(EntityState.POISONED, true, 20, player)
}
else {
animate(player, URN_SUCCESS)
sendMessage(player, "You successfully loot the urn.")
rewardXP(player, Skills.THIEVING, PlunderUtils.getUrnXp(player, false))
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 1))
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
}
player.unlock()
}
return@on true
}
on(SEALED_URNS, SCENERY, "check for snakes") { player, node ->
val urn = node.asScenery()
animate(player, URN_CHECK)
player.faceLocation(node.location)
player.lock()
runTask(player, 1){
player.unlock()
animate(player, URN_BIT)
player.varpManager.setVarbit(urn.definition.varbitID, 2)
animateScenery(urn, SNAKE_URN_ANIM)
}
return@on true
}
on(SNAKE_URNS, SCENERY, "charm snake") { player, node ->
if(!inInventory(player, Items.SNAKE_CHARM_4605))
{
sendMessage(player, "You need a snake charm to charm a snake.")
return@on true
}
lock(player, 2)
animate(player, CHARM_ANIM)
runTask(player, 1)
{
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 3)
sendMessage(player, "You charm the snake with your music.")
}
return@on true
}
on(CHARMED_SNAKES, SCENERY, "search") { player, node ->
animate(player, URN_CHECK)
player.faceLocation(node.location)
player.lock()
runTask(player, 1) {
player.unlock()
if(!PlunderUtils.rollUrnSuccess(player, true))
{
animate(player, URN_BIT)
sendMessage(player, "You've been bitten by something moving around in the urn.")
impact(player, RandomFunction.random(1,5))
player.stateManager.register(EntityState.POISONED, true, 20, player)
}
else {
animate(player, URN_SUCCESS)
sendMessage(player, "You successfully loot the urn.")
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 1))
rewardXP(player, Skills.THIEVING, PlunderUtils.getUrnXp(player, false) * 0.66)
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
}
player.unlock()
}
return@on true
}
on(OPEN_URNS, SCENERY, "search") { player, _ ->
sendMessage(player, "You've already looted this urn.")
return@on true
}
on(SARCOPHAGUS, SCENERY, "open") { player, node ->
sendMessage(player, "You attempt to push open the massive lid.")
val strength = getDynLevel(player, Skills.STRENGTH)
animate(player, PUSH_LID_START)
player.pulseManager.run(object : Pulse(2)
{
override fun pulse(): Boolean {
animate(player, PUSH_LID_LOOP)
if(RandomFunction.random(125) > strength)
return false
animate(player, PUSH_LID_FINISH)
runTask(player, 3){
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
rewardXP(player, Skills.STRENGTH, PlunderUtils.getSarcophagusXp(player))
if(RandomFunction.roll(25))
{
val mummy = PyramidPlunderMummyNPC(player.location, player)
mummy.isRespawn = false
mummy.init()
mummy.attack(player)
}
else if(!PlunderUtils.rollSceptre(player))
{
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 2))
}
player.unlock()
}
return true
}
})
return@on true
}
on(Scenery.GRAND_GOLD_CHEST_16473, SCENERY, "search") { player, node ->
animate(player, OPEN_CHEST_ANIM)
runTask(player){
if(RandomFunction.roll(25))
{
val swarm = PyramidPlunderSwarmNPC(player.location, player)
swarm.isRespawn = false
swarm.init()
swarm.attack(player)
impact(player, RandomFunction.random(1,5))
}
else
{
rewardXP(player, Skills.THIEVING, PlunderUtils.getChestXp(player))
if(!PlunderUtils.rollSceptre(player))
addItemOrDrop(player, PlunderUtils.rollArtifact(player, 3))
}
player.varpManager.setVarbit(node.asScenery().definition.varbitID, 1)
}
return@on true
}
on(Scenery.TOMB_DOOR_16475, SCENERY, "pick-lock") { player, node ->
val anim = Animation(CHECK_ANIM)
val duration = animationDuration(anim)
if(PlunderUtils.getRoom(player)!!.room == 8)
{
sendMessage(player, "This is the final room. I should probably just leave instead.")
return@on true
}
animate(player, anim)
player.lock()
val rate =
if(inInventory(player, Items.LOCKPICK_1523))
{
sendMessage(player, "You attempt to open the door.")
2
}
else
{
sendMessage(player, "You attempt to open the door. Lockpicks would make it easier...")
3
}
runTask(player, duration){
player.unlock()
if(RandomFunction.roll(rate))
{
val varbitId = node.asScenery().definition.varbitID
rewardXP(player, Skills.THIEVING, PlunderUtils.getDoorXp(player, rate == 3))
if(PlunderUtils.getDoor(player) == varbitId) {
PlunderUtils.loadNextRoom(player)
PlunderUtils.resetObjectVarbits(player)
} else {
sendMessage(player, "The door leads to a dead end.")
player.varpManager.setVarbit(varbitId, 1)
}
}
else
{
sendMessage(player, "Your attempt fails.")
}
}
return@on true
}
on(Scenery.TOMB_DOOR_16458, SCENERY, "leave tomb") { player, _ ->
openDialogue(player, object : DialogueFile()
{
override fun handle(componentID: Int, buttonID: Int) {
when(stage)
{
0 -> options("Yes, I'm sure I want to leave.", "No, never mind.").also { stage++ }
1 -> when(buttonID)
{
1 -> {
end()
teleport(player, Location.create(3288, 2802, 0))
PlunderUtils.unregisterPlayer(player)
PlunderUtils.resetOverlay(player)
PlunderUtils.resetObjectVarbits(player)
}
2 -> end()
}
}
}
})
return@on true
}
on(ENTRANCES, SCENERY, "search") { player, door ->
if(!getAttribute(player, "tarik-spoken-to", false))
{
sendDialogue(player, "I should probably try to find out more about this place before I try to break in.")
return@on true
}
val anim = Animation(CHECK_ANIM)
val duration = animationDuration(anim)
animate(player, anim)
sendMessage(player, "You use your thieving skills to search the stone panel.")
player.pulseManager.run(object : Pulse(duration){
override fun pulse(): Boolean {
if(RandomFunction.roll(3))
{
setAttribute(player, "pyramid-entrance", player.location.transform(0,0,0))
sendMessage(player, "You find a door! You open it.")
if(PlunderUtils.checkEntrance(door)) {
teleport(player, GUARDIAN_ROOM)
rewardXP(player, Skills.THIEVING, 20.0)
}
else
teleport(player, EMPTY_ROOM)
return true
}
animate(player, anim)
return false
}
})
return@on true
}
on(Scenery.TOMB_DOOR_16459, SCENERY, "leave tomb") { player, _ ->
teleport(player, getAttribute(player, "pyramid-entrance", Location.create(3288, 2802, 0)))
return@on true
}
on(NPCs.GUARDIAN_MUMMY_4476, NPC, "start-minigame") { player, _ ->
if(!getAttribute(player, "pp:mummy-spoken-to", false))
{
openDialogue(player, NPCs.GUARDIAN_MUMMY_4476)
return@on true
}
join(player)
return@on true
}
}
companion object {
@JvmStatic val GUARDIAN_ROOM = Location.create(1968, 4420, 2)
@JvmStatic val EMPTY_ROOM = Location.create(1934, 4450, 2)
@JvmStatic fun join(player: Player)
{
if(PlunderUtils.hasPlayer(player))
{
sendMessage(player, "[PLUNDER] You should never see this message. Please report this.")
return
}
PlunderUtils.registerPlayer(player)
PlunderUtils.loadNextRoom(player)
PlunderUtils.openOverlay(player)
}
}
}

View file

@ -29,6 +29,7 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
player.hook(Event.Tick, instance)
setAttribute(player, "random-manager", instance)
instance.rollNextSpawn()
instance.enabled = true
SystemLogger.logRE("Initialized REManager for ${player.username}.")
}

View file

@ -74,7 +74,7 @@ object DrillDemonUtils {
}
fun getMatTask(id: Int, player: Player): Int{
return player.varpManager.get(DD_SIGN_VARP).getVarbitValue(getOffsetForID(id))
return player.varpManager.get(DD_SIGN_VARP).getVarbitValue(getOffsetForID(id)) ?: 0
}
fun cleanup(player: Player){

View file

@ -0,0 +1,82 @@
package rs09.game.content.dialogue.region.sophanem
import api.setAttribute
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.player.Player
import core.plugin.Initializable
import org.rs09.consts.NPCs
import rs09.tools.END_DIALOGUE
@Initializable
class TarikDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
npcl(FacialExpression.WORRIED, "Ouch!")
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage)
{
0 -> playerl(FacialExpression.HALF_WORRIED, "Are you alright?").also { stage++ }
1 -> npcl(FacialExpression.FRIENDLY, "I'm fine, I'm fine. Just a scratch.").also { stage++ }
2 -> options("Who are you then?","How did you injure yourself?","Do you know anything about this pyramid?").also { stage++ }
3 -> when(buttonId) {
1 -> playerl(FacialExpression.FRIENDLY, "Who are you then?").also { stage = 10 }
2 -> playerl(FacialExpression.HALF_WORRIED, "How did you injure yourself?").also { stage = 20 }
3 -> playerl(FacialExpression.HALF_ASKING, "So what's in the pyramid?").also { stage = 30 }
}
//Who are you
10 -> npcl(FacialExpression.FRIENDLY, "Me? I'm Tarik.").also { stage++ }
11 -> playerl(FacialExpression.HALF_ASKING, "That hat you're wearing doesn't look like it comes from around here?").also { stage++ }
12 -> npcl(FacialExpression.FRIENDLY, "It was a present, my employer thought it would suit me. I'm not sure what it does, though it does keep the sun off very well.").also { stage++ }
13 -> playerl(FacialExpression.FRIENDLY, "Who is your employer then?").also { stage++ }
14 -> npcl(FacialExpression.FRIENDLY, "Simon Templeton, though I haven't seen him since the town gates were closed off.").also { stage++ }
15 -> playerl(FacialExpression.HALF_THINKING, "Simon Templeton ... that name seems familiar?").also { stage++ }
16 -> npcl(FacialExpression.FRIENDLY, "He's an archaeologist, I worked as an assistant for him. Though I work for myself now.").also { stage++ }
17 -> playerl(FacialExpression.FRIENDLY, "So what have you been up to?").also { stage++ }
18 -> npcl(FacialExpression.FRIENDLY, "Simon suggested that there might be riches to be found in that pyramid over there.").also { stage = 30 }
//How did you injure yourself
20 -> npcl(FacialExpression.NEUTRAL, "I've been investigating that pyramid over there.").also { stage = 30 }
//Do you know anything about this pyramid?
30 -> npcl(FacialExpression.HALF_THINKING, "Well, I'm not sure. First of all there's something odd about the doors on the place. There's four of them - but three of them lead to an empty tomb. The other one is guarded by something.").also { stage++ }
31 -> npcl(FacialExpression.THINKING, "If I make it through the door there's a Mummy waiting. But which door the right one is seems to change, it's all quite confusing.").also { stage++ }
32 -> playerl(FacialExpression.HALF_ASKING, "What about this Mummy?").also { stage++ }
33 -> npcl(FacialExpression.FRIENDLY, "I don't think he likes people. However he does allow you to enter some of the rooms in the tomb. They are dangerous though.").also { stage++ }
34 -> playerl(FacialExpression.HAPPY, "Bah, I laugh in the face of danger!").also { stage++ }
35 -> npcl(FacialExpression.FRIENDLY, "Well, if you go into that pyramid then you'll be laughing a lot then. It's full of poisonous snakes and scarabs, and rather nasty Mummies as well. You could die in there.").also { stage++ }
36 -> npcl(FacialExpression.FRIENDLY, "I managed to get into one room, but the next room was harder. My lockpicking skills weren't good enough, maybe I should have brought a lockpick.").also { stage++ }
37 -> api.sendDialogue(player, "The first room in the pyramid requires a thieving level of 21. Each subsequent room requires an extra 10 levels to enter.").also { stage++ }
38 -> npcl(FacialExpression.NEUTRAL, "There are also lots of poisonous snakes in the urns. They'll bite you if they can. You might be able to charm them if you know how. I'd bring some antipoison anyway if I were you.").also { stage++ }
39 -> playerl(FacialExpression.FRIENDLY, "It all sounds like fun to me. So is there anything valuable in there?").also { stage++ }
40 -> npcl(FacialExpression.NEUTRAL, "There are lots of artefacts, you should be able to sell them on the black market, I mean, to a legitimate trader, for some money.").also { stage++ }
41 -> playerl(FacialExpression.NEUTRAL, "You mean Simon Templeton?").also { stage++ }
42 -> npcl(FacialExpression.NEUTRAL, "Well, he's a 'legitimate' as you can get, if you can get out of this city and get to him.").also { stage++ }
43 -> playerl(FacialExpression.FRIENDLY, "I'll find a way. Is there anything else of value in there?").also { stage++ }
44 -> npcl(FacialExpression.SUSPICIOUS, "I have heard a rumour that there is a valuable magic sceptre in there as well.").also { stage++ }
45 -> playerl(FacialExpression.HALF_THINKING, "Ah, now you have piqued my interest. What do you know about this sceptre?").also { stage++ }
46 -> npcl(FacialExpression.SUSPICIOUS, "Not a lot. It is apparently made of gold and covered in jewels, and used to be owned by one of Tumeken's sons.").also { stage++ }
47 -> playerl(FacialExpression.HALF_ASKING, "Tumeken?").also { setAttribute(player, "/save:tarik-spoken-to", true); stage++ }
48 -> npcl(FacialExpression.NEUTRAL, "Tumeken, the sun god and head of the gods. His sons were the rulers, chosen by him to rule in his name.").also { stage++ }
49 -> playerl(FacialExpression.HALF_THINKING, "So these sons were rich and powerful then? This sceptre should be pretty good then.").also { stage++ }
50 -> npcl(FacialExpression.NEUTRAL, "Hmmm. Well it is supposed to have some magical powers.").also { stage++ }
51 -> playerl(FacialExpression.HALF_ASKING, "Magical powers? This sounds good. What are they?").also { stage++ }
52 -> npcl(FacialExpression.LAUGH, "I'll let you know when I find it!").also { stage++ }
53 -> playerl(FacialExpression.ANNOYED, "Not if I find it first!").also { stage++ }
54 -> npcl(FacialExpression.FRIENDLY, "Hey! If you find it I deserve a share of the profits! You wouldn't have known it existed without my help.").also { stage++ }
55 -> playerl(FacialExpression.NEUTRAL, "I'll think about it... Right, I think I'd better investigate this place.").also { stage = END_DIALOGUE }
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.TARIK_4478)
}
override fun newInstance(player: Player?): DialoguePlugin {
return TarikDialogue(player)
}
}

View file

@ -52,7 +52,7 @@ class PlayerSaveParser(val player: Player) {
}
}
fun parse() = GlobalScope.launch {
fun parse() {
if (read) {
parseCore()
parseAttributes()

View file

@ -88,7 +88,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
}
fun getCurrentState(): Int{
return player.varpManager.get(patch.varpIndex).getVarbitValue(patch.varpOffset)
return player.varpManager.get(patch.varpIndex).getVarbitValue(patch.varpOffset) ?: 0
}
fun setCurrentState(state: Int){

View file

@ -188,7 +188,7 @@ class VisualCommand : CommandPlugin() {
player!!.debug("syntax error: x y id")
return true
}
location = if (args.size > 2) Location.create(args[1]!!.toInt(), args[2]!!.toInt(), 3) else player!!.location
location = if (args.size > 2) Location.create(args[1]!!.toInt(), args[2]!!.toInt(), player!!.location.z) else player!!.location
`object` = RegionManager.getObject(location)
if (`object` == null) {
player!!.debug("error: object not found in region cache.")

View file

@ -1,16 +1,25 @@
package rs09.game.system.command.sets
import api.sendMessage
import core.cache.Cache
import core.cache.def.impl.NPCDefinition
import core.cache.def.impl.VarbitDefinition
import core.game.node.entity.combat.ImpactHandler.HitsplatType
import core.game.node.entity.npc.drop.NPCDropTables
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.SpellBookManager
import core.game.node.item.Item
import core.net.packet.context.PlayerContext
import core.net.packet.out.ResetInterface
import core.net.packet.out.Varbit
import core.plugin.Initializable
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.rs09.consts.Items
import rs09.game.content.global.NPCDropTable
import rs09.game.system.command.Command
import rs09.game.system.command.Privilege
import rs09.net.packet.PacketWriteQueue
@Initializable
class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
@ -57,5 +66,28 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
container.open(player)
}
define("varbits") { player, args ->
if(args.size < 2)
reject(player, "Usage: ::list_varbits varpIndex")
val varp = args[1].toIntOrNull() ?: reject(player, "Please use a valid int for the varpIndex.")
GlobalScope.launch {
sendMessage(player, "========== Found Varbits for Varp $varp ==========")
for(id in 0 until 10000)
{
val def = VarbitDefinition.forId(id)
if(def.configId == varp)
{
sendMessage(player, "${def.id} -> [offset: ${def.bitShift}, upperBound: ${def.bitSize}]")
}
}
sendMessage(player, "=========================================")
}
}
define("testpacket") { player, _ ->
PacketWriteQueue.write(ResetInterface(), PlayerContext(player))
}
}
}

View file

@ -27,7 +27,6 @@ import rs09.game.content.ame.RandomEvents
import rs09.game.ge.GrandExchange
import rs09.game.node.entity.state.newsys.states.FarmingState
import rs09.game.system.SystemLogger
import rs09.game.system.command.Command
import rs09.game.system.command.CommandMapping
import rs09.game.system.command.Privilege
import rs09.game.world.repository.Repository
@ -342,10 +341,10 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
reject(player, "Syntax: ::define_varbit varbitId")
}
val varbitID = args[1].toInt()
notify(player, "${varbitID}: ${VarbitDefinition.forId(varbitID, 0)}")
notify(player, "${varbitID}: ${VarbitDefinition.forId(varbitID)}")
}
define("togglexp", Privilege.STANDARD){ player, args ->
val enabled = player.varpManager.get(2501).getVarbit(0)?.value == 1
val enabled = player.varpManager.get(2501).getVarbit(0) == 1
player.varpManager.get(2501).setVarbit(0,if(enabled) 0 else 1).send(player)
notify(player, "XP drops are now " + colorize("%R" + if(!enabled) "ON." else "OFF."))
player.varpManager.flagSave(2501)
@ -406,7 +405,7 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
}
define("toggleslayer", Privilege.STANDARD){ player, _ ->
val disabled = player.varpManager.get(2502).getVarbit(0)?.value == 1
val disabled = player.varpManager.get(2502).getVarbit(0) == 1
player.varpManager.get(2502).setVarbit(0,if(disabled) 0 else 1).send(player)
if(!disabled){
player.varpManager.flagSave(2502)
@ -418,19 +417,35 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
define("setvarbit", Privilege.ADMIN){
player,args ->
if(args.size != 3){
reject(player,"Usage: ::setvarbit varbit value")
}
val index = args[1].toIntOrNull()
val value = args[3].toIntOrNull()
if(index == null || value == null){
reject(player,"Usage ::setvarbit index offset value")
}
player.varpManager.setVarbit(index!!, value!!)
}
define("setvarp", Privilege.ADMIN){
player,args ->
if(args.size < 4){
reject(player,"Usage: ::setvarbit index offset value")
reject(player,"Usage: ::setvarp index offset value")
}
val index = args[1].toIntOrNull()
val offset = args[2].toIntOrNull()
val value = args[3].toIntOrNull()
if(index == null || offset == null || value == null){
reject(player,"Usage ::setvarbit index offset value")
reject(player,"Usage ::setvarp index offset value")
}
player.varpManager.get(index!!).setVarbit(offset!!, value!!).send(player)
}
define("setvarc", Privilege.ADMIN) { player, args ->
if(args.size < 3){
reject(player,"Usage: ::setvarc index value")

View file

@ -1,49 +1,88 @@
package rs09.net.packet
import api.TickListener
import core.net.packet.OutgoingPacket
import core.net.packet.out.*
import gui.GuiEvent
import rs09.game.system.SystemLogger
import java.util.*
import java.util.concurrent.locks.ReentrantLock
import kotlin.collections.ArrayList
object PacketWriteQueue {
private val PacketsToWrite: Queue<QueuedPacket<*>> = LinkedList<QueuedPacket<*>>()
@JvmStatic
fun <T> handle(packet: OutgoingPacket<T>, context: T){
when(packet){
//Dynamic packets need to be sent immediately
is UpdateSceneGraph,
is BuildDynamicScene,
is InstancedLocationUpdate,
is ClearRegionChunk -> packet.send(context)
//Rest get queued up and sent at the end of the tick (authentic)
else -> queue(packet,context)
}
class PacketWriteQueue : TickListener {
override fun tick() {
flush()
}
@JvmStatic
fun <T> queue(packet: OutgoingPacket<T>, context: T){
PacketsToWrite.add(QueuedPacket(packet,context))
}
companion object {
private val queueLock = ReentrantLock()
private val packetsToQueue = ArrayList<QueuedPacket<*>>(1000)
private val packetsToWrite = LinkedList<QueuedPacket<*>>()
@JvmStatic
fun flush(){
while(!PacketsToWrite.isEmpty()){
val p = PacketsToWrite.poll() ?: continue
write(p.out,p.context)
@JvmStatic
fun <T> handle(packet: OutgoingPacket<T>, context: T) {
when (packet) {
//Dynamic packets need to be sent immediately
is UpdateSceneGraph,
is BuildDynamicScene,
is InstancedLocationUpdate,
is ClearRegionChunk -> packet.send(context)
//Rest get queued up and sent at the end of the tick (authentic)
else -> push(packet, context)
}
}
}
@Suppress("UNCHECKED_CAST")
fun <T> write(out: OutgoingPacket<*>, context: T){
val pack = out as? OutgoingPacket<T>
val ctx = context as? T
if(pack == null || ctx == null){
SystemLogger.logWarn("Failed packet casting")
return
@JvmStatic
fun <T> push(packet: OutgoingPacket<T>, context: T) {
if (queueLock.isLocked)
packetsToQueue.add(QueuedPacket(packet, context))
else
packetsToWrite.add(QueuedPacket(packet, context))
}
@JvmStatic
fun pop(): QueuedPacket<*>? {
return try {
packetsToWrite.pop()
} catch (e: NoSuchElementException) {
null
}
}
@JvmStatic
fun flush() {
queueLock.lock()
var packet: QueuedPacket<*>?
while (pop().also { packet = it } != null)
write(packet?.out ?: break, packet?.context ?: break)
if (packetsToWrite.isNotEmpty()) {
SystemLogger.logWarn("Packet queue was NOT empty! Remaining packets: ${packetsToWrite.size}")
try {
for (pkt in packetsToWrite) SystemLogger.logWarn("${pkt.out.javaClass.simpleName} <- ${pkt.context}")
} catch (e: Exception)
{
e.printStackTrace()
} finally {
packetsToWrite.clear()
}
}
val queueIter = packetsToQueue.iterator()
while (queueIter.hasNext()) {
packetsToWrite.add(queueIter.next())
queueIter.remove()
}
queueLock.unlock()
}
@Suppress("UNCHECKED_CAST")
fun <T> write(out: OutgoingPacket<*>, context: T) {
val pack = out as? OutgoingPacket<T>
val ctx = context as? T
if (pack == null || ctx == null) {
SystemLogger.logWarn("Failed packet casting")
return
}
pack.send(ctx)
}
pack.send(ctx)
}
}

View file

@ -19,7 +19,6 @@ import rs09.game.node.entity.player.info.login.PlayerSaveParser
import rs09.game.node.entity.player.info.login.PlayerSaver
import rs09.game.node.entity.skill.magic.SpellListener
import rs09.game.system.SystemLogger
import rs09.game.system.command.Command
import rs09.game.world.GameWorld
import java.util.*
import java.util.function.Consumer

View file

@ -79,9 +79,6 @@ class MajorUpdateWorker {
sequence.start()
sequence.run()
sequence.end()
GlobalScope.launch {
PacketWriteQueue.flush()
}
} catch (e: Exception) {
e.printStackTrace()
}