mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-10 10:20:41 -07:00
New server config option to preload the world map on boot, removes lag caused by lazy loading (server.preload_map = true)
Cached region clipping flags for faster lookups Minor optimizations to setAttribute codepath which avoids unnecessary checks Fixed a bug that would allow entities to attack through walls Fixed two separate bugs that would cause odd behavior attacking large entities from certain angles Removed unnecessary schema from global.sql Ensured that all but the `members` and `worlds` tables could be safely dropped out of the DB Better automatic handling for creating the default server account and creating the default server clan Fixed bugs related to interfaces flagged as uncloseable that would cause stack overflows Fixed premature home teleport while in tutorial Fixed getting stuck by going back up ladder in tutorial Fixed bug that prevented bots from taking damage Fixed a bug where players would not be in the default clan after completion of the tutorial Green Dragon bots reintroduced, no longer buy any items (these bots sell loot from green dragons in the wilderness on the GE)
This commit is contained in:
parent
67e54d5429
commit
ebf2ed4ab4
32 changed files with 495 additions and 616 deletions
File diff suppressed because one or more lines are too long
|
|
@ -125,14 +125,11 @@ public class Component {
|
|||
* @param c The component.
|
||||
*/
|
||||
public static void setUnclosable(Player p, Component c) {
|
||||
p.setAttribute("close_c_", false);
|
||||
p.setAttribute("close_c_", true);
|
||||
c.setCloseEvent(new CloseEvent() {
|
||||
@Override
|
||||
public boolean close(Player player, Component c) {
|
||||
if (!player.getAttribute("close_c_", false)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !player.getAttribute("close_c_", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ import core.game.node.entity.skill.Skills;
|
|||
import core.game.node.entity.state.EntityState;
|
||||
import core.game.node.entity.state.StateManager;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.game.world.map.zone.ZoneBorders;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import rs09.game.system.SystemLogger;
|
||||
import rs09.game.world.GameWorld;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.Viewport;
|
||||
|
|
@ -33,6 +36,7 @@ import rs09.game.world.update.UpdateMasks;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
|
@ -780,10 +784,6 @@ public abstract class Entity extends Node {
|
|||
attributes.setAttribute(key, value);
|
||||
}
|
||||
|
||||
public void setExpirableAttribute(String key, Object value, Long timeToLive){
|
||||
attributes.setExpirableAttribute(key,value,timeToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an attribute.
|
||||
* @param key The attribute name.
|
||||
|
|
@ -938,4 +938,34 @@ public abstract class Entity extends Node {
|
|||
this.invisible = invisible;
|
||||
}
|
||||
|
||||
public Location getClosestOccupiedTile(@NotNull Location other) {
|
||||
List<Location> occupied = getOccupiedTiles();
|
||||
|
||||
Location closest = location;
|
||||
if (occupied.size() > 1) {
|
||||
double lowest = 9999;
|
||||
for (Location tile : occupied) {
|
||||
double dist = tile.getDistance(other);
|
||||
if (dist < lowest) {
|
||||
lowest = dist;
|
||||
closest = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
public List<Location> getOccupiedTiles() {
|
||||
ArrayList<Location> occupied = new ArrayList<>();
|
||||
|
||||
Location northEast = location.transform(size, size, 0);
|
||||
|
||||
for (int x = location.getX(); x < northEast.getX(); x++) {
|
||||
for (int y = location.getY(); y < northEast.getY(); y++) {
|
||||
occupied.add(Location.create(x, y, location.getZ()));
|
||||
}
|
||||
}
|
||||
return occupied;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import core.game.node.entity.player.Player;
|
|||
import core.game.node.entity.player.link.prayer.PrayerType;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.system.task.Pulse;
|
||||
import rs09.game.ai.AIPlayer;
|
||||
import rs09.game.world.GameWorld;
|
||||
import core.game.world.map.zone.ZoneType;
|
||||
|
||||
|
|
@ -144,7 +145,7 @@ public final class ImpactHandler {
|
|||
if (disabledTicks > GameWorld.getTicks()) {
|
||||
return null;
|
||||
}
|
||||
if (entity instanceof Player && !(entity.getAttribute("tutorial:complete",false))) {
|
||||
if (entity instanceof Player && !(entity instanceof AIPlayer) && !(entity.getAttribute("tutorial:complete",false))) {
|
||||
Impact impact = new Impact(source, 0, style, HitsplatType.MISS);
|
||||
impactQueue.add(impact);
|
||||
return impact;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ public final class GameAttributes {
|
|||
*/
|
||||
public void setAttribute(String key, Object value) {
|
||||
if (key.startsWith("/save:")) {
|
||||
key = key.substring(6, key.length());
|
||||
key = key.substring(6);
|
||||
if (!savedAttributes.contains(key)) {
|
||||
savedAttributes.add(key);
|
||||
}
|
||||
|
|
@ -144,17 +144,6 @@ public final class GameAttributes {
|
|||
attributes.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an inherently temporary (but saved cross-session) key.
|
||||
* @param key the key to set
|
||||
* @param value the value to assign to the key
|
||||
* @param timeToLive the time (in milliseconds) that the key will be valid for
|
||||
*/
|
||||
public void setExpirableAttribute(String key, Object value, Long timeToLive){
|
||||
setAttribute(key,value);
|
||||
keyExpirations.put(key,System.currentTimeMillis() + timeToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an attribute.
|
||||
* @param key The attribute name.
|
||||
|
|
@ -163,9 +152,6 @@ public final class GameAttributes {
|
|||
@SuppressWarnings("unchecked")
|
||||
public <T> T getAttribute(String key) {
|
||||
key = key.replace("/save:","");
|
||||
if (!attributes.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
return (T) attributes.get(key);
|
||||
}
|
||||
|
||||
|
|
@ -182,9 +168,6 @@ public final class GameAttributes {
|
|||
if (object != null) {
|
||||
return (T) object;
|
||||
}
|
||||
if(keyExpirations.containsKey(string) && keyExpirations.get(string) < System.currentTimeMillis()){
|
||||
return fail;
|
||||
}
|
||||
return fail;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ public class NPC extends Entity {
|
|||
if (dialoguePlayer == null || !dialoguePlayer.isActive() || !dialoguePlayer.getInterfaceManager().hasChatbox()) {
|
||||
dialoguePlayer = null;
|
||||
if (walks && !getPulseManager().hasPulseRunning() && !getProperties().getCombatPulse().isAttacking() && !getProperties().getCombatPulse().isInCombat() && nextWalk < GameWorld.getTicks()) {
|
||||
if (RandomFunction.nextBool()) return;
|
||||
setNextWalk();
|
||||
Location l = getMovementDestination();
|
||||
if (canMove(l)) {
|
||||
|
|
|
|||
|
|
@ -193,9 +193,6 @@ public class RevenantNPC extends AbstractNPC {
|
|||
|
||||
@Override
|
||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||
if (entity.asPlayer().isArtificial()) {
|
||||
return false;
|
||||
}
|
||||
if (entity instanceof Player) {
|
||||
if (!checkCombatLevel(entity.asPlayer()) && !entity.asPlayer().isAdmin()) {
|
||||
if(message) {
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class BuildRegionChunk extends RegionChunk {
|
|||
objects[i][x][y] = null;
|
||||
}
|
||||
plane.getObjects()[baseX + x][baseY + y] = null;
|
||||
plane.getFlags().getClippingFlags()[baseX + x][baseY + y] = 0;
|
||||
plane.getFlags().clearFlag(baseX + x, baseY + y);
|
||||
}
|
||||
}
|
||||
clear();
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@ import core.game.node.Node;
|
|||
import core.game.world.map.path.Path;
|
||||
import core.game.world.map.path.Pathfinder;
|
||||
import core.tools.RandomFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import rs09.game.system.SystemLogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a location on the world map.
|
||||
|
|
@ -491,4 +494,45 @@ public final class Location extends Node {
|
|||
public void setZ(int z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Location> getStepComponents(Direction dir) {
|
||||
List<Location> output = new ArrayList<>(2);
|
||||
int stepX = dir.getStepX();
|
||||
int stepY = dir.getStepY();
|
||||
|
||||
if (stepX != 0) output.add(transform(stepX, 0, 0));
|
||||
if (stepY != 0) output.add(transform(0, stepY, 0));
|
||||
return output;
|
||||
}
|
||||
|
||||
public Direction deriveDirection(Location location) {
|
||||
int diffX = location.x - this.x;
|
||||
int diffY = location.y - this.y;
|
||||
|
||||
diffX = diffX >= 0 ? Math.min(diffX, 1) : -1;
|
||||
diffY = diffY >= 0 ? Math.min(diffY, 1) : -1;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (diffY != 0) {
|
||||
if (diffY > 0) {
|
||||
sb.append("NORTH");
|
||||
} else {
|
||||
sb.append("SOUTH");
|
||||
}
|
||||
}
|
||||
|
||||
if (diffX != 0) {
|
||||
if (sb.length() > 0) sb.append("_");
|
||||
if (diffX > 0) {
|
||||
sb.append("EAST");
|
||||
} else {
|
||||
sb.append("WEST");
|
||||
}
|
||||
}
|
||||
|
||||
if (sb.length() == 0) return null;
|
||||
return Direction.valueOf(sb.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,8 +301,8 @@ public class Region {
|
|||
byte[][][] mapscapeData = new byte[4][SIZE][SIZE];
|
||||
for (RegionPlane plane : r.planes) {
|
||||
plane.getFlags().setLandscape(new boolean[SIZE][SIZE]);
|
||||
plane.getFlags().setClippingFlags(new int[SIZE][SIZE]);
|
||||
plane.getProjectileFlags().setClippingFlags(new int[SIZE][SIZE]);
|
||||
//plane.getFlags().setClippingFlags(new int[SIZE][SIZE]);
|
||||
//plane.getProjectileFlags().setClippingFlags(new int[SIZE][SIZE]);
|
||||
}
|
||||
if (mapscapeId > -1) {
|
||||
ByteBuffer mapscape = ByteBuffer.wrap(Cache.getIndexes()[5].getCacheFile().getContainerUnpackedData(mapscapeId));
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ public class RegionChunk {
|
|||
copy[x][y] = objects[x][y];
|
||||
staticCopy[x][y] = plane.getObjects()[baseX + x][baseY + y];
|
||||
objects[x][y] = plane.getObjects()[baseX + x][baseY + y] = null;
|
||||
plane.getFlags().getClippingFlags()[baseX + x][baseY + y] = 0;
|
||||
plane.getFlags().clearFlag(baseX + x, baseY + y);
|
||||
}
|
||||
}
|
||||
rotation = direction.toInteger();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import rs09.game.system.SystemLogger
|
|||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* Manages the regions.
|
||||
|
|
@ -21,6 +22,8 @@ object RegionManager {
|
|||
* The region cache mapping.
|
||||
*/
|
||||
private val REGION_CACHE: MutableMap<Int, Region> = HashMap()
|
||||
@JvmStatic val CLIPPING_FLAGS = HashMap<Int, Array<Int>>()
|
||||
@JvmStatic val PROJECTILE_FLAGS = HashMap<Int, Array<Int>>()
|
||||
|
||||
public val LOCK = ReentrantLock()
|
||||
|
||||
|
|
@ -80,16 +83,50 @@ object RegionManager {
|
|||
*/
|
||||
@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
|
||||
val regionX = x shr 6
|
||||
val regionY = y shr 6
|
||||
val localX = x and 63
|
||||
val localY = y and 63
|
||||
return getClippingFlag(z, regionX, regionY, localX, localY)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clipping flags using Jagex-style coords
|
||||
* e.g 0_50_50_13_13 gets plane 0, region 50-50 (12850), (13, 13) which is in lumbridge.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getClippingFlag(z: Int, regionX: Int, regionY: Int, localX: Int, localY: Int, projectile: Boolean = false) : Int {
|
||||
val (region, index) = getFlagIndex(z, regionX, regionY, localX, localY)
|
||||
var flag = getFlags(region, projectile)[index]
|
||||
|
||||
if (flag == -1) {
|
||||
val r = forId((regionX shr 8) or regionY)
|
||||
if (!r.isLoaded)
|
||||
Region.load(r)
|
||||
if (!r.isHasFlags)
|
||||
return -1
|
||||
flag = getFlags(region, projectile)[index]
|
||||
}
|
||||
x -= (x shr 6) shl 6
|
||||
y -= (y shr 6) shl 6
|
||||
return region.planes[z].flags.clippingFlags[x][y]
|
||||
|
||||
return flag
|
||||
}
|
||||
|
||||
private fun getFlagIndex(z: Int, regionX: Int, regionY: Int, localX: Int, localY: Int) : Pair<Int,Int> {
|
||||
return Pair((regionX shl 8) or regionY, (z * 64 * 64) + (localX * 64) + localY)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getFlags(regionX: Int, regionY: Int, projectile: Boolean) : Array<Int> {
|
||||
val region = (regionX shl 8) or regionY
|
||||
return getFlags(region, projectile)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getFlags(regionId: Int, projectile: Boolean) : Array<Int> {
|
||||
return if (projectile)
|
||||
PROJECTILE_FLAGS.getOrPut (regionId) {Array(16384){0}}
|
||||
else
|
||||
CLIPPING_FLAGS.getOrPut (regionId) {Array(16384){-1}}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -136,26 +173,6 @@ object RegionManager {
|
|||
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.
|
||||
|
|
@ -217,16 +234,11 @@ object RegionManager {
|
|||
*/
|
||||
@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]
|
||||
val regionX = x shr 6
|
||||
val regionY = y shr 6
|
||||
val localX = x and 63
|
||||
val localY = y and 63
|
||||
return getClippingFlag(z, regionX, regionY, localX, localY, true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -320,8 +320,8 @@ public final class DynamicRegion extends Region {
|
|||
if (chunk == null) {
|
||||
for (int i = x << 3; i < (x + 1) << 3; i++) {
|
||||
for (int j = y << 3; j < (y + 1) << 3; j++) {
|
||||
p.getFlags().getClippingFlags()[i][j] = -1;
|
||||
p.getProjectileFlags().getClippingFlags()[i][j] = -1;
|
||||
p.getFlags().invalidateFlag(i, j);
|
||||
p.getProjectileFlags().invalidateFlag(i, j);
|
||||
Scenery object = p.getObjects()[i][j];
|
||||
if (object != null) {
|
||||
LandscapeParser.removeScenery(object);
|
||||
|
|
@ -344,8 +344,8 @@ public final class DynamicRegion extends Region {
|
|||
int fromX = (l.getX() - regionBase.getX()) + i;
|
||||
int fromY = (l.getY() - regionBase.getY()) + j;
|
||||
p.getFlags().getLandscape()[toX][toY] = rp.getFlags().getLandscape()[fromX][fromY];
|
||||
p.getFlags().getClippingFlags()[toX][toY] = rp.getFlags().getClippingFlags()[fromX][fromY];
|
||||
p.getProjectileFlags().getClippingFlags()[toX][toY] = rp.getProjectileFlags().getClippingFlags()[fromX][fromY];
|
||||
p.getFlags().flag(fromX, fromY, rp.getFlags().getFlag(fromX, fromY));
|
||||
p.getProjectileFlags().flag(fromX, fromY, rp.getFlags().getFlag(fromX, fromY));
|
||||
Scenery[] objects = { rp.getChunkObject(fromX, fromY) };
|
||||
RegionChunk ch = rp.getChunks()[fromX >> 3][fromY >> 3];
|
||||
if (ch instanceof BuildRegionChunk) {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public final class MapscapeParser {
|
|||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 64; x++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
r.getPlanes()[z].getFlags().flagEmptyTile(x,y);
|
||||
if ((mapscape[z][x][y] & 0x1) == 1) {
|
||||
int plane = z;
|
||||
if ((mapscape[1][x][y] & 0x2) == 2) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package core.game.world.map.build;
|
||||
|
||||
import core.game.world.map.RegionManager;
|
||||
import kotlin.Pair;
|
||||
import rs09.game.system.SystemLogger;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
|
||||
/**
|
||||
* Holds a region's flags like clipping flags, members, ...
|
||||
|
|
@ -9,6 +13,11 @@ import core.game.world.map.RegionManager;
|
|||
*/
|
||||
public final class RegionFlags {
|
||||
|
||||
public static final int TILE_OBJECT = 0x40000;
|
||||
public static final int EMPTY_TILE = 0;
|
||||
public static final int SOLID_TILE = 0x200000;
|
||||
public static final int OBJ_10_PROJECTILE = 0x20000;
|
||||
public static final int OBJ_10 = 0x100;
|
||||
/**
|
||||
* The plane.
|
||||
*/
|
||||
|
|
@ -28,11 +37,6 @@ public final class RegionFlags {
|
|||
* The base y-coordinate.
|
||||
*/
|
||||
private final int baseY;
|
||||
|
||||
/**
|
||||
* The clipping flags.
|
||||
*/
|
||||
private int[][] clippingFlags;
|
||||
|
||||
/**
|
||||
* The landscape data.
|
||||
|
|
@ -42,7 +46,7 @@ public final class RegionFlags {
|
|||
/**
|
||||
* If the flags are set for projectile clipping
|
||||
*/
|
||||
private boolean projectile;
|
||||
private final boolean projectile;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RegionFlags} {@code Object}.
|
||||
|
|
@ -71,7 +75,11 @@ public final class RegionFlags {
|
|||
* @param y The y-coordinate.
|
||||
*/
|
||||
public void flagSolidTile(int x, int y) {
|
||||
clippingFlags[x][y] |= 0x200000;
|
||||
flag(x, y, SOLID_TILE);
|
||||
}
|
||||
|
||||
public void flagEmptyTile(int x, int y) {
|
||||
flag(x, y, EMPTY_TILE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,7 +88,7 @@ public final class RegionFlags {
|
|||
* @param y The y-coordinate.
|
||||
*/
|
||||
public void flagTileObject(int x, int y) {
|
||||
clippingFlags[x][y] |= 0x40000;
|
||||
flag(x, y, TILE_OBJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,12 +97,7 @@ public final class RegionFlags {
|
|||
* @param y The y-coordinate.
|
||||
*/
|
||||
public void unflagTileObject(int x, int y) {
|
||||
if (clippingFlags == null) {
|
||||
return;
|
||||
}
|
||||
if ((clippingFlags[x][y] & 0x40000) != 0) {
|
||||
clippingFlags[x][y] &= ~0x40000;
|
||||
}
|
||||
unflag(x, y, TILE_OBJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,9 +109,9 @@ public final class RegionFlags {
|
|||
* @param projectileClipped If the object is solid.
|
||||
*/
|
||||
public void flagSolidObject(int x, int y, int sizeX, int sizeY, boolean projectileClipped) {
|
||||
int clipdata = 0x100;
|
||||
int clipdata = OBJ_10;
|
||||
if (projectileClipped) {
|
||||
clipdata += 0x20000;
|
||||
clipdata += OBJ_10_PROJECTILE;
|
||||
}
|
||||
for (int i = x; i < x + sizeX; i++) {
|
||||
for (int j = y; j < y + sizeY; j++) {
|
||||
|
|
@ -125,12 +128,11 @@ public final class RegionFlags {
|
|||
*/
|
||||
public void flag(int x, int y, int clipdata) {
|
||||
if (x > -1 && x < 64 && y > -1 && y < 64) {
|
||||
clippingFlags[x][y] |= clipdata;
|
||||
addFlag(x, y, clipdata);
|
||||
} else {
|
||||
RegionManager.addClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unflags a solid object (type 10/11).
|
||||
|
|
@ -141,9 +143,9 @@ public final class RegionFlags {
|
|||
* @param projectileClipped If the object is solid.
|
||||
*/
|
||||
public void unflagSolidObject(int x, int y, int sizeX, int sizeY, boolean projectileClipped) {
|
||||
int clipdata = 0x100;
|
||||
int clipdata = OBJ_10;
|
||||
if (projectileClipped) {
|
||||
clipdata += 0x20000;
|
||||
clipdata += OBJ_10_PROJECTILE;
|
||||
}
|
||||
for (int i = x; i < x + sizeX; i++) {
|
||||
for (int j = y; j < y + sizeY; j++) {
|
||||
|
|
@ -159,18 +161,47 @@ public final class RegionFlags {
|
|||
* @param clipdata The clip data.
|
||||
*/
|
||||
public void unflag(int x, int y, int clipdata) {
|
||||
if (clippingFlags == null) {
|
||||
return;
|
||||
}
|
||||
if (x > -1 && x < 64 && y > -1 && y < 64) {
|
||||
if ((clippingFlags[x][y] & clipdata) != 0) {
|
||||
clippingFlags[x][y] &= ~clipdata;
|
||||
}
|
||||
removeFlag(x, y, clipdata);
|
||||
} else {
|
||||
RegionManager.removeClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata);
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<Integer, Integer> getFlagIndex(int x, int y) {
|
||||
return new Pair<>(((baseX >> 6) << 8) | (baseY >> 6), (plane * 64 * 64) + (x * 64) + y);
|
||||
}
|
||||
|
||||
public int getFlag(int x, int y) {
|
||||
Pair<Integer, Integer> indices = getFlagIndex(x, y);
|
||||
return RegionManager.getFlags(indices.getFirst(), projectile)[indices.getSecond()];
|
||||
}
|
||||
|
||||
public void addFlag(int x, int y, int clipdata) {
|
||||
int current = getFlag(x, y);
|
||||
Pair<Integer, Integer> indices = getFlagIndex(x, y);
|
||||
RegionManager.getFlags(indices.getFirst(), projectile)[indices.getSecond()] = max(0, current) | clipdata;
|
||||
}
|
||||
|
||||
public void removeFlag(int x, int y, int clipdata) {
|
||||
int current = getFlag(x, y);
|
||||
Pair<Integer, Integer> indices = getFlagIndex(x, y);
|
||||
if ((current & clipdata) == 0) return;
|
||||
current = max(0, current) & ~clipdata;
|
||||
|
||||
RegionManager.getFlags(indices.getFirst(), projectile)[indices.getSecond()] = current;
|
||||
}
|
||||
|
||||
public void clearFlag(int x, int y) {
|
||||
Pair<Integer, Integer> indices = getFlagIndex(x, y);
|
||||
RegionManager.getFlags(indices.getFirst(), projectile)[indices.getSecond()] = 0;
|
||||
}
|
||||
|
||||
public void invalidateFlag(int x, int y) {
|
||||
Pair<Integer, Integer> indices = getFlagIndex(x, y);
|
||||
RegionManager.getFlags(indices.getFirst(), projectile)[indices.getSecond()] = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags a door object (type 0-3).
|
||||
* @param x The x-coordinate
|
||||
|
|
@ -465,13 +496,6 @@ public final class RegionFlags {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the clipping flags.
|
||||
*/
|
||||
public void unload() {
|
||||
clippingFlags = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the members.
|
||||
* @return The members.
|
||||
|
|
@ -488,22 +512,6 @@ public final class RegionFlags {
|
|||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clippingFlags.
|
||||
* @return The clippingFlags.
|
||||
*/
|
||||
public int[][] getClippingFlags() {
|
||||
return clippingFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clippingFlags.
|
||||
* @param clippingFlags The clippingFlags to set.
|
||||
*/
|
||||
public void setClippingFlags(int[][] clippingFlags) {
|
||||
this.clippingFlags = clippingFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plane.
|
||||
* @return The plane.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import java.util.List;
|
|||
* @author Emperor
|
||||
*/
|
||||
public final class DumbPathfinder extends Pathfinder {
|
||||
|
||||
/**
|
||||
* If a path can be found.
|
||||
*/
|
||||
|
|
@ -103,7 +102,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
found = true;
|
||||
switch (dir) {
|
||||
case NORTH:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x, y + 1) & 0x12c0120) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x, y + 1) & PREVENT_NORTH) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -111,7 +110,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
y++;
|
||||
break;
|
||||
case NORTH_EAST:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & 0x12c0180) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y + 1) & 0x12c0120) != 0 || (clipMaskSupplier.getClippingFlag(z, x + 1, y + 1) & 0x12c01e0) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & PREVENT_EAST) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y + 1) & PREVENT_NORTH) != 0 || (clipMaskSupplier.getClippingFlag(z, x + 1, y + 1) & PREVENT_NORTHEAST) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -120,7 +119,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
y++;
|
||||
break;
|
||||
case EAST:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & 0x12c0180) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & PREVENT_EAST) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -128,7 +127,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
x++;
|
||||
break;
|
||||
case SOUTH_EAST:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & 0x12c0180) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y - 1) & 0x12c0102) != 0 || (clipMaskSupplier.getClippingFlag(z, x + 1, y - 1) & 0x12c0183) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & PREVENT_EAST) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y - 1) & PREVENT_SOUTH) != 0 || (clipMaskSupplier.getClippingFlag(z, x + 1, y - 1) & PREVENT_SOUTHEAST) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -137,7 +136,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
y--;
|
||||
break;
|
||||
case SOUTH:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x, y - 1) & 0x12c0102) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x, y - 1) & PREVENT_SOUTH) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -145,7 +144,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
y--;
|
||||
break;
|
||||
case SOUTH_WEST:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & 0x12c0108) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y - 1) & 0x12c0102) != 0 || (clipMaskSupplier.getClippingFlag(z, x - 1, y - 1) & 0x12c010e) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & PREVENT_WEST) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y - 1) & PREVENT_SOUTH) != 0 || (clipMaskSupplier.getClippingFlag(z, x - 1, y - 1) & PREVENT_SOUTHWEST) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -154,7 +153,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
y--;
|
||||
break;
|
||||
case WEST:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & 0x12c0108) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & PREVENT_WEST) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -162,7 +161,7 @@ public final class DumbPathfinder extends Pathfinder {
|
|||
x--;
|
||||
break;
|
||||
case NORTH_WEST:
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & 0x12c0108) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y + 1) & 0x12c0120) != 0 || (clipMaskSupplier.getClippingFlag(z, x - 1, y + 1) & 0x12c0138) != 0) {
|
||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & PREVENT_WEST) != 0 || (clipMaskSupplier.getClippingFlag(z, x, y + 1) & PREVENT_NORTH) != 0 || (clipMaskSupplier.getClippingFlag(z, x - 1, y + 1) & PREVENT_NORTHWEST) != 0) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,15 @@ import core.game.world.map.RegionManager;
|
|||
import rs09.game.world.map.path.SmartPathfinder;
|
||||
|
||||
public abstract class Pathfinder {
|
||||
public static final int PREVENT_NORTH = 0x12c0120;
|
||||
public static final int PREVENT_EAST = 0x12c0180;
|
||||
public static final int PREVENT_NORTHEAST = 0x12c01e0;
|
||||
public static final int PREVENT_SOUTH = 0x12c0102;
|
||||
public static final int PREVENT_SOUTHEAST = 0x12c0183;
|
||||
public static final int PREVENT_WEST = 0x12c0108;
|
||||
public static final int PREVENT_SOUTHWEST = 0x12c010e;
|
||||
public static final int PREVENT_NORTHWEST = 0x12c0138;
|
||||
|
||||
|
||||
/**
|
||||
* The smart path finder.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import core.game.node.item.Item;
|
|||
import core.net.packet.IncomingPacket;
|
||||
import core.net.packet.IoBuffer;
|
||||
|
||||
import static api.ContentAPIKt.getAttribute;
|
||||
|
||||
/**
|
||||
* Represents the packet to handle an item slot switch.
|
||||
* @author 'Vexia
|
||||
|
|
@ -82,7 +84,7 @@ public class SlotSwitchPacket implements IncomingPacket {
|
|||
|
||||
final Item item = container.get(slot);
|
||||
final Item second = container.get(secondSlot);
|
||||
if (player.getInterfaceManager().hasChatbox()) {
|
||||
if (player.getInterfaceManager().hasChatbox() && !getAttribute(player, "close_c_", false)) {
|
||||
player.getInterfaceManager().closeChatbox();
|
||||
switchItem(secondSlot,slot,container,insert,player);
|
||||
container.refresh();
|
||||
|
|
|
|||
|
|
@ -217,5 +217,8 @@ class ServerConstants {
|
|||
|
||||
@JvmField
|
||||
var DISCORD_GE_WEBHOOK = ""
|
||||
|
||||
@JvmField
|
||||
var PRELOAD_MAP = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ import core.game.world.map.Location
|
|||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.ChatMessage
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.game.world.update.flag.player.ChatFlag
|
||||
import core.tools.RandomFunction
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -99,6 +101,11 @@ class ScriptAPI(private val bot: Player) {
|
|||
return entity
|
||||
}
|
||||
|
||||
fun sendChat(message: String) {
|
||||
bot.sendChat(message)
|
||||
bot.updateMasks.register(ChatFlag(ChatMessage(bot, message, 0, 0)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest node with a name contained in the list of acceptable names
|
||||
* @param acceptedNames the list of accepted npc/object names
|
||||
|
|
@ -422,7 +429,10 @@ class ScriptAPI(private val bot: Player) {
|
|||
* A function for teleporting the bot to the GE
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun teleportToGE(){
|
||||
fun teleportToGE() : Boolean{
|
||||
if (bot.isTeleBlocked) {
|
||||
return false
|
||||
}
|
||||
bot.lock()
|
||||
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
||||
bot.impactHandler.disabledTicks = 4
|
||||
|
|
@ -435,6 +445,7 @@ class ScriptAPI(private val bot: Player) {
|
|||
return true
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -548,7 +559,10 @@ class ScriptAPI(private val bot: Player) {
|
|||
* @param loc the location to teleport to
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun teleport(loc: Location){
|
||||
fun teleport(loc: Location) : Boolean {
|
||||
if (bot.isTeleBlocked) {
|
||||
return false
|
||||
}
|
||||
bot.lock()
|
||||
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
||||
bot.impactHandler.disabledTicks = 4
|
||||
|
|
@ -561,6 +575,7 @@ class ScriptAPI(private val bot: Player) {
|
|||
return true
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -457,8 +457,7 @@ class Adventurer(val style: CombatStyle): Script() {
|
|||
.replace("@name", localPlayer.username)
|
||||
.replace("@timer", until.toString())
|
||||
|
||||
bot.sendChat(chat)
|
||||
bot.updateMasks.register(ChatFlag(ChatMessage(bot, chat, 0, 0)))
|
||||
scriptAPI.sendChat(chat)
|
||||
}
|
||||
|
||||
enum class State{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import core.game.node.entity.combat.CombatStyle
|
|||
import core.game.node.entity.combat.InteractionType
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.entity.skill.prayer.BoneBuryingOptionPlugin
|
||||
import core.game.node.entity.state.EntityState
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
|
|
@ -15,6 +16,7 @@ import core.game.world.map.Location
|
|||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.game.world.map.zone.impl.WildernessZone
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
import rs09.game.ai.AIRepository
|
||||
import rs09.game.ai.pvmbots.CombatBotAssembler
|
||||
|
|
@ -25,16 +27,24 @@ import rs09.game.node.entity.combat.handlers.RangeSwingHandler
|
|||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* A bot script for killing green dragons in the wilderness.. Capable of banking, selling on ge, buying on ge, eating and more.
|
||||
* A bot script for killing green dragons in the wilderness.. Capable of banking, selling on ge, eating, trash talking, buries bones when fleeing and more.
|
||||
* @param style The combat style the bot is going to use.
|
||||
* @param area (optional) What area the bot tries to kill dragons in.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Script() {
|
||||
var state = State.KILLING
|
||||
companion object {
|
||||
val westDragons = ZoneBorders(2971,3606,2991,3628)
|
||||
val wildernessLine = ZoneBorders(3078,3523,3096,3523)
|
||||
val edgevilleLine = ZoneBorders(3078,3520,3096,3520)
|
||||
val bankZone = ZoneBorders(3092,3489,3094,3493)
|
||||
val trashTalkLines = arrayOf("Bro, seriously?", "Ffs.", "Jesus christ.", "????", "Friendly!", "Get a life dude", "Do you mind??? lol", "Lol.", "Kek.", "One sec burying all the bones.", "Yikes.", "Yeet", "Ah shit, here we go again.", "Cmonnnn", "Plz", "Do you have nothing better to do?", "Cmon bro pls", "I just need to get my prayer up bro jesus", "Reeeeeee", "I cant believe you've done this", "Really m8", "Zomg", "Aaaaaaaaaaaaaaaaaaaaa", "Rofl.", "Oh god oh fuck oh shit", "....", ":|", "A q p", "Hcim btw", "I hope the revenants kill your mum", "Wrap your ass titties", "Why do this", "Bruh", "Straight sussin no cap fr fr", "This ain't bussin dawg", "Really bro?")
|
||||
}
|
||||
var state = State.TO_BANK
|
||||
var handler: CombatSwingHandler? = null
|
||||
var lootDelay = 0
|
||||
var offerMade = false
|
||||
var trashTalkDelay = 0
|
||||
|
||||
var food = if (Random.nextBoolean()){
|
||||
Items.LOBSTER_379
|
||||
|
|
@ -45,28 +55,18 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
}
|
||||
|
||||
var myBorders: ZoneBorders? = null
|
||||
val type = when(style){
|
||||
CombatStyle.MELEE -> CombatBotAssembler.Type.MELEE
|
||||
CombatStyle.MAGIC -> CombatBotAssembler.Type.MAGE
|
||||
CombatStyle.RANGE -> CombatBotAssembler.Type.RANGE
|
||||
}
|
||||
val type = CombatBotAssembler.Type.MELEE
|
||||
|
||||
val westDragons = ZoneBorders(2971,3606,2991,3628)
|
||||
val wildernessLine = ZoneBorders(3078,3523,3096,3523)
|
||||
val edgevilleLine = ZoneBorders(3078,3520,3096,3520)
|
||||
val bankZone = ZoneBorders(3092,3489,3094,3493)
|
||||
override fun tick() {
|
||||
if(!bot.isActive){
|
||||
running = false
|
||||
return
|
||||
}
|
||||
if(bot.inventory.getAmount(food) < 3 && state == State.KILLING)
|
||||
state = State.TO_BANK
|
||||
scriptAPI.eat(food)
|
||||
|
||||
checkFoodStockAndEat()
|
||||
|
||||
when(state){
|
||||
|
||||
|
||||
|
||||
State.KILLING -> {
|
||||
bot.properties.combatPulse.temporaryHandler = handler
|
||||
scriptAPI.attackNpcInRadius(bot,"Green dragon",20)
|
||||
|
|
@ -86,11 +86,13 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
if(players.isEmpty()){
|
||||
state = State.TO_DRAGONS
|
||||
} else {
|
||||
if(bot.skullManager.level < 21 && bot.stateManager.get(EntityState.TELEBLOCK) != null){
|
||||
scriptAPI.teleportToGE()
|
||||
state = State.REFRESHING
|
||||
if(bot.skullManager.level < 21){
|
||||
if (scriptAPI.teleportToGE())
|
||||
state = State.REFRESHING
|
||||
return
|
||||
}
|
||||
sendTrashTalk()
|
||||
attemptToBuryBone()
|
||||
scriptAPI.walkTo(WildernessZone.getInstance().borders.random().randomLoc)
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +109,7 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
}
|
||||
return
|
||||
}
|
||||
items.forEach {it: Item -> scriptAPI.takeNearestGroundItem(it.id)}
|
||||
items.toTypedArray().forEach {it: Item -> scriptAPI.takeNearestGroundItem(it.id)}
|
||||
}
|
||||
|
||||
State.TO_BANK -> {
|
||||
|
|
@ -157,25 +159,10 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
}
|
||||
|
||||
State.BUYING_FOOD -> {
|
||||
if(!offerMade)
|
||||
{
|
||||
scriptAPI.buyFromGE(bot, food, 100)
|
||||
offerMade = true
|
||||
} else
|
||||
{
|
||||
val offer = AIRepository.getOffer(bot)
|
||||
if (offer == null) {
|
||||
offerMade = false
|
||||
} else {
|
||||
if (offer.completedAmount == offer.amount) {
|
||||
state = State.TO_DRAGONS
|
||||
offer.offerState = OfferState.REMOVED
|
||||
bot.bank.add(Item(offer.itemID, offer.completedAmount))
|
||||
bot.bank.refresh()
|
||||
scriptAPI.withdraw(food, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
state = State.TO_DRAGONS
|
||||
bot.bank.add(Item(food,50))
|
||||
bot.bank.refresh()
|
||||
scriptAPI.withdraw(food, 10)
|
||||
}
|
||||
|
||||
State.TO_DRAGONS -> {
|
||||
|
|
@ -236,13 +223,29 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
}
|
||||
}
|
||||
|
||||
private fun attemptToBuryBone() {
|
||||
if (bot.inventory.containsAtLeastOneItem(Items.DRAGON_BONES_536)) {
|
||||
BoneBuryingOptionPlugin().handle(bot, bot.inventory.get(Item(Items.DRAGON_BONES_536)), "bury")
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFoodStockAndEat() {
|
||||
if (bot.inventory.getAmount(food) < 3 && state == State.KILLING)
|
||||
state = State.TO_BANK
|
||||
scriptAPI.eat(food)
|
||||
}
|
||||
|
||||
private fun sendTrashTalk() {
|
||||
if (trashTalkDelay-- == 0)
|
||||
scriptAPI.sendChat(trashTalkLines.random())
|
||||
else
|
||||
trashTalkDelay = RandomFunction.random(10, 30)
|
||||
}
|
||||
|
||||
override fun newInstance(): Script {
|
||||
val script = GreenDragonKiller(style)
|
||||
val tier = CombatBotAssembler.Tier.HIGH
|
||||
if(type == CombatBotAssembler.Type.RANGE)
|
||||
script.bot = CombatBotAssembler().assembleRangeDragonBot(tier,bot.startLocation)
|
||||
else
|
||||
script.bot = CombatBotAssembler().assembleMeleeDragonBot(tier, bot.startLocation)
|
||||
val tier = CombatBotAssembler.Tier.MED
|
||||
script.bot = CombatBotAssembler().assembleMeleeDragonBot(tier, bot.startLocation)
|
||||
return script
|
||||
}
|
||||
|
||||
|
|
@ -262,11 +265,7 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
}
|
||||
|
||||
init {
|
||||
handler = when(style){
|
||||
CombatStyle.MELEE -> MeleeSwinger(this)
|
||||
CombatStyle.MAGIC -> MageSwinger(this)
|
||||
CombatStyle.RANGE -> RangeSwinger(this)
|
||||
}
|
||||
handler = MeleeSwinger(this)
|
||||
equipment.add(Item(Items.ANTI_DRAGON_SHIELD_1540))
|
||||
myBorders = westDragons
|
||||
skills[Skills.AGILITY] = 99
|
||||
|
|
@ -276,22 +275,10 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
|||
|
||||
internal class MeleeSwinger(val script: GreenDragonKiller) : MeleeSwingHandler() {
|
||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||
if(script.state == State.TO_BANK) {script.bot.pulseManager.current.stop()}
|
||||
if(victim is Player) {script.state = State.RUNNING; script.bot.pulseManager.current.stop()}
|
||||
return super.canSwing(entity, victim)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MageSwinger(val script: GreenDragonKiller) : MagicSwingHandler() {
|
||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||
if(victim is Player) {script.state = State.RUNNING; script.bot.pulseManager.current.stop()}
|
||||
return super.canSwing(entity, victim)
|
||||
}
|
||||
}
|
||||
|
||||
internal class RangeSwinger(val script: GreenDragonKiller) : RangeSwingHandler() {
|
||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||
if(victim is Player) {script.state = State.RUNNING; script.bot.pulseManager.current.stop()}
|
||||
if(victim is Player || victim.name.contains("revenant", ignoreCase = true)) {
|
||||
script.state = State.RUNNING
|
||||
script.bot.pulseManager.current.stop()
|
||||
}
|
||||
return super.canSwing(entity, victim)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ import core.game.content.dialogue.FacialExpression
|
|||
import core.game.content.global.action.ClimbActionHandler
|
||||
import core.game.content.global.action.DoorActionHandler
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Location
|
||||
import org.rs09.consts.NPCs
|
||||
import rs09.game.interaction.InteractionListener
|
||||
import rs09.game.world.repository.Repository
|
||||
|
||||
/**
|
||||
* Handles tutorial-specific node interactions
|
||||
|
|
@ -19,6 +21,7 @@ class TutorialListeners : InteractionListener {
|
|||
val COOKS_EXIT = 3018
|
||||
val QUEST_ENTER = 3019
|
||||
val QUEST_LADDER = 3029
|
||||
val QUEST_EXIT_LADDER = 3028
|
||||
val COMBAT_EXIT = 3030
|
||||
val BANK_EXIT = 3024
|
||||
val FINANCE_EXIT = 3025
|
||||
|
|
@ -80,14 +83,30 @@ class TutorialListeners : InteractionListener {
|
|||
}
|
||||
|
||||
on(QUEST_LADDER, SCENERY, "climb-down") {player, ladder ->
|
||||
if(getAttribute(player, "tutorial:stage", 0) != 29)
|
||||
if(getAttribute(player, "tutorial:stage", 0) < 29)
|
||||
return@on true
|
||||
|
||||
setAttribute(player, "tutorial:stage", 30)
|
||||
TutorialStage.load(player, 30)
|
||||
if (getAttribute(player, "tutorial:stage", 0) == 29) {
|
||||
setAttribute(player, "tutorial:stage", 30)
|
||||
TutorialStage.load(player, 30)
|
||||
}
|
||||
ClimbActionHandler.climbLadder(player, ladder.asScenery(), "climb-down")
|
||||
}
|
||||
|
||||
on(QUEST_EXIT_LADDER, SCENERY, "climb-up") { player, ladder ->
|
||||
ClimbActionHandler.climbLadder(player, ladder.asScenery(), "climb-up")
|
||||
|
||||
submitWorldPulse(object : Pulse(2) {
|
||||
override fun pulse(): Boolean {
|
||||
val questTutor = Repository.findNPC(NPCs.QUEST_GUIDE_949) ?: return true
|
||||
sendChat(questTutor, "What are you doing, ${player.username}? Get back down the ladder.")
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
return@on true
|
||||
}
|
||||
|
||||
on(COMBAT_GATES, SCENERY, "open"){player, gate ->
|
||||
if(getAttribute(player, "tutorial:stage", 0) != 43)
|
||||
return@on true
|
||||
|
|
|
|||
|
|
@ -10,15 +10,19 @@ import core.game.node.entity.player.link.InterfaceManager
|
|||
import core.game.node.entity.player.link.IronmanMode
|
||||
import core.game.node.entity.player.link.TeleportManager
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.communication.ClanRepository
|
||||
import core.game.world.map.Location
|
||||
import core.net.amsc.MSPacketRepository
|
||||
import core.net.amsc.WorldCommunicator
|
||||
import core.plugin.Initializable
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
import proto.management.JoinClanRequest
|
||||
import rs09.ServerConstants
|
||||
import rs09.game.interaction.inter.RulesAndInfo
|
||||
import rs09.game.world.GameWorld
|
||||
import rs09.tools.END_DIALOGUE
|
||||
import rs09.worker.ManagementEvents
|
||||
|
||||
/**
|
||||
* Handles the magic tutor's dialogue
|
||||
|
|
@ -179,6 +183,16 @@ class TutorialMagicTutorDialogue(player: Player? = null) : DialoguePlugin(player
|
|||
player.unhook(TutorialInteractionReceiver)
|
||||
player.unhook(TutorialButtonReceiver)
|
||||
RulesAndInfo.openFor(player)
|
||||
|
||||
if (GameWorld.settings!!.enable_default_clan) {
|
||||
player.communication.currentClan = ServerConstants.SERVER_NAME
|
||||
|
||||
val clanJoin = JoinClanRequest.newBuilder()
|
||||
clanJoin.clanName = ServerConstants.SERVER_NAME
|
||||
clanJoin.username = player.name
|
||||
|
||||
ManagementEvents.publish(clanJoin.build())
|
||||
}
|
||||
}
|
||||
|
||||
12 -> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package rs09.game.node.entity.combat
|
||||
|
||||
import core.game.component.Component
|
||||
import core.game.container.Container
|
||||
import core.game.container.impl.EquipmentContainer
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.Entity
|
||||
|
|
@ -15,8 +14,12 @@ import core.game.node.entity.player.link.audio.Audio
|
|||
import core.game.node.entity.player.link.prayer.PrayerType
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.entity.skill.summoning.familiar.Familiar
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.RegionManager.getClippingFlag
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.game.world.map.path.Pathfinder.*
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.tools.RandomFunction
|
||||
import rs09.game.system.SystemLogger
|
||||
|
|
@ -207,6 +210,11 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
|
|||
* @return `True` if so.
|
||||
*/
|
||||
open fun isAttackable(entity: Entity, victim: Entity): InteractionType? {
|
||||
if (type == CombatStyle.MELEE) {
|
||||
val stepType = canStepTowards(entity, victim)
|
||||
if (stepType != InteractionType.STILL_INTERACT) return stepType
|
||||
}
|
||||
|
||||
val comp = entity.getAttribute("autocast_component",null) as Component?
|
||||
if((comp != null || type == CombatStyle.MAGIC) && (entity.properties.autocastSpell == null || entity.properties.autocastSpell.spellId == 0) && entity is Player){
|
||||
val weapEx = entity.getExtension<Any>(WeaponInterface::class.java) as WeaponInterface?
|
||||
|
|
@ -235,6 +243,74 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
|
|||
return InteractionType.STILL_INTERACT
|
||||
}
|
||||
|
||||
private fun canStepTowards(entity: Entity, victim: Entity): InteractionType {
|
||||
val closestVictimTile = victim.getClosestOccupiedTile(entity.location)
|
||||
val closestEntityTile = entity.getClosestOccupiedTile(closestVictimTile)
|
||||
val dir = closestEntityTile.deriveDirection(closestVictimTile)
|
||||
?: return InteractionType.STILL_INTERACT //if we cannot derive a direction, it's because both tiles are the same, so hand off control to the main logic which already handles this case
|
||||
var next = closestEntityTile
|
||||
|
||||
while (next.getDistance(closestVictimTile) > 3) { //skip the initial gap in distance if it exists, because standard pathfinding would already stop us before this point if something was between us and the NPC or vice versa
|
||||
next = next.transform(dir)
|
||||
}
|
||||
|
||||
var result: InteractionType = InteractionType.STILL_INTERACT
|
||||
val maxIterations = next.getDistance(closestVictimTile).toInt()
|
||||
for (i in 0..maxIterations) { //step towards the target tile, checking if anything would obstruct us on the way, and immediately breaking + returning if it does.
|
||||
next = next.transform(dir)
|
||||
result = checkStepInterval(dir, next)
|
||||
if (result == InteractionType.NO_INTERACT) break
|
||||
}
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun checkStepInterval(
|
||||
dir: Direction,
|
||||
next: Location
|
||||
): InteractionType {
|
||||
val components = next.getStepComponents(dir)
|
||||
|
||||
when (dir) {
|
||||
Direction.NORTH -> if (getClippingFlag(next) and PREVENT_NORTH != 0) return InteractionType.NO_INTERACT
|
||||
Direction.EAST -> if (getClippingFlag(next) and PREVENT_EAST != 0) return InteractionType.NO_INTERACT
|
||||
Direction.SOUTH -> if (getClippingFlag(next) and PREVENT_SOUTH != 0) return InteractionType.NO_INTERACT
|
||||
Direction.WEST -> if (getClippingFlag(next) and PREVENT_WEST != 0) return InteractionType.NO_INTERACT
|
||||
|
||||
Direction.NORTH_EAST -> {
|
||||
if (getClippingFlag(components[0]) and PREVENT_EAST != 0
|
||||
|| getClippingFlag(components[1]) and PREVENT_NORTH != 0
|
||||
|| getClippingFlag(next) and PREVENT_NORTHEAST != 0
|
||||
) return InteractionType.NO_INTERACT
|
||||
}
|
||||
|
||||
Direction.NORTH_WEST -> {
|
||||
if (getClippingFlag(components[0]) and PREVENT_WEST != 0
|
||||
|| getClippingFlag(components[1]) and PREVENT_NORTH != 0
|
||||
|| getClippingFlag(next) and PREVENT_NORTHWEST != 0
|
||||
) return InteractionType.NO_INTERACT
|
||||
}
|
||||
|
||||
Direction.SOUTH_EAST -> {
|
||||
if (getClippingFlag(components[0]) and PREVENT_EAST != 0
|
||||
|| getClippingFlag(components[1]) and PREVENT_SOUTH != 0
|
||||
|| getClippingFlag(next) and PREVENT_SOUTHEAST != 0
|
||||
) return InteractionType.NO_INTERACT
|
||||
}
|
||||
|
||||
Direction.SOUTH_WEST -> {
|
||||
if (getClippingFlag(components[0]) and PREVENT_WEST != 0
|
||||
|| getClippingFlag(components[1]) and PREVENT_SOUTH != 0
|
||||
|| getClippingFlag(next) and PREVENT_SOUTHWEST != 0
|
||||
) return InteractionType.NO_INTERACT
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return InteractionType.STILL_INTERACT
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dragonfire message.
|
||||
* @param protection The protection value.
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ class ModernListeners : SpellListener("modern"){
|
|||
override fun defineListeners() {
|
||||
|
||||
onCast(Modern.HOME_TELEPORT,NONE){player, _ ->
|
||||
if (!getAttribute(player, "tutorial:complete", false)) {
|
||||
return@onCast
|
||||
}
|
||||
requires(player)
|
||||
player.teleporter.send(ServerConstants.HOME_LOCATION,TeleportManager.TeleportType.HOME)
|
||||
setDelay(player,true)
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ object ServerConfigParser {
|
|||
ServerConstants.SERVER_GE_NAME = data.getString("world.name_ge") ?: ServerConstants.SERVER_NAME
|
||||
ServerConstants.RULES_AND_INFO_ENABLED = data.getBoolean("world.show_rules", true)
|
||||
ServerConstants.BOTS_INFLUENCE_PRICE_INDEX = data.getBoolean("world.bots_influence_ge_price", true)
|
||||
ServerConstants.PRELOAD_MAP = data.getBoolean("server.preload_map", false)
|
||||
ServerConstants.REVENANT_POPULATION = data.getLong("world.revenant_population", 30L).toInt()
|
||||
ServerConstants.BANK_BOOTH_QUICK_OPEN = data.getBoolean("world.bank_booth_quick_open", false)
|
||||
ServerConstants.DISCORD_GE_WEBHOOK = data.getString("server.discord_webhook", "")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import core.game.system.SystemState
|
|||
import core.game.system.task.Pulse
|
||||
import core.game.system.task.TaskExecutor
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.Region
|
||||
import core.game.world.map.RegionManager
|
||||
import core.plugin.CorePluginTypes.StartupPlugin
|
||||
import core.tools.RandomFunction
|
||||
|
|
@ -179,6 +180,12 @@ object GameWorld {
|
|||
SystemManager.flag(if (settings?.isDevMode == true) SystemState.PRIVATE else SystemState.ACTIVE)
|
||||
}
|
||||
SceneryDefinition.getDefinitions().values.forEach(Consumer { obj: SceneryDefinition -> obj.examine })
|
||||
|
||||
if (ServerConstants.PRELOAD_MAP) {
|
||||
//force early loading of all commonly accessed regions to improve performance at the cost of memory usage
|
||||
(7483..15420).forEach { id -> RegionManager.forId(id).also { Region.load(it) } }
|
||||
}
|
||||
|
||||
System.gc()
|
||||
SystemLogger.initTradeLogger()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class ImmerseWorld : StartupListener {
|
|||
immerseSeersAndCatherby()
|
||||
immerseLumbridgeDraynor()
|
||||
immerseVarrock()
|
||||
// immerseWilderness() temp disabled due to unbalanced exchange rates
|
||||
immerseWilderness()
|
||||
immerseFishingGuild()
|
||||
immerseAdventurer()
|
||||
// immerseSlayer()
|
||||
|
|
@ -193,20 +193,13 @@ class ImmerseWorld : StartupListener {
|
|||
}
|
||||
|
||||
fun immerseWilderness() {
|
||||
val wilderness = Location.create(2979, 3603, 0)
|
||||
for (i in (0..1)) {
|
||||
GeneralBotCreator(
|
||||
GreenDragonKiller(CombatStyle.MELEE),
|
||||
assembler.assembleMeleeDragonBot(CombatBotAssembler.Tier.HIGH, wilderness)
|
||||
)
|
||||
GeneralBotCreator(
|
||||
val wilderness = Location.create(3092, 3493, 0)
|
||||
|
||||
repeat(6) {
|
||||
GeneralBotCreator (
|
||||
GreenDragonKiller(CombatStyle.MELEE),
|
||||
assembler.assembleMeleeDragonBot(CombatBotAssembler.Tier.MED, wilderness)
|
||||
)
|
||||
GeneralBotCreator(
|
||||
GreenDragonKiller(CombatStyle.RANGE),
|
||||
assembler.assembleRangedBot(CombatBotAssembler.Tier.HIGH, wilderness)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class MajorUpdateWorker {
|
|||
|
||||
//remove all null or finished pulses from the list
|
||||
rmlist.forEach {
|
||||
if (GameWorld.Pulser.TASKS.contains(it)) GameWorld.Pulser.TASKS.remove(it)
|
||||
GameWorld.Pulser.TASKS.remove(it)
|
||||
}
|
||||
|
||||
rmlist.clear()
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import proto.management.SendClanInfo
|
|||
import proto.management.SendClanInfo.ClanMember
|
||||
import proto.management.SendContactInfo
|
||||
import proto.management.SendContactInfo.Contact
|
||||
import rs09.ServerConstants
|
||||
import rs09.auth.UserAccountInfo
|
||||
import rs09.game.system.SystemLogger
|
||||
import rs09.game.world.GameWorld
|
||||
import rs09.game.world.repository.Repository
|
||||
|
|
@ -262,40 +264,29 @@ object ManagementEvents {
|
|||
|
||||
is SendClanInfo -> {
|
||||
if (event.hasInfo) {
|
||||
val clan = ClanRepository.getClans().getOrPut(event.clanOwner) { ClanRepository(event.clanOwner) }
|
||||
clan.name = event.clanName
|
||||
clan.joinRequirement = ClanRank.values()[event.joinRequirement]
|
||||
clan.kickRequirement = ClanRank.values()[event.kickRequirement]
|
||||
clan.messageRequirement = ClanRank.values()[event.messageRequirement]
|
||||
clan.lootRequirement = ClanRank.values()[event.lootRequirement]
|
||||
|
||||
for (member in event.membersList) {
|
||||
val entry = ClanEntry(member.username, member.world)
|
||||
clan.ranks[member.username] = ClanRank.values()[member.rank]
|
||||
if (member.world == GameWorld.settings!!.worldId) {
|
||||
val p = Repository.getPlayerByName(member.username)
|
||||
entry.player = p
|
||||
p?.communication?.clan = clan
|
||||
}
|
||||
clan.players.add(entry)
|
||||
}
|
||||
|
||||
clan.update()
|
||||
initializeClanFrom(event)
|
||||
} else {
|
||||
val info = GameWorld.accountStorage.getAccountInfo(event.clanOwner)
|
||||
var info = GameWorld.accountStorage.getAccountInfo(event.clanOwner)
|
||||
if (info.clanName.isNotEmpty()) {
|
||||
val reqs = CommunicationInfo.parseClanRequirements(info.clanReqs)
|
||||
val c = ClanRepository(event.clanOwner)
|
||||
val contacts = CommunicationInfo.parseContacts(info.contacts)
|
||||
c.name = info.clanName
|
||||
c.joinRequirement = reqs[0]
|
||||
c.messageRequirement = reqs[1]
|
||||
c.kickRequirement = reqs[2]
|
||||
c.lootRequirement = reqs[3]
|
||||
for ((username, contact) in contacts) {
|
||||
c.ranks[username] = contact.rank
|
||||
initializeClanWith(info)
|
||||
} else {
|
||||
SystemLogger.logMS("Creating default server clan")
|
||||
if (GameWorld.settings!!.enable_default_clan && event.clanOwner == ServerConstants.SERVER_NAME) {
|
||||
//Create a user with the default clan and some basic settings and stick them in the account storage
|
||||
if (info == UserAccountInfo.createDefault()) {
|
||||
info.username = ServerConstants.SERVER_NAME
|
||||
info.password = ServerConstants.MS_SECRET_KEY
|
||||
info.rights = 2
|
||||
SystemLogger.logAlert("Creating default server account: ${info.username}, password is your MS_SECRET_KEY!")
|
||||
GameWorld.authenticator.createAccountWith(info)
|
||||
info = GameWorld.accountStorage.getAccountInfo(event.clanOwner)
|
||||
}
|
||||
|
||||
info.clanName = "Global"
|
||||
info.clanReqs = "-1,-1,7,7" //Any join, any message, owner kick, owner loot
|
||||
GameWorld.accountStorage.update(info)
|
||||
initializeClanWith(info)
|
||||
}
|
||||
ClanRepository.getClans()[event.clanOwner] = c
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +314,44 @@ object ManagementEvents {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun initializeClanFrom(event: SendClanInfo) {
|
||||
val clan = ClanRepository.getClans().getOrPut(event.clanOwner) { ClanRepository(event.clanOwner) }
|
||||
clan.name = event.clanName
|
||||
clan.joinRequirement = ClanRank.values()[event.joinRequirement]
|
||||
clan.kickRequirement = ClanRank.values()[event.kickRequirement]
|
||||
clan.messageRequirement = ClanRank.values()[event.messageRequirement]
|
||||
clan.lootRequirement = ClanRank.values()[event.lootRequirement]
|
||||
|
||||
for (member in event.membersList) {
|
||||
val entry = ClanEntry(member.username, member.world)
|
||||
clan.ranks[member.username] = ClanRank.values()[member.rank]
|
||||
if (member.world == GameWorld.settings!!.worldId) {
|
||||
val p = Repository.getPlayerByName(member.username)
|
||||
entry.player = p
|
||||
p?.communication?.clan = clan
|
||||
}
|
||||
clan.players.add(entry)
|
||||
}
|
||||
|
||||
clan.update()
|
||||
}
|
||||
|
||||
private fun initializeClanWith(info: UserAccountInfo) {
|
||||
val reqs = CommunicationInfo.parseClanRequirements(info.clanReqs)
|
||||
val c = ClanRepository(info.username)
|
||||
val contacts = CommunicationInfo.parseContacts(info.contacts)
|
||||
c.name = info.clanName
|
||||
c.joinRequirement = reqs[0]
|
||||
c.messageRequirement = reqs[1]
|
||||
c.kickRequirement = reqs[2]
|
||||
c.lootRequirement = reqs[3]
|
||||
for ((username, contact) in contacts) {
|
||||
c.ranks[username] = contact.rank
|
||||
}
|
||||
ClanRepository.getClans()[info.username] = c
|
||||
}
|
||||
|
||||
private fun queueUntilClanInfo(clanName: String, message: Message) {
|
||||
val queue = waitingOnClanInfo.getOrPut(clanName) {LinkedList()}
|
||||
queue.offer(message)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
secret_key = "2009scape_development"
|
||||
write_logs = true
|
||||
msip = "127.0.0.1"
|
||||
#preload the map (Increases memory usage by 2GB but makes game ticks smoother)
|
||||
preload_map = false
|
||||
|
||||
|
||||
[database]
|
||||
database_name = "global"
|
||||
|
|
@ -15,6 +18,8 @@ database_port = "3306"
|
|||
|
||||
[world]
|
||||
name = "2009scape"
|
||||
#name used for announcements of bots selling items on the GE
|
||||
name_ge = "2009scape"
|
||||
debug = true
|
||||
dev = true
|
||||
start_gui = false
|
||||
|
|
@ -49,6 +54,12 @@ wild_pvp_enabled = false
|
|||
jad_practice_enabled = true
|
||||
personalized_shops = true
|
||||
bots_influence_ge_price = true
|
||||
#verbose cutscene logging (for cutscenes in the new system)
|
||||
verbose_cutscene = false
|
||||
#show the rules the first time a player logs in
|
||||
show_rules = true
|
||||
#the number of revenants active at a time
|
||||
revenant_population = 30
|
||||
|
||||
[paths]
|
||||
#path to the data folder, which contains the cache subfolder and such
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue