diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json index b359711cf..b80535acc 100644 --- a/Server/data/configs/item_configs.json +++ b/Server/data/configs/item_configs.json @@ -86655,7 +86655,7 @@ }, { "requirements": "{1,30}-{5,20}", - "shop_price": "10", + "shop_price": "10000", "ge_buy_limit": "100", "examine": "A Proselyte Temple Knight's leg armour.", "durability": null, diff --git a/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlActivityPlugin.java b/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlActivityPlugin.java index 3950c5401..71d2fa067 100644 --- a/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlActivityPlugin.java +++ b/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlActivityPlugin.java @@ -2,6 +2,7 @@ package core.game.content.activity.pestcontrol; import java.util.ArrayList; import java.util.List; +import java.util.PriorityQueue; import rs09.ServerConstants; import core.game.component.Component; @@ -17,6 +18,7 @@ import core.game.node.entity.state.EntityState; import core.game.node.item.GroundItemManager; import core.game.node.item.Item; import core.game.system.task.Pulse; +import rs09.game.ai.AIPlayer; import rs09.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.map.build.DynamicRegion; @@ -60,7 +62,13 @@ public final class PestControlActivityPlugin extends ActivityPlugin { /** * The waiting players. */ - private final List waitingPlayers = new ArrayList<>(20); + private final PriorityQueue waitingPlayers = new PriorityQueue(20, (player1, player2) -> { + //get priorities of players. default to 0 + int p1 = player1.getAttribute("pc_prior", 0); + int p2 = player2.getAttribute("pc_prior", 0); + //return in descending order + return p2 - p1; + }); /** * The active game sessions. @@ -313,7 +321,7 @@ public final class PestControlActivityPlugin extends ActivityPlugin { * Gets the list of waiting players. * @return The list of waiting players. */ - public List getWaitingPlayers() { + public PriorityQueue getWaitingPlayers() { return waitingPlayers; } diff --git a/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlSession.java b/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlSession.java index 45ef3be6e..c9b69c07d 100644 --- a/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlSession.java +++ b/Server/src/main/java/core/game/content/activity/pestcontrol/PestControlSession.java @@ -1,10 +1,6 @@ package core.game.content.activity.pestcontrol; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Random; +import java.util.*; import core.game.component.Component; import core.game.content.dialogue.FacialExpression; @@ -212,7 +208,7 @@ public final class PestControlSession { * Starts a game. * @param waitingPlayers The list of waiting players. */ - public void startGame(List waitingPlayers) { + public void startGame(PriorityQueue waitingPlayers) { region.flagActive(); initBarricadesList(); List list = new ArrayList<>(20); @@ -225,21 +221,29 @@ public final class PestControlSession { ids = list.toArray(new Integer[4]); int count = 0; String portalHealth = "" + (activity.getType().ordinal() == 0 ? 200 : 250); - for (Iterator it = waitingPlayers.iterator(); it.hasNext();) { - Player p = it.next(); + + List remainingPlayers = new ArrayList<>(); + for (Player p = waitingPlayers.poll(); p != null; p = waitingPlayers.poll()) { if (p.getSession().isActive()) { if (++count > MAX_TEAM_SIZE) { - int priority = p.getAttribute("pc_prior", 0) + 1; - p.getPacketDispatch().sendMessage("You have been given priority level " + priority + " over other players in joining the next"); - p.getPacketDispatch().sendMessage("game."); - p.setAttribute("pc_prior", priority); + remainingPlayers.add(p); continue; } addPlayer(p, portalHealth); } - it.remove(); } + + for (Player p : remainingPlayers) + { + int priority = p.getAttribute("pc_prior", 0) + 1; + p.getPacketDispatch().sendMessage("You have been given priority level " + priority + " over other players in joining the next"); + p.getPacketDispatch().sendMessage("game."); + p.setAttribute("pc_prior", priority); + waitingPlayers.add(p); + } + spawnNPCs(); + } /** diff --git a/Server/src/main/java/core/game/content/global/shop/Shop.kt b/Server/src/main/java/core/game/content/global/shop/Shop.kt index 1ae9e865e..08034c357 100644 --- a/Server/src/main/java/core/game/content/global/shop/Shop.kt +++ b/Server/src/main/java/core/game/content/global/shop/Shop.kt @@ -708,7 +708,7 @@ open class Shop @JvmOverloads constructor( open fun getBuyPrice(item: Item, player: Player): Int { var item = item item = Item(item.id, 1) - var price = item.definition.maxValue + var price = item.definition.value val sellVal = getSellingValue(item, player) if (price < sellVal) { price = getSellingValue(player, 0, item) + sellVal - (sellVal - item.definition.maxValue) diff --git a/Server/src/main/java/core/game/content/quest/members/animalmagnetism/AvasDevicePlugin.java b/Server/src/main/java/core/game/content/quest/members/animalmagnetism/AvasDevicePlugin.java index 75c775134..ef1adc6d8 100644 --- a/Server/src/main/java/core/game/content/quest/members/animalmagnetism/AvasDevicePlugin.java +++ b/Server/src/main/java/core/game/content/quest/members/animalmagnetism/AvasDevicePlugin.java @@ -34,18 +34,16 @@ public final class AvasDevicePlugin implements Plugin { state.init(); break; case "unequip": + player.clearState("avadevice"); if (args.length == 3) { Item second = (Item) args[2]; if (second.getId() == 10498 || second.getId() == 10499) { - player.clearState("avadevice"); AvaDeviceState newState = (AvaDeviceState) player.registerState("avadevice"); newState.setDevice(second.getId()); newState.init(); break; } } - if(player.hasActiveState("avadevice")) player.clearState("avadevice"); - break; } return true; } diff --git a/Server/src/main/java/core/game/content/ttrail/TreasureTrailPlugin.java b/Server/src/main/java/core/game/content/ttrail/TreasureTrailPlugin.java index 23cbcfe7f..f70aed69b 100644 --- a/Server/src/main/java/core/game/content/ttrail/TreasureTrailPlugin.java +++ b/Server/src/main/java/core/game/content/ttrail/TreasureTrailPlugin.java @@ -132,16 +132,7 @@ public final class TreasureTrailPlugin extends OptionHandler { @Override public boolean createDrop(Item item, Player player, NPC npc, Location l) { - if ((npc.getId() == 49 || npc.getId() == 3586)) { - return true; - } - if (npc.getDefinition().getDropTables().getMainTable().size() < 3) { - return false; - } - if (!hasClue(player)) { - return true; - } - return false; + return !hasClue(player); } @Override diff --git a/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java b/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java index f173c4ed7..46fe57c21 100644 --- a/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java +++ b/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; +import java.util.stream.Collectors; /** * Class used for handling combat impacts. @@ -262,6 +263,15 @@ public final class ImpactHandler { return impactLog; } + /** + * Gets the impact log filtered for Player objects + * @return The impact log of each Player and their damage + */ + public Map getPlayerImpactLog() { + return impactLog.entrySet().stream().filter(entry -> entry.getKey() instanceof Player).collect( + Collectors.toMap(m -> m.getKey().asPlayer(), m -> m.getValue())); + } + /** * Checks if the entity needs a hit update. * @return {@code True} if so. diff --git a/Server/src/main/java/core/game/node/entity/combat/handlers/ChinchompaSwingHandler.java b/Server/src/main/java/core/game/node/entity/combat/handlers/ChinchompaSwingHandler.java index 3a5958848..01cf93d59 100644 --- a/Server/src/main/java/core/game/node/entity/combat/handlers/ChinchompaSwingHandler.java +++ b/Server/src/main/java/core/game/node/entity/combat/handlers/ChinchompaSwingHandler.java @@ -146,6 +146,7 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { s.getVictim().animate(s.getVictim().getProperties().getDefenceAnimation()); } } + addExperience(entity, victim, state); } /** @@ -155,4 +156,4 @@ public final class ChinchompaSwingHandler extends RangeSwingHandler { public static ChinchompaSwingHandler getInstance() { return INSTANCE; } -} \ No newline at end of file +} diff --git a/Server/src/main/java/core/game/node/entity/combat/spell/BindSpell.java b/Server/src/main/java/core/game/node/entity/combat/spell/BindSpell.java index 322b156ce..bbd7aa8c5 100644 --- a/Server/src/main/java/core/game/node/entity/combat/spell/BindSpell.java +++ b/Server/src/main/java/core/game/node/entity/combat/spell/BindSpell.java @@ -134,9 +134,12 @@ public final class BindSpell extends CombatSpell { @Override public Plugin newInstance(SpellType type) throws Throwable { - SpellBook.MODERN.register(12, new BindSpell(SpellType.BIND, 20, 30.0, 151, BIND_START, BIND_PROJECTILE, BIND_END, Runes.NATURE_RUNE.getItem(2), Runes.EARTH_RUNE.getItem(3), Runes.WATER_RUNE.getItem(3))); - SpellBook.MODERN.register(30, new BindSpell(SpellType.SNARE, 50, 60.0, 152, SNARE_START, SNARE_PROJECTILE, SNARE_END, Runes.NATURE_RUNE.getItem(3), Runes.EARTH_RUNE.getItem(4), Runes.WATER_RUNE.getItem(4))); - SpellBook.MODERN.register(56, new BindSpell(SpellType.ENTANGLE, 79, 89.0, 153, ENTANGLE_START, ENTANGLE_PROJECTILE, ENTANGLE_END, Runes.NATURE_RUNE.getItem(4), Runes.EARTH_RUNE.getItem(5), Runes.WATER_RUNE.getItem(5))); + // TODO: bind/snare/entangle have separate casting and onhit components + // to their sound effects, in order for splashes to sound distinct, currently + // these just sound like the spells should on success, even if they splash + SpellBook.MODERN.register(12, new BindSpell(SpellType.BIND, 20, 30.0, 101, BIND_START, BIND_PROJECTILE, BIND_END, Runes.NATURE_RUNE.getItem(2), Runes.EARTH_RUNE.getItem(3), Runes.WATER_RUNE.getItem(3))); + SpellBook.MODERN.register(30, new BindSpell(SpellType.SNARE, 50, 60.0, 186, SNARE_START, SNARE_PROJECTILE, SNARE_END, Runes.NATURE_RUNE.getItem(3), Runes.EARTH_RUNE.getItem(4), Runes.WATER_RUNE.getItem(4))); + SpellBook.MODERN.register(56, new BindSpell(SpellType.ENTANGLE, 79, 89.0, 152, ENTANGLE_START, ENTANGLE_PROJECTILE, ENTANGLE_END, Runes.NATURE_RUNE.getItem(4), Runes.EARTH_RUNE.getItem(5), Runes.WATER_RUNE.getItem(5))); return this; } diff --git a/Server/src/main/java/core/game/node/entity/npc/NPC.java b/Server/src/main/java/core/game/node/entity/npc/NPC.java index 6bb1b1add..1ee2fafb5 100644 --- a/Server/src/main/java/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/java/core/game/node/entity/npc/NPC.java @@ -38,6 +38,8 @@ import rs09.game.system.config.ShopParser; import rs09.game.world.GameWorld; import rs09.game.world.repository.Repository; +import java.util.Map; + import static rs09.game.node.entity.player.info.stats.StatAttributeKeysKt.STATS_BASE; import static rs09.game.node.entity.player.info.stats.StatAttributeKeysKt.STATS_ENEMIES_KILLED; @@ -543,7 +545,7 @@ public class NPC extends Entity { if (getAttribute("disable:drop", false)) { return; } - if (killer instanceof Player && p != null && p.getIronmanManager().isIronman() && getImpactHandler().getImpactLog().size() > 1) { + if (killer instanceof Player && p != null && p.getIronmanManager().isIronman() && getImpactHandler().getPlayerImpactLog().size() > 1) { return; } if (definition == null || definition.getDropTables() == null) { diff --git a/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java b/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java index 366f19ac5..347c54d76 100644 --- a/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java +++ b/Server/src/main/java/core/game/node/entity/npc/drop/NPCDropTables.java @@ -10,7 +10,6 @@ import core.game.node.entity.skill.Skills; import core.game.node.item.GroundItem; import core.game.node.item.GroundItemManager; import core.game.node.item.Item; -import core.game.node.item.WeightedChanceItem; import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.tools.RandomFunction; @@ -41,21 +40,6 @@ public final class NPCDropTables { * The npcs that will display drop messages */ public static final int[] MESSAGE_NPCS = { 50, 7133, 7134, 2881, 2882, 2883, 3200, 3340, 6247, 6203, 6260, 6222, 2745, 1160, 8133, 8610, 8611, 8612, 8613, 8614, 6204, 6206, 6208, 6261, 6263, 6265, 6223, 6225, 6227 }; - - /** - * The default drop table (holding the 100% drops). - */ - private final List defaultTable = new ArrayList<>(20); - - /** - * The charms drop table (holding the charm drops). - */ - private final List charmTable = new ArrayList<>(20); - - /** - * The main drop table (holding the main drops). - */ - private final List mainTable = new ArrayList<>(20); public final NPCDropTable table = new NPCDropTable(); @@ -239,41 +223,6 @@ public final class NPCDropTables { return (1 / (1 + def.getCombatLevel())) * 10; } - /** - * @return the defaultTable. - */ - public List getDefaultTable() { - return defaultTable; - } - - /** - * @return the charmTable. - */ - public List getCharmTable() { - return charmTable; - } - - /** - * @return the mainTable. - */ - public List getMainTable() { - return mainTable; - } - - /** - * @return the mainTableSize. - */ - public int getMainTableSize() { - return mainTableSize; - } - - /** - * @param mainTableSize the mainTableSize to set. - */ - public void setMainTableSize(int mainTableSize) { - this.mainTableSize = mainTableSize; - } - /** * Gets the modRate. * @return The modRate. diff --git a/Server/src/main/java/core/game/node/entity/npc/familiar/BunyipNPC.java b/Server/src/main/java/core/game/node/entity/npc/familiar/BunyipNPC.java index 5492ace36..34f2c8f28 100644 --- a/Server/src/main/java/core/game/node/entity/npc/familiar/BunyipNPC.java +++ b/Server/src/main/java/core/game/node/entity/npc/familiar/BunyipNPC.java @@ -101,7 +101,7 @@ public class BunyipNPC extends Familiar { player.sendMessage("Error: Report to admin."); return false; } - if (player.getSkills().getLevel(Skills.COOKING) < CookableItems.forId(special.getItem().getId() + 2).level) { + if (player.getSkills().getLevel(Skills.COOKING) < CookableItems.forId(special.getItem().getId()).level) { player.sendMessage("You need a Cooking level of at least " + CookableItems.forId(special.getItem().getId()).level + " in order to do that."); return false; } diff --git a/Server/src/main/java/core/game/node/entity/player/Player.java b/Server/src/main/java/core/game/node/entity/player/Player.java index 4a8278c63..91901890e 100644 --- a/Server/src/main/java/core/game/node/entity/player/Player.java +++ b/Server/src/main/java/core/game/node/entity/player/Player.java @@ -480,6 +480,7 @@ public class Player extends Entity { if(time == 0){ sendMessage(colorize("%RYour antifire potion has expired.")); removeAttribute("fire:immune"); + getAudioManager().send(2607); } } if(getAttribute("poison:immunity",0) > 0){ @@ -491,6 +492,7 @@ public class Player extends Entity { if(time == 0){ sendMessage(colorize("%RYour antipoison potion has expired.")); removeAttribute("poison:immunity"); + getAudioManager().send(2607); } } if (!artificial && (System.currentTimeMillis() - getSession().getLastPing()) > 20_000L) { @@ -1384,7 +1386,10 @@ public class Player extends Entity { public void clearState(String key){ State state = states.get(key); if(state == null) return; - state.getPulse().stop(); + Pulse pulse = state.getPulse(); + if(pulse != null) { + pulse.stop(); + } states.remove(key); } } diff --git a/Server/src/main/java/core/game/node/entity/player/link/prayer/Prayer.java b/Server/src/main/java/core/game/node/entity/player/link/prayer/Prayer.java index 234e49a71..019ad27a1 100644 --- a/Server/src/main/java/core/game/node/entity/player/link/prayer/Prayer.java +++ b/Server/src/main/java/core/game/node/entity/player/link/prayer/Prayer.java @@ -8,11 +8,13 @@ import core.game.node.entity.combat.ImpactHandler.HitsplatType; import core.game.node.entity.impl.Projectile; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; +import core.game.system.task.Pulse; import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Graphics; import core.tools.RandomFunction; import rs09.game.node.entity.skill.skillcapeperks.SkillcapePerks; +import rs09.game.world.GameWorld; import java.util.ArrayList; import java.util.List; @@ -62,8 +64,15 @@ public final class Prayer { player.getConfigManager().set(type.getConfig(), 0); } getActive().clear(); - player.getAppearance().setHeadIcon(-1); - player.getAppearance().sync(); + // Clear the overhead prayer icon a tick later + GameWorld.getPulser().submit(new Pulse(1) { + @Override + public boolean pulse() { + player.getAppearance().setHeadIcon(-1); + player.getAppearance().sync(); + return true; + } + }); } /** @@ -119,6 +128,7 @@ public final class Prayer { if(prayerActiveTicks > 0 && prayerActiveTicks % 2 == 0){ if(getPlayer().getSkills().getPrayerPoints() == 0){ + getPlayer().getAudioManager().send(2672); reset(); return; } @@ -190,4 +200,4 @@ public final class Prayer { return active; } -} \ No newline at end of file +} diff --git a/Server/src/main/java/core/game/node/entity/skill/magic/lunar/SuperglassMakeSpell.java b/Server/src/main/java/core/game/node/entity/skill/magic/lunar/SuperglassMakeSpell.java index 8b20e1506..ae8188e5f 100644 --- a/Server/src/main/java/core/game/node/entity/skill/magic/lunar/SuperglassMakeSpell.java +++ b/Server/src/main/java/core/game/node/entity/skill/magic/lunar/SuperglassMakeSpell.java @@ -13,6 +13,7 @@ import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; import core.plugin.Plugin; +import core.tools.RandomFunction; /** * The super glass make spell. @@ -79,6 +80,11 @@ public class SuperglassMakeSpell extends MagicSpell { if (hasSet(player, setIndex)) { if (player.getInventory().remove(BUCKET_OF_SAND, SETS[setIndex])) { player.getInventory().add(MOLTEN_GLASS); + // https://runescape.wiki/w/Superglass_Make?oldid=1970761 + // "On average, each set will produce 1.30 pieces of molten glass" + if(RandomFunction.randomDouble(1.0) < 0.3) { + player.getInventory().add(MOLTEN_GLASS); + } player.getSkills().addExperience(Skills.CRAFTING, 10, true); } } diff --git a/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java b/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java index 6da870aba..207c26099 100644 --- a/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java +++ b/Server/src/main/java/core/game/node/entity/skill/runecrafting/RuneCraftPulse.java @@ -133,6 +133,7 @@ public final class RuneCraftPulse extends SkillPulse { public void animate() { player.animate(ANIMATION); player.graphics(GRAPHICS); + player.getAudioManager().send(2710); } @Override @@ -234,14 +235,14 @@ public final class RuneCraftPulse extends SkillPulse { } if (player.getInventory().remove(new Item(PURE_ESSENCE.getId(), amount)) && player.getInventory().remove(new Item(rune.getId(), amount))) { for (int i = 0; i < amount; i++) { - if (RandomFunction.random(1, 3) == 1 || hasBindingNeckalce()) { + if (RandomFunction.random(1, 3) == 1 || hasBindingNecklace()) { player.getInventory().add(new Item(combo.getRune().getId(), 1)); player.getSkills().addExperience(Skills.RUNECRAFTING, combo.getExperience(), true); } } - if (hasBindingNeckalce()) { - player.getEquipment().get(EquipmentContainer.SLOT_HAT).setCharge(player.getEquipment().get(EquipmentContainer.SLOT_HAT).getCharge() - 1); - if (1000 - player.getEquipment().get(EquipmentContainer.SLOT_HAT).getCharge() > 14) { + if (hasBindingNecklace()) { + player.getEquipment().get(EquipmentContainer.SLOT_AMULET).setCharge(player.getEquipment().get(EquipmentContainer.SLOT_AMULET).getCharge() - 1); + if (1000 - player.getEquipment().get(EquipmentContainer.SLOT_AMULET).getCharge() > 14) { player.getEquipment().remove(BINDING_NECKLACE, true); player.getPacketDispatch().sendMessage("Your binding necklace crumbles into dust."); } @@ -325,7 +326,7 @@ public final class RuneCraftPulse extends SkillPulse { * * @return True if so. */ - public boolean hasBindingNeckalce() { + public boolean hasBindingNecklace() { return player.getEquipment().containsItem(BINDING_NECKLACE); } diff --git a/Server/src/main/java/core/game/node/entity/skill/slayer/KuraskNPC.java b/Server/src/main/java/core/game/node/entity/skill/slayer/KuraskNPC.java index d3a80343b..cde7e0474 100644 --- a/Server/src/main/java/core/game/node/entity/skill/slayer/KuraskNPC.java +++ b/Server/src/main/java/core/game/node/entity/skill/slayer/KuraskNPC.java @@ -6,6 +6,8 @@ import core.game.node.entity.player.Player; import core.game.node.entity.player.link.SpellBookManager.SpellBook; import core.game.world.map.Location; import core.plugin.Initializable; +import org.rs09.consts.Items; +import rs09.game.node.entity.skill.slayer.SlayerUtils; /** * Handles the kurask npc. @@ -41,9 +43,7 @@ public final class KuraskNPC extends AbstractNPC { boolean effective = false; if (state.getAttacker() instanceof Player) { final Player player = (Player) state.getAttacker(); - if ((state.getWeapon() != null && state.getWeapon().getId() == 4158) || (state.getAmmunition() != null && state.getAmmunition().getItemId() == 4160) || (state.getWeapon() != null && state.getWeapon().getId() == 13290) || (state.getSpell() != null && state.getSpell().getSpellId() == 31 && player.getSpellBookManager().getSpellBook() == SpellBook.MODERN.getInterfaceId()) || (state.getAmmunition() != null && state.getAmmunition().getItemId() == 881)) { - effective = true; - } + effective = new SlayerUtils(player).hasBroadWeaponEquipped(state); } if (!effective) { state.setEstimatedHit(0); diff --git a/Server/src/main/java/core/game/node/entity/skill/slayer/TurothNPC.java b/Server/src/main/java/core/game/node/entity/skill/slayer/TurothNPC.java index c36239f22..7299fae07 100644 --- a/Server/src/main/java/core/game/node/entity/skill/slayer/TurothNPC.java +++ b/Server/src/main/java/core/game/node/entity/skill/slayer/TurothNPC.java @@ -6,6 +6,8 @@ import core.game.node.entity.player.Player; import core.game.node.entity.player.link.SpellBookManager.SpellBook; import core.game.world.map.Location; import core.plugin.Initializable; +import org.rs09.consts.Items; +import rs09.game.node.entity.skill.slayer.SlayerUtils; /** * Handles the turoth npc. @@ -41,9 +43,7 @@ public final class TurothNPC extends AbstractNPC { boolean effective = false; if (state.getAttacker() instanceof Player) { final Player player = (Player) state.getAttacker(); - if ((state.getWeapon() != null && state.getWeapon().getId() == 4158) || (state.getAmmunition() != null && state.getAmmunition().getItemId() == 4160) || (state.getWeapon() != null && state.getWeapon().getId() == 13290) || (state.getSpell() != null && state.getSpell().getSpellId() == 31 && player.getSpellBookManager().getSpellBook() == SpellBook.MODERN.getInterfaceId())) { - effective = true; - } + effective = new SlayerUtils(player).hasBroadWeaponEquipped(state); } if (!effective) { state.setEstimatedHit(0); diff --git a/Server/src/main/java/core/game/world/map/Location.java b/Server/src/main/java/core/game/world/map/Location.java index 17b22e7c0..b7d188f55 100644 --- a/Server/src/main/java/core/game/world/map/Location.java +++ b/Server/src/main/java/core/game/world/map/Location.java @@ -229,6 +229,23 @@ public final class Location extends Node { return product <= dist; } + /** + * Returns if a player is within a specified distance using max norm distance. + * @param other The other location. + * @param dist The amount of distance. + * @return If you're within the other distance. + */ + public boolean withinMaxnormDistance(Location other, int dist) { + if (other.z != z) { + return false; + } + + int a = Math.abs(other.x - x); + int b = Math.abs(other.y - y); + double max = Math.max(a, b); + return max <= dist; + } + /** * Returns the distance between you and the other. * @param other The other location. @@ -455,4 +472,4 @@ public final class Location extends Node { public void setZ(int z) { this.z = z; } -} \ No newline at end of file +} diff --git a/Server/src/main/java/core/game/world/map/RegionManager.kt b/Server/src/main/java/core/game/world/map/RegionManager.kt index 1b3a9b0ba..0aefac707 100644 --- a/Server/src/main/java/core/game/world/map/RegionManager.kt +++ b/Server/src/main/java/core/game/world/map/RegionManager.kt @@ -538,11 +538,15 @@ object RegionManager { */ @JvmStatic fun getSurroundingPlayers(n: Node, maximum: Int, vararg ignore: Node): List { - val players = getLocalPlayers(n.location, 1) + val players = getLocalPlayers(n.location, 2) var count = 0 val it = players.iterator() while (it.hasNext()) { val p = it.next() + if(!p.location.withinMaxnormDistance(n.location, 1)) { + it.remove() + continue + } if (++count >= maximum) { it.remove() continue @@ -577,11 +581,15 @@ object RegionManager { */ @JvmStatic fun getSurroundingNPCs(n: Node, maximum: Int, vararg ignore: Node): List { - val npcs = getLocalNpcs(n.location, 1) + val npcs = getLocalNpcs(n.location, 2) var count = 0 val it = npcs.iterator() while (it.hasNext()) { val p = it.next() + if(!p.location.withinMaxnormDistance(n.location, 1)) { + it.remove() + continue + } if (++count > maximum) { it.remove() continue @@ -806,4 +814,4 @@ object RegionManager { val lock: ReentrantLock @JvmStatic get() = LOCK -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/content/global/travel/EssenceTeleport.kt b/Server/src/main/kotlin/rs09/game/content/global/travel/EssenceTeleport.kt index c0ba603a5..490477409 100644 --- a/Server/src/main/kotlin/rs09/game/content/global/travel/EssenceTeleport.kt +++ b/Server/src/main/kotlin/rs09/game/content/global/travel/EssenceTeleport.kt @@ -38,7 +38,7 @@ object EssenceTeleport { npc.faceTemporary(player, 1) npc.graphics(Graphics(108)) player.lock() - player.audioManager.send(195) + player.audioManager.send(125) Projectile.create(npc, player, 109).send() npc.sendChat("Senventior Disthinte Molesko!") GameWorld.Pulser.submit(object : Pulse(1) { @@ -177,4 +177,4 @@ object EssenceTeleport { } } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt b/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt index 7dcb61a8a..dc015aa6f 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt @@ -129,7 +129,7 @@ class CombatPulse( if (handler == null) { handler = entity.getSwingHandler(true) } - if (!entity.isAttackable(v, handler!!.type)) { + if (!v.isAttackable(entity, handler!!.type)) { return true } if (!swing(entity, victim, handler)) { diff --git a/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/MeleeSwingHandler.kt b/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/MeleeSwingHandler.kt index 67839e677..315133061 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/MeleeSwingHandler.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/MeleeSwingHandler.kt @@ -244,6 +244,18 @@ open class MeleeSwingHandler if (state.secondaryHit > 0) { hit += state.secondaryHit } + if(state.targets != null) { + for (s in state.targets) { + if (s != null) { + if(s.estimatedHit > 0) { + hit += s.estimatedHit + } + if(s.secondaryHit > 0) { + hit += s.secondaryHit + } + } + } + } var experience = hit * EXPERIENCE_MOD val famExp = entity.getAttribute("fam-exp", false) && entity.familiarManager.hasFamiliar() if (!famExp) { diff --git a/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/RangeSwingHandler.kt b/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/RangeSwingHandler.kt index c40eaac9d..5e3bc381a 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/RangeSwingHandler.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/combat/handlers/RangeSwingHandler.kt @@ -148,6 +148,18 @@ open class RangeSwingHandler if (state.secondaryHit > 0) { hit += state.secondaryHit } + if(state.targets != null) { + for (s in state.targets) { + if (s != null) { + if(s.estimatedHit > 0) { + hit += s.estimatedHit + } + if(s.secondaryHit > 0) { + hit += s.secondaryHit + } + } + } + } val p = entity.asPlayer() val famExp = entity.getAttribute("fam-exp", false) && p.familiarManager.hasFamiliar() if (famExp) { diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt index 74bcb6c47..35844271a 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/FarmingPatch.kt @@ -65,9 +65,11 @@ enum class FarmingPatch(val varpIndex: Int, val varpOffset: Int, val type: Patch //Other DRAYNOR_BELLADONNA(512, 16, PatchType.BELLADONNA), + CANIFIS_MUSHROOM(512, 8, PatchType.MUSHROOM), ALKHARID_CACTUS(512, 0, PatchType.CACTUS), EVIL_TURNIP(1171, 7, PatchType.EVIL_TURNIP); + companion object { @JvmField val patches = FarmingPatch.values().map { (it.varpIndex shl it.varpOffset) to it }.toMap() @@ -93,4 +95,4 @@ enum class FarmingPatch(val varpIndex: Int, val varpOffset: Int, val type: Patch } else state.getPatch(this) } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt index 070e38617..824ce1b68 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt @@ -2,6 +2,7 @@ package rs09.game.node.entity.skill.farming import core.game.node.entity.player.Player import core.tools.RandomFunction +import org.rs09.consts.Items import rs09.game.system.SystemLogger import java.util.concurrent.TimeUnit import kotlin.math.ceil @@ -16,11 +17,20 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl var cropLives = 3 fun setNewHarvestAmount() { + val compostMod = when(compost) { + CompostType.NONE -> 0 + CompostType.NORMAL -> 1 + CompostType.SUPER -> 2 + } harvestAmt = when (plantable) { Plantable.LIMPWURT_SEED, Plantable.WOAD_SEED -> 3 + Plantable.MUSHROOM_SPORE -> 6 else -> 1 } - cropLives = 3 + if(plantable != null && plantable?.applicablePatch != PatchType.FLOWER) { + harvestAmt += compostMod + } + cropLives = 3 + compostMod } fun rollLivesDecrement(farmingLevel: Int, magicSecateurs: Boolean){ @@ -59,8 +69,9 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl PatchType.ALLOTMENT -> 8 //average of 8 per life times 3 lives = average 24 PatchType.HOPS -> 6 //average of 6 per life times 3 lives = 18 PatchType.BELLADONNA -> 2 //average of 2 per life times 3 lives = 6 + PatchType.EVIL_TURNIP -> 2 //average 2 per, same as BELLADONNA PatchType.CACTUS -> 3 //average of 3 per life times 3 lives = 9 - else -> return + else -> 0 // nothing should go here, but if it does, do not give extra crops amd decrement cropLives } if(magicSecateurs) chance += ceil(1.10 * chance).toInt() //will increase average yield by roughly 3. @@ -226,7 +237,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl CompostType.SUPER -> 13 } - if(RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP){ + if(patch != FarmingPatch.TROLL_STRONGHOLD_HERB && RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP ){ //bush, tree, fruit tree, herb and cactus can not disease on stage 1(0) of growth. if(!((patch.type == PatchType.BUSH || patch.type == PatchType.TREE || patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.CACTUS || patch.type == PatchType.HERB) && currentGrowthStage == 0)) { isDiseased = true @@ -293,6 +304,8 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl else -> return false }.getPatchFor(player) - return (fpatch.plantable != null && fpatch.plantable == plantable?.protectionFlower && fpatch.isGrown()) + return (fpatch.plantable != null && + (fpatch.plantable == plantable?.protectionFlower || fpatch.plantable == Plantable.forItemID(Items.WHITE_LILY_SEED_14589)) + && fpatch.isGrown()) } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt index 7de600039..753de795e 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/PatchType.kt @@ -9,7 +9,8 @@ enum class PatchType(val stageGrowthTime: Int) { FLOWER(5), HERB(20), SPIRIT_TREE(293), + MUSHROOM(30), BELLADONNA(80), CACTUS(60), EVIL_TURNIP(5) -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt index 8921590d3..4aa16095b 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Plantable.kt @@ -78,6 +78,7 @@ enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plant //Other BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA, Items.CAVE_NIGHTSHADE_2398), + MUSHROOM_SPORE(Items.MUSHROOM_SPORE_5282, 6, 7, 61.5, 57.7, 0.0, 53, PatchType.MUSHROOM, Items.MUSHROOM_6004), CACTUS_SEED(Items.CACTUS_SEED_5280, 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS, Items.CACTUS_SPINE_6016), EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP, Items.EVIL_TURNIP_12134) ; @@ -98,4 +99,4 @@ enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plant return forItemID(item.id) } } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt index 22d160a93..ae45353ca 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt @@ -125,7 +125,7 @@ object UseWithPatchHandler{ if(player.inventory.remove(event.usedItem,false)){ p.compost = if(usedItem.id == Items.SUPERCOMPOST_6034) CompostType.SUPER else CompostType.NORMAL if(p.compost == CompostType.SUPER) ContentAPI.rewardXP(player, Skills.FARMING, 26.0) else ContentAPI.rewardXP(player, Skills.FARMING, 18.5) - if(p.plantable != null){ + if(p.plantable != null && p.plantable?.applicablePatch != PatchType.FLOWER) { p.harvestAmt += if(p.compost == CompostType.NORMAL) 1 else if(p.compost == CompostType.SUPER) 2 else 0 } p.cropLives += if(p.compost == CompostType.SUPER) 2 else 1 @@ -212,4 +212,4 @@ object UseWithPatchHandler{ if(this == Items.WATERING_CAN1_5333) return Items.WATERING_CAN_5331 else return this - 1 } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/hunter/pitfall/HunterPitfall.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/hunter/pitfall/HunterPitfall.kt index 5f83e7d61..0226fa5aa 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/hunter/pitfall/HunterPitfall.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/hunter/pitfall/HunterPitfall.kt @@ -319,6 +319,10 @@ class PitfallNPC : AbstractNPC { } override fun isAttackable(entity: Entity, style: CombatStyle): Boolean { - return entity is Player + return false + } + + override fun isIgnoreAttackRestrictions(victim: Entity): Boolean { + return victim is Player } } diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/slayer/SlayerUtils.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/slayer/SlayerUtils.kt new file mode 100644 index 000000000..cf4cd4170 --- /dev/null +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/slayer/SlayerUtils.kt @@ -0,0 +1,18 @@ +package rs09.game.node.entity.skill.slayer + +import core.game.node.entity.combat.BattleState +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.SpellBookManager.SpellBook +import org.rs09.consts.Items + +class SlayerUtils(val player: Player) { + + fun hasBroadWeaponEquipped(state: BattleState): Boolean { + return (state.weapon != null && state.weapon.id == Items.LEAF_BLADED_SPEAR_4158 || + state.weapon != null && state.weapon.id == Items.LEAF_BLADED_SWORD_13290 || + state.ammunition != null && (state.ammunition.itemId == Items.BROAD_ARROW_4160 || state.ammunition.itemId == Items.BROAD_TIPPED_BOLTS_13280) || + state.spell != null && state.spell.spellId == 31 && player.spellBookManager + .spellBook == SpellBook.MODERN.interfaceId + ) + } +} \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/AvaDeviceState.kt b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/AvaDeviceState.kt index 45fac8e30..c752691f8 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/AvaDeviceState.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/AvaDeviceState.kt @@ -22,8 +22,7 @@ class AvaDeviceState(player: Player? = null) : State(player) { private val ACCUMULATOR_REWARDS = arrayOf(Items.STEEL_BAR_2353,Items.STEEL_2H_SWORD_1311,Items.STEEL_KNIFE_865,Items.STEEL_DAGGER_1207,Items.STEEL_MED_HELM_1141,Items.STEEL_DART_808,Items.STEEL_BOLTS_9141,Items.STEEL_ARROW_886,Items.IRON_BAR_2351) override fun save(root: JSONObject) { - if(pulse == null || !pulse!!.isRunning) - root.put("device-id",device) + root.put("device-id",device) } override fun parse(_data: JSONObject) { @@ -44,6 +43,8 @@ class AvaDeviceState(player: Player? = null) : State(player) { pulse = object : Pulse(TICKS){ override fun pulse(): Boolean { if(!hasDevice(player)){ + player.clearState("avadevice") + pulse = null return true } @@ -93,4 +94,4 @@ class AvaDeviceState(player: Player? = null) : State(player) { return false } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/GodspellChargedState.kt b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/GodspellChargedState.kt index 58d7641ac..dfa3be5d7 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/GodspellChargedState.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/GodspellChargedState.kt @@ -5,37 +5,40 @@ import core.game.system.task.Pulse import org.json.simple.JSONObject import rs09.game.node.entity.state.newsys.PlayerState import rs09.game.node.entity.state.newsys.State +import rs09.game.world.GameWorld; @PlayerState("godcharge") class GodspellChargedState(player: Player? = null) : State(player) { - var TICKS = 700 + val DURATION = 700 + var startTick: Int = 0 override fun save(root: JSONObject) { - if(TICKS > 0){ - root.put("ticksleft",TICKS) - } + root.put("ticks_elapsed", GameWorld.ticks - startTick) } override fun parse(_data: JSONObject) { - if(_data.containsKey("ticksleft")){ - TICKS = _data["ticksleft"].toString().toInt() + if(_data.containsKey("ticks_elapsed")){ + startTick = GameWorld.ticks - _data["ticks_elapsed"].toString().toInt() } } override fun newInstance(player: Player?): State { - return GodspellChargedState(player) + var ret = GodspellChargedState(player) + ret.startTick = GameWorld.ticks + return ret } override fun createPulse() { player ?: return - if(TICKS <= 0) return - pulse = object : Pulse(TICKS){ + if(GameWorld.ticks - startTick >= DURATION) return + pulse = object : Pulse(DURATION) { override fun pulse(): Boolean { player.sendMessage("Your magical charge fades away.") + player.clearState("godcharge") pulse = null return true } } } -} \ No newline at end of file +}