Merge branch 2009scape:master into valid-shop-repairs

This commit is contained in:
Tooze 2026-07-19 01:29:01 +00:00
commit cddeb86c34
8 changed files with 134 additions and 122 deletions

View file

@ -539,6 +539,12 @@
"walkable": "true",
"tabIndex": "-1"
},
{
"id": "375",
"interfaceType": "3",
"walkable": "false",
"tabIndex": "-1"
},
{
"id": "377",
"interfaceType": "8",

View file

@ -0,0 +1,77 @@
package content.global.handlers.item
import core.api.*
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.Player
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
/**
* Handles morphing with the Ring of Stone and Easter Ring.
*/
class MorphItemListener : InteractionListener, InterfaceListener {
// the morphing items
private val morphItems = intArrayOf(Items.RING_OF_STONE_6583, Items.EASTER_RING_7927)
// the NPCs to morph into
private val easterEggs = intArrayOf(
NPCs.EGG_3689,
NPCs.EGG_3690,
NPCs.EGG_3691,
NPCs.EGG_3692,
NPCs.EGG_3693,
NPCs.EGG_3694
)
private val stone = intArrayOf(NPCs.ROCKS_2626)
// the "unmorph" interface
private val morphIface = 375
// equipping the morph items
override fun defineListeners() {
onEquip(morphItems) { player, item ->
morph(player, item.id)
return@onEquip false
}
}
// the interface that appears when you morph
override fun defineInterfaceListeners() {
// hitting the 'unmorph' button
on(morphIface){ player, _, _, buttonID, _, _ ->
when(buttonID) {
3 -> closeAllInterfaces(player)
}
return@on true
}
// after the interface closes
onClose(morphIface) { player, _ ->
unmorph(player)
return@onClose true
}
}
// morphs the player
private fun morph(player: Player, item: Int) {
val morphId = when (item) {
Items.RING_OF_STONE_6583 -> stone.random()
else -> easterEggs.random()
}
playAudio(player, Sounds.EASTER06_HUMAN_INTO_EGG_1520)
stopWalk(player)
closeAllInterfaces(player)
player.appearance.transformNPC(morphId)
openInterface(player, morphIface)
}
// unmorphs the player
private fun unmorph(player: Player) {
player.appearance.transformNPC(-1)
}
}

View file

@ -1,113 +0,0 @@
package content.global.handlers.item;
import core.cache.def.impl.ItemDefinition;
import core.game.component.CloseEvent;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
import core.tools.RandomFunction;
import org.rs09.consts.Sounds;
import static core.api.ContentAPIKt.playAudio;
/**
* Handles a morph item.
* @author Vexia
*/
@Initializable
public class MorphItemPlugin implements Plugin<Object> {
/**
* The easter egg ids.
*/
protected static final int[] EASTER_EGG_IDS = new int[] { 3689, 3690, 3691, 3692, 3693, 3694 };
/**
* The morph component.
*/
private static final Component COMPONENT = new Component(375).setCloseEvent(new CloseEvent() {
@Override
public boolean close(Player player, Component c) {
unmorph(player);
return true;
}
});
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ItemDefinition.forId(7927).getHandlers().put("equipment", this);
ItemDefinition.forId(6583).getHandlers().put("equipment", this);
ClassScanner.definePlugin(new MorphInterfacePlugin());
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
final Player player = (Player) args[0];
final Item item = (Item) args[1];
switch (identifier) {
case "equip":
morph(player, item);
return false;
}
return true;
}
/**
* Morphs the player.
* @param player the player.
* @param item the item.
*/
private void morph(Player player, Item item) {
int morphId = item.getId() == 6583 ? 2626 : EASTER_EGG_IDS[RandomFunction.random(EASTER_EGG_IDS.length)];
playAudio(player, 1520);
player.getInterfaceManager().close();
player.getAppearance().transformNPC(morphId);
player.getInterfaceManager().removeTabs(0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
player.getLocks().lockMovement(GameWorld.getTicks() + 900000000);
player.getLocks().lockInteractions(GameWorld.getTicks() + 90000000);
player.getLocks().lockTeleport(GameWorld.getTicks() + 900000000);
player.getInterfaceManager().openSingleTab(COMPONENT);
player.getAppearance().sync();
player.getWalkingQueue().reset();
}
/**
* Unmorphs the player.
* @param player the player.
*/
private static void unmorph(Player player) {
player.getAppearance().transformNPC(-1);
player.unlock();
player.getInterfaceManager().restoreTabs();
}
/**
* Handles the morph interface plugin.
* @author Vexia
*/
public class MorphInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(375).setPlugin(this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
player.getInterfaceManager().closeSingleTab();
return true;
}
}
}

