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 index 98666d50..4974c8fc 100644 --- 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 @@ -1,23 +1,24 @@ package com.eu.habbo.habbohotel.items.interactions.games.football; import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.gameclients.GameClient; 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.RoomLayout; +import com.eu.habbo.habbohotel.rooms.RoomTile; 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.util.pathfinding.Direction8; 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; + private Direction8 lastDribbleDirection; public InteractionRebugFootball(ResultSet set, Item baseItem) throws SQLException { super(set, baseItem); @@ -43,12 +44,65 @@ public class InteractionRebugFootball extends InteractionDefault { public void onWalkOn(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { super.onWalkOn(roomUnit, room, objects); + Direction8 userDir = Direction8.getDirection(roomUnit.getBodyRotation().getValue()); + this.lastDribbleDirection = userDir; + + RoomTile goal = roomUnit.getGoal(); + if (goal != null && goal.x == this.getX() && goal.y == this.getY()) { + this.kick(room, roomUnit, 55); + } else { + this.kick(room, roomUnit, 0); + } + } + + @Override + public void onWalkOff(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { + super.onWalkOff(roomUnit, room, objects); + + if (objects != null && objects.length >= 2 && objects[1] instanceof RoomTile && objects[0] instanceof RoomTile) { + RoomTile fromTile = (RoomTile) objects[0]; + RoomTile nextTile = (RoomTile) objects[1]; + + int dx = nextTile.x - fromTile.x; + int dy = nextTile.y - fromTile.y; + Direction8 walkDir = Direction8.fromDelta(dx, dy); + + if (this.lastDribbleDirection != null && walkDir.getRot() == this.lastDribbleDirection.getRot()) { + this.kick(room, roomUnit, 55); + return; + } + } + + if (this.currentThread != null) { + this.currentThread.dead = true; + this.currentThread = null; + } + this.setExtradata("0"); + room.sendComposer(new ItemStateComposer(this).compose()); + } + + @Override + public void onClick(GameClient client, Room room, Object[] objects) throws Exception { + super.onClick(client, room, objects); + + if (client == null) return; + RoomUnit unit = client.getHabbo().getRoomUnit(); + if (RoomLayout.tilesAdjecent(unit.getCurrentLocation(), room.getLayout().getTile(this.getX(), this.getY()))) { + this.kick(room, unit, 55); + } + } + + private void kick(Room room, RoomUnit kicker, int momentum) { + boolean wasMoving = this.currentThread != null && !this.currentThread.dead && !this.currentThread.isDribble(); + if (this.currentThread != null) { this.currentThread.dead = true; } - boolean hasPath = !roomUnit.getPath().isEmpty(); - this.currentThread = new RebugKickBallAction(this, room, roomUnit, hasPath); + Direction8 direction = Direction8.getDirection(kicker.getBodyRotation().getValue()); + boolean zigzag = wasMoving && momentum > 0; + + this.currentThread = new RebugKickBallAction(this, room, direction, momentum, zigzag); 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 index 55694364..aebc389b 100644 --- a/Emulator/src/main/java/com/eu/habbo/threading/runnables/RebugKickBallAction.java +++ b/Emulator/src/main/java/com/eu/habbo/threading/runnables/RebugKickBallAction.java @@ -4,39 +4,56 @@ 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.Habbo; import com.eu.habbo.habbohotel.users.HabboItem; 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 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; + private boolean isDribble; public boolean dead = false; - public RebugKickBallAction(HabboItem ball, Room room, RoomUnit kicker, boolean hasPath) { + private final boolean zigzag; + private Direction8 zigzagA; + private Direction8 zigzagB; + private boolean zigzagSide = false; + + private int tilesSinceBounce = -1; + + 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.room = room; - this.direction = Direction8.fromDelta( - ball.getX() - kicker.getX(), - ball.getY() - kicker.getY() - ); - this.momentum = hasPath ? 55 : 0; + this.direction = direction; + this.momentum = momentum; + 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) { 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; + if (tile.getState() != RoomTileState.OPEN) return true; + return x == this.room.getLayout().getDoorX() && y == this.room.getLayout().getDoorY(); } @Override @@ -44,34 +61,110 @@ public class RebugKickBallAction implements Runnable { if (this.dead || !this.room.isLoaded()) return; try { - int nextX = this.ball.getX() + this.direction.getDiffX(); - int nextY = this.ball.getY() + this.direction.getDiffY(); + int nextX; + int nextY; + Direction8 moveDir; - if (isTileBlocked(nextX, nextY)) { - this.direction = this.direction.rotateDirection180Degrees(); + if (this.zigzag) { + Direction8 preferred = this.zigzagSide ? this.zigzagB : this.zigzagA; + 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(); 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); - if (nextTile == null) return; + if (nextTile == null) { + this.stopBall(); + 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.setRotation(moveDir.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); + if (!this.zigzag && this.tilesSinceBounce >= 0) { + this.tilesSinceBounce++; + } + + if (!this.zigzag && this.tilesSinceBounce > 1 && !this.isDribble) { + THashSet habbos = this.room.getHabbosAt(nextTile.x, nextTile.y); + if (!habbos.isEmpty()) { + this.direction = this.direction.rotateDirection180Degrees(); + this.tilesSinceBounce = 0; + } + } + + this.ball.setExtradata(this.isDribble ? "2" : "5"); + this.room.sendComposer(new ItemStateComposer(this.ball).compose()); + + this.momentum -= 11; + + if (!this.isDribble) { + long delay = getDelayForMomentum(this.momentum); + if (delay > 0) { + Emulator.getThreading().run(this, delay); + } else { + this.stopBall(); + } + } else { + this.dead = true; } - // Update tiles this.room.updateTile(oldTile); this.room.updateTile(nextTile); @@ -81,18 +174,20 @@ public class RebugKickBallAction implements Runnable { } 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; + 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) { switch (momentum) { case 55: return 100L; diff --git a/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar b/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar index 34273136..1ee1c0ae 100644 Binary files a/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar and b/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar differ