Merge remote-tracking branch 'upstream/master'

This commit is contained in:
skelsoft
2021-06-30 11:27:57 +10:00
17 changed files with 892 additions and 770 deletions
+7
View File
@@ -28,6 +28,7 @@
* [About the Project](#about-the-project)
* [Contributing](#contributing)
* [Contributing without Building](#contributing-without-building)
* [Video Setup Tutorial](#video-setup-tutorial)
* [Getting Started](#getting-started)
* [Github Setup](#github-setup)
* [Prerequisites](#prerequisites)
@@ -251,6 +252,12 @@ We use the AGPL 3.0 license, which can be found <a href="https://www.gnu.org/lic
<h4>Reminder: Developer support for setting up your own server ended October 5th, 2020. Do not ping/dm developers about setting up your server.</h4>
### Video Setup Tutorial
Occexe made a nice video showing you how to set it up if you'd prefer that. Check it out here:
[![View Tutorial](http://img.youtube.com/vi/3oQcsZdrRcE/0.jpg)](http://www.youtube.com/watch?v=3oQcsZdrRcE "2009Scape Setup")
[license-shield]: https://img.shields.io/badge/license-AGPL--3.0-informational
[license-url]: https://www.gnu.org/licenses/agpl-3.0.en.html
@@ -29,7 +29,7 @@ public final class SilverSicklePlugin extends OptionHandler {
@Override
public boolean handle(Player player, Node node, String option) {
Region region = RegionManager.getRegionCache().get(player.getLocation().getRegionId());
Region region = RegionManager.forId(player.getLocation().getRegionId());
switch (option) {
case "operate":
case "cast bloom":
@@ -48,6 +48,7 @@ public final class SilverSicklePlugin extends OptionHandler {
}
}
}
RegionManager.getLock().unlock();
return true;
}
return false;
@@ -10,6 +10,7 @@ import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.plugin.Plugin
import core.game.node.entity.skill.crafting.TanningProduct
import org.rs09.consts.NPCs
import rs09.game.interaction.InteractionListener
/**
@@ -31,6 +32,16 @@ class NPCTradePlugin : InteractionListener() {
}
return@on npc.openShop(player)
}
on(NPCs.SIEGFRIED_ERKLE_933, NPC, "trade"){player, node ->
val points = ContentAPI.getQP(player)
if(points < 40){
ContentAPI.sendNPCDialogue(player, NPCs.SIEGFRIED_ERKLE_933, "I'm sorry, adventurer, but you need 40 quest points to buy from me.")
return@on true
}
node.asNpc().openShop(player)
return@on true
}
}
override fun defineDestinationOverrides() {
@@ -761,7 +761,7 @@ public class Player extends Entity {
*/
public void updateSceneGraph(boolean login) {
Region region = getViewport().getRegion();
if (region instanceof DynamicRegion || (region == null && (region = RegionManager.getRegionCache().get(location.getRegionId())) instanceof DynamicRegion || region == null)) {
if (region instanceof DynamicRegion || region == null && (region = RegionManager.forId(location.getRegionId())) instanceof DynamicRegion) {
PacketRepository.send(BuildDynamicScene.class, new DynamicSceneContext(this, login));
} else {
PacketRepository.send(UpdateSceneGraph.class, new SceneGraphContext(this, login));
@@ -381,7 +381,7 @@ public final class HouseManager {
region = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6);
region.setBorders(borders);
region.setUpdateAllPlanes(true);
RegionManager.getRegionCache().put(region.getId(), region);
RegionManager.addRegion(region.getId(), region);
configureRoofs();
for (int z = 0; z < 3; z++) {
for (int x = 0; x < 8; x++) {
@@ -406,7 +406,7 @@ public final class HouseManager {
dungeon = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6);
dungeon.setBorders(borders);
dungeon.setUpdateAllPlanes(true);
RegionManager.getRegionCache().put(dungeon.getId(), dungeon);
RegionManager.addRegion(dungeon.getId(), dungeon);
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Room room = rooms[3][x][y];
@@ -1,737 +0,0 @@
package core.game.world.map;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.object.Scenery;
import rs09.game.system.SystemLogger;
import core.game.world.map.zone.ZoneBorders;
import core.tools.RandomFunction;
import java.util.*;
/**
* Manages the regions.
* @author Emperor
*
*/
public final class RegionManager {
/**
* The region cache mapping.
*/
private static final Map<Integer, Region> REGION_CACHE = new HashMap<>();
/**
* Gets the region for the given region id.
* @param regionId The region id.
* @return The region.
*/
public static Region forId(int regionId) {
Region region = REGION_CACHE.get(regionId);
if (region == null) {
region = new Region(regionId >> 8 & 0xFF, regionId & 0xFF);
REGION_CACHE.put(regionId, region);
}
return region;
}
/**
* Pulses the active regions.
*/
public static void pulse() {
Object[] rCacheArray = new Object[0];
try {
rCacheArray = REGION_CACHE.values().toArray();
} catch (ConcurrentModificationException e){
SystemLogger.logErr("Region Cache tried to process too early -- restarting...");
System.exit(0);
}
int rCacheLength = rCacheArray.length;
for (int i = 0; i < rCacheLength; i++) {
Region r = (Region) rCacheArray[i];
if (r != null && r.isActive()) {
RegionPlane[] planes = r.getPlanes();
int size = planes.length;
for (int j = 0; j < size; j++) {
planes[j].pulse();
}
}
}
}
/**
* Gets the clipping flag on the given location.
* @param l The location.
* @return The clipping flag.
*/
public static int getClippingFlag(Location l) {
return getClippingFlag(l.getZ(), l.getX(), l.getY());
}
/**
* Gets the clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return The clipping flags.
*/
public static int getClippingFlag(int z, int x, int y) {
Region region = forId((x >> 6) << 8 | y >> 6);
Region.load(region);
if (!region.isHasFlags()) {
return -1;
}
x -= (x >> 6) << 6;
y -= (y >> 6) << 6;
return region.getPlanes()[z].getFlags().getClippingFlags()[x][y];
}
/**
* Gets the water variant of a tile's clipping flag
* Essentially strips the landscape flag off a tile and keeps other flags, and makes normally walkable tiles unwalkable.
* @author Ceikry
*/
public static int getWaterClipFlag(int z, int x, int y){
int flag = getClippingFlag(z,x,y);
if(!isClipped(z,x,y)){
return flag | 0x100;
}
return flag & (~0x200000);
}
/**
* Checks if the tile is part of the landscape.
* @param l The location.
* @return {@code True} if so.
*/
public static boolean isLandscape(Location l) {
return isLandscape(l.getZ(), l.getX(), l.getY());
}
/**
* Checks if the tile is part of the landscape.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return {@code True} if so.
*/
public static boolean isLandscape(int z, int x, int y) {
Region region = forId((x >> 6) << 8 | y >> 6);
Region.load(region);
if (!region.isHasFlags() || region.getPlanes()[z].getFlags().getLandscape() == null) {
return false;
}
x -= (x >> 6) << 6;
y -= (y >> 6) << 6;
return region.getPlanes()[z].getFlags().getLandscape()[x][y];
}
/**
* Sets the clipping flag on the given location.
* @param l The location.
* @param flag The flag to set.
*/
public static void setClippingFlag(Location l, int flag) {
int x = l.getX();
int y = l.getY();
int z = l.getZ();
Region region = forId((x >> 6) << 8 | y >> 6);
Region.load(region);
if (!region.isHasFlags()) {
return;
}
x -= (x >> 6) << 6;
y -= (y >> 6) << 6;
region.getPlanes()[z].getFlags().getClippingFlags()[x][y] = flag;
}
/**
* Adds a clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @param projectile If the flag is being set for projectile pathfinding.
* @param flag The clipping flag.
*/
public static void addClippingFlag(int z, int x, int y, boolean projectile, int flag) {
Region region = forId((x >> 6) << 8 | y >> 6);
Region.load(region);
if (!region.isHasFlags()) {
return;
}
x -= (x >> 6) << 6;
y -= (y >> 6) << 6;
if (projectile) {
region.getPlanes()[z].getProjectileFlags().flag(x, y, flag);
} else {
region.getPlanes()[z].getFlags().flag(x, y, flag);
}
}
/**
* Adds a clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @param projectile If the flag is being set for projectile pathfinding.
* @param flag The clipping flag.
*/
public static void removeClippingFlag(int z, int x, int y, boolean projectile, int flag) {
Region region = forId((x >> 6) << 8 | y >> 6);
Region.load(region);
if (!region.isHasFlags()) {
return;
}
x -= (x >> 6) << 6;
y -= (y >> 6) << 6;
if (projectile) {
region.getPlanes()[z].getProjectileFlags().unflag(x, y, flag);
} else {
region.getPlanes()[z].getFlags().unflag(x, y, flag);
}
}
/**
* Gets the clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return The clipping flags.
*/
public static int getProjectileFlag(int z, int x, int y) {
Region region = forId((x >> 6) << 8 | y >> 6);
Region.load(region);
if (!region.isHasFlags()) {
return -1;
}
x -= (x >> 6) << 6;
y -= (y >> 6) << 6;
return region.getPlanes()[z].getProjectileFlags().getClippingFlags()[x][y];
}
/**
* Gets the clipping flag
* @param location the Location
* @return the clipping flag
*/
public static boolean isTeleportPermitted(Location location) {
return isTeleportPermitted(location.getZ(), location.getX(), location.getY());
}
/**
* Gets the clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return The clipping flags.
*/
public static boolean isTeleportPermitted(int z, int x, int y) {
if (!isLandscape(z, x, y)) {
return false;
}
int flag = getClippingFlag(z, x, y);
return (flag & 0x12c0102) == 0 || (flag & 0x12c0108) == 0 || (flag & 0x12c0120) == 0 || (flag & 0x12c0180) == 0;
}
/**
* Checks if the location has any clipping flags.
* @param location The location.
* @return {@code True} if a clipping flag disables access for this location.
*/
public static boolean isClipped(Location location) {
return isClipped(location.getZ(), location.getX(), location.getY());
}
/**
* Checks if the location has any clipping flags.
* @param z The plane.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @return {@code True} if a clipping flag disables access for this location.
*/
public static boolean isClipped(int z, int x, int y) {
if (!isLandscape(z, x, y)) {
return true;
}
int flag = getClippingFlag(z, x, y);
return (flag & 0x12c0102) != 0 || (flag & 0x12c0108) != 0 || (flag & 0x12c0120) != 0 || (flag & 0x12c0180) != 0;
}
/**
* Gets the spawn location of a node.
* @param owner the owner.
* @param node the node.
* @return the location.
*/
public static Location getSpawnLocation(Player owner, Node node) {
if (owner == null || node == null) {
return null;
}
Location destination = null;
for (int i = 0; i < 4; i++) {
Direction dir = Direction.get(i);
Location l = owner.getLocation().transform(dir, dir.toInteger() < 2 ? 1 : node.size());
boolean success = true;
loop:{
for (int x = 0; x < node.size(); x++) {
for (int y = 0; y < node.size(); y++) {
if (RegionManager.isClipped(l.transform(x, y, 0))) {
success = false;
break loop;
}
}
}
}
if (success) {
destination = l;
break;
}
}
return destination;
}
/**
* Gets the scenery on the current location.
* @param l The location.
* @return The scenery, or {@code null} if no object was found.
*/
public static Scenery getObject(Location l) {
return getObject(l.getZ(), l.getX(), l.getY());
}
/**
* Gets the scenery on the current absolute coordinates.
* @param z The height.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @return The scenery, or {@code null} if no object was found.
*/
public static Scenery getObject(int z, int x, int y) {
return getObject(z, x, y, -1);
}
/**
* Gets the object on the given absolute coordinates.
* @param z The height.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @param objectId The object id.
* @return The scenery, or {@code null} if no object was found.
*/
public static Scenery getObject(int z, int x, int y, int objectId) {
int regionId = ((x >> 6) << 8) | y >> 6;
x -= ((x >> 6) << 6);
y -= ((y >> 6) << 6);
Region region = forId(regionId);
Region.load(region);
Scenery object = region.getPlanes()[z].getChunkObject(x, y, objectId);
if (object != null && !object.isRenderable()) {
return null;
}
return object;
}
/**
* Gets the region plane for this location.
* @param l The location.
* @return The region plane.
*/
public static RegionPlane getRegionPlane(Location l) {
int regionId = ((l.getX() >> 6) << 8) | l.getY() >> 6;
return forId(regionId).getPlanes()[l.getZ()];
}
/**
* Gets a region chunk.
* @param l The location.
* @return The region chunk.
*/
public static RegionChunk getRegionChunk(Location l) {
RegionPlane plane = getRegionPlane(l);
return plane.getRegionChunk(l.getLocalX() / RegionChunk.SIZE, l.getLocalY() / RegionChunk.SIZE);
}
/**
* Moves the entity from the current region to the new one.
* @param entity The entity.
*/
public static void move(Entity entity) {
boolean player = entity instanceof Player;
int regionId = (entity.getLocation().getRegionX() >> 3) << 8 | (entity.getLocation().getRegionY() >> 3);
Viewport viewport = entity.getViewport();
Region current = forId(regionId);
int z = entity.getLocation().getZ();
RegionPlane plane = current.getPlanes()[z];
viewport.updateViewport(entity);
if (plane == viewport.getCurrentPlane()) {
entity.getZoneMonitor().updateLocation(entity.getWalkingQueue().getFootPrint());
return;
}
viewport.remove(entity);
if (player) {
current.add((Player) entity);
} else {
current.add((NPC) entity);
}
viewport.setRegion(current);
viewport.setCurrentPlane(plane);
List<RegionPlane> view = new LinkedList<>();
for (int regionX = (entity.getLocation().getRegionX() >> 3) - 1; regionX <= (entity.getLocation().getRegionX() >> 3) + 1; regionX++) {
for (int regionY = (entity.getLocation().getRegionY() >> 3) - 1; regionY <= (entity.getLocation().getRegionY() >> 3) + 1; regionY++) {
if (regionX < 0 || regionY < 0) {
continue;
}
Region region = forId(regionX << 8 | regionY);
RegionPlane p = region.getPlanes()[z];
if (player) {
region.incrementViewAmount();
region.flagActive();
}
view.add(p);
}
}
viewport.setViewingPlanes(view);
entity.getZoneMonitor().updateLocation(entity.getWalkingQueue().getFootPrint());
}
/**
* Gets the list of local NPCs with a maximum distance of 16.
* @param n The entity.
* @return The list of local NPCs.
*/
public static List<NPC> getLocalNpcs(Entity n) {
return getLocalNpcs(n, MapDistance.RENDERING.getDistance());
}
/**
* Gets the location entitys.
* @param location the location.
* @param distance the distance.
* @return the list.
*/
public static List<Entity> getLocalEntitys(Location location, int distance){
List<Entity> entitys = new ArrayList<>(20);
entitys.addAll(getLocalNpcs(location, distance));
entitys.addAll(getLocalPlayers(location, distance));
return entitys;
}
/**
* Gets the location entitys.
* @param entity the entity.
* @param distance the distance.
* @return the list.
*/
public static List<Entity> getLocalEntitys(Entity entity, int distance) {
return getLocalEntitys(entity.getLocation(), distance);
}
/**
* Gets the local entitys.
* @param entity the entity.
* @return the entitys.
*/
public static List<Entity> getLocalEntitys(Entity entity) {
return getLocalEntitys(entity.getLocation(), MapDistance.RENDERING.getDistance());
}
/**
* Gets the list of local NPCs.
* @param n The entity.
* @param distance The distance to the entity.
* @return The list of local NPCs.
*/
public static List<NPC> getLocalNpcs(Entity n, int distance) {
List<NPC> npcs = new LinkedList<>();
for (RegionPlane r : n.getViewport().getViewingPlanes()) {
for (NPC npc : r.getNpcs()) {
if (npc.getLocation().withinDistance(n.getLocation(), distance)) {
npcs.add(npc);
}
}
}
return npcs;
}
/**
* Gets the list of local players with a maximum distance of 15.
* @param n The entity.
* @return The list of local players.
*/
public static List<Player> getLocalPlayers(Entity n) {
return getLocalPlayers(n, MapDistance.RENDERING.getDistance());
}
/**
* Gets the list of local players.
* @param n The entity.
* @param distance The distance to the entity.
* @return The list of local players.
*/
public static List<Player> getLocalPlayers(Entity n, int distance) {
List<Player> players = new LinkedList<>();
for (RegionPlane r : n.getViewport().getViewingPlanes()) {
for (Player p : r.getPlayers()) {
if (p.getLocation().withinDistance(n.getLocation(), distance)) {
players.add(p);
}
}
}
return players;
}
/**
* Gets the surrounding players.
* @param n The node the players should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of players.
*/
public static List<Player> getSurroundingPlayers(Node n, Node...ignore) {
return getSurroundingPlayers(n, 9, ignore);
}
/**
* Gets the surrounding players.
* @param n The node the players should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of players.
*/
public static List<Player> getSurroundingPlayers(Node n, int maximum, Node...ignore) {
List<Player> players = getLocalPlayers(n.getLocation(), 1);
int count = 0;
for (Iterator<Player> it = players.iterator(); it.hasNext();) {
Player p = it.next();
if (++count >= maximum) {
it.remove();
continue;
}
for (Node node : ignore) {
if (p == node) {
count--;
it.remove();
break;
}
}
}
return players;
}
/**
* Gets the surrounding players.
* @param n The node the players should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of players.
*/
public static List<NPC> getSurroundingNPCs(Node n, Node...ignore) {
return getSurroundingNPCs(n, 9, ignore);
}
/**
* Gets the surrounding players.
* @param n The node the npcs should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of npcs.
*/
public static List<NPC> getSurroundingNPCs(Node n, int maximum, Node...ignore) {
List<NPC> npcs = getLocalNpcs(n.getLocation(), 1);
int count = 0;
for (Iterator<NPC> it = npcs.iterator(); it.hasNext();) {
NPC p = it.next();
if (++count > maximum) {
it.remove();
continue;
}
for (Node node : ignore) {
if (p == node) {
count--;
it.remove();
break;
}
}
}
return npcs;
}
/**
* Gets a random teleport location in the radius around the given location.
* @param location The centre location.
* @param radius The radius.
* @return A random teleport location.
*/
public static Location getTeleportLocation(Location location, int radius) {
int mod = radius >> 1;
if (mod == 0) {
mod++;
radius--;
}
return getTeleportLocation(location.transform(-mod, -mod, 0), mod + radius, mod + radius);
}
/**
* Gets a random teleport location in the radius around the given location.
* @param location The centre location.
* @return A random teleport location.
*/
public static Location getTeleportLocation(Location location, int areaX, int areaY) {
Location destination = location;
int x = RandomFunction.random(1 + areaX);
int y = RandomFunction.random(1 + areaY);
int count = 0;
while (!isTeleportPermitted(destination = location.transform(x, y, 0))) {
x = RandomFunction.random(1 + areaX);
y = RandomFunction.random(1 + areaY);
if (count++ >= areaX * 2) {
//This would be able to keep looping for several seconds otherwise (this actually happens).
for (x = 0; x < areaX + 1; x++) {
for (y = 0; y < areaY + 1; y++) {
if (isTeleportPermitted(destination = location.transform(x, y, 0))) {
return destination;
}
}
}
break;
}
}
return destination;
}
/**
* Gets the current viewport for the location.
* @param l The location.
* @return The viewport.
*/
public static List<Player> getViewportPlayers(Location l) {
List<Player> players = new LinkedList<>();
l = l.getChunkBase().transform(-8, -8, 0);
ZoneBorders b = new ZoneBorders(l.getX(), l.getY(), l.getX() + 24, l.getY() + 24);
for (int regionX = (l.getRegionX() - 6) >> 3; regionX <= (l.getRegionX() + 6) >> 3; regionX++) {
for (int regionY = (l.getRegionY() - 6) >> 3; regionY <= (l.getRegionY() + 6) >> 3; regionY++) {
for (Player player : forId(regionX << 8 | regionY).getPlanes()[l.getZ()].getPlayers()) {
l = player.getLocation();
if (b.insideBorder(l.getX(), l.getY())) {
players.add(player);
}
}
}
}
return players;
}
/**
* Gets a list of players in the given region.
* @param regionId The region id.
* @return The list of players in this region.
*/
public static List<Player> getRegionPlayers(int regionId) {
Region r = forId(regionId);
List<Player> players = new ArrayList<>(20);
for (RegionPlane plane : r.getPlanes()) {
players.addAll(plane.getPlayers());
}
return players;
}
/**
* Gets a list of local players within rendering distance of the location.
* @param l The location.
* @return The list of players.
*/
public static List<Player> getLocalPlayers(Location l) {
return getLocalPlayers(l, MapDistance.RENDERING.getDistance());
}
/**
* Gets a list of local players.
* @param l The location.
* @param distance The distance to that location.
* @return The list of players.
*/
public static List<Player> getLocalPlayers(Location l, int distance) {
List<Player> players = new LinkedList<>();
for (int regionX = (l.getRegionX() - 6) >> 3; regionX <= (l.getRegionX() + 6) >> 3; regionX++) {
for (int regionY = (l.getRegionY() - 6) >> 3; regionY <= (l.getRegionY() + 6) >> 3; regionY++) {
for (Player player : forId(regionX << 8 | regionY).getPlanes()[l.getZ()].getPlayers()) {
if (player.getLocation().withinDistance(l, distance)) {
players.add(player);
}
}
}
}
return players;
}
/**
* Gets a list of local players within 16 tile distance of the location.
* @param l The location.
* @return The list of players.
*/
public static List<NPC> getLocalNpcs(Location l) {
return getLocalNpcs(l, MapDistance.RENDERING.getDistance());
}
/**
* Gets the npc.
* @param entity the entity.
* @param id the id.
*/
public static NPC getNpc(final Entity entity, final int id) {
return getNpc(entity, id, 16);
}
/**
* Gets the npc.
* @param entity the entity.
* @param id the id.
* @param distance the distance.
* @return the npc.
*/
public static NPC getNpc(Entity entity, int id, int distance) {
return getNpc(entity.getLocation(), id, distance);
}
/**
* Gets an npc near the entity.
* @param id the id,
* @param distance the dinstance.
* @return the npc.
*/
public static NPC getNpc(final Location location, int id, int distance) {
List<NPC> npcs = getLocalNpcs(location, distance);
for (NPC n : npcs) {
if (n.getId() == id) {
return n;
}
}
return null;
}
/**
* Gets a list of local players.
* @param l The location.
* @param distance The distance to that location.
* @return The list of players.
*/
public static List<NPC> getLocalNpcs(Location l, int distance) {
List<NPC> npcs = new LinkedList<>();
for (int regionX = (l.getRegionX() - 6) >> 3; regionX <= (l.getRegionX() + 6) >> 3; regionX++) {
for (int regionY = (l.getRegionY() - 6) >> 3; regionY <= (l.getRegionY() + 6) >> 3; regionY++) {
for (NPC n : forId(regionX << 8 | regionY).getPlanes()[l.getZ()].getNpcs()) {
if (n.getLocation().withinDistance(l, (n.size() >> 1) + distance)) {
npcs.add(n);
}
}
}
}
return npcs;
}
/**
* Gets the regionCache.
* @return The regionCache.
*/
public static Map<Integer, Region> getRegionCache() {
return REGION_CACHE;
}
}
@@ -0,0 +1,807 @@
package core.game.world.map
import core.game.world.map.RegionManager
import core.game.world.map.RegionPlane
import core.game.node.`object`.Scenery
import core.game.node.Node
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.zone.ZoneBorders
import core.tools.RandomFunction
import rs09.game.system.SystemLogger
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
/**
* Manages the regions.
* @author Emperor
*/
object RegionManager {
/**
* The region cache mapping.
*/
private val REGION_CACHE: MutableMap<Int, Region> = HashMap()
public val LOCK = ReentrantLock()
/**
* Gets the region for the given region id.
* @param regionId The region id.
* @return The region.
*/
@JvmStatic
fun forId(regionId: Int): Region {
LOCK.tryLock(10000, TimeUnit.MILLISECONDS)
var region = REGION_CACHE[regionId]
if (region == null) {
region = Region((regionId shr 8) and 0xFF, regionId and 0xFF)
if(region!!.regionId != regionId){
SystemLogger.logErr("IDs do NOT match - ${region!!.regionId} supposed to be $regionId")
}
REGION_CACHE[regionId] = region
}
LOCK.unlock()
return REGION_CACHE[regionId]!!
}
/**
* Pulses the active regions.
*/
@JvmStatic
fun pulse() {
LOCK.tryLock(10000,TimeUnit.MILLISECONDS)
for (r in REGION_CACHE.values) {
if (r != null && r.isActive) {
for (p in r.planes) {
p.pulse()
}
}
}
LOCK.unlock()
}
/**
* Gets the clipping flag on the given location.
* @param l The location.
* @return The clipping flag.
*/
@JvmStatic
fun getClippingFlag(l: Location): Int {
return getClippingFlag(l.z, l.x, l.y)
}
/**
* Gets the clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return The clipping flags.
*/
@JvmStatic
fun getClippingFlag(z: Int, x: Int, y: Int): Int {
var x = x
var y = y
val region = forId(((x shr 6) shl 8) or (y shr 6))
Region.load(region)
if (!region.isHasFlags) {
return -1
}
x -= x shr 6 shl 6
y -= y shr 6 shl 6
return region.planes[z].flags.clippingFlags[x][y]
}
/**
* Gets the water variant of a tile's clipping flag
* Essentially strips the landscape flag off a tile and keeps other flags, and makes normally walkable tiles unwalkable.
* @author Ceikry
*/
@JvmStatic
fun getWaterClipFlag(z: Int, x: Int, y: Int): Int {
val flag = getClippingFlag(z, x, y)
return if (!isClipped(z, x, y)) {
flag or 0x100
} else flag and 0x200000.inv()
}
/**
* Checks if the tile is part of the landscape.
* @param l The location.
* @return `True` if so.
*/
@JvmStatic
fun isLandscape(l: Location): Boolean {
return isLandscape(l.z, l.x, l.y)
}
/**
* Checks if the tile is part of the landscape.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return `True` if so.
*/
@JvmStatic
fun isLandscape(z: Int, x: Int, y: Int): Boolean {
var x = x
var y = y
val region = forId(((x shr 6) shl 8) or (y shr 6))
Region.load(region)
if (!region.isHasFlags || region.planes[z].flags.landscape == null) {
return false
}
x -= x shr 6 shl 6
y -= y shr 6 shl 6
return region.planes[z].flags.landscape[x][y]
}
/**
* Sets the clipping flag on the given location.
* @param l The location.
* @param flag The flag to set.
*/
@JvmStatic
fun setClippingFlag(l: Location, flag: Int) {
var x = l.x
var y = l.y
val z = l.z
val region = forId(((x shr 6) shl 8) or (y shr 6))
Region.load(region)
if (!region.isHasFlags) {
return
}
x -= x shr 6 shl 6
y -= y shr 6 shl 6
region.planes[z].flags.clippingFlags[x][y] = flag
}
/**
* Adds a clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @param projectile If the flag is being set for projectile pathfinding.
* @param flag The clipping flag.
*/
@JvmStatic
fun addClippingFlag(z: Int, x: Int, y: Int, projectile: Boolean, flag: Int) {
var x = x
var y = y
val region = forId(((x shr 6) shl 8) or (y shr 6))
Region.load(region)
if (!region.isHasFlags) {
return
}
x -= x shr 6 shl 6
y -= y shr 6 shl 6
if (projectile) {
region.planes[z].projectileFlags.flag(x, y, flag)
} else {
region.planes[z].flags.flag(x, y, flag)
}
}
/**
* Adds a clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @param projectile If the flag is being set for projectile pathfinding.
* @param flag The clipping flag.
*/
@JvmStatic
fun removeClippingFlag(z: Int, x: Int, y: Int, projectile: Boolean, flag: Int) {
var x = x
var y = y
val region = forId(((x shr 6) shl 8) or (y shr 6))
Region.load(region)
if (!region.isHasFlags) {
return
}
x -= x shr 6 shl 6
y -= y shr 6 shl 6
if (projectile) {
region.planes[z].projectileFlags.unflag(x, y, flag)
} else {
region.planes[z].flags.unflag(x, y, flag)
}
}
/**
* Gets the clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return The clipping flags.
*/
@JvmStatic
fun getProjectileFlag(z: Int, x: Int, y: Int): Int {
var x = x
var y = y
val region = forId(((x shr 6) shl 8) or (y shr 6))
Region.load(region)
if (!region.isHasFlags) {
return -1
}
x -= x shr 6 shl 6
y -= y shr 6 shl 6
return region.planes[z].projectileFlags.clippingFlags[x][y]
}
/**
* Gets the clipping flag
* @param location the Location
* @return the clipping flag
*/
@JvmStatic
fun isTeleportPermitted(location: Location): Boolean {
return isTeleportPermitted(location.z, location.x, location.y)
}
/**
* Gets the clipping flag.
* @param z The plane.
* @param x The absolute x-coordinate.
* @param y The absolute y-coordinate.
* @return The clipping flags.
*/
@JvmStatic
fun isTeleportPermitted(z: Int, x: Int, y: Int): Boolean {
if (!isLandscape(z, x, y)) {
return false
}
val flag = getClippingFlag(z, x, y)
return flag and 0x12c0102 == 0 || flag and 0x12c0108 == 0 || flag and 0x12c0120 == 0 || flag and 0x12c0180 == 0
}
/**
* Checks if the location has any clipping flags.
* @param location The location.
* @return `True` if a clipping flag disables access for this location.
*/
@JvmStatic
fun isClipped(location: Location): Boolean {
return isClipped(location.z, location.x, location.y)
}
/**
* Checks if the location has any clipping flags.
* @param z The plane.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @return `True` if a clipping flag disables access for this location.
*/
@JvmStatic
fun isClipped(z: Int, x: Int, y: Int): Boolean {
if (!isLandscape(z, x, y)) {
return true
}
val flag = getClippingFlag(z, x, y)
return flag and 0x12c0102 != 0 || flag and 0x12c0108 != 0 || flag and 0x12c0120 != 0 || flag and 0x12c0180 != 0
}
/**
* Gets the spawn location of a node.
* @param owner the owner.
* @param node the node.
* @return the location.
*/
@JvmStatic
fun getSpawnLocation(owner: Player?, node: Node?): Location? {
if (owner == null || node == null) {
return null
}
var destination: Location? = null
for (i in 0..3) {
val dir = Direction.get(i)
val l = owner.location.transform(dir, if (dir.toInteger() < 2) 1 else node.size())
var success = true
for (x in 0 until node.size()) {
for (y in 0 until node.size()) {
if (isClipped(l.transform(x, y, 0))) {
success = false
break
}
}
}
if (success) {
destination = l
break
}
}
return destination
}
/**
* Gets the scenery on the current location.
* @param l The location.
* @return The scenery, or `null` if no object was found.
*/
@JvmStatic
fun getObject(l: Location): Scenery? {
return getObject(l.z, l.x, l.y)
}
/**
* Gets the scenery on the current absolute coordinates.
* @param z The height.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @return The scenery, or `null` if no object was found.
*/
@JvmStatic
fun getObject(z: Int, x: Int, y: Int): Scenery? {
return getObject(z, x, y, -1)
}
/**
* Gets the object on the given absolute coordinates.
* @param z The height.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @param objectId The object id.
* @return The scenery, or `null` if no object was found.
*/
@JvmStatic
fun getObject(z: Int, x: Int, y: Int, objectId: Int): Scenery? {
var x = x
var y = y
val regionId = ((x shr 6) shl 8) or (y shr 6)
x -= (x shr 6) shl 6
y -= (y shr 6) shl 6
val region = forId(regionId)
Region.load(region)
val `object`: Scenery? = region.planes[z].getChunkObject(x, y, objectId)
return if (`object` != null && !`object`.isRenderable()) {
null
} else `object`
}
/**
* Gets the region plane for this location.
* @param l The location.
* @return The region plane.
*/
@JvmStatic
fun getRegionPlane(l: Location): RegionPlane {
val regionId = ((l.x shr 6) shl 8) or (l.y shr 6)
return forId(regionId).planes[l.z]
}
/**
* Gets a region chunk.
* @param l The location.
* @return The region chunk.
*/
@JvmStatic
fun getRegionChunk(l: Location): RegionChunk {
val plane = getRegionPlane(l)
return plane.getRegionChunk(l.localX / RegionChunk.SIZE, l.localY / RegionChunk.SIZE)
}
/**
* Moves the entity from the current region to the new one.
* @param entity The entity.
*/
@JvmStatic
fun move(entity: Entity) {
val player = entity is Player
val regionId = ((entity.location.regionX shr 3) shl 8) or (entity.location.regionY shr 3)
val viewport = entity.viewport
val current = forId(regionId)
val z = entity.location.z
val plane = current.planes[z]
viewport.updateViewport(entity)
if (plane == viewport.currentPlane) {
entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint)
return
}
viewport.remove(entity)
if (player) {
current.add(entity as Player)
} else {
current.add(entity as NPC)
}
viewport.region = current
viewport.currentPlane = plane
val view: MutableList<RegionPlane> = LinkedList()
for (regionX in ((entity.location.regionX shr 3) - 1)..((entity.location.regionX shr 3) + 1)) {
for (regionY in ((entity.location.regionY shr 3) - 1)..((entity.location.regionY shr 3) + 1)) {
if (regionX < 0 || regionY < 0) {
continue
}
val region = forId((regionX shl 8) or regionY)
val p = region.planes[z]
if (player) {
region.incrementViewAmount()
region.flagActive()
}
view.add(p)
}
}
viewport.viewingPlanes = view
entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint)
}
/**
* Gets the list of local NPCs with a maximum distance of 16.
* @param n The entity.
* @return The list of local NPCs.
*/
@JvmStatic
fun getLocalNpcs(n: Entity): List<NPC> {
return getLocalNpcs(n, MapDistance.RENDERING.distance)
}
/**
* Gets the location entitys.
* @param location the location.
* @param distance the distance.
* @return the list.
*/
@JvmStatic
fun getLocalEntitys(location: Location, distance: Int): List<Entity> {
val entitys: MutableList<Entity> = ArrayList(20)
entitys.addAll(getLocalNpcs(location, distance))
entitys.addAll(getLocalPlayers(location, distance))
return entitys
}
/**
* Gets the location entitys.
* @param entity the entity.
* @param distance the distance.
* @return the list.
*/
@JvmStatic
fun getLocalEntitys(entity: Entity, distance: Int): List<Entity> {
return getLocalEntitys(entity.location, distance)
}
/**
* Gets the local entitys.
* @param entity the entity.
* @return the entitys.
*/
@JvmStatic
fun getLocalEntitys(entity: Entity): List<Entity> {
return getLocalEntitys(entity.location, MapDistance.RENDERING.distance)
}
/**
* Gets the list of local NPCs.
* @param n The entity.
* @param distance The distance to the entity.
* @return The list of local NPCs.
*/
@JvmStatic
fun getLocalNpcs(n: Entity, distance: Int): List<NPC> {
val npcs: MutableList<NPC> = LinkedList()
for (r in n.viewport.viewingPlanes) {
for (npc in r.npcs) {
if (npc.location.withinDistance(n.location, distance)) {
npcs.add(npc)
}
}
}
return npcs
}
/**
* Gets the list of local players with a maximum distance of 15.
* @param n The entity.
* @return The list of local players.
*/
@JvmStatic
fun getLocalPlayers(n: Entity): List<Player> {
return getLocalPlayers(n, MapDistance.RENDERING.distance)
}
/**
* Gets the list of local players.
* @param n The entity.
* @param distance The distance to the entity.
* @return The list of local players.
*/
@JvmStatic
fun getLocalPlayers(n: Entity, distance: Int): List<Player> {
val players: MutableList<Player> = LinkedList()
for (r in n.viewport.viewingPlanes) {
for (p in r.players) {
if (p.location.withinDistance(n.location, distance)) {
players.add(p)
}
}
}
return players
}
/**
* Gets the surrounding players.
* @param n The node the players should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of players.
*/
@JvmStatic
fun getSurroundingPlayers(n: Node, vararg ignore: Node): List<Player> {
return getSurroundingPlayers(n, 9, *ignore)
}
/**
* Gets the surrounding players.
* @param n The node the players should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of players.
*/
@JvmStatic
fun getSurroundingPlayers(n: Node, maximum: Int, vararg ignore: Node): List<Player> {
val players = getLocalPlayers(n.location, 1)
var count = 0
val it = players.iterator()
while (it.hasNext()) {
val p = it.next()
if (++count >= maximum) {
it.remove()
continue
}
for (node in ignore) {
if (p === node) {
count--
it.remove()
break
}
}
}
return players
}
/**
* Gets the surrounding players.
* @param n The node the players should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of players.
*/
@JvmStatic
fun getSurroundingNPCs(n: Node, vararg ignore: Node): List<NPC> {
return getSurroundingNPCs(n, 9, *ignore)
}
/**
* Gets the surrounding players.
* @param n The node the npcs should be surrounding.
* @param ignore The nodes not to add to the list.
* @return The list of npcs.
*/
@JvmStatic
fun getSurroundingNPCs(n: Node, maximum: Int, vararg ignore: Node): List<NPC> {
val npcs = getLocalNpcs(n.location, 1)
var count = 0
val it = npcs.iterator()
while (it.hasNext()) {
val p = it.next()
if (++count > maximum) {
it.remove()
continue
}
for (node in ignore) {
if (p === node) {
count--
it.remove()
break
}
}
}
return npcs
}
/**
* Gets a random teleport location in the radius around the given location.
* @param location The centre location.
* @param radius The radius.
* @return A random teleport location.
*/
@JvmStatic
fun getTeleportLocation(location: Location, radius: Int): Location {
var radius = radius
var mod = radius shr 1
if (mod == 0) {
mod++
radius--
}
return getTeleportLocation(location.transform(-mod, -mod, 0), mod + radius, mod + radius)
}
/**
* Gets a random teleport location in the radius around the given location.
* @param location The centre location.
* @return A random teleport location.
*/
@JvmStatic
fun getTeleportLocation(location: Location, areaX: Int, areaY: Int): Location {
var destination = location
var x: Int = RandomFunction.random(1 + areaX)
var y: Int = RandomFunction.random(1 + areaY)
var count = 0
while (!isTeleportPermitted(location.transform(x, y, 0).also { destination = it })) {
x = RandomFunction.random(1 + areaX)
y = RandomFunction.random(1 + areaY)
if (count++ >= areaX * 2) {
//This would be able to keep looping for several seconds otherwise (this actually happens).
x = 0
while (x < areaX + 1) {
y = 0
while (y < areaY + 1) {
if (isTeleportPermitted(location.transform(x, y, 0).also { destination = it })) {
return destination
}
y++
}
x++
}
break
}
}
return destination
}
/**
* Gets the current viewport for the location.
* @param l The location.
* @return The viewport.
*/
@JvmStatic
fun getViewportPlayers(l: Location): List<Player> {
var l = l
val players: MutableList<Player> = LinkedList()
l = l.chunkBase.transform(-8, -8, 0)
val b = ZoneBorders(l.x, l.y, l.x + 24, l.y + 24)
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
for (player in forId(regionX shl 8 or regionY).planes[l.z].players) {
l = player.location
if (b.insideBorder(l.x, l.y)) {
players.add(player)
}
}
}
}
return players
}
/**
* Gets a list of players in the given region.
* @param regionId The region id.
* @return The list of players in this region.
*/
@JvmStatic
fun getRegionPlayers(regionId: Int): List<Player> {
val r = forId(regionId)
val players: MutableList<Player> = ArrayList(20)
for (plane in r.planes) {
players.addAll(plane.players)
}
return players
}
/**
* Gets a list of local players within rendering distance of the location.
* @param l The location.
* @return The list of players.
*/
@JvmStatic
fun getLocalPlayers(l: Location): List<Player> {
return getLocalPlayers(l, MapDistance.RENDERING.distance)
}
/**
* Gets a list of local players.
* @param l The location.
* @param distance The distance to that location.
* @return The list of players.
*/
@JvmStatic
fun getLocalPlayers(l: Location, distance: Int): MutableList<Player> {
val players: MutableList<Player> = LinkedList()
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
for (player in forId((regionX shl 8) or regionY).planes[l.z].players) {
if (player.location.withinDistance(l, distance)) {
players.add(player)
}
}
}
}
return players
}
/**
* Gets a list of local players within 16 tile distance of the location.
* @param l The location.
* @return The list of players.
*/
@JvmStatic
fun getLocalNpcs(l: Location): List<NPC> {
return getLocalNpcs(l, MapDistance.RENDERING.distance)
}
/**
* Gets the npc.
* @param entity the entity.
* @param id the id.
*/
@JvmStatic
fun getNpc(entity: Entity, id: Int): NPC? {
return getNpc(entity, id, 16)
}
/**
* Gets the npc.
* @param entity the entity.
* @param id the id.
* @param distance the distance.
* @return the npc.
*/
@JvmStatic
fun getNpc(entity: Entity, id: Int, distance: Int): NPC? {
return getNpc(entity.location, id, distance)
}
/**
* Gets an npc near the entity.
* @param id the id,
* @param distance the dinstance.
* @return the npc.
*/
@JvmStatic
fun getNpc(location: Location, id: Int, distance: Int): NPC? {
val npcs: List<NPC> = getLocalNpcs(location, distance)
for (n in npcs) {
if (n.id == id) {
return n
}
}
return null
}
/**
* Gets a list of local players.
* @param l The location.
* @param distance The distance to that location.
* @return The list of players.
*/
@JvmStatic
fun getLocalNpcs(l: Location, distance: Int): MutableList<NPC> {
val npcs: MutableList<NPC> = LinkedList()
for (regionX in ((l.regionX - 6) shr 3)..((l.regionX + 6) shr 3)) {
for (regionY in ((l.regionY - 6) shr 3)..((l.regionY + 6) shr 3)) {
for (n in forId(regionX shl 8 or regionY).planes[l.z].npcs) {
if (n.location.withinDistance(l, (n.size() shr 1) + distance)) {
npcs.add(n)
}
}
}
}
return npcs
}
@JvmStatic
fun addRegion(id: Int, region: Region){
LOCK.tryLock(10000, TimeUnit.MILLISECONDS)
REGION_CACHE[id] = region
LOCK.unlock()
}
/**
* Gets the regionCache.
* @return The regionCache.
*/
val regionCache: Map<Int, Region>
@JvmStatic get(){
return REGION_CACHE
}
val lock: ReentrantLock
@JvmStatic get() = LOCK
}
@@ -122,14 +122,14 @@ public final class DynamicRegion extends Region {
Location loc = l.transform((x - baseX) << 6, (y - baseY) << 6, 0);
DynamicRegion region = copy(regionId, loc);
region.setBorders(border);
Region r = RegionManager.getRegionCache().get(region.getId());
Region r = RegionManager.forId(region.getId());
if (r != null) {
for (int z = 0; z < 4; z++) {
region.getPlanes()[z].getPlayers().addAll(r.getPlanes()[z].getPlayers());
region.getPlanes()[z].getNpcs().addAll(r.getPlanes()[z].getNpcs());
}
}
RegionManager.getRegionCache().put(region.getId(), region);
RegionManager.addRegion(region.getId(), region);
regions.add(region);
}
}
+22
View File
@@ -889,6 +889,18 @@ object ContentAPI {
player.packetDispatch.sendPlayerOnInterface(iface,child)
}
/**
* Sends a dialogue that uses the player's chathead.
* @param player the player to send the dialogue to
* @param npc the ID of the NPC to use for the chathead
* @param msg the message to send.
* @param expr the FacialExpression to use. An enum exists for these called FacialExpression. Defaults to FacialExpression.FRIENDLY
*/
@JvmStatic
fun sendNPCDialogue(player: Player, npc: Int, msg: String, expr: FacialExpression = FacialExpression.FRIENDLY){
player.dialogueInterpreter.sendDialogues(npc, expr, *DialUtils.splitLines(msg))
}
/**
* Sends an animation to a specific interface child
* @param player the player to send the packet to
@@ -972,4 +984,14 @@ object ContentAPI {
fun submitIndividualPulse(entity: Entity, pulse: Pulse){
entity.pulseManager.run(pulse)
}
/**
* Gets the number of QP a player has
* @param player the player to get the QP for
* @return the number of QP the player has
*/
@JvmStatic
fun getQP(player: Player): Int{
return player.questRepository.points
}
}
@@ -247,7 +247,7 @@ class ScriptAPI(private val bot: Player) {
* @return an Array of the nearest NPCs with matching name, or null.
* @author Ceikry
*/
private fun findTargets(entity: Entity?, radius: Int, name: String? = null): List<Entity>? {
private fun findTargets(entity: Entity, radius: Int, name: String? = null): List<Entity>? {
val targets: MutableList<Entity> = ArrayList()
val localNPCs: Array<Any> = RegionManager.getLocalNpcs(entity, radius).toTypedArray()
var length = localNPCs.size
@@ -41,7 +41,7 @@ class EquipHandler : InteractionListener() {
fun handleEquip(player: Player,node: Node){
val item = node.asItem()
if(item == null || player.inventory[item.slot] != item){
if(item == null || player.inventory[item.slot] != item || item.name.toLowerCase().contains("goblin mail")){
return
}
@@ -52,7 +52,9 @@ class EquipHandler : InteractionListener() {
return
}
}
InteractionListeners.run(node.id,player,node,true)
if(!InteractionListeners.run(node.id,player,node,true)){
return
}
val lock = player.locks.equipmentLock
if (lock != null && lock.isLocked) {
@@ -28,10 +28,10 @@ abstract class InteractionListener : Listener{
fun onUseWith(type: Int, used: IntArray, vararg with: Int, handler: (player: Player, used: Node, with: Node) -> Boolean){
InteractionListeners.add(type,used,with,handler)
}
fun onEquip(id: Int, handler: (player: Player, node: Node) -> Unit){
fun onEquip(id: Int, handler: (player: Player, node: Node) -> Boolean){
InteractionListeners.addEquip(id,handler)
}
fun onUnequip(id:Int, handler: (player: Player, node: Node) -> Unit){
fun onUnequip(id:Int, handler: (player: Player, node: Node) -> Boolean){
InteractionListeners.addUnequip(id,handler)
}
@@ -10,7 +10,7 @@ object InteractionListeners {
private val listeners = HashMap<String,(Player, Node) -> Boolean>(1000)
private val useWithListeners = HashMap<String,(Player,Node,Node) -> Boolean>(1000)
private val destinationOverrides = HashMap<String,(Node) -> Location>(100)
private val equipListeners = HashMap<String,(Player,Node) -> Unit>(10)
private val equipListeners = HashMap<String,(Player,Node) -> Boolean>(10)
@JvmStatic
fun add(id: Int, type: Int, option: Array<out String>, method: (Player,Node) -> Boolean){
@@ -53,22 +53,22 @@ object InteractionListeners {
}
@JvmStatic
fun addEquip(id: Int,method: (Player, Node) -> Unit){
fun addEquip(id: Int,method: (Player, Node) -> Boolean){
equipListeners["equip:$id"] = method
}
@JvmStatic
fun addUnequip(id: Int, method: (Player,Node) -> Unit){
fun addUnequip(id: Int, method: (Player,Node) -> Boolean){
equipListeners["unequip:$id"] = method
}
@JvmStatic
fun getEquip(id: Int): ((Player,Node) -> Unit)? {
fun getEquip(id: Int): ((Player,Node) -> Boolean)? {
return equipListeners["equip:$id"]
}
@JvmStatic
fun getUnequip(id: Int): ((Player,Node) -> Unit)? {
fun getUnequip(id: Int): ((Player,Node) -> Boolean)? {
return equipListeners["unequip:$id"]
}
@@ -124,11 +124,11 @@ object InteractionListeners {
}
@JvmStatic
fun run(id: Int, player: Player, node: Node, isEquip: Boolean){
fun run(id: Int, player: Player, node: Node, isEquip: Boolean): Boolean{
if(isEquip){
equipListeners["equip:$id"]?.invoke(player,node)
return equipListeners["equip:$id"]?.invoke(player,node)!!
} else {
equipListeners["unequip:$id"]?.invoke(player,node)
return equipListeners["unequip:$id"]?.invoke(player,node)!!
}
}
@@ -42,7 +42,7 @@ class CulChestItems: InteractionListener() {
}
fun alchemize(player: Player, node: Node){
fun alchemize(player: Player, node: Node): Boolean{
val amount = ContentAPI.amountInInventory(player, node.id) + ContentAPI.amountInEquipment(player, node.id)
val coins = amount * ContentAPI.itemDefinition(node.id).value
@@ -51,5 +51,6 @@ class CulChestItems: InteractionListener() {
ContentAPI.addItemOrDrop(player, 995, coins)
ContentAPI.sendDialogue(player, "The item instantly alchemized itself!")
return false //tell equip handler not to equip the gloves at all if they still even exist lel
}
}
@@ -0,0 +1,15 @@
package rs09.game.interaction.item
import api.ContentAPI
import org.rs09.consts.Items
import rs09.game.interaction.InteractionListener
class LegendsCapeLock : InteractionListener() {
override fun defineListeners() {
onEquip(Items.CAPE_OF_LEGENDS_1052){player, node ->
val points = ContentAPI.getQP(player)
if(points < 40) ContentAPI.sendDialogue(player, "You need 40 QP to equip that.")
return@onEquip points >= 40
}
}
}
@@ -23,10 +23,12 @@ class MistagEasterEgg : InteractionListener() {
onEquip(ZANIK_RING){player,_ ->
player.appearance.transformNPC(NPCs.ZANIK_3712)
return@onEquip true
}
onUnequip(ZANIK_RING){player, _ ->
player.appearance.transformNPC(-1)
return@onUnequip true
}
}
}
@@ -4,29 +4,20 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class ConfigParser {
fun prePlugin() = GlobalScope.launch{
launch {
fun prePlugin() {
NPCConfigParser().load()
ItemConfigParser().load()
}
launch {
ObjectConfigParser().load()
XteaParser().load()
}
InterfaceConfigParser().load()
InterfaceConfigParser().load()
}
fun postPlugin() = GlobalScope.launch{
launch {
fun postPlugin() {
ShopParser().load()
DropTableParser().load()
NPCSpawner().load()
}
launch {
DoorConfigLoader().load()
GroundSpawnLoader().load()
MusicConfigLoader().load()
}
RangedConfigLoader().load()
RangedConfigLoader().load()
}
}