Started implementing Castle Wars (not ready to enable yet)

This commit is contained in:
Dan Ginovker
2023-04-10 07:13:54 +00:00
committed by Ryan
parent dd3c957f8b
commit 034cc75a61
32 changed files with 1166 additions and 75 deletions
+3 -2
View File
@@ -5,6 +5,7 @@ import core.game.world.map.Location
import core.tools.LogLevel
import core.tools.mysql.Database
import core.tools.secondsToTicks
import rs09.game.content.activity.castlewars.CastleWars
import java.math.BigInteger
/**
@@ -224,9 +225,9 @@ class ServerConstants {
arrayOf(Location.create(2328, 3677, 0), "piscatoris"),
arrayOf(Location.create(2660, 3158, 0), "fishing trawler", "trawler"),
arrayOf(Location.create(2800, 3667, 0), "mountain camp"),
arrayOf(Location.create(2575, 3250, 0), "clocktower")
arrayOf(Location.create(2575, 3250, 0), "clocktower"),
arrayOf(CastleWars.lobbyBankArea.randomLoc, "cwars", "castle wars", "castle war", "castlewars", "castlewar", "castle")
)
//arrayOf(Location.create(0, 0, 0), ""),
@JvmField
var DATABASE: Database? = null
+12 -12
View File
@@ -408,33 +408,33 @@ fun rewardXP(player: Player, skill: Int, amount: Double) {
/**
* Replace an object with the given revert timer
* @param toReplace the GameObject instance we are replacing
* @param with the ID of the GameObject we wish to replace toReplace with
* @param for_ticks the number of ticks the object should be replaced for. Use -1 for permanent.
* @param toReplace the Scenery instance we are replacing
* @param with the ID of the Scenery we wish to replace toReplace with
* @param forTicks the number of ticks the object should be replaced for. Use -1 for permanent.
* @param loc the location to move the new object to if necessary. Defaults to null.
*/
fun replaceScenery(toReplace: Scenery, with: Int, for_ticks: Int, loc: Location? = null) {
fun replaceScenery(toReplace: Scenery, with: Int, forTicks: Int, loc: Location? = null) {
val newLoc = when (loc) {
null -> toReplace.location
else -> loc
}
if (for_ticks == -1) {
if (forTicks == -1) {
SceneryBuilder.replace(toReplace, toReplace.transform(with, toReplace.rotation, newLoc))
} else {
SceneryBuilder.replace(toReplace, toReplace.transform(with, toReplace.rotation, newLoc), for_ticks)
SceneryBuilder.replace(toReplace, toReplace.transform(with, toReplace.rotation, newLoc), forTicks)
}
toReplace.isActive = false
}
/**
* Replace an object with the given revert timer with the given rotation
* @param toReplace the GameObject instance we are replacing
* @param with the ID of the GameObject we wish to replace toReplace with
* @param for_ticks the number of ticks the object should be replaced for. Use -1 for permanent.
* @param toReplace the Scenery instance we are replacing
* @param with the ID of the Scenery we wish to replace toReplace with
* @param forTicks the number of ticks the object should be replaced for. Use -1 for permanent.
* @Param rotation the Direction of the rotation it should use. Direction.NORTH, Direction.SOUTH, etc
* @param loc the location to move the new object to if necessary. Defaults to null.
*/
fun replaceScenery(toReplace: Scenery, with: Int, for_ticks: Int, rotation: Direction, loc: Location? = null) {
fun replaceScenery(toReplace: Scenery, with: Int, forTicks: Int, rotation: Direction, loc: Location? = null) {
val newLoc = when (loc) {
null -> toReplace.location
else -> loc
@@ -449,10 +449,10 @@ fun replaceScenery(toReplace: Scenery, with: Int, for_ticks: Int, rotation: Dire
Direction.SOUTH_WEST -> 5
Direction.WEST -> 3
}
if (for_ticks == -1) {
if (forTicks == -1) {
SceneryBuilder.replace(toReplace, toReplace.transform(with, rot, newLoc))
} else {
SceneryBuilder.replace(toReplace, toReplace.transform(with, rot, newLoc), for_ticks)
SceneryBuilder.replace(toReplace, toReplace.transform(with, rot, newLoc), forTicks)
}
toReplace.isActive = false
}
+7
View File
@@ -47,5 +47,12 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
}
pushLine()
// If there's 5 lines, merge lines 4 and 5 into line 4.
if (lines.size > 4){
lines[3] = lines[3] + "<br>" + lines[4]
lines = lines.sliceArray(0..3)
}
return lines
}
+126 -7
View File
@@ -1,10 +1,129 @@
package core.api
import org.rs09.consts.Items
enum class God(vararg val validItems: Int) {
ARMADYL(87, 11694, 11718, 11720, 11722, 12670, 12671, 14671),
BANDOS(11061, 11696, 11724, 11726, 11728),
SARADOMIN(1718, 2412, 2415, 2661, 2663, 2665, 2667, 3479, 3675, 3489, 3840, 4682, 6762, 8055, 10384, 10386, 10388, 10390, 10440, 10446, 10452, 10458, 10464, 10470, 11181, 11698, 11730,542,544),
ZAMORAK(11716, 11700, 1724, 2414, 2417, 2653, 2655, 2657, 2659, 3478, 3674, 3841, 3842, 3852, 4683, 6764, 8056, 10368, 10370, 10372, 10374, 10444, 10450, 10456, 10460, 10468, 10474, 10776, 10786, 10790, 14662),
GUTHIX,
ZAROS
}
ARMADYL(
Items.ARMADYL_CHESTPLATE_11720,
Items.ARMADYL_GODSWORD_11694,
Items.ARMADYL_HELMET_11718,
Items.ARMADYL_HELMET_CHARGED_12671,
Items.ARMADYL_HELMET_E_12670,
Items.ARMADYL_PENDANT_87,
Items.ARMADYL_PLATESKIRT_11722,
),
BANDOS(
Items.ANCIENT_MACE_11061,
Items.BANDOS_BOOTS_11728,
Items.BANDOS_CHESTPLATE_11724,
Items.BANDOS_GODSWORD_11696,
Items.BANDOS_TASSETS_11726,
),
SARADOMIN(
Items.ANCIENT_SYMBOL_11181,
Items.GILDED_KITESHIELD_3489,
Items.HOLY_BOOK_3840,
Items.HOLY_SYMBOL_1718,
Items.HOLY_SYMBOL_4682,
Items.MONKS_ROBE_542,
Items.MONKS_ROBE_544,
Items.RUNE_HERALDIC_HELM_8488,
Items.SARADOMIN_BRACERS_10384,
Items.SARADOMIN_CAPE_2412,
Items.SARADOMIN_CHAPS_10388,
Items.SARADOMIN_CLOAK_10446,
Items.SARADOMIN_COIF_10390,
Items.SARADOMIN_CROZIER_10440,
Items.SARADOMIN_DHIDE_10386,
Items.SARADOMIN_FULL_HELM_2665,
Items.SARADOMIN_GODSWORD_11698,
Items.SARADOMIN_KITESHIELD_2667,
Items.SARADOMIN_MITRE_10452,
Items.SARADOMIN_MJOLNIR_6762,
Items.SARADOMIN_PLATEBODY_2661,
Items.SARADOMIN_PLATELEGS_2663,
Items.SARADOMIN_PLATESKIRT_3479,
Items.SARADOMIN_PLATESKIRT_3675,
Items.SARADOMIN_ROBE_LEGS_10464,
Items.SARADOMIN_ROBE_TOP_10458,
Items.SARADOMIN_STAFF_2415,
Items.SARADOMIN_STOLE_10470,
Items.SARADOMIN_SWORD_11730,
Items.SARADOMIN_SYMBOL_8055,
Items.STEEL_HERALDIC_HELM_8706,
),
ZAMORAK(
Items.DAGONHAI_HAT_14499,
Items.DAGONHAI_ROBE_TOP_14497,
Items.DAGONHAI_ROBE_BOTTOM_14501,
Items.DAMAGED_BOOK_3841,
Items.RUNE_HERALDIC_HELM_8494,
Items.STEEL_HERALDIC_HELM_8712,
Items.UNHOLY_BOOK_3842,
Items.UNHOLY_SYMBOL_1724,
Items.UNHOLY_SYMBOL_3852,
Items.UNHOLY_SYMBOL_4683,
Items.ZAMORAK_BRACERS_10368,
Items.ZAMORAK_CAPE_2414,
Items.ZAMORAK_CHAPS_10372,
Items.ZAMORAK_CLOAK_10450,
Items.ZAMORAK_COIF_10374,
Items.ZAMORAK_CROZIER_10444,
Items.ZAMORAK_DHIDE_10370,
Items.ZAMORAK_DHIDE_10790,
Items.ZAMORAK_FULL_HELM_2657,
Items.ZAMORAK_GODSWORD_11700,
Items.ZAMORAKIAN_SPEAR_11716,
Items.ZAMORAK_KITESHIELD_2659,
Items.ZAMORAK_MITRE_10456,
Items.ZAMORAK_MJOLNIR_6764,
Items.ZAMORAK_PLATEBODY_10776,
Items.ZAMORAK_PLATEBODY_2653,
Items.ZAMORAK_PLATELEGS_2655,
Items.ZAMORAK_PLATESKIRT_3478,
Items.ZAMORAK_PLATESKIRT_3674,
Items.ZAMORAK_ROBE_LEGS_10468,
Items.ZAMORAK_ROBE_TOP_10460,
Items.ZAMORAK_ROBE_TOP_10786,
Items.ZAMORAK_STAFF_2417,
Items.ZAMORAK_STOLE_10474,
Items.ZAMORAK_SYMBOL_8056,
),
GUTHIX(
Items.STEEL_HERALDIC_HELM_8692,
Items.RUNE_HERALDIC_HELM_8474,
Items.GUTHIX_BRACERS_10376,
Items.GUTHIX_CAPE_10720,
Items.GUTHIX_CHAPS_10380,
Items.GUTHIX_CLOAK_10448,
Items.GUTHIX_COIF_10382,
Items.GUTHIX_CROZIER_10442,
Items.GUTHIX_DRAGONHIDE_10378,
Items.GUTHIX_DRAGONHIDE_10794,
Items.GUTHIX_FULL_HELM_13833,
Items.GUTHIX_FULL_HELM_2673,
Items.GUTHIX_KITESHIELD_13834,
Items.GUTHIX_KITESHIELD_2675,
Items.GUTHIX_MITRE_10454,
Items.GUTHIX_MJOLNIR_6760,
Items.GUTHIX_PLATEBODY_10780,
Items.GUTHIX_PLATEBODY_2669,
Items.GUTHIX_PLATEBODY_13830,
Items.GUTHIX_PLATELEGS_2671,
Items.GUTHIX_PLATELEGS_13831,
Items.GUTHIX_PLATESKIRT_13832,
Items.GUTHIX_PLATESKIRT_3676,
Items.GUTHIX_ROBE_LEGS_10466,
Items.GUTHIX_ROBE_TOP_10462,
Items.GUTHIX_ROBE_TOP_10788,
Items.GUTHIX_STAFF_2416,
Items.GUTHIX_STOLE_10472,
Items.GUTHIX_SYMBOL_8057
),
ZAROS(
Items.ANCIENT_STAFF_13406,
Items.ANCIENT_STAFF_4675,
Items.ANCIENT_MACE_11061,
Items.ANCIENT_BOOK_7633,
)
}
+29
View File
@@ -882,6 +882,35 @@ public class ItemDefinition extends Definition<Item> {
return value;
}
/**
* Gets whether the Item has a value in a custom currency
* @param currency the configuration string of the currency in the item definition
* @return {@code True} if so.
*/
public boolean hasShopCurrencyValue(String currency) {
return getHandlers().getOrDefault(currency, "0") != "0";
}
/**
* Gets whether shops value the Item (even if the value is 0) in a currency
* @param currency the ID of the currency
* @return {@code True} if so.
*/
public boolean hasShopCurrencyValue(int currency) {
switch (currency) {
case Items.COINS_995:
return isTradeable();
case Items.TOKKUL_6529:
return hasShopCurrencyValue(ItemConfigParser.TOKKUL_PRICE);
case Items.ARCHERY_TICKET_1464:
return hasShopCurrencyValue(ItemConfigParser.ARCHERY_TICKET_PRICE);
case Items.CASTLE_WARS_TICKET_4067:
return hasShopCurrencyValue(ItemConfigParser.CASTLE_WARS_TICKET_PRICE);
default:
return false;
}
}
/**
* @return The value.
*/
@@ -372,6 +372,50 @@ public class Container {
return true;
}
/**
* Removes all items from the container that have the passed in IDs
*
* @param ids Array of IDs to remove
* @return {@code True} if all the items got removed, <br> {@code false} if some of the
* found items were null
*/
public boolean removeAll(int[] ids) {
boolean removedAll = true;
for (int id : ids) {
if (!removeAll(id)) {
removedAll = false;
}
}
update();
return removedAll;
}
/**
* Removes all items from the container that have the passed in ID
*
* @param id Item ID to remove all instances of
* @return {@code True} if all the items got removed, <br> {@code false} if some of the
* found items were null
*/
public boolean removeAll(int id) {
ArrayList<Item> matchingIdItems = new ArrayList<>();
for (Item item : this.items) {
// If the item is not null and the item ID matches the ID we're looking for
if (item != null && item.getId() == id) {
// Add the item to the list
matchingIdItems.add(item);
}
}
boolean res = true;
// Remove all the items from the container
for (Item item : matchingIdItems) {
if (!remove(item, false)) {
res = false;
}
}
return res;
}
/**
* Replaces the item on the given slot with the argued item.
*
@@ -463,6 +463,7 @@ public final class DialogueInterpreter {
*/
public Component sendDialogues(int npcId, int expression, String... messages) {
if (messages.length < 1 || messages.length > 4) {
System.err.println("Invalid amount of messages: " + messages.length);
return null;
}
boolean npc = npcId > -1;
@@ -341,6 +341,7 @@ public final class WalkingQueue {
* {@code false} if not.
*/
public boolean isRunningBoth() {
if (isRunDisabled()) return false;
if (entity instanceof Player && ((Player) entity).getSettings().isRunToggled()) {
return true;
}
+7 -4
View File
@@ -17,6 +17,7 @@ import org.rs09.consts.Components
import org.rs09.consts.Items
import core.ServerConstants
import core.game.shops.Shops.Companion.logShop
import core.game.system.config.ItemConfigParser
import core.game.world.GameWorld
import java.lang.Integer.max
import java.lang.Integer.min
@@ -159,8 +160,9 @@ class Shop(val title: String, val stock: Array<ShopItem>, val general: Boolean =
val item = cont[slot]
val price = when(currency)
{
Items.TOKKUL_6529 -> item.definition.getConfiguration("tokkul_price", 1)
Items.ARCHERY_TICKET_1464 -> item.definition.getConfiguration("archery_ticket_price", 1)
Items.TOKKUL_6529 -> item.definition.getConfiguration(ItemConfigParser.TOKKUL_PRICE, 1)
Items.ARCHERY_TICKET_1464 -> item.definition.getConfiguration(ItemConfigParser.ARCHERY_TICKET_PRICE, 1)
Items.CASTLE_WARS_TICKET_4067 -> item.definition.getConfiguration(ItemConfigParser.CASTLE_WARS_TICKET_PRICE, 1)
else -> getGPCost(Item(item.id, 1), if (isMainStock) stock[item.slot].amount else playerStock[slot].amount, if (isMainStock) item.amount else playerStock[slot].amount)
}
@@ -199,8 +201,9 @@ class Shop(val title: String, val stock: Array<ShopItem>, val general: Boolean =
val price = when(currency)
{
Items.TOKKUL_6529 -> (item.definition.getConfiguration("tokkul_price", 1) / 10.0).toInt() // selling items authentically return 10x less tokkul (floored/truncated) than the item's shop price
Items.ARCHERY_TICKET_1464 -> item.definition.getConfiguration("archery_ticket_price", 1)
Items.TOKKUL_6529 -> (item.definition.getConfiguration(ItemConfigParser.TOKKUL_PRICE, 1) / 10.0).toInt() // selling items authentically return 10x less tokkul (floored/truncated) than the item's shop price
Items.ARCHERY_TICKET_1464 -> item.definition.getConfiguration(ItemConfigParser.ARCHERY_TICKET_PRICE, 1)
Items.CASTLE_WARS_TICKET_4067 -> item.definition.getConfiguration(ItemConfigParser.CASTLE_WARS_TICKET_PRICE, 1)
else -> getGPSell(Item(shopItemId, 1), stockAmt, currentAmt)
}
+22 -17
View File
@@ -52,20 +52,25 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe
return items
}
stock.split('-').map {
val tokens = it.replace("{", "").replace("}", "").split(",".toRegex()).toTypedArray()
var amount = tokens[1].trim()
if(amount == "inf")
amount = "-1"
val item = tokens[0].toInt()
if(idsInStock[item] != null) {
log(this::class.java, Log.WARN, "[SHOPS] MALFORMED STOCK IN SHOP ID $id FOR ITEM $item")
items.forEach { if(it.itemId == item) {
it.amount += amount.toInt()
return@map
}}
} else {
items.add(ShopItem(item, amount.toInt(), tokens.getOrNull(2)?.toIntOrNull() ?: 100))
idsInStock[item] = true
try {
val tokens = it.replace("{", "").replace("}", "").split(",".toRegex()).toTypedArray()
var amount = tokens[1].trim()
if(amount == "inf")
amount = "-1"
val item = tokens[0].toInt()
if(idsInStock[item] != null) {
log(this::class.java, Log.WARN, "[SHOPS] MALFORMED STOCK IN SHOP ID $id FOR ITEM $item")
items.forEach { if(it.itemId == item) {
it.amount += amount.toInt()
return@map
}}
} else {
items.add(ShopItem(item, amount.toInt(), tokens.getOrNull(2)?.toIntOrNull() ?: 100))
idsInStock[item] = true
}
} catch (e: Exception) {
log(this::class.java, Log.WARN, "[SHOPS] MALFORMED STOCK IN SHOP ID $id FOR ITEM $it")
throw e
}
}
return items
@@ -215,9 +220,9 @@ class Shops : StartupListener, TickListener, InteractionListener, InterfaceListe
val valueMsg = when {
(price.amount == -1)
|| !def.isTradeable
|| def.id in intArrayOf(Items.COINS_995, Items.TOKKUL_6529, Items.ARCHERY_TICKET_1464)
|| def.hasDestroyAction() -> "This shop will not buy that item."
|| !def.hasShopCurrencyValue(price.id)
|| def.id in intArrayOf(Items.COINS_995, Items.TOKKUL_6529, Items.ARCHERY_TICKET_1464, Items.CASTLE_WARS_TICKET_4067)
-> "This shop will not buy that item."
else -> "${player.inventory[slot].name}: This shop will buy this item for ${price.amount} ${price.name.lowercase()}."
}
@@ -7,8 +7,10 @@ import core.plugin.Initializable
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import core.ServerConstants
import core.api.log
import core.game.system.command.Privilege
import core.game.world.repository.Repository
import core.tools.Log
@Initializable
class TeleportCommandSet : CommandSet(Privilege.ADMIN){
@@ -217,6 +217,11 @@ class ItemConfigParser {
*/
const val ARCHERY_TICKET_PRICE = "archery_ticket_price"
/**
* The Castle Wars Ticket price of items (in Lanthas' shop).
*/
const val CASTLE_WARS_TICKET_PRICE = "castle_wars_ticket_price"
}
val parser = JSONParser()
@@ -270,8 +275,9 @@ class ItemConfigParser {
//ints
"equip_audio",
"point_price",
"tokkul_price",
"archery_ticket_price",
TOKKUL_PRICE,
ARCHERY_TICKET_PRICE,
CASTLE_WARS_TICKET_PRICE,
"ge_buy_limit",
"weapon_interface",
"attack_speed",
@@ -92,6 +92,7 @@ object ServerConfigParser {
jad_practice_enabled = data.getBoolean("world.jad_practice_enabled"),
ge_announcement_limit = data.getLong("world.ge_announcement_limit", 500L).toInt(),
smartpathfinder_bfs = data.getBoolean("world.smartpathfinder_bfs", false),
enable_castle_wars = data.getBoolean("world.enable_castle_wars", false),
message_model = data.getString("world.motw_identifier").toInt(),
message_string = data.getString("world.motw_text").replace("@name", ServerConstants.SERVER_NAME)
)
@@ -84,6 +84,7 @@ class GameSettings
var jad_practice_enabled: Boolean,
var ge_announcement_limit: Int,
var smartpathfinder_bfs: Boolean,
var enable_castle_wars: Boolean,
/**"Lobby" interface
* The message of the week models to display
@@ -140,6 +141,7 @@ class GameSettings
val jad_practice_enabled = if(data.containsKey("jad_practice_enabled")) data["jad_practice_enabled"] as Boolean else true
val ge_announcement_limit = data["ge_announcement_limit"].toString().toInt()
val smartpathfinder_bfs = if(data.containsKey("smartpathfinder_bfs")) data["smartpathfinder_bfs"] as Boolean else false
val enable_castle_wars = if(data.containsKey("enable_castle_wars")) data["enable_castle_wars"] as Boolean else false
val allow_token_purchase = data["allow_token_purchase"] as Boolean
val message_of_the_week_identifier = data["message_of_the_week_identifier"].toString().toInt()
val message_of_the_week_text = data["message_of_the_week_text"].toString()
@@ -171,6 +173,7 @@ class GameSettings
jad_practice_enabled,
ge_announcement_limit,
smartpathfinder_bfs,
enable_castle_wars,
message_of_the_week_identifier,
message_of_the_week_text
)
@@ -2,6 +2,7 @@ package core.game.world.map.zone;
import core.game.node.Node;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.tools.RandomFunction;
import java.util.ArrayList;
@@ -97,6 +98,10 @@ public final class ZoneBorders {
this.zeroPlaneCheck = zeroPlaneCheck;
}
public ZoneBorders(Location l1, Location l2) {
this(l1.getX(), l1.getY(), l2.getX(), l2.getY(), l1.getZ());
}
/**
* Creates zone borders for the given region id.
* @param regionId The region id.
@@ -234,6 +239,16 @@ public final class ZoneBorders {
return new Location(x, y, plane);
}
public Location getRandomWalkableLoc() {
Location loc = getRandomLoc();
int tries = 0; // prevent bad code from DOSing server
while (!RegionManager.isTeleportPermitted(loc) && tries < 20) {
loc = getRandomLoc();
tries += 1;
}
return loc;
}
/**
* Adds an exception.
* @param exception The exception to add.
+14 -1
View File
@@ -11,4 +11,17 @@ fun secondsToTicks(seconds: Int): Int {
fun ticksToSeconds(ticks: Int): Int {
val ticksMs = ticks * tick
return ticksMs / 1000
}
}
fun minutesToTicks(minutes: Int): Int {
val minutesMs = minutes * 60 * 1000
return minutesMs / tick
}
fun ticksToMinutes(ticks: Int): Int {
val ticksMs = ticks * tick
return ticksMs / 1000 / 60
}
const val ticksPerSecond = second / tick
const val ticksPerMinute = 60 * ticksPerSecond