Added initial version

This commit is contained in:
Ceikry
2021-03-07 20:37:32 -06:00
commit b452bd670c
13290 changed files with 1178433 additions and 0 deletions
@@ -0,0 +1,47 @@
package core
import core.game.world.map.Location
import java.io.File
class JSONUtils {
companion object {
/**
* Parses a location from the format "x,y,z"
* @author Ceikry
* @param locString The string to parse
* @return Location
*/
@JvmStatic
fun parseLocation(locString: String): Location {
val locTokens = locString.split(",").map { it.toInt() }
return Location(locTokens[0], locTokens[1], locTokens[2])
}
/**
* Parses a path string
* @author Ceikry
* @param pathString The string to parse
* @return a String with the proper file separators for the current OS.
*/
@JvmStatic
fun parsePath(pathString: String): String {
var pathTokens: List<String>? = null
if(pathString.contains("/"))
pathTokens = pathString.split("/")
else if(pathString.contains("\\"))
pathTokens = pathString.split("\\")
pathTokens ?: return pathString //return the initial pathString if path does not contain file separators.
var pathProduct = ""
for(token in pathTokens){
if(token != "")
pathProduct += "$token${File.separator}"
}
return pathProduct
}
}
}
+142
View File
@@ -0,0 +1,142 @@
package core
import core.game.system.*
import core.game.system.config.ServerConfigParser
import core.game.system.mysql.SQLManager
import core.game.world.GameWorld
import core.game.world.repository.Repository
import core.gui.ConsoleFrame
import core.net.NioReactor
import core.net.amsc.WorldCommunicator
import core.tools.TimeStamp
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import core.game.ge.GEAutoStock
import kotlinx.coroutines.delay
import java.io.File
import java.net.BindException
import java.util.*
import kotlin.system.exitProcess
/**
* The main class, for those that are unable to read the class' name.
* @author Emperor
* @author Vexia
* @author Ceikry
*/
object Server {
/**
* The time stamp of when the server started running.
*/
@JvmField
var startTime: Long = 0
var lastHeartbeat = System.currentTimeMillis()
var running = false
/**
* The NIO reactor.
*/
var reactor: NioReactor? = null
/**
* The main method, in this method we load background utilities such as
* cache and our world, then end with starting networking.
* @param args The arguments cast on runtime.
* @throws Throwable When an exception occurs.
*/
@Throws(Throwable::class)
@JvmStatic
fun main(args: Array<String>) {
if (args.isNotEmpty()) {
SystemLogger.logInfo("Using config file: ${args[0]}")
ServerConfigParser(args[0])
} else {
SystemLogger.logInfo("Using config file: ${"worldprops" + File.separator + "default.json"}")
ServerConfigParser("worldprops" + File.separator + "default.json")
}
if (GameWorld.settings?.isGui == true) {
try {
ConsoleFrame.getInstance().init()
} catch (e: Exception) {
SystemLogger.logWarn("X11 server missing - launching server with no GUI!")
}
}
startTime = System.currentTimeMillis()
val t = TimeStamp()
GameWorld.prompt(true)
SQLManager.init()
Runtime.getRuntime().addShutdownHook(ServerConstants.SHUTDOWN_HOOK)
SystemLogger.logInfo("Starting networking...")
try {
NioReactor.configure(43594 + GameWorld.settings?.worldId!!).start()
} catch (e: BindException) {
SystemLogger.logErr("Port " + (43594 + GameWorld.settings?.worldId!!) + " is already in use!")
throw e
}
WorldCommunicator.connect()
SystemLogger.logInfo(GameWorld.settings?.name + " flags " + GameWorld.settings?.toString())
SystemLogger.logInfo(GameWorld.settings?.name + " started in " + t.duration(false, "") + " milliseconds.")
GEAutoStock.autostock()
val scanner = Scanner(System.`in`)
running = true
GlobalScope.launch {
while(scanner.hasNextLine()){
val command = scanner.nextLine()
when(command){
"stop" -> SystemManager.flag(SystemState.TERMINATED)
"players" -> System.out.println("Players online: " + (Repository.LOGGED_IN_PLAYERS.size))
"update" -> SystemManager.flag(SystemState.UPDATING)
"help","commands" -> printCommands()
"restartworker" -> SystemManager.flag(SystemState.ACTIVE)
}
}
}
GlobalScope.launch {
delay(20000)
while(running){
if(System.currentTimeMillis() - lastHeartbeat > 1800){
running = false
exitProcess(0)
}
delay(625)
}
}
}
@JvmStatic
fun heartbeat() {
lastHeartbeat = System.currentTimeMillis()
}
fun printCommands(){
println("stop - stop the server (saves all accounts and such)")
println("players - show online player count")
println("update - initiate an update with a countdown visible to players")
println("help, commands - show this")
println("restartworker - Reboots the major update worker in case of a travesty.")
}
fun autoReconnect() {
/*SystemLogger.log("Attempting autoreconnect of server")
WorldCommunicator.connect()*/
}
/**
* Gets the startTime.
* @return the startTime
*/
fun getStartTime(): Long {
return startTime
}
/**
* Sets the bastartTime.ZZ
* @param startTime the startTime to set.
*/
fun setStartTime(startTime: Long) {
Server.startTime = startTime
}
}
@@ -0,0 +1,217 @@
package core
import core.game.system.SystemShutdownHook
import core.game.system.mysql.SQLManager
import core.game.world.map.Location
import core.tools.mysql.Database
import core.tools.secondsToTicks
import org.json.simple.JSONObject
import java.io.File
import java.math.BigInteger
/**
* A class holding various variables for the server.
* @author Ceikry
*/
class ServerConstants {
companion object {
@JvmField
var SHUTDOWN_HOOK: Thread = Thread(SystemShutdownHook())
@JvmField
var DATA_PATH: String? = null
//path to the cache
@JvmField
var CACHE_PATH: String? = null
//path for the server store (obsolete, but kept for the sake of system sanity.)
@JvmField
var STORE_PATH: String? = null
//path for player saves
@JvmField
var PLAYER_SAVE_PATH: String? = null
@JvmField
var PLAYER_ATTRIBUTE_PATH = "ish";
//path to the various config files, such as npc_spawns.json
var CONFIG_PATH: String? = null
@JvmField
var GRAND_EXCHANGE_DATA_PATH: String? = null
@JvmField
var RDT_DATA_PATH: String? = null
@JvmField
var OBJECT_PARSER_PATH: String? = null
@JvmField
var SCRIPTS_PATH: String? = null
@JvmField
var DIALOGUE_SCRIPTS_PATH: String? = null
@JvmField
var LOGS_PATH: String? = null
@JvmField
var BOT_DATA_PATH: String? = null
//the max number of players.
@JvmField
var MAX_PLAYERS = 0
//the max number of NPCs
@JvmField
var MAX_NPCS = 0
//the location where new players are placed on login.
@JvmField
var START_LOCATION: Location? = null
//Location for all home teleports/respawn location
@JvmField
var HOME_LOCATION: Location? = null
//the name for the database
@JvmField
var DATABASE_NAME: String? = null
//username for the database
@JvmField
var DATABASE_USER: String? = null
//password for the database
@JvmField
var DATABASE_PASS: String? = null
//address for the database
@JvmField
var DATABASE_ADDRESS: String? = null
@JvmField
var DATABASE_PORT: String? = null
@JvmField
var WRITE_LOGS: Boolean = false
@JvmField
var BANK_SIZE: Int = 496
@JvmField
var GE_AUTOSAVE_FREQUENCY = secondsToTicks(3600) //1 hour
@JvmField
var GE_AUTOSTOCK_ENABLED = false
//location names for the ::to command.
val TELEPORT_DESTINATIONS = arrayOf(
arrayOf(Location.create(2974, 4383, 2), "corp", "corporal", "corporeal"),
arrayOf(Location.create(2659, 2649, 0), "pc", "pest control", "pest"),
arrayOf(Location.create(3293, 3184, 0), "al kharid", "alkharid", "kharid"),
arrayOf(Location.create(3222, 3217, 0), "lumbridge", "lumby"),
arrayOf(Location.create(3110, 3168, 0), "wizard tower", "wizards tower", "tower", "wizards"),
arrayOf(Location.create(3083, 3249, 0), "draynor", "draynor village"),
arrayOf(Location.create(3019, 3244, 0), "port sarim", "sarim"),
arrayOf(Location.create(2956, 3209, 0), "rimmington"),
arrayOf(Location.create(2965, 3380, 0), "fally", "falador"),
arrayOf(Location.create(2895, 3436, 0), "taverley"),
arrayOf(Location.create(3080, 3423, 0), "barbarian village", "barb"),
arrayOf(Location.create(3213, 3428, 0), "varrock"),
arrayOf(Location.create(3164, 3485, 0), "grand exchange", "ge"),
arrayOf(Location.create(2917, 3175, 0), "karamja"),
arrayOf(Location.create(2450, 5165, 0), "tzhaar"),
arrayOf(Location.create(2795, 3177, 0), "brimhaven"),
arrayOf(Location.create(2849, 2961, 0), "shilo village", "shilo"),
arrayOf(Location.create(2605, 3093, 0), "yanille"),
arrayOf(Location.create(2663, 3305, 0), "ardougne", "ardy"),
arrayOf(Location.create(2450, 3422, 0), "gnome stronghold", "gnome"),
arrayOf(Location.create(2730, 3485, 0), "camelot", "cammy", "seers"),
arrayOf(Location.create(2805, 3435, 0), "catherby"),
arrayOf(Location.create(2659, 3657, 0), "rellekka"),
arrayOf(Location.create(2890, 3676, 0), "trollheim"),
arrayOf(Location.create(2914, 3746, 0), "godwars", "gwd", "god wars"),
arrayOf(Location.create(3180, 3684, 0), "bounty hunter", "bh"),
arrayOf(Location.create(3272, 3687, 0), "clan wars", "clw"),
arrayOf(Location.create(3090, 3957, 0), "mage arena", "mage", "magearena", "arena"),
arrayOf(Location.create(3069, 10257, 0), "king black dragon", "kbd"),
arrayOf(Location.create(3359, 3416, 0), "digsite"),
arrayOf(Location.create(3488, 3489, 0), "canifis"),
arrayOf(Location.create(3428, 3526, 0), "slayer tower", "slayer"),
arrayOf(Location.create(3502, 9483, 2), "kalphite queen", "kq", "kalphite hive", "kalphite"),
arrayOf(Location.create(3233, 2913, 0), "pyramid"),
arrayOf(Location.create(3419, 2917, 0), "nardah"),
arrayOf(Location.create(3482, 3090, 0), "uzer"),
arrayOf(Location.create(3358, 2970, 0), "pollnivneach", "poln"),
arrayOf(Location.create(3305, 2788, 0), "sophanem"),
arrayOf(Location.create(2898, 3544, 0), "burthorpe", "burthorp"),
arrayOf(Location.create(3088, 3491, 0), "edge", "edgeville"),
arrayOf(Location.create(3169, 3034, 0), "bedabin"),
arrayOf(Location.create(3565, 3289, 0), "barrows"),
arrayOf(Location.create(3016, 3513, 0), "bkf", "black knights fortress"),
arrayOf(Location.create(3052, 3481, 0), "monastery")
)
@JvmField
var DATABASE: Database? = null
//if SQL is enabled
@JvmField
var MYSQL = true
//the server name
@JvmField
var SERVER_NAME: String = ""
//The RSA_KEY for the server.
@JvmField
var EXPONENT = BigInteger("52317200263721308660411803146360972546561037484450290559823448967617618536819222494429186211525706853703641369936136465589036631055945454547936148730495933263344792588795811788941129493188907621550836988152620502378278134421731002382361670176785306598134280732756356458964850508114958769985438054979422820241")
//The MODULUS for the server.
@JvmField
var MODULUS = BigInteger("96982303379631821170939875058071478695026608406924780574168393250855797534862289546229721580153879336741968220328805101128831071152160922518190059946555203865621183480223212969502122536662721687753974815205744569357388338433981424032996046420057284324856368815997832596174397728134370577184183004453899764051")
/**
* Parses a JSONObject and retrieves the values for all settings in this file.
* @author Ceikry
* @param data : The JSONObject to parse.
*/
fun parse(data: JSONObject) {
MAX_PLAYERS = data["max_players"].toString().toInt()
MAX_NPCS = data["max_npcs"].toString().toInt()
START_LOCATION = JSONUtils.parseLocation(data["new_player_location"].toString())
HOME_LOCATION = JSONUtils.parseLocation(data["home_location"].toString())
DATA_PATH = JSONUtils.parsePath(data["data_path"].toString())
CACHE_PATH = JSONUtils.parsePath(data["cache_path"].toString())
STORE_PATH = JSONUtils.parsePath(data["store_path"].toString())
PLAYER_SAVE_PATH = JSONUtils.parsePath(data["save_path"].toString())
CONFIG_PATH = JSONUtils.parsePath(data["configs_path"].toString())
PLAYER_ATTRIBUTE_PATH = PLAYER_SAVE_PATH + "attributes" + File.separator
GRAND_EXCHANGE_DATA_PATH = JSONUtils.parsePath(data["grand_exchange_data_path"].toString())
BOT_DATA_PATH = JSONUtils.parsePath(data["bot_data_path"].toString())
RDT_DATA_PATH = JSONUtils.parsePath(data["rare_drop_table_path"].toString())
OBJECT_PARSER_PATH = JSONUtils.parsePath(data["object_parser_path"].toString())
SCRIPTS_PATH = JSONUtils.parsePath(data["scripts_path"].toString())
DIALOGUE_SCRIPTS_PATH = JSONUtils.parsePath(data["dialogue_scripts_path"].toString())
if(data.containsKey("logs_path")){
LOGS_PATH = data["logs_path"].toString()
}
if(data.containsKey("writeLogs")){
WRITE_LOGS = data["writeLogs"] as Boolean
}
DATABASE_NAME = data["database_name"].toString()
DATABASE_USER = data["database_username"].toString()
DATABASE_PASS = data["database_password"].toString()
DATABASE_ADDRESS = data["database_address"].toString()
DATABASE_PORT = data["database_port"].toString()
DATABASE = Database(DATABASE_ADDRESS, DATABASE_NAME, DATABASE_USER, DATABASE_PASS)
}
}
}
@@ -0,0 +1,217 @@
package core
import core.game.system.SystemShutdownHook
import core.game.system.mysql.SQLManager
import core.game.world.map.Location
import core.tools.mysql.Database
import core.tools.secondsToTicks
import org.json.simple.JSONObject
import java.io.File
import java.math.BigInteger
/**
* A class holding various variables for the server.
* @author Ceikry
*/
class ServerConstants {
companion object {
@JvmField
var SHUTDOWN_HOOK: Thread = Thread(SystemShutdownHook())
@JvmField
var DATA_PATH: String? = null
//path to the cache
@JvmField
var CACHE_PATH: String? = null
//path for the server store (obsolete, but kept for the sake of system sanity.)
@JvmField
var STORE_PATH: String? = null
//path for player saves
@JvmField
var PLAYER_SAVE_PATH: String? = null
@JvmField
var PLAYER_ATTRIBUTE_PATH = "ish";
//path to the various config files, such as npc_spawns.json
var CONFIG_PATH: String? = null
@JvmField
var GRAND_EXCHANGE_DATA_PATH: String? = null
@JvmField
var RDT_DATA_PATH: String? = null
@JvmField
var OBJECT_PARSER_PATH: String? = null
@JvmField
var SCRIPTS_PATH: String? = null
@JvmField
var DIALOGUE_SCRIPTS_PATH: String? = null
@JvmField
var LOGS_PATH: String? = null
@JvmField
var BOT_DATA_PATH: String? = null
//the max number of players.
@JvmField
var MAX_PLAYERS = 0
//the max number of NPCs
@JvmField
var MAX_NPCS = 0
//the location where new players are placed on login.
@JvmField
var START_LOCATION: Location? = null
//Location for all home teleports/respawn location
@JvmField
var HOME_LOCATION: Location? = null
//the name for the database
@JvmField
var DATABASE_NAME: String? = null
//username for the database
@JvmField
var DATABASE_USER: String? = null
//password for the database
@JvmField
var DATABASE_PASS: String? = null
//address for the database
@JvmField
var DATABASE_ADDRESS: String? = null
@JvmField
var DATABASE_PORT: String? = null
@JvmField
var WRITE_LOGS: Boolean = false
@JvmField
var BANK_SIZE: Int = 496
@JvmField
var GE_AUTOSAVE_FREQUENCY = secondsToTicks(3600) //1 hour
@JvmField
var GE_AUTOSTOCK_ENABLED = false
//location names for the ::to command.
val TELEPORT_DESTINATIONS = arrayOf(
arrayOf(Location.create(2974, 4383, 2), "corp", "corporal", "corporeal"),
arrayOf(Location.create(2659, 2649, 0), "pc", "pest control", "pest"),
arrayOf(Location.create(3293, 3184, 0), "al kharid", "alkharid", "kharid"),
arrayOf(Location.create(3222, 3217, 0), "lumbridge", "lumby"),
arrayOf(Location.create(3110, 3168, 0), "wizard tower", "wizards tower", "tower", "wizards"),
arrayOf(Location.create(3083, 3249, 0), "draynor", "draynor village"),
arrayOf(Location.create(3019, 3244, 0), "port sarim", "sarim"),
arrayOf(Location.create(2956, 3209, 0), "rimmington"),
arrayOf(Location.create(2965, 3380, 0), "fally", "falador"),
arrayOf(Location.create(2895, 3436, 0), "taverley"),
arrayOf(Location.create(3080, 3423, 0), "barbarian village", "barb"),
arrayOf(Location.create(3213, 3428, 0), "varrock"),
arrayOf(Location.create(3164, 3485, 0), "grand exchange", "ge"),
arrayOf(Location.create(2917, 3175, 0), "karamja"),
arrayOf(Location.create(2450, 5165, 0), "tzhaar"),
arrayOf(Location.create(2795, 3177, 0), "brimhaven"),
arrayOf(Location.create(2849, 2961, 0), "shilo village", "shilo"),
arrayOf(Location.create(2605, 3093, 0), "yanille"),
arrayOf(Location.create(2663, 3305, 0), "ardougne", "ardy"),
arrayOf(Location.create(2450, 3422, 0), "gnome stronghold", "gnome"),
arrayOf(Location.create(2730, 3485, 0), "camelot", "cammy", "seers"),
arrayOf(Location.create(2805, 3435, 0), "catherby"),
arrayOf(Location.create(2659, 3657, 0), "rellekka"),
arrayOf(Location.create(2890, 3676, 0), "trollheim"),
arrayOf(Location.create(2914, 3746, 0), "godwars", "gwd", "god wars"),
arrayOf(Location.create(3180, 3684, 0), "bounty hunter", "bh"),
arrayOf(Location.create(3272, 3687, 0), "clan wars", "clw"),
arrayOf(Location.create(3090, 3957, 0), "mage arena", "mage", "magearena", "arena"),
arrayOf(Location.create(3069, 10257, 0), "king black dragon", "kbd"),
arrayOf(Location.create(3359, 3416, 0), "digsite"),
arrayOf(Location.create(3488, 3489, 0), "canifis"),
arrayOf(Location.create(3428, 3526, 0), "slayer tower", "slayer"),
arrayOf(Location.create(3502, 9483, 2), "kalphite queen", "kq", "kalphite hive", "kalphite"),
arrayOf(Location.create(3233, 2913, 0), "pyramid"),
arrayOf(Location.create(3419, 2917, 0), "nardah"),
arrayOf(Location.create(3482, 3090, 0), "uzer"),
arrayOf(Location.create(3358, 2970, 0), "pollnivneach", "poln"),
arrayOf(Location.create(3305, 2788, 0), "sophanem"),
arrayOf(Location.create(2898, 3544, 0), "burthorpe", "burthorp"),
arrayOf(Location.create(3088, 3491, 0), "edge", "edgeville"),
arrayOf(Location.create(3169, 3034, 0), "bedabin"),
arrayOf(Location.create(3565, 3289, 0), "barrows"),
arrayOf(Location.create(3016, 3513, 0), "bkf", "black knights fortress"),
arrayOf(Location.create(3052, 3481, 0), "monastery")
)
@JvmField
var DATABASE: Database? = null
//if SQL is enabled
@JvmField
var MYSQL = true
//the server name
@JvmField
var SERVER_NAME: String = ""
//The RSA_KEY for the server.
@JvmField
var EXPONENT = BigInteger("52317200263721308660411803146360972546561037484450290559823448967617618536819222494429186211525706853703641369936136465589036631055945454547936148730495933263344792588795811788941129493188907621550836988152620502378278134421731002382361670176785306598134280732756356458964850508114958769985438054979422820241")
//The MODULUS for the server.
@JvmField
var MODULUS = BigInteger("96982303379631821170939875058071478695026608406924780574168393250855797534862289546229721580153879336741968220328805101128831071152160922518190059946555203865621183480223212969502122536662721687753974815205744569357388338433981424032996046420057284324856368815997832596174397728134370577184183004453899764051")
/**
* Parses a JSONObject and retrieves the values for all settings in this file.
* @author Ceikry
* @param data : The JSONObject to parse.
*/
fun parse(data: JSONObject) {
MAX_PLAYERS = data["max_players"].toString().toInt()
MAX_NPCS = data["max_npcs"].toString().toInt()
START_LOCATION = JSONUtils.parseLocation(data["new_player_location"].toString())
HOME_LOCATION = JSONUtils.parseLocation(data["home_location"].toString())
DATA_PATH = JSONUtils.parsePath(data["data_path"].toString())
CACHE_PATH = JSONUtils.parsePath(data["cache_path"].toString())
STORE_PATH = JSONUtils.parsePath(data["store_path"].toString())
PLAYER_SAVE_PATH = JSONUtils.parsePath(data["save_path"].toString())
CONFIG_PATH = JSONUtils.parsePath(data["configs_path"].toString())
PLAYER_ATTRIBUTE_PATH = PLAYER_SAVE_PATH + "attributes" + File.separator
GRAND_EXCHANGE_DATA_PATH = JSONUtils.parsePath(data["grand_exchange_data_path"].toString())
BOT_DATA_PATH = JSONUtils.parsePath(data["bot_data_path"].toString())
RDT_DATA_PATH = JSONUtils.parsePath(data["rare_drop_table_path"].toString())
OBJECT_PARSER_PATH = JSONUtils.parsePath(data["object_parser_path"].toString())
SCRIPTS_PATH = JSONUtils.parsePath(data["scripts_path"].toString())
DIALOGUE_SCRIPTS_PATH = JSONUtils.parsePath(data["dialogue_scripts_path"].toString())
if(data.containsKey("logs_path")){
LOGS_PATH = data["logs_path"].toString()
}
if(data.containsKey("writeLogs")){
WRITE_LOGS = data["writeLogs"] as Boolean
}
DATABASE_NAME = data["database_name"].toString()
DATABASE_USER = data["database_username"].toString()
DATABASE_PASS = data["database_password"].toString()
DATABASE_ADDRESS = data["database_address"].toString()
DATABASE_PORT = data["database_port"].toString()
DATABASE = Database(DATABASE_ADDRESS, DATABASE_NAME, DATABASE_USER, DATABASE_PASS)
}
}
}
@@ -0,0 +1,52 @@
package core;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class Util {
/**
* Capitalize the first letter of the string
* @return Capitalized string
*/
public static String capitalize(String name) {
if (name != null && name.length() != 0) {
char[] chars = name.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
} else {
return name;
}
}
public static String strToEnum(String name) {
name = name.toUpperCase();
return name.replaceAll(" ", "_");
}
public static String enumToString(String name) {
name = name.toLowerCase();
name = name.replaceAll("_", " ");
return capitalize(name);
}
public static double clamp(double input, double min, double max) {
return Math.max(Math.min(input, max), min);
}
public static long nextMidnight(long currentTime) {
Date date = new Date();
Calendar cal = Calendar.getInstance();
date.setTime(currentTime);
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.HOUR_OF_DAY, 24);
return cal.getTime().getTime();
}
}
+238
View File
@@ -0,0 +1,238 @@
package core.cache;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import core.ServerConstants;
import core.cache.def.impl.AnimationDefinition;
import core.cache.def.impl.GraphicDefinition;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.NPCDefinition;
import core.cache.def.impl.ObjectDefinition;
import core.game.system.SystemLogger;
/**
* A cache reader.
*
* @author Emperor
* @author Dragonkk
*/
public final class Cache {
/**
* The cache file manager.
*/
private static CacheFileManager[] cacheFileManagers;
/**
* The container cache file informer.
*/
private static CacheFile referenceFile;
/**
* Construct a new instance.
*/
private Cache(String location) {
try {
init(location);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Initialize the cache reader.
*
* @param path The cache path.x
* @throws Throwable When an exception occurs.
*/
public static void init(String path) throws Throwable {
SystemLogger.logInfo("Initializing cache...");
byte[] cacheFileBuffer = new byte[520];
RandomAccessFile containersInformFile = new RandomAccessFile(path + File.separator + "main_file_cache.idx255", "r");
RandomAccessFile dataFile = new RandomAccessFile(path + File.separator + "main_file_cache.dat2", "r");
referenceFile = new CacheFile(255, containersInformFile, dataFile, 500000, cacheFileBuffer);
int length = (int) (containersInformFile.length() / 6);
cacheFileManagers = new CacheFileManager[length];
for (int i = 0; i < length; i++) {
File f = new File(path + File.separator + "main_file_cache.idx" + i);
if (f.exists() && f.length() > 0) {
CacheFile cacheFile = new CacheFile(i, new RandomAccessFile(f, "r"), dataFile, 1000000, cacheFileBuffer);
cacheFileManagers[i] = new CacheFileManager(cacheFile, true);
if (cacheFileManagers[i].getInformation() == null) {
SystemLogger.logErr("Error loading cache index " + i + ": no information.");
cacheFileManagers[i] = null;
}
}
}
ItemDefinition.parse();
ObjectDefinition.parse();
}
/**
* Initializes the cache.
*/
public static void init() {
try {
init(ServerConstants.CACHE_PATH);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Gets the archive buffer for the grab requests.
*
* @param index The index id.
* @param archive The archive id.
* @param priority The priority.
* @param encryptionValue The current encryption value.
* @return The byte buffer.
*/
public static ByteBuffer getArchiveData(int index, int archive, boolean priority, int encryptionValue) {
byte[] data = index == 255 ? referenceFile.getContainerData(archive) : cacheFileManagers[index].getCacheFile().getContainerData(archive);
if (data == null || data.length < 1) {
SystemLogger.logErr("Invalid JS-5 request - " + index + ", " + archive + ", " + priority + ", " + encryptionValue + "!");
return null;
}
int compression = data[0] & 0xff;
int length = ((data[1] & 0xff) << 24) + ((data[2] & 0xff) << 16) + ((data[3] & 0xff) << 8) + (data[4] & 0xff);
int settings = compression;
if (!priority) {
settings |= 0x80;
}
int realLength = compression != 0 ? length + 4 : length;
// TODO There are two archives that lack two bytes at the end (The version, most likely). This causes the client CRC to be miscalculated. To combat this, we simply send two more bytes if the length seems to be off.
realLength += (index != 255 && compression != 0 && data.length - length == 9) ? 2 : 0;
ByteBuffer buffer = ByteBuffer.allocate((realLength + 5) + (realLength / 512) + 10);
buffer.put((byte) index);
buffer.putShort((short) archive);
buffer.put((byte) settings);
buffer.putInt(length);
for (int i = 5; i < realLength + 5; i++) {
if (buffer.position() % 512 == 0) {
buffer.put((byte) 255);
}
if (data.length > i)
buffer.put(data[i]);
else
buffer.put((byte) 0);
}
if (encryptionValue != 0) {
for (int i = 0; i < buffer.position(); i++) {
buffer.put(i, (byte) (buffer.get(i) ^ encryptionValue));
}
}
buffer.flip();
return buffer;
}
/**
* Generate the reference data for the cache files.
*
* @return The reference data byte array.
*/
public static final byte[] generateReferenceData() {
ByteBuffer buffer = ByteBuffer.allocate(cacheFileManagers.length * 8);
for (int index = 0; index < cacheFileManagers.length; index++) {
if (cacheFileManagers[index] == null) {
buffer.putInt(index == 24 ? 609698396 : 0);
buffer.putInt(0);
continue;
}
buffer.putInt(cacheFileManagers[index].getInformation().getInformationContainer().getCrc());
buffer.putInt(cacheFileManagers[index].getInformation().getRevision());
}
return buffer.array();
}
/**
* Get the cache file managers.
*
* @return The cache file managers.
*/
public static final CacheFileManager[] getIndexes() {
return cacheFileManagers;
}
/**
* Get the container cache file informer.
*
* @return The container cache file informer.
*/
public static final CacheFile getReferenceFile() {
return referenceFile;
}
/**
* Method used to return the component size of the interface.
*
* @param interfaceId the interface.
* @return the value.
*/
public static final int getInterfaceDefinitionsComponentsSize(int interfaceId) {
return getIndexes()[3].getFilesSize(interfaceId);
}
/**
* Method used to return the max size of the interface definitions.
*
* @return the size.
*/
public static final int getInterfaceDefinitionsSize() {
return getIndexes()[3].getContainersSize();
}
/**
* Method used to return the {@link NPCDefinition} size.
*
* @return the size.
*/
public static final int getNPCDefinitionsSize() {
int lastContainerId = getIndexes()[18].getContainersSize() - 1;
return lastContainerId * 128 + getIndexes()[18].getFilesSize(lastContainerId);
}
/**
* Method used to return the {@link GraphicDefinition} size.
*
* @return the size.
*/
public static final int getGraphicDefinitionsSize() {
int lastContainerId = getIndexes()[21].getContainersSize() - 1;
return lastContainerId * 256 + getIndexes()[21].getFilesSize(lastContainerId);
}
/**
* Method used to return the {@link AnimationDefinition} size.
*
* @return the size.
*/
public static final int getAnimationDefinitionsSize() {
int lastContainerId = getIndexes()[20].getContainersSize() - 1;
return lastContainerId * 128 + getIndexes()[20].getFilesSize(lastContainerId);
}
/**
* Method used to return the {@link ObjectDefinition} size.
*
* @return the size.
*/
public static final int getObjectDefinitionsSize() {
int lastContainerId = getIndexes()[16].getContainersSize() - 1;
return lastContainerId * 256 + getIndexes()[16].getFilesSize(lastContainerId);
}
/**
* Method used to return the item definition size.
*
* @return the size.
*/
public static final int getItemDefinitionsSize() {
int lastContainerId = getIndexes()[19].getContainersSize() - 1;
return lastContainerId * 256 + getIndexes()[19].getFilesSize(lastContainerId);
}
}
+148
View File
@@ -0,0 +1,148 @@
package core.cache;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import core.cache.crypto.XTEACryption;
import core.cache.misc.ContainersInformation;
/**
* A cache file.
* @author Dragonkk
*/
public final class CacheFile {
/**
* The index file id.
*/
private int indexFileId;
/**
* The cache file buffer.
*/
private byte[] cacheFileBuffer;
/**
* The maximum container size.
*/
private int maxContainerSize;
/**
* The index file.
*/
private RandomAccessFile indexFile;
/**
* The data file.
*/
private RandomAccessFile dataFile;
/**
* Construct a new cache file.
* @param indexFileId The index file id.
* @param indexFile The index file.
* @param dataFile The data file.
* @param maxContainerSize The maximum container size.
* @param cacheFileBuffer The cache file buffer.
*/
public CacheFile(int indexFileId, RandomAccessFile indexFile, RandomAccessFile dataFile, int maxContainerSize, byte[] cacheFileBuffer) {
this.cacheFileBuffer = cacheFileBuffer;
this.indexFileId = indexFileId;
this.maxContainerSize = maxContainerSize;
this.indexFile = indexFile;
this.dataFile = dataFile;
}
/**
* Get the unpacked container data.
* @param containerId The container id.
* @param xteaKeys The container keys.
* @return The unpacked container data.
*/
public final byte[] getContainerUnpackedData(int containerId, int[] xteaKeys) {
byte[] packedData = getContainerData(containerId);
if (packedData == null) {
return null;
}
if (xteaKeys != null && (xteaKeys[0] != 0 || xteaKeys[1] != 0 || xteaKeys[2] != 0 || xteaKeys[3] != 0)) {
packedData = XTEACryption.decrypt(xteaKeys, ByteBuffer.wrap(packedData), 5, packedData.length).array();
}
return ContainersInformation.unpackCacheContainer(packedData);
}
/**
* Get the container data for the specified container id.
* @param containerId The container id.
* @return The container data.
*/
public final byte[] getContainerData(int containerId) {
synchronized (dataFile) {
try {
if (indexFile.length() < (6 * containerId + 6)) {
return null;
}
indexFile.seek(6 * containerId);
indexFile.read(cacheFileBuffer, 0, 6);
int containerSize = (cacheFileBuffer[2] & 0xff) + (((0xff & cacheFileBuffer[0]) << 16) + (cacheFileBuffer[1] << 8 & 0xff00));
int sector = ((cacheFileBuffer[3] & 0xff) << 16) - (-(0xff00 & cacheFileBuffer[4] << 8) - (cacheFileBuffer[5] & 0xff));
if (containerSize < 0 || containerSize > maxContainerSize) {
return null;
}
if (sector <= 0 || dataFile.length() / 520L < sector) {
return null;
}
byte data[] = new byte[containerSize];
int dataReadCount = 0;
int part = 0;
while (containerSize > dataReadCount) {
if (sector == 0) {
return null;
}
dataFile.seek(520 * sector);
int dataToReadCount = containerSize - dataReadCount;
if (dataToReadCount > 512) {
dataToReadCount = 512;
}
dataFile.read(cacheFileBuffer, 0, 8 + dataToReadCount);
int currentContainerId = (0xff & cacheFileBuffer[1]) + (0xff00 & cacheFileBuffer[0] << 8);
int currentPart = ((cacheFileBuffer[2] & 0xff) << 8) + (0xff & cacheFileBuffer[3]);
int nextSector = (cacheFileBuffer[6] & 0xff) + (0xff00 & cacheFileBuffer[5] << 8) + ((0xff & cacheFileBuffer[4]) << 16);
int currentIndexFileId = cacheFileBuffer[7] & 0xff;
if (containerId != currentContainerId || currentPart != part || indexFileId != currentIndexFileId) {
return null;
}
if (nextSector < 0 || (dataFile.length() / 520L) < nextSector) {
return null;
}
for (int index = 0; dataToReadCount > index; index++) {
data[dataReadCount++] = cacheFileBuffer[8 + index];
}
part++;
sector = nextSector;
}
return data;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
/**
* Get the index file id.
* @return
*/
public int getIndexFileId() {
return indexFileId;
}
/**
* Get the unpacked container data.
* @param containerId The container id.
* @return The unpacked container data.
*/
public final byte[] getContainerUnpackedData(int containerId) {
return getContainerUnpackedData(containerId, null);
}
}
@@ -0,0 +1,293 @@
package core.cache;
import java.nio.ByteBuffer;
import core.cache.misc.ContainersInformation;
import core.tools.StringUtils;
/**
* A cache file manager.
* @author Dragonkk
*/
public final class CacheFileManager {
/**
* The cache file.
*/
private CacheFile cacheFile;
/**
* The containers information.
*/
private ContainersInformation information;
/**
* Discard a files data.
*/
private boolean discardFilesData;
/**
* A array holding file data.
*/
private byte[][][] filesData;
/**
* Construct a new cache file manager.
* @param cacheFile The cache file.
* @param discardFilesData To discard a files data.
*/
public CacheFileManager(CacheFile cacheFile, boolean discardFilesData) {
this.cacheFile = cacheFile;
this.discardFilesData = discardFilesData;
byte[] informContainerPackedData = Cache.getReferenceFile().getContainerData(cacheFile.getIndexFileId());
if (informContainerPackedData == null) {
return;
}
information = new ContainersInformation(informContainerPackedData);
resetFilesData();
}
/**
* Get the cache file.
* @return The cache file.
*/
public CacheFile getCacheFile() {
return cacheFile;
}
/**
* Get the containers size.
* @return The containers size.
*/
public int getContainersSize() {
return information.getContainers().length;
}
/**
* Get the files size.
* @param containerId The container id.
* @return The files size.
*/
public int getFilesSize(int containerId) {
if (!validContainer(containerId)) {
return -1;
}
return information.getContainers()[containerId].getFiles().length;
}
/**
* Reset the file data.
*/
public void resetFilesData() {
filesData = new byte[information.getContainers().length][][];
}
/**
* Check if a file is valid.
* @param containerId The container id.
* @param fileId The file id.
* @return If the file is valid {@code true}.
*/
public boolean validFile(int containerId, int fileId) {
if (!validContainer(containerId)) {
return false;
}
if (fileId < 0 || information.getContainers()[containerId] == null || information.getContainers()[containerId].getFiles().length <= fileId) {
return false;
}
return true;
}
/**
* If a container is valid.
* @param containerId The container id.
* @return If the container is valid {@code true}.
*/
public boolean validContainer(int containerId) {
if (containerId < 0 || information.getContainers().length <= containerId) {
return false;
}
return true;
}
/**
* Get the file ids.
* @param containerId The container id.
* @return The file ids.
*/
public int[] getFileIds(int containerId) {
if (!validContainer(containerId)) {
return null;
}
return information.getContainers()[containerId].getFilesIndexes();
}
/**
* Get the archive id.
* @param name The archive name.
* @return The archive id.
*/
public int getArchiveId(String name) {
if (name == null) {
return -1;
}
int hash = StringUtils.getNameHash(name);
for (int containerIndex = 0; containerIndex < information.getContainersIndexes().length; containerIndex++) {
if (information.getContainers()[information.getContainersIndexes()[containerIndex]].getNameHash() == hash) {
return information.getContainersIndexes()[containerIndex];
}
}
return -1;
}
/**
* Get the file data.
* @param containerId The container id.
* @param fileId The file id.
* @return The get file data.
*/
public byte[] getFileData(int containerId, int fileId) {
return getFileData(containerId, fileId, null);
}
/**
* Load the file data.
* @param archiveId The container id.
* @param keys The container keys.
* @return If the file data is loaded {@code true}.
*/
public boolean loadFilesData(int archiveId, int[] keys) {
byte[] data = cacheFile.getContainerUnpackedData(archiveId, keys);
if (data == null) {
return false;
}
if (filesData[archiveId] == null) {
if (information.getContainers()[archiveId] == null) {
return false; // container inform doesnt exist anymore
}
filesData[archiveId] = new byte[information.getContainers()[archiveId].getFiles().length][];
}
if (information.getContainers()[archiveId].getFilesIndexes().length == 1) {
int fileId = information.getContainers()[archiveId].getFilesIndexes()[0];
filesData[archiveId][fileId] = data;
} else {
int readPosition = data.length;
int amtOfLoops = data[--readPosition] & 0xff;
readPosition -= amtOfLoops * (information.getContainers()[archiveId].getFilesIndexes().length * 4);
ByteBuffer buffer = ByteBuffer.wrap(data);
int filesSize[] = new int[information.getContainers()[archiveId].getFilesIndexes().length];
buffer.position(readPosition);
for (int loop = 0; loop < amtOfLoops; loop++) {
int offset = 0;
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
filesSize[fileIndex] += offset += buffer.getInt();
}
}
byte[][] filesBufferData = new byte[information.getContainers()[archiveId].getFilesIndexes().length][];
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
filesBufferData[fileIndex] = new byte[filesSize[fileIndex]];
filesSize[fileIndex] = 0;
}
buffer.position(readPosition);
int sourceOffset = 0;
for (int loop = 0; loop < amtOfLoops; loop++) {
int dataRead = 0;
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
dataRead += buffer.getInt();
System.arraycopy(data, sourceOffset, filesBufferData[fileIndex], filesSize[fileIndex], dataRead);
sourceOffset += dataRead;
filesSize[fileIndex] += dataRead;
}
}
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
filesData[archiveId][information.getContainers()[archiveId].getFilesIndexes()[fileIndex]] = filesBufferData[fileIndex];
}
}
return true;
}
/**
* Get the file data.
* @param containerId The container id.
* @param fileId The file id.
* @param xteaKeys The container keys.
* @return The file data.
*/
public byte[] getFileData(int containerId, int fileId, int[] xteaKeys) {
if (!validFile(containerId, fileId)) {
return null;
}
if (filesData[containerId] == null || filesData[containerId][fileId] == null) {
if (!loadFilesData(containerId, xteaKeys)) {
return null;
}
}
byte[] data = filesData[containerId][fileId];
if (discardFilesData) {
if (filesData[containerId].length == 1) {
filesData[containerId] = null;
} else {
filesData[containerId][fileId] = null;
}
}
return data;
}
/**
* Get the containers information.
* @return The containers information.
*/
public ContainersInformation getInformation() {
return information;
}
/**
* Gets the discardFilesData.
* @return the discardFilesData.
*/
public boolean isDiscardFilesData() {
return discardFilesData;
}
/**
* Sets the discardFilesData.
* @param discardFilesData the discardFilesData to set
*/
public void setDiscardFilesData(boolean discardFilesData) {
this.discardFilesData = discardFilesData;
}
/**
* Gets the filesData.
* @return the filesData.
*/
public byte[][][] getFilesData() {
return filesData;
}
/**
* Sets the filesData.
* @param filesData the filesData to set
*/
public void setFilesData(byte[][][] filesData) {
this.filesData = filesData;
}
/**
* Sets the cacheFile.
* @param cacheFile the cacheFile to set
*/
public void setCacheFile(CacheFile cacheFile) {
this.cacheFile = cacheFile;
}
/**
* Sets the information.
* @param information the information to set
*/
public void setInformation(ContainersInformation information) {
this.information = information;
}
}
+193
View File
@@ -0,0 +1,193 @@
package core.cache;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.HashMap;
import java.util.Map;
import core.cache.misc.buffer.ByteBufferUtils;
/**
* The server data storage.
* @author Emperor
*/
public final class ServerStore {
/**
* The storage.
*/
private static Map<String, StoreFile> storage = new HashMap<>();
/**
* If the store has initialized.
*/
private static boolean initialized;
/**
* Initializes the store.
* @param path The file path.
*/
public static void init(String path) {
storage = new HashMap<>();
File file = new File(path + "/dynamic_cache.keldagrim");
if (file.exists()) {
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
FileChannel channel = raf.getChannel();
ByteBuffer buffer = channel.map(MapMode.READ_WRITE, 0, channel.size());
int size = buffer.getShort() & 0xFFFF;
for (int i = 0; i < size; i++) {
StoreFile store = new StoreFile();
store.setDynamic(true);
String archive = ByteBufferUtils.getString(buffer);
byte[] data = new byte[buffer.getInt()];
buffer.get(data);
store.setData(data);
storage.put(archive, store);
}
if (buffer.hasRemaining()) {
throw new IllegalStateException("Unable to read all dynamic data (size=" + size + ")!");
}
channel.close();
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
initialized = true;
}
/**
* Used for writing the static store.
* @param path The path.
*/
public static void createStaticStore(String path) {
write(path + "/static_cache.keldagrim", false);
}
/**
* Writes all the dynamic storage files (on server termination).
* @param path The path.
*/
public static void dump(String path) {
write(path + "/dynamic_cache.keldagrim", true);
}
/**
* Writes the store file to the given file path.
* @param filePath The file path.
* @param dynamic If the dynamic store is being written.
*/
public static void write(String filePath, boolean dynamic) {
if (!initialized) {
throw new IllegalStateException("Server store has not been initialized!");
}
File f = new File(filePath);
if (f.exists()) {
f.delete();
}
ByteBuffer buffer = ByteBuffer.allocate(1 << 28);
buffer.putShort((short) 0);
int size = 0;
for (String archive : storage.keySet()) {
StoreFile file = storage.get(archive);
if (file.isDynamic() != dynamic) {
continue;
}
size++;
ByteBuffer buf = file.data();
ByteBufferUtils.putString(archive, buffer);
buffer.putInt(buf.remaining());
buffer.put(buf);
}
buffer.putShort(0, (short) size);
buffer.flip();
try (RandomAccessFile raf = new RandomAccessFile(f, "rw")) {
FileChannel channel = raf.getChannel();
channel.write(buffer);
channel.close();
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Sets the archive data.
* @param archive The archive id.
* @param buffer The readable buffer.
*/
public static void setArchive(String archive, ByteBuffer buffer) {
setArchive(archive, buffer, true);
}
/**
* Sets the archive data.
* @param archive The archive id.
* @param buffer The readable buffer.
* @param dynamic If the data changes during server runtime.
*/
public static void setArchive(String archive, ByteBuffer buffer, boolean dynamic) {
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
setArchive(archive, data, dynamic, true);
}
/**
* Sets the archive data.
* @param archive The archive index.
* @param data The archive data.
* @param dynamic If the data changes during server runtime.
*/
public static void setArchive(String archive, byte[] data, boolean dynamic) {
setArchive(archive, data, dynamic, true);
}
/**
* Sets the archive data.
* @param archive The archive index.
* @param data The archive data.
* @param dynamic If the data changes during server runtime.
* @param overwrite If the archive should be overwritten.
*/
public static void setArchive(String archive, byte[] data, boolean dynamic, boolean overwrite) {
StoreFile file = storage.get(archive);
if (file == null) {
storage.put(archive, file = new StoreFile());
} else if (!overwrite) {
throw new IllegalStateException("Already contained archive " + archive + "!");
}
file.setDynamic(dynamic);
file.setData(data);
}
/**
* Gets the archive data for the given archive id.
* @param archive The archive index.
* @return The archive data.
*/
public static ByteBuffer getArchive(String archive) {
return get(archive).data();
}
/**
* Sets the archive file.
* @param archive The archive.
* @param file The file.
*/
public static void set(String archive, StoreFile file) {
storage.put(archive, file);
}
/**
* Gets the store file for the given archive.
* @param archive The archive id.
* @return The store file.
*/
public static StoreFile get(String archive) {
return storage.get(archive);
}
}
+72
View File
@@ -0,0 +1,72 @@
package core.cache;
import java.nio.ByteBuffer;
/**
* Represents a file used in the server store.
* @author Emperor
*/
public final class StoreFile {
/**
* If the data can change during server runtime.
*/
private boolean dynamic;
/**
* The file data.
*/
private byte[] data;
/**
* Constructs a new {@code StoreFile} {@code Object}.
*/
public StoreFile() {
/*
* empty.
*/
}
/**
* Puts the data on the buffer.
* @param buffer The buffer.
*/
public void put(ByteBuffer buffer) {
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
this.data = data;
}
/**
* Creates a byte buffer containing the file data.
* @return The buffer.
*/
public ByteBuffer data() {
return ByteBuffer.wrap(data);
}
/**
* Sets the data.
* @param data The data.
*/
public void setData(byte[] data) {
this.data = data;
}
/**
* Gets the dynamic.
* @return The dynamic.
*/
public boolean isDynamic() {
return dynamic;
}
/**
* Sets the dynamic.
* @param dynamic The dynamic to set.
*/
public void setDynamic(boolean dynamic) {
this.dynamic = dynamic;
}
}
@@ -0,0 +1,56 @@
package core.cache.bzip2;
public class BZip2BlockEntry {
boolean aBooleanArray2205[];
boolean aBooleanArray2213[];
byte aByte2201;
byte aByteArray2204[];
byte aByteArray2211[];
byte aByteArray2212[];
byte aByteArray2214[];
byte aByteArray2219[];
byte aByteArray2224[];
byte aByteArrayArray2229[][];
int anInt2202;
int anInt2203;
int anInt2206;
int anInt2207;
int anInt2208;
int anInt2209;
int anInt2215;
int anInt2216;
int anInt2217;
int anInt2221;
int anInt2222;
int anInt2223;
int anInt2225;
int anInt2227;
int anInt2232;
int anIntArray2200[];
int anIntArray2220[];
int anIntArray2226[];
int anIntArray2228[];
int anIntArrayArray2210[][];
int anIntArrayArray2218[][];
int anIntArrayArray2230[][];
public BZip2BlockEntry() {
anIntArray2200 = new int[6];
anInt2203 = 0;
aByteArray2204 = new byte[4096];
aByteArray2211 = new byte[256];
aByteArray2214 = new byte[18002];
aByteArray2219 = new byte[18002];
anIntArray2220 = new int[257];
anIntArrayArray2218 = new int[6][258];
aBooleanArray2205 = new boolean[16];
aBooleanArray2213 = new boolean[256];
anInt2209 = 0;
anIntArray2226 = new int[16];
anIntArrayArray2210 = new int[6][258];
aByteArrayArray2229 = new byte[6][258];
anIntArrayArray2230 = new int[6][258];
anIntArray2228 = new int[256];
}
}
@@ -0,0 +1,536 @@
package core.cache.bzip2;
public class BZip2Decompressor {
private static int anIntArray257[];
private static BZip2BlockEntry entryInstance = new BZip2BlockEntry();
public static final void decompress(byte decompressedData[], byte packedData[], int containerSize, int blockSize) {
synchronized (entryInstance) {
entryInstance.aByteArray2224 = packedData;
entryInstance.anInt2209 = blockSize;
entryInstance.aByteArray2212 = decompressedData;
entryInstance.anInt2203 = 0;
entryInstance.anInt2206 = decompressedData.length;
entryInstance.anInt2232 = 0;
entryInstance.anInt2207 = 0;
entryInstance.anInt2217 = 0;
entryInstance.anInt2216 = 0;
method1793(entryInstance);
entryInstance.aByteArray2224 = null;
entryInstance.aByteArray2212 = null;
}
}
private static final void method1785(BZip2BlockEntry entry) {
entry.anInt2215 = 0;
for (int i = 0; i < 256; i++) {
if (entry.aBooleanArray2213[i]) {
entry.aByteArray2211[entry.anInt2215] = (byte) i;
entry.anInt2215++;
}
}
}
private static final void method1786(int ai[], int ai1[], int ai2[], byte abyte0[], int i, int j, int k) {
int l = 0;
for (int i1 = i; i1 <= j; i1++) {
for (int l2 = 0; l2 < k; l2++) {
if (abyte0[l2] == i1) {
ai2[l] = l2;
l++;
}
}
}
for (int j1 = 0; j1 < 23; j1++) {
ai1[j1] = 0;
}
for (int k1 = 0; k1 < k; k1++) {
ai1[abyte0[k1] + 1]++;
}
for (int l1 = 1; l1 < 23; l1++) {
ai1[l1] += ai1[l1 - 1];
}
for (int i2 = 0; i2 < 23; i2++) {
ai[i2] = 0;
}
int i3 = 0;
for (int j2 = i; j2 <= j; j2++) {
i3 += ai1[j2 + 1] - ai1[j2];
ai[j2] = i3 - 1;
i3 <<= 1;
}
for (int k2 = i + 1; k2 <= j; k2++) {
ai1[k2] = (ai[k2 - 1] + 1 << 1) - ai1[k2];
}
}
private static final void method1787(BZip2BlockEntry entry) {
byte byte4 = entry.aByte2201;
int i = entry.anInt2222;
int j = entry.anInt2227;
int k = entry.anInt2221;
int ai[] = anIntArray257;
int l = entry.anInt2208;
byte abyte0[] = entry.aByteArray2212;
int i1 = entry.anInt2203;
int j1 = entry.anInt2206;
int k1 = j1;
int l1 = entry.anInt2225 + 1;
label0: do {
if (i > 0) {
do {
if (j1 == 0) {
break label0;
}
if (i == 1) {
break;
}
abyte0[i1] = byte4;
i--;
i1++;
j1--;
} while (true);
if (j1 == 0) {
i = 1;
break;
}
abyte0[i1] = byte4;
i1++;
j1--;
}
boolean flag = true;
while (flag) {
flag = false;
if (j == l1) {
i = 0;
break label0;
}
byte4 = (byte) k;
l = ai[l];
byte byte0 = (byte) (l & 0xff);
l >>= 8;
j++;
if (byte0 != k) {
k = byte0;
if (j1 == 0) {
i = 1;
} else {
abyte0[i1] = byte4;
i1++;
j1--;
flag = true;
continue;
}
break label0;
}
if (j != l1) {
continue;
}
if (j1 == 0) {
i = 1;
break label0;
}
abyte0[i1] = byte4;
i1++;
j1--;
flag = true;
}
i = 2;
l = ai[l];
byte byte1 = (byte) (l & 0xff);
l >>= 8;
if (++j != l1) {
if (byte1 != k) {
k = byte1;
} else {
i = 3;
l = ai[l];
byte byte2 = (byte) (l & 0xff);
l >>= 8;
if (++j != l1) {
if (byte2 != k) {
k = byte2;
} else {
l = ai[l];
byte byte3 = (byte) (l & 0xff);
l >>= 8;
j++;
i = (byte3 & 0xff) + 4;
l = ai[l];
k = (byte) (l & 0xff);
l >>= 8;
j++;
}
}
}
}
} while (true);
entry.anInt2216 += k1 - j1;
entry.aByte2201 = byte4;
entry.anInt2222 = i;
entry.anInt2227 = j;
entry.anInt2221 = k;
anIntArray257 = ai;
entry.anInt2208 = l;
entry.aByteArray2212 = abyte0;
entry.anInt2203 = i1;
entry.anInt2206 = j1;
}
private static final byte method1788(BZip2BlockEntry entry) {
return (byte) method1790(1, entry);
}
private static final byte method1789(BZip2BlockEntry entryInstance2) {
return (byte) method1790(8, entryInstance2);
}
private static final int method1790(int i, BZip2BlockEntry entry) {
int j;
do {
if (entry.anInt2232 >= i) {
int k = entry.anInt2207 >> entry.anInt2232 - i & (1 << i) - 1;
entry.anInt2232 -= i;
j = k;
break;
}
entry.anInt2207 = entry.anInt2207 << 8 | entry.aByteArray2224[entry.anInt2209] & 0xff;
entry.anInt2232 += 8;
entry.anInt2209++;
entry.anInt2217++;
} while (true);
return j;
}
public static void clearBlockEntryInstance() {
entryInstance = null;
}
private static final void method1793(BZip2BlockEntry entryInstance2) {
// unused
/*
* boolean flag = false; boolean flag1 = false; boolean flag2 = false;
* boolean flag3 = false; boolean flag4 = false; boolean flag5 = false;
* boolean flag6 = false; boolean flag7 = false; boolean flag8 = false;
* boolean flag9 = false; boolean flag10 = false; boolean flag11 =
* false; boolean flag12 = false; boolean flag13 = false; boolean flag14
* = false; boolean flag15 = false; boolean flag16 = false; boolean
* flag17 = false;
*/
int j8 = 0;
int ai[] = null;
int ai1[] = null;
int ai2[] = null;
entryInstance2.anInt2202 = 1;
if (anIntArray257 == null) {
anIntArray257 = new int[entryInstance2.anInt2202 * 0x186a0];
}
boolean flag18 = true;
while (flag18) {
byte byte0 = method1789(entryInstance2);
if (byte0 == 23) {
return;
}
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1789(entryInstance2);
byte0 = method1788(entryInstance2);
entryInstance2.anInt2223 = 0;
byte0 = method1789(entryInstance2);
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
byte0 = method1789(entryInstance2);
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
byte0 = method1789(entryInstance2);
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
for (int j = 0; j < 16; j++) {
byte byte1 = method1788(entryInstance2);
if (byte1 == 1) {
entryInstance2.aBooleanArray2205[j] = true;
} else {
entryInstance2.aBooleanArray2205[j] = false;
}
}
for (int k = 0; k < 256; k++) {
entryInstance2.aBooleanArray2213[k] = false;
}
for (int l = 0; l < 16; l++) {
if (entryInstance2.aBooleanArray2205[l]) {
for (int i3 = 0; i3 < 16; i3++) {
byte byte2 = method1788(entryInstance2);
if (byte2 == 1) {
entryInstance2.aBooleanArray2213[l * 16 + i3] = true;
}
}
}
}
method1785(entryInstance2);
int i4 = entryInstance2.anInt2215 + 2;
int j4 = method1790(3, entryInstance2);
int k4 = method1790(15, entryInstance2);
for (int i1 = 0; i1 < k4; i1++) {
int j3 = 0;
do {
byte byte3 = method1788(entryInstance2);
if (byte3 == 0) {
break;
}
j3++;
} while (true);
entryInstance2.aByteArray2214[i1] = (byte) j3;
}
byte abyte0[] = new byte[6];
for (byte byte16 = 0; byte16 < j4; byte16++) {
abyte0[byte16] = byte16;
}
for (int j1 = 0; j1 < k4; j1++) {
byte byte17 = entryInstance2.aByteArray2214[j1];
byte byte15 = abyte0[byte17];
for (; byte17 > 0; byte17--) {
abyte0[byte17] = abyte0[byte17 - 1];
}
abyte0[0] = byte15;
entryInstance2.aByteArray2219[j1] = byte15;
}
for (int k3 = 0; k3 < j4; k3++) {
int k6 = method1790(5, entryInstance2);
for (int k1 = 0; k1 < i4; k1++) {
do {
byte byte4 = method1788(entryInstance2);
if (byte4 == 0) {
break;
}
byte4 = method1788(entryInstance2);
if (byte4 == 0) {
k6++;
} else {
k6--;
}
} while (true);
entryInstance2.aByteArrayArray2229[k3][k1] = (byte) k6;
}
}
for (int l3 = 0; l3 < j4; l3++) {
byte byte8 = 32;
int i = 0;
for (int l1 = 0; l1 < i4; l1++) {
if (entryInstance2.aByteArrayArray2229[l3][l1] > i) {
i = entryInstance2.aByteArrayArray2229[l3][l1];
}
if (entryInstance2.aByteArrayArray2229[l3][l1] < byte8) {
byte8 = entryInstance2.aByteArrayArray2229[l3][l1];
}
}
method1786(entryInstance2.anIntArrayArray2230[l3], entryInstance2.anIntArrayArray2218[l3], entryInstance2.anIntArrayArray2210[l3], entryInstance2.aByteArrayArray2229[l3], byte8, i, i4);
entryInstance2.anIntArray2200[l3] = byte8;
}
int l4 = entryInstance2.anInt2215 + 1;
int i5 = -1;
int j5 = 0;
for (int i2 = 0; i2 <= 255; i2++) {
entryInstance2.anIntArray2228[i2] = 0;
}
int i9 = 4095;
for (int k8 = 15; k8 >= 0; k8--) {
for (int l8 = 15; l8 >= 0; l8--) {
entryInstance2.aByteArray2204[i9] = (byte) (k8 * 16 + l8);
i9--;
}
entryInstance2.anIntArray2226[k8] = i9 + 1;
}
int l5 = 0;
if (j5 == 0) {
i5++;
j5 = 50;
byte byte12 = entryInstance2.aByteArray2219[i5];
j8 = entryInstance2.anIntArray2200[byte12];
ai = entryInstance2.anIntArrayArray2230[byte12];
ai2 = entryInstance2.anIntArrayArray2210[byte12];
ai1 = entryInstance2.anIntArrayArray2218[byte12];
}
j5--;
int l6 = j8;
int k7;
byte byte9;
for (k7 = method1790(l6, entryInstance2); k7 > ai[l6]; k7 = k7 << 1 | byte9) {
l6++;
byte9 = method1788(entryInstance2);
}
for (int k5 = ai2[k7 - ai1[l6]]; k5 != l4;) {
if (k5 == 0 || k5 == 1) {
int i6 = -1;
int j6 = 1;
do {
if (k5 == 0) {
i6 += j6;
} else if (k5 == 1) {
i6 += 2 * j6;
}
j6 *= 2;
if (j5 == 0) {
i5++;
j5 = 50;
byte byte13 = entryInstance2.aByteArray2219[i5];
j8 = entryInstance2.anIntArray2200[byte13];
ai = entryInstance2.anIntArrayArray2230[byte13];
ai2 = entryInstance2.anIntArrayArray2210[byte13];
ai1 = entryInstance2.anIntArrayArray2218[byte13];
}
j5--;
int i7 = j8;
int l7;
byte byte10;
for (l7 = method1790(i7, entryInstance2); l7 > ai[i7]; l7 = l7 << 1 | byte10) {
i7++;
byte10 = method1788(entryInstance2);
}
k5 = ai2[l7 - ai1[i7]];
} while (k5 == 0 || k5 == 1);
i6++;
byte byte5 = entryInstance2.aByteArray2211[entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[0]] & 0xff];
entryInstance2.anIntArray2228[byte5 & 0xff] += i6;
for (; i6 > 0; i6--) {
anIntArray257[l5] = byte5 & 0xff;
l5++;
}
} else {
int i11 = k5 - 1;
byte byte6;
if (i11 < 16) {
int i10 = entryInstance2.anIntArray2226[0];
byte6 = entryInstance2.aByteArray2204[i10 + i11];
for (; i11 > 3; i11 -= 4) {
int j11 = i10 + i11;
entryInstance2.aByteArray2204[j11] = entryInstance2.aByteArray2204[j11 - 1];
entryInstance2.aByteArray2204[j11 - 1] = entryInstance2.aByteArray2204[j11 - 2];
entryInstance2.aByteArray2204[j11 - 2] = entryInstance2.aByteArray2204[j11 - 3];
entryInstance2.aByteArray2204[j11 - 3] = entryInstance2.aByteArray2204[j11 - 4];
}
for (; i11 > 0; i11--) {
entryInstance2.aByteArray2204[i10 + i11] = entryInstance2.aByteArray2204[(i10 + i11) - 1];
}
entryInstance2.aByteArray2204[i10] = byte6;
} else {
int k10 = i11 / 16;
int l10 = i11 % 16;
int j10 = entryInstance2.anIntArray2226[k10] + l10;
byte6 = entryInstance2.aByteArray2204[j10];
for (; j10 > entryInstance2.anIntArray2226[k10]; j10--) {
entryInstance2.aByteArray2204[j10] = entryInstance2.aByteArray2204[j10 - 1];
}
entryInstance2.anIntArray2226[k10]++;
for (; k10 > 0; k10--) {
entryInstance2.anIntArray2226[k10]--;
entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[k10]] = entryInstance2.aByteArray2204[(entryInstance2.anIntArray2226[k10 - 1] + 16) - 1];
}
entryInstance2.anIntArray2226[0]--;
entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[0]] = byte6;
if (entryInstance2.anIntArray2226[0] == 0) {
int l9 = 4095;
for (int j9 = 15; j9 >= 0; j9--) {
for (int k9 = 15; k9 >= 0; k9--) {
entryInstance2.aByteArray2204[l9] = entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[j9] + k9];
l9--;
}
entryInstance2.anIntArray2226[j9] = l9 + 1;
}
}
}
entryInstance2.anIntArray2228[entryInstance2.aByteArray2211[byte6 & 0xff] & 0xff]++;
anIntArray257[l5] = entryInstance2.aByteArray2211[byte6 & 0xff] & 0xff;
l5++;
if (j5 == 0) {
i5++;
j5 = 50;
byte byte14 = entryInstance2.aByteArray2219[i5];
j8 = entryInstance2.anIntArray2200[byte14];
ai = entryInstance2.anIntArrayArray2230[byte14];
ai2 = entryInstance2.anIntArrayArray2210[byte14];
ai1 = entryInstance2.anIntArrayArray2218[byte14];
}
j5--;
int j7 = j8;
int i8;
byte byte11;
for (i8 = method1790(j7, entryInstance2); i8 > ai[j7]; i8 = i8 << 1 | byte11) {
j7++;
byte11 = method1788(entryInstance2);
}
k5 = ai2[i8 - ai1[j7]];
}
}
entryInstance2.anInt2222 = 0;
entryInstance2.aByte2201 = 0;
entryInstance2.anIntArray2220[0] = 0;
for (int j2 = 1; j2 <= 256; j2++) {
entryInstance2.anIntArray2220[j2] = entryInstance2.anIntArray2228[j2 - 1];
}
for (int k2 = 1; k2 <= 256; k2++) {
entryInstance2.anIntArray2220[k2] += entryInstance2.anIntArray2220[k2 - 1];
}
for (int l2 = 0; l2 < l5; l2++) {
byte byte7 = (byte) (anIntArray257[l2] & 0xff);
anIntArray257[entryInstance2.anIntArray2220[byte7 & 0xff]] |= l2 << 8;
entryInstance2.anIntArray2220[byte7 & 0xff]++;
}
entryInstance2.anInt2208 = anIntArray257[entryInstance2.anInt2223] >> 8;
entryInstance2.anInt2227 = 0;
entryInstance2.anInt2208 = anIntArray257[entryInstance2.anInt2208];
entryInstance2.anInt2221 = (byte) (entryInstance2.anInt2208 & 0xff);
entryInstance2.anInt2208 >>= 8;
entryInstance2.anInt2227++;
entryInstance2.anInt2225 = l5;
method1787(entryInstance2);
if (entryInstance2.anInt2227 == entryInstance2.anInt2225 + 1 && entryInstance2.anInt2222 == 0) {
flag18 = true;
} else {
flag18 = false;
}
}
}
}
@@ -0,0 +1,271 @@
package core.cache.crypto;
/**
* <p> An implementation of an ISAAC cipher. See <a
* href="http://en.wikipedia.org/wiki/ISAAC_(cipher)">
* http://en.wikipedia.org/wiki/ISAAC_(cipher)</a> for more information. </p>
* <p> This implementation is based on the one written by Bob Jenkins, which is
* available at <a href="http://www.burtleburtle.net/bob/java/rand/Rand.java">
* http://www.burtleburtle.net/bob/java/rand/Rand.java</a>. </p>
* @author Graham Edgecombe
*/
public class ISAACCipher {
/**
* The golden ratio.
*/
public static final int RATIO = 0x9e3779b9;
/**
* The log of the size of the results and memory arrays.
*/
public static final int SIZE_LOG = 8;
/**
* The size of the results and memory arrays.
*/
public static final int SIZE = 1 << SIZE_LOG;
/**
* For pseudorandom lookup.
*/
public static final int MASK = (SIZE - 1) << 2;
/**
* The count through the results.
*/
private int count = 0;
/**
* The results.
*/
private int results[] = new int[SIZE];
/**
* The internal memory state.
*/
private int memory[] = new int[SIZE];
/**
* The accumulator.
*/
private int a;
/**
* The last result.
*/
private int b;
/**
* The counter.
*/
private int c;
/**
* Creates the ISAAC cipher.
* @param seed The seed.
*/
public ISAACCipher(int[] seed) {
for (int i = 0; i < seed.length; i++) {
results[i] = seed[i];
}
init(true);
}
/**
* Gets the next value.
* @return The next value.
*/
public int getNextValue() {
if (count-- == 0) {
isaac();
count = SIZE - 1;
}
return 0;//results[count];
}
/**
* Generates 256 results.
*/
public void isaac() {
int i, j, x, y;
b += ++c;
for (i = 0, j = SIZE / 2; i < SIZE / 2;) {
x = memory[i];
a ^= a << 13;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
x = memory[i];
a ^= a >>> 6;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
x = memory[i];
a ^= a << 2;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
x = memory[i];
a ^= a >>> 16;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
}
for (j = 0; j < SIZE / 2;) {
x = memory[i];
a ^= a << 13;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
x = memory[i];
a ^= a >>> 6;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
x = memory[i];
a ^= a << 2;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
x = memory[i];
a ^= a >>> 16;
a += memory[j++];
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
}
}
/**
* Initialises the ISAAC.
* @param flag Flag indicating if we should perform a second pass.
*/
public void init(boolean flag) {
int i;
int a, b, c, d, e, f, g, h;
a = b = c = d = e = f = g = h = RATIO;
for (i = 0; i < 4; ++i) {
a ^= b << 11;
d += a;
b += c;
b ^= c >>> 2;
e += b;
c += d;
c ^= d << 8;
f += c;
d += e;
d ^= e >>> 16;
g += d;
e += f;
e ^= f << 10;
h += e;
f += g;
f ^= g >>> 4;
a += f;
g += h;
g ^= h << 8;
b += g;
h += a;
h ^= a >>> 9;
c += h;
a += b;
}
for (i = 0; i < SIZE; i += 8) {
if (flag) {
a += results[i];
b += results[i + 1];
c += results[i + 2];
d += results[i + 3];
e += results[i + 4];
f += results[i + 5];
g += results[i + 6];
h += results[i + 7];
}
a ^= b << 11;
d += a;
b += c;
b ^= c >>> 2;
e += b;
c += d;
c ^= d << 8;
f += c;
d += e;
d ^= e >>> 16;
g += d;
e += f;
e ^= f << 10;
h += e;
f += g;
f ^= g >>> 4;
a += f;
g += h;
g ^= h << 8;
b += g;
h += a;
h ^= a >>> 9;
c += h;
a += b;
memory[i] = a;
memory[i + 1] = b;
memory[i + 2] = c;
memory[i + 3] = d;
memory[i + 4] = e;
memory[i + 5] = f;
memory[i + 6] = g;
memory[i + 7] = h;
}
if (flag) {
for (i = 0; i < SIZE; i += 8) {
a += memory[i];
b += memory[i + 1];
c += memory[i + 2];
d += memory[i + 3];
e += memory[i + 4];
f += memory[i + 5];
g += memory[i + 6];
h += memory[i + 7];
a ^= b << 11;
d += a;
b += c;
b ^= c >>> 2;
e += b;
c += d;
c ^= d << 8;
f += c;
d += e;
d ^= e >>> 16;
g += d;
e += f;
e ^= f << 10;
h += e;
f += g;
f ^= g >>> 4;
a += f;
g += h;
g ^= h << 8;
b += g;
h += a;
h ^= a >>> 9;
c += h;
a += b;
memory[i] = a;
memory[i + 1] = b;
memory[i + 2] = c;
memory[i + 3] = d;
memory[i + 4] = e;
memory[i + 5] = f;
memory[i + 6] = g;
memory[i + 7] = h;
}
}
isaac();
count = SIZE;
}
}
@@ -0,0 +1,45 @@
package core.cache.crypto;
/**
* Represents a ISAAC key pair, for both input and output.
* @author `Discardedx2
*/
public final class ISAACPair {
/**
* The input cipher.
*/
private ISAACCipher input;
/**
* The output cipher.
*/
private ISAACCipher output;
/**
* Constructs a new {@code ISAACPair} {@code Object}.
* @param input The input cipher.
* @param output The output cipher.
*/
public ISAACPair(ISAACCipher input, ISAACCipher output) {
this.input = input;
this.output = output;
}
/**
* Gets the input cipher.
* @return The input cipher.
*/
public ISAACCipher getInput() {
return input;
}
/**
* Gets the output cipher.
* @return The output cipher.
*/
public ISAACCipher getOutput() {
return output;
}
}
@@ -0,0 +1,124 @@
package core.cache.crypto;
import java.nio.ByteBuffer;
/**
* Holds XTEA cryption methods.
* @author ?
* @author Emperor
*/
public final class XTEACryption {
/**
* The delta value
*/
private static final int DELTA = -1640531527;
/**
* The sum.
*/
private static final int SUM = -957401312;
/**
* The amount of "cryption cycles".
*/
private static final int NUM_ROUNDS = 32;
/**
* Constructs a new {@code XTEACryption}.
*/
private XTEACryption() {
/*
* empty.
*/
}
/**
* Decrypts the contents of the buffer.
* @param keys The cryption keys.
* @param buffer The buffer.
*/
public static ByteBuffer decrypt(int[] keys, ByteBuffer buffer) {
return decrypt(keys, buffer, buffer.position(), buffer.limit());
}
/**
* Decrypts the buffer data.
* @param keys The keys.
* @param buffer The buffer to decrypt.
* @param offset The offset of the data to decrypt.
* @param length The length.
* @return The decrypted data.
*/
public static ByteBuffer decrypt(int[] keys, ByteBuffer buffer, int offset, int length) {
int numBlocks = (length - offset) / 8;
int[] block = new int[2];
for (int i = 0; i < numBlocks; i++) {
int index = i * 8 + offset;
block[0] = buffer.getInt(index);
block[1] = buffer.getInt(index + 4);
decipher(keys, block);
buffer.putInt(index, block[0]);
buffer.putInt(index + 4, block[1]);
}
return buffer;
}
/**
* Deciphers the values.
* @param keys The cryption key.
* @param block The values to decipher.
*/
private static void decipher(int[] keys, int[] block) {
long sum = SUM;
for (int i = 0; i < NUM_ROUNDS; i++) {
block[1] -= (keys[(int) ((sum & 0x1933) >>> 11)] + sum ^ block[0] + (block[0] << 4 ^ block[0] >>> 5));
sum -= DELTA;
block[0] -= ((block[1] << 4 ^ block[1] >>> 5) + block[1] ^ keys[(int) (sum & 0x3)] + sum);
}
}
/**
* Encrypts the contents of the byte buffer.
* @param keys The cryption keys.
* @param buffer The buffer to encrypt.
*/
public static void encrypt(int[] keys, ByteBuffer buffer) {
encrypt(keys, buffer, buffer.position(), buffer.limit());
}
/**
* Encrypts the buffer data.
* @param keys The keys.
* @param buffer The buffer to encrypt.
* @param offset The offset of the data to encrypt.
* @param length The length.
* @return The encrypted data.
*/
public static void encrypt(int[] keys, ByteBuffer buffer, int offset, int length) {
int numBlocks = (length - offset) / 8;
int[] block = new int[2];
for (int i = 0; i < numBlocks; i++) {
int index = i * 8 + offset;
block[0] = buffer.getInt(index);
block[1] = buffer.getInt(index + 4);
encipher(keys, block);
buffer.putInt(index, block[0]);
buffer.putInt(index + 4, block[1]);
}
}
/**
* Enciphers the values of the block.
* @param keys The cryption keys.
* @param block The block to encipher.
*/
private static void encipher(int[] keys, int[] block) {
long sum = 0;
for (int i = 0; i < NUM_ROUNDS; i++) {
block[0] += ((block[1] << 4 ^ block[1] >>> 5) + block[1] ^ keys[(int) (sum & 0x3)] + sum);
sum += DELTA;
block[1] += (keys[(int) ((sum & 0x1933) >>> 11)] + sum ^ block[0] + (block[0] << 4 ^ block[0] >>> 5));
}
}
}
@@ -0,0 +1,187 @@
package core.cache.def;
import java.util.HashMap;
import java.util.Map;
import core.tools.StringUtils;
import core.game.node.Node;
/**
* Represent's a node's definitions.
* @author Emperor
* @param <T> The node type.
*/
public class Definition<T extends Node> {
/**
* The node id.
*/
protected int id;
/**
* The name.
*/
protected String name = "null";
/**
* The examine info.
*/
protected String examine;
/**
* The options.
*/
protected String[] options;
/**
* The configurations.
*/
protected final Map<String, Object> handlers = new HashMap<String, Object>();
/**
* Constructs a new {@code Definition} {@code Object}.
*/
public Definition() {
/*
* empty.
*/
}
/**
* Checks if this node has options.
* @return {@code True} if so.
*/
public boolean hasOptions() {
return hasOptions(true);
}
/**
* Checks if this node has options.
* @param examine If examine should be treated as an option.
* @return {@code True} if so.
*/
public boolean hasOptions(boolean examine) {
if (name.equals("null") || options == null) {
return false;
}
for (String option : options) {
if (option != null && !option.equals("null")) {
if (examine || !option.equals("Examine")) {
return true;
}
}
}
return false;
}
/**
* Gets a configuration of this item's definitions.
* @param key The key.
* @return The configuration value.
*/
@SuppressWarnings("unchecked")
public <V> V getConfiguration(String key) {
return (V) handlers.get(key);
}
/**
* Gets a configuration from this item's definitions.
* @param key The key.
* @param fail The object to return if there was no value found for this
* key.
* @return The value, or the fail object.
*/
@SuppressWarnings("unchecked")
public <V> V getConfiguration(String key, V fail) {
V object = (V) handlers.get(key);
if (object == null) {
return fail;
}
return object;
}
/**
* Gets the id.
* @return The id.
*/
public int getId() {
return id;
}
/**
* Sets the id.
* @param id The id to set.
*/
public void setId(int id) {
this.id = id;
}
/**
* Gets the name.
* @return The name.
*/
public String getName() {
return name;
}
/**
* Sets the name.
* @param name The name to set.
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the examine.
* @return The examine.
*/
public String getExamine() {
if (examine == null) {
try {
examine = handlers.get("examine").toString();
} catch (Exception e){}
if(examine == null) {
if (name.length() > 0) {
examine = "It's a" + (StringUtils.isPlusN(name) ? "n " : " ") + name + ".";
} else {
examine = "null";
}
}
}
return examine;
}
/**
* Sets the examine.
* @param examine The examine to set.
*/
public void setExamine(String examine) {
this.examine = examine;
}
/**
* Gets the options.
* @return The options.
*/
public String[] getOptions() {
return options;
}
/**
* Sets the options.
* @param options The options to set.
*/
public void setOptions(String[] options) {
this.options = options;
}
/**
* Gets the configurations.
* @return The configurations.
*/
public Map<String, Object> getHandlers() {
return handlers;
}
}
@@ -0,0 +1,201 @@
package core.cache.def.impl;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import core.cache.Cache;
import core.cache.misc.buffer.ByteBufferUtils;
/**
* Represents an animation's definitions.
* @author Emperor
*/
public final class AnimationDefinition {
public int anInt2136;
public int anInt2137;
public int[] anIntArray2139;
public int anInt2140;
public boolean aBoolean2141 = false;
public int anInt2142;
public int emoteItem;
public int anInt2144 = -1;
public int[][] handledSounds;
public boolean[] aBooleanArray2149;
public int[] anIntArray2151;
public boolean aBoolean2152;
public int[] durations;
public int anInt2155;
public boolean aBoolean2158;
public boolean aBoolean2159;
public int anInt2162;
public int anInt2163;
boolean newHeader;
// added
public int[] soundMinDelay;
public int[] soundMaxDelay;
public int[] anIntArray1362;
public boolean effect2Sound;
private static final Map<Integer, AnimationDefinition> animDefs = new HashMap<>();
public static final AnimationDefinition forId(int emoteId) {
try {
AnimationDefinition defs = animDefs.get(emoteId);
if (defs != null) {
return defs;
}
byte[] data = Cache.getIndexes()[20].getFileData(emoteId >>> 7, emoteId & 0x7f);
defs = new AnimationDefinition();
if (data != null) {
defs.readValueLoop(ByteBuffer.wrap(data));
}
defs.method2394();
animDefs.put(emoteId, defs);
return defs;
} catch (Throwable t) {
return null;
}
}
private void readValueLoop(ByteBuffer buffer) {
for (;;) {
int opcode = buffer.get() & 0xFF;
if (opcode == 0) {
break;
}
readValues(buffer, opcode);
}
}
/**
* Gets the duration of this animation in milliseconds.
* @return The duration.
*/
public int getDuration() {
if (durations == null) {
return 0;
}
int duration = 0;
for (int i : durations) {
if (i > 100) {
continue;
}
duration += i * 20;
}
return duration;
}
/**
* Gets the duration of this animation in (600ms) ticks.
* @return The duration in ticks.
*/
public int getDurationTicks() {
int ticks = getDuration() / 600;
return Math.max(ticks, 1);
}
private void readValues(ByteBuffer buffer, int opcode) {
if (opcode == 1) {
int length = buffer.getShort() & 0xFFFF;
durations = new int[length];
for (int i = 0; i < length; i++) {
durations[i] = buffer.getShort() & 0xFFFF;
}
anIntArray2139 = new int[length];
for (int i = 0; i < length; i++) {
anIntArray2139[i] = buffer.getShort() & 0xFFFF;
}
for (int i = 0; i < length; i++) {
anIntArray2139[i] = ((buffer.getShort() & 0xFFFF << 16) + anIntArray2139[i]);
}
} else if (opcode != 2) {
if (opcode != 3) {
if (opcode == 4)
aBoolean2152 = true;
else if (opcode == 5)
anInt2142 = buffer.get() & 0xFF;
else if (opcode != 6) {
if (opcode == 7)
emoteItem = buffer.getShort() & 0xFFFF;
else if ((opcode ^ 0xffffffff) != -9) {
if (opcode != 9) {
if (opcode != 10) {
if (opcode == 11)
anInt2155 = buffer.get() & 0xFF;
else if (opcode == 12) {
int i = buffer.get() & 0xFF;
anIntArray2151 = new int[i];
for (int i_19_ = 0; ((i_19_ ^ 0xffffffff) > (i ^ 0xffffffff)); i_19_++) {
anIntArray2151[i_19_] = buffer.getShort() & 0xFFFF;
}
for (int i_20_ = 0; i > i_20_; i_20_++)
anIntArray2151[i_20_] = ((buffer.getShort() & 0xFFFF << 16) + anIntArray2151[i_20_]);
} else if (opcode == 13) {
// opcode 13
int i = buffer.getShort() & 0xFFFF;
handledSounds = new int[i][];
for (int i_21_ = 0; i_21_ < i; i_21_++) {
int i_22_ = buffer.get() & 0xFF;
if ((i_22_ ^ 0xffffffff) < -1) {
handledSounds[i_21_] = new int[i_22_];
handledSounds[i_21_][0] = ByteBufferUtils.getTriByte(buffer);
for (int i_23_ = 1; ((i_22_ ^ 0xffffffff) < (i_23_ ^ 0xffffffff)); i_23_++) {
handledSounds[i_21_][i_23_] = buffer.getShort() & 0xFFFF;
}
}
}
} else if (opcode == 14) {
aBoolean2141 = true;
} else {
System.out.println("Unhandled animation opcode " + opcode);
}
} else
anInt2162 = buffer.get() & 0xFF;
} else
anInt2140 = buffer.get() & 0xFF;
} else
anInt2136 = buffer.get() & 0xFF;
} else
anInt2144 = buffer.getShort() & 0xFFFF;
} else {
aBooleanArray2149 = new boolean[256];
int length = buffer.get() & 0xFF;
for (int i = 0; i < length; i++) {
aBooleanArray2149[buffer.get() & 0xFF] = true;
}
}
} else
anInt2163 = buffer.getShort() & 0xFFFF;
}
public void method2394() {
if (anInt2140 == -1) {
if (aBooleanArray2149 == null)
anInt2140 = 0;
else
anInt2140 = 2;
}
if (anInt2162 == -1) {
if (aBooleanArray2149 == null)
anInt2162 = 0;
else
anInt2162 = 2;
}
}
public AnimationDefinition() {
anInt2136 = 99;
emoteItem = -1;
anInt2140 = -1;
aBoolean2152 = false;
anInt2142 = 5;
aBoolean2159 = false;
anInt2163 = -1;
anInt2155 = 2;
aBoolean2158 = false;
anInt2162 = -1;
}
}
@@ -0,0 +1,255 @@
package core.cache.def.impl;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import core.cache.Cache;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.world.GameWorld;
/**
* The CS2 mapping.
* @author Emperor
*/
public final class CS2Mapping {
/**
* The CS2 mappings.
*/
private static final Map<Integer, CS2Mapping> maps = new HashMap<>();
/**
* The script id.
*/
private final int scriptId;
/**
* Unknown value.
*/
private int unknown;
/**
* Second unknown value.
*/
private int unknown1;
/**
* The default string value.
*/
private String defaultString;
/**
* The default integer value.
*/
private int defaultInt;
/**
* The mapping.
*/
private HashMap<Integer, Object> map;
/**
* The array of the objects.
*/
private Object[] array;
/**
* Constructs a new {@code CS2Mapping} {@code Object}.
* @param scriptId The script id.
*/
public CS2Mapping(int scriptId) {
this.scriptId = scriptId;
}
/**
* The main method.
* @param args The arguments cast on runtime.
* @throws Throwable When an exception occurs.
*/
public static void main(String... args) throws Throwable {
GameWorld.prompt(false);
BufferedWriter bw = new BufferedWriter(new FileWriter("./cs2.txt"));
for (int i = 0; i < 10000; i++) {
CS2Mapping mapping = forId(i);
if (mapping == null) {
continue;
}
if (mapping.map == null) {
continue;
}
bw.append("ScriptAPI - " + i + " [");
for (int index : mapping.map.keySet()) {
bw.append(mapping.map.get(index) + ": " + index + " ");
}
bw.append("]");
bw.newLine();
}
bw.flush();
bw.close();
}
/**
* Gets the mapping for the given script id.
* @param scriptId The script id.
* @return The mapping.
*/
public static CS2Mapping forId(int scriptId) {
CS2Mapping mapping = maps.get(scriptId);
if (mapping != null) {
return mapping;
}
mapping = new CS2Mapping(scriptId);
byte[] bs = Cache.getIndexes()[17].getFileData(scriptId >>> 8, scriptId & 0xFF);
if (bs != null) {
mapping.load(ByteBuffer.wrap(bs));
} else {
return null;
}
maps.put(scriptId, mapping);
return mapping;
}
/**
* Loads the mapping data.
* @param buffer The buffer to read the data from.
*/
private void load(ByteBuffer buffer) {
int opcode;
while ((opcode = buffer.get() & 0xFF) != 0) {
switch (opcode) {
case 1:
unknown = buffer.get() & 0xFF;
break;
case 2:
unknown1 = buffer.get() & 0xFF;
break;
case 3:
defaultString = ByteBufferUtils.getString(buffer);
break;
case 4:
defaultInt = buffer.getInt();
break;
case 5:
case 6:
int size = buffer.getShort() & 0xFFFF;
String string = null;
int val = 0;
map = new HashMap<>(size);
array = new Object[size];
for (int i = 0; i < size; i++) {
int key = buffer.getInt();
if (opcode == 5) {
string = ByteBufferUtils.getString(buffer);
array[i] = string;
map.put(key, string);
} else {
val = buffer.getInt();
array[i] = val;
map.put(key, val);
}
}
break;
}
}
}
/**
* Gets the array of objects.
* @return the objects.
*/
public Object[] getArray() {
return array;
}
/**
* Gets the scriptId.
* @return The scriptId.
*/
public int getScriptId() {
return scriptId;
}
/**
* Gets the unknown.
* @return The unknown.
*/
public int getUnknown() {
return unknown;
}
/**
* Sets the unknown.
* @param unknown The unknown to set.
*/
public void setUnknown(int unknown) {
this.unknown = unknown;
}
/**
* Gets the unknown1.
* @return The unknown1.
*/
public int getUnknown1() {
return unknown1;
}
/**
* Sets the unknown1.
* @param unknown1 The unknown1 to set.
*/
public void setUnknown1(int unknown1) {
this.unknown1 = unknown1;
}
/**
* Gets the defaultString.
* @return The defaultString.
*/
public String getDefaultString() {
return defaultString;
}
/**
* Sets the defaultString.
* @param defaultString The defaultString to set.
*/
public void setDefaultString(String defaultString) {
this.defaultString = defaultString;
}
/**
* Gets the defaultInt.
* @return The defaultInt.
*/
public int getDefaultInt() {
return defaultInt;
}
/**
* Sets the defaultInt.
* @param defaultInt The defaultInt to set.
*/
public void setDefaultInt(int defaultInt) {
this.defaultInt = defaultInt;
}
/**
* Gets the map.
* @return The map.
*/
public HashMap<Integer, Object> getMap() {
return map;
}
/**
* Sets the map.
* @param map The map to set.
*/
public void setMap(HashMap<Integer, Object> map) {
this.map = map;
}
}
@@ -0,0 +1,208 @@
package core.cache.def.impl;
import java.nio.ByteBuffer;
import java.util.Arrays;
import core.ServerConstants;
import core.cache.Cache;
/**
* The definitions for player clothing/look.
* @author Emperor
*/
public final class ClothDefinition {
/**
* The equipment slot.
*/
private int equipmentSlot;
/**
* The model ids.
*/
private int[] modelIds;
/**
* Unknown boolean.
*/
private boolean unknownBool;
/**
* Original colors.
*/
private int[] originalColors;
/**
* The colors to change to.
*/
private int[] modifiedColors;
/**
* Original texture colors.
*/
private int[] originalTextureColors;
/**
* Texture colors to change to.
*/
private int[] modifiedTextureColors;
/**
* Other model ids(?)
*/
private int[] models = { -1, -1, -1, -1, -1 };
/**
* Gets the definitions for the given cloth id.
* @param clothId The clothing id.
* @return The definition.
*/
public static ClothDefinition forId(int clothId) {
ClothDefinition def = new ClothDefinition();
byte[] bs = Cache.getIndexes()[2].getFileData(3, clothId);
if (bs != null) {
def.load(ByteBuffer.wrap(bs));
}
return def;
}
/**
* The main method.
* @param args The arguments cast on runtime.
*/
public static void main(String... args) {
try {
Cache.init(ServerConstants.CACHE_PATH);
} catch (Throwable e) {
e.printStackTrace();
}
int length = Cache.getIndexes()[2].getFilesSize(3);
System.out.println("Definition size: " + length + ".");
for (int i = 0; i < length; i++) {
ClothDefinition def = forId(i);
if (def.unknownBool)
System.out.println("Clothing " + i + ": " + def.equipmentSlot + ", " + def.unknownBool + ", " + Arrays.toString(def.modelIds) + ", " + Arrays.toString(def.models));
}
}
/**
* Loads the definitions.
* @param buffer The buffer.
*/
public void load(ByteBuffer buffer) {
int opcode;
while ((opcode = buffer.get() & 0xFF) != 0) {
parse(opcode, buffer);
}
}
/**
* Parses an opcode.
* @param opcode The opcode.
* @param buffer The buffer to read the data from.
*/
private void parse(int opcode, ByteBuffer buffer) {
switch (opcode) {
case 1:
equipmentSlot = buffer.get() & 0xFF;
break;
case 2:
int length = buffer.get() & 0xFF;
modelIds = new int[length];
for (int i = 0; i < length; i++) {
modelIds[i] = buffer.getShort() & 0xFFFF;
}
break;
case 3:
unknownBool = true;
break;
case 40:
length = buffer.get() & 0xFF;
originalColors = new int[length];
modifiedColors = new int[length];
for (int i = 0; i < length; i++) {
originalColors[i] = buffer.getShort();
modifiedColors[i] = buffer.getShort();
}
break;
case 41:
length = buffer.get() & 0xFF;
originalTextureColors = new int[length];
modifiedTextureColors = new int[length];
for (int i = 0; i < length; i++) {
originalTextureColors[i] = buffer.getShort();
modifiedTextureColors[i] = buffer.getShort();
}
break;
default:
if (opcode >= 60 && opcode < 70) {
models[opcode - 60] = buffer.getShort() & 0xFFFF;
}
break;
}
}
/**
* Gets the unknown.
* @return The unknown.
*/
public int getUnknown() {
return equipmentSlot;
}
/**
* Gets the modelIds.
* @return The modelIds.
*/
public int[] getModelIds() {
return modelIds;
}
/**
* Gets the unknownBool.
* @return The unknownBool.
*/
public boolean isUnknownBool() {
return unknownBool;
}
/**
* Gets the originalColors.
* @return The originalColors.
*/
public int[] getOriginalColors() {
return originalColors;
}
/**
* Gets the modifiedColors.
* @return The modifiedColors.
*/
public int[] getModifiedColors() {
return modifiedColors;
}
/**
* Gets the originalTextureColors.
* @return The originalTextureColors.
*/
public int[] getOriginalTextureColors() {
return originalTextureColors;
}
/**
* Gets the modifiedTextureColors.
* @return The modifiedTextureColors.
*/
public int[] getModifiedTextureColors() {
return modifiedTextureColors;
}
/**
* Gets the models.
* @return The models.
*/
public int[] getModels() {
return models;
}
}
@@ -0,0 +1,189 @@
package core.cache.def.impl;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import core.ServerConstants;
import core.cache.Cache;
/**
* Represents a Graphic's definition.
* @author Jagex
*/
public class GraphicDefinition {
public short[] aShortArray1435;
public short[] aShortArray1438;
public int anInt1440;
public boolean aBoolean1442;
public int defaultModel;
public int anInt1446;
public boolean aBoolean1448 = false;
public int anInt1449;
public int animationId;
public int anInt1451;
public int graphicsId;
public int anInt1454;
public short[] aShortArray1455;
public short[] aShortArray1456;
// added
public byte byteValue;
// added
public int intValue;
/**
* The definitions mapping.
*/
private static final Map<Integer, GraphicDefinition> graphicDefinitions = new HashMap<>();
/**
* Gets the graphic definition for the given graphic id.
* @param gfxId The graphic id.
* @return The definition.
*/
public static final GraphicDefinition forId(int gfxId) {
GraphicDefinition def = graphicDefinitions.get(gfxId);
if (def != null) {
return def;
}
byte[] data = Cache.getIndexes()[21].getFileData(gfxId >>> 735411752, gfxId & 0xff);
def = new GraphicDefinition();
def.graphicsId = gfxId;
if (data != null) {
def.readValueLoop(ByteBuffer.wrap(data));
}
graphicDefinitions.put(gfxId, def);
return def;
}
/**
* The main method, used for running a graphic definition search.
* @param s The arguments cast on runtime.
*/
public static final void main(String... s) {
try {
Cache.init(ServerConstants.CACHE_PATH);
} catch (Throwable e) {
e.printStackTrace();
}
// 5046 - 5050 are related anims & 2148
GraphicDefinition d = GraphicDefinition.forId(803);
System.out.println("Graphic " + d.graphicsId + " anim id = " + d.animationId + ", " + d.defaultModel + ".");
for (int i = 0; i < 5000; i++) {
GraphicDefinition def = GraphicDefinition.forId(i);
if (def == null) {
continue;
}
if ((def.animationId > 2000 && def.animationId < 2200) || (def.defaultModel >= 1300 && def.defaultModel < 1500)) {
System.out.println("Possible match [id=" + i + ", anim=" + def.animationId + "].");
}
}
}
/**
* Reads and handles all data from the input stream.
* @param buffer The input stream.
*/
private void readValueLoop(ByteBuffer buffer) {
for (;;) {
int opcode = buffer.get() & 0xFF;
if (opcode == 0) {
break;
}
readValues(buffer, opcode);
}
}
/**
* Reads the opcode values from the input stream.
* @param buffer The input stream.
* @param opcode The opcode to handle.
*/
public void readValues(ByteBuffer buffer, int opcode) {
if (opcode != 1) {
if (opcode == 2)
animationId = buffer.getShort();
else if (opcode == 4)
anInt1446 = buffer.getShort() & 0xFFFF;
else if (opcode != 5) {
if ((opcode ^ 0xffffffff) != -7) {
if (opcode == 7)
anInt1440 = buffer.get() & 0xFF;
else if ((opcode ^ 0xffffffff) == -9)
anInt1451 = buffer.get() & 0xFF;
else if (opcode != 9) {
if (opcode != 10) {
if (opcode == 11) { // added opcode
// aBoolean1442 = true;
byteValue = (byte) 1;
} else if (opcode == 12) { // added opcode
// aBoolean1442 = true;
byteValue = (byte) 4;
} else if (opcode == 13) { // added opcode
// aBoolean1442 = true;
byteValue = (byte) 5;
} else if (opcode == 14) { // added opcode
// aBoolean1442 = true;
// aByte2856 = 2;
byteValue = (byte) 2;
intValue = (buffer.get() & 0xFF) * 256;
} else if (opcode == 15) {
// aByte2856 = 3;
byteValue = (byte) 3;
intValue = buffer.getShort() & 0xFFFF;
} else if (opcode == 16) {
// aByte2856 = 3;
byteValue = (byte) 3;
intValue = buffer.getInt();
} else if (opcode != 40) {
if ((opcode ^ 0xffffffff) == -42) {
int i = buffer.get() & 0xFF;
aShortArray1455 = new short[i];
aShortArray1435 = new short[i];
for (int i_0_ = 0; i > i_0_; i_0_++) {
aShortArray1455[i_0_] = (short) (buffer.getShort() & 0xFFFF);
aShortArray1435[i_0_] = (short) (buffer.getShort() & 0xFFFF);
}
}
} else {
int i = buffer.get() & 0xFF;
aShortArray1438 = new short[i];
aShortArray1456 = new short[i];
for (int i_1_ = 0; ((i ^ 0xffffffff) < (i_1_ ^ 0xffffffff)); i_1_++) {
aShortArray1438[i_1_] = (short) (buffer.getShort() & 0xFFFF);
aShortArray1456[i_1_] = (short) (buffer.getShort() & 0xFFFF);
}
}
} else
aBoolean1448 = true;
} else {
// aBoolean1442 = true;
byteValue = (byte) 3;
intValue = 8224;
}
} else
anInt1454 = buffer.getShort() & 0xFFFF;
} else
anInt1449 = buffer.getShort() & 0xFFFF;
} else
defaultModel = buffer.getShort();
}
/**
* Constructs a new {@code GraphicDefinition} {@code Object}.
*/
public GraphicDefinition() {
byteValue = 0;
intValue = -1;
anInt1446 = 128;
aBoolean1442 = false;
anInt1449 = 128;
anInt1451 = 0;
animationId = -1;
anInt1454 = 0;
anInt1440 = 0;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,329 @@
package core.cache.def.impl;
import core.cache.Cache;
import core.game.system.SystemLogger;
import core.game.world.GameWorld;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
/**
* Holds definitions for render animations.
* @author Jagex
* @author Emperor
*
*/
public class RenderAnimationDefinition {
public int turn180Animation;
public int anInt951 = -1;
public int anInt952;
public int turnCWAnimation = -1;
public int anInt954;
public int anInt955;
public int anInt956;
public int anInt957;
public int anInt958;
public int[] anIntArray959 = null;
public int anInt960;
public int anInt961 = 0;
public int anInt962;
public int walkAnimationId;
public int anInt964;
public int anInt965;
public int anInt966;
public int[] standAnimationIds;
public int anInt969;
public int[] anIntArray971;
public int standAnimationId;
public int anInt973;
public int anInt974;
public int anInt975;
public int runAnimationId;
public int anInt977;
public boolean aBoolean978;
public int[][] anIntArrayArray979;
public int anInt980;
public int turnCCWAnimation;
public int anInt983;
public int anInt985;
public int anInt986;
public int anInt987;
public int anInt988;
public int anInt989;
public int anInt990;
public int anInt992;
public int anInt993;
public int anInt994;
/**
* Gets the render animation definitions for the given id.
* @param animId The render animation id.
* @return The render animation definitions.
*/
public static RenderAnimationDefinition forId(int animId) {
RenderAnimationDefinition defs = new RenderAnimationDefinition();
if (animId == -1) {
return null;
}
byte[] data = Cache.getIndexes()[2].getFileData(32, animId);
defs = new RenderAnimationDefinition();
if (data != null) {
defs.parse(ByteBuffer.wrap(data));
} else {
SystemLogger.logErr("No definitions found for render animation " + animId + ", size=" + Cache.getIndexes()[2].getFilesSize(32) + "!");
}
return defs;
}
private void parse(ByteBuffer buffer) {
for (;;) {
int opcode = buffer.get() & 0xFF;
if (opcode == 0) {
break;
}
parseOpcode(buffer, opcode);
}
}
private void parseOpcode(ByteBuffer buffer, int opcode) {
if (opcode == 54) {
@SuppressWarnings("unused")
int anInt1260 = (buffer.get() & 0xFF) << 6;
@SuppressWarnings("unused")
int anInt1227 = (buffer.get() & 0xFF) << 6;
} else if (opcode == 55) {
int[] anIntArray1246 = new int[12];
int i_14_ = buffer.get() & 0xFF;
anIntArray1246[i_14_] = buffer.getShort() & 0xFFFF;
} else if (opcode == 56) {
int[][] anIntArrayArray1217 = new int[12][];
int i_12_ = buffer.get() & 0xFF;
anIntArrayArray1217[i_12_] = new int[3];
for (int i_13_ = 0; i_13_ < 3; i_13_++)
anIntArrayArray1217[i_12_][i_13_] = buffer.getShort();
} else if ((opcode ^ 0xffffffff) != -2) {
if ((opcode ^ 0xffffffff) != -3) {
if (opcode != 3) {
if ((opcode ^ 0xffffffff) != -5) {
if (opcode == 5)
anInt977 = buffer.getShort() & 0xFFFF;
else if ((opcode ^ 0xffffffff) != -7) {
if (opcode == 7)
anInt960 = buffer.getShort() & 0xFFFF;
else if ((opcode ^ 0xffffffff) == -9)
anInt985 = buffer.getShort() & 0xFFFF;
else if (opcode == 9)
anInt957 = buffer.getShort() & 0xFFFF;
else if (opcode == 26) {
anInt973 = (short) (4 * buffer
.get() & 0xFF);
anInt975 = (short) (buffer.get() & 0xFF * 4);
} else if ((opcode ^ 0xffffffff) == -28) {
if (anIntArrayArray979 == null)
anIntArrayArray979 = new int[12][];
int i = buffer.get() & 0xFF;
anIntArrayArray979[i] = new int[6];
for (int i_1_ = 0; (i_1_ ^ 0xffffffff) > -7; i_1_++)
anIntArrayArray979[i][i_1_] = buffer
.getShort();
} else if ((opcode ^ 0xffffffff) == -29) {
anIntArray971 = new int[12];
for (int i = 0; i < 12; i++) {
anIntArray971[i] = buffer
.get() & 0xFF;
if (anIntArray971[i] == 255)
anIntArray971[i] = -1;
}
} else if (opcode != 29) {
if (opcode != 30) {
if ((opcode ^ 0xffffffff) != -32) {
if (opcode != 32) {
if ((opcode ^ 0xffffffff) != -34) {
if (opcode != 34) {
if (opcode != 35) {
if ((opcode ^ 0xffffffff) != -37) {
if ((opcode ^ 0xffffffff) != -38) {
if (opcode != 38) {
if ((opcode ^ 0xffffffff) != -40) {
if ((opcode ^ 0xffffffff) != -41) {
if ((opcode ^ 0xffffffff) == -42)
turnCWAnimation = buffer
.getShort() & 0xFFFF;
else if (opcode != 42) {
if ((opcode ^ 0xffffffff) == -44)
buffer.getShort();
else if ((opcode ^ 0xffffffff) != -45) {
if ((opcode ^ 0xffffffff) == -46)
anInt964 = buffer
.getShort() & 0xFFFF;
else if ((opcode ^ 0xffffffff) != -47) {
if (opcode == 47)
anInt966 = buffer
.getShort() & 0xFFFF;
else if (opcode == 48)
anInt989 = buffer
.getShort() & 0xFFFF;
else if (opcode != 49) {
if ((opcode ^ 0xffffffff) != -51) {
if (opcode != 51) {
if (opcode == 52) {
int i = buffer
.get() & 0xFF;
anIntArray959 = new int[i];
standAnimationIds = new int[i];
for (int i_2_ = 0; i_2_ < i; i_2_++) {
standAnimationIds[i_2_] = buffer
.getShort() & 0xFFFF;
int i_3_ = buffer
.get() & 0xFF;
anIntArray959[i_2_] = i_3_;
anInt994 += i_3_;
}
} else if (opcode == 53)
aBoolean978 = false;
} else
anInt962 = buffer
.getShort() & 0xFFFF;
} else
anInt990 = buffer
.getShort() & 0xFFFF;
} else
anInt952 = buffer
.getShort() & 0xFFFF;
} else
anInt983 = buffer
.getShort() & 0xFFFF;
} else
anInt955 = buffer
.getShort() & 0xFFFF;
} else
turnCCWAnimation = buffer
.getShort() & 0xFFFF;
} else
turn180Animation = buffer
.getShort() & 0xFFFF;
} else
anInt954 = buffer
.getShort() & 0xFFFF;
} else
anInt958 = (buffer
.getShort() & 0xFFFF);
} else
anInt951 = (buffer
.get() & 0xFF);
} else
anInt965 = (buffer
.getShort());
} else
anInt969 = (buffer
.getShort() & 0xFFFF);
} else
anInt993 = buffer
.get() & 0xFF;
} else
anInt956 = (buffer.getShort());
} else
anInt961 = buffer
.getShort() & 0xFFFF;
} else
anInt988 = buffer.get() & 0xFF;
} else
anInt980 = buffer.getShort() & 0xFFFF;
} else
anInt992 = buffer.get() & 0xFF;
} else
runAnimationId = buffer.getShort() & 0xFFFF;
} else
anInt986 = buffer.getShort() & 0xFFFF;
} else
anInt987 = buffer.getShort() & 0xFFFF;
} else
anInt974 = buffer.getShort() & 0xFFFF;
} else {
standAnimationId = buffer.getShort() & 0xFFFF;
walkAnimationId = buffer.getShort() & 0xFFFF;
if ((standAnimationId ^ 0xffffffff) == -65536)
standAnimationId = -1;
if ((walkAnimationId ^ 0xffffffff) == -65536)
walkAnimationId = -1;
}
}
public RenderAnimationDefinition() {
anInt957 = -1;
anInt954 = -1;
anInt960 = -1;
anInt958 = -1;
anInt965 = 0;
anInt973 = 0;
turn180Animation = -1;
anInt956 = 0;
standAnimationId = -1;
standAnimationIds = null;
anInt952 = -1;
anInt983 = -1;
anInt985 = -1;
anInt962 = -1;
anInt966 = -1;
anInt977 = -1;
anInt975 = 0;
runAnimationId = -1;
anInt988 = 0;
turnCCWAnimation = -1;
anInt987 = -1;
anInt980 = 0;
anInt964 = -1;
walkAnimationId = -1;
anInt986 = -1;
aBoolean978 = true;
anInt992 = 0;
anInt955 = -1;
anInt989 = -1;
anInt974 = -1;
anInt969 = 0;
anInt994 = 0;
anInt990 = -1;
anInt993 = 0;
}
public static void main(String...args) throws Throwable {
GameWorld.prompt(false);
RenderAnimationDefinition def = RenderAnimationDefinition.forId(1426);
System.out.println("size: " + def.getClass().getDeclaredFields().length);
for (Field f : def.getClass().getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers())) {
if (f.getType().isArray()) {
Object object = f.get(def);
if (object != null) {
int length = Array.getLength(object);
System.out.print(f.getName() + ", [");
for (int i = 0; i < length; i++) {
System.out.print(Array.get(object, i) + (i < (length - 1) ? ", " : "]"));
}
continue;
}
}
System.out.println(f.getName() + ", " + f.get(def));
}
}
for (Field f : def.getClass().getSuperclass().getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers())) {
if (f.getType().isArray()) {
Object object = f.get(def);
if (object != null) {
int length = Array.getLength(object);
System.out.print(f.getName() + ", [");
for (int i = 0; i < length; i++) {
System.out.print(Array.get(object, i) + (i < (length - 1) ? ", " : "]"));
}
continue;
}
}
System.out.println(f.getName() + ", " + f.get(def));
}
}
}
}
@@ -0,0 +1,176 @@
package core.cache.def.impl;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import core.cache.Cache;
import core.game.Varbit;
import core.game.node.entity.player.Player;
import core.game.system.SystemLogger;
import core.game.world.GameWorld;
/**
* Handles config definition reading.
* @author Emperor
*/
public final class VarbitDefinition {
/**
* The config definitions mapping.
*/
private static final Map<Integer, VarbitDefinition> MAPPING = new HashMap<>();
/**
* The bit size flags.
*/
private static final int[] BITS = new int[32];
/**
* The file id.
*/
private final int id;
/**
* The config id.
*/
private int configId;
/**
* The bit shift amount.
*/
private int bitShift;
/**
* The bit amount.
*/
private int bitSize;
/**
* Constructs a new {@code ConfigFileDefinition} {@code Object}.
* @param id The file id.
*/
public VarbitDefinition(int id) {
this.id = id;
}
/**
* Initializes the bit flags.
*/
static {
int flag = 2;
for (int i = 0; i < 32; i++) {
BITS[i] = flag - 1;
flag += flag;
}
}
/**
* Gets the config file definitions for the given file id.
* @param id The file id.
* @return The definition.
*/
public static VarbitDefinition forObjectID(int id) {
return forId(id,10);
}
public static VarbitDefinition forNPCID(int id){
return forId(id,10);
}
public static VarbitDefinition forItemID(int id){
return forId(id,30);
}
public static VarbitDefinition forId(int id, int shiftAmount){
/*VarbitDefinition def = MAPPING.get(id);
if (def != null) {
return def;
}*/
VarbitDefinition def;
def = new VarbitDefinition(id);
byte[] bs = Cache.getIndexes()[22].getFileData(id >>> 10, id & 0x3ff);
if (bs != null) {
ByteBuffer buffer = ByteBuffer.wrap(bs);
int opcode = 0;
while ((opcode = buffer.get() & 0xFF) != 0) {
if (opcode == 1) {
def.configId = buffer.getShort() & 0xFFFF;
def.bitShift = buffer.get() & 0xFF;
def.bitSize = buffer.get() & 0xFF;
}
}
}
MAPPING.put(id, def);
return def;
}
public static void main(String... args) throws Throwable {
GameWorld.prompt(false);
for (int i = 0; i < 15000; i++) {
VarbitDefinition def = forObjectID(i);
if (def != null && def.configId == 33) {
System.out.println("Config file [id=" + i + ", shift=" + def.bitShift + "]!");
}
}
}
/**
* Gets the current config value for this file.
* @param player The player.
* @return The config value.
*/
public int getValue(Player player) {
int size = BITS[bitSize - bitShift];
int bitValue = player.varpManager.get(getConfigId()).getBitRangeValue(getBitShift(), getBitShift() + (bitSize - bitShift) + 1);
if(bitValue != 0){
return bitValue >>> bitShift;
}
return size & (player.getConfigManager().get(configId) >>> bitShift);
}
/**
* Gets the mapping.
* @return The mapping.
*/
public static Map<Integer, VarbitDefinition> getMapping() {
return MAPPING;
}
/**
* Gets the id.
* @return The id.
*/
public int getId() {
return id;
}
/**
* Gets the configId.
* @return The configId.
*/
public int getConfigId() {
return configId;
}
/**
* Gets the bitShift.
* @return The bitShift.
*/
public int getBitShift() {
return bitShift;
}
/**
* Gets the bitSize.
* @return The bitSize.
*/
public int getBitSize() {
return bitSize;
}
@Override
public String toString() {
return "ConfigFileDefinition [id=" + id + ", configId=" + configId + ", bitShift=" + bitShift + ", bitSize=" + bitSize + "]";
}
}
+365
View File
@@ -0,0 +1,365 @@
private void readValues(int i, InputStream stream, int opcode) {
if (opcode != 1 && opcode != 5) {
if (opcode != 2) {
if (opcode != 14) {
if (opcode != 15) {
if (opcode == 17) {
projectileCliped = false;
clipType = 0;
} else if (opcode != 18) {
if (opcode == 19)
secondInt = stream.readUnsignedByte();
else if (opcode == 21)
aByte3912 = (byte) 1;
else if (opcode != 22) {
if (opcode != 23) {
if (opcode != 24) {
if (opcode == 27)
clipType = 1;
else if (opcode == 28)
anInt3892 = (stream
.readUnsignedByte() << 2);
else if (opcode != 29) {
if (opcode != 39) {
if (opcode < 30 || opcode >= 35) {
if (opcode == 40) {
int i_53_ = (stream
.readUnsignedByte());
originalColors = new short[i_53_];
modifiedColors = new short[i_53_];
for (int i_54_ = 0; i_53_ > i_54_; i_54_++) {
originalColors[i_54_] = (short) (stream
.readUnsignedShort());
modifiedColors[i_54_] = (short) (stream
.readUnsignedShort());
}
} else if (opcode != 41) {
if (opcode != 42) {
if (opcode != 62) {
if (opcode != 64) {
if (opcode == 65)
anInt3902 = stream
.readUnsignedShort();
else if (opcode != 66) {
if (opcode != 67) {
if (opcode == 69)
anInt3925 = stream
.readUnsignedByte();
else if (opcode != 70) {
if (opcode == 71)
anInt3889 = stream
.readShort() << 2;
else if (opcode != 72) {
if (opcode == 73)
secondBool = true;
else if (opcode == 74)
notCliped = true;
else if (opcode != 75) {
if (opcode != 77
&& opcode != 92) {
if (opcode == 78) {
anInt3860 = stream
.readUnsignedShort();
anInt3904 = stream
.readUnsignedByte();
} else if (opcode != 79) {
if (opcode == 81) {
aByte3912 = (byte) 2;
anInt3882 = 256 * stream
.readUnsignedByte();
} else if (opcode != 82) {
if (opcode == 88)
aBoolean3853 = false;
else if (opcode != 89) {
if (opcode == 90)
aBoolean3870 = true;
else if (opcode != 91) {
if (opcode != 93) {
if (opcode == 94)
aByte3912 = (byte) 4;
else if (opcode != 95) {
if (opcode != 96) {
if (opcode == 97)
aBoolean3866 = true;
else if (opcode == 98)
aBoolean3923 = true;
else if (opcode == 99) {
anInt3857 = stream
.readUnsignedByte();
anInt3835 = stream
.readUnsignedShort();
} else if (opcode == 100) {
anInt3844 = stream
.readUnsignedByte();
anInt3913 = stream
.readUnsignedShort();
} else if (opcode != 101) {
if (opcode == 102)
anInt3838 = stream
.readUnsignedShort();
else if (opcode == 103)
thirdInt = 0;
else if (opcode != 104) {
if (opcode == 105)
aBoolean3906 = true;
else if (opcode == 106) {
int i_55_ = stream
.readUnsignedByte();
anIntArray3869 = new int[i_55_];
anIntArray3833 = new int[i_55_];
for (int i_56_ = 0; i_56_ < i_55_; i_56_++) {
anIntArray3833[i_56_] = stream
.readUnsignedShort();
int i_57_ = stream
.readUnsignedByte();
anIntArray3869[i_56_] = i_57_;
anInt3881 += i_57_;
}
} else if (opcode == 107)
anInt3851 = stream
.readUnsignedShort();
else if (opcode >= 150
&& opcode < 155) {
options[opcode
+ -150] = stream
.readString();
/*if (!loader.showOptions)
options[opcode + -150] = null;*/
} else if (opcode != 160) {
if (opcode == 162) {
aByte3912 = (byte) 3;
anInt3882 = stream
.readInt();
} else if (opcode == 163) {
aByte3847 = (byte) stream
.readByte();
aByte3849 = (byte) stream
.readByte();
aByte3837 = (byte) stream
.readByte();
aByte3914 = (byte) stream
.readByte();
} else if (opcode != 164) {
if (opcode != 165) {
if (opcode != 166) {
if (opcode == 167)
anInt3921 = stream
.readUnsignedShort();
else if (opcode != 168) {
if (opcode == 169) {
aBoolean3845 = true;
//added opcode
}else if (opcode == 170) {
int anInt3383 = stream.readUnsignedSmart();
//added opcode
}else if (opcode == 171) {
int anInt3362 = stream.readUnsignedSmart();
//added opcode
}else if (opcode == 173) {
int anInt3302 = stream.readUnsignedShort();
int anInt3336 = stream.readUnsignedShort();
//added opcode
}else if (opcode == 177) {
boolean ub = true;
//added opcode
}else if (opcode == 178) {
int db = stream.readUnsignedByte();
} else if (opcode == 249) {
int i_58_ = stream
.readUnsignedByte();
if (aClass194_3922 == null) {
/*int i_59_ = Class307
.method3331(
(byte) -117,
i_58_);
aClass194_3922 = new HashTable(
i_59_);*/
}
for (int i_60_ = 0; i_60_ < i_58_; i_60_++) {
boolean bool = stream
.readUnsignedByte() == 1;
int i_61_ = stream.read24BitInt();
Object class279;
if (!bool)
/*class279 = new IntegerNode(*/
stream
.readInt();//);
else
/*class279 = new Class279_Sub4(*/
stream
.readString();//);
/*aClass194_3922
.method1598(
(long) i_61_,
-125,
class279);*/
}
}
} else
aBoolean3894 = true;
} else
anInt3877 = stream
.readShort();
} else
anInt3875 = stream
.readShort();
} else
anInt3834 = stream
.readShort();
} else {
int i_62_ = stream
.readUnsignedByte();
anIntArray3908 = new int[i_62_];
for (int i_63_ = 0; i_62_ > i_63_; i_63_++)
anIntArray3908[i_63_] = stream
.readUnsignedShort();
}
} else
anInt3865 = stream
.readUnsignedByte();
} else
anInt3850 = stream
.readUnsignedByte();
} else
aBoolean3924 = true;
} else {
aByte3912 = (byte) 5;
anInt3882 = stream
.readShort();
}
} else {
aByte3912 = (byte) 3;
anInt3882 = stream
.readUnsignedShort();
}
} else
aBoolean3873 = true;
} else
aBoolean3895 = false;
} else
aBoolean3891 = true;
} else {
anInt3900 = stream
.readUnsignedShort();
anInt3905 = stream
.readUnsignedShort();
anInt3904 = stream
.readUnsignedByte();
int i_64_ = stream
.readUnsignedByte();
anIntArray3859 = new int[i_64_];
for (int i_65_ = 0; i_65_ < i_64_; i_65_++)
anIntArray3859[i_65_] = stream
.readUnsignedShort();
}
} else {
configFileId = stream
.readUnsignedShort();
if (configFileId == 65535)
configFileId = -1;
configId = stream
.readUnsignedShort();
if (configId == 65535)
configId = -1;
int i_66_ = -1;
if (opcode == 92) {
i_66_ = stream
.readUnsignedShort();
if (i_66_ == 65535)
i_66_ = -1;
}
int i_67_ = stream
.readUnsignedByte();
childrenIds = new int[i_67_
- -2];
for (int i_68_ = 0; i_67_ >= i_68_; i_68_++) {
childrenIds[i_68_] = stream
.readUnsignedShort();
if (childrenIds[i_68_] == 65535)
childrenIds[i_68_] = -1;
}
childrenIds[i_67_ + 1] = i_66_;
}
} else
anInt3855 = stream
.readUnsignedByte();
} else
anInt3915 = stream
.readShort() << 2;
} else
anInt3883 = stream
.readShort() << 2;
} else
anInt3917 = stream
.readUnsignedShort();
} else
anInt3841 = stream
.readUnsignedShort();
} else
aBoolean3872 = false;
} else
aBoolean3839 = true;
} else {
int i_69_ = (stream
.readUnsignedByte());
aByteArray3858 = (new byte[i_69_]);
for (int i_70_ = 0; i_70_ < i_69_; i_70_++)
aByteArray3858[i_70_] = (byte) (stream
.readByte());
}
} else {
int i_71_ = (stream
.readUnsignedByte());
aShortArray3920 = new short[i_71_];
aShortArray3919 = new short[i_71_];
for (int i_72_ = 0; i_71_ > i_72_; i_72_++) {
aShortArray3920[i_72_] = (short) (stream
.readUnsignedShort());
aShortArray3919[i_72_] = (short) (stream
.readUnsignedShort());
}
}
} else
options[-30
+ opcode] = (stream
.readString());
} else
anInt3840 = (stream.readByte() * 5);
} else
anInt3878 = stream.readByte();
} else {
anInt3876 = stream.readUnsignedShort();
if (anInt3876 == 65535)
anInt3876 = -1;
}
} else
thirdInt = 1;
} else
aBoolean3867 = true;
} else
projectileCliped = false;
} else
sizeY = stream.readUnsignedByte();
} else
sizeX = stream.readUnsignedByte();
} else
name = stream.readString();
} else {
boolean aBoolean1162 = false;
if (opcode == 5 && aBoolean1162)
method3297(stream);
int i_73_ = stream.readUnsignedByte();
anIntArrayArray3916 = new int[i_73_][];
aByteArray3899 = new byte[i_73_];
for (int i_74_ = 0; i_74_ < i_73_; i_74_++) {
aByteArray3899[i_74_] = (byte) stream.readByte();
int i_75_ = stream.readUnsignedByte();
anIntArrayArray3916[i_74_] = new int[i_75_];
for (int i_76_ = 0; i_75_ > i_76_; i_76_++)
anIntArrayArray3916[i_74_][i_76_] = stream
.readUnsignedShort();
}
if (opcode == 5 && !aBoolean1162)
method3297(stream);
}
}
@@ -0,0 +1,47 @@
package core.cache.gzip;
import java.nio.ByteBuffer;
import java.util.zip.Inflater;
public class GZipDecompressor {
private static final Inflater inflaterInstance = new Inflater(true);
public static final void decompress(ByteBuffer buffer, byte data[]) {
synchronized (inflaterInstance) {
if (~buffer.get(buffer.position()) != -32 || buffer.get(buffer.position() + 1) != -117) {
data = null;
// throw new RuntimeException("Invalid GZIP header!");
}
try {
inflaterInstance.setInput(buffer.array(), buffer.position() + 10, -buffer.position() - 18 + buffer.limit());
inflaterInstance.inflate(data);
} catch (Exception e) {
// inflaterInstance.reset();
data = null;
// throw new RuntimeException("Invalid GZIP compressed data!");
}
inflaterInstance.reset();
}
}
public static final boolean decompress(byte[] compressed, byte data[], int offset, int length) {
synchronized (inflaterInstance) {
if (data[offset] != 31 || data[offset + 1] != -117)
return false;
// throw new RuntimeException("Invalid GZIP header!");
try {
inflaterInstance.setInput(data, offset + 10, -offset - 18 + length);
inflaterInstance.inflate(compressed);
} catch (Exception e) {
inflaterInstance.reset();
e.printStackTrace();
return false;
// throw new RuntimeException("Invalid GZIP compressed data!");
}
inflaterInstance.reset();
return true;
}
}
}
@@ -0,0 +1,109 @@
package core.cache.misc;
/**
* A container.
* @author Dragonkk
*/
public class Container {
/**
* The version.
*/
private int version;
/**
* The CRC.
*/
private int crc;
/**
* The name hash.
*/
private int nameHash;
/**
* If updated.
*/
private boolean updated;
/**
* Construct a new container.
*/
public Container() {
nameHash = -1;
version = -1;
crc = -1;
}
/**
* Set the version.
* @param version
*/
public void setVersion(int version) {
this.version = version;
}
/**
* Update the version.
*/
public void updateVersion() {
version++;
updated = true;
}
/**
* Get the version.
* @return The version.
*/
public int getVersion() {
return version;
}
/**
* Get the next version.
* @return The next version.
*/
public int getNextVersion() {
return updated ? version : version + 1;
}
/**
* Set the CRC.
* @param crc The cRC.
*/
public void setCrc(int crc) {
this.crc = crc;
}
/**
* Get the CRC.
* @return The CRC.
*/
public int getCrc() {
return crc;
}
/**
* Set the name hash.
* @param nameHash The name hash.
*/
public void setNameHash(int nameHash) {
this.nameHash = nameHash;
}
/**
* Get the name hash.
* @return The name hash.
*/
public int getNameHash() {
return nameHash;
}
/**
* If is updated.
* @return If is updated.
*/
public boolean isUpdated() {
return updated;
}
}
@@ -0,0 +1,228 @@
package core.cache.misc;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.CRC32;
import core.cache.bzip2.BZip2Decompressor;
import core.cache.gzip.GZipDecompressor;
/**
* A class holding the containers information.
* @author Dragonkk
*/
public final class ContainersInformation {
/**
* The information container.
*/
private Container informationContainer;
/**
* The protocol.
*/
private int protocol;
/**
* The revision.
*/
private int revision;
/**
* The container indexes.
*/
private int[] containersIndexes;
/**
* The containers.
*/
private FilesContainer[] containers;
/**
* If files have to be named.
*/
private boolean filesNamed;
/**
* If it has to be whirpool.
*/
private boolean whirpool;
/**
* The data.
*/
private final byte[] data;
/**
* Construct a new containers information.
* @param informationContainerPackedData The information container data
* packed.
*/
public ContainersInformation(byte[] informationContainerPackedData) {
this.data = Arrays.copyOf(informationContainerPackedData, informationContainerPackedData.length);
informationContainer = new Container();
informationContainer.setVersion((informationContainerPackedData[informationContainerPackedData.length - 2] << 8 & 0xff00) + (informationContainerPackedData[-1 + informationContainerPackedData.length] & 0xff));
CRC32 crc32 = new CRC32();
crc32.update(informationContainerPackedData);
informationContainer.setCrc((int) crc32.getValue());
decodeContainersInformation(unpackCacheContainer(informationContainerPackedData));
}
/**
* Unpacks a container.
* @param packedData The packed container data.
* @return The unpacked data.
*/
public static final byte[] unpackCacheContainer(byte[] packedData) {
ByteBuffer buffer = ByteBuffer.wrap(packedData);
int compression = buffer.get() & 0xFF;
int containerSize = buffer.getInt();
if (containerSize < 0 || containerSize > 5000000) {
return null;
// throw new RuntimeException();
}
if (compression == 0) {
byte unpacked[] = new byte[containerSize];
buffer.get(unpacked, 0, containerSize);
return unpacked;
}
int decompressedSize = buffer.getInt();
if (decompressedSize < 0 || decompressedSize > 20000000) {
return null;
// throw new RuntimeException();
}
byte decompressedData[] = new byte[decompressedSize];
if (compression == 1) {
BZip2Decompressor.decompress(decompressedData, packedData, containerSize, 9);
} else {
GZipDecompressor.decompress(buffer, decompressedData);
}
return decompressedData;
}
/**
* Get the container indexes.
* @return The container indexes.
*/
public int[] getContainersIndexes() {
return containersIndexes;
}
/**
* Get the containers.
* @return The containers.
*/
public FilesContainer[] getContainers() {
return containers;
}
/**
* Get the information container.
* @return The information container.
*/
public Container getInformationContainer() {
return informationContainer;
}
/**
* Get the revision.
* @return The revision.
*/
public int getRevision() {
return revision;
}
/**
* Decode the containers information.
* @param data The data.
*/
public void decodeContainersInformation(byte[] data) {
ByteBuffer buffer = ByteBuffer.wrap(data);
protocol = buffer.get() & 0xFF;
if (protocol != 5 && protocol != 6) {
throw new RuntimeException();
}
revision = protocol < 6 ? 0 : buffer.getInt();
int nameHash = buffer.get() & 0xFF;
filesNamed = (0x1 & nameHash) != 0;
whirpool = (0x2 & nameHash) != 0;
containersIndexes = new int[buffer.getShort() & 0xFFFF];
int lastIndex = -1;
for (int index = 0; index < containersIndexes.length; index++) {
containersIndexes[index] = (buffer.getShort() & 0xFFFF) + (index == 0 ? 0 : containersIndexes[index - 1]);
if (containersIndexes[index] > lastIndex) {
lastIndex = containersIndexes[index];
}
}
containers = new FilesContainer[lastIndex + 1];
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]] = new FilesContainer();
}
if (filesNamed) {
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setNameHash(buffer.getInt());
}
}
byte[][] filesHashes = null;
if (whirpool) {
filesHashes = new byte[containers.length][];
for (int index = 0; index < containersIndexes.length; index++) {
filesHashes[containersIndexes[index]] = new byte[64];
buffer.get(filesHashes[containersIndexes[index]], 0, 64);
}
}
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setCrc(buffer.getInt());
}
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setVersion(buffer.getInt());
}
for (int index = 0; index < containersIndexes.length; index++) {
containers[containersIndexes[index]].setFilesIndexes(new int[buffer.getShort() & 0xFFFF]);
}
for (int index = 0; index < containersIndexes.length; index++) {
int lastFileIndex = -1;
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFilesIndexes()[fileIndex] = (buffer.getShort() & 0xFFFF) + (fileIndex == 0 ? 0 : containers[containersIndexes[index]].getFilesIndexes()[fileIndex - 1]);
if (containers[containersIndexes[index]].getFilesIndexes()[fileIndex] > lastFileIndex) {
lastFileIndex = containers[containersIndexes[index]].getFilesIndexes()[fileIndex];
}
}
containers[containersIndexes[index]].setFiles(new Container[lastFileIndex + 1]);
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]] = new Container();
}
}
if (whirpool) {
for (int index = 0; index < containersIndexes.length; index++) {
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setVersion(filesHashes[containersIndexes[index]][containers[containersIndexes[index]].getFilesIndexes()[fileIndex]]);
}
}
}
if (filesNamed) {
for (int index = 0; index < containersIndexes.length; index++) {
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setNameHash(buffer.getInt());
}
}
}
}
/**
* If is whirpool.
* @return If is whirpool {@code true}.
*/
public boolean isWhirpool() {
return whirpool;
}
/**
* Gets the data.
* @return The data.
*/
public byte[] getData() {
return data;
}
}
@@ -0,0 +1,57 @@
package core.cache.misc;
/**
* A class holding the file containers.
* @author Dragonkk
*/
public final class FilesContainer extends Container {
/**
* The file indexes.
*/
private int[] filesIndexes;
/**
* The files.
*/
private Container[] files;
/**
* Construct a new files container.
*/
public FilesContainer() {
}
/**
* Set the files.
* @param containers The files.
*/
public void setFiles(Container[] containers) {
this.files = containers;
}
/**
* Get the files.
* @return The files.
*/
public Container[] getFiles() {
return files;
}
/**
* Set the file indexes.
* @param containersIndexes The file indexes.
*/
public void setFilesIndexes(int[] containersIndexes) {
this.filesIndexes = containersIndexes;
}
/**
* Get the file indexes.
* @return The file indexes.
*/
public int[] getFilesIndexes() {
return filesIndexes;
}
}
@@ -0,0 +1,39 @@
package core.cache.misc.buffer;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/**
* Handles the reading of data from a byte buffer.
* @author Emperor
*/
public final class BufferInputStream extends InputStream {
/**
* The buffer to write on.
*/
private final ByteBuffer buffer;
/**
* The buffer input stream.
* @param buffer The buffer.
*/
public BufferInputStream(ByteBuffer buffer) throws IOException {
this.buffer = buffer;
}
@Override
public int read() throws IOException {
return buffer.get();
}
/**
* Gets the buffer.
* @return The buffer.
*/
public ByteBuffer getBuffer() {
return buffer;
}
}
@@ -0,0 +1,57 @@
package core.cache.misc.buffer;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* Handles the writing of data on a byte buffer.
* @author Emperor
*/
public final class BufferOutputStream extends OutputStream {
/**
* The buffer to write on.
*/
private final ByteBuffer buffer;
/**
* Constructs a new {@code BufferOutputStream} {@code Object}.
* @param buffer The buffer to write on.
* @throws IOException When an I/O exception occurs.
* @throws SecurityException If a security manager exists and its
* checkPermission method denies enabling subclassing.
*/
public BufferOutputStream(ByteBuffer buffer) throws IOException, SecurityException {
super();
this.buffer = buffer;
}
@Override
public void write(int b) throws IOException {
buffer.put((byte) b);
}
@Override
public void flush() {
/*
* empty.
*/
}
@Override
public void close() {
/*
* empty.
*/
}
/**
* Gets the buffer.
* @return The buffer.
*/
public ByteBuffer getBuffer() {
return buffer;
}
}
@@ -0,0 +1,181 @@
package core.cache.misc.buffer;
import java.io.ObjectInputStream;
import java.nio.ByteBuffer;
/**
* Holds utility methods for reading/writing a byte buffer.
* @author Emperor
*/
public final class ByteBufferUtils {
/**
* Gets a string from the byte buffer.
* @param buffer The byte buffer.
* @return The string.
*/
public static String getString(ByteBuffer buffer) {
StringBuilder sb = new StringBuilder();
byte b;
while ((b = buffer.get()) != 0) {
sb.append((char) b);
}
return sb.toString();
}
/**
* Puts a string on the byte buffer.
* @param s The string to put.
* @param buffer The byte buffer.
*/
public static void putString(String s, ByteBuffer buffer) {
buffer.put(s.getBytes()).put((byte) 0);
}
/**
* Gets a string from the byte buffer.
* @param s The string.
* @param buffer The byte buffer.
* @return The string.
*/
public static ByteBuffer putGJ2String(String s, ByteBuffer buffer) {
byte[] packed = new byte[256];
int length = packGJString2(0, packed, s);
return buffer.put((byte) 0).put(packed, 0, length).put((byte) 0);
}
/**
* Decodes the XTEA encryption.
* @param keys The keys.
* @param start The start index.
* @param end The end index.
* @param buffer The byte buffer.
*/
public static void decodeXTEA(int[] keys, int start, int end, ByteBuffer buffer) {
int l = buffer.position();
buffer.position(start);
int length = (end - start) / 8;
for (int i = 0; i < length; i++) {
int firstInt = buffer.getInt();
int secondInt = buffer.getInt();
int sum = 0xc6ef3720;
int delta = 0x9e3779b9;
for (int j = 32; j-- > 0;) {
secondInt -= keys[(sum & 0x1c84) >>> 11] + sum ^ (firstInt >>> 5 ^ firstInt << 4) + firstInt;
sum -= delta;
firstInt -= (secondInt >>> 5 ^ secondInt << 4) + secondInt ^ keys[sum & 3] + sum;
}
buffer.position(buffer.position() - 8);
buffer.putInt(firstInt);
buffer.putInt(secondInt);
}
buffer.position(l);
}
/**
* Converts a String to an Integer?
* @param position The position.
* @param buffer The buffer used.
* @param string The String to convert.
* @return The Integer.
*/
public static int packGJString2(int position, byte[] buffer, String string) {
int length = string.length();
int offset = position;
for (int i = 0; length > i; i++) {
int character = string.charAt(i);
if (character > 127) {
if (character > 2047) {
buffer[offset++] = (byte) ((character | 919275) >> 12);
buffer[offset++] = (byte) (128 | ((character >> 6) & 63));
buffer[offset++] = (byte) (128 | (character & 63));
} else {
buffer[offset++] = (byte) ((character | 12309) >> 6);
buffer[offset++] = (byte) (128 | (character & 63));
}
} else
buffer[offset++] = (byte) character;
}
return offset - position;
}
/**
* Gets a tri-byte from the buffer.
* @param buffer The buffer.
* @return The value.
*/
public static int getTriByte(ByteBuffer buffer) {
return ((buffer.get() & 0xFF) << 16) + ((buffer.get() & 0xFF) << 8) + (buffer.get() & 0xFF);
}
/**
* Gets a smart from the buffer.
* @param buffer The buffer.
* @return The value.
*/
public static int getSmart(ByteBuffer buffer) {
int peek = buffer.get() & 0xFF;
if (peek <= Byte.MAX_VALUE) {
return peek;
}
return ((peek << 8) | (buffer.get() & 0xFF)) - 32768;
}
/**
* Gets a smart from the buffer.
* @param buffer The buffer.
* @return The value.
*/
public static int getBigSmart(ByteBuffer buffer) {
int value = 0;
int current = getSmart(buffer);
while (current == 32767) {
current = getSmart(buffer);
value += 32767;
}
value += current;
return value;
}
/* *//**
* Writes an object on the buffer.
* @param buffer The buffer to write on.
* @param o The object.
*/
/*
* public static void putObject(ByteBuffer buffer, Object o) { ByteBuffer b;
* try (ObjectOutputStream out = new ObjectOutputStream(new
* BufferOutputStream(b = ByteBuffer.allocate(99999)))) {
* out.writeObject(o); b.flip(); } catch (Throwable e) {
* e.printStackTrace(); b = (ByteBuffer) ByteBuffer.allocate(0).flip(); }
* buffer.putInt(b.remaining()); if (b.remaining() > 0) { buffer.put(b); } }
*/
/**
* Gets an object from the byte buffer.
* @param buffer The buffer.
* @return The object.
*/
public static Object getObject(ByteBuffer buffer) {
int length = buffer.getInt();
if (length > 0) {
byte[] bytes = new byte[length];
buffer.get(bytes);
try (ObjectInputStream str = new ObjectInputStream(new BufferInputStream(ByteBuffer.wrap(bytes)))) {
return (Object) str.readObject();
} catch (Throwable e) {
e.printStackTrace();
}
}
return null;
}
/**
* Constructs a new {@code ByteBufferUtils} {@code Object}.
*/
private ByteBufferUtils() {
/*
* empty.
*/
}
}
@@ -0,0 +1,5 @@
package core.game
class Varbit(var value: Int, val offset: Int){
}
@@ -0,0 +1,70 @@
package core.game
import core.game.node.entity.player.Player
import core.game.system.SystemLogger
/**
* A class that represents Varps and aids in modifying/calculating them
* @author Ceikry
*/
class Varp(val index: Int) {
val varbits = ArrayList<Varbit>()
var save = false
fun setVarbit(offset: Int, value: Int): Varp{
for(vb in varbits){
if (vb.offset == offset){
varbits.remove(vb)
break
}
}
varbits.add(Varbit(value,offset))
return this
}
fun getValue(): Int{
var config = 0
for(varbit in varbits){
config = config or (varbit.value shl varbit.offset)
}
return config
}
fun getVarbit(offset: Int): Varbit?{
for(varbit in varbits){
if(varbit.offset == offset) return varbit
}
return null
}
fun getVarbitValue(offset: Int): Int{
return getVarbit(offset)?.value ?: 0
}
fun send(player: Player){
player.packetDispatch.sendVarp(this)
}
fun clear(): Varp{
varbits.clear()
return this
}
fun clearBitRange(first : Int, last : Int){
for(varbit in varbits){
if(varbit.offset in first..last){
varbit.value = 0
}
}
}
fun getBitRangeValue(first: Int, last: Int): Int{
var product = 0
for(varbit in varbits){
if(varbit.offset in first..last){
product = product or (varbit.value shl varbit.offset)
}
}
return product
}
}
@@ -0,0 +1,91 @@
package core.game
import core.cache.def.impl.VarbitDefinition
import core.game.node.entity.player.Player
import org.json.simple.JSONArray
import org.json.simple.JSONObject
/**
* Manages the collection of a player's varps.
* Also handles saving and loading of saved varps.
* @author Ceikry
*/
class VarpManager(val player: Player) {
val varps = Array(3500) { Varp(it) }
fun get(index: Int): Varp{
return varps[index]
}
fun send(index: Int){
player.packetDispatch.sendVarp(get(index))
}
fun set(index: Int, value: Int){
get(index).varbits.clear()
get(index).varbits.add(Varbit(value,0))
get(index).send(player)
}
fun setVarbit(def: VarbitDefinition, value: Int){
get(def.configId).setVarbit(def.bitShift,value).send(player)
}
fun flagSave(index: Int){
get(index).save = true
}
fun unflagSave(index: Int){
get(index).save = false
}
fun sendAllVarps(){
for(varp in varps){
if(varp.getValue() != 0){
player.packetDispatch.sendVarp(varp)
}
}
}
fun getSavedVarps(): ArrayList<Varp>{
val list = ArrayList<Varp>()
for(varp in varps){
if(varp.save) list.add(varp)
}
return list
}
fun save(root: JSONObject){
val varps = JSONArray()
for(varp in getSavedVarps()){
val varpobj = JSONObject()
varpobj.put("index",varp.index.toString())
val bitArray = JSONArray()
for(varbit in varp.varbits){
val varbitobj = JSONObject()
varbitobj.put("offset",varbit.offset.toString())
varbitobj.put("value",varbit.value.toString())
bitArray.add(varbitobj)
}
varpobj.put("bitArray",bitArray)
varps.add(varpobj)
}
root.put("varps",varps)
}
fun parse(data: JSONArray){
for(varpobj in data){
val vobj = varpobj as JSONObject
val index = vobj["index"].toString().toInt()
val varp = get(index)
val bits = vobj["bitArray"] as JSONArray
for(vbit in bits){
val varbit = vbit as JSONObject
val offset = varbit["offset"].toString().toInt()
val value = varbit["value"].toString().toInt()
varp.setVarbit(offset,value)
varp.save = true
}
}
}
}
@@ -0,0 +1,5 @@
package core.game.camerautils
object CameraUtils {
}
@@ -0,0 +1,33 @@
package core.game.camerautils
import core.game.node.entity.player.Player
import core.game.system.SystemLogger
import core.net.packet.PacketRepository
import core.net.packet.context.CameraContext
import core.net.packet.out.CameraViewPacket
class PlayerCamera(val player: Player?) {
var ctx: CameraContext? = null
fun setPosition(x: Int, y: Int, height: Int){
player ?: return
ctx = CameraContext(player,CameraContext.CameraType.SET,x,y,height,0,0)
PacketRepository.send(CameraViewPacket::class.java,ctx)
}
fun rotateTo(x: Int, y: Int, height: Int, speed: Int){
player ?: return
ctx = CameraContext(player,CameraContext.CameraType.ROTATION,x,y,height,speed,1)
PacketRepository.send(CameraViewPacket::class.java,ctx)
}
fun rotateBy(diffX: Int, diffY: Int, diffHeight: Int, speed: Int){
player ?: return
ctx ?: return
ctx = CameraContext(player,CameraContext.CameraType.ROTATION, ctx!!.x + diffX, ctx!!.y + diffY, ctx!!.height + diffHeight,speed,1)
PacketRepository.send(CameraViewPacket::class.java,ctx)
}
fun panTo(x: Int, y: Int, height: Int, speed: Int){
player ?: return
ctx = CameraContext(player,CameraContext.CameraType.POSITION,x,y,height,speed,1)
PacketRepository.send(CameraViewPacket::class.java,ctx)
}
}
@@ -0,0 +1,104 @@
package core.game.component;
/**
* Used to generate component option settings.
* @author Mangis
*/
public final class AccessMaskBuilder {
/**
* Contains the value which should be sent in access mask packet.
*/
private int value;
/**
* Sets default option setting.
* @param allowed If the packet for the default option should be sent to the
* server.
*/
public void allowDefaultOption(boolean allowed) {
value &= ~(0x1);
if (allowed) {
value |= 0x1;
}
}
/**
* Sets right click option settings. If specified option is not allowed, it
* will not appear in right click menu and the packet will not be send to
* server when clicked.
* @param optionId The option index.
* @param show If the option is allowed.
*/
public void showMenuOption(int optionId, boolean show) {
if (optionId < 0 || optionId > 9) {
throw new IllegalArgumentException("Option index must be 0-9.");
}
value &= ~(0x1 << (optionId + 1));
if (show) {
value |= (0x1 << (optionId + 1));
}
}
/**
* Sets use on option settings. If nothing is allowed then 'use' option will
* not appear in right click menu.
*/
public void setUseOnSettings(boolean groundItems, boolean npcs, boolean objects, boolean otherPlayer, boolean selfPlayer, boolean component) {
int useFlag = 0;
if (groundItems) {
useFlag |= 0x1;
}
if (npcs) {
useFlag |= 0x2;
}
if (objects) {
useFlag |= 0x4;
}
if (otherPlayer) {
useFlag |= 0x8;
}
if (selfPlayer) {
useFlag |= 0x10;
}
if (component) {
useFlag |= 0x20;
}
value &= ~(127 << 7); // disable
value |= useFlag << 7;
}
/**
* Sets interface events depth. For example, we have inventory interface
* which is opened on gameframe interface (548) If depth is 1, then the
* clicks in inventory will also invoke click event handler scripts on
* gameframe interface.
* @param depth The depth value.
*/
public void setInterfaceEventsDepth(int depth) {
if (depth < 0 || depth > 7) {
throw new IllegalArgumentException("depth must be 0-7.");
}
value &= ~(0x7 << 18);
value |= (depth << 18);
}
/**
* Flags other component options being allowed to be used on this component.
* @param allow If an option can be used on this component.
*/
public void allowUsage(boolean allow) {
value &= ~(1 << 22);
if (allow) {
value |= (1 << 22);
}
}
/**
* Gets the current value.
* @return The value.
*/
public int getValue() {
return value;
}
}
@@ -0,0 +1,20 @@
package core.game.component;
import core.game.node.entity.player.Player;
/**
* An event called when the interface gets closed.
* @author Emperor
*/
public interface CloseEvent {
/**
* Called when the interface gets closed.
* @param player The player.
* @param c The component.
* @return {@code True} if successful, {@code false} if the component should
* remain open.
*/
boolean close(Player player, Component c);
}
@@ -0,0 +1,178 @@
package core.game.component;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.InterfaceManager;
import core.net.packet.PacketRepository;
import core.net.packet.context.InterfaceContext;
import core.net.packet.out.Interface;
/**
* Represents a component.
* @author Emperor
*
*/
public class Component {
/**
* The component id.
*/
protected int id;
/**
* The component definitions.
*/
protected final ComponentDefinition definition;
/**
* The close event.
*/
protected CloseEvent closeEvent;
/**
* The component plugin.
*/
protected ComponentPlugin plugin;
/**
* If the component is hidden.
*/
private boolean hidden;
/**
* Constructs a new {@code Component} {@code Object}.
* @param id The component id.
*/
public Component(int id) {
this.id = id;
this.definition = ComponentDefinition.forId(id);
this.plugin = definition.getPlugin();
}
/**
* Opens the component.
*/
public void open(Player player) {
InterfaceManager manager = player.getInterfaceManager();
if (definition == null) {
PacketRepository.send(Interface.class, new InterfaceContext(player, manager.getWindowPaneId(), manager.getDefaultChildId(), getId(), false));
if (plugin != null) {
plugin.open(player, this);
}
return;
}
if (definition.getType() == InterfaceType.WINDOW_PANE) {
return;
}
if (definition.getType() == InterfaceType.TAB) {
PacketRepository.send(Interface.class, new InterfaceContext(player, definition.getWindowPaneId(manager.isResizable()), definition.getChildId(manager.isResizable()) + definition.getTabIndex(), getId(), definition.isWalkable()));
if (plugin != null) {
plugin.open(player, this);
}
return;
}
PacketRepository.send(Interface.class, new InterfaceContext(player, definition.getWindowPaneId(manager.isResizable()), definition.getChildId(manager.isResizable()), getId(), definition.isWalkable()));
if (plugin != null) {
plugin.open(player, this);
}
}
/**
* Closes the component.
* @param player The player.
* @return {@code True} if the component can be closed.
*/
public boolean close(Player player) {
if (closeEvent != null && !closeEvent.close(player, this)) {
return false;
}
return true;
}
/**
* Gets the id.
* @return The id.
*/
public int getId() {
return id;
}
/**
* Gets the definition.
* @return The definition.
*/
public ComponentDefinition getDefinition() {
return definition;
}
/**
* Gets the closeEvent.
* @return The closeEvent.
*/
public CloseEvent getCloseEvent() {
return closeEvent;
}
/**
* Sets the closeEvent.
* @param closeEvent The closeEvent to set.
*/
public Component setCloseEvent(CloseEvent closeEvent) {
this.closeEvent = closeEvent;
return this;
}
/**
* Sets the component unclosable.
* @param c The component.
*/
public static void setUnclosable(Player p, Component c) {
p.setAttribute("close_c_", false);
c.setCloseEvent(new CloseEvent() {
@Override
public boolean close(Player player, Component c) {
if (!player.getAttribute("close_c_", false)) {
return false;
}
return true;
}
});
}
/**
* Sets the plugin.
* @param plugin the plugin.
*/
public void setPlugin(ComponentPlugin plugin) {
this.plugin = plugin;
}
/**
* Gets the component plugin.
* @return the plugin.
*/
public ComponentPlugin getPlugin() {
if (plugin == null) {
ComponentPlugin p = ComponentDefinition.forId(getId()).getPlugin();
if ((plugin = p) != null) {
return p;
}
}
return plugin;
}
/**
* Gets the hidden value.
* @return The hidden.
*/
public boolean isHidden() {
return hidden;
}
/**
* Sets the hidden value.
* @param hidden The hidden to set.
*/
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
}
@@ -0,0 +1,178 @@
package core.game.component;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Represents the component definitions.
* @author Emperor
*
*/
public final class ComponentDefinition {
/**
* The component definitions mapping.
*/
private static final Map<Integer, ComponentDefinition> DEFINITIONS = new HashMap<Integer, ComponentDefinition>();
/**
* The interface type.
*/
private InterfaceType type = InterfaceType.DEFAULT;
/**
* The interface context.
*/
private boolean walkable;
/**
* The tab index.
*/
private int tabIndex = -1;
/**
* Represents the plugin handler.
*/
private ComponentPlugin plugin;
/**
* Constructs a new {@code ComponentDefinition} {@code Object}.
*/
public ComponentDefinition() {
/*
* empty.
*/
}
/**
* Parses the definition values from a result set.
* @throws SQLException The exception if thrown.
*/
public ComponentDefinition parse(String type, String walkable, String tabIndex){
setType(InterfaceType.values()[Integer.parseInt(type)]);
setWalkable(Boolean.parseBoolean(walkable));
setTabIndex(Integer.parseInt(tabIndex));
return this;
}
/**
* Gets the component definitions for the component id.
* @param componentId The component id.
* @return The component definitions.
*/
public static ComponentDefinition forId(int componentId) {
ComponentDefinition def = DEFINITIONS.get(componentId);
if (def == null) {
DEFINITIONS.put(componentId, def = new ComponentDefinition());
}
return def;
}
/**
* Add a plugin to a definition.
* @param id the id.
* @param plugin the plugin.
*/
public static void put(int id, ComponentPlugin plugin) {
ComponentDefinition.forId(id).setPlugin(plugin);
}
/**
* Gets the definitions mapping.
* @return The definitions mapping.
*/
public static Map<Integer, ComponentDefinition> getDefinitions() {
return DEFINITIONS;
}
/**
* Gets the plugin.
* @return The plugin.
*/
public ComponentPlugin getPlugin() {
return plugin;
}
/**
* Sets the plugin.
* @param plugin The plugin to set.
*/
public void setPlugin(ComponentPlugin plugin) {
this.plugin = plugin;
}
/**
* Gets the window pane id.
* @param resizable If the player is using resizable mode.
* @return The window pane id.
*/
public int getWindowPaneId(boolean resizable) {
return resizable ? type.getResizablePaneId() : type.getFixedPaneId();
}
/**
* Gets the child id.
* @param resizable If the player is using resizable mode.
* @return The child id.
*/
public int getChildId(boolean resizable) {
return resizable ? type.getResizableChildId() : type.getFixedChildId();
}
/**
* Gets the type.
* @return the type
*/
public InterfaceType getType() {
return type;
}
/**
* Sets the batype.
* @param type the type to set.
*/
public void setType(InterfaceType type) {
this.type = type;
}
/**
* Gets the walkable.
* @return the walkable
*/
public boolean isWalkable() {
return walkable;
}
/**
* Sets the bawalkable.
* @param walkable the walkable to set.
*/
public void setWalkable(boolean walkable) {
this.walkable = walkable;
}
/**
* Gets the tabIndex.
* @return the tabIndex
*/
public int getTabIndex() {
return tabIndex;
}
/**
* Sets the batabIndex.
* @param tabIndex the tabIndex to set.
*/
public void setTabIndex(int tabIndex) {
this.tabIndex = tabIndex;
}
@Override
public String toString() {
return "ComponentDefinition [type=" + type + ", walkable=" + walkable + ", tabIndex=" + tabIndex + ", plugin=" + plugin + "]";
}
}
@@ -0,0 +1,35 @@
package core.game.component;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
/**
* Represents the plugin used to handle a component reward.
* @author Vexia
*/
public abstract class ComponentPlugin implements Plugin<Object> {
/**
* Handles the interface interaction.
* @param player The player.
* @param component The component.
* @param opcode The opcode.
* @param slot The slot.
* @param itemId The item id.
* @return {@code True} if succesfully handled.
*/
public abstract boolean handle(final Player player, Component component, final int opcode, final int button, int slot, int itemId);
/**
* Called when this component opens.
* @param player The player
* @param component The component opening.
*/
public void open(Player player, Component component) {}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
}
@@ -0,0 +1,122 @@
package core.game.component;
import static core.tools.Interfaces.*;
/**
* Represents an interface type.
* @author Emperor
*
*/
public enum InterfaceType {
/**
* Default interface.
*/
DEFAULT(TOPLEVEL_548, TOPLEVEL_FULLSCREEN_746, 11, 6),
/**
* Walkable interface.
*/
OVERLAY(TOPLEVEL_548, TOPLEVEL_FULLSCREEN_746, 4, 5),
/**
* A tab interface.
*/
TAB(TOPLEVEL_548, TOPLEVEL_FULLSCREEN_746, 83, 93),
/**
* The only tab to be shown (when this type is opened).
*/
SINGLE_TAB(TOPLEVEL_548, TOPLEVEL_FULLSCREEN_746, 80, 76),
/**
* Chatbox dialogue interface.
*/
DIALOGUE(CHATTOP_752, CHATTOP_752, 12, 12),
/**
* A window pane.
*/
WINDOW_PANE(TOPLEVEL_548, TOPLEVEL_FULLSCREEN_746, 0, 0),
/**
* Client script chatbox interface.
*/
CS_CHATBOX(CHATTOP_752, CHATTOP_752, 6, 6),
/**
* Chatbox interface.
*/
CHATBOX(CHATTOP_752, CHATTOP_752, 8, 8),
/**
* Wilderness overlay
*/
WILDERNESS_OVERLAY(TOPLEVEL_548, TOPLEVEL_FULLSCREEN_746, 11, 3);
/**
* The fixed window pane id.
*/
private final int fixedPaneId;
/**
* The resizable window pane id.
*/
private final int resizablePaneId;
/**
* The fixed child id.
*/
private final int fixedChildId;
/**
* The resizable child id.
*/
private final int resizableChildId;
/**
* Constructs a new {@Code InterfaceType} {@Code Object}
* @param fixedPaneId The fixed window pane id.
* @param resizablePaneId The resizable window pane id.
* @param fixedChildId The fixed child id.
* @param resizableChildId The resizable child id.
*/
private InterfaceType(int fixedPaneId, int resizablePaneId, int fixedChildId, int resizableChildId) {
this.fixedPaneId = fixedPaneId;
this.resizablePaneId = resizablePaneId;
this.fixedChildId = fixedChildId;
this.resizableChildId = resizableChildId;
}
/**
* Gets the fixedPaneId.
* @return the fixedPaneId
*/
public int getFixedPaneId() {
return fixedPaneId;
}
/**
* Gets the resizablePaneId.
* @return the resizablePaneId
*/
public int getResizablePaneId() {
return resizablePaneId;
}
/**
* Gets the fixedChildId.
* @return the fixedChildId
*/
public int getFixedChildId() {
return fixedChildId;
}
/**
* Gets the resizableChildId.
* @return the resizableChildId
*/
public int getResizableChildId() {
return resizableChildId;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,117 @@
package core.game.container;
import core.game.node.item.Item;
/**
* Represents a container event.
* @author Emperor
*/
public final class ContainerEvent {
/**
* Represents a null item.
*/
public static final Item NULL_ITEM = new Item(0, 0);
/**
* The array of changed items.
*/
private final Item[] items;
/**
* Clears the container.
*/
private boolean clear;
/**
* Constructs a new {@code ContainerEvent} {@code Object}.
* @param size The container size.
*/
public ContainerEvent(int size) {
this.items = new Item[size];
}
/**
* Flags a null item on the given slot.
* @param slot The slot.
*/
public void flagNull(int slot) {
items[slot] = NULL_ITEM;
}
/**
* Flags an item on the given slot.
* @param slot The slot.
* @param item The item.
*/
public void flag(int slot, Item item) {
items[slot] = item;
}
/**
* Gets the amount of item slots changed.
* @return The amount of item slots that have changed.
*/
public int getChangeCount() {
int count = 0;
for (Item item : items) {
if (item != null) {
count++;
}
}
return count;
}
/**
* Gets the updated slots.
* @return The slots array.
*/
public int[] getSlots() {
int size = 0;
int[] slots = new int[items.length];
for (int i = 0; i < items.length; i++) {
if (items[i] != null) {
slots[size++] = i;
}
}
int[] slot = new int[size];
for (int i = 0; i < size; i++) {
slot[i] = slots[i];
}
return slot;
}
/**
* Gets the items.
* @return The items.
*/
public Item[] getItems() {
return items;
}
/**
* Flags an empty container.
*/
public void flagEmpty() {
this.clear = true;
for (int i = 0; i < items.length; i++) {
items[i] = null;
}
}
/**
* Gets the clear.
* @return The clear.
*/
public boolean isClear() {
return clear;
}
/**
* Sets the clear flag.
* @param clear The container is cleared.
*/
public void setClear(boolean clear) {
this.clear = clear;
}
}
@@ -0,0 +1,21 @@
package core.game.container;
/**
* Represents a container listener.
* @author Emperor
*/
public interface ContainerListener {
/**
* Updates the changed item slots in the container.
* @param c The container we're listening to.
* @param event The container event.
*/
void update(Container c, ContainerEvent event);
/**
* Updates the entire container.
* @param c The container.
*/
void refresh(Container c);
}
@@ -0,0 +1,29 @@
package core.game.container;
/**
* Represents the container types.
* @author Emperor
*/
public enum ContainerType {
/**
* The default container type.
*/
DEFAULT,
/**
* If the container is used for a shop.
*/
SHOP,
/**
* The container should always stack items.
*/
ALWAYS_STACK,
/**
* The container should never stack items.
*/
NEVER_STACK;
}
@@ -0,0 +1,19 @@
package core.game.container;
/**
* The sort type of the container.
* @author Emperor
*/
public enum SortType {
/**
* Sort by item id (default).
*/
ID,
/**
* Sort by item identification hash (bank).
*/
HASH
}
@@ -0,0 +1,122 @@
package core.game.container.access;
import core.game.node.entity.player.Player;
/**
* Contains the mask value methods. The 'access mask' is actually just a bit
* register that contains permissions for a specific interface (@Peterbjornx)
* @date 5/02/2013
* @author Stacx
* @author Emperor
*/
public final class BitregisterAssembler {
/**
* The register size.
*/
public static final int SIZE = 32 - 1;
/**
* Examine option.
*/
public static final int EXAMINE_OPT = 9;
/**
* Allow dragging.
*/
public static final int DRAGABLE = 17;
/**
* Allow switching item slots.
*/
public static final int SLOT_SWITCH = 20;
/**
* The flags.
*/
private boolean[] permissions = new boolean[SIZE];
/**
* Constructs a new {@code BitregisterAssembler} {@code Object}.
* @param permissions The permissions.
*/
public BitregisterAssembler(int... permissions) {
for (int i : permissions) {
this.permissions[i] = true;
}
}
/**
* Constructs a new {@code BitregisterAssembler} {@code Object}.
*/
public BitregisterAssembler(String[] options) {
enableOptions(options);
}
/**
* Enables the given options ({@code null} options will remain disabled).
* @param options The options.
*/
public void enableOptions(String...options) {
if (options.length > 9) {
throw new IllegalStateException("Too many options specified - maximum 9 allowed!");
}
for (int i = 0; i < options.length; i++) {
if (options[i] != null && !options[i].equals("null")) {
permissions[i] = true;
}
}
}
/**
* Enables the examine option.
*/
public void enableExamineOption() {
permissions[EXAMINE_OPT] = true;
}
/**
* Enables items being dragged.
*/
public void enableDragging() {
permissions[DRAGABLE] = true;
}
/**
* Enables item switching slots (& dragging).
*/
public void enableSlotSwitch() {
enableDragging();
permissions[SLOT_SWITCH] = true;
}
/**
* <b>Send</b> and assemble a bit register for our
* @param player , the player instance
* @param interfaceIndex , the interface index
* @param childIndex , the child index for our interface
* @param offset , the offset for the loop in client
* @param length , the length of our loop
*/
public static void send(Player player, int interfaceIndex, int childIndex, int offset, int length, BitregisterAssembler assembler) {
if (offset >= length) {
throw new RuntimeException("Offset cannot excess length. length = " + length);
}
player.getPacketDispatch().sendAccessMask(assembler.calculateRegister(), childIndex, interfaceIndex, offset, length);
}
/**
* Calculates the register.
* @return The value.
*/
public int calculateRegister() {
int value = 0;
for (int i = 0; i < SIZE; i++) {
if (permissions[i]) {
value |= 2 << i;
}
}
return value;
}
}
@@ -0,0 +1,165 @@
package core.game.container.access;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
/**
* Generates a set of items and options on an interface.
* @date 5/02/2013
* @author Stacx
*/
public class InterfaceContainer {
/**
* The client script index for set_options.
*/
private static final int CLIENT_SCRIPT_INDEX = 150;
/**
* This index will increase each time a set is generated.
*/
private static int index = 600; // 93
/**
* Generates a container/array of items in an interface positioned on the
* child index.
* @param player , the player we generate this set for
* @param itemArray , the container/array of items we want to display
* @param options , the right-click options we want for the items
* @param interfaceIndex , the interface index
* @param childIndex , the child index of the interface where we display the
* items at.
* @return The container key.
*/
private static int generate(Player player, Item[] itemArray, String[] options, int interfaceIndex, int childIndex, int x, int y, int key) {
Object[] clientScript = new Object[options.length + 7];
player.getPacketDispatch().sendRunScript(CLIENT_SCRIPT_INDEX, generateScriptArguments(options.length), populateScript(clientScript, options, interfaceIndex << 16 | childIndex, x, y, key));
BitregisterAssembler.send(player, interfaceIndex, childIndex, 0, itemArray.length, new BitregisterAssembler(options));
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, -1, -2, key, itemArray, itemArray.length, false));
return increment();
}
public static int generateOptions(Player player, String[] options, int interfaceIndex, int childIndex, int x, int y, int key){
player.getPacketDispatch().sendRunScript(CLIENT_SCRIPT_INDEX, generateScriptArguments(options.length), populateScript(new Object[options.length + 7],options,interfaceIndex << 16 | childIndex, x, y, key));
BitregisterAssembler.send(player,interfaceIndex,childIndex,0,28,new BitregisterAssembler(options));
return increment();
}
/**
* Generates options for the interface item container.
* @param player The player.
* @param interfaceId The interface id.
* @param childId The child index.
* @param itemLength The amount of items.
* @param options The options.
* @return The container key.
*/
public static int generate(Player player, int interfaceId, int childId, int itemLength, String... options) {
return generate(player, interfaceId, childId, itemLength, 7, 3, options);
}
/**
* Generates options for the interface item container.
* @param player The player.
* @param interfaceId The interface id.
* @param childId The child index.
* @param itemLength The amount of items.
* @param x The amount of items in a row.
* @param y The amount of item rows.
* @param options The options.
* @return The container key.
*/
public static int generate(Player player, int interfaceId, int childId, int itemLength, int x, int y, String... options) {
int key = increment();
Object[] clientScript = new Object[options.length + 7];
player.getPacketDispatch().sendRunScript(CLIENT_SCRIPT_INDEX, generateScriptArguments(options.length), populateScript(clientScript, options, interfaceId << 16 | childId, x, y, key));
BitregisterAssembler.send(player, interfaceId, childId, 0, itemLength, new BitregisterAssembler(options));
return key;
}
/**
* Increments the current index.
* @return The previous index.
*/
private static int increment() {
if (index == 6999) {
index = 600;
}
return index++;
}
/**
* Populates an object array used as a script for the client
* @param script , the array we want to populate
* @param options , the right-click options for our items
* @param hash , interfaceIndex << 16 | childIndex
* @return script, the populated script
*/
private static Object[] populateScript(Object[] script, String[] options, int hash, int x, int y, int key) {
int offset = 0;
for (String option : options) {
script[offset++] = option;
}
System.arraycopy(new Object[] { -1, 0, x, y, key, hash }, 0, script, offset, 6);
return script;
}
/**
* Generates a script argument type string for the client (note: everything
* but a "s" is integer for the run script packet)
* @param length , the amount of options
* @return the generated string.
*/
private static String generateScriptArguments(int length) {
StringBuilder builder = new StringBuilder("IviiiI");
while (length > 0) {
builder.append("s");
length--;
}
return builder.toString();
}
/**
* Default method to generate and send an item array for the client.
* @return The container key.
* @see {@link InterfaceContainer.generate}
*/
public static int generateItems(Player player, Item[] itemArray, String[] options, int interfaceIndex, int childIndex) {
return generateItems(player, itemArray, options, interfaceIndex, childIndex, 7, 3, increment());
}
/**
* Default method to generate and send an item array for the client.
* @return The container key.
* @see {@link InterfaceContainer.generate}
*/
public static int generateItems(Player player, Item[] itemArray, String[] options, int interfaceIndex, int childIndex, int key) {
return generateItems(player, itemArray, options, interfaceIndex, childIndex, 7, 3, key);
}
/**
* Method to generate the send items for the client with a specified
* location for the items.
* @param x , the x coordinate
* @param y , the y coordinate
* @return The container key.
*/
public static int generateItems(Player player, Item[] itemArray, String[] options, int interfaceIndex, int childIndex, int x, int y) {
return generateItems(player, itemArray, options, interfaceIndex, childIndex, x, y, increment());
}
/**
* Method to generate the send items for the client with a specified
* location for the items.
* @param x , the x coordinate
* @param y , the y coordinate
* @return The container key.
*/
public static int generateItems(Player player, Item[] itemArray, String[] options, int interfaceIndex, int childIndex, int x, int y, int key) {
return generate(player, itemArray, options, interfaceIndex, childIndex, x, y, key);
}
}
@@ -0,0 +1,556 @@
package core.game.container.impl;
import core.ServerConstants;
import core.game.component.Component;
import core.game.container.*;
import core.game.container.access.BitregisterAssembler;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.IronmanMode;
import core.game.node.item.Item;
import core.game.system.config.ItemConfigParser;
import core.game.world.GameWorld;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
import java.nio.ByteBuffer;
/**
* Represents the bank container.
* @author Emperor
*/
public final class BankContainer extends Container {
/**
* The bank container size.
*/
public static final int SIZE = ServerConstants.BANK_SIZE;
/**
* The maximum amount of bank tabs
*/
public static final int TAB_SIZE = 11;
/**
* The player reference.
*/
private Player player;
/**
* The bank listener.
*/
private final BankListener listener;
/**
* Set {@code true} to note items.
*/
private boolean noteItems;
/**
* If the bank is open.
*/
private boolean open;
/**
* The last x-amount entered.
*/
private int lastAmountX = 50;
/**
* The current tab index.
*/
private int tabIndex = 10;
/**
* The tab start indexes.
*/
private final int[] tabStartSlot = new int[TAB_SIZE];
/**
* If inserting items is enabled.
*/
private boolean insertItems;
/**
* Construct a new {@code BankContainer} {@code Object}.
* @param player The player reference.
*/
public BankContainer(Player player) {
super(SIZE, ContainerType.ALWAYS_STACK, SortType.HASH);
super.register(listener = new BankListener(player));
this.player = player;
}
/**
* Open the bank.
*/
public void open() {
if (open) {
return;
}
if (player.getIronmanManager().checkRestriction(IronmanMode.ULTIMATE)) {
return;
}
if (!player.getBankPinManager().isUnlocked() && !GameWorld.getSettings().isDevMode()) {
player.getBankPinManager().openType(1);
return;
}
player.getInterfaceManager().openComponent(762).setCloseEvent((player, c) -> {
BankContainer.this.close();
return true;
});
player.getInterfaceManager().openSingleTab(new Component(763));
super.refresh();
player.getInventory().getListeners().add(listener);
player.getInventory().refresh();
player.varpManager.get(1249).setVarbit(0,lastAmountX).send(player);
player.getPacketDispatch().sendAccessMask(1278, 73, 762, 0, ServerConstants.BANK_SIZE);
BitregisterAssembler assembly = new BitregisterAssembler(0, 1, 2, 3, 4, 5);
assembly.enableExamineOption();
assembly.enableSlotSwitch();
player.getPacketDispatch().sendAccessMask(assembly.calculateRegister(), 0, 763, 0, 27);
player.getPacketDispatch().sendRunScript(1451, "");
open = true;
setTabConfigurations();
sendBankSpace();
}
public void open(Player player) {
if (open) {
return;
}
if (player.getIronmanManager().checkRestriction(IronmanMode.ULTIMATE)) {
return;
}
if (!player.getBankPinManager().isUnlocked() && !GameWorld.getSettings().isDevMode()) {
player.getBankPinManager().openType(1);
return;
}
player.getInterfaceManager().openComponent(762).setCloseEvent((player1, c) -> {
BankContainer.this.close();
return true;
});
this.player.getBank().refresh(player.getBank().listener);
player.getInterfaceManager().openSingleTab(new Component(763));
player.getInventory().getListeners().add(player.getBank().listener);
player.getInventory().refresh();
player.varpManager.get(1249).setVarbit(0,lastAmountX).send(player);
player.getPacketDispatch().sendAccessMask(1278, 73, 762, 0, SIZE);
BitregisterAssembler assembly = new BitregisterAssembler(0, 1, 2, 3, 4, 5);
assembly.enableExamineOption();
assembly.enableSlotSwitch();
player.getPacketDispatch().sendAccessMask(assembly.calculateRegister(), 0, 763, 0, 27);
player.getPacketDispatch().sendRunScript(1451, "");
open = true;
this.player.getBank().setTabConfigurations(player);
}
@Override
public long save(ByteBuffer buffer) {
buffer.putInt(lastAmountX);
buffer.put((byte) tabStartSlot.length);
for (int j : tabStartSlot) {
buffer.putShort((short) j);
}
return super.save(buffer);
}
@Override
public int parse(ByteBuffer buffer) {
lastAmountX = buffer.getInt();
int length = buffer.get() & 0xFF;
for (int i = 0; i < length; i++) {
tabStartSlot[i] = buffer.getShort();
}
return super.parse(buffer);
}
/**
* Closes the bank.
*/
public void close() {
open = false;
player.getInventory().getListeners().remove(listener);
player.getInterfaceManager().closeSingleTab();
player.removeAttribute("search");
player.getPacketDispatch().sendRunScript(571, "");
}
/**
* Adds an item to the bank container.
* @param slot The item slot.
* @param amount The amount.
*/
public void addItem(int slot, int amount) {
if (slot < 0 || slot > player.getInventory().capacity() || amount < 1) {
return;
}
Item item = player.getInventory().get(slot);
if (item == null) {
return;
}
int maximum = player.getInventory().getAmount(item);
if (amount > maximum) {
amount = maximum;
}
int maxCount = super.getMaximumAdd(item);
if (amount > maxCount) {
amount = maxCount;
if (amount < 1) {
player.getPacketDispatch().sendMessage("There is not enough space left in your bank.");
return;
}
}
if (!item.getDefinition().getConfiguration(ItemConfigParser.BANKABLE, true)) {
player.sendMessage("A magical force prevents you from banking this item");
return;
}
item = new Item(item.getId(), amount, item.getCharge());
boolean unnote = !item.getDefinition().isUnnoted();
if (player.getInventory().remove(item, slot, true)) {
Item add = unnote ? new Item(item.getDefinition().getNoteId(), amount, item.getCharge()) : item;
if (unnote && !add.getDefinition().isUnnoted()) {
add = item;
}
int preferredSlot = -1;
if (tabIndex != 0 && tabIndex != 10 && !super.contains(add.getId(), 1)) {
preferredSlot = tabStartSlot[tabIndex] + getItemsInTab(tabIndex);
insert(freeSlot(), preferredSlot, false);
increaseTabStartSlots(tabIndex);
}
super.add(add, true, preferredSlot);
setTabConfigurations();
}
}
/**
* Re-opens the bank interface.
*/
public void reopen() {
if (!open) {
return;
}
player.getInterfaceManager().close();
open();
refresh();
}
/**
* Takes a item from the bank container and adds one to the inventory
* container.
* @param slot The slot.
* @param amount The amount.
*/
public void takeItem(int slot, int amount) {
if (slot < 0 || slot > super.capacity() || amount <= 0) {
return;
}
Item item = get(slot);
if (item == null) {
return;
}
if (amount > item.getAmount()) {
amount = item.getAmount(); // It always stacks in the bank.
}
item = new Item(item.getId(), amount, item.getCharge());
int noteId = item.getDefinition().getNoteId();
Item add = noteItems && noteId > 0 ? new Item(noteId, amount, item.getCharge()) : item;
int maxCount = player.getInventory().getMaximumAdd(add);
if (amount > maxCount) {
item.setAmount(maxCount);
add.setAmount(maxCount);
if (maxCount < 1) {
player.getPacketDispatch().sendMessage("Not enough space in your inventory.");
return;
}
}
if (noteItems && noteId < 0) {
player.getPacketDispatch().sendMessage("This item can't be withdrawn as a note.");
add = item;
}
if (super.remove(item, slot, false)) {
player.getInventory().add(add);
}
int tabId = getTabByItemSlot(slot);
if (get(slot) == null) {
decreaseTabStartSlots(tabId);
}
setTabConfigurations();
shift();
if (player.getAttribute("search", false)) {
reopen();
}
}
/**
* Updates the last x-amount entered.
* @param amount The amount to set.
*/
public void updateLastAmountX(int amount) {
this.lastAmountX = amount;
player.varpManager.get(1249).setVarbit(0,amount).send(player);
}
/**
* Gets the tab the item slot is in.
* @param itemSlot The item slot.
* @return The tab index.
*/
public int getTabByItemSlot(int itemSlot) {
int tabId = 0;
for (int i = 0; i < tabStartSlot.length; i++) {
if (itemSlot >= tabStartSlot[i]) {
tabId = i;
}
}
return tabId;
}
/**
* Increases a tab's start slot.
* @param startId The start id.
*/
public void increaseTabStartSlots(int startId) {
for (int i = startId + 1; i < tabStartSlot.length; i++) {
tabStartSlot[i]++;
}
}
/**
* Decreases a tab's start slot.
* @param startId The start id.
*/
public void decreaseTabStartSlots(int startId) {
if (startId == 10) {
return;
}
for (int i = startId + 1; i < tabStartSlot.length; i++) {
tabStartSlot[i]--;
}
if (getItemsInTab(startId) == 0) {
collapseTab(startId);
}
}
/**
* Gets the array index for a tab.
* @param tabId The tab id.
* @return The array index.
*/
public static int getArrayIndex(int tabId) {
if (tabId == 41 || tabId == 74) {
return 10;
}
int base = 39;
for (int i = 1; i < 10; i++) {
if (tabId == base) {
return i;
}
base -= 2;
}
return -1;
}
/**
* Sends the bank space values on the interface.
*/
public void sendBankSpace() {
player.getPacketDispatch().sendString(Integer.toString(capacity() - freeSlots()), 762, 97);
player.getPacketDispatch().sendString(Integer.toString(capacity()), 762, 98);
}
/**
* Collapses a tab.
* @param tabId The tab index.
*/
public void collapseTab(int tabId) {
int size = getItemsInTab(tabId);
Item[] tempTabItems = new Item[size];
for (int i = 0; i < size; i++) {
tempTabItems[i] = get(tabStartSlot[tabId] + i);
replace(null, tabStartSlot[tabId] + i, false);
}
shift();
for (int i = tabId; i < tabStartSlot.length - 1; i++) {
tabStartSlot[i] = tabStartSlot[i + 1] - size;
}
tabStartSlot[10] = tabStartSlot[10] - size;
for (int i = 0; i < size; i++) {
int slot = freeSlot();
replace(tempTabItems[i], slot, false);
}
refresh(); //We only refresh once.
setTabConfigurations();
}
/**
* Sets the tab configs.
*/
public void setTabConfigurations() {
int value = getItemsInTab(1);
value += getItemsInTab(2) << 10;
value += getItemsInTab(3) << 20;
player.getConfigManager().set(1246, value);
value = getItemsInTab(4);
value += getItemsInTab(5) << 10;
value += getItemsInTab(6) << 20;
player.getConfigManager().set(1247, value);
value = -2013265920;
value += (134217728 * (tabIndex == 10 ? 0 : tabIndex));
value += getItemsInTab(7);
value += getItemsInTab(8) << 10;
player.getConfigManager().set(1248, value);
}
/**
* Sets the tab configs.
*/
public void setTabConfigurations(Player player) {
int value = getItemsInTab(1);
value += getItemsInTab(2) << 10;
value += getItemsInTab(3) << 20;
player.getConfigManager().set(1246, value);
value = getItemsInTab(4);
value += getItemsInTab(5) << 10;
value += getItemsInTab(6) << 20;
player.getConfigManager().set(1247, value);
value = -2013265920;
value += (134217728 * (tabIndex == 10 ? 0 : tabIndex));
value += getItemsInTab(7);
value += getItemsInTab(8) << 10;
player.getConfigManager().set(1248, value);
}
/**
* Gets the amount of items in one tab.
* @param tabId The tab index.
* @return The amount of items in this tab.
*/
public int getItemsInTab(int tabId) {
return tabStartSlot[tabId + 1] - tabStartSlot[tabId];
}
/**
* Checks if the item can be added.
* @param item the item.
* @return {@code True} if so.
*/
public boolean canAdd(Item item) {
return item.getDefinition().getConfiguration(ItemConfigParser.BANKABLE, true);
}
/**
* Gets the last x-amount.
* @return The last x-amount.
*/
public int getLastAmountX() {
return lastAmountX;
}
/**
* If items have to be noted.
* @return If items have to be noted {@code true}.
*/
public boolean isNoteItems() {
return noteItems;
}
/**
* Set if items have to be noted.
* @param noteItems If items have to be noted {@code true}.
*/
public void setNoteItems(boolean noteItems) {
this.noteItems = noteItems;
}
/**
* Gets the tabStartSlot value.
* @return The tabStartSlot.
*/
public int[] getTabStartSlot() {
return tabStartSlot;
}
/**
* Gets the tabIndex value.
* @return The tabIndex.
*/
public int getTabIndex() {
return tabIndex;
}
/**
* Sets the tabIndex value.
* @param tabIndex The tabIndex to set.
*/
public void setTabIndex(int tabIndex) {
this.tabIndex = tabIndex;
}
/**
* Sets the insert items value.
* @param insertItems The insert items value.
*/
public void setInsertItems(boolean insertItems) {
this.insertItems = insertItems;
}
/**
* Gets the insert items value.
* @return {@code True} if inserting items mode is enabled.
*/
public boolean isInsertItems() {
return insertItems;
}
/**
* Checks if the bank is opened.
* @return {@code True} if so.
*/
public boolean isOpen() {
return open;
}
/**
* Listens to the bank container.
* @author Emperor
*/
private static class BankListener implements ContainerListener {
/**
* The player reference.
*/
private Player player;
/**
* Construct a new {@code BankListener} {@code Object}.
* @param player The player reference.
*/
public BankListener(Player player) {
this.player = player;
}
@Override
public void update(Container c, ContainerEvent event) {
if (c instanceof BankContainer) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 762, 64000, 95, event.getItems(), false, event.getSlots()));
} else {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 763, 64000, 93, event.getItems(), false, event.getSlots()));
}
player.getBank().setTabConfigurations();
player.getBank().sendBankSpace();
}
@Override
public void refresh(Container c) {
if (c instanceof BankContainer) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 762, 64000, 95, c.toArray(), c.capacity(), false));
} else {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 763, 64000, 93, c.toArray(), 28, false));
}
player.getBank().setTabConfigurations();
player.getBank().sendBankSpace();
}
}
}
@@ -0,0 +1,285 @@
package core.game.container.impl;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.system.config.ItemConfigParser;
import core.game.world.update.flag.player.AppearanceFlag;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
import core.net.packet.out.WeightUpdate;
import core.plugin.Plugin;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.skill.skillcapeperks.SkillcapePerks;
/**
* Represents the equipment container.
* @author Emperor
*/
public final class EquipmentContainer extends Container {
/**
* The equipment slots.
*/
public static final int SLOT_HAT = 0, SLOT_CAPE = 1, SLOT_AMULET = 2, SLOT_WEAPON = 3, SLOT_CHEST = 4, SLOT_SHIELD = 5, SLOT_LEGS = 7, SLOT_HANDS = 9, SLOT_FEET = 10, SLOT_RING = 12, SLOT_ARROWS = 13;
/**
* The bonus names.
*/
private static final String[] BONUS_NAMES = { "Stab: ", "Slash: ", "Crush: ", "Magic: ", "Ranged: ", "Stab: ", "Slash: ", "Crush: ", "Magic: ", "Ranged: ", "Summoning: ", "Strength: ", "Prayer: " };
/**
* The player.
*/
private final Player player;
/**
* Constructs a new {@code EquipmentContainer} {@code Object}.
* @param player The player.
*/
public EquipmentContainer(Player player) {
super(14);
this.player = player;
register(new EquipmentListener(player));
}
@Override
public boolean add(Item item, boolean fire) {
return add(item, fire, true);
}
/**
* Adds an item to the equipment container.
* @param item The item to add.
* @param fire If we should refresh.
* @param fromInventory If the item is being equipped from the inventory.
* @return {@code True} if succesful, {@code false} if not.
*/
public boolean add(Item item, boolean fire, boolean fromInventory) {
return add(item, player.getInventory().getSlot(item), fire, fromInventory);
}
/**
* Adds an item to the equipment container.
* @param item The item to add.
* @param inventorySlot The inventory slot of the item.
* @param fire If we should refresh.
* @param fromInventory If the item is being equipped from the inventory.
* @return {@code True} if succesful, {@code false} if not.
*/
public boolean add(Item item, int inventorySlot, boolean fire, boolean fromInventory) {
int slot = item.getDefinition().getConfiguration(ItemConfigParser.EQUIP_SLOT, -1);
if (slot == -1 && item.getDefinition().getConfiguration(ItemConfigParser.WEAPON_INTERFACE, -1) != -1) {
slot = SLOT_WEAPON;
}
// slot = 3;
if (slot < 0) {
return false; // Item can't be equipped.
}
if (!item.getDefinition().hasRequirement(player, true, true)) {
return false;
}
Item current = super.get(slot);
if (current != null && current.getId() == item.getId() && current.getDefinition().isStackable()) {
int amount = getMaximumAdd(item);
if (item.getAmount() > amount) {
amount += current.getAmount();
} else {
amount = current.getAmount() + item.getAmount();
}
if (fromInventory) {
player.getInventory().remove(new Item(item.getId(), amount - current.getAmount()));
}
replace(new Item(item.getId(), amount), slot);
return true;
}
if (fromInventory && current != null) {
Plugin<Object> plugin = current.getDefinition().getConfiguration("equipment", null);
if (plugin != null) {
Object object = plugin.fireEvent("unequip", player, current, item);
if (object != null && !((Boolean) object)) {
return true;
}
}
}
if (fromInventory && !player.getInventory().remove(item, inventorySlot, true)) {
return false;
}
Item secondary = null;
if (item.getDefinition().getConfiguration(ItemConfigParser.TWO_HANDED, false)) {
secondary = get(SLOT_SHIELD);
} else if (slot == SLOT_SHIELD) {
secondary = get(SLOT_WEAPON);
if (secondary != null && !secondary.getDefinition().getConfiguration(ItemConfigParser.TWO_HANDED, false)) {
secondary = null;
}
}
int currentSlot = -1;
if (current != null) {
currentSlot = inventorySlot;
if (current.getDefinition().isStackable() && player.getInventory().contains(current.getId(), 1)) {
currentSlot = -1;
}
}
if (current != null && !player.getInventory().add(current, true, inventorySlot)) {
player.getInventory().add(item);
player.getPacketDispatch().sendMessage("Not enough space in your inventory!");
return false;
}
if (secondary != null && !player.getInventory().add(secondary)) {
if (current != null && currentSlot != -1) {
player.getInventory().remove(current, currentSlot, false);
}
player.getInventory().add(item);
player.getPacketDispatch().sendMessage("Not enough space in your inventory!");
return false;
}
super.replace(item, slot, fire);
if (item.getSlot() == SLOT_WEAPON) {
player.getPacketDispatch().sendString(item.getName(), 92, 0);
}
if (secondary != null) {
super.remove(secondary);
}
return true;
}
/**
* Listens to the equipment container.
* @author Emperor
*/
private static class EquipmentListener implements ContainerListener {
/**
* The player.
*/
private final Player player;
/**
* Constructs a new {@code EquipmentContainer} {@code Object}.
* @param player The player.
*/
public EquipmentListener(Player player) {
this.player = player;
}
@Override
public void update(Container c, ContainerEvent event) {
int[] slots = event.getSlots();
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 387, 28, 94, event.getItems(), false, slots));
update(c);
boolean updateDefenceAnimation = false;
for (int slot : slots) {
if (slot == EquipmentContainer.SLOT_WEAPON) {
player.getProperties().setAttackSpeed(c.getNew(slot).getDefinition().getConfiguration(ItemConfigParser.ATTACK_SPEED, 4));
WeaponInterface inter = player.getExtension(WeaponInterface.class);
if (inter == null) {
break;
}
inter.updateInterface();
updateDefenceAnimation = true;
} else if (slot == EquipmentContainer.SLOT_SHIELD) {
updateDefenceAnimation = true;
}
}
if (updateDefenceAnimation) {
player.getProperties().updateDefenceAnimation();
}
}
@Override
public void refresh(Container c) {
player.getProperties().setAttackSpeed(c.getNew(3).getDefinition().getConfiguration(ItemConfigParser.ATTACK_SPEED, 4));
WeaponInterface inter = player.getExtension(WeaponInterface.class);
if (inter != null) {
inter.updateInterface();
}
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 387, 28, 94, c.toArray(), 14, false));
update(c);
player.getProperties().updateDefenceAnimation();
}
/**
* Updates the bonuses, weight, animations, ...
* @param c The container.
*/
public void update(Container c) {
if (c.getNew(SLOT_SHIELD).getId() != 11283 && player.getAttribute("dfs_spec", false)) {
player.removeAttribute("dfs_spec");
player.getProperties().getCombatPulse().setHandler(null);
if (!player.getSettings().isSpecialToggled()) {
player.getConfigManager().set(301, 0);
}
}
player.getAppearance().setAnimations();
player.getUpdateMasks().register(new AppearanceFlag(player));
player.getSettings().updateWeight();
updateBonuses(player);
}
}
/**
* Updates the bonuses.
* @param player The player.
*/
public static void updateBonuses(Player player) {
int[] bonuses = new int[15];
for (Item item : player.getEquipment().toArray()) {
if (item != null) {
int[] bonus = item.getDefinition().getConfiguration(ItemConfigParser.BONUS, new int[15]);
for (int i = 0; i < bonus.length; i++) {
if (i == 14 && bonuses[i] != 0) {
continue;
}
bonuses[i] += bonus[i];
}
}
}
Item weapon = player.getEquipment().get(SLOT_WEAPON);
if(weapon != null && weapon.getDefinition().getRequirement(Skills.STRENGTH) > 0 && SkillcapePerks.isActive(SkillcapePerks.FINE_ATTUNEMENT,player)){
int[] bonus = weapon.getDefinition().getConfiguration(ItemConfigParser.BONUS, new int[15]);
bonuses[11] += Math.ceil(bonus[11] * 0.20);
}
Item shield = player.getEquipment().get(SLOT_SHIELD);
if(shield != null && SkillcapePerks.isActive(SkillcapePerks.GRAND_BULLWARK,player)){
bonuses[5] += Math.ceil(bonuses[5] * 0.20);
bonuses[6] += Math.ceil(bonuses[6] * 0.20);
bonuses[7] += Math.ceil(bonuses[7] * 0.20);
bonuses[9] += Math.ceil(bonuses[9] * 0.20);
}
if (shield != null && shield.getId() == 11283) {
int increase = shield.getCharge() / 20;
bonuses[5] += increase;
bonuses[6] += increase;
bonuses[7] += increase;
bonuses[9] += increase;
}
player.getProperties().setBonuses(bonuses);
update(player);
}
/**
* Updates the equipment stats interface.
* @param player The player to update for.
*/
public static void update(Player player) {
if (!player.getInterfaceManager().hasMainComponent(667)) {
return;
}
PacketRepository.send(WeightUpdate.class, player.getPacketDispatch().getContext());
int index = 0;
int[] bonuses = player.getProperties().getBonuses();
for (int i = 36; i < 50; i++) {
if (i == 47) {
continue;
}
int bonus = bonuses[index];
String bonusValue = bonus > -1 ? ("+" + bonus) : Integer.toString(bonus);
player.getPacketDispatch().sendString(BONUS_NAMES[index++] + bonusValue, 667, i);
}
player.getPacketDispatch().sendString("Attack bonus", 667, 34);
}
}
@@ -0,0 +1,65 @@
package core.game.container.impl;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.node.entity.skill.summoning.SummoningPouch;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
/**
* Handles the inventory container listening.
* @author Emperor
*/
public final class InventoryListener implements ContainerListener {
/**
* The player.
*/
private final Player player;
/**
* Constructs a new {@code InventoryListener} {@code Object}.
* @param player The player.
*/
public InventoryListener(Player player) {
this.player = player;
}
/**
* Updates the required settings etc for the player when the container
* updates.
* @param c The container.
*/
public void update(Container c) {
player.getSettings().updateWeight();
boolean hadPouch = player.getFamiliarManager().isHasPouch();
boolean pouch = false;
for (Item item : c.toArray()) {
if (item != null && SummoningPouch.get(item.getId()) != null) {
pouch = true;
break;
}
}
player.getFamiliarManager().setHasPouch(pouch);
if (hadPouch != pouch && player.getSkullManager().isWilderness()) {
player.getAppearance().sync();
}
}
@Override
public void refresh(Container c) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 149, 0, 93, c, false));
update(c);
}
@Override
public void update(Container c, ContainerEvent event) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 149, 0, 93, event.getItems(), false, event.getSlots()));
update(c);
}
}
@@ -0,0 +1,79 @@
package core.game.content.activity;
import core.game.node.entity.player.Player;
import core.game.system.SystemLogger;
import core.game.world.GameWorld;
import java.util.HashMap;
import java.util.Map;
/**
* Manages the activities.
* @author Emperor
*/
public final class ActivityManager {
/**
* The mapping of instanced activities.
*/
private static final Map<String, ActivityPlugin> ACTIVITIES = new HashMap<>();
/**
* Constructs a new {@code ActivityManager} {@code Object}.
*/
private ActivityManager() {
/*
* empty.
*/
}
/**
* Registers an activity plugin.
* @param plugin The plugin to register.
*/
public static void register(ActivityPlugin plugin) {
plugin.register();
ACTIVITIES.put(plugin.getName(), plugin);
if (!plugin.isInstanced()) {
plugin.configure();
}
}
/**
* Starts an instanced activity.
* @param player The player.
* @param name The name.
* @param login If we are logging in.
* @param args The arguments.
*/
public static boolean start(Player player, String name, boolean login, Object... args) {
ActivityPlugin plugin = ACTIVITIES.get(name);
if (plugin == null) {
if (GameWorld.getSettings().isDevMode()) {
SystemLogger.logErr("Unhandled activity - " + name + "!");
}
return false;
}
try {
if (plugin.isInstanced()) {
(plugin = plugin.newInstance(player)).configure();
}
return plugin.start(player, login, args);
} catch (Throwable e) {
e.printStackTrace();
if (GameWorld.getSettings().isDevMode()) {
player.getPacketDispatch().sendMessage("Error starting activity " + (plugin == null ? null : plugin.getName()) + "!");
}
}
return false;
}
/**
* Gets the activity by the name.
* @param name the name.
* @return the activity.
*/
public static ActivityPlugin getActivity(String name) {
return ACTIVITIES.get(name);
}
}
@@ -0,0 +1,246 @@
package core.game.content.activity;
import core.ServerConstants;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.game.world.map.Region;
import core.game.world.map.build.DynamicRegion;
import core.game.world.map.zone.*;
import core.game.world.map.zone.impl.MultiwayCombatZone;
import core.plugin.Plugin;
import core.plugin.PluginManifest;
import core.plugin.PluginType;
/**
* A plugin implementation used for activity plugins.
* @author Emperor
*/
@PluginManifest(type = PluginType.ACTIVITY)
public abstract class ActivityPlugin extends MapZone implements Plugin<Player> {
/**
* If the activity is instanced.
*/
private boolean instanced;
/**
* If the activity is multicombat.
*/
private boolean multicombat;
/**
* If the activity is safe.
*/
private boolean safe;
/**
* The region of the activity.
*/
protected DynamicRegion region;
/**
* The base location.
*/
protected Location base;
/**
* The player.
*/
protected Player player;
/**
* Constructs a new {@code ActivityPlugin} {@code Object}.
* @param name The name.
* @param instanced If the activity is instanced.
* @param multicombat If the activity is multicombat.
* @param safe If the activity is safe (the player does not lose his/her
* items).
*/
public ActivityPlugin(String name, boolean instanced, boolean multicombat, boolean safe, ZoneRestriction... restrictions) {
super(name, true, ZoneRestriction.RANDOM_EVENTS);
for (ZoneRestriction restriction : restrictions) {
addRestriction(restriction.getFlag());
}
this.instanced = instanced;
this.multicombat = multicombat;
this.safe = safe;
if (safe) {
setZoneType(ZoneType.SAFE.getId());
}
}
@Override
public void register(ZoneBorders borders) {
if (multicombat) {
MultiwayCombatZone.getInstance().register(borders);
}
super.register(borders);
}
/**
* Sets the region base location.
*/
protected void setRegionBase() {
if (region != null) {
if (multicombat) {
region.toggleMulticombat();
}
setBase(Location.create(region.getBorders().getSouthWestX(), region.getBorders().getSouthWestY(), 0));
}
}
/**
* Sets the region base for multiple regions.
* @param regions The regions.
*/
protected void setRegionBase(DynamicRegion[] regions) {
region = regions[0];
Location l = region.getBaseLocation();
for (DynamicRegion r : regions) {
if (r.getX() > l.getX() || r.getY() > l.getY()) {
l = r.getBaseLocation();
}
}
ZoneBorders borders = new ZoneBorders(region.getX() << 6, region.getY() << 6, l.getX() + Region.SIZE, l.getY() + Region.SIZE);
RegionZone multiZone = multicombat ? new RegionZone(MultiwayCombatZone.getInstance(), borders) : null;
RegionZone zone = new RegionZone(this, borders);
for (DynamicRegion r : regions) {
if (multicombat) {
r.setMulticombat(true);
r.getRegionZones().add(multiZone);
}
r.getRegionZones().add(zone);
}
setBase(Location.create(borders.getSouthWestX(), borders.getSouthWestY(), 0));
}
/**
* Starts the activity for the player.
* @param player The player.
* @param login If the player is logging in.
* @param args The arguments.
* @return {@code True} if successfully started the activity.
*/
public boolean start(Player player, boolean login, Object... args) {
this.player = player;
return true;
}
@Override
public boolean enter(Entity e) {
Location l;
if (e instanceof Player && (l = getSpawnLocation()) != null) {
e.getProperties().setSpawnLocation(l);
}
e.getProperties().setSafeZone(safe);
e.setAttribute("activity", this);
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
e.getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
}
Location l;
if (instanced && logout && (l = getSpawnLocation()) != null) {
e.setLocation(l);
}
e.getProperties().setSafeZone(false);
e.removeAttribute("activity");
return super.leave(e, logout);
}
/**
* Method used to do anything on registration.
*/
public void register() {
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public abstract ActivityPlugin newInstance(Player p) throws Throwable;
/**
* Gets the spawn location for this activity.
*/
public abstract Location getSpawnLocation();
/**
* Gets the instanced.
* @return The instanced.
*/
public boolean isInstanced() {
return instanced;
}
/**
* Sets the instanced.
* @param instanced The instanced to set.
*/
public void setInstanced(boolean instanced) {
this.instanced = instanced;
}
/**
* Gets the multicombat.
* @return The multicombat.
*/
public boolean isMulticombat() {
return multicombat;
}
/**
* Sets the multicombat.
* @param multicombat The multicombat to set.
*/
public void setMulticombat(boolean multicombat) {
this.multicombat = multicombat;
}
/**
* Gets the safe.
* @return The safe.
*/
public boolean isSafe() {
return safe;
}
/**
* Sets the safe.
* @param safe The safe to set.
*/
public void setSafe(boolean safe) {
this.safe = safe;
}
/**
* Gets the player.
* @return The player.
*/
public Player getPlayer() {
return player;
}
/**
* Gets the base.
* @return The base.
*/
public Location getBase() {
return base;
}
/**
* Sets the base.
* @param base The base to set.
*/
public void setBase(Location base) {
this.base = base;
}
}
@@ -0,0 +1,336 @@
package core.game.content.activity;
import core.game.component.Component;
import core.game.node.entity.Entity;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.build.DynamicRegion;
import core.net.packet.PacketRepository;
import core.net.packet.context.MinimapStateContext;
import core.net.packet.out.MinimapState;
import core.plugin.PluginManifest;
import core.plugin.PluginType;
import java.util.ArrayList;
import java.util.List;
/**
* Represents the plugin used to handle a cutscene.
* @author Vexia
* @date 28/12/2013
*/
@PluginManifest(type = PluginType.ACTIVITY)
public abstract class CutscenePlugin extends ActivityPlugin {
/**
* The list of tabs to remove.
*/
private static final int[] TABS = new int[] { 0, 1, 2, 3, 4, 5, 6, 11, 12 };
/**
* The npcs in our cutscene.
*/
protected final List<NPC> npcs = new ArrayList<>();
/**
* The start pulse used for effect.
*/
private final StartPulse startPulse = new StartPulse();
/**
* The ending pulse used for effect.
*/
private final EndPulse endPulse = new EndPulse();
/**
* If we should use a fade in or not.
*/
private final boolean fade;
/**
* Constructs a new {@code CutscenePlugin} {@code Object}.
* @param name the name of the cutscene/mapzone.
* @param fade fading in or not.
*/
public CutscenePlugin(String name, final boolean fade) {
super(name, true, false, true);
this.fade = fade;
}
/**
* Constructs a new {@code CutscenePlugin} {@code Object}.
* @param name the name.
*/
public CutscenePlugin(final String name) {
this(name, true);
}
@Override
public boolean start(final Player player, boolean login, Object... args) {
player.setAttribute("cutscene:original-loc", player.getLocation());
player.removeAttribute("real-end");
player.setAttribute("real-end", player.getLocation());
if (isFade()) {
GameWorld.getPulser().submit(getStartPulse());
} else {
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, getMapState()));
player.getInterfaceManager().hideTabs(getRemovedTabs());
player.getProperties().setTeleportLocation(getStartLocation());
player.unlock();
player.getWalkingQueue().reset();
player.getLocks().lockMovement(1000000);
player.getInterfaceManager().close();
open();
}
player.lock();
return super.start(player, login, args);
}
@SuppressWarnings("deprecation")
@Override
public boolean leave(final Entity e, boolean logout) {
if (player != null) {
if (logout) {
player.setLocation(player.getAttribute("cutscene:original-loc", player.getLocation()));
end();
} else {
unpause();
}
player.unlock();
player.getWalkingQueue().reset();
player.getLocks().unlockMovement();
}
return super.leave(e, logout);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
/**
* Method used to stop the cutscene.
* @param fade if we should use a fade cutout.
*/
public void stop(boolean fade) {
if (fade) {
GameWorld.getPulser().submit(endPulse);
} else {
end();
}
}
/**
* Method used to end the cutscene.
*/
public void end() {
if (region != null) {
for (int i = 0; i < region.getPlanes().length; i++) {
for (NPC n : region.getPlanes()[i].getNpcs()) {
if (n == null) {
continue;
}
n.clear();
}
}
}
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
player.getInterfaceManager().restoreTabs();
player.unlock();// incase he was locked.
player.getWalkingQueue().reset();
}
/**
* Represents the pulse used when starting a cutscene. This is used to give
* dramatic effect for entering a cutscene. In the future allow for this to
* be toggled.
* @author 'Vexia
* @date 30/12/2013
*/
public class StartPulse extends Pulse {
/**
* Represents the counter.
*/
private int counter = 0;
/**
* Constructs a new {@code StartPulse} {@code Object}.
*/
public StartPulse() {
super(1, player);
}
@Override
public boolean pulse() {
switch (counter++) {
case 1:
player.lock();
player.getInterfaceManager().openOverlay(new Component(115));
break;
case 3:
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, getMapState()));
player.getInterfaceManager().hideTabs(getRemovedTabs());
break;
case 4:
player.getProperties().setTeleportLocation(getStartLocation());
break;
case 5:
player.getInterfaceManager().closeOverlay();
player.getInterfaceManager().close();
player.unlock();
player.getWalkingQueue().reset();
player.getLocks().lockMovement(1000000);
open();
return true;
}
return false;
}
}
/**
* Represents the pulse used when ending a cutscene. This is used to give
* dramatic effect for entering a cutscene.
* @author 'Vexia
* @date 30/12/2013
*/
public class EndPulse extends Pulse {
/**
* Represents the counter.
*/
private int counter = 0;
/**
* Constructs a new {@code EndPulse} {@code Object}.
*/
public EndPulse() {
super(1, player);
}
@Override
public boolean pulse() {
switch (counter++) {
case 1:
player.lock();
player.getInterfaceManager().openOverlay(new Component(115));
break;
case 3:
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, getMapState()));
player.getInterfaceManager().hideTabs(getRemovedTabs());
break;
case 4:
Location loc = (Location) (player.getAttribute("real-end", player.getAttribute("cutscene:original-loc", player.getLocation())));
player.getProperties().setTeleportLocation(loc);
break;
case 5:
end();
stop();
fade();// specfic for fadeout.
if (player.getSession().isActive()) {
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
}
player.getInterfaceManager().closeOverlay();
if (player.getSession().isActive()) {
player.getInterfaceManager().close();
}
player.getProperties().setSafeZone(false);
return true;
}
return false;
}
}
/**
* Method called when the dim interface is closed. And you can see the
* cutscene.
*/
public void open() {
}
/**
* Method called on the end of the cutscene.
*/
public void fade() {
}
/**
* Gets the mapstate to use. (override if needed).
* @return the state.
*/
public int getMapState() {
return 2;
}
/**
* Gets the removed tabs. (override if needed).
* @return the tabs.
*/
public int[] getRemovedTabs() {
return TABS;
}
/**
* Gets the starting location (region based, override if needed).
* @return the location.
*/
public Location getStartLocation() {
return getBase();
}
/**
* Method used to unpause this cutscene.
*/
public final void unpause() {
stop(true);
}
/**
* Gets the player.
* @return The player.
*/
public Player getPlayer() {
return player;
}
/**
* Gets the region.
* @return The region.
*/
public DynamicRegion getRegion() {
return region;
}
/**
* Gets the nPCS.
* @return The nPCS.
*/
public List<NPC> getNPCS() {
return npcs;
}
/**
* Gets the fade.
* @return The fade.
*/
public boolean isFade() {
return fade;
}
/**
* Gets the start pulse.
* @return the pulse.
*/
public Pulse getStartPulse() {
return startPulse;
}
public Pulse getEndPulse(){return new EndPulse();}
}
@@ -0,0 +1,73 @@
package core.game.content.activity.allfiredup
import core.game.node.entity.player.Player
import core.game.system.SystemLogger
import core.game.world.map.Location
/**
* Various data for beacons, such as varp and offset, required FM level, etc
* @author Ceikry
*/
enum class AFUBeacon(val title: String, val fmLevel: Int, val varpId: Int, val offset: Int, val location: Location, val experience: Double, val keeper: Int = 0) {
RIVER_SALVE("",43,1283,0,Location.create(3396, 3464, 0),216.2,8065),
RAG_AND_BONE("",43,1283,3,Location.create(3343, 3510, 0),235.8,8066),
JOLLY_BOAR("",48,1283,6,Location.create(3278, 3525, 0), 193.8,8067),
NORTH_VARROCK_CASTLE("",53,1283,9,Location.create(3236, 3527, 0),178.5,8068),
GRAND_EXCHANGE("",59,1283,12,Location.create(3170, 3536, 0),194.3,8069),
EDGEVILLE("",62,1283,15,Location.create(3087, 3516, 0),86.7,8070),
MONASTERY("",68,1283,18,Location.create(3034, 3518, 0),224.4,8071),
GOBLIN_VILLAGE("",72,1283,21,Location.create(2968, 3516, 0),194.8,8072),
BURTHORPE("",76,1283,24,Location.create(2940, 3565, 0),195.3,8073),
DEATH_PLATEAU("",79,1288,0,Location.create(2944, 3622, 0),249.9,8074),
TROLLHEIM("",83,1288,3,Location.create(2939, 3680, 0),201.0,8075),
GWD("",87,1288,6,Location.create(2937, 3773, 0),255.0,8076),
TEMPLE("",89,1288,9,Location.create(2946, 3836, 0),198.9),
PLATEAU("",92,1288,12,Location.create(2964, 3931, 0),147.9);
companion object {
fun forLocation(location: Location): AFUBeacon {
for (beacon in values()) {
if (beacon.location.equals(location)) return beacon
}
return RIVER_SALVE.also { SystemLogger.logWarn("Unhandled Beacon Location ${location.toString()}") }
}
fun resetAllBeacons(player: Player){
for(beacon in values()){
player.varpManager.get(beacon.varpId).setVarbit(beacon.offset,0).send(player)
}
}
}
fun light(player: Player){
player.varpManager.get(varpId).setVarbit(offset,2).send(player)
}
fun diminish(player: Player){
player.varpManager.get(varpId).setVarbit(offset,3).send(player)
}
fun extinguish(player: Player){
player.varpManager.get(varpId).setVarbit(offset,0).send(player)
}
fun lightGnomish(player: Player){
player.varpManager.get(varpId).setVarbit(offset,4).send(player)
}
fun fillWithLogs(player: Player){
player.varpManager.get(varpId).setVarbit(offset,1).send(player)
}
fun getState(player: Player): BeaconState{
return BeaconState.values()[player.varpManager.get(varpId).getVarbit(offset)?.value ?: 0]
}
}
enum class BeaconState{
EMPTY,
FILLED,
LIT,
DYING,
WARNING
}
@@ -0,0 +1,229 @@
package core.game.content.activity.allfiredup
import core.cache.def.impl.ObjectDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import core.tools.Items
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.skill.Skills
private val VALID_LOGS = arrayOf(Items.LOGS_1511,Items.OAK_LOGS_1521,Items.WILLOW_LOGS_1519,Items.MAPLE_LOGS_1517,Items.YEW_LOGS_1515,Items.MAGIC_LOGS_1513)
private val FILL_ANIM = Animation(9136)
private val LIGHT_ANIM = Animation(7307)
/**
* Handles interactions for beacons
* @author Ceikry
*/
@Initializable
class AFUBeaconHandler : OptionHandler(){
override fun newInstance(arg: Any?): Plugin<Any> {
for(i in 38448..38461)
ObjectDefinition.forId(i).childrenIds.forEach {
ObjectDefinition.forId(it).handlers["option:add-logs"] = this
ObjectDefinition.forId(it).handlers["option:light"] = this
}
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
val beacon = AFUBeacon.forLocation(node.location)
val questComplete = player.questRepository.isComplete("All Fired Up")
val questStage = player.questRepository.getStage("All Fired Up")
if ((beacon != AFUBeacon.RIVER_SALVE && beacon != AFUBeacon.RAG_AND_BONE && !questComplete)
|| (beacon == AFUBeacon.RIVER_SALVE && questStage < 20 && !questComplete)
|| (beacon == AFUBeacon.RAG_AND_BONE && questStage < 50 && !questComplete)) {
player.dialogueInterpreter.sendDialogues(player, FacialExpression.THINKING, "I probably shouldn't mess with this.")
return true
}
player.debug(beacon.getState(player).name)
when (beacon.getState(player)) {
BeaconState.EMPTY -> fillBeacon(player, beacon, questComplete)
BeaconState.DYING -> restoreBeacon(player, beacon, questComplete)
BeaconState.FILLED -> lightBeacon(player, beacon, questComplete)
BeaconState.LIT, BeaconState.WARNING -> {
player.debug("INVALID BEACON STATE")
}
}
return true
}
fun fillBeacon(player: Player, beacon: AFUBeacon, questComplete: Boolean){
when(beacon){
AFUBeacon.MONASTERY -> {
if(player.skills.getLevel(Skills.PRAYER) < 31){
player.dialogueInterpreter.sendDialogues(NPC(beacon.keeper).getShownNPC(player),FacialExpression.ANGRY,"You must join the monastery to light this beacon!")
return
}
}
AFUBeacon.GWD -> {
if(!AFURepairClimbHandler.isRepaired(player,beacon)){
player.dialogueInterpreter.sendDialogue("You must repair the windbreak before you","can light this beacon.")
return
}
}
AFUBeacon.GOBLIN_VILLAGE -> {
if(!player.questRepository.isComplete("Lost Tribe")){
player.dialogueInterpreter.sendDialogues(NPC(beacon.keeper).getShownNPC(player),FacialExpression.THINKING,"We no trust you outsider. You no light our beacon.","(Complete Lost Tribe to use this beacon.)")
return
}
}
}
if(player.skills.getLevel(Skills.FIREMAKING) < beacon.fmLevel){
player.dialogueInterpreter.sendDialogue("You need ${beacon.fmLevel} Firemaking to light this beacon.")
return
}
val logs = getLogs(player,20)
if (logs.id != 0 && player.inventory.remove(logs)) {
player.lock()
var session: AFUSession? = null
if(questComplete){
session = player.getAttribute("afu-session", null)
if(session == null) {
session = AFUSession(player)
session.init()
}
}
GameWorld.Pulser.submit(object : Pulse() {
var counter = 0
override fun pulse(): Boolean {
when (counter++) {
0 -> player.animator.animate(FILL_ANIM)
1 -> {
beacon.fillWithLogs(player)
if(questComplete){
session?.setLogs(beacon.ordinal,logs)
}
player.varpManager.flagSave(beacon.varpId);
}
2 -> player.unlock().also {player.animator.animate(Animation.RESET); return true }
}
return false
}
})
} else {
player.dialogueInterpreter.sendDialogue("You need some logs to do this.")
}
}
fun lightBeacon(player: Player,beacon: AFUBeacon, questComplete: Boolean){
var session: AFUSession? = null
if(questComplete){
session = player.getAttribute("afu-session",null)
if(session == null) return
}
if(player.inventory.contains(Items.TINDERBOX_590,1)){
player.lock()
GameWorld.Pulser.submit(object: Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(LIGHT_ANIM)
1 -> {
beacon.light(player)
if(questComplete){
session?.startTimer(beacon.ordinal)
if(session?.getLitBeacons() == 6 && !player.hasFireRing()){
player.sendMessage("Congratulations on lighting 6 beacons at once! King Roald has something for you.")
player.setAttribute("/save:afu-mini:ring",true)
}
if(session?.getLitBeacons() == 10 && !player.hasFlameGloves()){
player.sendMessage("Congratulations on lighting 10 beacons at once! King Roald has something for you.")
player.setAttribute("/save:afu-mini:gloves",true)
}
if(session?.getLitBeacons() == 14 && !player.hasInfernoAdze()){
player.sendMessage("Congratulations on lighting all 14 beacons! King Roald has something special for you.")
player.setAttribute("/save:afu-mini:adze",true)
}
var experience = beacon.experience
experience += session?.getBonusExperience() ?: 0.0
player.skills.addExperience(Skills.FIREMAKING,experience)
} else {
player.questRepository.getQuest("All Fired Up").setStage(player, player.questRepository.getStage("All Fired Up") + 10)
}
}
2 -> player.unlock().also { return true }
}
return false
}
})
} else {
player.dialogueInterpreter.sendDialogue("You need a tinderbox to light this.")
}
}
fun restoreBeacon(player: Player,beacon: AFUBeacon, questComplete: Boolean){
var session: AFUSession? = null
if(questComplete){
session = player.getAttribute("afu-session",null)
if(session == null) return
}
val logs = getLogs(player, 5)
if (logs.id != 0 && player.inventory.remove(logs)) {
player.lock()
GameWorld.Pulser.submit(object: Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(FILL_ANIM)
1 -> beacon.light(player).also {
if(questComplete){
session?.refreshTimer(beacon,logs.id)
} else {
player.questRepository.getQuest("All Fired Up").setStage(player, 80)
}
}
2 -> player.unlock().also { return true }
}
return false
}
})
} else {
player.dialogueInterpreter.sendDialogue("You need some logs to do this.")
}
}
fun getLogs(player: Player, amount: Int): Item{
var logId = 0
for (log in VALID_LOGS) if (player.inventory.getAmount(log) >= amount) {logId = log; break}
return Item(logId,amount)
}
fun Player.hasFireRing(): Boolean{
return inventory.containsItem(Item(Items.RING_OF_FIRE_13659)) || bank.containsItem(Item(Items.RING_OF_FIRE_13659)) || equipment.containsItem(Item(Items.RING_OF_FIRE_13659))
}
fun Player.hasFlameGloves(): Boolean{
return inventory.containsItem(Item(Items.FLAME_GLOVES_13660)) || bank.containsItem(Item(Items.FLAME_GLOVES_13660)) || equipment.containsItem(Item(Items.FLAME_GLOVES_13660))
}
fun Player.hasInfernoAdze(): Boolean{
return inventory.containsItem(Item(Items.INFERNO_ADZE_13661)) || bank.containsItem(Item(Items.INFERNO_ADZE_13661)) || equipment.containsItem(Item(Items.INFERNO_ADZE_13661))
}
}
@@ -0,0 +1,145 @@
package core.game.content.activity.allfiredup
import core.cache.def.impl.ObjectDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.impl.ForceMovement
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import core.tools.Items
import core.game.node.entity.skill.Skills
import core.game.node.entity.skill.construction.NailType
import java.util.*
/**
* Handles repairing and climbing of the 3 beacon shortcuts needed to access them
* @author Ceikry
*/
@Initializable
class AFURepairClimbHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ObjectDefinition.forId(38480).handlers["option:repair"] = this
ObjectDefinition.forId(38470).handlers["option:repair"] = this
ObjectDefinition.forId(38494).handlers["option:repair"] = this
ObjectDefinition.forId(38469).handlers["option:climb"] = this
ObjectDefinition.forId(38471).handlers["option:climb"] = this
ObjectDefinition.forId(38486).handlers["option:climb"] = this
ObjectDefinition.forId(38481).handlers["option:climb"] = this
ObjectDefinition.forId(38469).handlers["option:climb"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
var rco: RepairClimbObject = RepairClimbObject.GWD
for(ent in RepairClimbObject.values()) if(ent.destinationDown?.withinDistance(player.location,2) == true || ent.destinationUp?.withinDistance(player.location,2) == true) rco = ent
if(option.equals("repair")) repair(player,rco) else climb(player,rco,node.location)
return true
}
private fun repair(player: Player,rco: RepairClimbObject){
val skill = rco.levelRequirement?.first ?: 0
val level = rco.levelRequirement?.second ?: 0
if(player.skills.getLevel(skill) < level){
player.dialogueInterpreter.sendDialogue("You need level $level ${Skills.SKILL_NAME[skill]} for this.")
return
}
var requiresNeedle = false
val requiredItems = when(rco){
RepairClimbObject.DEATH_PLATEAU -> {
arrayOf(Item(Items.PLANK_960,2))
}
RepairClimbObject.BURTHORPE -> {
arrayOf(Item(Items.IRON_BAR_2351,2))
}
RepairClimbObject.GWD -> {
requiresNeedle = true
arrayOf(Item(Items.JUTE_FIBRE_5931,3))
}
RepairClimbObject.TEMPLE -> {
arrayOf(Item(Items.IRON_BAR_2351,2))
}
}
if(requiresNeedle){
if(player.inventory.containsItem(Item(Items.NEEDLE_1733)) && player.inventory.containItems(*requiredItems.map { it.id }.toIntArray())) {
player.inventory.remove(*requiredItems)
if (Random().nextBoolean()) player.inventory.remove(Item(Items.NEEDLE_1733))
} else {
player.dialogueInterpreter.sendDialogue("You need a needle and ${requiredItems.map { "${it.amount} ${it.name.toLowerCase()}s" }.toString().replace("[","").replace("]","")} for this.")
return
}
} else {
if(player.inventory.containsItem(Item(Items.HAMMER_2347)) && player.inventory.containItems(*requiredItems.map { it.id }.toIntArray())) {
val nails = NailType.get(player,4)
if(nails == null && rco == RepairClimbObject.DEATH_PLATEAU){
player.dialogueInterpreter.sendDialogue("You need 4 nails for this.")
return
} else if (rco == RepairClimbObject.DEATH_PLATEAU){
player.inventory.remove(Item(nails.itemId,4))
}
player.inventory.remove(*requiredItems)
} else {
player.dialogueInterpreter.sendDialogue("You need a hammer and ${requiredItems.map { "${it.amount} ${it.name.toLowerCase()}s" }.toString().replace("[","").replace("]","")} for this.")
return
}
}
player.varpManager.get(rco.varp).setVarbit(rco.offset,1).send(player)
player.varpManager.flagSave(rco.varp)
}
private fun climb(player: Player, rco: RepairClimbObject, location: Location){
ForceMovement.run(player,location,rco.getOtherLocation(player),rco.getAnimation(player),rco.getAnimation(player),rco.getDirection(player),20).endAnimation = Animation(-1)
}
private enum class RepairClimbObject(val varp: Int, val offset: Int, val destinationUp: Location?, val destinationDown: Location?, val levelRequirement: Pair<Int,Int>?){
DEATH_PLATEAU(1282,15,Location.create(2949, 3623, 0),Location.create(2954, 3623, 0), Pair(Skills.CONSTRUCTION,42)),
BURTHORPE(1282,14,Location.create(2941, 3563, 0),Location.create(2934, 3563, 0),Pair(Skills.SMITHING,56)),
GWD(1283,27,null,null,Pair(Skills.CRAFTING,60)),
TEMPLE(1287,29,Location.create(2949, 3835, 0),Location.create(2956, 3835, 0),Pair(Skills.SMITHING,64));
fun getOtherLocation(player: Player): Location?{
if(player.location == destinationDown) return destinationUp
else return destinationDown
}
fun getAnimation(player: Player): Animation {
if(getOtherLocation(player) == destinationDown) return Animation(1148)
else return Animation(740)
}
fun getDirection(player: Player): Direction {
if(this == BURTHORPE){
return Direction.EAST
} else return Direction.WEST
}
fun isRepaired(player: Player): Boolean{
return player.varpManager.get(varp).getVarbit(offset)?.value == 1
}
}
companion object {
fun isRepaired(player: Player, beacon: AFUBeacon): Boolean{
if(beacon == AFUBeacon.DEATH_PLATEAU) return RepairClimbObject.DEATH_PLATEAU.isRepaired(player)
if(beacon == AFUBeacon.BURTHORPE) return RepairClimbObject.BURTHORPE.isRepaired(player)
if(beacon == AFUBeacon.GWD) return RepairClimbObject.GWD.isRepaired(player)
if(beacon == AFUBeacon.TEMPLE) return RepairClimbObject.TEMPLE.isRepaired(player)
else return true
}
}
}
@@ -0,0 +1,131 @@
package core.game.content.activity.allfiredup
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.SystemLogger
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.plugin.Plugin
import core.tools.Items
import core.tools.stringtools.colorize
/**
* Handles keeping track of lit beacons and their burn time remaining
* @author Ceikry
*/
class AFUSession(val player: Player) {
private val beaconTimers = Array(14){i -> BeaconTimer(0,AFUBeacon.values()[i])}
private val logInventories = Array(14){Item(0,0)}
private val beaconWatched = Array(14){false}
private var isActive = false
fun init() {
isActive = true
GameWorld.Pulser.submit(object: Pulse(){
override fun pulse(): Boolean {
player.setAttribute("afu-pulse",this)
beaconTimers.forEach {timer ->
timer.ticks--
if(timer.ticks == 300) timer.beacon.diminish(player).also {
if(beaconWatched[timer.beacon.ordinal]){
beaconWatched[timer.beacon.ordinal] = false
timer.ticks += (getTicks(logInventories[timer.beacon.ordinal].id) * 5)
timer.beacon.light(player)
player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_"," ")} watcher has used your backup logs."))
} else {
player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_", " ")} beacon is dying!"))
}
}
if(timer.ticks == 0) timer.beacon.extinguish(player).also { player.sendMessage(colorize("%RThe ${timer.beacon.name.toLowerCase().replace("_"," ")} beacon has gone out!")) }
}
return !isActive
}
})
player.setAttribute("afu-session",this)
player.logoutPlugins.add(AFULogoutPlugin())
}
fun getLitBeacons(): Int{
return beaconTimers.count { it.ticks > 0 }
}
fun end(){
isActive = false
}
fun setLogs(beaconIndex: Int, logs: Item){
logInventories[beaconIndex] = logs
}
fun startTimer(beaconIndex: Int){
val ticks = getTicks(logInventories[beaconIndex].id) * 20
logInventories[beaconIndex] = Item(0,0)
beaconTimers[beaconIndex].ticks = ticks
}
fun refreshTimer(beacon: AFUBeacon, logID: Int){
val ticks = getTicks(logID) * 5
beaconTimers.forEach {
if(it.beacon.ordinal == beacon.ordinal) it.ticks += ticks
}
}
fun setWatcher(index: Int, logs: Item){
beaconWatched[index] = true
logInventories[index] = logs
}
fun isWatched(index: Int): Boolean{
return beaconWatched[index]
}
fun getTicks(logID: Int): Int{
val ticks = when(logID){
Items.LOGS_1511 -> 65
Items.OAK_LOGS_1521 -> 68
Items.WILLOW_LOGS_1519 -> 73
Items.MAPLE_LOGS_1517 -> 79
Items.YEW_LOGS_1515 -> 83
Items.MAGIC_LOGS_1513 -> 90
else -> 0
}
return ticks
}
fun getBonusExperience(): Double{
return when(getLitBeacons()){
1 -> 608.4
2 -> 1622.4
3 -> 1987.4
4 -> 2149.6
5 -> 2149.6
6 -> 2514.6
7 -> 2555.2
8 -> 2758.0
9 -> 2839.1
10 -> 3041.9
11 -> 3123.0
12 -> 3244.7
13 -> 3366.4
14 -> 4867.4
else -> 0.0
}
}
internal class BeaconTimer(var ticks: Int, val beacon: AFUBeacon)
class AFULogoutPlugin: Plugin<Player> {
override fun newInstance(arg: Player?): Plugin<Player> {
arg ?: return this
AFUBeacon.resetAllBeacons(arg)
val session: AFUSession? = arg.getAttribute("afu-session",null)
session?.end()
arg.removeAttribute("afu-session")
return this
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit
}
}
}
@@ -0,0 +1,91 @@
package core.game.content.activity.allfiredup
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import core.tools.Items
import core.game.content.dialogue.DialoguePlugin
import core.game.node.entity.skill.Skills
private val VALID_LOGS = arrayOf(Items.LOGS_1511, Items.OAK_LOGS_1521, Items.WILLOW_LOGS_1519, Items.MAPLE_LOGS_1517, Items.YEW_LOGS_1515, Items.MAGIC_LOGS_1513)
@Initializable
//TODO: Add requirements for beacon keepers to watch beacons, most of the requirements were not possible to implement at the time of writing this.
class BeaconTenderDialogue(player: Player? = null) : DialoguePlugin(player) {
var index = 0
override fun newInstance(player: Player?): DialoguePlugin {
return BeaconTenderDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
index = getIndexOf((args[0] as NPC).originalId)
if(index == AFUBeacon.GWD.ordinal && player.skills.getLevel(Skills.SUMMONING) < 81){
npc("Awwf uurrrhur","(You need 81 Summoning to communicate with Nanuq.)")
stage = 1000
return true
}
if(index == AFUBeacon.MONASTERY.ordinal && player.skills.getLevel(Skills.PRAYER) < 53){
npc("I will aid you when your devotion is","strong enough.","(You need 53 Prayer for him to watch the beacon.)")
stage = 1000
return true
}
npc = (args[0] as NPC).getShownNPC(player)
npc("Hello, adventurer.")
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
val beacon = AFUBeacon.values()[index]
val logs = getLogs(player,5)
val session: AFUSession? = player.getAttribute("afu-session",null)
when(stage){
0 -> player("Hello!").also { stage++ }
1 -> if(beacon.getState(player) == BeaconState.LIT && session?.isWatched(index) == false){
options("Can you watch this beacon for me?","Nevermind.").also { stage = 10 }
} else {
npc("Carry on, adventurer.").also { stage = 1000 }
}
10 -> when(buttonId){
1 -> player("Can you watch this beacon for me?").also { stage++ }
2 -> player("Nevermind.").also { stage = 1000 }
}
11 -> npc("Certainly, adventurer. Do you have logs for me?").also { stage++ }
12 -> if(logs.id != 0){
player("Yes, I do!").also { stage++ }
} else {
player("No, I don't.").also { stage = 1000 }
}
13 -> npc("Great, hand them over.").also { stage++ }
14 -> player("Here you go!").also {
player.inventory.remove(logs)
session?.setWatcher(index,logs)
stage = 1000
}
1000 -> end()
}
return true
}
fun getIndexOf(id: Int): Int{
if(id == 8065) return 0
if(id == 8066) return 1
for(index in ids.indices){
if(ids[index] == id) return index + 2
}
return -1
}
fun getLogs(player: Player, amount: Int): Item {
var logId = 0
for (log in VALID_LOGS) if (player.inventory.getAmount(log) >= amount) {logId = log; break}
return Item(logId,amount)
}
override fun getIds(): IntArray {
return intArrayOf(8067,8068,8069,8070,8071,8072,8073,8074,8075,8076)
}
}
@@ -0,0 +1,126 @@
package core.game.content.activity.barrows;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.BattleState;
import core.game.node.entity.combat.DeathTask;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.world.map.Location;
import core.tools.RandomFunction;
/**
* Handles a barrow brother NPC.
* @author Emperor
*/
public final class BarrowBrother extends NPC {
/**
* The player to target.
*/
private final Player player;
/**
* Constructs a new {@code BarrowBrother} {@code Object}.
* @param player The target.
* @param id The NPC id.
* @param location The location.
*/
public BarrowBrother(Player player, int id, Location location) {
super(id, location);
this.player = player;
}
@Override
public void init() {
super.init();
super.setRespawn(false);
if (location.getZ() == 3) {
sendChat("You dare disturb my rest!");
} else {
sendChat("You dare steal from us!");
}
getProperties().getCombatPulse().attack(player);
HintIconManager.registerHintIcon(player, this);
}
@Override
public void handleTickActions() {
if (DeathTask.isDead(player)) {
return;
}
if (!player.isActive() || !player.getLocation().withinDistance(location)) {
clear();
return;
}
if (!getProperties().getCombatPulse().isAttacking()) {
getProperties().getCombatPulse().attack(player);
}
}
@Override
public void sendImpact(BattleState state) {
int maxHit = 0;
switch (getId()) {
case 2025:// ahrim
maxHit = 25;
break;
case 2026:// dharok
maxHit = 60;
break;
case 2027:// guthan
maxHit = 24;
break;
case 2028:// karil
maxHit = 20;
break;
case 2029:// torag
maxHit = 23;
break;
case 2030:// verac
maxHit = 25;
break;
}
if (state.getEstimatedHit() > maxHit) {
state.setEstimatedHit(RandomFunction.random(maxHit - 10, maxHit));
}
if (state.getSecondaryHit() > maxHit) {
state.setSecondaryHit(RandomFunction.random(maxHit - 10, maxHit));
}
}
@Override
public void finalizeDeath(Entity killer) {
super.finalizeDeath(killer);
if (killer == player) {
player.getSavedData().getActivityData().getBarrowBrothers()[getBrotherIndex()] = true;
BarrowsActivityPlugin.sendConfiguration(player);
}
}
@Override
public void clear() {
super.clear();
if (player.isActive()) {
player.getHintIconManager().clear();
}
player.removeAttribute("barrow:npc");
player.removeAttribute("brother:" + getBrotherIndex());
}
/**
* Gets the barrow brother index.
* @return The index.
*/
private int getBrotherIndex() {
return getId() - 2025;
}
/**
* Gets the player.
* @return The player.
*/
public Player getPlayer() {
return player;
}
}
@@ -0,0 +1,375 @@
package core.game.content.activity.barrows;
import core.game.component.Component;
import core.game.content.activity.ActivityPlugin;
import core.game.content.global.action.ClimbActionHandler;
import core.game.content.global.action.DoorActionHandler;
import core.plugin.Initializable;
import core.game.node.entity.skill.summoning.familiar.Familiar;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.DeathTask;
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.npc.agg.AggressiveBehavior;
import core.game.node.entity.npc.agg.AggressiveHandler;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.ActivityData;
import core.game.node.object.GameObject;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.update.flag.context.Graphics;
import core.net.packet.PacketRepository;
import core.net.packet.context.CameraContext;
import core.net.packet.context.MinimapStateContext;
import core.net.packet.context.CameraContext.CameraType;
import core.net.packet.out.CameraViewPacket;
import core.net.packet.out.MinimapState;
import core.plugin.PluginManager;
import core.tools.RandomFunction;
/**
* Handles the barrows activity plugin.
* @author Emperor
*/
@Initializable
public final class BarrowsActivityPlugin extends ActivityPlugin {
/**
* The tunnel configuration values.
*/
private static final int[] TUNNEL_CONFIGS = { 55328769, 2867201, 44582944, 817160, 537688072, 40763408, 44320784, 23478274 };
/**
* Represents the tunnels between 2 rooms in the barrows tunnels.
*/
public static final ZoneBorders[] MINI_TUNNELS = {
new ZoneBorders(3532, 9665, 3570, 9671),
new ZoneBorders(3575, 9676, 3570, 9671),
new ZoneBorders(3575, 9676, 3581, 9714),
new ZoneBorders(3534, 9718, 3570, 9723),
new ZoneBorders(3523, 9675, 3528, 9712),
new ZoneBorders(3541, 9711, 3545, 9712),
new ZoneBorders(3558, 9711, 3562, 9712),
new ZoneBorders(3568, 9701, 3569, 9705),
new ZoneBorders(3551, 9701, 3552, 9705),
new ZoneBorders(3534, 9701, 3535, 9705),
new ZoneBorders(3541, 9694, 3545, 9695),
new ZoneBorders(3558, 9694, 3562, 9695),
new ZoneBorders(3568, 9684, 3569, 9688),
new ZoneBorders(3551, 9684, 3552, 9688),
new ZoneBorders(3534, 9684, 3535, 9688),
new ZoneBorders(3541, 9677, 3545, 9678),
new ZoneBorders(3558, 9677, 3562, 9678),
};
/**
* The overlay.
*/
private static final Component OVERLAY = new Component(24);
/**
* The activity handling pulse.
*/
private static final Pulse PULSE = new Pulse(3) {
@Override
public boolean pulse() {
boolean end = true;
for (Player p : RegionManager.getRegionPlayers(14231)) {
end = false;
int index = p.getAttribute("barrow:drain-index", -1);
if (index > -1) {
p.removeAttribute("barrow:drain-index");
p.getPacketDispatch().sendItemOnInterface(-1, 1, 24, index);
continue;
}
if (p.getLocation().getZ() == 0 && p.getAttribute("barrow:looted", false)) {
if (RandomFunction.random(15) == 0) {
p.getImpactHandler().manualHit(p, RandomFunction.random(5), HitsplatType.NORMAL);
Graphics.send(Graphics.create(405), p.getLocation());
}
}
if (p.getLocks().isLocked("barrow:drain") || RandomFunction.random(100) % 2 == 0) {
continue;
}
int drain = 8;
for (boolean killed : p.getSavedData().getActivityData().getBarrowBrothers()) {
if (killed) {
drain += 1;
}
}
p.getSkills().decrementPrayerPoints(drain);
p.getLocks().lock("barrow:drain", (3 + RandomFunction.random(15)) * 3);
index = 1 + RandomFunction.random(6);
p.setAttribute("barrow:drain-index", index);
p.getPacketDispatch().sendItemZoomOnInterface(4761 + RandomFunction.random(12), 100, 24, index);
p.getPacketDispatch().sendAnimationInterface(9810, 24, index);
}
return end;
}
};
/**
* Constructs a new {@code BarrowsActivityPlugin} {@code Object}.
*/
public BarrowsActivityPlugin() {
super("Barrows", false, false, false);
}
@Override
public void locationUpdate(Entity e, Location last) {
if (e instanceof Player && e.getViewport().getRegion().getId() == 14231) {
boolean tunnel = false;
for (ZoneBorders border : MINI_TUNNELS) {
if (border.insideBorder(e)) {
tunnel = true;
break;
}
}
Player player = (Player) e;
if ((player.getConfigManager().get(1270) == 1) != tunnel) {
player.getConfigManager().set(1270, tunnel ? 3 : 0, true);//@emp: proper value seems to be 3, val of 1 makes corridors black
}
}
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player player = (Player) e;
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2));
player.getInterfaceManager().openOverlay(OVERLAY);
player.getConfigManager().set(0, 1);
if (player.getConfigManager().get(452) == 0) {
shuffleCatacombs(player);
}
sendConfiguration(player);
if (!PULSE.isRunning()) {
PULSE.restart();
PULSE.start();
GameWorld.getPulser().submit(PULSE);
}
} else {
((NPC) e).setAggressive(true);
((NPC) e).setAggressiveHandler(new AggressiveHandler(e, new AggressiveBehavior() {
@Override
public boolean canSelectTarget(Entity entity, Entity target) {
if (!target.isActive() || DeathTask.isDead(target)) {
return false;
}
if (!target.getProperties().isMultiZone() && target.inCombat()) {
return false;
}
return true;
}
}));
}
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
player.getInterfaceManager().closeOverlay();
NPC npc = player.getAttribute("barrow:npc");
if (npc != null && !DeathTask.isDead(npc)) {
npc.clear();
}
player.removeAttribute("barrow:solvedpuzzle");
player.removeAttribute("barrow:opened_chest");
player.removeAttribute("crusade-delay");
if (!logout && player.getAttribute("barrow:looted", false)) {
for (int i = 0; i < 6; i++) {
player.removeAttribute("brother:" + i);
player.getSavedData().getActivityData().getBarrowBrothers()[i] = false;
}
player.removeAttribute("barrow:looted");
shuffleCatacombs(player);
player.getSavedData().getActivityData().setBarrowTunnelIndex(RandomFunction.random(6));
player.getSavedData().getActivityData().setBarrowKills(0);
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.RESET, 0, 0, 0, 0, 0));
}
}
return super.leave(e, logout);
}
/**
* "Shuffles" the catacomb gates.
* @param player The player.
*/
public static void shuffleCatacombs(Player player) {
int value = TUNNEL_CONFIGS[RandomFunction.random(TUNNEL_CONFIGS.length)];
value |= 1 << (6 + RandomFunction.random(4));
player.getConfigManager().set(452, value);
}
@Override
public boolean death(Entity e, Entity killer) {
Player player = null;
if (killer instanceof Player) {
player = (Player) killer;
} else if (killer instanceof Familiar) {
player = ((Familiar) killer).getOwner();
}
if (player != null && e instanceof NPC) {
player.getSavedData().getActivityData().setBarrowKills(player.getSavedData().getActivityData().getBarrowKills() + 1);
sendConfiguration(player);
}
return false;
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof GameObject) {
GameObject object = (GameObject) target;
Player player = (Player) e;
if (object.getId() >= 6702 && object.getId() <= 6707) {
ClimbActionHandler.climb((Player) e, ClimbActionHandler.CLIMB_UP, BarrowsCrypt.getCrypt(object.getId() - 6702).getExitLocation());
return true;
}
if (object.getId() >= 6708 && object.getId() <= 6712) {
ClimbActionHandler.climb((Player) e, ClimbActionHandler.CLIMB_UP, BarrowsCrypt.getCrypt(player.getSavedData().getActivityData().getBarrowTunnelIndex()).getEnterLocation());
return true;
}
switch (object.getWrapper().getId()) {
case 6727:
case 6724:
case 6746:
case 6743:
if (player.getAttribute("barrow:solvedpuzzle", false)) {
break;
}
player.setAttribute("barrow:puzzledoor", object);
BarrowsPuzzle.open(player);
return true;
}
switch (object.getId()) {
case 6714:
case 6733:
int index = -1;
for (int i = 0; i < player.getSavedData().getActivityData().getBarrowBrothers().length; i++) {
if (!player.getSavedData().getActivityData().getBarrowBrothers()[i] && RandomFunction.random(15) == 0 && !player.getAttribute("brother:" + i, false)) {
index = i;
break;
}
}
if (index > -1) {
BarrowsCrypt.getCrypt(index).spawnBrother(player, RegionManager.getTeleportLocation(target.getLocation(), 1));
}
DoorActionHandler.handleAutowalkDoor(e, (GameObject) target);
return true;
case 6821:
BarrowsCrypt.getCrypt(BarrowsCrypt.AHRIM).openSarcophagus((Player) e, object);
return true;
case 6771:
BarrowsCrypt.getCrypt(BarrowsCrypt.DHAROK).openSarcophagus((Player) e, object);
return true;
case 6773:
BarrowsCrypt.getCrypt(BarrowsCrypt.GUTHAN).openSarcophagus((Player) e, object);
return true;
case 6822:
BarrowsCrypt.getCrypt(BarrowsCrypt.KARIL).openSarcophagus((Player) e, object);
return true;
case 6772:
BarrowsCrypt.getCrypt(BarrowsCrypt.TORAG).openSarcophagus((Player) e, object);
return true;
case 6823:
BarrowsCrypt.getCrypt(BarrowsCrypt.VERAC).openSarcophagus((Player) e, object);
return true;
case 6774:
player.lock(1);
for (int i = 0; i < player.getSavedData().getActivityData().getBarrowBrothers().length; i++) {
if (!player.getSavedData().getActivityData().getBarrowBrothers()[i] && !player.getAttribute("brother:" + i, false)) {
BarrowsCrypt.getCrypt(i).spawnBrother(player, RegionManager.getTeleportLocation(target.getCenterLocation(), 4));
}
}
player.setAttribute("barrow:opened_chest", true);
sendConfiguration(player);
return true;
case 6775:
if (option.getName().equals("Close")) {
player.removeAttribute("barrow:opened_chest");
sendConfiguration(player);
return true;
}
if (player.getAttribute("barrow:looted", false)) {
player.getPacketDispatch().sendMessage("The chest is empty.");
return true;
}
player.setAttribute("/save:barrow:looted",true);
RewardChest.reward(player);
//PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.SHAKE, 3, 2, 2, 2, 2));
return true;
}
}
return false;
}
/**
* Sends the kill count configuration.
* @param player The player.
*/
public static void sendConfiguration(Player player) {
ActivityData data = player.getSavedData().getActivityData();
int config = data.getBarrowKills() << 17;
for (int i = 0; i < data.getBarrowBrothers().length; i++) {
if (data.getBarrowBrothers()[i]) { // This actually wasn't in 498
// but we'll keep it anyways.
config |= 1 << i;
}
}
if (player.getAttribute("barrow:opened_chest", false)) {
config |= 1 << 16;
}
player.getConfigManager().set(453, config);
}
@Override
public boolean actionButton(Player player, int interfaceId, int buttonId, int slot, int itemId, int opcode) {
return false;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (target instanceof BarrowBrother) {
Player p = null;
if (e instanceof Player) {
p = (Player) e;
} else if (e instanceof Familiar) {
p = ((Familiar) e).getOwner();
}
if (p != null && p != ((BarrowBrother) target).getPlayer()) {
p.getPacketDispatch().sendMessage("He's not after you.");
return false;
}
}
return super.continueAttack(e, target, style, message);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public void configure() {
PluginManager.definePlugin(new TunnelEntranceDialogue());
PluginManager.definePlugin(BarrowsPuzzle.SHAPES);
registerRegion(14231);
BarrowsCrypt.init();
PULSE.stop();
}
}
@@ -0,0 +1,191 @@
package core.game.content.activity.barrows;
import core.game.content.global.action.DigAction;
import core.game.content.global.action.DigSpadeHandler;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.object.GameObject;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
/**
* Handles a barrows crypt.
* @author Emperor
*/
public final class BarrowsCrypt {
/**
* The ahrim barrows crypt index.
*/
public static final int AHRIM = 0;
/**
* The dharok barrows crypt index.
*/
public static final int DHAROK = 1;
/**
* The guthan barrows crypt index.
*/
public static final int GUTHAN = 2;
/**
* The karil barrows crypt index.
*/
public static final int KARIL = 3;
/**
* The torag barrows crypt index.
*/
public static final int TORAG = 4;
/**
* The verac barrows crypt index.
*/
public static final int VERAC = 5;
/**
* The barrows crypts.
*/
private static final BarrowsCrypt[] CRYPTS = { new BarrowsCrypt(AHRIM, 2025, Location.create(3557, 9703, 3), Location.create(3565, 3289, 0)), new BarrowsCrypt(DHAROK, 2026, Location.create(3556, 9718, 3), Location.create(3575, 3298, 0)), new BarrowsCrypt(GUTHAN, 2027, Location.create(3534, 9704, 3), Location.create(3577, 3283, 0)), new BarrowsCrypt(KARIL, 2028, Location.create(3546, 9684, 3), Location.create(3565, 3276, 0)), new BarrowsCrypt(TORAG, 2029, Location.create(3568, 9683, 3), Location.create(3553, 3283, 0)), new BarrowsCrypt(VERAC, 2030, Location.create(3578, 9706, 3), Location.create(3557, 3298, 0)) };
/**
* The NPC id.
*/
private final int npcId;
/**
* The location to teleport to when entering the crypt.
*/
private final Location location;
/**
* The exit location.
*/
private final Location exitLocation;
/**
* The crypt index.
*/
private final int index;
/**
* Constructs a new {@code BarrowsCrypt} {@code Object}.
* @param location The location to teleport to when entering the crypt.
* @param exitLocation The location to teleport to when leaving the crypt.
*/
public BarrowsCrypt(int index, int npcId, Location location, Location exitLocation) {
this.index = index;
this.npcId = npcId;
this.location = location;
this.exitLocation = exitLocation;
}
/**
* Initializes the barrow crypts.
*/
public static void init() {
for (final BarrowsCrypt crypt : CRYPTS) {
DigAction action = new DigAction() {
@Override
public void run(Player player) {
crypt.enter(player);
}
};
Location base = crypt.getExitLocation();
for (int x = -2; x <= 2; x++) {
for (int y = -2; y <= 2; y++) {
DigSpadeHandler.register(base.transform(x, y, 0), action);
}
}
}
}
/**
* Opens the sarcophagus.
* @param player The player.
*/
public void openSarcophagus(Player player, GameObject object) {
if (index == player.getSavedData().getActivityData().getBarrowTunnelIndex()) {
player.getDialogueInterpreter().open("barrow_tunnel", index);
return;
}
if (player.getSavedData().getActivityData().getBarrowBrothers()[index] || player.getAttribute("barrow:npc") != null) {
player.getPacketDispatch().sendMessage("You don't find anything.");
return;
}
player.getPacketDispatch().sendMessage("You don't find anything.");
Location location = RegionManager.getTeleportLocation(object.getLocation().transform(Direction.SOUTH_WEST), object.getSizeX() + 1, object.getSizeY() + 1);
spawnBrother(player, location);
}
/**
* Spawns the barrow brother.
* @param player The player.
* @param location The location.
* @return {@code True} if successful.
*/
public boolean spawnBrother(Player player, Location location) {
if (player.getAttribute("brother:" + index, false)) {
return false;
}
NPC npc = new BarrowBrother(player, npcId, location);
npc.init();
player.setAttribute("barrow:npc", npc);
player.setAttribute("brother:" + index, true);
return true;
}
/**
* Enters the crypt.
* @param player The player.
*/
protected void enter(Player player) {
player.addExtension(BarrowsCrypt.class, this);
player.getPacketDispatch().sendMessage("You've broken into a crypt!");
player.getProperties().setTeleportLocation(getEnterLocation());
}
/**
* Gets the crypt for the given index.
* @param index The crypt index.
* @return The barrows crypt.
*/
public static BarrowsCrypt getCrypt(int index) {
return CRYPTS[index];
}
/**
* Gets the location to teleport to upon entering.
* @return The location.
*/
public Location getEnterLocation() {
return location;
}
/**
* Gets the exit location.
* @return The location.
*/
public Location getExitLocation() {
return exitLocation;
}
/**
* Gets the npcId.
* @return The npcId.
*/
public int getNpcId() {
return npcId;
}
/**
* Gets the index.
* @return The index.
*/
public int getIndex() {
return index;
}
}
@@ -0,0 +1,169 @@
package core.game.content.activity.barrows;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.net.packet.PacketRepository;
import core.net.packet.context.DisplayModelContext;
import core.net.packet.context.DisplayModelContext.ModelType;
import core.net.packet.out.DisplayModel;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the barrows puzzle.
* @author Emperor
*/
public final class BarrowsPuzzle extends ComponentPlugin {
/**
* The shapes puzzle.
*/
public static final BarrowsPuzzle SHAPES = new BarrowsPuzzle(new int[] { 6734, 6735, 6736 }, getAnswerModel(6731, true), getAnswerModel(6732, false), getAnswerModel(6733, false));
/**
* The lines puzzle.
*/
public static final BarrowsPuzzle LINES = new BarrowsPuzzle(new int[] { 6728, 6729, 6730 }, getAnswerModel(6725, true), getAnswerModel(6726, false), getAnswerModel(6727, false));
/**
* The squares puzzle.
*/
public static final BarrowsPuzzle SQUARES = new BarrowsPuzzle(new int[] { 6722, 6723, 6724 }, getAnswerModel(6719, true), getAnswerModel(6720, false), getAnswerModel(6721, false));
/**
* The triangle-on-circles puzzle.
*/
public static final BarrowsPuzzle TRIANGLE_CIRCLES = new BarrowsPuzzle(new int[] { 6716, 6717, 6718 }, getAnswerModel(6713, true), getAnswerModel(6714, false), getAnswerModel(6715, false));
/**
* The puzzle component.
*/
private static final Component COMPONENT = new Component(25);
/**
* The question models.
*/
private final int[] questionModels;
/**
* The answer models.
*/
private final int[] answerModels;
/**
* Constructs a new {@code BarrowsPuzzle} {@code Object}.
* @param questionModels The question models.
* @param answerModels The answer models.
*/
private BarrowsPuzzle(int[] questionModels, int... answerModels) {
this.questionModels = questionModels;
this.answerModels = answerModels;
}
/**
* Creates a new barrows puzzle instance of this puzzle.
* @return The new barrows puzzle instance.
*/
public BarrowsPuzzle create() {
int[] answers = Arrays.copyOf(answerModels, answerModels.length);
List<Integer> list = new ArrayList<>();
for (int answer : answers) {
list.add(answer);
}
Collections.shuffle(list, new Random());
for (int i = 0; i < list.size(); i++) {
answers[i] = list.get(i);
}
return new BarrowsPuzzle(questionModels, answers);
}
/**
* Opens a random barrows puzzle.
* @param player The player.
*/
public static void open(Player player) {
int index = RandomFunction.random(4);
if (index == player.getAttribute("puzzle:index", -1)) {
index = (index + 1) % 4;
}
open(player, index);
}
/**
* Opens the barrows puzzle for the given index.
* @param player The player.
* @param index The index (0 = shapes, 1 = lines, 2 = squares, 3 =
* triangle-on-circle).
*/
public static void open(Player player, int index) {
BarrowsPuzzle puzzle = SHAPES;
switch (index) {
case 1:
puzzle = LINES;
break;
case 2:
puzzle = SQUARES;
break;
case 3:
puzzle = TRIANGLE_CIRCLES;
break;
}
puzzle = puzzle.create();
player.setAttribute("puzzle:index", index);
player.setAttribute("puzzle:answers", puzzle.answerModels);
player.getInterfaceManager().open(COMPONENT);
for (int i = 0; i < puzzle.questionModels.length; i++) {
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, ModelType.MODEL, puzzle.questionModels[i], 0, 25, 6 + i));
}
for (int i = 0; i < puzzle.answerModels.length; i++) {
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, ModelType.MODEL, puzzle.answerModels[i] & 0xFFFF, 0, 25, 2 + i));
}
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, ModelType.MODEL, puzzle.answerModels[2] & 0xFFFF, 0, 25, 5));
}
/**
* Gets the answer model id.
* @param modelId The model id.
* @param correct If the answer is correct.
* @return The model id hash.
*/
private static int getAnswerModel(int modelId, boolean correct) {
return modelId | (correct ? 1 : 0) << 16;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(25, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 2:
case 3:
case 5:
player.getInterfaceManager().close();
boolean correct = ((player.getAttribute("puzzle:answers", new int[3])[button == 5 ? 2 : button - 2] >> 16) & 0xFF) == 1;
if (!correct) {
player.getPacketDispatch().sendMessage("You got the puzzle wrong! You can hear the catacombs moving around you.");
BarrowsActivityPlugin.shuffleCatacombs(player);
break;
}
player.setAttribute("/save:barrow:solvedpuzzle", true);
player.getPacketDispatch().sendMessage("You hear the doors' locking mechanism grind open.");
break;
default:
return false;
}
return true;
}
}
@@ -0,0 +1,100 @@
package core.game.content.activity.barrows
import core.game.component.Component
import core.game.container.access.InterfaceContainer
import core.game.content.global.BossKillCounter
import core.game.node.entity.player.Player
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.node.item.WeightedChanceItem
import core.tools.Items
import core.tools.RandomFunction
import java.util.*
/**
* The reward chest.
* @author Ceikry
* and slightly kermit
*/
object RewardChest {
/**
* The low profit drop table.
*/
private val DROP_TABLE = arrayOf(
//Weighted total = 3050
WeightedChanceItem(Items.COINS_995, 1, 5306, 950),
WeightedChanceItem(Items.MIND_RUNE_558, 60, 60, 300),
WeightedChanceItem(Items.MIND_RUNE_558, 100, 850, 300),
WeightedChanceItem(Items.CHAOS_RUNE_562, 115, 720, 300),
WeightedChanceItem(Items.DEATH_RUNE_560, 15, 15, 300),
WeightedChanceItem(Items.DEATH_RUNE_560, 70, 230, 300),
WeightedChanceItem(Items.BLOOD_RUNE_565, 35, 230, 300),
WeightedChanceItem(Items.BOLT_RACK_4740, 35, 280, 300),
//Weight total = 975
WeightedChanceItem(Items.SUPER_DEFENCE2_165, 1, 1, 325),
WeightedChanceItem(Items.PRAYER_POTION2_141, 1, 1, 325),
WeightedChanceItem(Items.RESTORE_POTION2_129, 1, 1, 325),
//Weight total = 53
WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985, 1, 1, 25),
WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987, 1, 1, 25),
WeightedChanceItem(Items.DRAGON_MED_HELM_1149, 1, 1, 3),
//Weight total = 120 BARROWS ITEMS V
WeightedChanceItem(4708, 1, 1, 5),
WeightedChanceItem(4710, 1, 1, 5),
WeightedChanceItem(4712, 1, 1, 5),
WeightedChanceItem(4714, 1, 1, 5),
WeightedChanceItem(4716, 1, 1, 5),
WeightedChanceItem(4718, 1, 1, 5),
WeightedChanceItem(4720, 1, 1, 5),
WeightedChanceItem(4722, 1, 1, 5),
WeightedChanceItem(4724, 1, 1, 5),
WeightedChanceItem(4726, 1, 1, 5),
WeightedChanceItem(4728, 1, 1, 5),
WeightedChanceItem(4730, 1, 1, 5),
WeightedChanceItem(4732, 1, 1, 5),
WeightedChanceItem(4734, 1, 1, 5),
WeightedChanceItem(4736, 1, 1, 5),
WeightedChanceItem(4738, 1, 1, 5),
WeightedChanceItem(4745, 1, 1, 5),
WeightedChanceItem(4747, 1, 1, 5),
WeightedChanceItem(4749, 1, 1, 5),
WeightedChanceItem(4751, 1, 1, 5),
WeightedChanceItem(4753, 1, 1, 5),
WeightedChanceItem(4755, 1, 1, 5),
WeightedChanceItem(4757, 1, 1, 5),
WeightedChanceItem(4759, 1, 1, 5)
)
/**
* Rewards the player.
*
* @param player The player.
*/
@JvmStatic
fun reward(player: Player) {
for (killed in player.savedData.activityData.barrowBrothers) {
if (!killed){
player.sendMessage("You can't loot the chest until you kill all 6 barrows brothers.")
player.removeAttribute("barrow:looted")
// Because they haven't
// actually looted the
// chest yet.
return
}
}
val rewards: MutableList<Item> = ArrayList()
var maxRolls = 2 + RandomFunction.random(0,player.savedData.activityData.barrowKills / 3)
if(maxRolls > 6) maxRolls = 6
for (i in 0 until maxRolls) {
rewards.add(RandomFunction.rollWeightedChanceTable(*DROP_TABLE))
}
InterfaceContainer.generateItems(player, rewards.toTypedArray(), arrayOf("Pog!","Examine"), 364, 4,3,4)
player.interfaceManager.open(Component(364))
BossKillCounter.addtoBarrowsCount(player)
for(item in rewards){
if(!player.inventory.add(item)){
GroundItemManager.create(item,player)
}
}
}
}
@@ -0,0 +1,83 @@
package core.game.content.activity.barrows;
import core.game.content.dialogue.DialogueInterpreter;
import core.game.content.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.plugin.PluginManifest;
import core.plugin.PluginType;
/**
* The tunnel entrance dialogue handling plugin.
* @author Emperor
*/
@PluginManifest(type = PluginType.DIALOGUE)
public final class TunnelEntranceDialogue extends DialoguePlugin {
/**
* The crypt index.
*/
@SuppressWarnings("unused")
private int index;
/**
* Constructs a new {@code TunnelEntranceDialogue} {@code Object}.
*/
public TunnelEntranceDialogue() {
super();
}
/**
* Constructs a new {@code TunnelEntranceDialogue} {@code Object}.
* @param player The player.
*/
public TunnelEntranceDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new TunnelEntranceDialogue(player);
}
@Override
public boolean open(Object... args) {
this.index = (Integer) args[0];
player.getDialogueInterpreter().sendPlainMessage(false, "You find a hidden tunnel, do you want to enter?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (stage++ == 0) {
player.getDialogueInterpreter().sendOptions(null, "Yeah, I'm fearless!", "No way, that looks scary!");
return true;
}
switch (buttonId) {
case 1:
int offsetX = 0;
int offsetY = 0;
int configValue = player.getConfigManager().get(452);
if ((configValue & (1 << 7)) != 0) {
offsetX = 34;
offsetY = 34;
} else if ((configValue & (1 << 6)) != 0) {
offsetY = 34;
} else if ((configValue & (1 << 9)) != 0) {
offsetX = 34;
}
int x = 3534 + offsetX;
int y = 9677 + offsetY;
player.getProperties().setTeleportLocation(Location.create(x, y, 0));
case 2:
end();
return true;
}
return false;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("barrow_tunnel") };
}
}
@@ -0,0 +1,80 @@
package core.game.content.activity.bountyhunter;
import core.cache.def.impl.ObjectDefinition;
import core.game.content.activity.ActivityManager;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.object.GameObject;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
/**
* Handles the bounty hunter options.
* @author Emperor
*/
public final class BHOptionHandler extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ObjectDefinition.forId(28110).getHandlers().put("option:exit", this);
ObjectDefinition.forId(28119).getHandlers().put("option:enter", this);
ObjectDefinition.forId(28120).getHandlers().put("option:enter", this);
ObjectDefinition.forId(28121).getHandlers().put("option:enter", this);
ObjectDefinition.forId(28122).getHandlers().put("option:exit", this);
ObjectDefinition.forId(28115).getHandlers().put("option:view", this);
ObjectDefinition.forId(28116).getHandlers().put("option:view", this);
return this;
}
@Override
public boolean handle(final Player player, Node node, String option) {
GameObject object = (GameObject) node;
final BountyHunterActivity activity = player.getExtension(BountyHunterActivity.class);
switch (object.getId()) {
case 28119:
ActivityManager.start(player, "BH low_level", false);
return true;
case 28120:
ActivityManager.start(player, "BH mid_level", false);
return true;
case 28121:
ActivityManager.start(player, "BH high_level", false);
return true;
case 28115:
BHScoreBoard.getRogues().open(player);
return true;
case 28116:
BHScoreBoard.getHunters().open(player);
return true;
case 28122:
if (activity == null) {
return false;
}
if (player.getAttribute("exit_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You can't leave the crater until the exit penalty is over.");
return true;
}
player.lock(2);
GameWorld.getPulser().submit(new Pulse(1) {
@Override
public boolean pulse() {
player.getProperties().setTeleportLocation(activity.getType().getExitLocation());
return true;
}
});
player.animate(Animation.create(7376));
return true;
case 28110:
if (activity == null) {
return false;
}
activity.leaveWaitingRoom(player, false);
return true;
}
return false;
}
}
@@ -0,0 +1,161 @@
package core.game.content.activity.bountyhunter;
import java.nio.ByteBuffer;
import core.cache.ServerStore;
import core.cache.StoreFile;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.component.Component;
import core.game.node.entity.player.Player;
import core.tools.StringUtils;
/**
* The score board.
* @author Emperor
*/
public final class BHScoreBoard {
/**
* The score board size.
*/
private static final int SIZE = 10;
/**
* The names.
*/
private String[] names = new String[SIZE];
/**
* The scores.
*/
private int[] scores = new int[SIZE];
/**
* The bounty hunters scoreboard.
*/
private static final BHScoreBoard HUNTERS = new BHScoreBoard();
/**
* The bounty hunter rogues scoreboard.
*/
private static final BHScoreBoard ROGUES = new BHScoreBoard();
/**
* Constructs a new {@code BHScoreBoard} {@code Object}.
*/
public BHScoreBoard() {
for (int i = 0; i < SIZE; i++) {
names[i] = "Nobody yet";
}
}
/**
* Initializes the score boards data.
*/
public static void init() {
StoreFile file = ServerStore.get("bh_scores");
if (file == null) { // Indicates no cache exists yet.
return;
}
ByteBuffer buffer = file.data();
for (int i = 0; i < SIZE; i++) {
HUNTERS.scores[i] = buffer.getInt();
HUNTERS.names[i] = ByteBufferUtils.getString(buffer);
}
for (int i = 0; i < SIZE; i++) {
ROGUES.scores[i] = buffer.getInt();
ROGUES.names[i] = ByteBufferUtils.getString(buffer);
}
}
/**
* Updates the store file for the scores.
*/
public static void update() {
ByteBuffer buffer = ByteBuffer.allocate(500);
for (int i = 0; i < SIZE; i++) {
buffer.putInt(HUNTERS.scores[i]);
ByteBufferUtils.putString(HUNTERS.names[i], buffer);
}
for (int i = 0; i < SIZE; i++) {
buffer.putInt(ROGUES.scores[i]);
ByteBufferUtils.putString(ROGUES.names[i], buffer);
}
buffer.flip();
ServerStore.setArchive("bh_scores", buffer);
}
/**
* Opens the score board.
* @param player The player.
*/
public void open(Player player) {
int component = 654;
if (this == ROGUES) {
component = 655;
}
player.getInterfaceManager().open(new Component(component));
for (int i = 0; i < SIZE; i++) {
player.getPacketDispatch().sendString(StringUtils.formatDisplayName(names[i]), component, 15 + i);
player.getPacketDispatch().sendString(Integer.toString(scores[i]), component, 25 + i);
}
}
/**
* Checks if the ratings of the player is good enough for the score board.
* @param player The player.
*/
public void check(Player player) {
int score = player.getSavedData().getActivityData().getBountyHunterRate();
if (this == ROGUES) {
score = player.getSavedData().getActivityData().getBountyRogueRate();
}
for (int i = 0; i < SIZE; i++) {
if (score > scores[i]) {
insert(player, score, i);
update();
break;
}
}
}
/**
* Inserts the player in the score board.
* @param player The player.
* @param score The score.
* @param index The board index.
*/
private void insert(Player player, int score, int index) {
if (names[index].equals(player.getName())) {
scores[index] = score;
return;
}
for (int i = SIZE - 2; i >= index; i--) {
String name = names[i];
if (name.equals(player.getName())) {
name = names[--i];
}
scores[i + 1] = scores[i];
names[i + 1] = name;
}
names[index] = player.getName();
scores[index] = score;
}
/**
* Gets the rogues.
* @return The rogues.
*/
public static BHScoreBoard getRogues() {
return ROGUES;
}
/**
* Gets the hunters.
* @return The hunters.
*/
public static BHScoreBoard getHunters() {
return HUNTERS;
}
}
@@ -0,0 +1,105 @@
package core.game.content.activity.bountyhunter;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
/**
* Holds a player's bounty hunter data.
* @author Emperor
*/
public final class BountyEntry {
/**
* The target.
*/
private Player target;
/**
* The player hunting this player.
*/
private Player hunter;
/**
* Constructs a new {@code BountyEntry} {@code Object}.
*/
public BountyEntry() {
/*
* empty.
*/
}
/**
* Updates the overlay.
* @param player The player.
*/
public void update(Player player) {
String name = "No one";
if (target != null) {
name = target.getUsername();
}
player.getPacketDispatch().sendString(name, 653, 7);
updatePenalty(player, false);
}
/**
* Updates the current penalty.
* @param player The player.
* @param unlock If the components should be unlocked.
*/
public void updatePenalty(Player player, boolean unlock) {
int penalty = player.getAttribute("pickup_penalty", 0);
int child = -1;
if (GameWorld.getTicks() > penalty) {
player.removeAttribute("pickup_penalty");
player.getPacketDispatch().sendInterfaceConfig(653, 8, true);
} else if (penalty != 0) {
child = 8;
int seconds = (int) Math.round((penalty - GameWorld.getTicks()) * 0.6);
player.getPacketDispatch().sendString(seconds + " Sec", 653, 10);
}
penalty = player.getAttribute("exit_penalty", 0);
if (GameWorld.getTicks() > penalty) {
player.removeAttribute("exit_penalty");
player.getPacketDispatch().sendInterfaceConfig(653, 11, true);
} else if (penalty != 0) {
child = 11;
int seconds = (int) Math.round((penalty - GameWorld.getTicks()) * 0.6);
player.getPacketDispatch().sendString(seconds + " Sec", 653, 13);
}
if (unlock && child > -1) {
player.getPacketDispatch().sendInterfaceConfig(653, child, false);
}
}
/**
* Gets the target.
* @return The target.
*/
public Player getTarget() {
return target;
}
/**
* Sets the target.
* @param target The target to set.
*/
public void setTarget(Player target) {
this.target = target;
}
/**
* Gets the hunter.
* @return The hunter.
*/
public Player getHunter() {
return hunter;
}
/**
* Sets the hunter.
* @param hunter The hunter to set.
*/
public void setHunter(Player hunter) {
this.hunter = hunter;
}
}
@@ -0,0 +1,639 @@
package core.game.content.activity.bountyhunter;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.content.activity.ActivityManager;
import core.game.content.activity.ActivityPlugin;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.item.GroundItem;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.Point;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.map.zone.impl.MultiwayCombatZone;
import core.game.world.map.zone.impl.WildernessZone;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.PluginManager;
import core.tools.RandomFunction;
import java.util.*;
/**
* Handles the Bounty hunter activity.
* @author Emperor
*/
@Initializable
public final class BountyHunterActivity extends ActivityPlugin {
/**
* The skull values.
*/
private static final int[] SKULL_VALUES = { 100_000, // Bronze skull
500_000, // Iron skull
1_100_000, // Adamant skull
2_500_000, // Runite skull
-1 // Dragon skull
};
/**
* The exit offsets.
*/
private static final Point[] EXIT_OFFSETS = { new Point(19, 58), new Point(24, 44), new Point(29, 34), new Point(36, 22), new Point(52, 17), new Point(14, 72), new Point(15, 85), new Point(17, 127), new Point(14, 133), new Point(19, 151), new Point(38, 163), new Point(49, 170), new Point(64, 20), new Point(84, 16), new Point(106, 18), new Point(69, 176), new Point(85, 176), new Point(127, 174), new Point(130, 21), new Point(138, 33), new Point(155, 48), new Point(163, 53), new Point(172, 60), new Point(174, 64), new Point(176, 106), new Point(178, 84), new Point(155, 169), new Point(162, 162), new Point(163, 153), new Point(173, 136) };
/**
* The minimum amount of players to enter the crater.
*/
private static final int MINIMUM_PLAYERS = 2;
/**
* The waiting room overlay.
*/
private static final Component WAITING_OVERLAY = new Component(656);
/**
* The game overlay.
*/
private static final Component GAME_OVERLAY = new Component(653);
/**
* The player in the current crater.
*/
final Map<Player, BountyEntry> players = new HashMap<>();
/**
* The waiting room.
*/
private final List<Player> waitingRoom = new ArrayList<>();
/**
* The crater type.
*/
private final CraterType type;
/**
* The amount of time to wait in the waiting room.
*/
private int waitingTime = 166;
/**
* The waiting room pulse.
*/
private final Pulse waitRoomPulse = new Pulse(1) {
@Override
public boolean pulse() {
String time = Integer.toString((int) Math.round(waitingTime-- * 0.6)) + " Sec";
for (Player player : waitingRoom) {
player.getPacketDispatch().sendString(time, 656, 10);
}
if (waitingTime == -1) {
for (Iterator<Player> it = waitingRoom.iterator(); it.hasNext();) {
enterCrater(it.next());
it.remove();
}
return true;
}
return false;
}
@Override
public void stop() {
super.stop();
waitingTime = 166;
}
};
/**
* The game pulse (doesn't update every tick on 2009scape as well).
*/
private final Pulse gamePulse = new Pulse(10) {
@Override
public boolean pulse() {
for (Player player : players.keySet()) {
BountyEntry entry = players.get(player);
if (entry.getTarget() == null) {
findTarget(player);
}
entry.updatePenalty(player, false);
}
return false;
}
};
/**
* Constructs a new {@code BountyHunterActivity} {@code Object}.
*/
public BountyHunterActivity() {
this(CraterType.LOW_LEVEL);
}
/**
* Constructs a new {@code BountyHunterActivity} {@code Object}.
*/
public BountyHunterActivity(CraterType type) {
super("BH " + type.name().toLowerCase(), false, false, false, ZoneRestriction.FOLLOWERS);
this.type = type;
}
@Override
public void register() {
waitRoomPulse.stop();
gamePulse.stop();
if (getType() == CraterType.LOW_LEVEL) {
// Disable bounty hunter area as wilderness
Location check = Location.create(3166, 3679, 0);
for (ZoneBorders border : WildernessZone.getInstance().getBorders()) {
if (border.insideBorder(check)) {
/* if (GameWorld.getSettings().isPvp()) {
border.addException(new ZoneBorders(2924, 3306, 3078, 3404));
}*/
border.addException(new ZoneBorders(3140, 3653, 3149, 3670));
border.addException(new ZoneBorders(3150, 3656, 3154, 3676));
border.addException(new ZoneBorders(3155, 3661, 3164, 3686));
border.addException(new ZoneBorders(3165, 3667, 3173, 3693));
border.addException(new ZoneBorders(3174, 3673, 3192, 3705));
border.addException(new ZoneBorders(3193, 3681, 3196, 3709));
break;
}
}
PluginManager.definePlugin(new ComponentPlugin() {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(657, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
if (button == 18) {
player.getInterfaceManager().close();
player.lock(1);
BountyHunterActivity activity = player.getExtension(BountyHunterActivity.class);
if (activity.players.isEmpty()) {
activity.joinWaitingRoom(player);
return true;
}
activity.enterCrater(player);
}
return true;
}
});
BHScoreBoard.init();
PluginManager.definePlugin(new BountyLocateSpell());
PluginManager.definePlugin(new BHOptionHandler());
ActivityManager.register(new BountyHunterActivity(CraterType.MID_LEVEL));
ActivityManager.register(new BountyHunterActivity(CraterType.HIGH_LEVEL));
}
}
@Override
public boolean start(Player player, boolean login, Object... args) {
if (player.getFamiliarManager().hasFamiliar()) {
player.getPacketDispatch().sendMessage("You can't bring a follower into the crater.");
return false;
}
if (!getType().canEnter(player)) {
return false;
}
player.addExtension(BountyHunterActivity.class, this);
if (!login) {
player.getInterfaceManager().open(new Component(657));
} else {
enterCrater(player);
}
return true;
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player && getType().getZone().insideBorder(e.getLocation()) || e instanceof Player) {
if (e.getAttribute("viewing_orb") != null) {
return super.enter(e);
}
Player player = (Player) e;
for (int i = 0; i < type.ordinal(); i++) {
if (!player.getMusicPlayer().hasUnlockedIndex(517 + i)) {
player.getMusicPlayer().unlock(444 - i, false);
}
}
player.addExtension(BountyHunterActivity.class, this);
BountyEntry entry = new BountyEntry();
players.put(player, entry);
player.getInterfaceManager().openOverlay(GAME_OVERLAY);
int penalty;
if ((penalty = player.getAttribute("pickup_penalty", 0)) != 0) {
player.setAttribute("/save:pickup_penalty", GameWorld.getTicks() + penalty);
}
if ((penalty = player.getAttribute("exit_penalty", 0)) != 0) {
player.setAttribute("/save:exit_penalty", GameWorld.getTicks() + penalty);
if (player.getPrayer().get(PrayerType.PROTECT_ITEMS)) {
player.getPrayer().toggle(PrayerType.PROTECT_ITEMS);
}
}
findTarget(player);
entry.updatePenalty(player, true);
player.getInteraction().set(Option._P_ATTACK);
player.getInteraction().remove(Option._P_ASSIST);
player.getSkullManager().setSkullCheckDisabled(true);
player.getSkullManager().setWilderness(true);
player.setAttribute("bh_joined", GameWorld.getTicks() + 10);
updateSkull(player);
if (!gamePulse.isRunning()) {
gamePulse.start();
GameWorld.getPulser().submit(gamePulse);
}
}
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
player.removeExtension(BountyHunterActivity.class);
if (waitingRoom.contains(player)) {
leaveWaitingRoom(player, logout);
}
BountyEntry entry = players.get(player);
if (entry != null) {
leaveCrater(player, logout, entry);
}
}
return super.leave(e, logout);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof GroundItem && option.getName().equals("take")) {
return actionButton((Player) e, 192, 19, -1, -1, 55);
}
if (target instanceof Item && option.getName().equals("drop")) {
if (((Item) target).getValue() > 1000) {
((Player) e).getPacketDispatch().sendMessage("This item is too valuable to drop in the crater.");
return true;
}
}
return false;
}
@Override
public boolean ignoreMultiBoundaries(Entity attacker, Entity victim) {
if (attacker instanceof Player) {
BountyEntry entry = players.get(attacker);
return entry != null && entry.getTarget() == victim;
}
return false;
}
@SuppressWarnings("deprecation")
@Override
public boolean actionButton(Player player, int interfaceId, int buttonId, int slot, int itemId, int opcode) {
if (interfaceId == 192 && buttonId == 19) {
BountyEntry entry = players.get(player);
if (entry != null && player.getAttribute("pickup_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You should not be picking up items. Now you must wait before you can leave.");
player.removeAttribute("pickup_penalty");
player.setAttribute("/save:exit_penalty", GameWorld.getTicks() + 300);
entry.updatePenalty(player, true);
if (player.getPrayer().get(PrayerType.PROTECT_ITEMS)) {
player.getPrayer().toggle(PrayerType.PROTECT_ITEMS);
}
}
} else if (interfaceId == 271 && buttonId == 25) {
if (player.getAttribute("exit_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You can't use the protect item prayer until your penalty has passed.");
player.getConfigManager().send(PrayerType.PROTECT_ITEMS.getConfig(), 0);
return true;
}
}
return false;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e instanceof Player && target instanceof Player) {
if (((Player) target).getAttribute("bh_joined", -1) > GameWorld.getTicks()) {
((Player) e).getPacketDispatch().sendMessage("This player has only just entered and is temporarily invulnerable to attacks.");
return false;
}
e.removeAttribute("bh_joined");
}
return true;
}
/**
* Updates the skull.
* @param player The player.
*/
private void updateSkull(final Player player) {
if (player.getAttribute("value_listener") == null) {
ContainerListener listener = new ContainerListener() {
@Override
public void update(Container c, ContainerEvent event) {
refresh(c);
}
@Override
public void refresh(Container c) {
updateSkull(player);
}
};
player.setAttribute("value_listener", listener);
player.getInventory().getListeners().add(listener);
player.getEquipment().getListeners().add(listener);
}
long value = 0;
for (Item item : player.getInventory().toArray()) {
if (item != null) {
value += item.getValue();
}
}
for (Item item : player.getEquipment().toArray()) {
if (item != null) {
value += item.getValue();
}
}
int skull = 2;
if (value >= 0) {
for (int i = 0; i < SKULL_VALUES.length - 1; i++) {
if (value < SKULL_VALUES[i]) {
skull = 6 - i;
break;
}
}
}
player.getSkullManager().setSkulled(true);
player.getAppearance().setSkullIcon(skull);
player.getAppearance().sync();
}
/**
* Enters the bounty hunter crater.
* @param player The player.
*/
public void enterCrater(Player player) {
Point offset = RandomFunction.getRandomElement(EXIT_OFFSETS);
Location destination = Location.create(getType().getZone().getSouthWestX() + offset.getX(), getType().getZone().getSouthWestY() + offset.getY(), 0);
player.getProperties().setTeleportLocation(destination);
player.animate(Animation.create(7377));
}
/**
* Leaves the bounty hunter crater.
* @param player The player.
* @param logout If the player has logged out.
* @param entry The player's bounty entry.
*/
public void leaveCrater(Player player, boolean logout, BountyEntry entry) {
if (entry.getHunter() != null) {
BountyEntry other = players.get(entry.getHunter());
if (other != null) {
entry.getHunter().getPacketDispatch().sendMessage("Your target has " + (logout ? "logged out" : "left") + ". You shall be found a new target.");
other.setTarget(null);
findTarget(entry.getHunter());
}
}
if (entry.getTarget() != null) {
BountyEntry other = players.get(entry.getTarget());
if (other != null) {
other.setHunter(null);
}
}
player.getHintIconManager().clear();
players.remove(player);
ContainerListener listener = player.getAttribute("value_listener");
if (listener != null) {
player.getInventory().getListeners().remove(listener);
player.getEquipment().getListeners().remove(listener);
}
player.getAppearance().setSkullIcon(-1);
player.getAppearance().sync();
player.getInteraction().remove(Option._P_ATTACK);
player.getInteraction().set(Option._P_ASSIST);
player.getSkullManager().setSkullCheckDisabled(false);
player.getSkullManager().setWilderness(false);
player.getInterfaceManager().closeOverlay();
if (players.isEmpty()) {
gamePulse.stop();
}
int penalty;
if ((penalty = player.getAttribute("pickup_penalty", 0)) > GameWorld.getTicks()) {
player.setAttribute("/save:pickup_penalty", penalty - GameWorld.getTicks());
} else {
player.removeAttribute("pickup_penalty");
}
if ((penalty = player.getAttribute("exit_penalty", 0)) > GameWorld.getTicks()) {
player.setAttribute("/save:exit_penalty", penalty - GameWorld.getTicks());
} else {
player.removeAttribute("exit_penalty");
}
player.getSkullManager().setSkulled(false);
}
/**
* Joins the waiting room.
* @param player The player.
*/
private void joinWaitingRoom(Player player) {
waitingRoom.add(player);
player.getProperties().setTeleportLocation(getType().getRoomLocation());
player.getInterfaceManager().openOverlay(WAITING_OVERLAY);
player.getPacketDispatch().sendString("Players waiting (need " + MINIMUM_PLAYERS + "):", 656, 6);
updateWaitingRoomSize();
if (waitingRoom.size() == MINIMUM_PLAYERS) {
String time = (int) Math.round(waitingTime * 0.6) + " Sec";
for (Player p : waitingRoom) {
player.getPacketDispatch().sendString(time, 656, 10);
p.getPacketDispatch().sendInterfaceConfig(656, 9, false);
p.getPacketDispatch().sendInterfaceConfig(656, 8, false);
}
if (!waitRoomPulse.isRunning()) {
waitRoomPulse.start();
GameWorld.getPulser().submit(waitRoomPulse);
}
} else if (waitingRoom.size() > MINIMUM_PLAYERS) {
player.getPacketDispatch().sendString((int) Math.round(waitingTime * 0.6) + " Sec", 656, 10);
player.getPacketDispatch().sendInterfaceConfig(656, 9, false);
player.getPacketDispatch().sendInterfaceConfig(656, 8, false);
}
}
/**
* Leaves the waiting room.
* @param player The player.
*/
@SuppressWarnings("deprecation")
public void leaveWaitingRoom(Player player, boolean logout) {
waitingRoom.remove(player);
if (waitingRoom.size() < MINIMUM_PLAYERS && waitRoomPulse.isRunning()) {
waitRoomPulse.stop();
for (Player p : waitingRoom) {
p.getPacketDispatch().sendInterfaceConfig(656, 9, true);
p.getPacketDispatch().sendInterfaceConfig(656, 8, true);
}
}
updateWaitingRoomSize();
player.getProperties().setTeleportLocation(getType().getExitLocation());
player.getInterfaceManager().closeOverlay();
if (logout) {
player.setLocation(getType().getExitLocation());
}
}
/**
* Finds a target for the specified player.
* @param player The player.
*/
private void findTarget(Player player) {
Player target = null;
BountyEntry other = null;
int difference = 999;
for (Player p : players.keySet()) {
if (p == player) {
continue;
}
BountyEntry entry = players.get(p);
if (entry.getHunter() == null) {
int diff = Math.abs(player.getProperties().getCurrentCombatLevel() - p.getProperties().getCurrentCombatLevel());
if (diff < difference) {
difference = diff;
target = p;
other = entry;
}
}
}
if (other != null) {
other.setHunter(player);
HintIconManager.registerHintIcon(player, target);
} else {
player.getHintIconManager().clear();
}
BountyEntry entry = players.get(player);
entry.setTarget(target);
entry.update(player);
}
/**
* Updates the amount of players in the waiting room.
*/
private void updateWaitingRoomSize() {
String size = Integer.toString(waitingRoom.size());
for (Player player : waitingRoom) {
player.getPacketDispatch().sendString(size, 656, 7);
}
}
@Override
public boolean canLogout(Player player) {
if (player.getAttribute("exit_penalty", 0) > GameWorld.getTicks()) {
player.getPacketDispatch().sendMessage("You can't logout until the exit penalty is over.");
return false;
}
return true;
}
@Override
public boolean death(Entity e, Entity killer) {
if (e instanceof Player) {
Player player = (Player) e;
BountyEntry entry = players.get(player);
if (entry != null) {
if (entry.getHunter() != killer && killer instanceof Player) {
handleRogueKill((Player) killer, player, entry);
} else if (entry.getHunter() == killer) { // "They" is not a
// typo, this was
// the actual
// message on RS.
entry.getHunter().getPacketDispatch().sendMessage("You killed " + player.getUsername() + ". They were your target, so your Hunter PvP rating increases!");
entry.getHunter().getSavedData().getActivityData().updateBountyHunterRate(1);
BHScoreBoard.getHunters().check(entry.getHunter());
} else if (entry.getHunter() != null) {
entry.getHunter().getPacketDispatch().sendMessage("Your target has died. You shall be found a new target.");
}
if (entry.getHunter() != null) {
BountyEntry other = players.get(entry.getHunter());
if (other != null) {
other.setTarget(null);
}
entry.setHunter(null);
}
player.getHintIconManager().clear();
if (player.getAttribute("pickup_penalty", 0) != 0) {
player.setAttribute("pickup_penalty", GameWorld.getTicks() - 5);
}
if (player.getAttribute("exit_penalty", 0) != 0) {
player.setAttribute("exit_penalty", GameWorld.getTicks() - 5);
}
entry.updatePenalty((Player) e, true);
}
}
return false;
}
/**
* Handles a rogue kill.
* @param player The player who killed the victim.
* @param victim The victim.
*/
private void handleRogueKill(Player player, Player victim, BountyEntry entry) {
player.getPacketDispatch().sendMessage("You killed " + victim.getUsername() + ". They were not your target, so your Rogue PvP rating");
player.getPacketDispatch().sendMessage("increases!");
player.getPacketDispatch().sendMessage("This means you get the pick-up penalty: pick anything up and you can't leave!");
player.getSavedData().getActivityData().updateBountyRogueRate(1);
BHScoreBoard.getRogues().check(player);
player.setAttribute("/save:pickup_penalty", GameWorld.getTicks() + 300);
entry.updatePenalty(player, true);
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (e instanceof Player && type != -1) {
((Player) e).getPacketDispatch().sendMessage("A magical force stops you from teleporting.");
return false;
}
return true;
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public Location getSpawnLocation() {
return Location.create(3166, 3679, 0);
}
@Override
public void configure() {
registerRegion(6234);
register(getType().getZone());
int x = getType().getZone().getSouthWestX();
int y = getType().getZone().getSouthWestY();
MultiwayCombatZone.getInstance().register(new ZoneBorders(x + 56, y + 40, x + 140, y + 140));
}
/**
* Gets the type.
* @return The type.
*/
public CraterType getType() {
return type;
}
}
@@ -0,0 +1,98 @@
package core.game.content.activity.bountyhunter;
import core.game.node.entity.skill.magic.MagicSpell;
import core.game.node.entity.skill.magic.Runes;
import core.game.interaction.MovementPulse;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.equipment.SpellType;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.node.entity.player.link.TeleportManager.TeleportType;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.plugin.Plugin;
/**
* Handles the bounty target locate spell.
* @author Emperor
*/
public final class BountyLocateSpell extends MagicSpell {
/**
* Constructs a new {@code BountyLocateSpell} {@code Object}.
*/
public BountyLocateSpell() {
super(SpellBook.MODERN, 32, 45, null, null, null, new Item[] { Runes.AIR_RUNE.getItem(1), Runes.FIRE_RUNE.getItem(1), Runes.LAW_RUNE.getItem(1) });
}
@Override
public boolean cast(Entity entity, Node target) {
BountyHunterActivity activity = entity.getExtension(BountyHunterActivity.class);
Player player = (Player) entity;
if (activity == null) {
player.getPacketDispatch().sendMessage("You can only use this spell in the Bounty Hunter craters.");
return false;
}
BountyEntry entry = activity.players.get(player);
if (entry == null || entry.getTarget() == null) {
player.getPacketDispatch().sendMessage("You don't have a target to teleport to.");
return true;
}
if (player.getStateManager().hasState(EntityState.FROZEN) || player.getStateManager().hasState(EntityState.STUNNED)) {
player.getPacketDispatch().sendMessage("You can't use this when " + (player.getStateManager().hasState(EntityState.STUNNED) ? "stunned." : "frozen."));
return true;
}
boolean combat = player.inCombat();
if (!super.meetsRequirements(entity, true, combat)) {
return false;
}
if (combat) {
player.getPacketDispatch().sendMessage("You were fighting recently so you'll run instead of teleport.");
target = entry.getTarget();
Location location = entry.getTarget().getLocation();
if (!location.withinDistance(player.getLocation(), 30)) {
int offsetX = location.getX() - player.getLocation().getX();
int offsetY = location.getY() - player.getLocation().getY();
if (offsetX > 30) {
offsetX = 30;
} else if (offsetX < -30) {
offsetX = -30;
}
if (offsetY > 30) {
offsetY = 30;
} else if (offsetY < -30) {
offsetY = -30;
}
target = player.getLocation().transform(offsetX, offsetY, 0);
}
player.getPulseManager().run(new MovementPulse(player, target) {
@Override
public boolean pulse() {
return true;
}
}, "movement");
return true;
}
Location destination = RegionManager.getTeleportLocation(entry.getTarget().getLocation(), 5);
if (entity.getTeleporter().send(destination, TeleportType.NORMAL, -1)) {
if (!super.meetsRequirements(entity, true, true)) {
entity.getTeleporter().getCurrentTeleport().stop();
return false;
}
entity.setAttribute("magic-delay", GameWorld.getTicks() + 5);
return true;
}
return false;
}
@Override
public Plugin<SpellType> newInstance(SpellType arg) throws Throwable {
SpellBook.MODERN.register(60, this);
return this;
}
}
@@ -0,0 +1,131 @@
package core.game.content.activity.bountyhunter;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBorders;
/**
* Represents the crater types.
* @author Emperor
*/
public enum CraterType {
/**
* The low level crater.
*/
LOW_LEVEL(3, Location.create(1548, 5804, 0), Location.create(1548, 5804, 0), Location.create(3152, 3672, 0), new ZoneBorders(2688, 5632, 2879, 5823)),
/**
* The mid level crater.
*/
MID_LEVEL(50, Location.create(1558, 5785, 0), Location.create(1548, 5804, 0), Location.create(3158, 3680, 0), new ZoneBorders(2944, 5632, 3135, 5823)),
/**
* The high level crater.
*/
HIGH_LEVEL(95, Location.create(1570, 5804, 0), Location.create(1548, 5804, 0), Location.create(3164, 3685, 0), new ZoneBorders(3200, 5632, 3391, 5823));
/**
* The level required to enter the crater.
*/
private final int level;
/**
* The waiting room location.
*/
private final Location roomLocation;
/**
* The crater location.
*/
private final Location craterLocation;
/**
* The exit location.
*/
private final Location exitLocation;
/**
* The zone borders.
*/
private final ZoneBorders zone;
/**
* Constructs a new {@code CraterType} {@code Object}. The level required to
* enter the crater.
* @param roomLocation The location of the waiting room.
* @param craterLocation The location of the crater.
* @param exitLocation The location to go the when exiting.
* @param zone The crater zone.
*/
private CraterType(int level, Location roomLocation, Location craterLocation, Location exitLocation, ZoneBorders zone) {
this.level = level;
this.roomLocation = roomLocation;
this.craterLocation = craterLocation;
this.exitLocation = exitLocation;
this.zone = zone;
}
/**
* Checks if the player can enter the crater.
* @param player The player.
* @return {@code True} if so.
*/
public boolean canEnter(Player player) {
int combatLevel = player.getProperties().getCurrentCombatLevel();
if (player.getIronmanManager().checkRestriction()) {
return false;
}
if (ordinal() < CraterType.values().length - 1) {
if (combatLevel > CraterType.values()[ordinal() + 1].level + 5) {
player.getPacketDispatch().sendMessage("Your combat level has to be below " + (CraterType.values()[ordinal() + 1].level + 5) + " to enter this crater.");
return false;
}
}
if (combatLevel < level) {
player.getPacketDispatch().sendMessage("You need a combat level of " + level + " to enter this crater.");
return false;
}
return true;
}
/**
* Gets the level requirement.
* @return The level requirement.
*/
public int getLevel() {
return level;
}
/**
* Gets the roomLocation.
* @return The roomLocation.
*/
public Location getRoomLocation() {
return roomLocation;
}
/**
* Gets the craterLocation.
* @return The craterLocation.
*/
public Location getCraterLocation() {
return craterLocation;
}
/**
* Gets the exitLocation.
* @return The exitLocation.
*/
public Location getExitLocation() {
return exitLocation;
}
/**
* Gets the zone.
* @return The zone.
*/
public ZoneBorders getZone() {
return zone;
}
}
@@ -0,0 +1,87 @@
package core.game.content.activity.clanwars;
import core.game.content.activity.ActivityManager;
import core.game.interaction.Option;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestModule;
import core.game.node.entity.player.link.request.RequestType;
import core.game.system.communication.ClanRank;
import core.plugin.Plugin;
/**
* Handles the Clan wars challenge option.
* @author Emperor
* @versuib 1,9
*/
public final class CWChallengeOption extends OptionHandler {
/**
* The challenge option.
*/
public static final Option OPTION = new Option("Challenge", 0);
/**
* The request type.
*/
private static final RequestType REQUEST_TYPE = new RequestType("Sending challenge request...", ":clanreq:", getModule()) {
@Override
public boolean canRequest(Player player, Player target) {
if (player.getCommunication().getClan() == null) {
player.getPacketDispatch().sendMessage("You have to be in a clan to challenge players.");
return false;
}
if (player.getCommunication().getClan().getRank(player).ordinal() < ClanRank.CAPTAIN.ordinal()) {
player.getPacketDispatch().sendMessage("Your clan rank is not high enough to challenge other clans.");
return false;
}
if (player.getCommunication().getClan().getClanWar() != null) {
player.getPacketDispatch().sendMessage("Your clan is already in a war.");
return false;
}
if (target.getCommunication().getClan() == null) {
player.getPacketDispatch().sendMessage("This player is not in a clan.");
return false;
}
if (target.getCommunication().getClan().getRank(target).ordinal() < ClanRank.CAPTAIN.ordinal()) {
player.getPacketDispatch().sendMessage("This player's clan rank is not high enough to accept challenges.");
return false;
}
if (target.getCommunication().getClan().getClanWar() != null) {
player.getPacketDispatch().sendMessage("This player's clan is already in a war.");
return false;
}
if (target.getCommunication().getClan() == player.getCommunication().getClan()) {
player.getPacketDispatch().sendMessage("You can't challenge someone from your own clan.");
return false;
}
return true;
}
};
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
OPTION.setHandler(this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getRequestManager().request((Player) node, REQUEST_TYPE);
return true;
}
/**
* Gets the request module.
* @return The module.
*/
private static RequestModule getModule() {
return new RequestModule() {
@Override
public void open(Player player, Player target) {
ActivityManager.start(player, "Clan wars", false, target);
}
};
}
}
@@ -0,0 +1,497 @@
package core.game.content.activity.clanwars;
import java.util.ArrayList;
import java.util.List;
import core.game.component.Component;
import core.game.content.activity.ActivityPlugin;
import core.plugin.Initializable;
import core.game.node.entity.skill.summoning.familiar.Familiar;
import core.game.node.entity.skill.summoning.pet.Pet;
import core.game.interaction.Option;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.ConfigurationManager.Configuration;
import core.game.node.object.GameObject;
import core.game.node.object.ObjectBuilder;
import core.game.system.communication.ClanEntry;
import core.game.system.communication.ClanRepository;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.build.DynamicRegion;
import core.game.world.map.zone.RegionZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneType;
import core.game.world.map.zone.impl.MultiwayCombatZone;
import core.game.world.update.flag.chunk.AnimateObjectUpdateFlag;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the clan wars activity.
* @author Emperor
*/
@Initializable
public final class ClanWarsActivityPlugin extends ActivityPlugin {
/**
* The first clan.
*/
private ClanRepository firstClan;
/**
* The second clan.
*/
private ClanRepository secondClan;
/**
* The first clan's players.
*/
private List<Player> firstClanPlayers = new ArrayList<>();
/**
* The second clan's players.
*/
private List<Player> secondClanPlayers = new ArrayList<>();
/**
* The list of viewing players.
*/
private List<Player> viewingPlayers = new ArrayList<>();
/**
* The amount of ticks.
*/
private int ticks;
/**
* The updating pulse.
*/
private Pulse pulse;
/**
* The attack option.
*/
private static final Option ATTACK_OPTION = new Option("Attack", 0).setHandler(new OptionHandler() {
@Override
public boolean handle(Player player, Node node, String option) {
player.getPulseManager().clear("interaction:attack:" + node.hashCode());
player.getProperties().getCombatPulse().attack(node);
return true;
}
@Override
public boolean isWalk() {
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
return this;
}
@Override
public boolean isDelayed(Player player) {
return false;
}
});
/**
* Constructs a new {@code ClanWarsActivityPlugin} {@code Object}.
*/
public ClanWarsActivityPlugin() {
super("Clan wars", true, false, true);
}
@Override
public boolean start(Player player, boolean login, Object... args) {
Player other = (Player) args[0];
firstClan = player.getCommunication().getClan();
secondClan = other.getCommunication().getClan();
firstClan.setClanWar(this);
secondClan.setClanWar(this);
sendWarDeclaration(firstClan.getPlayers());
sendWarDeclaration(secondClan.getPlayers());
handleWall();
join(player);
join(other);
return true;
}
/**
* Handles the wall in the middle of the battlefield.
*/
private void handleWall() {
int offset = 0;
for (int x = 5; x < 54; x++) {
offset = (offset + 1) % 3;
ObjectBuilder.add(new GameObject(28174 + offset, base.transform(x, 64, 0)));
}
GameWorld.getPulser().submit(pulse = new Pulse(200) {
@Override
public boolean pulse() {
for (int x = 5; x < 54; x++) {
Location l = base.transform(x, 64, 0);
GameObject object = RegionManager.getObject(l);
if (object != null) {
Animation anim = Animation.create(7386 + ((object.getId() - 28174) % 3));
anim.setObject(object);
RegionManager.getRegionChunk(l).flag(new AnimateObjectUpdateFlag(anim));
}
}
GameWorld.getPulser().submit(new Pulse(5) {
@Override
public boolean pulse() {
for (int x = 5; x < 54; x++) {
Location l = base.transform(x, 64, 0);
GameObject object = RegionManager.getObject(l);
if (object != null) {
ObjectBuilder.remove(object);
}
}
return true;
}
});
super.setTicksPassed(250);
sendGameData();
if (firstClanPlayers.isEmpty() || secondClanPlayers.isEmpty()) {
finishWar();
}
return true;
}
});
}
/**
* Ends the war.
*/
public void finishWar() {
firstClan.setClanWar(null);
secondClan.setClanWar(null);
int firstInterfaceId = firstClanPlayers.isEmpty() ? 650 : 651;
int secondInterfaceId = firstClanPlayers.isEmpty() ? 651 : 650;
String[] message = new String[] { "Your clan has been defeated!", "Your clan is victorious!" };
for (Player p : firstClanPlayers) {
p.getProperties().setTeleportLocation(getLeaveLocation());
p.getInterfaceManager().openComponent(firstInterfaceId);
p.getPacketDispatch().sendMessage(message[firstInterfaceId - 650]);
p.fullRestore();
PulseManager.cancelDeathTask(p);
}
for (Player p : secondClanPlayers) {
p.getProperties().setTeleportLocation(getLeaveLocation());
p.getInterfaceManager().openComponent(secondInterfaceId);
p.getPacketDispatch().sendMessage(message[secondInterfaceId - 650]);
p.fullRestore();
PulseManager.cancelDeathTask(p);
}
for (Player p : viewingPlayers) {
p.getProperties().setTeleportLocation(getLeaveLocation());
if (p.getCommunication().getClan() == firstClan) {
p.getInterfaceManager().openComponent(firstInterfaceId);
p.getPacketDispatch().sendMessage(message[firstInterfaceId - 650]);
} else {
p.getInterfaceManager().openComponent(secondInterfaceId);
p.getPacketDispatch().sendMessage(message[secondInterfaceId - 650]);
}
}
}
/**
* Sends the game data for all players in the game.
*/
public void sendGameData() {
for (Player p : firstClanPlayers) {
sendGameData(p);
}
for (Player p : secondClanPlayers) {
sendGameData(p);
}
for (Player p : viewingPlayers) {
sendGameData(p);
}
}
/**
* Sends the game data for the player.
* @param p The player.
*/
public void sendGameData(Player p) {
int value = 0;
boolean first = p.getCommunication().getClan() == firstClan;
String name = firstClan.getName();
if (first) {
value |= firstClanPlayers.size() << 5;
value |= secondClanPlayers.size() << 14;
} else {
name = secondClan.getName();
value |= secondClanPlayers.size() << 5;
value |= firstClanPlayers.size() << 14;
}
if (pulse.getTicksPassed() < 200) {
value |= (200 - pulse.getTicksPassed()) << 23;
}
p.getConfigManager().set(Configuration.CLAN_WAR_DATA, value);
p.getPacketDispatch().sendString(name, 265, 2);
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (type != -1 && type != 2 && e instanceof Player) {
((Player) e).getPacketDispatch().sendMessage("You can't teleport away from a war.");
return false;
}
return true;
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInteraction().set(ATTACK_OPTION);
player.getInteraction().remove(Option._P_ASSIST);
player.getSkullManager().setSkullCheckDisabled(true);
player.getSkullManager().setWilderness(true);
player.getInterfaceManager().openOverlay(new Component(265));
} else if (e instanceof Familiar && !(e instanceof Pet)) {
Familiar familiar = (Familiar) e;
if (familiar.isCombatFamiliar()) {
familiar.transform(familiar.getOriginalId() + 1);
}
}
return true;
}
@Override
public boolean death(Entity e, Entity killer) {
if (e instanceof Player) {
return enterViewingRoom((Player) e);
}
return false;
}
/**
* Enters the viewing room.
* @param player The player.
* @return {@code True} if successfully entered the viewing room.
*/
public boolean enterViewingRoom(Player player) {
Location destination = null;
if (player.getCommunication().getClan() == firstClan) {
remove(player, firstClanPlayers);
destination = base.transform(55 + RandomFunction.randomize(3), 51 + RandomFunction.randomize(11), 0);
} else if (player.getCommunication().getClan() == secondClan) {
remove(player, secondClanPlayers);
destination = base.transform(55 + RandomFunction.randomize(3), 66 + RandomFunction.randomize(11), 0);
} else {
return false;
}
player.getProperties().setTeleportLocation(destination);
viewingPlayers.add(player);
sendGameData();
return true;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e instanceof Familiar) {
e = ((Familiar) e).getOwner();
}
if (target instanceof Familiar) {
target = ((Familiar) target).getOwner();
}
if (e instanceof Player && target instanceof Player) {
Player player = (Player) e;
Player other = (Player) target;
ClanRepository clan = player.getCommunication().getClan();
if (pulse.isRunning()) {
player.getPacketDispatch().sendMessage("The war hasn't started yet.");
return false;
}
if (!firstClanPlayers.contains(player) && !secondClanPlayers.contains(player)) {
return false;
}
if (other.getCommunication().getClan() == clan) {
player.getPacketDispatch().sendMessage("You can only attack players in a different clan.");
return false;
}
if (!firstClanPlayers.contains(other) && !secondClanPlayers.contains(other)) {
player.getPacketDispatch().sendMessage("You can't attack this player.");
return false;
}
}
return true;
}
/**
* Removes the player from the game.
* @param player The player.
* @param players The players list.
*/
public void remove(Player player, List<Player> players) {
players.remove(player);
if (!pulse.isRunning() && players.isEmpty()) {
finishWar();
}
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof GameObject) {
GameObject object = (GameObject) target;
if (object.getId() == 28214 || object.getId() == 28140) {
e.getProperties().setTeleportLocation(getLeaveLocation());
return true;
}
}
return false;
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInterfaceManager().closeOverlay();
player.getInteraction().remove(ATTACK_OPTION);
if (firstClanPlayers.contains(player)) {
remove(player, firstClanPlayers);
} else if (secondClanPlayers.contains(player)) {
remove(player, secondClanPlayers);
} else {
viewingPlayers.remove(player);
}
sendGameData();
player.getSkullManager().setSkullCheckDisabled(false);
player.getSkullManager().setWilderness(false);
if (logout) {
e.setLocation(getLeaveLocation());
}
} else if (e instanceof Familiar && !(e instanceof Pet)) {
Familiar familiar = (Familiar) e;
if (familiar.isCombatFamiliar()) {
familiar.reTransform();
}
}
return true;
}
@Override
public Object fireEvent(String identifier, Object... args) {
if (identifier.equals("join")) {
join((Player) args[0]);
return true;
}
if (identifier.equals("leavefc")) {
Player p = (Player) args[0];
p.getProperties().setTeleportLocation(getLeaveLocation());
return true;
}
return null;
}
/**
* Gets the leaving location.
* @return The leaving location.
*/
private static Location getLeaveLocation() {
Location l = Location.create(3265 + RandomFunction.randomize(13), 3675 + RandomFunction.randomize(18), 0);
while (!RegionManager.isTeleportPermitted(l)) {
l = l.transform(1, 1, 0);
}
return l;
}
/**
* Makes the player join the game.
* @param player The player.
*/
public void join(Player player) {
if (!pulse.isRunning()) {
enterViewingRoom(player);
return;
}
boolean first = player.getCommunication().getClan() == firstClan;
if (first) {
if (firstClanPlayers.contains(player)) {
return;
}
firstClanPlayers.add(player);
player.getProperties().setTeleportLocation(base.transform(34 + RandomFunction.randomize(4), 10, 0));
} else {
if (secondClanPlayers.contains(player)) {
return;
}
secondClanPlayers.add(player);
player.getProperties().setTeleportLocation(base.transform(26 + RandomFunction.randomize(4), 118, 0));
}
sendGameData();
}
/**
* Sends messages to the list of players.
* @param players The players list.
*/
private static void sendWarDeclaration(List<ClanEntry> players) {
Location check = Location.create(3272, 3682, 0);
for (ClanEntry e : players) {
Player p = e.getPlayer();
if (p.getLocation().withinDistance(check, 128)) {
p.getPacketDispatch().sendMessage("<col=ff0000>Your clan has been challenged to a clan war!");
p.getPacketDispatch().sendMessage("<col=ff0000>Step through the purple portal in the Challenge Hall.");
p.getPacketDispatch().sendMessage("<col=ff0000>Battle will commence in 2 minutes.");
}
}
}
@Override
public void configure() {
setZoneType(ZoneType.SAFE.getId());
DynamicRegion[] regions = DynamicRegion.create(new ZoneBorders(3264, 3712, 3328, 3840));
setRegionBase(regions);
int x = base.getX();
int y = base.getY() + 20;
RegionZone multi = new RegionZone(MultiwayCombatZone.getInstance(), new ZoneBorders(x, y, x + 63, y + 88));
for (DynamicRegion r : regions) {
r.setMulticombat(true);
r.getRegionZones().add(multi);
r.setRegionTimeOut(250);
r.setMusicId(442);
}
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return new ClanWarsActivityPlugin();
}
/**
* Gets the ticks.
* @return The ticks.
*/
public int getTicks() {
return ticks;
}
/**
* Sets the ticks.
* @param ticks The ticks to set.
*/
public void setTicks(int ticks) {
this.ticks = ticks;
}
}
@@ -0,0 +1,98 @@
package core.game.content.activity.clanwars;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.node.object.GameObject;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.map.zone.impl.WildernessZone;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.PluginManager;
/**
* Handles the clan wars challenge room.
* @author Emperor
*/
@Initializable
public final class ClanWarsChallengeRoom extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code ClanWarsChallengeRoom} {@code Object}.
*/
public ClanWarsChallengeRoom() {
super("clan wars cr", true, ZoneRestriction.RANDOM_EVENTS);
}
@Override
public void configure() {
register(new ZoneBorders(3264, 3672, 3279, 3695));
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player p = (Player) e;
p.getSkullManager().setWildernessDisabled(true);
p.getSkullManager().setWilderness(false);
p.getInterfaceManager().closeOverlay();
p.getInteraction().remove(Option._P_ASSIST);
p.getInteraction().set(CWChallengeOption.OPTION);
}
return super.enter(e);
}
@Override
public boolean leave(final Entity e, final boolean logout) {
if (e instanceof Player) {
Player p = (Player) e;
p.getSkullManager().setWildernessDisabled(false);
p.getInteraction().remove(CWChallengeOption.OPTION);
p.getInteraction().set(Option._P_ASSIST);
if (WildernessZone.isInZone(e)) {
WildernessZone.show(p);
p.getSkullManager().setWilderness(true);
}
}
return super.leave(e, logout);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (target instanceof GameObject) {
GameObject object = (GameObject) target;
Player player = (Player) e;
if (object.getId() == 28213) {
if (player.getCommunication().getClan() == null) {
player.getPacketDispatch().sendMessage("You have to be in a clan to enter this portal.");
} else if (player.getCommunication().getClan().isDefault()) {
player.sendMessage("You can't use the main clan chat for this.");
return true;
} else if (player.getCommunication().getClan().getClanWar() == null) {
player.getPacketDispatch().sendMessage("Your clan has to be in a war.");
} else {
player.getCommunication().getClan().getClanWar().fireEvent("join", player);
}
return true;
}
}
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
PluginManager.definePlugin(new CWChallengeOption());
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
}
@@ -0,0 +1,39 @@
package core.game.content.activity.duel;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
/**
* Handles the challenge option for dueling.
* @author Vexia
*
*/
public class ChallengeOptionPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
DuelArenaActivity.CHALLENGE_OPTION.setHandler(this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Player other = (Player) node;
if (other.getInterfaceManager().isOpened() || other.getExtension(DuelSession.class) != null) {
player.getPacketDispatch().sendMessage("Other player is busy at the moment.");
return true;
}
if (other.getRequestManager().getTarget() == player && other.getAttribute("duel:partner") == player) {
player.getRequestManager().request(other, other.getAttribute("duel:staked", false) ? DuelArenaActivity.STAKE_REQUEST : DuelArenaActivity.FRIEND_REQUEST);
return true;
}
player.getInterfaceManager().open(DuelArenaActivity.DUEL_TYPE_SELECT);
player.setAttribute("duel:staked", false);
player.setAttribute("duel:partner", other);
player.getConfigManager().set(283, 1 << 26);
return true;
}
}
@@ -0,0 +1,595 @@
package core.game.content.activity.duel;
import java.util.ArrayList;
import java.util.List;
import core.ServerConstants;
import core.cache.def.impl.ObjectDefinition;
import core.game.container.Container;
import core.game.container.impl.EquipmentContainer;
import core.game.content.dialogue.DialogueAction;
import core.game.node.entity.skill.summoning.familiar.Familiar;
import core.game.interaction.Option;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.item.GroundItem;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneRestriction;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import core.tools.StringUtils;
/**
* Represents a dueling area.
* @author Vexia
*
*/
public class DuelArea extends MapZone {
/**
* The respawn locations.
*/
public static final Location[] RESPAWN_LOCATIONS = new Location[] { Location.create(3371, 3275, 0), Location.create(3365, 3276, 0), Location.create(3366, 3274, 0), Location.create(3369, 3274, 0), Location.create(3372, 3275, 0), Location.create(3372, 3266, 0), Location.create(3371, 3269, 0), Location.create(3376, 3270, 0), Location.create(3376, 3273, 0), Location.create(3377, 3275, 0) };
/**
* The zone borders set for the area.
*/
private final ZoneBorders border;
/**
* If this area has obstacles.
*/
private final boolean obstacles;
/**
* The center location to determine starting points.
*/
private final Location center;
/**
* The fight option.
*/
private static final Option FIGHT_OPTION = new Option("Fight", 0).setHandler(new OptionHandler() {
@Override
public boolean handle(Player player, Node node, String option) {
player.getPulseManager().clear("interaction:attack:" + node.hashCode());
player.getProperties().getCombatPulse().attack(node);
return true;
}
@Override
public boolean isWalk() {
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
return this;
}
@Override
public boolean isDelayed(Player player) {
return false;
}
});
/**
* Constructs a new {@Code DuelArea} {@Code Object}
*/
public DuelArea() {
this(-1, null, false, null);
}
/**
* Constructs a new {@Code DuelArea} {@Code Object}
* @param index the index.
* @param border the border.
* @param obstacles if there is obstacles.
*/
public DuelArea(int index, ZoneBorders border, boolean obstacles, Location center) {
super("Duel Area - " + index, true, ZoneRestriction.FIRES, ZoneRestriction.CANNON, ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.FOLLOWERS);
this.obstacles = obstacles;
this.border = border;
this.center = center;
}
/**
* Starts a duel between two players.
* @param session the session.
*/
public void duel(final DuelSession session) {
Location[] locations = getStartLocations(session);
session.getPlayer().teleport(locations[0]);
session.getOther().teleport(locations[1]);
session.getPlayer().getInterfaceManager().close();
session.getPlayer().getInterfaceManager().restoreTabs();
session.getOther().getInterfaceManager().close();
session.getOther().getInterfaceManager().restoreTabs();
session.getPlayer().setAttribute("duel:icon", HintIconManager.registerHintIcon(session.getPlayer(), session.getOther()));
session.getOther().setAttribute("duel:icon", HintIconManager.registerHintIcon(session.getOther(), session.getPlayer()));
session.getPlayer().setAttribute("duel:ammo", new ArrayList<GroundItem>());
session.getOther().setAttribute("duel:ammo", new ArrayList<GroundItem>());
session.getPlayer().setAttribute("vengeance", false);
session.getOther().setAttribute("vengeance", false);
GameWorld.getPulser().submit(new Pulse(4, session.getPlayer(), session.getOther()) {
int count;
@Override
public boolean pulse() {
String chat = count < 3 ? String.valueOf(3 - count) : "FIGHT!";
session.getPlayer().sendChat(chat);
session.getOther().sendChat(chat);
return count++ >= 3;
}
@Override
public void stop() {
super.stop();
if (session.getPlayer().isActive() && session.getOther().isActive() && session.getFightState() != 2) {
session.setFightState(1);
session.getPlayer().getSkullManager().setSkullCheckDisabled(true);
session.getPlayer().getSkullManager().setWilderness(true);
session.getOther().getSkullManager().setSkullCheckDisabled(true);
session.getOther().getSkullManager().setWilderness(true);
session.getPlayer().getProperties().setMultiZone(true);
session.getOther().getProperties().setMultiZone(true);
}
}
});
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (!e.isPlayer()) {
return true;
}
Player p = e.asPlayer();
final DuelSession session = getSession(p);
if (session == null) {
return true;
}
if (option.getName().equalsIgnoreCase("eat") && session.hasRule(DuelRule.NO_FOOD)) {
p.sendMessage("You can't eat in this fight.");
return true;
}
if (option.getName().equalsIgnoreCase("drink") && session.hasRule(DuelRule.NO_DRINKS)) {
p.sendMessage("You can't drink in this fight.");
return true;
}
if (option.getName().equalsIgnoreCase("wield") || option.getName().equalsIgnoreCase("wear") && target instanceof Item) {
if (session.isRestrictedEquipment(target.asItem())) {
p.sendMessage("You can't equip that during this duel.");
return true;
}
}
if (option.getName().equalsIgnoreCase("Summon") && !session.hasRule(DuelRule.ENABLE_SUMMONING)) {
p.sendMessage("You cannot summon familiars whilst in a duel.");
return true;
}
if (option.getName().equalsIgnoreCase("drop") && target instanceof Item) {
p.sendMessage("You cannot drop items whilst in a duel.");
return true;
}
switch (target.getId()) {
case 3203:
handleForfeit(p);
return true;
}
return super.interact(e, target, option);
}
@Override
public boolean move(Entity entity, Location from, Location to) {
if (entity.isPlayer()) {
Player p = entity.asPlayer();
DuelSession session = getSession(p);
if (session == null) {
return false;
}
return !session.hasRule(DuelRule.NO_MOVEMENT);
}
return super.move(entity, from, to);
}
@Override
public boolean actionButton(Player player, int interfaceId, int buttonId, int slot, int itemId, int opcode) {
DuelSession session = getSession(player);
if (session == null) {
return true;
}
WeaponInterface inter = player.getExtension(WeaponInterface.class);
if (inter != null && interfaceId == inter.getId()) {
switch (buttonId) {
case 8:
case 10:
if (session.hasRule(DuelRule.NO_SPECIAL_ATTACKS)) {
player.sendMessage("You can't use special attacks during a duel.");
return true;
}
break;
}
}
switch (interfaceId) {
case 182:
player.sendMessage("You can't logout during a duel.");
return true;
case 271:
if (session.hasRule(DuelRule.NO_PRAYER)) {
player.getPrayer().toggle(PrayerType.get(buttonId));
player.getPrayer().toggle(PrayerType.get(buttonId));
player.sendMessage("Use of prayer has been turned off for this duel.");
return true;
}
break;
case 430:
if (session.hasRule(DuelRule.NO_MAGIC)) {
player.sendMessage("Use of prayer has been turned off for this duel.");
return true;
}
break;
}
return super.actionButton(player, interfaceId, buttonId, slot, itemId, opcode);
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e.isPlayer() && target instanceof Player && !checkAttack(e.asPlayer(), ((Player) target))) {
return false;
}
if (e instanceof Familiar && target instanceof Player) {
Familiar f = (Familiar) e;
Player o = f.getOwner();
if (o != null && target.asPlayer() != getSession(o).getOpposite(o)) {
return false;
}
}
if (e instanceof Familiar && target instanceof Familiar) {
Familiar f = (Familiar) e;
Familiar t = (Familiar) target;
if (getSession(f.getOwner()).getOpposite(f.getOwner()) != t.getOwner()) {
return false;
}
}
if (e.isPlayer()) {
Player p = e.asPlayer();
DuelSession session = getSession(p);
if (session == null) {
return false;
}
boolean canAttack = true;
switch (style) {
case MAGIC:
canAttack = !session.hasRule(DuelRule.NO_MAGIC);
break;
case MELEE:
canAttack = !session.hasRule(DuelRule.NO_MELEE);
break;
case RANGE:
canAttack = !session.hasRule(DuelRule.NO_RANGE);
break;
}
if (!canAttack) {
p.sendMessage(StringUtils.formatDisplayName(style.name().toLowerCase()) + " has been turned off for this duel.");
return false;
}
if (session.hasRule(DuelRule.FUN_WEAPONS) && (p.getEquipment().get(EquipmentContainer.SLOT_WEAPON) == null || !p.getEquipment().get(EquipmentContainer.SLOT_WEAPON).getDefinition().getConfiguration("fun_weapon", false))) {
p.sendMessages("This is a 'fun weapon' duel. You can only use flowers, basket of eggs, or a", "rubber chicken.");
return false;
}
if (target instanceof Familiar) {
Familiar f = (Familiar) target;
if (f.getOwner() != null && getSession(p).getOpposite(p) != f.getOwner()) {
p.sendMessage("You can't attack that familiar.");
return false;
}
}
}
return true;
}
@Override
public boolean teleport(Entity e, int type, Node node) {
if (e.isPlayer()) {
e.asPlayer().getDialogueInterpreter().sendDialogue("Coward! You can't teleport from a duel.");
}
return false;
}
@Override
public boolean enter(Entity e) {
if (e.isPlayer()) {
getSession(e.asPlayer());
e.getProperties().setSafeZone(true);
e.getProperties().setSpawnLocation(RandomFunction.getRandomElement(RESPAWN_LOCATIONS));
e.asPlayer().getInteraction().remove(DuelArenaActivity.CHALLENGE_OPTION);
e.asPlayer().getInteraction().set(FIGHT_OPTION);
} else if (e instanceof Familiar) {
Familiar f = (Familiar) e;
Player o = f.getOwner();
if (o != null && !o.getFamiliarManager().hasPet()) {
DuelSession s = getSession(f.getOwner());
if (s != null && s.hasRule(DuelRule.ENABLE_SUMMONING)) {
f.transform();
}
}
f.getProperties().setMultiZone(true);
}
return super.enter(e);
}
@SuppressWarnings("deprecation")
@Override
public boolean leave(Entity entity, boolean logout) {
entity.getProperties().setSafeZone(false);
if (entity instanceof Player) {
Player p = entity.asPlayer();
if (logout) {
p.setLocation(RandomFunction.getRandomElement(RESPAWN_LOCATIONS));
}
p.lock(1);
leave(p);
DuelSession session = getSession(p);
if (session == null) {
return true;
}
session.leave(p, logout ? 1 : p.getAttribute("duel:forfeit", false) ? 0 : 2);
remove(session.getOpposite(p));
leave(session.getOpposite(p));
} else if (entity instanceof Familiar) {
Familiar familiar = (Familiar) entity;
if (familiar.isCombatFamiliar()) {
familiar.reTransform();
}
familiar.getProperties().setMultiZone(false);
}
return super.leave(entity, logout);
}
@Override
public void configure() {
register(border);
}
/**
* Handles the leaving of a player.
* @param p the player.
*/
private void leave(Player p) {
if (p.getAttribute("duel:ammo", null) != null) {
List<GroundItem> ammo = p.getAttribute("duel:ammo");
Container c = new Container(40);
for (GroundItem item : ammo) {
if (item == null) {
continue;
}
if (item.isActive() && GroundItemManager.getItems().contains(item) && item.droppedBy(p)) {
GroundItemManager.destroy(item);
c.add(item);
}
}
p.getInventory().addAll(c);
}
p.getInteraction().remove(FIGHT_OPTION);
p.getSkullManager().setSkullCheckDisabled(false);
p.getSkullManager().setWilderness(false);
p.getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
p.getProperties().setMultiZone(false);
p.getInteraction().set(DuelArenaActivity.CHALLENGE_OPTION);
}
/**
* Forcefully removes a player.
* @param player the player.
*/
private static void remove(Player player) {
HintIconManager.removeHintIcon(player, player.getAttribute("duel:icon", -1));
if (player.getExtension(DuelSession.class) != null) {
player.teleport(RandomFunction.getRandomElement(RESPAWN_LOCATIONS));
}
}
/**
* Handles the forfeit trapdoor.
* @param p the player.
*/
public static void handleForfeit(Player p) {
DuelSession session = getSession(p);
if (session == null) {
return;
}
if (session.getFightState() != 1) {
p.sendMessage("The duel has not started yet!");
return;
}
if (session.hasRule(DuelRule.NO_FORFEIT)) {
p.getDialogueInterpreter().sendDialogue("Forfeit has been turned off for this duel.");
return;
}
p.getDialogueInterpreter().sendOptions("Do you wish to forfeit?", "Yes", "No");
p.getDialogueInterpreter().addAction(new DialogueAction() {
@Override
public void handle(Player player, int buttonId) {
if (buttonId == 2) {
remove(player);
player.setAttribute("duel:forfeit", true);
}
}
});
}
/**
* Gets the starting locations for the session.
* @param session the session.
* @return the locations.
*/
public Location[] getStartLocations(DuelSession session) {
Location start = null;
Location[] locations = new Location[2];
while (start == null) {
start = center.transform(RandomFunction.random(10), RandomFunction.random(session.hasRule(DuelRule.NO_MOVEMENT) ? 6 : 10), 0);
if (isValidLocation(start)) {
locations[locations[0] == null ? 0 : 1] = start;
if (session.hasRule(DuelRule.NO_MOVEMENT)) {
Location l = null;
if (!isValidLocation(l = start.transform(1, 0, 0))) {
if (!isValidLocation(l = start.transform(-1, 0, 0))) {
if (!isValidLocation(l = start.transform(1, 0, 0))) {
if (!isValidLocation(l = start.transform(-1, 0, 0))) {
locations[1] = start;
break;
}
}
}
}
start = l;
locations[1] = l;
break;
}
start = locations[1] == null ? null : start;
} else {
start = null;
}
}
return locations;
}
@Override
public boolean startDeath(Entity entity, Entity killer) {
if (entity instanceof Player) {
Player k = killer instanceof Player ? killer.asPlayer() : killer instanceof Familiar ? ((Familiar) killer).getOwner() : null;
if (k != null) {
k.getImpactHandler().setDisabledTicks(10);
k.getSkills().heal(100);
k.lock(5);
}
}
return true;
}
@Override
public boolean death(Entity e, Entity killer) {
if (e.isPlayer() && (killer.isPlayer() || killer instanceof Familiar)) {
Player k = killer instanceof Familiar ? ((Familiar) killer).getOwner() : killer.asPlayer();
if (k != null) {
k.getSkills().heal(100);
PulseManager.cancelDeathTask(e);
}
}
return super.death(e, killer);
}
/**
* Checks if the location is valid to start on.
* @param location the location.
* @return {@code True} if so.
*/
public boolean isValidLocation(Location location) {
return RegionManager.isTeleportPermitted(location) && RegionManager.getObject(location) == null;
}
/**
* Checks the attack of a player.
* @param player the player.
* @param target the target.
* @return {@code True} if so.
*/
public boolean checkAttack(Player player, Player target) {
DuelSession session = getSession(player);
if (session == null) {
return false;
}
if (session.getOpposite(player) != target) {
player.sendMessage("You can only attack your opponent!");
return false;
}
if (session.getFightState() != 1) {
player.sendMessage("You can't attack yet!");
return false;
}
return true;
}
/**
* Gets the duel session for the player.
* @param player the player.
* @return the duel session.
*/
public static DuelSession getSession(Player player) {
DuelSession session = player.getExtension(DuelSession.class);
if (session == null) {
remove(player);
}
return session;
}
/**
* Gets the obstacles.
* @return the obstacles.
*/
public boolean isObstacles() {
return obstacles;
}
/**
* Gets the border.
* @return the border.
*/
public ZoneBorders getBorder() {
return border;
}
/**
* Gets the center.
* @return the center.
*/
public Location getCenter() {
return center;
}
/**
* Handles the forfeit trapdoor plugin.
* @author Vexia
*
*/
public static class ForfeitTrapdoorPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ObjectDefinition.forId(3203).getHandlers().put("option:forfeit", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
handleForfeit(player);
return true;
}
@Override
public Location getDestination(Node node, Node n) {
Location loc = null;
if (node instanceof Player) {
DuelSession session = getSession(node.asPlayer());
if (session != null && session.hasRule(DuelRule.NO_MOVEMENT)) {
loc = node.getLocation();
}
}
return loc;
}
}
}
@@ -0,0 +1,229 @@
package core.game.content.activity.duel;
import java.util.ArrayList;
import java.util.List;
import core.game.component.Component;
import core.game.content.activity.ActivityPlugin;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.CombatStyle;
import core.game.node.entity.impl.PulseManager;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestType;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Initializable;
import core.plugin.PluginManager;
import core.tools.RandomFunction;
/**
* Handles the Duel Arena activity.
* @author Emperor
* @author Vexia
*
*/
@Initializable
public final class DuelArenaActivity extends ActivityPlugin {
/**
* The friendly duel request.
*/
public static final RequestType FRIEND_REQUEST = new RequestType("Sending duel offer...", ":duelfriend:", new DuelReqModule(false));
/**
* The staked duel request.
*/
public static final RequestType STAKE_REQUEST = new RequestType("Sending duel offer...", ":duelstake:", new DuelReqModule(true));
/**
* The dueling areas.
*/
public static final DuelArea[] DUEL_AREAS = new DuelArea[] { new DuelArea(0, new ZoneBorders(3332, 3244, 3357, 3258), false, Location.create(3345, 3251, 0)), new DuelArea(1, new ZoneBorders(3364, 3244, 3388, 3259), true, Location.create(3378, 3251, 0)), new DuelArea(2, new ZoneBorders(3333, 3224, 3357, 3239), true, Location.create(3345, 3231, 0)), new DuelArea(3, new ZoneBorders(3364, 3225, 3388, 3240), false, Location.create(3376, 3231, 0)), new DuelArea(4, new ZoneBorders(3333, 3205, 3357, 3220), false, Location.create(3346, 3212, 0)), new DuelArea(5, new ZoneBorders(3364, 3206, 3388, 3221), true, Location.create(3377, 3213, 0)) };
/**
* The challenge option.
*/
public static final Option CHALLENGE_OPTION = new Option("Challenge", 0);
/**
* The select duel type component.
*/
public static final Component DUEL_TYPE_SELECT = new Component(640);
/**
* The overlay.
*/
private static final Component OVERLAY = new Component(638);
/**
* The scoreboard.
*/
private static final String[] SCOREBOARD = new String[50];
/**
* Constructs a new {@code DuelArenaActivity} {@code Object}.
*/
public DuelArenaActivity() {
super("Duel arena", false, false, true);
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInterfaceManager().openOverlay(OVERLAY);
player.getInteraction().set(CHALLENGE_OPTION);
player.getConfigManager().set(286, 0);
}
return super.enter(e);
}
@Override
public boolean leave(Entity e, boolean logout) {
if (e instanceof Player) {
Player player = (Player) e;
player.getInterfaceManager().closeOverlay();
player.getInteraction().remove(CHALLENGE_OPTION);
}
return super.leave(e, logout);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return this;
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public boolean continueAttack(Entity e, Node target, CombatStyle style, boolean message) {
if (e.isPlayer() && e.asPlayer().getZoneMonitor().getZones().size() > 1) {
return super.continueAttack(e, target, style, message);
}
return false;
}
@Override
public boolean interact(Entity e, Node target, Option o) {
if (e.isPlayer()) {
switch (target.getId()) {
case 3192:
openScoreboard(e.asPlayer());
return true;
}
}
return super.interact(e, target, o);
}
@Override
public boolean death(Entity e, Entity killer) {
if (e.isPlayer() && e.asPlayer().getZoneMonitor().getZones().size() > 1) {
return true;
}
if (e instanceof Player && killer instanceof Player) {
e.getSkills().heal(100);
PulseManager.cancelDeathTask(e);
return true;
}
return true;
}
@Override
public void configure() {
for (DuelArea area : DUEL_AREAS) {
ZoneBuilder.configure(area);
}
parseScoreboard();
register(new ZoneBorders(3325, 3201, 3396, 3280));
PluginManager.definePlugin(new DuelArea.ForfeitTrapdoorPlugin());
PluginManager.definePlugins(new DuelSession(null, null, false), new DuelComponentPlugin(), new ChallengeOptionPlugin());
}
/**
* Opens the scoreboard.
* @param player the player.
*/
public static void openScoreboard(Player player) {
player.lock(2);
parseScoreboard();
player.getInterfaceManager().open(new Component(632));
int index = 0;
for (int i = 16; i < 65; i++) {
player.getPacketDispatch().sendString(SCOREBOARD[index] == null ? "" : SCOREBOARD[index], 632, i - 1);
index++;
}
}
/**
* Parses the scoreboard data from the database.
*/
public static void parseScoreboard() {
/*Connection connection = SQLManager.getConnection();
if (connection == null) {
return;
}
java.sql.PreparedStatement statement;
try {
statement = connection.prepareStatement("SELECT * FROM duel_scoreboard WHERE id <= 50");
ResultSet set = statement.executeQuery();
while (set.next()) {
SCOREBOARD[set.getInt(1) - 1] = set.getString(2);
}
statement = connection.prepareStatement("DELETE FROM duel_scoreboard WHERE id > 50");
statement.executeUpdate();
} catch (SQLException e) {
SQLManager.close(connection);
e.printStackTrace();
}
SQLManager.close(connection);*/
}
/**
* Inserts an entry into the scoreboard.
* @param winner the winner.
* @param looser the looser.
*/
public static void insertEntry(Player winner, Player looser) {
/*String entry = winner.getUsername() + " (" + winner.getProperties().getCurrentCombatLevel() + ") beat " + looser.getUsername() + " (" + looser.getProperties().getCurrentCombatLevel() + ")";
Connection connection = SQLManager.getConnection();
if (connection == null) {
return;
}
java.sql.PreparedStatement statement;
try {
statement = connection.prepareStatement("UPDATE duel_scoreboard SET id = ID + 1");
statement.executeUpdate();
statement = connection.prepareStatement("INSERT INTO duel_scoreboard (id,entry) VALUES(?,?)");
statement.setInt(1, 1);
statement.setString(2, entry);
statement.executeUpdate();
} catch (SQLException e) {
SQLManager.close(connection);
e.printStackTrace();
}
SQLManager.close(connection);*/
}
/**
* Gets the dueling area.
* @param obstacles if we're using obstacles.
* @return {@code DuelArea} the area.
*/
public static DuelArea getDuelArea(boolean obstacles) {
List<DuelArea> options = new ArrayList<>();
for (DuelArea area : DUEL_AREAS) {
if (!obstacles && area.isObstacles() || obstacles && !area.isObstacles()) {
continue;
}
options.add(area);
}
return options.get(RandomFunction.random(options.size()));
}
}
@@ -0,0 +1,69 @@
package core.game.content.activity.duel;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
import core.plugin.Plugin;
/**
* Handles the duel arena components.
* @author Vexia
*
*/
public class DuelComponentPlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(640).setPlugin(this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 640:
boolean staked = false;
switch (button) {
case 20:
Player other = player.getAttribute("duel:partner");
if (other == null || other.getExtension(DuelSession.class) != null) {
player.getPacketDispatch().sendMessage("Other player is busy at the moment.");
return true;
}
if (player.getAttribute("duel:staked", false) && other.getIronmanManager().isIronman() && !GameWorld.getSettings().isDevMode()) {
other.sendMessage("You can't accept a staked duel as an Ironman.");
player.sendMessage("You can't duel Ironman players.");
return true;
}
player.getInterfaceManager().close();
if (!player.getAttribute("duel:staked", false)) {
player.getRequestManager().request(other, DuelArenaActivity.FRIEND_REQUEST);
} else {
player.getRequestManager().request(other, DuelArenaActivity.STAKE_REQUEST);
}
return true;
case 18:
case 22:
staked = false;
break;
case 19:
case 21:
staked = true;
if (player.getIronmanManager().isIronman()) {
player.sendMessage("You can't stake as an Iron man.");
staked = false;
}
break;
default:
return false;
}
player.setAttribute("duel:staked", staked);
player.getConfigManager().set(283, (staked ? 2 : 1) << 26);
break;
}
return true;
}
}
@@ -0,0 +1,33 @@
package core.game.content.activity.duel;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.request.RequestModule;
/**
* Handles a duel request getting accepted.
* @author Emperor
*/
public final class DuelReqModule implements RequestModule {
/**
* If the duel request is staked.
*/
private boolean staked;
/**
* Constructs a new {@code DuelReqModule} {@code Object}.
* @param staked If the duel is staked.
*/
public DuelReqModule(boolean staked) {
this.staked = staked;
}
@Override
public void open(Player player, Player target) {
DuelSession session = new DuelSession(player, target, staked);
player.addExtension(DuelSession.class, session);
target.addExtension(DuelSession.class, session);
session.openRules();
}
}
@@ -0,0 +1,80 @@
package core.game.content.activity.duel;
import core.game.container.impl.EquipmentContainer;
/**
* Represents a dueling rule.
* @author Emperor
*/
public enum DuelRule {
NO_RANGE(4, "You cannot use Ranged attacks."), NO_MELEE(5, "You cannot use Melee attacks."), NO_MAGIC(6, "You cannot use Magic attacks."), FUN_WEAPONS(12, "You can only attack with 'fun' weapons."), NO_FORFEIT(0, "You cannot forfeit the duel."), NO_DRINKS(7, "You cannot use potions."), NO_FOOD(8, "You cannot use food."), NO_PRAYER(9, "You cannot use Prayer."), NO_MOVEMENT(1, "You cannot move."), OBSTACLES(10, "There will be obstacles in the arena."), ENABLE_SUMMONING(28, "Familiars will be allowed in the arena."), NO_SPECIAL_ATTACKS(13, "You cannot use special attacks."), NO_HATS(14, "", EquipmentContainer.SLOT_HAT), NO_CAPES(15, "", EquipmentContainer.SLOT_CAPE), NO_AMULET(16, "", EquipmentContainer.SLOT_AMULET), NO_WEAPON(17, "You can't use 2H weapons such as bows.", EquipmentContainer.SLOT_WEAPON), NO_SHIELD(19, "You can't use 2H weapons such as bows.", EquipmentContainer.SLOT_SHIELD), NO_BODY(18, "", EquipmentContainer.SLOT_CHEST), NO_LEGS(21, "", EquipmentContainer.SLOT_LEGS), NO_GLOVES(23, "", EquipmentContainer.SLOT_HANDS), NO_RINGS(26, "", EquipmentContainer.SLOT_RING), NO_BOOTS(24, "", EquipmentContainer.SLOT_FEET), NO_ARROWS(27, "", EquipmentContainer.SLOT_ARROWS);
/**
* The config index.
*/
private final int configIndex;
/**
* The information to display on the second screen.
*/
private final String info;
/**
* The equpment slot.
*/
private int equipmentSlot = -1;
/**
* Constructs a new {@code DuelRule} {@code Object}.
* @param configIndex The config index.
* @param info the info for the second screen.
*/
private DuelRule(int configIndex, String info) {
this.configIndex = configIndex;
this.info = info;
}
/**
* Constructs a new {@code DuelRule} {@code Object}.
* @param configIndex The config index.
* @param info the info for the second screen.
* @param equipmentSlot the equipment slot.
*/
private DuelRule(int configIndex, String info, int equipmentSlot) {
this.configIndex = configIndex;
this.info = info;
this.equipmentSlot = equipmentSlot;
}
/**
* Gets the configIndex.
* @return The configIndex.
*/
public int getConfigIndex() {
return configIndex;
}
/**
* Gets the info.
* @return The info.
*/
public String getInfo() {
return info;
}
/**
* Gets the equipmentSlot.
* @return the equipmentSlot.
*/
public int getEquipmentSlot() {
return equipmentSlot;
}
/**
* Sets the equipmentSlot.
* @param equipmentSlot the equipmentSlot to set
*/
public void setEquipmentSlot(int equipmentSlot) {
this.equipmentSlot = equipmentSlot;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,212 @@
package core.game.content.activity.duel;
import core.game.component.Component;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.container.ContainerType;
import core.game.container.SortType;
import core.game.container.access.InterfaceContainer;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.login.PlayerParser;
import core.game.node.item.Item;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
/**
* Represents the staking container.
* @author Vexia
*
*/
public class StakeContainer extends Container {
/**
* The inventory params.
*/
private static final Object[] INVY_PARAMS = new Object[] { "", "", "", "Stake-X", "Stake-All", "Stake-10", "Stake-5", "Stake", -1, 0, 7, 4, 93, (336 << 16) };
/**
* The withdraw options.
*/
private static final String[] WITHDRAW_OPTIONS = new String[] { "Remove-X", "Remove-All", "Remove-10", "Remove-5", "Remove" };
/**
* The overlay interface.
*/
public static final Component OVERLAY = new Component(336);
/**
* The serial version UID.
*/
private static final long serialVersionUID = 3454088488966242754L;
/**
* The player of the container.
*/
private final Player player;
/**
* The dueling session.
*/
private final DuelSession session;
/**
* The stake listener.
*/
private final StakeListener listener;
/**
* If the container has been released.
*/
private boolean released;
/**
* Constructs a new {@Code StakeContainer} {@Code Object}
* @param player the player.
* @param session the session.
*/
public StakeContainer(Player player, DuelSession session) {
super(28, ContainerType.DEFAULT, SortType.ID);
this.player = player;
this.session = session;
this.getListeners().add(listener = new StakeListener());
}
/**
* Opens the staking container.
*/
public void open() {
player.getInterfaceManager().openSingleTab(OVERLAY);
player.getPacketDispatch().sendRunScript(150, "IviiiIssssssss", INVY_PARAMS);
player.getPacketDispatch().sendAccessMask(1278, 0, 336, 0, 27);
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, -1, 2, 93, player.getInventory(), false));
}
/**
* Offers an item to the stake.
* @param slot the slot.
* @param amount the amount.
*/
public void offer(final int slot, int amount) {
final Item item = player.getInventory().get(slot);
if (item == null) {
return;
}
if ((slot < 0 || slot > player.getInventory().capacity() || amount < 1)) {
return;
}
if (!item.getDefinition().isTradeable()) {
player.sendMessage("You can't offer that item.");
return;
}
Item remove = new Item(item.getId(), amount);
if (item.getAmount() > getMaximumAdd(item)) {
item.setAmount(getMaximumAdd(item));
if (item.getAmount() < 1) {
return;
}
}
remove.setAmount(amount > player.getInventory().getAmount(item) ? player.getInventory().getAmount(item) : amount);
if (player.getInventory().remove(remove, slot, true)) {
session.resetAccept();
add(remove);
StakeContainer c = session.getOppositeContainer(player);
c.getListener().update(c, c.getEvent());
}
}
/**
* Withdraws an item from the container.
* @param slot the slot.
* @param amount the amount.
*/
public void withdraw(final int slot, int amount) {
final Item item = get(slot);
if (item == null) {
return;
}
if ((slot < 0 || slot > player.getInventory().capacity() || amount < 1)) {
return;
}
if (!item.getDefinition().isTradeable()) {
player.sendMessage("You can't offer that item.");
return;
}
Item remove = new Item(item.getId(), amount);
if (item.getAmount() > getMaximumAdd(item)) {
item.setAmount(getMaximumAdd(item));
if (item.getAmount() < 1) {
return;
}
}
remove.setAmount(amount > getAmount(item) ? getAmount(item) : amount);
if (remove(remove, slot, true) && player.getInventory().add(remove)) {
session.resetAccept();
shift();
StakeContainer c = session.getOppositeContainer(player);
c.getListener().update(c, c.getEvent());
}
}
/**
* Releases the container back to the player.
*/
public void release() {
if (released) {
return;
}
released = true;
if (!player.getInventory().hasSpaceFor(this)) {
player.getBank().addAll(this);
player.sendMessage("Your stake was sent to your bake due to invalid inventory space.");
return;
}
player.getInventory().addAll(this);
PlayerParser.save(player);
}
/**
* Gets the serialversionuid.
* @return the serialversionuid.
*/
public static long getSerialversionuid() {
return serialVersionUID;
}
/**
* Gets the session.
* @return the session.
*/
public DuelSession getSession() {
return session;
}
/**
* Gets the listener.
* @return the listener.
*/
public StakeListener getListener() {
return listener;
}
/**
* Represents the container listener for a players stake session.
* @author Vexia
*
*/
public final class StakeListener implements ContainerListener {
@Override
public void update(Container c, ContainerEvent event) {
InterfaceContainer.generateItems(player, c.toArray(), WITHDRAW_OPTIONS, 631, 103, 12, 3);
InterfaceContainer.generateItems(player, session.getOppositeContainer(player).toArray(), WITHDRAW_OPTIONS, 631, 104, 12, 3);
}
@Override
public void refresh(Container c) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, -1, 2, 93, player.getInventory(), false));
}
}
}
@@ -0,0 +1,89 @@
package core.game.content.activity.fishingtrawler
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.map.build.DynamicRegion
import core.game.world.map.zone.ZoneRestriction
import core.plugin.Initializable
import core.tools.ticksToSeconds
import core.game.content.activity.ActivityManager
import core.game.content.activity.ActivityPlugin
import core.tools.stringtools.colorize
/**
* Handles the fishing trawler "waiting room"
* @author Ceikry
*/
private val WAIT_TIME = if(GameWorld.settings?.isDevMode == true) 10 else 203
private val waitingPlayers = ArrayList<Player>()
private val sessions = ArrayList<FishingTrawlerSession>()
private var activity: FishingTrawlerActivity? = null
private var nextStart = GameWorld.ticks + WAIT_TIME
@Initializable
class FishingTrawlerActivity : ActivityPlugin("fishing trawler",false,false,true,ZoneRestriction.CANNON,ZoneRestriction.FIRES,ZoneRestriction.FOLLOWERS,ZoneRestriction.RANDOM_EVENTS) {
init {
activity = this
}
override fun configure() {
GameWorld.Pulser.submit(
object : Pulse(1){
override fun pulse(): Boolean {
if((nextStart - GameWorld.ticks) % 100 == 0){
for(player in waitingPlayers) {
player.sendMessage (colorize("%R${ticksToSeconds(nextStart - GameWorld.ticks) / 60} minutes until next game."))
}
}
if(GameWorld.ticks >= nextStart && waitingPlayers.isNotEmpty()){
val session = FishingTrawlerSession(DynamicRegion.create(8011), activity!!)
session.start(waitingPlayers)
sessions.add(session)
waitingPlayers.clear()
nextStart = GameWorld.ticks + WAIT_TIME
}
sessions.removeIf { session ->
if(!session.isActive && session.inactiveTicks >= 100){
session.clearNPCs()
true
} else {
if(!session.isActive) {
session.inactiveTicks++
}
false
}
}
return false
}
})
}
override fun start(player: Player?, login: Boolean, vararg args: Any?): Boolean {
player ?: return false
waitingPlayers.add(player)
return true
}
fun addPlayer(player: Player){
if(waitingPlayers.isEmpty()) {
nextStart = GameWorld.ticks + WAIT_TIME
player.dialogueInterpreter.sendDialogue("Trawler will leave in 2 minutes.","If you have a team get them on board now!")
}
waitingPlayers.add(player)
}
fun removePlayer(player: Player){
waitingPlayers.remove(player)
}
override fun newInstance(p: Player?): ActivityPlugin {
ActivityManager.register(this)
return this
}
override fun getSpawnLocation(): Location {
return Location.create(2667, 3161, 0)
}
}
@@ -0,0 +1,241 @@
package core.game.content.activity.fishingtrawler
import core.cache.def.impl.ItemDefinition
import core.cache.def.impl.ObjectDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.player.info.stats.FISHING_TRAWLER_LEAKS_PATCHED
import core.game.node.entity.player.info.stats.STATS_BASE
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import core.tools.Items
import core.game.content.activity.ActivityManager
import core.game.content.dialogue.DialoguePlugin
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.skill.Skills
import core.tools.stringtools.colorize
import kotlin.math.ceil
/**
* Option handler for fishing trawler
* @author Ceikry
*/
@Initializable
class FishingTrawlerOptionHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ObjectDefinition.forId(2178).handlers["option:cross"] = this
ObjectDefinition.forId(2167).handlers["option:fill"] = this
ObjectDefinition.forId(2164).handlers["option:inspect"] = this
ObjectDefinition.forId(2165).handlers["option:inspect"] = this
ObjectDefinition.forId(2166).handlers["option:inspect"] = this
ObjectDefinition.forId(2160).handlers["option:climb-on"] = this
ObjectDefinition.forId(2159).handlers["option:climb-on"] = this
ObjectDefinition.forId(2179).handlers["option:cross"] = this
ObjectDefinition.forId(255).handlers["option:operate"] = this
ItemDefinition.forId(583).handlers["option:bail-with"] = this
ItemDefinition.forId(585).handlers["option:empty"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
when(node?.id){
2178 -> { //Cross plank onto boat
if(player.skills.getLevel(Skills.FISHING) < 15){
player.dialogueInterpreter.sendDialogue("You need to be at least level 15 fishing to play.")
return true
}
player.properties.teleportLocation = Location.create(2672, 3170, 1)
(ActivityManager.getActivity("fishing trawler") as FishingTrawlerActivity).addPlayer(player)
}
2167 -> { //Fill hole
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
session ?: return false
player.lock()
player.pulseManager.run(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(827)).also { player.lock() }
1 -> session.repairHole(player,node.asObject()).also { player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_LEAKS_PATCHED"); player.unlock() }
2 -> return true
}
return false
}
})
}
2164,2165 -> { //inspect net
player.dialogueInterpreter.open(18237583)
}
2166 -> { //inspect reward net
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
if(session == null || session.boatSank){
player.dialogueInterpreter.sendDialogues(player, FacialExpression.GUILTY,"I'd better not go stealing other people's fish.")
return true
}
player.dialogueInterpreter.open(18237582)
}
2179 -> { //plank from boat to dock
player.properties.teleportLocation = Location.create(2676, 3170, 0)
(ActivityManager.getActivity("fishing trawler") as FishingTrawlerActivity).removePlayer(player)
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
session?.players?.remove(player)
player.logoutPlugins.clear()
}
2159,2160 -> { //barrel
player.properties.teleportLocation = Location.create(2672, 3222, 0)
player.dialogueInterpreter.sendDialogue("You climb onto the floating barrel and begin to kick your way to the","shore.","You make it to the shore tired and weary.")
player.logoutPlugins.clear()
player.appearance.setDefaultAnimations()
player.appearance.sync()
}
583 -> { //bail-with bucket
val session: FishingTrawlerSession? = player.getAttribute("ft-session",null)
session ?: return false
if(!session.isActive){
return false
}
if(player.location.y > 0){
player.sendMessage("You can't scoop water out up here.")
return true
}
player.lock()
player.pulseManager.run(
object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(4471))
1 -> if(player.inventory.remove(node.asItem())) {
if (session.waterAmount > 0) {
session.waterAmount -= 20
if (session.waterAmount < 0) session.waterAmount = 0
player.inventory.add(Item(Items.BAILING_BUCKET_585))
} else {
player.sendMessage("There's no water to remove.")
player.inventory.add(node.asItem())
}
}
2 -> player.unlock().also { return true }
}
return false
}
}
)
}
585 -> { //Empty bailing bucket
player.lock()
player.pulseManager.run(
object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(2450))
1 -> {
if(player.inventory.remove(node.asItem()))
player.inventory.add(Item(Items.BAILING_BUCKET_583))
player.unlock()
return true
}
}
return false
}
}
)
}
255 -> {//operate winch
player.sendMessage("It seems the winch is jammed - I can't move it.")
}
}
return true
}
}
@Initializable
class NetLootDialogue(player: Player? = null): DialoguePlugin(player){
var session: FishingTrawlerSession? = null
var rolls = 0
override fun newInstance(player: Player?): DialoguePlugin {
return NetLootDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
session = player.getAttribute("ft-session",null)
if(session == null) return false
rolls = ceil(session!!.fishAmount / session!!.players.size.toDouble()).toInt()
player.dialogueInterpreter.sendOptions("Skip Junk Items?","Yes","No")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(buttonId){
1 -> TrawlerLoot.getLoot(rolls,true).forEach {
if(!player.bank.add(it)) GroundItemManager.create(it,player)
}
2 -> TrawlerLoot.getLoot(rolls,false).forEach {
if(!player.bank.add(it)) GroundItemManager.create(it,player)
}
}
player.sendMessage(colorize("%RYour reward has been sent to your bank."))
player.skills.addExperience(Skills.FISHING,(((0.015 * player.skills.getLevel(Skills.FISHING))) * player.skills.getLevel(Skills.FISHING)) * rolls)
player.removeAttribute("ft-session")
end()
return true
}
override fun getIds(): IntArray {
return intArrayOf(18237582)
}
}
@Initializable
class NetRepairDialogue(player: Player? = null) : DialoguePlugin(player){
var session: FishingTrawlerSession? = null
override fun newInstance(player: Player?): DialoguePlugin {
return NetRepairDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
session = player.getAttribute("ft-session",null)
if(session!!.netRipped){
player.dialogueInterpreter.sendDialogue("The net is ripped and needs repair.")
stage = 10
} else {
player.dialogueInterpreter.sendDialogue("The net is in perfect condition")
stage = 0
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
session ?: return false
when(stage++){
0 -> end()
10 -> player.dialogueInterpreter.sendOptions("Repair the net?","Yes","No")
11 -> when(buttonId){
1 -> {
end()
session!!.repairNet(player)
}
else -> {}
}
12 -> end()
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(18237583)
}
}
@@ -0,0 +1,26 @@
package core.game.content.activity.fishingtrawler
import core.game.node.entity.player.Player
private const val configIndex = 391
private const val interfaceID = 366
private const val netOkayChild = 27
private const val netRippedChild = 28
private const val fishChild = 29
private const val timeChild = 30
/**
* Handles updating the fishing trawler overlay interface
* @author Ceikry
*/
object FishingTrawlerOverlay {
@JvmStatic
fun sendUpdate(player: Player, waterPercent: Int, NetRipped: Boolean, fishCaught: Int, timeLeft: Int){
player.configManager.set(configIndex,waterPercent)
player.packetDispatch.sendInterfaceConfig(interfaceID,if(NetRipped) netRippedChild else netOkayChild, false)
player.packetDispatch.sendInterfaceConfig(interfaceID,if(NetRipped) netOkayChild else netRippedChild, true)
player.packetDispatch.sendString("${if(fishCaught > 0) fishCaught else "Nothing"}",interfaceID,fishChild)
player.packetDispatch.sendString("$timeLeft Minutes", interfaceID, timeChild)
}
}
@@ -0,0 +1,42 @@
package core.game.content.activity.fishingtrawler
import core.game.component.Component
import core.game.component.ComponentDefinition
import core.game.component.ComponentPlugin
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Plugin
import kotlin.math.ceil
/**
* THIS will have to be implemented at a later date.
* Interface 367 in our cache, for whatever reason, opens correctly but all the children
* are null or cant hold items. This interface cant even be opened in 2 different versions
* of a cache editor I have. Something is completely fucked about this interface
* in particular.
*/
class FishingTrawlerRewardInterface : ComponentPlugin() {
override fun newInstance(arg: Any?): Plugin<Any> {
ComponentDefinition.put(367,this)
return this
}
override fun open(player: Player?, component: Component?) {
super.open(player, component)
val session: FishingTrawlerSession? = player?.getAttribute("ft-session",null)
session ?: return
val numRolls = ceil(session.fishAmount / session.players.size.toDouble()).toInt()
player?.removeAttribute("ft-session")
val loot = ArrayList<Item>()
for(i in 0 until numRolls){
}
}
override fun handle(player: Player?, component: Component?, opcode: Int, button: Int, slot: Int, itemId: Int): Boolean {
TODO("Not yet implemented")
}
}
@@ -0,0 +1,279 @@
package core.game.content.activity.fishingtrawler
import core.game.component.Component
import core.game.node.`object`.GameObject
import core.game.node.`object`.ObjectBuilder
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.info.stats.FISHING_TRAWLER_GAMES_WON
import core.game.node.entity.player.info.stats.FISHING_TRAWLER_SHIPS_SANK
import core.game.node.entity.player.info.stats.STATS_BASE
import core.game.node.entity.state.EntityState
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.map.build.DynamicRegion
import core.game.world.update.flag.context.Animation
import core.plugin.Plugin
import core.tools.Items
import core.tools.RandomFunction
import core.tools.secondsToTicks
import core.tools.ticksToSeconds
import java.util.concurrent.TimeUnit
import kotlin.random.Random
/**
* Handles a fishing trawler session
* @author Ceikry
*/
private const val OVERLAY_ID = 366
private const val TUTORIAL_ID = 368
private val HOLE_X_COORDS = intArrayOf(29,30,31,32,33,34,35,36)
private const val HOLE_NORTH_Y = 26
private const val HOLE_SOUTH_Y = 23
private const val LEAKING_ID = 2167
private const val PATCHED_ID = 2168
class FishingTrawlerSession(var region: DynamicRegion, val activity: FishingTrawlerActivity) {
var players: ArrayList<Player> = ArrayList()
var netRipped = false
var fishAmount = 0
var timeLeft = secondsToTicks(600)
var base = region.baseLocation
var isActive = false
var boatSank = false
var hole_locations = ArrayList<Location>()
var used_locations = ArrayList<Location>()
var maxHoles = 0
var waterAmount = 0
var murphy: NPC? = null
val murphyLocations = ArrayList<Location>()
val npcs = ArrayList<NPC>()
var inactiveTicks = 0
fun start(pl: ArrayList<Player>){
this.players.addAll(pl)
isActive = true
initHoles()
initMurphy(29,25)
initGulls()
GameWorld.Pulser.submit(TrawlerPulse(this))
for(player in pl){
player.interfaceManager.openOverlay(Component(OVERLAY_ID))
player.interfaceManager.open(Component(TUTORIAL_ID))
updateOverlay(player)
player.properties.teleportLocation = base.transform(36,24,0)
player.setAttribute("ft-session",this)
player.logoutPlugins.add(TrawlerLogoutPlugin())
player.stateManager.set(EntityState.TELEBLOCK,timeLeft)
}
}
fun swapBoatType(fromRegion: Int){
val newRegion = DynamicRegion.create(fromRegion)
GameWorld.Pulser.submit(SwapBoatPulse(players,newRegion))
}
class SwapBoatPulse(val playerList: ArrayList<Player>,val newRegion: DynamicRegion) : Pulse(3){
override fun pulse(): Boolean {
val session: FishingTrawlerSession? = playerList[0].getAttribute("ft-session",null)
session ?: return true
session.region = newRegion
session.base = newRegion.baseLocation
session.clearNPCs()
session.initMurphy(26,26)
session.initGulls()
for(player in playerList){
player.interfaceManager.closeOverlay()
player.appearance.setAnimations(Animation(188))
player.properties.teleportLocation = session.base.transform(36,24,0)
player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_SHIPS_SANK")
player.stateManager.remove(EntityState.TELEBLOCK)
}
return true
}
}
class TrawlerPulse(val session: FishingTrawlerSession) : Pulse(){
var ticks = 0
override fun pulse(): Boolean {
ticks++
session.timeLeft--
if(session.boatSank){
session.tickMurphy()
return true
}
if(ticks % 15 == 0 && !session.netRipped){
if(RandomFunction.random(100) <= 10){
session.ripNet()
session.murphy?.sendChat("Arrh! Check that net!")
} else {
session.fishAmount += 3
}
}
session.waterAmount += (session.getLeakingHoles())
if(session.waterAmount >= 500){
session.boatSank = true
session.isActive = false
session.swapBoatType(7755)
}
if(RandomFunction.random(100) <= 9){
session.spawnHole()
}
if(session.timeLeft <= 0){
session.isActive = false
for(player in session.players){
player.interfaceManager.closeOverlay()
player.properties.teleportLocation = Location.create(2666, 3162, 0)
player.logoutPlugins.clear()
player.incrementAttribute("/save:$STATS_BASE:$FISHING_TRAWLER_GAMES_WON")
}
}
for(player in session.players){
session.updateOverlay(player)
}
session.tickMurphy()
return !session.isActive
}
}
fun initHoles(){
maxHoles = players.size
if(maxHoles > 16) maxHoles = 16
if(maxHoles < 5) maxHoles = 5
val tempLocationList = ArrayList<Location>()
while(tempLocationList.size < maxHoles){
val x = HOLE_X_COORDS.random()
val y = if(Random.nextBoolean()) HOLE_NORTH_Y else HOLE_SOUTH_Y
val loc = Location.create(x,y,0)
var alreadyHas = false
for(location in tempLocationList){
if(location.equals(loc)) {
alreadyHas = true
break
}
}
if(!alreadyHas) {
tempLocationList.add(base.transform(loc.x, loc.y, 0))
}
}
hole_locations.addAll(tempLocationList)
}
fun initMurphy(localX: Int, localY: Int){
murphy = NPC(463)
murphy?.isWalks = false
murphy?.isPathBoundMovement = true
//29,25 -> 36,25
murphy?.location = base.transform(localX,localY,0)
murphy?.isRespawn = false
for(i in 29..36){
murphyLocations.add(Location.create(base.transform(i,25,0)))
}
murphy?.init()
npcs.add(murphy!!)
}
fun clearNPCs(){
npcs.forEach {
it.clear()
}
npcs.clear()
}
fun tickMurphy(){
var phrase = if(boatSank){
arrayOf("No fishes for you today!","Keep your head above water, shipmate.", "Arrrgh! We sunk!","You'll be joining Davy Jones!").random()
} else if(waterAmount < 200){
arrayOf("Blistering barnacles!","Let's get a net full of fishes!").random()
} else {
arrayOf("We'll all end up in a watery grave!","My mother could bail better than that!","It's a fierce sea today traveller.").random()
}
if(getLeakingHoles() > 0 && RandomFunction.random(100) <= 15){
phrase = "The water is coming in matey!"
}
if(RandomFunction.random(100) <= 10){
murphy?.sendChat(phrase)
}
if(RandomFunction.random(100) <= 6){
val dest = murphyLocations.random()
murphy?.walkingQueue?.reset()
murphy?.walkingQueue?.addPath(dest.x,dest.y,true)
}
}
fun initGulls(){
for(loc in arrayOf(base.transform(38,17,0),base.transform(33,18,0),base.transform(28,16,0),base.transform(28,30,0),base.transform(34,32,0))){
val npc = NPC(1179)
npc.location = loc
npcs.add(npc)
npc.isRespawn = false
npc.isWalks = true
npc.walkRadius = 6
npc.init()
}
}
fun spawnHole(){
if(hole_locations.isEmpty() && used_locations.isEmpty()) return
val holeLocation = hole_locations.random().also { hole_locations.remove(it) }
if(!ObjectBuilder.replace(GameObject(PATCHED_ID, holeLocation), GameObject(LEAKING_ID, holeLocation, if (holeLocation.y == HOLE_NORTH_Y) 1 else 3)) && !ObjectBuilder.replace(GameObject(2177, holeLocation), GameObject(LEAKING_ID, holeLocation, if (holeLocation.y == HOLE_NORTH_Y) 1 else 3))) {
maxHoles -= 1
}
}
fun getLeakingHoles(): Int{
return maxHoles - hole_locations.size
}
fun repairHole(player: Player,obj: GameObject){
if(player.inventory.remove(Item(Items.SWAMP_PASTE_1941))){
ObjectBuilder.replace(obj,GameObject(PATCHED_ID,obj.location,obj.rotation))
hole_locations.add(obj.location)
if(RandomFunction.random(100) <= 30){
murphy?.sendChat("That's the stuff! Fill those holes!")
}
} else {
player.dialogueInterpreter.sendDialogue("You need swamp paste to repair this.")
}
}
fun ripNet(){
netRipped = true
}
fun repairNet(player: Player){
if(player.inventory.remove(Item(Items.ROPE_954))){
netRipped = false
player.dialogueInterpreter.sendDialogue("You repair the net.")
} else {
player.dialogueInterpreter.sendDialogue("You need rope to repair this net.")
}
}
fun updateOverlay(player: Player){
FishingTrawlerOverlay.sendUpdate(player,((waterAmount / 500.0) * 100).toInt(),netRipped,fishAmount,TimeUnit.SECONDS.toMinutes(ticksToSeconds(timeLeft).toLong()).toInt() + 1)
}
}
class TrawlerLogoutPlugin : Plugin<Player>{
override fun newInstance(arg: Player?): Plugin<Player> {
arg?.location = Location.create(2667, 3161, 0)
val session: FishingTrawlerSession? = arg?.getAttribute("ft-session",null)
session ?: return this
session.players.remove(arg)
return this
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit
}
}
@@ -0,0 +1,56 @@
package core.game.content.activity.fishingtrawler
import core.game.node.item.Item
import core.game.node.item.WeightedChanceItem
import core.tools.Items
import core.tools.RandomFunction
/**
* Rolls/stores the loot table for fishing trawler
* @author Ceikry
*/
object TrawlerLoot {
val junkItems = arrayOf(Items.BROKEN_ARMOUR_698, Items.BROKEN_ARROW_687, Items.OLD_BOOT_685, Items.BROKEN_GLASS_1469, Items.BROKEN_STAFF_689, Items.BUTTONS_688,Items.DAMAGED_ARMOUR_697, Items.RUSTY_SWORD_686, Items.EMPTY_POT_1931, Items.OYSTER_407)
@JvmStatic
fun getLoot(rolls: Int, skipJunk: Boolean): ArrayList<Item>{
val loot = ArrayList<Item>()
for(i in 0 until rolls){
loot.add(RandomFunction.rollWeightedChanceTable(listOf(*lootTable)))
}
if(skipJunk){
val removeList = ArrayList<Item>()
for(item in loot){
if(junkItems.contains(item.id)) removeList.add(item)
}
loot.removeAll(removeList)
}
return loot
}
val lootTable = arrayOf(
WeightedChanceItem(Items.RAW_SHRIMPS_317,1,150),
WeightedChanceItem(Items.RAW_SARDINE_327,1,150),
WeightedChanceItem(Items.RAW_ANCHOVIES_321,1,150),
WeightedChanceItem(Items.RAW_TUNA_359,1,140),
WeightedChanceItem(Items.RAW_LOBSTER_377,1,140),
WeightedChanceItem(Items.RAW_SWORDFISH_371,1,130),
WeightedChanceItem(Items.RAW_SHARK_383,1,120),
WeightedChanceItem(Items.RAW_SEA_TURTLE_395,1,120),
WeightedChanceItem(Items.RAW_MANTA_RAY_389,1,120),
WeightedChanceItem(Items.BROKEN_ARROW_687,1,70),
WeightedChanceItem(Items.BROKEN_GLASS_1469,1,70),
WeightedChanceItem(Items.BROKEN_STAFF_689,1,70),
WeightedChanceItem(Items.BUTTONS_688,1,80),
WeightedChanceItem(Items.DAMAGED_ARMOUR_697,1,70),
WeightedChanceItem(Items.OLD_BOOT_685,1,60),
WeightedChanceItem(Items.OYSTER_407,1,50),
WeightedChanceItem(Items.EMPTY_POT_1931,1,50),
WeightedChanceItem(Items.RUSTY_SWORD_686,1,50),
//Inauthentic rewards
WeightedChanceItem(Items.LOOP_HALF_OF_A_KEY_987,1,40),
WeightedChanceItem(Items.TOOTH_HALF_OF_A_KEY_985,1,40),
WeightedChanceItem(Items.CASKET_405,1,60),
WeightedChanceItem(Items.PIRATES_HAT_2651,1,2),
WeightedChanceItem(Items.LUCKY_CUTLASS_7140,1,2)
)
}
@@ -0,0 +1,91 @@
package core.game.content.activity.fog;
import core.cache.def.impl.ObjectDefinition;
import core.game.content.activity.ActivityPlugin;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneBorders;
import core.plugin.Plugin;
import core.plugin.PluginManager;
/**
* Represents the fist of guthix activity.
* @author Vexia
*/
public class FOGActivityPlugin extends ActivityPlugin {
/**
* The maximum amount of players in a game.
*/
public static final int MAX_PLAYERS = 250;
/**
* The waiting interface id.
*/
public static final int WAITING_INTERFACE = 731;
/**
* The current fist of guthix round.
*/
private int round;
/**
* Constructs a new {@code FOGActivityPlugin} {@code Object}
*/
public FOGActivityPlugin() {
super("Fist of Guthix", false, true, true);
}
@Override
public ActivityPlugin newInstance(Player p) throws Throwable {
return new FOGActivityPlugin();
}
@Override
public Location getSpawnLocation() {
return null;
}
@Override
public void configure() {
PluginManager.definePlugin(new FOGLobbyZone());
PluginManager.definePlugin(new FOGWaitingZone());
PluginManager.definePlugin(new OptionHandler() {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ObjectDefinition.forId(30204).getHandlers().put("option:enter", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
switch (node.getId()) {
case 30204:
player.teleport(Location.create(1675, 5599, 0));
return true;
}
return true;
}
});
register(new ZoneBorders(1625, 5638, 1715, 5747));
}
/**
* Gets the round.
* @return the round
*/
public int getRound() {
return round;
}
/**
* Sets the round.
* @param round the round to set.
*/
public void setRound(int round) {
this.round = round;
}
}
@@ -0,0 +1,75 @@
package core.game.content.activity.fog;
import core.game.component.Component;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Plugin;
/**
* Represents a zone where players can prepare for a game.
* @author Vexia
*/
public class FOGLobbyZone extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code FOGHallZone} {@code Object}
*/
public FOGLobbyZone() {
super("Fog Lobby", true);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public boolean enter(Entity e) {
if (e.isPlayer()) {
sendInterface(e.asPlayer());
}
return super.enter(e);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
if (!e.isPlayer()) {
return super.interact(e, target, option);
}
Player player = e.asPlayer();
switch (target.getId()) {
case 30203:
player.teleport(Location.create(3242, 3574, 0));
return true;
}
return super.interact(e, target, option);
}
/**
* Sends the fist of guthix lobby interface.
* @param player the player.
*/
private void sendInterface(Player player) {
player.getInterfaceManager().openOverlay(new Component(FOGActivityPlugin.WAITING_INTERFACE));
player.getPacketDispatch().sendInterfaceConfig(FOGActivityPlugin.WAITING_INTERFACE, 17, true);
player.getPacketDispatch().sendInterfaceConfig(FOGActivityPlugin.WAITING_INTERFACE, 26, true);
player.getPacketDispatch().sendString("Rating: " + player.getSavedData().getActivityData().getFogRating(), FOGActivityPlugin.WAITING_INTERFACE, 7);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public void configure() {
super.registerRegion(6743);
}
}
@@ -0,0 +1,104 @@
package core.game.content.activity.fog;
import core.game.node.entity.player.Player;
/**
* Represents a fist of guthix player.
* @author Vexia
*/
public class FOGPlayer {
/**
* The player instance.
*/
private final Player player;
/**
* The target FOG player.
*/
private final FOGPlayer target;
/**
* If the player is hunted or a hunter.
*/
private boolean hunted;
/**
* The amount of fist of guthix charges.
*/
private int charges;
/**
* Constructs a new {@code FOGPlayer} {@code Object}
* @param player the player.
* @param oponent the other player.
*/
public FOGPlayer(Player player, FOGPlayer oponent) {
this.player = player;
this.target = oponent;
}
/**
* Switches the roles of the player.
*/
public void switchRoles() {
hunted = !hunted;
}
/**
* Increments the energy charges.
* @param increment the number to increment.
*/
public void incrementCharges(int increment) {
charges += increment;
}
/**
* Gets the hunted.
* @return the hunted
*/
public boolean isHunted() {
return hunted;
}
/**
* Sets the hunted.
* @param hunted the hunted to set.
*/
public void setHunted(boolean hunted) {
this.hunted = hunted;
}
/**
* Gets the charges.
* @return the charges
*/
public int getCharges() {
return charges;
}
/**
* Sets the charges.
* @param charges the charges to set.
*/
public void setCharges(int charges) {
this.charges = charges;
}
/**
* Gets the player.
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Gets the target.
* @return the target
*/
public FOGPlayer getTarget() {
return target;
}
}
@@ -0,0 +1,49 @@
package core.game.content.activity.fog;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Plugin;
/**
* Represents the zone where players wait for a match.
* @author Vexia
*/
public class FOGWaitingZone extends MapZone implements Plugin<Object> {
/**
* Constructs a new {@code FOGLobbyZone} {@code Object}
*/
public FOGWaitingZone() {
super("Fog Waiting Room", true);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public boolean enter(Entity e) {
return super.enter(e);
}
@Override
public boolean interact(Entity e, Node target, Option option) {
return super.interact(e, target, option);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public void configure() {
super.registerRegion(6487);
}
}
@@ -0,0 +1,45 @@
package core.game.content.activity.fog
import core.game.content.global.action.ClimbActionHandler
import core.game.interaction.DestinationFlag
import core.game.interaction.MovementPulse
import core.game.node.Node
import core.game.node.`object`.GameObject
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
import core.game.content.quest.PluginInteraction
import core.game.content.quest.PluginInteractionManager
@Initializable
class FogInteractionHandler : PluginInteraction(30204, 30203){
override fun handle(player: Player?, node: Node?): Boolean {
when(node?.id){
30204 -> player?.pulseManager?.run(ClimbPulse(player,node as GameObject)).also { return true }
30203 -> player?.pulseManager?.run(ClimbPulse(player, node as GameObject)).also { return true }
}
return false
}
class ClimbPulse(val player: Player,val obj: GameObject) : MovementPulse(player,obj, DestinationFlag.OBJECT){
override fun pulse(): Boolean {
player.faceLocation(obj.location)
when(obj.id) {
30204 -> ClimbActionHandler.climbLadder(player, obj, "climb-down")
30203 -> ClimbActionHandler.climbLadder(player,obj,"climb-up")
}
return true
}
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit
}
override fun newInstance(arg: Any?): Plugin<Any> {
PluginInteractionManager.register(this,PluginInteractionManager.InteractionType.OBJECT)
return this
}
}
@@ -0,0 +1,65 @@
package core.game.content.activity.fog
import core.game.component.Component
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.GameWorld
import core.plugin.Initializable
import core.game.interaction.FOGRewardsInterface
import core.game.content.dialogue.DialoguePlugin
@Initializable
class ReggieDialogue(player: Player? = null) : DialoguePlugin(player){
override fun open(vararg args: Any?): Boolean {
if(GameWorld.settings?.allow_token_purchase == true){
options("Can I see your shop?","Nevermind.","Can I buy some tokens?")
} else {
options("Can I see your shop?","Nevermind.")
}
stage = 0
return true
}
override fun newInstance(player: Player?): DialoguePlugin {
FOGRewardsInterface().newInstance(Unit)
return ReggieDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
var buyAmount = 0
when(stage){
0 -> when(buttonId){
1 -> npc("Certainly!").also { stage++ }
2 -> end()
3 -> npc("Sure thing. My tokens are 1000 coins","each.").also { stage = 10 }
}
1 -> end().also { player.interfaceManager.open(Component(732)) }
//Buying tokens with config option set to true
10 -> player?.dialogueInterpreter?.sendOptions("How many?","50","100","250","500").also { stage++ }
11 -> when(buttonId){
1 -> buyAmount = 50
2 -> buyAmount = 100
3 -> buyAmount = 250
4 -> buyAmount = 500
else -> buyAmount = 0
}.also {
if(buyAmount > 0){
if(player?.inventory?.containsItem(Item(995, 1000 * buyAmount))!!) {
player?.inventory?.add(Item(12852, buyAmount))
player?.inventory?.remove(Item(995, 1000 * buyAmount))
} else {
player?.sendMessage("You dont have enough coins for that.")
}
}
end()
}
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(7601)
}
}
@@ -0,0 +1,32 @@
package core.game.content.activity.gnomecooking
import core.cache.def.impl.ItemDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
@Initializable
class DeliveryBoxHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
ItemDefinition.forId(9477).handlers["option:check"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
val jobId = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_JOB_ORDINAL",-1)
if(jobId == -1){
player.dialogueInterpreter.sendDialogue("You do not currently have a job.")
} else {
val job = GnomeCookingJob.values()[jobId]
val item = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_NEEDED_ITEM", Item(0))
player.dialogueInterpreter.sendDialogue("I need to deliver a ${item.name.toLowerCase()} to ${NPC(job.npc_id).name.toLowerCase()},","who is ${job.tip}")
}
return true
}
}
@@ -0,0 +1,107 @@
package core.game.content.activity.gnomecooking
import core.cache.def.impl.ItemDefinition
import core.tools.Items
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.plugin.Initializable
import core.plugin.Plugin
import core.tools.RandomFunction
import core.game.content.dialogue.DialoguePlugin
val gnomeItems = arrayOf(Items.FRUIT_BATTA_2277, Items.TOAD_BATTA_2255, Items.CHEESE_PLUSTOM_BATTA_2259, Items.WORM_BATTA_2253, Items.VEGETABLE_BATTA_2281,
Items.CHOCOLATE_BOMB_2185, Items.VEG_BALL_2195, Items.TANGLED_TOADS_LEGS_2187, Items.WORM_HOLE_2191, Items.TOAD_CRUNCHIES_2217, Items.WORM_CRUNCHIES_2205, Items.CHOCCHIP_CRUNCHIES_2209, Items.SPICY_CRUNCHIES_2213)
@Initializable
class GCRewardTokenHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
val def = ItemDefinition.forId(9474)
def.handlers["option:check"] = this
def.handlers["option:activate"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
option ?: return false
when(option){
"check" -> {
val charges = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD",0)
player.dialogueInterpreter.sendDialogue("You have $charges redeemable charges.")
}
"activate" -> {
player.dialogueInterpreter.open(939382893)
}
}
return true
}
@Initializable
class RewardTokenActivationDialogue(player: Player? = null) : DialoguePlugin(player){
override fun newInstance(player: Player?): DialoguePlugin {
return RewardTokenActivationDialogue(player)
}
override fun open(vararg args: Any?): Boolean {
player.dialogueInterpreter.sendOptions("How many charges?","1","5","10")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> end().also {
when (buttonId) {
1 -> sendCharges(1, player)
2 -> sendCharges(5, player)
3 -> sendCharges(10, player)
}
}
}
return true
}
fun sendCharges(amount: Int, player: Player){
val playerCharges = player.getAttribute("$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD",0)
if(playerCharges < amount){
player.dialogueInterpreter.sendDialogue("You don't have that many charges.")
return
}
if(player.inventory.freeSlots() < amount){
player.dialogueInterpreter.sendDialogue("You don't have enough space in your inventory.")
return
}
val itemList = ArrayList<Item>()
for(charge in 0 until amount){
itemList.add(Item(gnomeItems.random()))
}
player.dialogueInterpreter.sendDialogue("You put in for delivery of $amount items. Wait a bit...")
GameWorld.Pulser.submit(DeliveryPulse(player,itemList))
player.setAttribute("/save:$GC_BASE_ATTRIBUTE:$GC_REDEEMABLE_FOOD", playerCharges - amount)
}
class DeliveryPulse(val player: Player,val items: ArrayList<Item>) : Pulse(RandomFunction.random(15,30)){
override fun pulse(): Boolean {
player.inventory.add(*items.toTypedArray())
player.dialogueInterpreter.sendDialogue("Your food delivery has arrived!")
return true
}
}
override fun getIds(): IntArray {
return intArrayOf(939382893)
}
}
}
@@ -0,0 +1,11 @@
package core.game.content.activity.gnomecooking
const val GC_BASE_ATTRIBUTE = "gnome_cooking"
const val GC_TUT_PROG = "tutorial:stage"
const val GC_TUT_FIN = "tutorial:complete"
const val GC_JOB_ORDINAL = "job:job_ordinal"
const val GC_JOB_COMPLETE = "job:job_complete"
const val GC_HARD_JOB = "job:hard_job"
const val GC_NEEDED_ITEM = "job:needed_item"
const val GC_POINTS = "job:points"
const val GC_REDEEMABLE_FOOD = "job:redeemable_food"

Some files were not shown because too many files have changed in this diff Show More