Merge remote-tracking branch 'origin/master'

This commit is contained in:
ceikry 2021-09-30 21:35:31 -05:00
commit fe685d18ac
34 changed files with 237 additions and 134 deletions

View file

@ -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,

View file

@ -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<Player> waitingPlayers = new ArrayList<>(20);
private final PriorityQueue<Player> waitingPlayers = new PriorityQueue<Player>(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<Player> getWaitingPlayers() {
public PriorityQueue<Player> getWaitingPlayers() {
return waitingPlayers;
}

View file

@ -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<Player> waitingPlayers) {
public void startGame(PriorityQueue<Player> waitingPlayers) {
region.flagActive();
initBarricadesList();
List<Integer> list = new ArrayList<>(20);
@ -225,21 +221,29 @@ public final class PestControlSession {
ids = list.toArray(new Integer[4]);
int count = 0;
String portalHealth = "<col=00FF00>" + (activity.getType().ordinal() == 0 ? 200 : 250);
for (Iterator<Player> it = waitingPlayers.iterator(); it.hasNext();) {
Player p = it.next();
List<Player> 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();
}
/**

View file

@ -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)

View file

@ -34,18 +34,16 @@ public final class AvasDevicePlugin implements Plugin<Object> {
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;
}

View file

@ -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

View file

@ -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<Player, Integer> 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.

View file

@ -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;
}
}
}

View file

@ -134,9 +134,12 @@ public final class BindSpell extends CombatSpell {
@Override
public Plugin<SpellType> 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;
}

View file

@ -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) {

View file

@ -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<WeightedChanceItem> defaultTable = new ArrayList<>(20);
/**
* The charms drop table (holding the charm drops).
*/
private final List<WeightedChanceItem> charmTable = new ArrayList<>(20);
/**
* The main drop table (holding the main drops).
*/
private final List<WeightedChanceItem> 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<WeightedChanceItem> getDefaultTable() {
return defaultTable;
}
/**
* @return the charmTable.
*/
public List<WeightedChanceItem> getCharmTable() {
return charmTable;
}
/**
* @return the mainTable.
*/
public List<WeightedChanceItem> 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.

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}

View file

@ -133,6 +133,7 @@ public final class RuneCraftPulse extends SkillPulse<Item> {
public void animate() {
player.animate(ANIMATION);
player.graphics(GRAPHICS);
player.getAudioManager().send(2710);
}
@Override
@ -234,14 +235,14 @@ public final class RuneCraftPulse extends SkillPulse<Item> {
}
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<Item> {
*
* @return <code>True</code> if so.
*/
public boolean hasBindingNeckalce() {
public boolean hasBindingNecklace() {
return player.getEquipment().containsItem(BINDING_NECKLACE);
}

View file

@ -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);

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -538,11 +538,15 @@ object RegionManager {
*/
@JvmStatic
fun getSurroundingPlayers(n: Node, maximum: Int, vararg ignore: Node): List<Player> {
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<NPC> {
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
}
}

View file

@ -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 {
}
}
}
}

View file

@ -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)) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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)
}
}
}

View file

@ -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())
}
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}
}
}

View file

@ -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
}
}
}

View file

@ -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
}
}

View file

@ -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
)
}
}

View file

@ -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
}
}
}

View file

@ -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
}
}
}
}
}