🌑 Rebug football now 100%

This commit is contained in:
duckietm
2026-03-17 10:06:43 +01:00
parent 68180bcb04
commit 48b7839021
2 changed files with 107 additions and 32 deletions
@@ -8,6 +8,7 @@ import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomLayout; import com.eu.habbo.habbohotel.rooms.RoomLayout;
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.messages.outgoing.rooms.items.ItemStateComposer;
import com.eu.habbo.threading.runnables.RebugKickBallAction; import com.eu.habbo.threading.runnables.RebugKickBallAction;
import com.eu.habbo.util.pathfinding.Direction8; import com.eu.habbo.util.pathfinding.Direction8;
@@ -46,12 +47,10 @@ public class InteractionRebugFootball extends InteractionDefault {
Direction8 userDir = Direction8.getDirection(roomUnit.getBodyRotation().getValue()); Direction8 userDir = Direction8.getDirection(roomUnit.getBodyRotation().getValue());
this.lastDribbleDirection = userDir; this.lastDribbleDirection = userDir;
// If this tile is the user's final destination, they'll stop here → long shot
RoomTile goal = roomUnit.getGoal(); RoomTile goal = roomUnit.getGoal();
if (goal != null && goal.x == this.getX() && goal.y == this.getY()) { if (goal != null && goal.x == this.getX() && goal.y == this.getY()) {
this.kick(room, roomUnit, 55); this.kick(room, roomUnit, 55);
} else { } else {
// Dribble: ball moves 1 tile ahead of the user
this.kick(room, roomUnit, 0); this.kick(room, roomUnit, 0);
} }
} }
@@ -68,18 +67,18 @@ public class InteractionRebugFootball extends InteractionDefault {
int dy = nextTile.y - fromTile.y; int dy = nextTile.y - fromTile.y;
Direction8 walkDir = Direction8.fromDelta(dx, dy); Direction8 walkDir = Direction8.fromDelta(dx, dy);
// User is walking in the same direction as the ball was dribbled → long shot
if (this.lastDribbleDirection != null && walkDir.getRot() == this.lastDribbleDirection.getRot()) { if (this.lastDribbleDirection != null && walkDir.getRot() == this.lastDribbleDirection.getRot()) {
this.kick(room, roomUnit, 55); this.kick(room, roomUnit, 55);
return; return;
} }
} }
// Walking sideways or away → just stop the ball
if (this.currentThread != null) { if (this.currentThread != null) {
this.currentThread.dead = true; this.currentThread.dead = true;
this.currentThread = null; this.currentThread = null;
} }
this.setExtradata("0");
room.sendComposer(new ItemStateComposer(this).compose());
} }
@Override @Override
@@ -89,18 +88,21 @@ public class InteractionRebugFootball extends InteractionDefault {
if (client == null) return; if (client == null) return;
RoomUnit unit = client.getHabbo().getRoomUnit(); RoomUnit unit = client.getHabbo().getRoomUnit();
if (RoomLayout.tilesAdjecent(unit.getCurrentLocation(), room.getLayout().getTile(this.getX(), this.getY()))) { if (RoomLayout.tilesAdjecent(unit.getCurrentLocation(), room.getLayout().getTile(this.getX(), this.getY()))) {
// Long shot when clicking the ball
this.kick(room, unit, 55); this.kick(room, unit, 55);
} }
} }
private void kick(Room room, RoomUnit kicker, int momentum) { private void kick(Room room, RoomUnit kicker, int momentum) {
boolean wasMoving = this.currentThread != null && !this.currentThread.dead && !this.currentThread.isDribble();
if (this.currentThread != null) { if (this.currentThread != null) {
this.currentThread.dead = true; this.currentThread.dead = true;
} }
Direction8 direction = Direction8.getDirection(kicker.getBodyRotation().getValue()); Direction8 direction = Direction8.getDirection(kicker.getBodyRotation().getValue());
this.currentThread = new RebugKickBallAction(this, room, direction, momentum); boolean zigzag = wasMoving && momentum > 0;
this.currentThread = new RebugKickBallAction(this, room, direction, momentum, zigzag);
Emulator.getThreading().run(this.currentThread, 50); Emulator.getThreading().run(this.currentThread, 50);
} }
} }
@@ -7,13 +7,10 @@ import com.eu.habbo.habbohotel.rooms.RoomTileState;
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.outgoing.rooms.items.FloorItemOnRollerComposer; import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import com.eu.habbo.messages.outgoing.rooms.items.ItemStateComposer;
import com.eu.habbo.util.pathfinding.Direction8; import com.eu.habbo.util.pathfinding.Direction8;
import gnu.trove.set.hash.THashSet; 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 { public class RebugKickBallAction implements Runnable {
private final HabboItem ball; private final HabboItem ball;
@@ -23,21 +20,40 @@ public class RebugKickBallAction implements Runnable {
private boolean isDribble; private boolean isDribble;
public boolean dead = false; public boolean dead = false;
// Track tiles traveled since last wall bounce for user-bounce logic private final boolean zigzag;
private int tilesSinceBounce = -1; // -1 = no bounce has happened yet private Direction8 zigzagA;
private Direction8 zigzagB;
private boolean zigzagSide = false;
private int tilesSinceBounce = -1;
public RebugKickBallAction(HabboItem ball, Room room, Direction8 direction, int momentum) { public RebugKickBallAction(HabboItem ball, Room room, Direction8 direction, int momentum) {
this(ball, room, direction, momentum, false);
}
public RebugKickBallAction(HabboItem ball, Room room, Direction8 direction, int momentum, boolean zigzag) {
this.ball = ball; this.ball = ball;
this.room = room; this.room = room;
this.direction = direction; this.direction = direction;
this.momentum = momentum; this.momentum = momentum;
this.isDribble = (momentum == 0); this.isDribble = (momentum == 0);
this.zigzag = zigzag && !this.isDribble;
if (this.zigzag) {
this.zigzagA = direction.rotateDirection45Degrees(false);
this.zigzagB = direction.rotateDirection45Degrees(true);
}
}
public boolean isDribble() {
return this.isDribble;
} }
private boolean isTileBlocked(int x, int y) { private boolean isTileBlocked(int x, int y) {
RoomTile tile = this.room.getLayout().getTile((short) x, (short) y); RoomTile tile = this.room.getLayout().getTile((short) x, (short) y);
if (tile == null) return true; if (tile == null) return true;
return tile.getState() != RoomTileState.OPEN; if (tile.getState() != RoomTileState.OPEN) return true;
return x == this.room.getLayout().getDoorX() && y == this.room.getLayout().getDoorY();
} }
@Override @Override
@@ -45,35 +61,87 @@ public class RebugKickBallAction implements Runnable {
if (this.dead || !this.room.isLoaded()) return; if (this.dead || !this.room.isLoaded()) return;
try { try {
int nextX = this.ball.getX() + this.direction.getDiffX(); int nextX;
int nextY = this.ball.getY() + this.direction.getDiffY(); int nextY;
Direction8 moveDir;
if (isTileBlocked(nextX, nextY)) { if (this.zigzag) {
this.direction = this.direction.rotateDirection180Degrees(); Direction8 preferred = this.zigzagSide ? this.zigzagB : this.zigzagA;
this.tilesSinceBounce = 0; Direction8 fallback = this.zigzagSide ? this.zigzagA : this.zigzagB;
nextX = this.ball.getX() + preferred.getDiffX();
nextY = this.ball.getY() + preferred.getDiffY();
if (isTileBlocked(nextX, nextY)) {
nextX = this.ball.getX() + fallback.getDiffX();
nextY = this.ball.getY() + fallback.getDiffY();
if (isTileBlocked(nextX, nextY)) {
nextX = this.ball.getX() + this.direction.getDiffX();
nextY = this.ball.getY() + this.direction.getDiffY();
if (isTileBlocked(nextX, nextY)) {
this.stopBall();
return;
}
moveDir = this.direction;
} else {
moveDir = fallback;
}
} else {
moveDir = preferred;
this.zigzagSide = !this.zigzagSide;
}
} else {
nextX = this.ball.getX() + this.direction.getDiffX(); nextX = this.ball.getX() + this.direction.getDiffX();
nextY = this.ball.getY() + this.direction.getDiffY(); nextY = this.ball.getY() + this.direction.getDiffY();
if (isTileBlocked(nextX, nextY)) {
int dx = this.direction.getDiffX();
int dy = this.direction.getDiffY();
if (dx != 0 && dy != 0) {
boolean xBlocked = isTileBlocked(this.ball.getX() + dx, this.ball.getY());
boolean yBlocked = isTileBlocked(this.ball.getX(), this.ball.getY() + dy);
if (xBlocked && !yBlocked) {
this.direction = Direction8.fromDelta(-dx, dy);
} else if (!xBlocked && yBlocked) {
this.direction = Direction8.fromDelta(dx, -dy);
} else {
this.direction = this.direction.rotateDirection180Degrees();
}
} else {
this.direction = this.direction.rotateDirection180Degrees();
}
this.tilesSinceBounce = 0;
nextX = this.ball.getX() + this.direction.getDiffX();
nextY = this.ball.getY() + this.direction.getDiffY();
}
moveDir = this.direction;
} }
RoomTile nextTile = this.room.getLayout().getTile((short) nextX, (short) nextY); RoomTile nextTile = this.room.getLayout().getTile((short) nextX, (short) nextY);
if (nextTile == null) return; if (nextTile == null) {
this.stopBall();
return;
}
RoomTile oldTile = this.room.getLayout().getTile(this.ball.getX(), this.ball.getY()); RoomTile oldTile = this.room.getLayout().getTile(this.ball.getX(), this.ball.getY());
double oldZ = this.ball.getZ(); double oldZ = this.ball.getZ();
this.ball.setRotation(this.direction.getRot()); this.ball.setRotation(moveDir.getRot());
this.ball.setX(nextTile.x); this.ball.setX(nextTile.x);
this.ball.setY(nextTile.y); this.ball.setY(nextTile.y);
this.ball.setZ(nextTile.getStackHeight()); this.ball.setZ(nextTile.getStackHeight());
this.ball.needsUpdate(true); this.ball.needsUpdate(true);
// Count tiles since bounce if (!this.zigzag && this.tilesSinceBounce >= 0) {
if (this.tilesSinceBounce >= 0) {
this.tilesSinceBounce++; this.tilesSinceBounce++;
} }
// After bouncing, if ball has traveled more than 1 tile from the wall, bounce off users if (!this.zigzag && this.tilesSinceBounce > 1 && !this.isDribble) {
if (this.tilesSinceBounce > 1 && !this.isDribble) {
THashSet<Habbo> habbos = this.room.getHabbosAt(nextTile.x, nextTile.y); THashSet<Habbo> habbos = this.room.getHabbosAt(nextTile.x, nextTile.y);
if (!habbos.isEmpty()) { if (!habbos.isEmpty()) {
this.direction = this.direction.rotateDirection180Degrees(); this.direction = this.direction.rotateDirection180Degrees();
@@ -81,19 +149,22 @@ public class RebugKickBallAction implements Runnable {
} }
} }
// Schedule next movement this.ball.setExtradata(this.isDribble ? "2" : "5");
this.room.sendComposer(new ItemStateComposer(this.ball).compose());
this.momentum -= 11;
if (!this.isDribble) { if (!this.isDribble) {
long delay = getDelayForMomentum(this.momentum); long delay = getDelayForMomentum(this.momentum);
if (delay > 0) { if (delay > 0) {
Emulator.getThreading().run(this, delay); Emulator.getThreading().run(this, delay);
} else { } else {
this.dead = true; this.stopBall();
} }
} else { } else {
this.dead = true; this.dead = true;
} }
// Update tiles
this.room.updateTile(oldTile); this.room.updateTile(oldTile);
this.room.updateTile(nextTile); this.room.updateTile(nextTile);
@@ -103,18 +174,20 @@ public class RebugKickBallAction implements Runnable {
} }
this.room.getItemsAt(nextTile).add(this.ball); this.room.getItemsAt(nextTile).add(this.ball);
// Send rolling animation
this.room.sendComposer(new FloorItemOnRollerComposer( this.room.sendComposer(new FloorItemOnRollerComposer(
this.ball, null, oldTile, oldZ, nextTile, this.ball.getZ(), 0.0D, this.room this.ball, null, oldTile, oldZ, nextTile, this.ball.getZ(), 0.0D, this.room
).compose()); ).compose());
// Decay momentum
this.momentum -= 11;
} catch (Exception e) { } catch (Exception e) {
this.dead = true; this.stopBall();
} }
} }
private void stopBall() {
this.dead = true;
this.ball.setExtradata("0");
this.room.sendComposer(new ItemStateComposer(this.ball).compose());
}
private long getDelayForMomentum(int momentum) { private long getDelayForMomentum(int momentum) {
switch (momentum) { switch (momentum) {
case 55: return 100L; case 55: return 100L;