From 56161d36b56ce23a01bdec8ecfecf6801c837946 Mon Sep 17 00:00:00 2001 From: duckietm Date: Mon, 16 Mar 2026 11:25:59 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=99=20Added=20Rebug=20football?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -- Rebug Football Physics -- To use rebug football physics on a ball, set its interaction_type to 'rebug_football'. -- The default 'football' interaction uses the standard physics. -- -- Example: Change all footballs to use rebug physics: -- UPDATE items_base SET interaction_type = 'rebug_football' WHERE interaction_type = 'football'; -- -- Example: Change a specific ball item to use rebug physics: -- UPDATE items_base SET interaction_type = 'rebug_football' WHERE id = ; -- -- To revert back to default physics: -- UPDATE items_base SET interaction_type = 'football' WHERE interaction_type = 'rebug_football'; --- .../habbo/habbohotel/items/ItemManager.java | 2 + .../football/InteractionRebugFootball.java | 54 +++++++++ .../runnables/RebugKickBallAction.java | 106 ++++++++++++++++++ .../eu/habbo/util/pathfinding/Direction8.java | 95 ++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionRebugFootball.java create mode 100644 Emulator/src/main/java/com/eu/habbo/threading/runnables/RebugKickBallAction.java create mode 100644 Emulator/src/main/java/com/eu/habbo/util/pathfinding/Direction8.java diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java index b33f1c10..50928f05 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java @@ -17,6 +17,7 @@ import com.eu.habbo.habbohotel.items.interactions.games.battlebanzai.scoreboards import com.eu.habbo.habbohotel.items.interactions.games.battlebanzai.scoreboards.InteractionBattleBanzaiScoreboardYellow; import com.eu.habbo.habbohotel.items.interactions.games.football.InteractionFootball; import com.eu.habbo.habbohotel.items.interactions.games.football.InteractionFootballGate; +import com.eu.habbo.habbohotel.items.interactions.games.football.InteractionRebugFootball; import com.eu.habbo.habbohotel.items.interactions.games.football.goals.InteractionFootballGoalBlue; import com.eu.habbo.habbohotel.items.interactions.games.football.goals.InteractionFootballGoalGreen; import com.eu.habbo.habbohotel.items.interactions.games.football.goals.InteractionFootballGoalRed; @@ -344,6 +345,7 @@ public class ItemManager { this.interactionsList.add(new ItemInteraction("football", InteractionFootball.class)); + this.interactionsList.add(new ItemInteraction("rebug_football", InteractionRebugFootball.class)); this.interactionsList.add(new ItemInteraction("football_gate", InteractionFootballGate.class)); this.interactionsList.add(new ItemInteraction("football_counter_blue", InteractionFootballScoreboardBlue.class)); this.interactionsList.add(new ItemInteraction("football_counter_green", InteractionFootballScoreboardGreen.class)); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionRebugFootball.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionRebugFootball.java new file mode 100644 index 00000000..98666d50 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionRebugFootball.java @@ -0,0 +1,54 @@ +package com.eu.habbo.habbohotel.items.interactions.games.football; + +import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.items.Item; +import com.eu.habbo.habbohotel.items.interactions.InteractionDefault; +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomUnit; +import com.eu.habbo.threading.runnables.RebugKickBallAction; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Rebug-style football interaction. + * Uses simplified momentum-decay physics with 180-degree bounce. + * Set interaction_type to "rebug_football" on a ball item to use this instead of the default football physics. + */ +public class InteractionRebugFootball extends InteractionDefault { + + private RebugKickBallAction currentThread; + + public InteractionRebugFootball(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + this.setExtradata("0"); + } + + public InteractionRebugFootball(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + this.setExtradata("0"); + } + + @Override + public boolean canWalkOn(RoomUnit roomUnit, Room room, Object[] objects) { + return true; + } + + @Override + public boolean isWalkable() { + return true; + } + + @Override + public void onWalkOn(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { + super.onWalkOn(roomUnit, room, objects); + + if (this.currentThread != null) { + this.currentThread.dead = true; + } + + boolean hasPath = !roomUnit.getPath().isEmpty(); + this.currentThread = new RebugKickBallAction(this, room, roomUnit, hasPath); + Emulator.getThreading().run(this.currentThread, 50); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/threading/runnables/RebugKickBallAction.java b/Emulator/src/main/java/com/eu/habbo/threading/runnables/RebugKickBallAction.java new file mode 100644 index 00000000..55694364 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/threading/runnables/RebugKickBallAction.java @@ -0,0 +1,106 @@ +package com.eu.habbo.threading.runnables; + +import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomTile; +import com.eu.habbo.habbohotel.rooms.RoomTileState; +import com.eu.habbo.habbohotel.rooms.RoomUnit; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer; +import com.eu.habbo.util.pathfinding.Direction8; +import gnu.trove.set.hash.THashSet; + +/** + * Alternative football physics based on the Rebug plugin. + * Uses momentum decay (ball slows down over time) and simple 180-degree bounce. + */ +public class RebugKickBallAction implements Runnable { + + private final HabboItem ball; + private final Room room; + private Direction8 direction; + private int momentum; + public boolean dead = false; + + public RebugKickBallAction(HabboItem ball, Room room, RoomUnit kicker, boolean hasPath) { + this.ball = ball; + this.room = room; + this.direction = Direction8.fromDelta( + ball.getX() - kicker.getX(), + ball.getY() - kicker.getY() + ); + this.momentum = hasPath ? 55 : 0; + } + + private boolean isTileBlocked(int x, int y) { + RoomTile tile = this.room.getLayout().getTile((short) x, (short) y); + if (tile == null) return true; + if (tile.hasUnits()) return true; + return tile.getState() != RoomTileState.OPEN; + } + + @Override + public void run() { + if (this.dead || !this.room.isLoaded()) return; + + try { + int nextX = this.ball.getX() + this.direction.getDiffX(); + int nextY = this.ball.getY() + this.direction.getDiffY(); + + if (isTileBlocked(nextX, nextY)) { + this.direction = this.direction.rotateDirection180Degrees(); + nextX = this.ball.getX() + this.direction.getDiffX(); + nextY = this.ball.getY() + this.direction.getDiffY(); + } + + RoomTile nextTile = this.room.getLayout().getTile((short) nextX, (short) nextY); + if (nextTile == null) return; + + RoomTile oldTile = this.room.getLayout().getTile(this.ball.getX(), this.ball.getY()); + double oldZ = this.ball.getZ(); + + this.ball.setRotation(this.direction.getRot()); + this.ball.setX(nextTile.x); + this.ball.setY(nextTile.y); + this.ball.setZ(nextTile.getStackHeight()); + this.ball.needsUpdate(true); + + // Schedule next movement based on momentum + long delay = getDelayForMomentum(this.momentum); + if (delay > 0) { + Emulator.getThreading().run(this, delay); + } + + // Update tiles + this.room.updateTile(oldTile); + this.room.updateTile(nextTile); + + THashSet oldItems = this.room.getItemsAt(oldTile); + if (oldItems != null && !oldItems.isEmpty()) { + oldItems.remove(this.ball); + } + this.room.getItemsAt(nextTile).add(this.ball); + + // Send rolling animation + this.room.sendComposer(new FloorItemOnRollerComposer( + this.ball, null, oldTile, oldZ, nextTile, this.ball.getZ(), 0.0D, this.room + ).compose()); + + // Decay momentum + this.momentum -= 11; + } catch (Exception e) { + this.dead = true; + } + } + + private long getDelayForMomentum(int momentum) { + switch (momentum) { + case 55: return 100L; + case 44: return 100L; + case 33: return 200L; + case 22: return 250L; + case 11: return 500L; + default: return 0L; + } + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/util/pathfinding/Direction8.java b/Emulator/src/main/java/com/eu/habbo/util/pathfinding/Direction8.java new file mode 100644 index 00000000..200e8ce5 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/util/pathfinding/Direction8.java @@ -0,0 +1,95 @@ +package com.eu.habbo.util.pathfinding; + +/** + * 8-directional movement utility for ball physics. + * Ported from the Rebug soccer plugin. + */ +public class Direction8 { + public static final Direction8[] DIRECTIONS = new Direction8[8]; + + public static final Direction8 N = new Direction8(0, "N", 0, -1); + public static final Direction8 NE = new Direction8(1, "NE", 1, -1); + public static final Direction8 E = new Direction8(2, "E", 1, 0); + public static final Direction8 SE = new Direction8(3, "SE", 1, 1); + public static final Direction8 S = new Direction8(4, "S", 0, 1); + public static final Direction8 SW = new Direction8(5, "SW", -1, 1); + public static final Direction8 W = new Direction8(6, "W", -1, 0); + public static final Direction8 NW = new Direction8(7, "NW", -1, -1); + + private final int rot; + private final String rotName; + private final int xDiff; + private final int yDiff; + + public Direction8(int rot, String rotName, int diffX, int diffY) { + this.rot = rot; + this.rotName = rotName; + this.xDiff = diffX; + this.yDiff = diffY; + DIRECTIONS[rot] = this; + } + + public static Direction8 fromDelta(int deltaX, int deltaY) { + if (deltaX == 0) { + if (deltaY < 0) return N; + if (deltaY > 0) return S; + } + if (deltaX > 0) { + if (deltaY < 0) return NE; + if (deltaY == 0) return E; + if (deltaY > 0) return SE; + } + if (deltaX < 0) { + if (deltaY < 0) return NW; + if (deltaY == 0) return W; + if (deltaY > 0) return SW; + } + return N; + } + + public static Direction8 getDirection(int dir) { + if (dir < 0 || dir > 7) return N; + return DIRECTIONS[dir]; + } + + public static int validateDirection8Value(int dir) { + return dir & 0x7; + } + + public int getRot() { + return this.rot; + } + + public String getRotName() { + return this.rotName; + } + + public int getDiffX() { + return this.xDiff; + } + + public int getDiffY() { + return this.yDiff; + } + + public Direction8 rotateDirection180Degrees() { + return getDirectionAtRot(4); + } + + public Direction8 rotateDirection90Degrees(boolean clockwise) { + return getDirectionAtRot(clockwise ? 2 : -2); + } + + public Direction8 rotateDirection45Degrees(boolean clockwise) { + return getDirectionAtRot(clockwise ? 1 : -1); + } + + public Direction8 getDirectionAtRot(int diff) { + return DIRECTIONS[validateDirection8Value(this.rot + diff)]; + } + + @Override + public String toString() { + return this.rotName + "(" + this.rot + ")"; + } +}