View file

@ -106,7 +106,7 @@ public enum SmithingType {
/**
* Grapple Tips
*/
TYPE_GRAPPLE_TIP(1, 170, 171, new int[] { 175, 176, 175, 174, 173 }, 1),
TYPE_GRAPPLE_TIP(1, 170, 171, new int[] { 176, 175, 174, 173 }, 1),
/**
* The studs type.

View file

@ -9,6 +9,7 @@ import core.game.node.entity.combat.spell.CombatSpell;
/**
* Represents an entity's current battle state.
*
* @author Emperor
*/
public final class BattleState {
@ -99,6 +100,7 @@ public final class BattleState {
/**
* Constructs a new {@code BattleState} {@Code Object}
*
* @param victim The victim entity.
*/
public BattleState(Entity entity, Entity victim) {
@ -134,6 +136,7 @@ public final class BattleState {
/**
* Gets the estimatedHit.
*
* @return The estimatedHit.
*/
public int getEstimatedHit() {
@ -142,6 +145,7 @@ public final class BattleState {
/**
* Sets the estimated hit.
*
* @param estimatedHit The estimated hit to set.
*/
public void setEstimatedHit(int estimatedHit) {
@ -164,6 +168,7 @@ public final class BattleState {
/**
* Gets the recoilDamage.
*
* @return The recoilDamage.
*/
public int getRecoilDamage() {
@ -172,6 +177,7 @@ public final class BattleState {
/**
* Sets the recoilDamage.
*
* @param recoilDamage The recoilDamage to set.
*/
public void setRecoilDamage(int recoilDamage) {
@ -236,6 +242,7 @@ public final class BattleState {
/**
* Gets the maximumHit.
*
* @return The maximumHit.
*/
public int getMaximumHit() {
@ -244,6 +251,7 @@ public final class BattleState {
/**
* Sets the maximumHit.
*
* @param maximumHit The maximumHit to set.
*/
public void setMaximumHit(int maximumHit) {
@ -252,6 +260,7 @@ public final class BattleState {
/**
* Gets the rangeWeapon.
*
* @return The rangeWeapon.
*/
public RangeWeapon getRangeWeapon() {
@ -260,6 +269,7 @@ public final class BattleState {
/**
* Sets the rangeWeapon.
*
* @param rangeWeapon The rangeWeapon to set.
*/
public void setRangeWeapon(RangeWeapon rangeWeapon) {
@ -268,6 +278,7 @@ public final class BattleState {
/**
* Gets the ammunition.
*
* @return The ammunition.
*/
public Ammunition getAmmunition() {
@ -276,6 +287,7 @@ public final class BattleState {
/**
* Sets the ammunition.
*
* @param ammunition The ammunition to set.
*/
public void setAmmunition(Ammunition ammunition) {
@ -284,6 +296,7 @@ public final class BattleState {
/**
* Gets the frozen.
*
* @return The frozen.
*/
public boolean isFrozen() {
@ -292,6 +305,7 @@ public final class BattleState {
/**
* Sets the frozen.
*
* @param frozen The frozen to set.
*/
public void setFrozen(boolean frozen) {
@ -300,6 +314,7 @@ public final class BattleState {
/**
* Gets the style.
*
* @return The style.
*/
public CombatStyle getStyle() {
@ -308,6 +323,7 @@ public final class BattleState {
/**
* Sets the style.
*
* @param style The style to set.
*/
public void setStyle(CombatStyle style) {
@ -316,6 +332,7 @@ public final class BattleState {
/**
* Gets the armourEffect.
*
* @return The armourEffect.
*/
public ArmourSet getArmourEffect() {
@ -324,6 +341,7 @@ public final class BattleState {
/**
* Sets the armourEffect.
*
* @param armourEffect The armourEffect to set.
*/
public void setArmourEffect(ArmourSet armourEffect) {
@ -332,6 +350,7 @@ public final class BattleState {
/**
* Gets the attacking entity.
*
* @return The entity.
*/
public Entity getAttacker() {
@ -340,10 +359,9 @@ public final class BattleState {
public int getTotalDamage() {
int hit = Math.max(estimatedHit, 0) + Math.max(secondaryHit, 0);
if (targets != null) {
for (BattleState s : targets) {
if (s != null) {
if (s != null && s != this) {
hit += Math.max(s.getEstimatedHit(), 0) + Math.max(s.getSecondaryHit(), 0);
}
}

View file

@ -254,9 +254,15 @@ abstract class CombatSwingHandler(var type: CombatStyle?) {
?: return InteractionType.STILL_INTERACT //if we cannot derive a direction, it's because both tiles are the same, so hand off control to the main logic which already handles this case
var next = closestEntityTile
while (next.getDistance(closestVictimTile) > 3) { //skip the initial gap in distance if it exists, because standard pathfinding would already stop us before this point if something was between us and the NPC or vice versa
//Skip the initial gap in distance if it exists, because standard pathfinding would already stop us before this point if something was between us and the NPC or vice versa.
//A fixed-direction walk can only arrive within its starting distance in steps; on oblique approaches it
//passes beside the target and never converges, so the walk is hard-capped at that many steps.
val maxSkipSteps = next.getDistance(closestVictimTile).toInt() + 1
for (i in 0 until maxSkipSteps) {
if (next.getDistance(closestVictimTile) <= 3) break
next = next.transform(dir)
}
if (next.getDistance(closestVictimTile) > 3) return InteractionType.STILL_INTERACT //never converged (oblique approach), so defer to the range checks instead
var result: InteractionType = InteractionType.STILL_INTERACT
val maxIterations = next.getDistance(closestVictimTile).toInt()

View file

@ -253,10 +253,14 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
return 1.0 + (e!!.skills.maximumLifepoints - e.skills.lifepoints) * 0.01
}
var multiplier = 1.0
if(e is Player && e.isWearingVoid(CombatStyle.MELEE) && (skillId == Skills.ATTACK || skillId == Skills.STRENGTH)) {
return 1.1
multiplier += 0.1
}
return 1.0
if (e is Player && e.properties.armourSet === ArmourSet.BERSERKER_NECKLACE_SETS && skillId == Skills.STRENGTH) {
multiplier += 0.2
}
return multiplier
}
override fun getArmourSet(e: Entity?): ArmourSet? {
@ -269,6 +273,9 @@ open class MeleeSwingHandler (vararg flags: SwingHandlerFlag)
if (ArmourSet.VERAC.isUsing(e)) {
return ArmourSet.VERAC
}
if (ArmourSet.BERSERKER_NECKLACE_SETS.isUsing(e)) {
return ArmourSet.BERSERKER_NECKLACE_SETS
}
return if (ArmourSet.TORAG.isUsing(e)) {
ArmourSet.TORAG
} else super.getArmourSet(e)

View file

@ -8,6 +8,7 @@ import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.update.flag.context.Graphics;
import core.tools.RandomFunction;
import org.rs09.consts.Items;
/**
* Represents the types of armour sets.
@ -129,6 +130,15 @@ public enum ArmourSet {
}
return super.isUsing(e);
}
},
/**
* Berserker Necklace sets
*/
BERSERKER_NECKLACE_SETS(null, new int[][] { { Items.BERSERKER_NECKLACE_11128 }, { Items.TOKTZ_XIL_AK_6523, Items.TOKTZ_XIL_EK_6525, Items.TZHAAR_KET_EM_6527, Items.TZHAAR_KET_OM_6528 } }) {
@Override
public boolean isUsing(Entity e) {
return super.isUsing(e);
}
};
/**
@ -148,8 +158,9 @@ public enum ArmourSet {
*/
private ArmourSet(Graphics endGraphic, int[][] set) {
this.endGraphic = endGraphic;
this.sets = new Item[4][5];
this.sets = new Item[set.length][];
for (int i = 0; i < set.length; i++) {
sets[i] = new Item[set[i].length];
for (int k = 0; k < sets[i].length; k++) {
sets[i][k] = new Item(set[i][k]);
}
@ -197,7 +208,7 @@ public enum ArmourSet {
}
}
}
return hits == 4;
return hits == sets.length;
}
}
}