Fixed issue preventing pickup of dwarf remains in Dwarf Cannon

Added more sophisticated debug varp printing
Fixed issue preventing surprise exam rewards if player moves before reward is granted
Voluntarily leaving a clan should now persist
Fixed bug that would result in keeping the previous wand when purchasing MTA upgrade
Fixed issue preventing proper teleport jewellery usage
Fixed a bug that prevented manual casting of Ancient spells
Added many sanity checks to death code and fixed a bug with delayed impacts
Added dragon slayer requirements to Green (g) and Green (t) bodies
Rewrote the "catchup" logic used for growing farming patches during missed playtime
Fixed bug preventing fruit trees and berries from growing while logged out
Summoning potion now correctly restores 25% of summoning special energy
This commit is contained in:
Ceikry
2023-01-24 01:37:39 +00:00
committed by Ryan
parent dd5e63a409
commit 4e6e2e678d
24 changed files with 129 additions and 61 deletions
@@ -17,6 +17,7 @@ import core.plugin.Plugin;
import core.tools.RandomFunction; import core.tools.RandomFunction;
import kotlin.Unit; import kotlin.Unit;
import rs09.game.content.global.action.EquipHandler; import rs09.game.content.global.action.EquipHandler;
import rs09.game.node.entity.player.info.LogType;
import rs09.game.node.entity.player.info.PlayerMonitor; import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.system.config.ItemConfigParser; import rs09.game.system.config.ItemConfigParser;
@@ -311,7 +312,7 @@ public final class DuelSession extends ComponentPlugin {
log = log.substring(0, log.length() - 1); log = log.substring(0, log.length() - 1);
} }
log += "}"; log += "}";
PlayerMonitor.logMisc(player, "Duel", log); PlayerMonitor.log(player, LogType.DUEL_INFO, log);
} else { } else {
player.removeExtension(DuelSession.class); player.removeExtension(DuelSession.class);
} }
@@ -1,5 +1,6 @@
package core.game.content.activity.mta; package core.game.content.activity.mta;
import api.ContainerisedItem;
import core.game.component.CloseEvent; import core.game.component.CloseEvent;
import core.game.component.Component; import core.game.component.Component;
import core.game.component.ComponentPlugin; import core.game.component.ComponentPlugin;
@@ -15,6 +16,8 @@ import rs09.game.world.GameWorld;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static api.ContentAPIKt.hasAnItem;
/** /**
* Represents the mage training arena shop. * Represents the mage training arena shop.
* @author Vexia * @author Vexia
@@ -147,9 +150,11 @@ public class MTAShop {
player.sendMessage("You already unlocked that spell."); player.sendMessage("You already unlocked that spell.");
return; return;
} }
ContainerisedItem itemToRemove = null;
if (slot >= 1 && slot <= 3) { if (slot >= 1 && slot <= 3) {
Item required = ITEMS[slot - 1]; Item required = ITEMS[slot - 1];
if (!player.hasItem(new Item(required.getId(), 1)) && !player.hasItem(new Item(6914, 1))) { itemToRemove = hasAnItem(player, required.getId());
if (!itemToRemove.exists() && !player.hasItem(new Item(6914, 1))) {
player.sendMessage("You don't have the required wand in order to buy this upgrade."); player.sendMessage("You don't have the required wand in order to buy this upgrade.");
return; return;
} }
@@ -163,6 +168,7 @@ public class MTAShop {
player.getSavedData().getActivityData().setBonesToPeaches(true); player.getSavedData().getActivityData().setBonesToPeaches(true);
player.getDialogueInterpreter().sendDialogue("The guardian teaches you how to use the Bones to Peaches spell!"); player.getDialogueInterpreter().sendDialogue("The guardian teaches you how to use the Bones to Peaches spell!");
} else { } else {
if (itemToRemove == null || itemToRemove.remove())
player.getInventory().add(item); player.getInventory().add(item);
} }
for (int i = 0; i < prices.length; i++) { for (int i = 0; i < prices.length; i++) {
@@ -7,6 +7,7 @@ import core.game.world.update.flag.context.Animation;
import core.game.content.consumable.effects.*; import core.game.content.consumable.effects.*;
import core.game.node.entity.skill.Skills; import core.game.node.entity.skill.Skills;
import rs09.game.content.consumable.effects.KegOfBeerEffect; import rs09.game.content.consumable.effects.KegOfBeerEffect;
import rs09.game.content.consumable.effects.RestoreSummoningSpecial;
import java.util.HashMap; import java.util.HashMap;
@@ -321,7 +322,7 @@ public enum Consumables {
HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))), HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))),
RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))), RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))),
SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(2, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 2, 0.2)))), SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(2, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 2, 0.2)))),
SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new SummoningEffect(7, 0.25))), SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new MultiEffect(new RestoreSummoningSpecial(), new SummoningEffect(7, 0.25)))),
COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))), COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))),
ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new MultiEffect(new EnergyEffect(10), new HealingEffect(3)))), ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new MultiEffect(new EnergyEffect(10), new HealingEffect(3)))),
FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))), FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))),
@@ -338,6 +338,8 @@ public abstract class Entity extends Node {
* @param state The battle state. * @param state The battle state.
*/ */
public void onImpact(final Entity entity, BattleState state) { public void onImpact(final Entity entity, BattleState state) {
if (DeathTask.isDead(this))
state.neutralizeHits();
if (properties.isRetaliating() && !properties.getCombatPulse().isAttacking() && !getLocks().isInteractionLocked() && properties.getCombatPulse().getNextAttack() < GameWorld.getTicks()) { if (properties.isRetaliating() && !properties.getCombatPulse().isAttacking() && !getLocks().isInteractionLocked() && properties.getCombatPulse().getNextAttack() < GameWorld.getTicks()) {
if (!getWalkingQueue().hasPath() && !getPulseManager().isMovingPulse() || (this instanceof NPC)) { if (!getWalkingQueue().hasPath() && !getPulseManager().isMovingPulse() || (this instanceof NPC)) {
properties.getCombatPulse().attack(entity); properties.getCombatPulse().attack(entity);
@@ -138,6 +138,11 @@ public final class ImpactHandler {
* @return The impact object created. * @return The impact object created.
*/ */
public Impact handleImpact(Entity source, int hit, final CombatStyle style, final BattleState state, HitsplatType type, boolean secondary) { public Impact handleImpact(Entity source, int hit, final CombatStyle style, final BattleState state, HitsplatType type, boolean secondary) {
if (DeathTask.isDead(this.entity)) {
this.entity.getProperties().getCombatPulse().setVictim(null);
this.entity.getProperties().getCombatPulse().stop();
return null;
}
boolean fam = source instanceof Familiar; boolean fam = source instanceof Familiar;
if (fam) { if (fam) {
source = ((Familiar) source).getOwner(); source = ((Familiar) source).getOwner();
@@ -394,6 +394,8 @@ public class NPC extends Entity {
return; return;
} }
if (respawnTick > GameWorld.getTicks()) { if (respawnTick > GameWorld.getTicks()) {
if (respawnTick - GameWorld.getTicks() == 2)
teleport(getProperties().getSpawnLocation());
return; return;
} }
if (respawnTick == GameWorld.getTicks()) { if (respawnTick == GameWorld.getTicks()) {
@@ -522,9 +524,8 @@ public class NPC extends Entity {
GlobalKillCounter.incrementKills(p, originalId); GlobalKillCounter.incrementKills(p, originalId);
} }
handleDrops(p, killer); handleDrops(p, killer);
if (!isRespawn()) { if (!isRespawn())
clear(); clear();
}
killer.dispatch(new NPCKillEvent(this)); killer.dispatch(new NPCKillEvent(this));
} }
@@ -65,13 +65,12 @@ import proto.management.ClanLeaveNotification;
import proto.management.PlayerStatusUpdate; import proto.management.PlayerStatusUpdate;
import rs09.GlobalStats; import rs09.GlobalStats;
import rs09.ServerConstants; import rs09.ServerConstants;
import rs09.game.Varp;
import rs09.game.VarpManager; import rs09.game.VarpManager;
import rs09.game.node.entity.combat.CombatSwingHandler; import rs09.game.node.entity.combat.CombatSwingHandler;
import rs09.game.node.entity.combat.equipment.EquipmentDegrader; import rs09.game.node.entity.combat.equipment.EquipmentDegrader;
import rs09.game.node.entity.player.graves.Grave; import rs09.game.node.entity.player.graves.Grave;
import rs09.game.node.entity.player.graves.GraveType;
import rs09.game.node.entity.player.graves.GraveController; import rs09.game.node.entity.player.graves.GraveController;
import rs09.game.node.entity.player.info.LogType;
import rs09.game.node.entity.player.info.PlayerMonitor; import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.node.entity.player.info.login.PlayerSaver; import rs09.game.node.entity.player.info.login.PlayerSaver;
import rs09.game.node.entity.skill.runecrafting.PouchManager; import rs09.game.node.entity.skill.runecrafting.PouchManager;
@@ -654,7 +653,7 @@ public class Player extends Entity {
GroundItemManager.create(item, location, killer instanceof Player ? (Player) killer : this); GroundItemManager.create(item, location, killer instanceof Player ? (Player) killer : this);
} }
if (killer instanceof Player) if (killer instanceof Player)
PlayerMonitor.logMisc((Player) killer, "PK", "Killed " + name + ", who dropped: " + itemsLost); PlayerMonitor.log((Player) killer, LogType.PK, "Killed " + name + ", who dropped: " + itemsLost);
sendMessage(colorize("%RDue to the circumstances of your death, you do not have a grave.")); sendMessage(colorize("%RDue to the circumstances of your death, you do not have a grave."));
} }
@@ -103,6 +103,7 @@ public abstract class NodeTask {
return NodeTask.this.removeFor(s, node, n); return NodeTask.this.removeFor(s, node, n);
} }
}; };
pulse.start();
return pulse; return pulse;
} }
@@ -603,8 +603,17 @@ object RegionManager {
val it = npcs.iterator() val it = npcs.iterator()
while (it.hasNext()) { while (it.hasNext()) {
val p = it.next() val p = it.next()
if(p.properties.teleportLocation != null && !p.properties.teleportLocation.withinMaxnormDistance(n.location, 1)) {
it.remove()
continue
}
if(p.getAttribute("state:death", false)) {
it.remove()
continue
}
if(p.isInvisible()) { if(p.isInvisible()) {
it.remove() it.remove()
continue
} }
if(!p.location.withinMaxnormDistance(n.location, 1)) { if(!p.location.withinMaxnormDistance(n.location, 1)) {
it.remove() it.remove()
+24 -2
View File
@@ -55,6 +55,8 @@ import rs09.game.content.global.shops.Shops
import rs09.game.ge.GrandExchangeRecords import rs09.game.ge.GrandExchangeRecords
import rs09.game.interaction.InteractionListeners import rs09.game.interaction.InteractionListeners
import rs09.game.interaction.inter.ge.StockMarket import rs09.game.interaction.inter.ge.StockMarket
import rs09.game.node.entity.player.info.LogType
import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.node.entity.skill.slayer.SlayerManager import rs09.game.node.entity.skill.slayer.SlayerManager
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import rs09.game.system.config.ItemConfigParser import rs09.game.system.config.ItemConfigParser
@@ -164,7 +166,14 @@ fun areAnyEquipped(player: Player, vararg ids: Int): Boolean {
} }
} }
data class ContainerisedItem(val container: core.game.container.Container?, val itemId: Int) class ContainerisedItem(val container: core.game.container.Container?, val itemId: Int) {
fun remove() : Boolean {
return this.container?.remove(this.itemId.asItem()) ?: false
}
fun exists() : Boolean {
return this.container != null && this.itemId > -1
}
}
/** /**
* Check if player has any of the specified item IDs equipped, in inventory, or in banks * Check if player has any of the specified item IDs equipped, in inventory, or in banks
@@ -239,16 +248,29 @@ fun addItem(player: Player, id: Int, amount: Int = 1, container: Container = Con
* @param container the Container to modify * @param container the Container to modify
* @return the item that was previously in the slot, or null if none. * @return the item that was previously in the slot, or null if none.
*/ */
fun replaceSlot(player: Player, slot: Int, item: Item, container: Container = Container.INVENTORY): Item? { fun replaceSlot(player: Player, slot: Int, item: Item, currentItem: Item? = null, container: Container = Container.INVENTORY): Item? {
val cont = when (container) { val cont = when (container) {
Container.INVENTORY -> player.inventory Container.INVENTORY -> player.inventory
Container.EQUIPMENT -> player.equipment Container.EQUIPMENT -> player.equipment
Container.BANK -> player.bank Container.BANK -> player.bank
} }
if (currentItem == null) {
return cont.replace(item, slot) return cont.replace(item, slot)
} }
if (cont.remove(currentItem))
return cont.replace(item, slot)
PlayerMonitor.log(player, LogType.DUPE_ALERT, "Potential slot-replacement-based dupe attempt, slot: $slot, item: $item")
val other = when (container) {
Container.INVENTORY -> Container.EQUIPMENT
else -> Container.INVENTORY
}
if (removeItem(player, currentItem, other))
return cont.replace(item, slot)
return null
}
/** /**
* Add an item with a variable quantity or drop it if a player does not have enough space * Add an item with a variable quantity or drop it if a player does not have enough space
* @param player the player whose inventory to add to * @param player the player whose inventory to add to
@@ -1,6 +1,7 @@
package rs09.game.content.ame.events.supriseexam package rs09.game.content.ame.events.supriseexam
import api.* import api.*
import core.game.node.entity.impl.PulseType
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.item.GroundItemManager import core.game.node.item.GroundItemManager
import core.game.node.item.Item import core.game.node.item.Item
@@ -51,7 +52,7 @@ object SurpriseExamUtils {
} }
return true return true
} }
}) }, PulseType.CUSTOM_1)
} }
fun generateInterface(player: Player){ fun generateInterface(player: Player){
@@ -1,13 +0,0 @@
package rs09.game.content.consumable.effects
import core.game.node.entity.player.Player
import core.game.content.consumable.ConsumableEffect
import core.game.node.entity.skill.Skills
class RestoreSummoning(val percent: Double) : ConsumableEffect(){
override fun activate(p: Player?) {
var amt = (p!!.skills!!.getStaticLevel(Skills.SUMMONING) * percent).toInt()
if(amt + p.skills.getLevel(Skills.SUMMONING) > p.skills.getStaticLevel(Skills.SUMMONING)) amt = p.skills.getStaticLevel(Skills.SUMMONING) - p.skills.getLevel(Skills.SUMMONING)
p.skills.setLevel(Skills.SUMMONING, p.skills.getLevel(Skills.SUMMONING) + amt)
}
}
@@ -0,0 +1,11 @@
package rs09.game.content.consumable.effects
import core.game.content.consumable.ConsumableEffect
import core.game.node.entity.player.Player
class RestoreSummoningSpecial : ConsumableEffect(){
override fun activate(p: Player) {
val f = p.familiarManager.familiar
f?.updateSpecialPoints(-15)
}
}
@@ -14,7 +14,7 @@ import rs09.tools.END_DIALOGUE
*/ */
@Initializable @Initializable
class AlKharidShopKeeperDialogue(player: Player? = null) : DialoguePlugin() { class AlKharidShopKeeperDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin { override fun newInstance(player: Player?): DialoguePlugin {
return AlKharidShopKeeperDialogue(player) return AlKharidShopKeeperDialogue(player)
} }
@@ -249,7 +249,7 @@ enum class EnchantedJewellery(
private fun replaceJewellery(player: Player, item: Item, nextJewellery: Item, isEquipped: Boolean) { private fun replaceJewellery(player: Player, item: Item, nextJewellery: Item, isEquipped: Boolean) {
if (isEquipped) { if (isEquipped) {
replaceSlot(player, item.slot, nextJewellery, Container.EQUIPMENT) replaceSlot(player, item.slot, nextJewellery, item, Container.EQUIPMENT)
} else { } else {
replaceSlot(player, item.slot, nextJewellery) replaceSlot(player, item.slot, nextJewellery)
} }
@@ -6,14 +6,13 @@ import core.game.content.dialogue.FacialExpression
import core.game.content.global.GodType import core.game.content.global.GodType
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.link.audio.Audio import core.game.node.entity.player.link.audio.Audio
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.runecrafting.RunePouch import core.game.node.entity.skill.runecrafting.RunePouch
import core.game.node.item.GroundItem import core.game.node.item.GroundItem
import core.game.node.item.GroundItemManager import core.game.node.item.GroundItemManager
import core.game.node.item.Item import core.game.node.item.Item
import core.game.world.map.RegionManager import core.game.world.map.RegionManager
import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items import rs09.game.node.entity.player.info.LogType
import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import rs09.game.system.config.GroundSpawnLoader import rs09.game.system.config.GroundSpawnLoader
@@ -58,7 +57,7 @@ object PickupHandler {
} }
if (item.isActive && player.inventory.add(add)) { if (item.isActive && player.inventory.add(add)) {
if (item.dropper is Player && item.dropper.details.uid != player.details.uid){ if (item.dropper is Player && item.dropper.details.uid != player.details.uid){
PlayerMonitor.logMisc(item.dropper, "DropTrade", "${getItemName(item.id)} x${item.amount} picked up by ${player.name}.") PlayerMonitor.log(item.dropper, LogType.DROP_TRADE, "${getItemName(item.id)} x${item.amount} picked up by ${player.name}.")
} }
if (!RegionManager.isTeleportPermitted(item.location)) { if (!RegionManager.isTeleportPermitted(item.location)) {
player.animate(Animation.create(535)) player.animate(Animation.create(535))
@@ -83,7 +83,9 @@ class ItemQuestRequirementListener : InteractionListener {
Items.ZAMORAK_PLATEBODY_2653, Items.ZAMORAK_PLATEBODY_2653,
Items.SARADOMIN_PLATEBODY_2661, Items.SARADOMIN_PLATEBODY_2661,
Items.GUTHIX_PLATEBODY_2669, Items.GUTHIX_PLATEBODY_2669,
Items.GREEN_DHIDE_BODY_1135 Items.GREEN_DHIDE_BODY_1135,
Items.DHIDE_BODYG_7370, //Green (g)
Items.DHIDE_BODY_T_7372 //Green (t)
) )
private val questCapes = intArrayOf(9813,9814) private val questCapes = intArrayOf(9813,9814)
@@ -437,7 +437,7 @@ class CombatPulse(
GameWorld.Pulser.submit(object : Pulse(delay - 1, entity, victim) { GameWorld.Pulser.submit(object : Pulse(delay - 1, entity, victim) {
var impact = false var impact = false
override fun pulse(): Boolean { override fun pulse(): Boolean {
if (DeathTask.isDead(victim)) { if (DeathTask.isDead(victim) || DeathTask.isDead(entity)) {
return true return true
} }
if (impact || getDelay() == 0) { if (impact || getDelay() == 0) {
@@ -81,11 +81,11 @@ object PlayerMonitor {
dispatch(event) dispatch(event)
} }
@JvmStatic fun logMisc(player: Player, type: String, details: String) { @JvmStatic fun log(player: Player, type: LogType, details: String) {
val event = LogEvent.MiscLog( val event = LogEvent.MiscLog(
player.name, player.name,
player.details.uid, player.details.uid,
type, type.token,
details, details,
System.currentTimeMillis() System.currentTimeMillis()
) )
@@ -254,3 +254,12 @@ object PlayerMonitor {
private const val WEALTH_LOG_INSERT = "INSERT INTO wealth_logs(player,uid,total,diff,timestamp) VALUES (?,?,?,?,?);" private const val WEALTH_LOG_INSERT = "INSERT INTO wealth_logs(player,uid,total,diff,timestamp) VALUES (?,?,?,?,?);"
} }
enum class LogType(val token: String) {
DUPE_ALERT("dupe_warning"),
DUEL_INFO("Duel"),
PK("PK"),
DROP_TRADE("DropTrade"),
COMMAND("CommandUsed"),
IP_LOG("login_ip")
}
@@ -317,6 +317,16 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
return getCurrentState() - plantable!!.value - plantable!!.stages return getCurrentState() - plantable!!.value - plantable!!.stages
} }
fun getStageGrowthMinutes() : Int {
var minutes = patch.type.stageGrowthTime
if(patch.type == PatchType.FRUIT_TREE && isGrown()) {
// Fruit trees take 160 minutes per stage to grow, but
// restocking their fruit should take 40 minutes per fruit
minutes = 40
}
return minutes
}
fun isFlowerProtected(): Boolean{ fun isFlowerProtected(): Boolean{
if(patch.type != PatchType.ALLOTMENT) return false if(patch.type != PatchType.ALLOTMENT) return false
@@ -1,5 +1,6 @@
package rs09.game.node.entity.state.newsys.states package rs09.game.node.entity.state.newsys.states
import core.Util.clamp
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.system.task.Pulse import core.game.system.task.Pulse
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@@ -101,20 +102,6 @@ class FarmingState(player: Player? = null) : State(player) {
patch.compost = CompostType.values()[compostOrdinal] patch.compost = CompostType.values()[compostOrdinal]
patch.protectionPaid = protectionPaid patch.protectionPaid = protectionPaid
patch.setCurrentState(savedState) patch.setCurrentState(savedState)
if((patch.currentGrowthStage < patch.plantable?.stages ?: 0) && !patch.isWeedy()){
val startTime = (patch.nextGrowth - TimeUnit.MINUTES.toMillis(patch.patch.type.stageGrowthTime * (patch.currentGrowthStage + 1).toLong()))
var expectedStage = Math.floor((System.currentTimeMillis() - startTime.toDouble()) / TimeUnit.MINUTES.toMillis(patch.patch.type.stageGrowthTime.toLong())).toInt()
SystemLogger.logErr(this::class.java, "$expectedStage $startTime ${System.currentTimeMillis()}")
if(!patchDiseased && !patchDead) {
if (expectedStage > patch.plantable?.stages ?: 0) {
expectedStage = patch.plantable?.stages ?: 0
}
for(i in 0 until (expectedStage - patch.currentGrowthStage)){
patch.update()
}
}
}
if((savedState - (patch?.plantable?.value ?: 0)) > patch.currentGrowthStage){ if((savedState - (patch?.plantable?.value ?: 0)) > patch.currentGrowthStage){
patch.setCurrentState(savedState) patch.setCurrentState(savedState)
@@ -122,6 +109,25 @@ class FarmingState(player: Player? = null) : State(player) {
patch.setCurrentState((patch.plantable?.value ?: 0) + patch.currentGrowthStage) patch.setCurrentState((patch.plantable?.value ?: 0) + patch.currentGrowthStage)
} }
val type = patch.patch.type
val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE && patch.getFruitOrBerryCount() < 6)
if(shouldPlayCatchup && patch.plantable != null && !patchDead){
var stagesToSimulate = if (!patch.isGrown()) patch.plantable!!.stages - patch.currentGrowthStage else 0
if (type == PatchType.BUSH)
stagesToSimulate += Math.min(4, 4 - patch.getFruitOrBerryCount())
if (type == PatchType.FRUIT_TREE)
stagesToSimulate += Math.min(6, 6 - patch.getFruitOrBerryCount())
val nowTime = System.currentTimeMillis()
var simulatedTime = patch.nextGrowth
while (simulatedTime < nowTime && stagesToSimulate-- > 0 && !patch.isDead) {
val timeToIncrement = TimeUnit.MINUTES.toMillis(patch.getStageGrowthMinutes().toLong())
patch.update()
simulatedTime += timeToIncrement
}
}
if(patchMap[fPatch] == null) { if(patchMap[fPatch] == null) {
patchMap[fPatch] = patch patchMap[fPatch] = patch
} }
@@ -148,13 +154,7 @@ class FarmingState(player: Player? = null) : State(player) {
if(patch.nextGrowth < System.currentTimeMillis() && !patch.isDead){ if(patch.nextGrowth < System.currentTimeMillis() && !patch.isDead){
patch.update() patch.update()
var minutes = patch.patch.type.stageGrowthTime.toLong() patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(patch.getStageGrowthMinutes().toLong())
if(patch.patch.type == PatchType.FRUIT_TREE && patch.isGrown()) {
// Fruit trees take 160 minutes per stage to grow, but
// restocking their fruit should take 40 minutes per fruit
minutes = 40
}
patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(minutes)
} }
} }
@@ -38,7 +38,6 @@ import core.net.amsc.MSPacketRepository
import core.net.packet.PacketRepository import core.net.packet.PacketRepository
import core.net.packet.context.PlayerContext import core.net.packet.context.PlayerContext
import core.net.packet.out.ClearMinimapFlag import core.net.packet.out.ClearMinimapFlag
import discord.Discord
import org.rs09.consts.Components import org.rs09.consts.Components
import proto.management.ClanMessage import proto.management.ClanMessage
import proto.management.JoinClanRequest import proto.management.JoinClanRequest
@@ -53,6 +52,7 @@ import rs09.game.interaction.InteractionListeners
import rs09.game.interaction.InterfaceListeners import rs09.game.interaction.InterfaceListeners
import rs09.game.interaction.QCRepository import rs09.game.interaction.QCRepository
import rs09.game.interaction.inter.ge.StockMarket import rs09.game.interaction.inter.ge.StockMarket
import rs09.game.node.entity.player.info.LogType
import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.node.entity.skill.magic.SpellListener import rs09.game.node.entity.skill.magic.SpellListener
import rs09.game.node.entity.skill.magic.SpellListeners import rs09.game.node.entity.skill.magic.SpellListeners
@@ -199,7 +199,7 @@ object PacketProcessor {
pkt.player.interfaceManager.closeChatbox() pkt.player.interfaceManager.closeChatbox()
} }
is Packet.Command -> { is Packet.Command -> {
PlayerMonitor.logMisc(pkt.player, "CommandUse", pkt.commandLine) PlayerMonitor.log(pkt.player, LogType.COMMAND, pkt.commandLine)
CommandSystem.commandSystem.parse(pkt.player, pkt.commandLine) CommandSystem.commandSystem.parse(pkt.player, pkt.commandLine)
} }
is Packet.ChatMessage -> { is Packet.ChatMessage -> {
@@ -404,7 +404,7 @@ object PacketProcessor {
if (book != "none") if (book != "none")
SpellListeners.run(child, type, book, player, target) SpellListeners.run(child, type, book, player, target)
when (iface) { when (iface) {
430,192 -> MagicSpell.castSpell(player, SpellBookManager.SpellBook.forInterface(iface), child, target) 430,192,193 -> MagicSpell.castSpell(player, SpellBookManager.SpellBook.forInterface(iface), child, target)
662 -> { 662 -> {
if (player.familiarManager.hasFamiliar()) if (player.familiarManager.hasFamiliar())
player.familiarManager.familiar.executeSpecialMove(FamiliarSpecial(target, iface, child, target as? Item)) player.familiarManager.familiar.executeSpecialMove(FamiliarSpecial(target, iface, child, target as? Item))
@@ -664,7 +664,7 @@ object PacketProcessor {
player.debug("ID: ${wrapperChild.id}, Option: ${option.name}[${option.index}]") player.debug("ID: ${wrapperChild.id}, Option: ${option.name}[${option.index}]")
player.debug("Loc: ${scenery.location}, Dir: ${scenery.direction}") player.debug("Loc: ${scenery.location}, Dir: ${scenery.direction}")
if (hasWrapper) { if (hasWrapper) {
player.debug("WrapperID: ${scenery.id}, Varbit: ${scenery.definition.configFile.id}") player.debug("WrapperID: ${scenery.id}, ${scenery.definition.configFile?.let { "Varbit: ${it.id}"} ?: "Varp: ${scenery.definition.configId}"}")
} }
player.debug("------------------------------------------------") player.debug("------------------------------------------------")
@@ -19,6 +19,7 @@ import rs09.ServerStore
import rs09.ServerStore.Companion.addToList import rs09.ServerStore.Companion.addToList
import rs09.ServerStore.Companion.getList import rs09.ServerStore.Companion.getList
import rs09.auth.AuthResponse import rs09.auth.AuthResponse
import rs09.game.node.entity.player.info.LogType
import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.node.entity.player.info.login.LoginParser import rs09.game.node.entity.player.info.login.LoginParser
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
@@ -132,7 +133,7 @@ object Login {
} }
val player = Player(details) val player = Player(details)
PlayerMonitor.logMisc(player, "login_ip", details.ipAddress) PlayerMonitor.log(player, LogType.IP_LOG, details.ipAddress)
if (canBypassAccountLimitCheck(player)) { if (canBypassAccountLimitCheck(player)) {
proceedWithAcceptableLogin(session, player, opcode) proceedWithAcceptableLogin(session, player, opcode)
} else { } else {
@@ -223,6 +223,7 @@ object ManagementEvents {
sendMessage(p, "Error leaving clan. Please relog.") sendMessage(p, "Error leaving clan. Please relog.")
} else { } else {
clan.leave(p, true) clan.leave(p, true)
p.details.communication.clan = null
} }
} }