mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-11 17:10:21 -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.
|
* @param c The component.
|
||||||
*/
|
*/
|
||||||
public static void setUnclosable(Player p, Component c) {
|
public static void setUnclosable(Player p, Component c) {
|
||||||
p.setAttribute("close_c_", false);
|
p.setAttribute("close_c_", true);
|
||||||
c.setCloseEvent(new CloseEvent() {
|
c.setCloseEvent(new CloseEvent() {
|
||||||
@Override
|
@Override
|
||||||
public boolean close(Player player, Component c) {
|
public boolean close(Player player, Component c) {
|
||||||
if (!player.getAttribute("close_c_", false)) {
|
return !player.getAttribute("close_c_", false);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ import core.game.node.entity.skill.Skills;
|
||||||
import core.game.node.entity.state.EntityState;
|
import core.game.node.entity.state.EntityState;
|
||||||
import core.game.node.entity.state.StateManager;
|
import core.game.node.entity.state.StateManager;
|
||||||
import core.game.system.task.Pulse;
|
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 rs09.game.world.GameWorld;
|
||||||
import core.game.world.map.Location;
|
import core.game.world.map.Location;
|
||||||
import core.game.world.map.Viewport;
|
import core.game.world.map.Viewport;
|
||||||
|
|
@ -33,6 +36,7 @@ import rs09.game.world.update.UpdateMasks;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
@ -780,10 +784,6 @@ public abstract class Entity extends Node {
|
||||||
attributes.setAttribute(key, value);
|
attributes.setAttribute(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExpirableAttribute(String key, Object value, Long timeToLive){
|
|
||||||
attributes.setExpirableAttribute(key,value,timeToLive);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an attribute.
|
* Gets an attribute.
|
||||||
* @param key The attribute name.
|
* @param key The attribute name.
|
||||||
|
|
@ -938,4 +938,34 @@ public abstract class Entity extends Node {
|
||||||
this.invisible = invisible;
|
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.entity.player.link.prayer.PrayerType;
|
||||||
import core.game.node.item.Item;
|
import core.game.node.item.Item;
|
||||||
import core.game.system.task.Pulse;
|
import core.game.system.task.Pulse;
|
||||||
|
import rs09.game.ai.AIPlayer;
|
||||||
import rs09.game.world.GameWorld;
|
import rs09.game.world.GameWorld;
|
||||||
import core.game.world.map.zone.ZoneType;
|
import core.game.world.map.zone.ZoneType;
|
||||||
|
|
||||||
|
|
@ -144,7 +145,7 @@ public final class ImpactHandler {
|
||||||
if (disabledTicks > GameWorld.getTicks()) {
|
if (disabledTicks > GameWorld.getTicks()) {
|
||||||
return null;
|
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);
|
Impact impact = new Impact(source, 0, style, HitsplatType.MISS);
|
||||||
impactQueue.add(impact);
|
impactQueue.add(impact);
|
||||||
return impact;
|
return impact;
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ public final class GameAttributes {
|
||||||
*/
|
*/
|
||||||
public void setAttribute(String key, Object value) {
|
public void setAttribute(String key, Object value) {
|
||||||
if (key.startsWith("/save:")) {
|
if (key.startsWith("/save:")) {
|
||||||
key = key.substring(6, key.length());
|
key = key.substring(6);
|
||||||
if (!savedAttributes.contains(key)) {
|
if (!savedAttributes.contains(key)) {
|
||||||
savedAttributes.add(key);
|
savedAttributes.add(key);
|
||||||
}
|
}
|
||||||
|
|
@ -144,17 +144,6 @@ public final class GameAttributes {
|
||||||
attributes.put(key, value);
|
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.
|
* Gets an attribute.
|
||||||
* @param key The attribute name.
|
* @param key The attribute name.
|
||||||
|
|
@ -163,9 +152,6 @@ public final class GameAttributes {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T getAttribute(String key) {
|
public <T> T getAttribute(String key) {
|
||||||
key = key.replace("/save:","");
|
key = key.replace("/save:","");
|
||||||
if (!attributes.containsKey(key)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (T) attributes.get(key);
|
return (T) attributes.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,9 +168,6 @@ public final class GameAttributes {
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
return (T) object;
|
return (T) object;
|
||||||
}
|
}
|
||||||
if(keyExpirations.containsKey(string) && keyExpirations.get(string) < System.currentTimeMillis()){
|
|
||||||
return fail;
|
|
||||||
}
|
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,7 @@ public class NPC extends Entity {
|
||||||
if (dialoguePlayer == null || !dialoguePlayer.isActive() || !dialoguePlayer.getInterfaceManager().hasChatbox()) {
|
if (dialoguePlayer == null || !dialoguePlayer.isActive() || !dialoguePlayer.getInterfaceManager().hasChatbox()) {
|
||||||
dialoguePlayer = null;
|
dialoguePlayer = null;
|
||||||
if (walks && !getPulseManager().hasPulseRunning() && !getProperties().getCombatPulse().isAttacking() && !getProperties().getCombatPulse().isInCombat() && nextWalk < GameWorld.getTicks()) {
|
if (walks && !getPulseManager().hasPulseRunning() && !getProperties().getCombatPulse().isAttacking() && !getProperties().getCombatPulse().isInCombat() && nextWalk < GameWorld.getTicks()) {
|
||||||
|
if (RandomFunction.nextBool()) return;
|
||||||
setNextWalk();
|
setNextWalk();
|
||||||
Location l = getMovementDestination();
|
Location l = getMovementDestination();
|
||||||
if (canMove(l)) {
|
if (canMove(l)) {
|
||||||
|
|
|
||||||
|
|
@ -193,9 +193,6 @@ public class RevenantNPC extends AbstractNPC {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
public boolean isAttackable(Entity entity, CombatStyle style, boolean message) {
|
||||||
if (entity.asPlayer().isArtificial()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (entity instanceof Player) {
|
if (entity instanceof Player) {
|
||||||
if (!checkCombatLevel(entity.asPlayer()) && !entity.asPlayer().isAdmin()) {
|
if (!checkCombatLevel(entity.asPlayer()) && !entity.asPlayer().isAdmin()) {
|
||||||
if(message) {
|
if(message) {
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ public class BuildRegionChunk extends RegionChunk {
|
||||||
objects[i][x][y] = null;
|
objects[i][x][y] = null;
|
||||||
}
|
}
|
||||||
plane.getObjects()[baseX + x][baseY + 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();
|
clear();
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,11 @@ import core.game.node.Node;
|
||||||
import core.game.world.map.path.Path;
|
import core.game.world.map.path.Path;
|
||||||
import core.game.world.map.path.Pathfinder;
|
import core.game.world.map.path.Pathfinder;
|
||||||
import core.tools.RandomFunction;
|
import core.tools.RandomFunction;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import rs09.game.system.SystemLogger;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a location on the world map.
|
* Represents a location on the world map.
|
||||||
|
|
@ -491,4 +494,45 @@ public final class Location extends Node {
|
||||||
public void setZ(int z) {
|
public void setZ(int z) {
|
||||||
this.z = 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];
|
byte[][][] mapscapeData = new byte[4][SIZE][SIZE];
|
||||||
for (RegionPlane plane : r.planes) {
|
for (RegionPlane plane : r.planes) {
|
||||||
plane.getFlags().setLandscape(new boolean[SIZE][SIZE]);
|
plane.getFlags().setLandscape(new boolean[SIZE][SIZE]);
|
||||||
plane.getFlags().setClippingFlags(new int[SIZE][SIZE]);
|
//plane.getFlags().setClippingFlags(new int[SIZE][SIZE]);
|
||||||
plane.getProjectileFlags().setClippingFlags(new int[SIZE][SIZE]);
|
//plane.getProjectileFlags().setClippingFlags(new int[SIZE][SIZE]);
|
||||||
}
|
}
|
||||||
if (mapscapeId > -1) {
|
if (mapscapeId > -1) {
|
||||||
ByteBuffer mapscape = ByteBuffer.wrap(Cache.getIndexes()[5].getCacheFile().getContainerUnpackedData(mapscapeId));
|
ByteBuffer mapscape = ByteBuffer.wrap(Cache.getIndexes()[5].getCacheFile().getContainerUnpackedData(mapscapeId));
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ public class RegionChunk {
|
||||||
copy[x][y] = objects[x][y];
|
copy[x][y] = objects[x][y];
|
||||||
staticCopy[x][y] = plane.getObjects()[baseX + x][baseY + y];
|
staticCopy[x][y] = plane.getObjects()[baseX + x][baseY + y];
|
||||||
objects[x][y] = plane.getObjects()[baseX + x][baseY + y] = null;
|
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();
|
rotation = direction.toInteger();
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import rs09.game.system.SystemLogger
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the regions.
|
* Manages the regions.
|
||||||
|
|
@ -21,6 +22,8 @@ object RegionManager {
|
||||||
* The region cache mapping.
|
* The region cache mapping.
|
||||||
*/
|
*/
|
||||||
private val REGION_CACHE: MutableMap<Int, Region> = HashMap()
|
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()
|
public val LOCK = ReentrantLock()
|
||||||
|
|
||||||
|
|
@ -80,16 +83,50 @@ object RegionManager {
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getClippingFlag(z: Int, x: Int, y: Int): Int {
|
fun getClippingFlag(z: Int, x: Int, y: Int): Int {
|
||||||
var x = x
|
val regionX = x shr 6
|
||||||
var y = y
|
val regionY = y shr 6
|
||||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
val localX = x and 63
|
||||||
Region.load(region)
|
val localY = y and 63
|
||||||
if (!region.isHasFlags) {
|
return getClippingFlag(z, regionX, regionY, localX, localY)
|
||||||
return -1
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 flag
|
||||||
return region.planes[z].flags.clippingFlags[x][y]
|
}
|
||||||
|
|
||||||
|
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]
|
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.
|
* Adds a clipping flag.
|
||||||
* @param z The plane.
|
* @param z The plane.
|
||||||
|
|
@ -217,16 +234,11 @@ object RegionManager {
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getProjectileFlag(z: Int, x: Int, y: Int): Int {
|
fun getProjectileFlag(z: Int, x: Int, y: Int): Int {
|
||||||
var x = x
|
val regionX = x shr 6
|
||||||
var y = y
|
val regionY = y shr 6
|
||||||
val region = forId(((x shr 6) shl 8) or (y shr 6))
|
val localX = x and 63
|
||||||
Region.load(region)
|
val localY = y and 63
|
||||||
if (!region.isHasFlags) {
|
return getClippingFlag(z, regionX, regionY, localX, localY, true)
|
||||||
return -1
|
|
||||||
}
|
|
||||||
x -= (x shr 6) shl 6
|
|
||||||
y -= (y shr 6) shl 6
|
|
||||||
return region.planes[z].projectileFlags.clippingFlags[x][y]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -320,8 +320,8 @@ public final class DynamicRegion extends Region {
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
for (int i = x << 3; i < (x + 1) << 3; i++) {
|
for (int i = x << 3; i < (x + 1) << 3; i++) {
|
||||||
for (int j = y << 3; j < (y + 1) << 3; j++) {
|
for (int j = y << 3; j < (y + 1) << 3; j++) {
|
||||||
p.getFlags().getClippingFlags()[i][j] = -1;
|
p.getFlags().invalidateFlag(i, j);
|
||||||
p.getProjectileFlags().getClippingFlags()[i][j] = -1;
|
p.getProjectileFlags().invalidateFlag(i, j);
|
||||||
Scenery object = p.getObjects()[i][j];
|
Scenery object = p.getObjects()[i][j];
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
LandscapeParser.removeScenery(object);
|
LandscapeParser.removeScenery(object);
|
||||||
|
|
@ -344,8 +344,8 @@ public final class DynamicRegion extends Region {
|
||||||
int fromX = (l.getX() - regionBase.getX()) + i;
|
int fromX = (l.getX() - regionBase.getX()) + i;
|
||||||
int fromY = (l.getY() - regionBase.getY()) + j;
|
int fromY = (l.getY() - regionBase.getY()) + j;
|
||||||
p.getFlags().getLandscape()[toX][toY] = rp.getFlags().getLandscape()[fromX][fromY];
|
p.getFlags().getLandscape()[toX][toY] = rp.getFlags().getLandscape()[fromX][fromY];
|
||||||
p.getFlags().getClippingFlags()[toX][toY] = rp.getFlags().getClippingFlags()[fromX][fromY];
|
p.getFlags().flag(fromX, fromY, rp.getFlags().getFlag(fromX, fromY));
|
||||||
p.getProjectileFlags().getClippingFlags()[toX][toY] = rp.getProjectileFlags().getClippingFlags()[fromX][fromY];
|
p.getProjectileFlags().flag(fromX, fromY, rp.getFlags().getFlag(fromX, fromY));
|
||||||
Scenery[] objects = { rp.getChunkObject(fromX, fromY) };
|
Scenery[] objects = { rp.getChunkObject(fromX, fromY) };
|
||||||
RegionChunk ch = rp.getChunks()[fromX >> 3][fromY >> 3];
|
RegionChunk ch = rp.getChunks()[fromX >> 3][fromY >> 3];
|
||||||
if (ch instanceof BuildRegionChunk) {
|
if (ch instanceof BuildRegionChunk) {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ public final class MapscapeParser {
|
||||||
for (int z = 0; z < 4; z++) {
|
for (int z = 0; z < 4; z++) {
|
||||||
for (int x = 0; x < 64; x++) {
|
for (int x = 0; x < 64; x++) {
|
||||||
for (int y = 0; y < 64; y++) {
|
for (int y = 0; y < 64; y++) {
|
||||||
|
r.getPlanes()[z].getFlags().flagEmptyTile(x,y);
|
||||||
if ((mapscape[z][x][y] & 0x1) == 1) {
|
if ((mapscape[z][x][y] & 0x1) == 1) {
|
||||||
int plane = z;
|
int plane = z;
|
||||||
if ((mapscape[1][x][y] & 0x2) == 2) {
|
if ((mapscape[1][x][y] & 0x2) == 2) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package core.game.world.map.build;
|
package core.game.world.map.build;
|
||||||
|
|
||||||
import core.game.world.map.RegionManager;
|
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, ...
|
* Holds a region's flags like clipping flags, members, ...
|
||||||
|
|
@ -9,6 +13,11 @@ import core.game.world.map.RegionManager;
|
||||||
*/
|
*/
|
||||||
public final class RegionFlags {
|
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.
|
* The plane.
|
||||||
*/
|
*/
|
||||||
|
|
@ -28,11 +37,6 @@ public final class RegionFlags {
|
||||||
* The base y-coordinate.
|
* The base y-coordinate.
|
||||||
*/
|
*/
|
||||||
private final int baseY;
|
private final int baseY;
|
||||||
|
|
||||||
/**
|
|
||||||
* The clipping flags.
|
|
||||||
*/
|
|
||||||
private int[][] clippingFlags;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The landscape data.
|
* The landscape data.
|
||||||
|
|
@ -42,7 +46,7 @@ public final class RegionFlags {
|
||||||
/**
|
/**
|
||||||
* If the flags are set for projectile clipping
|
* If the flags are set for projectile clipping
|
||||||
*/
|
*/
|
||||||
private boolean projectile;
|
private final boolean projectile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code RegionFlags} {@code Object}.
|
* Constructs a new {@code RegionFlags} {@code Object}.
|
||||||
|
|
@ -71,7 +75,11 @@ public final class RegionFlags {
|
||||||
* @param y The y-coordinate.
|
* @param y The y-coordinate.
|
||||||
*/
|
*/
|
||||||
public void flagSolidTile(int x, int y) {
|
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.
|
* @param y The y-coordinate.
|
||||||
*/
|
*/
|
||||||
public void flagTileObject(int x, int y) {
|
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.
|
* @param y The y-coordinate.
|
||||||
*/
|
*/
|
||||||
public void unflagTileObject(int x, int y) {
|
public void unflagTileObject(int x, int y) {
|
||||||
if (clippingFlags == null) {
|
unflag(x, y, TILE_OBJECT);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((clippingFlags[x][y] & 0x40000) != 0) {
|
|
||||||
clippingFlags[x][y] &= ~0x40000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -106,9 +109,9 @@ public final class RegionFlags {
|
||||||
* @param projectileClipped If the object is solid.
|
* @param projectileClipped If the object is solid.
|
||||||
*/
|
*/
|
||||||
public void flagSolidObject(int x, int y, int sizeX, int sizeY, boolean projectileClipped) {
|
public void flagSolidObject(int x, int y, int sizeX, int sizeY, boolean projectileClipped) {
|
||||||
int clipdata = 0x100;
|
int clipdata = OBJ_10;
|
||||||
if (projectileClipped) {
|
if (projectileClipped) {
|
||||||
clipdata += 0x20000;
|
clipdata += OBJ_10_PROJECTILE;
|
||||||
}
|
}
|
||||||
for (int i = x; i < x + sizeX; i++) {
|
for (int i = x; i < x + sizeX; i++) {
|
||||||
for (int j = y; j < y + sizeY; j++) {
|
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) {
|
public void flag(int x, int y, int clipdata) {
|
||||||
if (x > -1 && x < 64 && y > -1 && y < 64) {
|
if (x > -1 && x < 64 && y > -1 && y < 64) {
|
||||||
clippingFlags[x][y] |= clipdata;
|
addFlag(x, y, clipdata);
|
||||||
} else {
|
} else {
|
||||||
RegionManager.addClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata);
|
RegionManager.addClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unflags a solid object (type 10/11).
|
* Unflags a solid object (type 10/11).
|
||||||
|
|
@ -141,9 +143,9 @@ public final class RegionFlags {
|
||||||
* @param projectileClipped If the object is solid.
|
* @param projectileClipped If the object is solid.
|
||||||
*/
|
*/
|
||||||
public void unflagSolidObject(int x, int y, int sizeX, int sizeY, boolean projectileClipped) {
|
public void unflagSolidObject(int x, int y, int sizeX, int sizeY, boolean projectileClipped) {
|
||||||
int clipdata = 0x100;
|
int clipdata = OBJ_10;
|
||||||
if (projectileClipped) {
|
if (projectileClipped) {
|
||||||
clipdata += 0x20000;
|
clipdata += OBJ_10_PROJECTILE;
|
||||||
}
|
}
|
||||||
for (int i = x; i < x + sizeX; i++) {
|
for (int i = x; i < x + sizeX; i++) {
|
||||||
for (int j = y; j < y + sizeY; j++) {
|
for (int j = y; j < y + sizeY; j++) {
|
||||||
|
|
@ -159,18 +161,47 @@ public final class RegionFlags {
|
||||||
* @param clipdata The clip data.
|
* @param clipdata The clip data.
|
||||||
*/
|
*/
|
||||||
public void unflag(int x, int y, int clipdata) {
|
public void unflag(int x, int y, int clipdata) {
|
||||||
if (clippingFlags == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (x > -1 && x < 64 && y > -1 && y < 64) {
|
if (x > -1 && x < 64 && y > -1 && y < 64) {
|
||||||
if ((clippingFlags[x][y] & clipdata) != 0) {
|
removeFlag(x, y, clipdata);
|
||||||
clippingFlags[x][y] &= ~clipdata;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
RegionManager.removeClippingFlag(plane, baseX + x, baseY + y, projectile, clipdata);
|
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).
|
* Flags a door object (type 0-3).
|
||||||
* @param x The x-coordinate
|
* @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.
|
* Gets the members.
|
||||||
* @return The members.
|
* @return The members.
|
||||||
|
|
@ -488,22 +512,6 @@ public final class RegionFlags {
|
||||||
this.members = members;
|
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.
|
* Gets the plane.
|
||||||
* @return The plane.
|
* @return The plane.
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import java.util.List;
|
||||||
* @author Emperor
|
* @author Emperor
|
||||||
*/
|
*/
|
||||||
public final class DumbPathfinder extends Pathfinder {
|
public final class DumbPathfinder extends Pathfinder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a path can be found.
|
* If a path can be found.
|
||||||
*/
|
*/
|
||||||
|
|
@ -103,7 +102,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
found = true;
|
found = true;
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case NORTH:
|
case NORTH:
|
||||||
if ((clipMaskSupplier.getClippingFlag(z, x, y + 1) & 0x12c0120) != 0) {
|
if ((clipMaskSupplier.getClippingFlag(z, x, y + 1) & PREVENT_NORTH) != 0) {
|
||||||
found = false;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +110,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
y++;
|
y++;
|
||||||
break;
|
break;
|
||||||
case NORTH_EAST:
|
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;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +119,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
y++;
|
y++;
|
||||||
break;
|
break;
|
||||||
case EAST:
|
case EAST:
|
||||||
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & 0x12c0180) != 0) {
|
if ((clipMaskSupplier.getClippingFlag(z, x + 1, y) & PREVENT_EAST) != 0) {
|
||||||
found = false;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +127,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
x++;
|
x++;
|
||||||
break;
|
break;
|
||||||
case SOUTH_EAST:
|
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;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +136,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
y--;
|
y--;
|
||||||
break;
|
break;
|
||||||
case SOUTH:
|
case SOUTH:
|
||||||
if ((clipMaskSupplier.getClippingFlag(z, x, y - 1) & 0x12c0102) != 0) {
|
if ((clipMaskSupplier.getClippingFlag(z, x, y - 1) & PREVENT_SOUTH) != 0) {
|
||||||
found = false;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +144,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
y--;
|
y--;
|
||||||
break;
|
break;
|
||||||
case SOUTH_WEST:
|
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;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +153,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
y--;
|
y--;
|
||||||
break;
|
break;
|
||||||
case WEST:
|
case WEST:
|
||||||
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & 0x12c0108) != 0) {
|
if ((clipMaskSupplier.getClippingFlag(z, x - 1, y) & PREVENT_WEST) != 0) {
|
||||||
found = false;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +161,7 @@ public final class DumbPathfinder extends Pathfinder {
|
||||||
x--;
|
x--;
|
||||||
break;
|
break;
|
||||||
case NORTH_WEST:
|
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;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,15 @@ import core.game.world.map.RegionManager;
|
||||||
import rs09.game.world.map.path.SmartPathfinder;
|
import rs09.game.world.map.path.SmartPathfinder;
|
||||||
|
|
||||||
public abstract class Pathfinder {
|
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.
|
* The smart path finder.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import core.game.node.item.Item;
|
||||||
import core.net.packet.IncomingPacket;
|
import core.net.packet.IncomingPacket;
|
||||||
import core.net.packet.IoBuffer;
|
import core.net.packet.IoBuffer;
|
||||||
|
|
||||||
|
import static api.ContentAPIKt.getAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the packet to handle an item slot switch.
|
* Represents the packet to handle an item slot switch.
|
||||||
* @author 'Vexia
|
* @author 'Vexia
|
||||||
|
|
@ -82,7 +84,7 @@ public class SlotSwitchPacket implements IncomingPacket {
|
||||||
|
|
||||||
final Item item = container.get(slot);
|
final Item item = container.get(slot);
|
||||||
final Item second = container.get(secondSlot);
|
final Item second = container.get(secondSlot);
|
||||||
if (player.getInterfaceManager().hasChatbox()) {
|
if (player.getInterfaceManager().hasChatbox() && !getAttribute(player, "close_c_", false)) {
|
||||||
player.getInterfaceManager().closeChatbox();
|
player.getInterfaceManager().closeChatbox();
|
||||||
switchItem(secondSlot,slot,container,insert,player);
|
switchItem(secondSlot,slot,container,insert,player);
|
||||||
container.refresh();
|
container.refresh();
|
||||||
|
|
|
||||||
|
|
@ -217,5 +217,8 @@ class ServerConstants {
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var DISCORD_GE_WEBHOOK = ""
|
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.RegionManager
|
||||||
import core.game.world.map.path.Pathfinder
|
import core.game.world.map.path.Pathfinder
|
||||||
import core.game.world.update.flag.context.Animation
|
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.context.Graphics
|
||||||
|
import core.game.world.update.flag.player.ChatFlag
|
||||||
import core.tools.RandomFunction
|
import core.tools.RandomFunction
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -99,6 +101,11 @@ class ScriptAPI(private val bot: Player) {
|
||||||
return entity
|
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
|
* Gets the nearest node with a name contained in the list of acceptable names
|
||||||
* @param acceptedNames the list of accepted npc/object 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
|
* A function for teleporting the bot to the GE
|
||||||
* @author Ceikry
|
* @author Ceikry
|
||||||
*/
|
*/
|
||||||
fun teleportToGE(){
|
fun teleportToGE() : Boolean{
|
||||||
|
if (bot.isTeleBlocked) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
bot.lock()
|
bot.lock()
|
||||||
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
||||||
bot.impactHandler.disabledTicks = 4
|
bot.impactHandler.disabledTicks = 4
|
||||||
|
|
@ -435,6 +445,7 @@ class ScriptAPI(private val bot: Player) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -548,7 +559,10 @@ class ScriptAPI(private val bot: Player) {
|
||||||
* @param loc the location to teleport to
|
* @param loc the location to teleport to
|
||||||
* @author Ceikry
|
* @author Ceikry
|
||||||
*/
|
*/
|
||||||
fun teleport(loc: Location){
|
fun teleport(loc: Location) : Boolean {
|
||||||
|
if (bot.isTeleBlocked) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
bot.lock()
|
bot.lock()
|
||||||
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
||||||
bot.impactHandler.disabledTicks = 4
|
bot.impactHandler.disabledTicks = 4
|
||||||
|
|
@ -561,6 +575,7 @@ class ScriptAPI(private val bot: Player) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -457,8 +457,7 @@ class Adventurer(val style: CombatStyle): Script() {
|
||||||
.replace("@name", localPlayer.username)
|
.replace("@name", localPlayer.username)
|
||||||
.replace("@timer", until.toString())
|
.replace("@timer", until.toString())
|
||||||
|
|
||||||
bot.sendChat(chat)
|
scriptAPI.sendChat(chat)
|
||||||
bot.updateMasks.register(ChatFlag(ChatMessage(bot, chat, 0, 0)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class State{
|
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.combat.InteractionType
|
||||||
import core.game.node.entity.player.Player
|
import core.game.node.entity.player.Player
|
||||||
import core.game.node.entity.skill.Skills
|
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.entity.state.EntityState
|
||||||
import core.game.node.item.Item
|
import core.game.node.item.Item
|
||||||
import core.game.system.task.Pulse
|
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.RegionManager
|
||||||
import core.game.world.map.zone.ZoneBorders
|
import core.game.world.map.zone.ZoneBorders
|
||||||
import core.game.world.map.zone.impl.WildernessZone
|
import core.game.world.map.zone.impl.WildernessZone
|
||||||
|
import core.tools.RandomFunction
|
||||||
import org.rs09.consts.Items
|
import org.rs09.consts.Items
|
||||||
import rs09.game.ai.AIRepository
|
import rs09.game.ai.AIRepository
|
||||||
import rs09.game.ai.pvmbots.CombatBotAssembler
|
import rs09.game.ai.pvmbots.CombatBotAssembler
|
||||||
|
|
@ -25,16 +27,24 @@ import rs09.game.node.entity.combat.handlers.RangeSwingHandler
|
||||||
import kotlin.random.Random
|
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 style The combat style the bot is going to use.
|
||||||
* @param area (optional) What area the bot tries to kill dragons in.
|
* @param area (optional) What area the bot tries to kill dragons in.
|
||||||
* @author Ceikry
|
* @author Ceikry
|
||||||
*/
|
*/
|
||||||
class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Script() {
|
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 handler: CombatSwingHandler? = null
|
||||||
var lootDelay = 0
|
var lootDelay = 0
|
||||||
var offerMade = false
|
var offerMade = false
|
||||||
|
var trashTalkDelay = 0
|
||||||
|
|
||||||
var food = if (Random.nextBoolean()){
|
var food = if (Random.nextBoolean()){
|
||||||
Items.LOBSTER_379
|
Items.LOBSTER_379
|
||||||
|
|
@ -45,28 +55,18 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
||||||
}
|
}
|
||||||
|
|
||||||
var myBorders: ZoneBorders? = null
|
var myBorders: ZoneBorders? = null
|
||||||
val type = when(style){
|
val type = CombatBotAssembler.Type.MELEE
|
||||||
CombatStyle.MELEE -> CombatBotAssembler.Type.MELEE
|
|
||||||
CombatStyle.MAGIC -> CombatBotAssembler.Type.MAGE
|
|
||||||
CombatStyle.RANGE -> CombatBotAssembler.Type.RANGE
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
override fun tick() {
|
||||||
if(!bot.isActive){
|
if(!bot.isActive){
|
||||||
running = false
|
running = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(bot.inventory.getAmount(food) < 3 && state == State.KILLING)
|
|
||||||
state = State.TO_BANK
|
checkFoodStockAndEat()
|
||||||
scriptAPI.eat(food)
|
|
||||||
when(state){
|
when(state){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
State.KILLING -> {
|
State.KILLING -> {
|
||||||
bot.properties.combatPulse.temporaryHandler = handler
|
bot.properties.combatPulse.temporaryHandler = handler
|
||||||
scriptAPI.attackNpcInRadius(bot,"Green dragon",20)
|
scriptAPI.attackNpcInRadius(bot,"Green dragon",20)
|
||||||
|
|
@ -86,11 +86,13 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
||||||
if(players.isEmpty()){
|
if(players.isEmpty()){
|
||||||
state = State.TO_DRAGONS
|
state = State.TO_DRAGONS
|
||||||
} else {
|
} else {
|
||||||
if(bot.skullManager.level < 21 && bot.stateManager.get(EntityState.TELEBLOCK) != null){
|
if(bot.skullManager.level < 21){
|
||||||
scriptAPI.teleportToGE()
|
if (scriptAPI.teleportToGE())
|
||||||
state = State.REFRESHING
|
state = State.REFRESHING
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
sendTrashTalk()
|
||||||
|
attemptToBuryBone()
|
||||||
scriptAPI.walkTo(WildernessZone.getInstance().borders.random().randomLoc)
|
scriptAPI.walkTo(WildernessZone.getInstance().borders.random().randomLoc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +109,7 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
items.forEach {it: Item -> scriptAPI.takeNearestGroundItem(it.id)}
|
items.toTypedArray().forEach {it: Item -> scriptAPI.takeNearestGroundItem(it.id)}
|
||||||
}
|
}
|
||||||
|
|
||||||
State.TO_BANK -> {
|
State.TO_BANK -> {
|
||||||
|
|
@ -157,25 +159,10 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
||||||
}
|
}
|
||||||
|
|
||||||
State.BUYING_FOOD -> {
|
State.BUYING_FOOD -> {
|
||||||
if(!offerMade)
|
state = State.TO_DRAGONS
|
||||||
{
|
bot.bank.add(Item(food,50))
|
||||||
scriptAPI.buyFromGE(bot, food, 100)
|
bot.bank.refresh()
|
||||||
offerMade = true
|
scriptAPI.withdraw(food, 10)
|
||||||
} 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.TO_DRAGONS -> {
|
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 {
|
override fun newInstance(): Script {
|
||||||
val script = GreenDragonKiller(style)
|
val script = GreenDragonKiller(style)
|
||||||
val tier = CombatBotAssembler.Tier.HIGH
|
val tier = CombatBotAssembler.Tier.MED
|
||||||
if(type == CombatBotAssembler.Type.RANGE)
|
script.bot = CombatBotAssembler().assembleMeleeDragonBot(tier, bot.startLocation)
|
||||||
script.bot = CombatBotAssembler().assembleRangeDragonBot(tier,bot.startLocation)
|
|
||||||
else
|
|
||||||
script.bot = CombatBotAssembler().assembleMeleeDragonBot(tier, bot.startLocation)
|
|
||||||
return script
|
return script
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,11 +265,7 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
handler = when(style){
|
handler = MeleeSwinger(this)
|
||||||
CombatStyle.MELEE -> MeleeSwinger(this)
|
|
||||||
CombatStyle.MAGIC -> MageSwinger(this)
|
|
||||||
CombatStyle.RANGE -> RangeSwinger(this)
|
|
||||||
}
|
|
||||||
equipment.add(Item(Items.ANTI_DRAGON_SHIELD_1540))
|
equipment.add(Item(Items.ANTI_DRAGON_SHIELD_1540))
|
||||||
myBorders = westDragons
|
myBorders = westDragons
|
||||||
skills[Skills.AGILITY] = 99
|
skills[Skills.AGILITY] = 99
|
||||||
|
|
@ -276,22 +275,10 @@ class GreenDragonKiller(val style: CombatStyle, area: ZoneBorders? = null) : Scr
|
||||||
|
|
||||||
internal class MeleeSwinger(val script: GreenDragonKiller) : MeleeSwingHandler() {
|
internal class MeleeSwinger(val script: GreenDragonKiller) : MeleeSwingHandler() {
|
||||||
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
override fun canSwing(entity: Entity, victim: Entity): InteractionType? {
|
||||||
if(script.state == State.TO_BANK) {script.bot.pulseManager.current.stop()}
|
if(victim is Player || victim.name.contains("revenant", ignoreCase = true)) {
|
||||||
if(victim is Player) {script.state = State.RUNNING; script.bot.pulseManager.current.stop()}
|
script.state = State.RUNNING
|
||||||
return super.canSwing(entity, victim)
|
script.bot.pulseManager.current.stop()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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()}
|
|
||||||
return super.canSwing(entity, victim)
|
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.ClimbActionHandler
|
||||||
import core.game.content.global.action.DoorActionHandler
|
import core.game.content.global.action.DoorActionHandler
|
||||||
import core.game.node.scenery.Scenery
|
import core.game.node.scenery.Scenery
|
||||||
|
import core.game.system.task.Pulse
|
||||||
import core.game.world.map.Location
|
import core.game.world.map.Location
|
||||||
import org.rs09.consts.NPCs
|
import org.rs09.consts.NPCs
|
||||||
import rs09.game.interaction.InteractionListener
|
import rs09.game.interaction.InteractionListener
|
||||||
|
import rs09.game.world.repository.Repository
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles tutorial-specific node interactions
|
* Handles tutorial-specific node interactions
|
||||||
|
|
@ -19,6 +21,7 @@ class TutorialListeners : InteractionListener {
|
||||||
val COOKS_EXIT = 3018
|
val COOKS_EXIT = 3018
|
||||||
val QUEST_ENTER = 3019
|
val QUEST_ENTER = 3019
|
||||||
val QUEST_LADDER = 3029
|
val QUEST_LADDER = 3029
|
||||||
|
val QUEST_EXIT_LADDER = 3028
|
||||||
val COMBAT_EXIT = 3030
|
val COMBAT_EXIT = 3030
|
||||||
val BANK_EXIT = 3024
|
val BANK_EXIT = 3024
|
||||||
val FINANCE_EXIT = 3025
|
val FINANCE_EXIT = 3025
|
||||||
|
|
@ -80,14 +83,30 @@ class TutorialListeners : InteractionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
on(QUEST_LADDER, SCENERY, "climb-down") {player, ladder ->
|
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
|
return@on true
|
||||||
|
|
||||||
setAttribute(player, "tutorial:stage", 30)
|
if (getAttribute(player, "tutorial:stage", 0) == 29) {
|
||||||
TutorialStage.load(player, 30)
|
setAttribute(player, "tutorial:stage", 30)
|
||||||
|
TutorialStage.load(player, 30)
|
||||||
|
}
|
||||||
ClimbActionHandler.climbLadder(player, ladder.asScenery(), "climb-down")
|
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 ->
|
on(COMBAT_GATES, SCENERY, "open"){player, gate ->
|
||||||
if(getAttribute(player, "tutorial:stage", 0) != 43)
|
if(getAttribute(player, "tutorial:stage", 0) != 43)
|
||||||
return@on true
|
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.IronmanMode
|
||||||
import core.game.node.entity.player.link.TeleportManager
|
import core.game.node.entity.player.link.TeleportManager
|
||||||
import core.game.node.item.Item
|
import core.game.node.item.Item
|
||||||
|
import core.game.system.communication.ClanRepository
|
||||||
import core.game.world.map.Location
|
import core.game.world.map.Location
|
||||||
import core.net.amsc.MSPacketRepository
|
import core.net.amsc.MSPacketRepository
|
||||||
import core.net.amsc.WorldCommunicator
|
import core.net.amsc.WorldCommunicator
|
||||||
import core.plugin.Initializable
|
import core.plugin.Initializable
|
||||||
import org.rs09.consts.Items
|
import org.rs09.consts.Items
|
||||||
import org.rs09.consts.NPCs
|
import org.rs09.consts.NPCs
|
||||||
|
import proto.management.JoinClanRequest
|
||||||
|
import rs09.ServerConstants
|
||||||
import rs09.game.interaction.inter.RulesAndInfo
|
import rs09.game.interaction.inter.RulesAndInfo
|
||||||
import rs09.game.world.GameWorld
|
import rs09.game.world.GameWorld
|
||||||
import rs09.tools.END_DIALOGUE
|
import rs09.tools.END_DIALOGUE
|
||||||
|
import rs09.worker.ManagementEvents
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the magic tutor's dialogue
|
* Handles the magic tutor's dialogue
|
||||||
|
|
@ -179,6 +183,16 @@ class TutorialMagicTutorDialogue(player: Player? = null) : DialoguePlugin(player
|
||||||
player.unhook(TutorialInteractionReceiver)
|
player.unhook(TutorialInteractionReceiver)
|
||||||
player.unhook(TutorialButtonReceiver)
|
player.unhook(TutorialButtonReceiver)
|
||||||
RulesAndInfo.openFor(player)
|
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 -> {
|
12 -> {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package rs09.game.node.entity.combat
|
package rs09.game.node.entity.combat
|
||||||
|
|
||||||
import core.game.component.Component
|
import core.game.component.Component
|
||||||
import core.game.container.Container
|
|
||||||
import core.game.container.impl.EquipmentContainer
|
import core.game.container.impl.EquipmentContainer
|
||||||
import core.game.node.Node
|
import core.game.node.Node
|
||||||
import core.game.node.entity.Entity
|
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.player.link.prayer.PrayerType
|
||||||
import core.game.node.entity.skill.Skills
|
import core.game.node.entity.skill.Skills
|
||||||
import core.game.node.entity.skill.summoning.familiar.Familiar
|
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
|
||||||
|
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.map.path.Pathfinder.*
|
||||||
import core.game.world.update.flag.context.Animation
|
import core.game.world.update.flag.context.Animation
|
||||||
import core.tools.RandomFunction
|
import core.tools.RandomFunction
|
||||||
import rs09.game.system.SystemLogger
|
import rs09.game.system.SystemLogger
|
||||||
|
|
@ -207,6 +210,11 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
|
||||||
* @return `True` if so.
|
* @return `True` if so.
|
||||||
*/
|
*/
|
||||||
open fun isAttackable(entity: Entity, victim: Entity): InteractionType? {
|
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?
|
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){
|
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?
|
val weapEx = entity.getExtension<Any>(WeaponInterface::class.java) as WeaponInterface?
|
||||||
|
|
@ -235,6 +243,74 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
|
||||||
return InteractionType.STILL_INTERACT
|
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.
|
* Gets the dragonfire message.
|
||||||
* @param protection The protection value.
|
* @param protection The protection value.
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,9 @@ class ModernListeners : SpellListener("modern"){
|
||||||
override fun defineListeners() {
|
override fun defineListeners() {
|
||||||
|
|
||||||
onCast(Modern.HOME_TELEPORT,NONE){player, _ ->
|
onCast(Modern.HOME_TELEPORT,NONE){player, _ ->
|
||||||
|
if (!getAttribute(player, "tutorial:complete", false)) {
|
||||||
|
return@onCast
|
||||||
|
}
|
||||||
requires(player)
|
requires(player)
|
||||||
player.teleporter.send(ServerConstants.HOME_LOCATION,TeleportManager.TeleportType.HOME)
|
player.teleporter.send(ServerConstants.HOME_LOCATION,TeleportManager.TeleportType.HOME)
|
||||||
setDelay(player,true)
|
setDelay(player,true)
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ object ServerConfigParser {
|
||||||
ServerConstants.SERVER_GE_NAME = data.getString("world.name_ge") ?: ServerConstants.SERVER_NAME
|
ServerConstants.SERVER_GE_NAME = data.getString("world.name_ge") ?: ServerConstants.SERVER_NAME
|
||||||
ServerConstants.RULES_AND_INFO_ENABLED = data.getBoolean("world.show_rules", true)
|
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.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.REVENANT_POPULATION = data.getLong("world.revenant_population", 30L).toInt()
|
||||||
ServerConstants.BANK_BOOTH_QUICK_OPEN = data.getBoolean("world.bank_booth_quick_open", false)
|
ServerConstants.BANK_BOOTH_QUICK_OPEN = data.getBoolean("world.bank_booth_quick_open", false)
|
||||||
ServerConstants.DISCORD_GE_WEBHOOK = data.getString("server.discord_webhook", "")
|
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.Pulse
|
||||||
import core.game.system.task.TaskExecutor
|
import core.game.system.task.TaskExecutor
|
||||||
import core.game.world.map.Location
|
import core.game.world.map.Location
|
||||||
|
import core.game.world.map.Region
|
||||||
import core.game.world.map.RegionManager
|
import core.game.world.map.RegionManager
|
||||||
import core.plugin.CorePluginTypes.StartupPlugin
|
import core.plugin.CorePluginTypes.StartupPlugin
|
||||||
import core.tools.RandomFunction
|
import core.tools.RandomFunction
|
||||||
|
|
@ -179,6 +180,12 @@ object GameWorld {
|
||||||
SystemManager.flag(if (settings?.isDevMode == true) SystemState.PRIVATE else SystemState.ACTIVE)
|
SystemManager.flag(if (settings?.isDevMode == true) SystemState.PRIVATE else SystemState.ACTIVE)
|
||||||
}
|
}
|
||||||
SceneryDefinition.getDefinitions().values.forEach(Consumer { obj: SceneryDefinition -> obj.examine })
|
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()
|
System.gc()
|
||||||
SystemLogger.initTradeLogger()
|
SystemLogger.initTradeLogger()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class ImmerseWorld : StartupListener {
|
||||||
immerseSeersAndCatherby()
|
immerseSeersAndCatherby()
|
||||||
immerseLumbridgeDraynor()
|
immerseLumbridgeDraynor()
|
||||||
immerseVarrock()
|
immerseVarrock()
|
||||||
// immerseWilderness() temp disabled due to unbalanced exchange rates
|
immerseWilderness()
|
||||||
immerseFishingGuild()
|
immerseFishingGuild()
|
||||||
immerseAdventurer()
|
immerseAdventurer()
|
||||||
// immerseSlayer()
|
// immerseSlayer()
|
||||||
|
|
@ -193,20 +193,13 @@ class ImmerseWorld : StartupListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun immerseWilderness() {
|
fun immerseWilderness() {
|
||||||
val wilderness = Location.create(2979, 3603, 0)
|
val wilderness = Location.create(3092, 3493, 0)
|
||||||
for (i in (0..1)) {
|
|
||||||
GeneralBotCreator(
|
repeat(6) {
|
||||||
GreenDragonKiller(CombatStyle.MELEE),
|
GeneralBotCreator (
|
||||||
assembler.assembleMeleeDragonBot(CombatBotAssembler.Tier.HIGH, wilderness)
|
|
||||||
)
|
|
||||||
GeneralBotCreator(
|
|
||||||
GreenDragonKiller(CombatStyle.MELEE),
|
GreenDragonKiller(CombatStyle.MELEE),
|
||||||
assembler.assembleMeleeDragonBot(CombatBotAssembler.Tier.MED, wilderness)
|
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
|
//remove all null or finished pulses from the list
|
||||||
rmlist.forEach {
|
rmlist.forEach {
|
||||||
if (GameWorld.Pulser.TASKS.contains(it)) GameWorld.Pulser.TASKS.remove(it)
|
GameWorld.Pulser.TASKS.remove(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
rmlist.clear()
|
rmlist.clear()
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import proto.management.SendClanInfo
|
||||||
import proto.management.SendClanInfo.ClanMember
|
import proto.management.SendClanInfo.ClanMember
|
||||||
import proto.management.SendContactInfo
|
import proto.management.SendContactInfo
|
||||||
import proto.management.SendContactInfo.Contact
|
import proto.management.SendContactInfo.Contact
|
||||||
|
import rs09.ServerConstants
|
||||||
|
import rs09.auth.UserAccountInfo
|
||||||
import rs09.game.system.SystemLogger
|
import rs09.game.system.SystemLogger
|
||||||
import rs09.game.world.GameWorld
|
import rs09.game.world.GameWorld
|
||||||
import rs09.game.world.repository.Repository
|
import rs09.game.world.repository.Repository
|
||||||
|
|
@ -262,40 +264,29 @@ object ManagementEvents {
|
||||||
|
|
||||||
is SendClanInfo -> {
|
is SendClanInfo -> {
|
||||||
if (event.hasInfo) {
|
if (event.hasInfo) {
|
||||||
val clan = ClanRepository.getClans().getOrPut(event.clanOwner) { ClanRepository(event.clanOwner) }
|
initializeClanFrom(event)
|
||||||
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()
|
|
||||||
} else {
|
} else {
|
||||||
val info = GameWorld.accountStorage.getAccountInfo(event.clanOwner)
|
var info = GameWorld.accountStorage.getAccountInfo(event.clanOwner)
|
||||||
if (info.clanName.isNotEmpty()) {
|
if (info.clanName.isNotEmpty()) {
|
||||||
val reqs = CommunicationInfo.parseClanRequirements(info.clanReqs)
|
initializeClanWith(info)
|
||||||
val c = ClanRepository(event.clanOwner)
|
} else {
|
||||||
val contacts = CommunicationInfo.parseContacts(info.contacts)
|
SystemLogger.logMS("Creating default server clan")
|
||||||
c.name = info.clanName
|
if (GameWorld.settings!!.enable_default_clan && event.clanOwner == ServerConstants.SERVER_NAME) {
|
||||||
c.joinRequirement = reqs[0]
|
//Create a user with the default clan and some basic settings and stick them in the account storage
|
||||||
c.messageRequirement = reqs[1]
|
if (info == UserAccountInfo.createDefault()) {
|
||||||
c.kickRequirement = reqs[2]
|
info.username = ServerConstants.SERVER_NAME
|
||||||
c.lootRequirement = reqs[3]
|
info.password = ServerConstants.MS_SECRET_KEY
|
||||||
for ((username, contact) in contacts) {
|
info.rights = 2
|
||||||
c.ranks[username] = contact.rank
|
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) {
|
private fun queueUntilClanInfo(clanName: String, message: Message) {
|
||||||
val queue = waitingOnClanInfo.getOrPut(clanName) {LinkedList()}
|
val queue = waitingOnClanInfo.getOrPut(clanName) {LinkedList()}
|
||||||
queue.offer(message)
|
queue.offer(message)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
secret_key = "2009scape_development"
|
secret_key = "2009scape_development"
|
||||||
write_logs = true
|
write_logs = true
|
||||||
msip = "127.0.0.1"
|
msip = "127.0.0.1"
|
||||||
|
#preload the map (Increases memory usage by 2GB but makes game ticks smoother)
|
||||||
|
preload_map = false
|
||||||
|
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
database_name = "global"
|
database_name = "global"
|
||||||
|
|
@ -15,6 +18,8 @@ database_port = "3306"
|
||||||
|
|
||||||
[world]
|
[world]
|
||||||
name = "2009scape"
|
name = "2009scape"
|
||||||
|
#name used for announcements of bots selling items on the GE
|
||||||
|
name_ge = "2009scape"
|
||||||
debug = true
|
debug = true
|
||||||
dev = true
|
dev = true
|
||||||
start_gui = false
|
start_gui = false
|
||||||
|
|
@ -49,6 +54,12 @@ wild_pvp_enabled = false
|
||||||
jad_practice_enabled = true
|
jad_practice_enabled = true
|
||||||
personalized_shops = true
|
personalized_shops = true
|
||||||
bots_influence_ge_price = 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]
|
[paths]
|
||||||
#path to the data folder, which contains the cache subfolder and such
|
#path to the data folder, which contains the cache subfolder and such
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue