🆙 Updates

This commit is contained in:
duckietm
2026-01-07 15:54:18 +01:00
parent 16d88b4422
commit ad2c52d3af
28 changed files with 310 additions and 142 deletions
@@ -40,7 +40,7 @@ public class GamePlayer {
this.wiredScore += amount; this.wiredScore += amount;
} }
WiredManager.triggerScoreAchieved(this.habbo.getHabboInfo().getCurrentRoom(), this.habbo.getRoomUnit(), this.score); WiredManager.triggerScoreAchieved(this.habbo.getHabboInfo().getCurrentRoom(), this.habbo.getRoomUnit(), this.score, amount);
} }
} }
@@ -48,7 +48,7 @@ public class InteractionDice extends HabboItem {
if (client != null) { if (client != null) {
if (RoomLayout.tilesAdjecent(room.getLayout().getTile(this.getX(), this.getY()), client.getHabbo().getRoomUnit().getCurrentLocation())) { if (RoomLayout.tilesAdjecent(room.getLayout().getTile(this.getX(), this.getY()), client.getHabbo().getRoomUnit().getCurrentLocation())) {
if (!this.getExtradata().equalsIgnoreCase("-1")) { if (!this.getExtradata().equalsIgnoreCase("-1")) {
FurnitureDiceRolledEvent event = Emulator.getPluginManager().fireEvent(new FurnitureDiceRolledEvent(this, client.getHabbo(), -1)); FurnitureDiceRolledEvent event = (FurnitureDiceRolledEvent) Emulator.getPluginManager().fireEvent(new FurnitureDiceRolledEvent(this, client.getHabbo(), -1));
if (event.isCancelled()) if (event.isCancelled())
return; return;
@@ -58,9 +58,9 @@ public class InteractionDice extends HabboItem {
Emulator.getThreading().run(this); Emulator.getThreading().run(this);
if (event.result > 0) { if (event.result > 0) {
Emulator.getThreading().run(new RandomDiceNumber(room, this, event.result), 2000); Emulator.getThreading().run(new RandomDiceNumber(room, this, event.result), 1500);
} else { } else {
Emulator.getThreading().run(new RandomDiceNumber(this, room, this.getBaseItem().getStateCount()), 2000); Emulator.getThreading().run(new RandomDiceNumber(this, room, this.getBaseItem().getStateCount()), 1500);
} }
} }
} }
@@ -15,12 +15,12 @@ import java.sql.SQLException;
public class InteractionFXBox extends InteractionDefault { public class InteractionFXBox extends InteractionDefault {
public InteractionFXBox(ResultSet set, Item baseItem) throws SQLException { public InteractionFXBox(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem); super(set, baseItem);
// this.setExtradata("0"); // this.setExtradata("0");
} }
public InteractionFXBox(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { public InteractionFXBox(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells); super(id, userId, item, extradata, limitedStack, limitedSells);
// this.setExtradata("0"); // this.setExtradata("0");
} }
@Override @Override
@@ -1,14 +1,18 @@
package com.eu.habbo.habbohotel.items.interactions; package com.eu.habbo.habbohotel.items.interactions;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.achievements.AchievementManager;
import com.eu.habbo.habbohotel.gameclients.GameClient; import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.ICycleable; import com.eu.habbo.habbohotel.items.ICycleable;
import com.eu.habbo.habbohotel.items.Item; import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.pets.HorsePet; import com.eu.habbo.habbohotel.pets.HorsePet;
import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.PetTasks;
import com.eu.habbo.habbohotel.rooms.*; import com.eu.habbo.habbohotel.rooms.*;
import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.threading.runnables.HabboItemNewState;
import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -56,9 +60,10 @@ public class InteractionObstacle extends HabboItem implements ICycleable {
@Override @Override
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
/*Pet pet = room.getPet(roomUnit); Pet pet = room.getPet(roomUnit);
if (pet instanceof HorsePet && ((HorsePet) pet).getRider() != null) { if (pet instanceof HorsePet && ((HorsePet) pet).getRider() != null) {
Habbo rider = ((HorsePet) pet).getRider();
if (pet.getTask() != null && pet.getTask().equals(PetTasks.RIDE)) { if (pet.getTask() != null && pet.getTask().equals(PetTasks.RIDE)) {
if (pet.getRoomUnit().hasStatus(RoomUnitStatus.JUMP)) { if (pet.getRoomUnit().hasStatus(RoomUnitStatus.JUMP)) {
pet.getRoomUnit().removeStatus(RoomUnitStatus.JUMP); pet.getRoomUnit().removeStatus(RoomUnitStatus.JUMP);
@@ -75,13 +80,13 @@ public class InteractionObstacle extends HabboItem implements ICycleable {
this.setExtradata(state + ""); this.setExtradata(state + "");
pet.getRoomUnit().setStatus(RoomUnitStatus.JUMP, "0"); pet.getRoomUnit().setStatus(RoomUnitStatus.JUMP, "0");
AchievementManager.progressAchievement(habbo, Emulator.getGameEnvironment().getAchievementManager().getAchievement("HorseConsecutiveJumpsCount")); AchievementManager.progressAchievement(rider, Emulator.getGameEnvironment().getAchievementManager().getAchievement("HorseConsecutiveJumpsCount"));
AchievementManager.progressAchievement(habbo, Emulator.getGameEnvironment().getAchievementManager().getAchievement("HorseJumping")); AchievementManager.progressAchievement(rider, Emulator.getGameEnvironment().getAchievementManager().getAchievement("HorseJumping"));
} }
room.updateItemState(this); room.updateItemState(this);
} }
}*/ }
} }
@Override @Override
@@ -6,6 +6,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.PetManager; import com.eu.habbo.habbohotel.pets.PetManager;
import com.eu.habbo.habbohotel.pets.PetTasks; import com.eu.habbo.habbohotel.pets.PetTasks;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.habbohotel.users.Habbo;
@@ -33,7 +34,11 @@ public class InteractionPetBreedingNest extends HabboItem {
@Override @Override
public boolean canWalkOn(RoomUnit roomUnit, Room room, Object[] objects) { public boolean canWalkOn(RoomUnit roomUnit, Room room, Object[] objects) {
return room.getPet(roomUnit) != null && !this.boxFull(); Pet pet = room.getPet(roomUnit);
if (pet == null) return false;
// Don't let ridden pets enter breeding nest
if (pet instanceof RideablePet && ((RideablePet) pet).getRider() != null) return false;
return !this.boxFull();
} }
@Override @Override
@@ -6,6 +6,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionDefault; import com.eu.habbo.habbohotel.items.interactions.InteractionDefault;
import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.PetTasks; import com.eu.habbo.habbohotel.pets.PetTasks;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus; import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
@@ -32,6 +33,10 @@ public class InteractionPetDrink extends InteractionDefault {
Pet pet = room.getPet(roomUnit); Pet pet = room.getPet(roomUnit);
if (pet != null) { if (pet != null) {
// Don't let ridden pets drink
if (pet instanceof RideablePet && ((RideablePet) pet).getRider() != null)
return;
if (pet.getPetData().haveDrinkItem(this)) { if (pet.getPetData().haveDrinkItem(this)) {
if (pet.levelThirst >= 35) { if (pet.levelThirst >= 35) {
pet.setTask(PetTasks.EAT); pet.setTask(PetTasks.EAT);
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionDefault; import com.eu.habbo.habbohotel.items.interactions.InteractionDefault;
import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.PetTasks; import com.eu.habbo.habbohotel.pets.PetTasks;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus; import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
@@ -34,6 +35,10 @@ public class InteractionPetFood extends InteractionDefault {
Pet pet = room.getPet(roomUnit); Pet pet = room.getPet(roomUnit);
if (pet != null) { if (pet != null) {
// Don't let ridden pets eat
if (pet instanceof RideablePet && ((RideablePet) pet).getRider() != null)
return;
if (pet.getPetData().haveFoodItem(this)) { if (pet.getPetData().haveFoodItem(this)) {
if (pet.levelHunger >= 35) { if (pet.levelHunger >= 35) {
pet.setTask(PetTasks.EAT); pet.setTask(PetTasks.EAT);
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionDefault; import com.eu.habbo.habbohotel.items.interactions.InteractionDefault;
import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.PetTasks; import com.eu.habbo.habbohotel.pets.PetTasks;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus; import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
@@ -33,6 +34,10 @@ public class InteractionPetToy extends InteractionDefault {
Pet pet = room.getPet(roomUnit); Pet pet = room.getPet(roomUnit);
if (pet != null) { if (pet != null) {
// Don't let ridden pets play with toys
if (pet instanceof RideablePet && ((RideablePet) pet).getRider() != null)
return;
if (pet.getEnergy() <= 35) { if (pet.getEnergy() <= 35) {
return; return;
} }
@@ -6,10 +6,14 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect; import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger; import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings; import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile; import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.rooms.RoomTileState; import com.eu.habbo.habbohotel.rooms.RoomTileState;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
import com.eu.habbo.habbohotel.rooms.RoomUnitType;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.wired.core.WiredContext; import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType; import com.eu.habbo.habbohotel.wired.WiredEffectType;
@@ -17,6 +21,7 @@ import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException; import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserEffectComposer; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserEffectComposer;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
import com.eu.habbo.threading.runnables.RoomUnitTeleport; import com.eu.habbo.threading.runnables.RoomUnitTeleport;
import com.eu.habbo.threading.runnables.SendRoomUnitEffectComposer; import com.eu.habbo.threading.runnables.SendRoomUnitEffectComposer;
import gnu.trove.procedure.TObjectProcedure; import gnu.trove.procedure.TObjectProcedure;
@@ -54,6 +59,27 @@ public class WiredEffectTeleport extends InteractionWiredEffect {
return; return;
} }
// If this is a rider, sync the riding pet to the rider's current position immediately
// Both will teleport together when the delay fires
if (roomUnit.getRoomUnitType() == RoomUnitType.USER) {
Habbo habbo = room.getHabbo(roomUnit);
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getRiding() != null) {
RideablePet ridingPet = habbo.getHabboInfo().getRiding();
RoomUnit petUnit = ridingPet.getRoomUnit();
if (petUnit != null) {
// Sync pet to rider's current position
RoomTile riderTile = roomUnit.getCurrentLocation();
petUnit.setLocation(riderTile);
petUnit.setZ(roomUnit.getZ() - 1.0);
petUnit.setPreviousLocation(riderTile);
petUnit.setGoalLocation(riderTile);
petUnit.removeStatus(RoomUnitStatus.MOVE);
petUnit.setCanWalk(false);
room.sendComposer(new RoomUserStatusComposer(petUnit).compose());
}
}
}
// makes a temporary effect // makes a temporary effect
roomUnit.getRoom().unIdle(roomUnit.getRoom().getHabbo(roomUnit)); roomUnit.getRoom().unIdle(roomUnit.getRoom().getHabbo(roomUnit));
@@ -126,25 +126,12 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect {
public void execute(WiredContext ctx) { public void execute(WiredContext ctx) {
Room room = ctx.room(); Room room = ctx.room();
RoomUnit roomUnit = ctx.actor().orElse(null); RoomUnit roomUnit = ctx.actor().orElse(null);
Object[] stuff = ctx.legacyStuff();
// Prevent infinite recursion by checking for WiredEffectTriggerStacks in the call chain // Get the current call stack depth from the event
// and limiting the recursion depth int currentDepth = ctx.event().getCallStackDepth();
int stackDepth = 0;
if (stuff != null) {
for (Object obj : stuff) {
if (obj instanceof WiredEffectTriggerStacks) {
stackDepth++;
// If this specific stack is already in the chain, prevent infinite loop
if (obj == this) {
return;
}
}
}
}
// Prevent excessive recursion depth // Prevent excessive recursion depth
if (stackDepth >= MAX_STACK_DEPTH) { if (currentDepth >= MAX_STACK_DEPTH) {
return; return;
} }
@@ -169,17 +156,8 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect {
} }
} }
// Create new stuff array with this trigger stack added for recursion tracking // Execute effects at tiles with incremented call stack depth
Object[] newStuff; WiredManager.executeEffectsAtTiles(usedTiles, roomUnit, room, currentDepth + 1);
if (stuff != null) {
newStuff = new Object[stuff.length + 1];
System.arraycopy(stuff, 0, newStuff, 0, stuff.length);
newStuff[newStuff.length - 1] = this;
} else {
newStuff = new Object[] { this };
}
WiredManager.executeEffectsAtTiles(usedTiles, roomUnit, room, newStuff);
} }
@Deprecated @Deprecated
@@ -120,14 +120,16 @@ public class WiredTriggerBotReachedFurni extends InteractionWiredTrigger {
public boolean matches(HabboItem triggerItem, WiredEvent event) { public boolean matches(HabboItem triggerItem, WiredEvent event) {
RoomUnit roomUnit = event.getActor().orElse(null); RoomUnit roomUnit = event.getActor().orElse(null);
Room room = event.getRoom(); Room room = event.getRoom();
Object[] stuff = event.getLegacyStuff();
if (stuff.length >= 1) { // Get the furniture item the bot walked onto
if (stuff[0] instanceof HabboItem) { HabboItem sourceItem = event.getSourceItem().orElse(null);
return this.items.contains(stuff[0]) && room.getBots(this.botName).stream().anyMatch(bot -> bot.getRoomUnit() == roomUnit); if (sourceItem == null || roomUnit == null) {
} return false;
} }
return false;
// Check if this furniture is in our monitored list AND the actor is the correct bot
return this.items.contains(sourceItem) &&
room.getBots(this.botName).stream().anyMatch(bot -> bot.getRoomUnit() == roomUnit);
} }
@Deprecated @Deprecated
@@ -6,9 +6,7 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings; import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredManager; import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.WiredTriggerType; import com.eu.habbo.habbohotel.wired.WiredTriggerType;
import com.eu.habbo.habbohotel.wired.core.WiredEvent; import com.eu.habbo.habbohotel.wired.core.WiredEvent;
@@ -37,25 +35,14 @@ public class WiredTriggerFurniStateToggled extends InteractionWiredTrigger {
@Override @Override
public boolean matches(HabboItem triggerItem, WiredEvent event) { public boolean matches(HabboItem triggerItem, WiredEvent event) {
RoomUnit roomUnit = event.getActor().orElse(null); // Reject if this was triggered by a wired effect (to prevent loops)
Room room = event.getRoom(); if (event.isTriggeredByEffect()) {
Object[] stuff = event.getLegacyStuff(); return false;
}
if (stuff.length >= 1) { HabboItem sourceItem = event.getSourceItem().orElse(null);
Habbo habbo = room.getHabbo(roomUnit); if (sourceItem != null) {
return this.items.contains(sourceItem);
if (habbo != null) {
for (Object object : stuff) {
if (object instanceof WiredEffectType) {
return false;
}
}
HabboItem sourceItem = event.getSourceItem().orElse(null);
if (sourceItem != null) {
return this.items.contains(sourceItem);
}
}
} }
return false; return false;
} }
@@ -28,15 +28,11 @@ public class WiredTriggerScoreAchieved extends InteractionWiredTrigger {
@Override @Override
public boolean matches(HabboItem triggerItem, WiredEvent event) { public boolean matches(HabboItem triggerItem, WiredEvent event) {
Object[] stuff = event.getLegacyStuff(); int points = event.getScore();
if (stuff.length >= 2) { int amountAdded = event.getScoreAdded();
int points = (Integer) stuff[0];
int amountAdded = (Integer) stuff[1];
return points - amountAdded < this.score && points >= this.score; // Check if this score addition crossed the threshold
} return points - amountAdded < this.score && points >= this.score;
return false;
} }
@Deprecated @Deprecated
@@ -556,6 +556,10 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
this.cycleManager.resetIdleCycles(); this.cycleManager.resetIdleCycles();
if (this.roomCycleTask != null) {
this.roomCycleTask.cancel(false);
}
this.roomCycleTask = Emulator.getThreading().getService() this.roomCycleTask = Emulator.getThreading().getService()
.scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS); .scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS);
} catch (Exception e) { } catch (Exception e) {
@@ -868,16 +872,20 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
} }
if (this.loaded) { if (this.loaded) {
try { // Set loaded to false FIRST to prevent re-entry and ensure cycle stops
this.loaded = false;
try {
if (this.traxManager != null && !this.traxManager.disposed()) { if (this.traxManager != null && !this.traxManager.disposed()) {
this.traxManager.dispose(); this.traxManager.dispose();
} }
this.roomCycleTask.cancel(false); if (this.roomCycleTask != null) {
this.roomCycleTask.cancel(false);
this.roomCycleTask = null;
}
this.scheduledTasks.clear(); this.scheduledTasks.clear();
this.scheduledComposers.clear(); this.scheduledComposers.clear();
this.loaded = false;
this.tileCache.clear(); this.tileCache.clear();
@@ -279,14 +279,23 @@ public class RoomRollerManager {
Habbo rollingHabbo = this.room.getHabbo(unit); Habbo rollingHabbo = this.room.getHabbo(unit);
if (rollingHabbo != null && rollingHabbo.getHabboInfo() != null) { if (rollingHabbo != null && rollingHabbo.getHabboInfo() != null) {
RideablePet riding = rollingHabbo.getHabboInfo().getRiding(); RideablePet riding = rollingHabbo.getHabboInfo().getRiding();
if (riding != null) { if (riding != null && riding.getRoomUnit() != null) {
RoomUnit ridingUnit = riding.getRoomUnit(); RoomUnit ridingUnit = riding.getRoomUnit();
newZ = ridingUnit.getZ() + zOffset; double petOldZ = ridingUnit.getZ();
double petNewZ = tileInFront.getStackHeight();
// Update pet position immediately before composing messages to prevent desync
rolledUnitIds.add(ridingUnit.getId()); rolledUnitIds.add(ridingUnit.getId());
updatedUnit.remove(ridingUnit); updatedUnit.remove(ridingUnit);
messages.add(new RoomUnitOnRollerComposer(ridingUnit, roller,
ridingUnit.getCurrentLocation(), ridingUnit.getZ(), tileInFront, newZ, // Compose and send pet roller message first
this.room)); RoomUnitOnRollerComposer petRollerComposer = new RoomUnitOnRollerComposer(
ridingUnit, roller, ridingUnit.getCurrentLocation(), petOldZ,
tileInFront, petNewZ, this.room);
messages.add(petRollerComposer);
// Update newZ for the rider (1 unit above pet)
newZ = petNewZ + 1.0;
isRiding = true; isRiding = true;
} }
} }
@@ -295,9 +304,12 @@ public class RoomRollerManager {
usersRolledThisTile.add(unit.getId()); usersRolledThisTile.add(unit.getId());
rolledUnitIds.add(unit.getId()); rolledUnitIds.add(unit.getId());
updatedUnit.remove(unit); updatedUnit.remove(unit);
// For riding users, use pet-relative Z values
double riderOldZ = isRiding ? unit.getZ() : unit.getZ();
double riderNewZ = isRiding ? newZ : (unit.getZ() + zOffset);
messages.add(new RoomUnitOnRollerComposer(unit, roller, unit.getCurrentLocation(), messages.add(new RoomUnitOnRollerComposer(unit, roller, unit.getCurrentLocation(),
unit.getZ() + (isRiding ? 1 : 0), tileInFront, newZ + (isRiding ? 1 : 0), riderOldZ, tileInFront, riderNewZ, this.room));
this.room));
if (itemsOnRoller.isEmpty()) { if (itemsOnRoller.isEmpty()) {
HabboItem item = this.room.getTopItemAt(tileInFront.x, tileInFront.y); HabboItem item = this.room.getTopItemAt(tileInFront.x, tileInFront.y);
@@ -23,18 +23,13 @@ import com.eu.habbo.util.pathfinding.Rotation;
import gnu.trove.map.TMap; import gnu.trove.map.TMap;
import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.THashMap;
import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.THashSet;
import java.util.ArrayList; import org.slf4j.Logger;
import java.util.Comparator; import org.slf4j.LoggerFactory;
import java.util.Deque;
import java.util.LinkedList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RoomUnit { public class RoomUnit {
@@ -155,9 +150,11 @@ public class RoomUnit {
if (!this.isWalking() && !this.isKicked) { if (!this.isWalking() && !this.isKicked) {
if (this.status.remove(RoomUnitStatus.MOVE) == null) { if (this.status.remove(RoomUnitStatus.MOVE) == null) {
Habbo habboT = room.getHabbo(this); Habbo habboT = room.getHabbo(this);
if (habboT != null) { if (habboT != null && habboT.getHabboInfo() != null && habboT.getHabboInfo().getRiding() != null) {
habboT.getHabboInfo().getRiding().getRoomUnit().status.remove(RoomUnitStatus.MOVE); RoomUnit ridingRoomUnit = habboT.getHabboInfo().getRiding().getRoomUnit();
if (ridingRoomUnit != null) {
ridingRoomUnit.status.remove(RoomUnitStatus.MOVE);
}
} }
return true; return true;
} }
@@ -480,6 +480,10 @@ public class HabboInfo implements Runnable {
roomUnit.setZ(riding.getRoomUnit().getZ()); roomUnit.setZ(riding.getRoomUnit().getZ());
roomUnit.setPreviousLocationZ(riding.getRoomUnit().getZ()); roomUnit.setPreviousLocationZ(riding.getRoomUnit().getZ());
roomUnit.stopWalking(); roomUnit.stopWalking();
if (riding.getRoomUnit() != null) {
riding.getRoomUnit().setCanWalk(true);
room.sendComposer(new RoomUserStatusComposer(riding.getRoomUnit()).compose());
}
room.sendComposer(new RoomUserStatusComposer(roomUnit).compose()); room.sendComposer(new RoomUserStatusComposer(roomUnit).compose());
List<RoomTile> availableTiles = isRemoving ? new ArrayList<>() : this.getCurrentRoom().getLayout().getWalkableTilesAround(roomUnit.getCurrentLocation()); List<RoomTile> availableTiles = isRemoving ? new ArrayList<>() : this.getCurrentRoom().getLayout().getWalkableTilesAround(roomUnit.getCurrentLocation());
@@ -256,14 +256,6 @@ public final class WiredContext {
return legacySettings != null ? legacySettings : new Object[0]; return legacySettings != null ? legacySettings : new Object[0];
} }
/**
* Get the legacy stuff array from the event.
* @return the legacy stuff array
*/
public Object[] legacyStuff() {
return event.getLegacyStuff();
}
// ========== Utility Methods ========== // ========== Utility Methods ==========
/** /**
@@ -128,11 +128,15 @@ public final class WiredEvent {
private final Type type; private final Type type;
private final Room room; private final Room room;
private final RoomUnit actor; // nullable private final RoomUnit actor; // nullable - the user/bot that caused the event
private final HabboItem sourceItem; // nullable private final HabboItem sourceItem; // nullable - the furniture involved
private final RoomTile tile; // nullable private final RoomTile tile; // nullable - the tile where event occurred
private final String text; // nullable private final String text; // nullable - text for say triggers
private final Object[] legacyStuff; // for adapter compatibility private final RoomUnit targetUnit; // nullable - target user (e.g., for bot reached habbo)
private final int score; // score value for score achieved events
private final int scoreAdded; // amount added for score achieved events
private final boolean triggeredByEffect; // true if triggered by a wired effect (to prevent loops)
private final int callStackDepth; // recursion depth for trigger stacks effect
private final long createdAtMs; private final long createdAtMs;
private WiredEvent(Builder builder) { private WiredEvent(Builder builder) {
@@ -142,7 +146,11 @@ public final class WiredEvent {
this.sourceItem = builder.sourceItem; this.sourceItem = builder.sourceItem;
this.tile = builder.tile; this.tile = builder.tile;
this.text = builder.text; this.text = builder.text;
this.legacyStuff = builder.legacyStuff; this.targetUnit = builder.targetUnit;
this.score = builder.score;
this.scoreAdded = builder.scoreAdded;
this.triggeredByEffect = builder.triggeredByEffect;
this.callStackDepth = builder.callStackDepth;
this.createdAtMs = builder.createdAtMs; this.createdAtMs = builder.createdAtMs;
} }
@@ -199,12 +207,46 @@ public final class WiredEvent {
} }
/** /**
* Get the legacy stuff array for adapter compatibility. * Get the target unit for this event.
* This allows legacy triggers/conditions/effects to work with the new system. * Used for events like BOT_REACHED_HABBO where we need to track the target user.
* @return the legacy stuff array, or empty array if not set * @return optional containing the target unit
*/ */
public Object[] getLegacyStuff() { public Optional<RoomUnit> getTargetUnit() {
return legacyStuff != null ? legacyStuff : new Object[0]; return Optional.ofNullable(targetUnit);
}
/**
* Get the score value for score achieved events.
* @return the current score
*/
public int getScore() {
return score;
}
/**
* Get the amount of score added for score achieved events.
* @return the amount added
*/
public int getScoreAdded() {
return scoreAdded;
}
/**
* Check if this event was triggered by a wired effect.
* Used to prevent infinite loops (e.g., effect toggles furni -> triggers state changed -> triggers effect).
* @return true if triggered by a wired effect
*/
public boolean isTriggeredByEffect() {
return triggeredByEffect;
}
/**
* Get the call stack depth for recursion tracking.
* Used by WiredEffectTriggerStacks to prevent infinite recursion.
* @return the current recursion depth
*/
public int getCallStackDepth() {
return callStackDepth;
} }
/** /**
@@ -256,7 +298,11 @@ public final class WiredEvent {
private HabboItem sourceItem; private HabboItem sourceItem;
private RoomTile tile; private RoomTile tile;
private String text; private String text;
private Object[] legacyStuff; private RoomUnit targetUnit;
private int score;
private int scoreAdded;
private boolean triggeredByEffect;
private int callStackDepth;
private long createdAtMs = System.currentTimeMillis(); private long createdAtMs = System.currentTimeMillis();
private Builder(Type type, Room room) { private Builder(Type type, Room room) {
@@ -307,12 +353,52 @@ public final class WiredEvent {
} }
/** /**
* Set the legacy stuff array for adapter compatibility. * Set the target unit for this event.
* @param stuff the legacy object array * @param targetUnit the target room unit
* @return this builder * @return this builder
*/ */
public Builder legacyStuff(Object[] stuff) { public Builder targetUnit(RoomUnit targetUnit) {
this.legacyStuff = stuff; this.targetUnit = targetUnit;
return this;
}
/**
* Set the score value for score achieved events.
* @param score the current score
* @return this builder
*/
public Builder score(int score) {
this.score = score;
return this;
}
/**
* Set the amount of score added for score achieved events.
* @param scoreAdded the amount added
* @return this builder
*/
public Builder scoreAdded(int scoreAdded) {
this.scoreAdded = scoreAdded;
return this;
}
/**
* Mark this event as triggered by a wired effect.
* @param triggeredByEffect true if triggered by effect
* @return this builder
*/
public Builder triggeredByEffect(boolean triggeredByEffect) {
this.triggeredByEffect = triggeredByEffect;
return this;
}
/**
* Set the call stack depth for recursion tracking.
* @param callStackDepth the recursion depth
* @return this builder
*/
public Builder callStackDepth(int callStackDepth) {
this.callStackDepth = callStackDepth;
return this; return this;
} }
@@ -357,13 +357,17 @@ public final class WiredManager {
/** /**
* Trigger when score is achieved. * Trigger when score is achieved.
* @param room the room
* @param user the user who scored
* @param score the current total score
* @param scoreAdded the amount of score just added
*/ */
public static boolean triggerScoreAchieved(Room room, RoomUnit user, int score) { public static boolean triggerScoreAchieved(Room room, RoomUnit user, int score, int scoreAdded) {
if (!isEnabled() || room == null || user == null) { if (!isEnabled() || room == null || user == null) {
return false; return false;
} }
WiredEvent event = WiredEvents.scoreAchieved(room, user, score); WiredEvent event = WiredEvents.scoreAchieved(room, user, score, scoreAdded);
return handleEvent(event); return handleEvent(event);
} }
@@ -631,7 +635,15 @@ public final class WiredManager {
// ========== Effect Execution ========== // ========== Effect Execution ==========
public static boolean executeEffectsAtTiles(THashSet<RoomTile> tiles, final RoomUnit roomUnit, final Room room, final Object[] stuff) { /**
* Execute all wired effects at the specified tiles.
* @param tiles the tiles to execute effects at
* @param roomUnit the triggering room unit (may be null)
* @param room the room
* @param callStackDepth current recursion depth for trigger stacks
* @return true if any effects were executed
*/
public static boolean executeEffectsAtTiles(THashSet<RoomTile> tiles, final RoomUnit roomUnit, final Room room, final int callStackDepth) {
for (RoomTile tile : tiles) { for (RoomTile tile : tiles) {
if (room != null) { if (room != null) {
THashSet<HabboItem> items = room.getItemsAt(tile); THashSet<HabboItem> items = room.getItemsAt(tile);
@@ -642,7 +654,7 @@ public final class WiredManager {
InteractionWiredEffect effect = (InteractionWiredEffect) item; InteractionWiredEffect effect = (InteractionWiredEffect) item;
WiredEvent event = WiredEvent.builder(WiredEvent.Type.CUSTOM, room) WiredEvent event = WiredEvent.builder(WiredEvent.Type.CUSTOM, room)
.actor(roomUnit) .actor(roomUnit)
.legacyStuff(stuff) .callStackDepth(callStackDepth)
.build(); .build();
WiredContext ctx = new WiredContext(event, effect, DefaultWiredServices.getInstance(), new WiredState(100)); WiredContext ctx = new WiredContext(event, effect, DefaultWiredServices.getInstance(), new WiredState(100));
effect.execute(ctx); effect.execute(ctx);
@@ -199,19 +199,19 @@ public final class WiredEvents {
.build(); .build();
} }
/**
* Create an event for when a score is achieved.
/** /**
* Create an event for when a score threshold is achieved. * Create an event for when a score threshold is achieved.
* @param room the room * @param room the room
* @param user the user who achieved the score * @param user the user who achieved the score
* @param score the score achieved * @param score the current total score
* @param scoreAdded the amount of score just added
* @return the event * @return the event
*/ */
public static WiredEvent scoreAchieved(Room room, RoomUnit user, int score) { public static WiredEvent scoreAchieved(Room room, RoomUnit user, int score, int scoreAdded) {
return WiredEvent.builder(WiredEvent.Type.SCORE_ACHIEVED, room) return WiredEvent.builder(WiredEvent.Type.SCORE_ACHIEVED, room)
.actor(user) .actor(user)
.legacyStuff(new Object[]{score}) .score(score)
.scoreAdded(scoreAdded)
.build(); .build();
} }
@@ -257,7 +257,7 @@ public final class WiredEvents {
return WiredEvent.builder(WiredEvent.Type.BOT_REACHED_HABBO, room) return WiredEvent.builder(WiredEvent.Type.BOT_REACHED_HABBO, room)
.actor(botUnit) .actor(botUnit)
.tile(targetUser.getCurrentLocation()) .tile(targetUser.getCurrentLocation())
.legacyStuff(new Object[]{targetUser}) .targetUnit(targetUser)
.build(); .build();
} }
@@ -324,15 +324,14 @@ public final class WiredEvents {
* @param triggerType the legacy trigger type * @param triggerType the legacy trigger type
* @param room the room * @param room the room
* @param roomUnit the triggering unit (may be null) * @param roomUnit the triggering unit (may be null)
* @param stuff legacy stuff array * @param stuff legacy stuff array (now only used to extract typed data)
* @return the event * @return the event
*/ */
public static WiredEvent fromLegacy(WiredTriggerType triggerType, Room room, RoomUnit roomUnit, Object[] stuff) { public static WiredEvent fromLegacy(WiredTriggerType triggerType, Room room, RoomUnit roomUnit, Object[] stuff) {
WiredEvent.Type eventType = WiredEvent.Type.fromLegacyType(triggerType); WiredEvent.Type eventType = WiredEvent.Type.fromLegacyType(triggerType);
WiredEvent.Builder builder = WiredEvent.builder(eventType, room) WiredEvent.Builder builder = WiredEvent.builder(eventType, room)
.actor(roomUnit) .actor(roomUnit);
.legacyStuff(stuff);
// Try to extract common data from stuff array // Try to extract common data from stuff array
if (stuff != null) { if (stuff != null) {
@@ -252,7 +252,6 @@ public final class WiredTickService {
if (tickables.add(tickable)) { if (tickables.add(tickable)) {
tickable.onRegistered(room, System.currentTimeMillis()); tickable.onRegistered(room, System.currentTimeMillis());
LOGGER.debug("Registered tickable {} in room {}", tickable.getId(), roomId);
} }
} }
@@ -273,7 +272,6 @@ public final class WiredTickService {
if (tickables != null) { if (tickables != null) {
if (tickables.remove(tickable)) { if (tickables.remove(tickable)) {
tickable.onUnregistered(room); tickable.onUnregistered(room);
LOGGER.debug("Unregistered tickable {} from room {}", tickable.getId(), roomId);
} }
// Clean up empty sets // Clean up empty sets
@@ -43,7 +43,7 @@ public class PetInformationComposer extends MessageComposer {
} }
this.response.appendInt(this.pet.getEnergy()); this.response.appendInt(this.pet.getEnergy());
this.response.appendInt(this.pet.getMaxEnergy()); //Max energy this.response.appendInt(this.pet.getMaxEnergy()); //Max energy
this.response.appendInt(this.pet.getHappiness()); //this.pet.getHappiness() this.response.appendInt(this.pet.getHappiness());
this.response.appendInt(100); this.response.appendInt(100);
this.response.appendInt(this.pet.getRespect()); this.response.appendInt(this.pet.getRespect());
this.response.appendInt(this.pet.getUserId()); this.response.appendInt(this.pet.getUserId());
@@ -51,7 +51,19 @@ public class PetInformationComposer extends MessageComposer {
this.response.appendString(this.room.getFurniOwnerName(this.pet.getUserId())); //Owner name this.response.appendString(this.room.getFurniOwnerName(this.pet.getUserId())); //Owner name
this.response.appendInt(this.pet instanceof MonsterplantPet ? ((MonsterplantPet) this.pet).getRarity() : 0); this.response.appendInt(this.pet instanceof MonsterplantPet ? ((MonsterplantPet) this.pet).getRarity() : 0);
this.response.appendBoolean(this.pet instanceof RideablePet && this.requestingHabbo != null && (((RideablePet) this.pet).getRider() == null || this.pet.getUserId() == this.requestingHabbo.getHabboInfo().getId()) && ((RideablePet) this.pet).hasSaddle()); // can ride
// Can ride: pet has saddle, no one riding or user owns pet, and (user owns pet or anyone can ride)
boolean canRide = false;
if (this.pet instanceof RideablePet && this.requestingHabbo != null) {
RideablePet rideablePet = (RideablePet) this.pet;
boolean hasSaddle = rideablePet.hasSaddle();
boolean noRider = rideablePet.getRider() == null;
boolean isOwner = this.pet.getUserId() == this.requestingHabbo.getHabboInfo().getId();
boolean canRidePermission = isOwner || rideablePet.anyoneCanRide();
canRide = hasSaddle && (noRider || isOwner) && canRidePermission;
}
this.response.appendBoolean(canRide);
this.response.appendBoolean(this.pet instanceof RideablePet && ((RideablePet) this.pet).getRider() != null && this.requestingHabbo != null && ((RideablePet) this.pet).getRider().getHabboInfo().getId() == this.requestingHabbo.getHabboInfo().getId()); // is current user riding this.response.appendBoolean(this.pet instanceof RideablePet && ((RideablePet) this.pet).getRider() != null && this.requestingHabbo != null && ((RideablePet) this.pet).getRider().getHabboInfo().getId() == this.requestingHabbo.getHabboInfo().getId()); // is current user riding
this.response.appendInt(0); this.response.appendInt(0);
this.response.appendInt(this.pet instanceof RideablePet && ((RideablePet) this.pet).anyoneCanRide() ? 1 : 0); // anyone can ride this.response.appendInt(this.pet instanceof RideablePet && ((RideablePet) this.pet).anyoneCanRide() ? 1 : 0); // anyone can ride
@@ -45,7 +45,7 @@ public class RoomPetHorseFigureComposer extends MessageComposer {
this.response.appendInt(this.pet.getHairColor()); this.response.appendInt(this.pet.getHairColor());
} }
this.response.appendBoolean(this.pet.hasSaddle()); this.response.appendBoolean(this.pet.hasSaddle());
this.response.appendBoolean(false); // this.pet.anyoneCanRide() this.response.appendBoolean(this.pet.anyoneCanRide());
return this.response; return this.response;
} }
@@ -4,10 +4,12 @@ import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.bots.Bot; import com.eu.habbo.habbohotel.bots.Bot;
import com.eu.habbo.habbohotel.items.interactions.InteractionRoller; import com.eu.habbo.habbohotel.items.interactions.InteractionRoller;
import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile; import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitType; import com.eu.habbo.habbohotel.rooms.RoomUnitType;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.MessageComposer; import com.eu.habbo.messages.outgoing.MessageComposer;
@@ -58,7 +60,21 @@ public class RoomUnitOnRollerComposer extends MessageComposer {
// Early validation: Check if the roller movement is still valid before composing the packet // Early validation: Check if the roller movement is still valid before composing the packet
if (this.roller != null && room.getLayout() != null) { if (this.roller != null && room.getLayout() != null) {
// Check if the destination tile is blocked by another unit that moved there // Check if the destination tile is blocked by another unit that moved there
if (this.newLocation.hasUnits() && !this.newLocation.getUnits().contains(this.roomUnit)) { // Skip this check for pets with riders or users riding pets (they share the tile)
boolean isRidingPetOrRider = false;
if (this.roomUnit.getRoomUnitType() == RoomUnitType.PET) {
Pet pet = this.room.getPet(this.roomUnit);
if (pet instanceof RideablePet && ((RideablePet) pet).getRider() != null) {
isRidingPetOrRider = true;
}
} else if (this.roomUnit.getRoomUnitType() == RoomUnitType.USER) {
Habbo habbo = this.room.getHabbo(this.roomUnit);
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getRiding() != null) {
isRidingPetOrRider = true;
}
}
if (!isRidingPetOrRider && this.newLocation.hasUnits() && !this.newLocation.getUnits().contains(this.roomUnit)) {
return null; return null;
} }
@@ -106,6 +122,15 @@ public class RoomUnitOnRollerComposer extends MessageComposer {
Pet pet = this.room.getPet(this.roomUnit); Pet pet = this.room.getPet(this.roomUnit);
if (pet != null) { if (pet != null) {
pet.needsUpdate = true; pet.needsUpdate = true;
// If this pet has a rider, sync the rider's position with the pet
if (pet instanceof RideablePet) {
RideablePet rideablePet = (RideablePet) pet;
Habbo rider = rideablePet.getRider();
if (rider != null && rider.getRoomUnit() != null) {
rider.getRoomUnit().setLastRollerTime(System.currentTimeMillis());
}
}
} }
} }
} }
@@ -21,7 +21,10 @@ public class RoomUnitRidePet implements Runnable {
@Override @Override
public void run() { public void run() {
if (this.habbo.getRoomUnit() == null || this.pet.getRoomUnit() == null || this.pet.getRoom() != this.habbo.getHabboInfo().getCurrentRoom() || this.goalTile == null || this.habbo.getRoomUnit().getGoal() != this.goalTile) if (this.habbo == null || this.habbo.getRoomUnit() == null || this.pet == null ||
this.pet.getRoomUnit() == null || this.habbo.getHabboInfo() == null ||
this.pet.getRoom() != this.habbo.getHabboInfo().getCurrentRoom() ||
this.goalTile == null || this.habbo.getRoomUnit().getGoal() != this.goalTile)
return; return;
if (habbo.getRoomUnit().getCurrentLocation().distance(pet.getRoomUnit().getCurrentLocation()) <= 1) { if (habbo.getRoomUnit().getCurrentLocation().distance(pet.getRoomUnit().getCurrentLocation()) <= 1) {
@@ -34,10 +37,16 @@ public class RoomUnitRidePet implements Runnable {
habbo.getRoomUnit().setPreviousLocationZ(this.pet.getRoomUnit().getZ() + 1); habbo.getRoomUnit().setPreviousLocationZ(this.pet.getRoomUnit().getZ() + 1);
habbo.getRoomUnit().setRotation(this.pet.getRoomUnit().getBodyRotation()); habbo.getRoomUnit().setRotation(this.pet.getRoomUnit().getBodyRotation());
habbo.getRoomUnit().statusUpdate(true); habbo.getRoomUnit().statusUpdate(true);
// Set up the pet for riding
pet.setRider(habbo); pet.setRider(habbo);
pet.setTask(PetTasks.RIDE);
pet.getRoomUnit().stopWalking();
pet.getRoomUnit().setGoalLocation(habbo.getRoomUnit().getCurrentLocation());
habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserStatusComposer(habbo.getRoomUnit()).compose()); habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserStatusComposer(habbo.getRoomUnit()).compose());
habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserEffectComposer(habbo.getRoomUnit()).compose()); habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserEffectComposer(habbo.getRoomUnit()).compose());
pet.setTask(PetTasks.RIDE); habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserStatusComposer(pet.getRoomUnit()).compose());
} else { } else {
pet.getRoomUnit().setWalkTimeOut(3 + Emulator.getIntUnixTimestamp()); pet.getRoomUnit().setWalkTimeOut(3 + Emulator.getIntUnixTimestamp());
pet.getRoomUnit().stopWalking(); pet.getRoomUnit().stopWalking();