Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Underground escape #158

Merged
merged 13 commits into from
Apr 22, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,51 @@ public static void placeTNT(PrisonEscapeLocation location) {
((TNTPrimed) WORLD.spawn(bukkitLocation, TNTPrimed.class)).setFuseTicks(EXPLOSION_TICKS);
}

// ########################################
// # Maze #
// ########################################

public static void fillMazeWithDirt(PrisonEscapeLocation upperCorner, PrisonEscapeLocation lowerCorner) {
fill(upperCorner, lowerCorner, Material.DIRT);
}

public static void clearMazePart(PrisonEscapeLocation upperCorner, PrisonEscapeLocation lowerCorner) {
fill(upperCorner, lowerCorner, Material.AIR);
}

public static void raiseMazeWall(PrisonEscapeLocation upperCorner, PrisonEscapeLocation lowerCorner) {
fill(upperCorner, lowerCorner, Material.COBBLESTONE);
}

public static boolean isDirtBlock(int x, int y, int z) {
return WORLD.getBlockAt(x, y, z).getType() == Material.DIRT;
}

public static void clearDirtFromMazePart(PrisonEscapeLocation upperCorner, PrisonEscapeLocation lowerCorner) {
for (int x = lowerCorner.getX(); x <= upperCorner.getX(); x++) {
for (int y = lowerCorner.getY(); y <= upperCorner.getY(); y++) {
for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) {
Block block = WORLD.getBlockAt(x, y, z);
if (block.getType() == Material.DIRT) {
block.setType(Material.AIR);
}
}
}
}
}

// ########################################
// # Util #
// ########################################

private static void fill(PrisonEscapeLocation upperCorner, PrisonEscapeLocation lowerCorner, Material type) {
for (int x = lowerCorner.getX(); x <= upperCorner.getX(); x++) {
for (int y = lowerCorner.getY(); y <= upperCorner.getY(); y++) {
for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) {
WORLD.getBlockAt(x, y, z).setType(type);
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
import net.tiagofar78.prisonescape.game.phases.Phase;
import net.tiagofar78.prisonescape.game.phases.Waiting;
import net.tiagofar78.prisonescape.game.prisonbuilding.Chest;
import net.tiagofar78.prisonescape.game.prisonbuilding.Obstacle;
import net.tiagofar78.prisonescape.game.prisonbuilding.PrisonBuilding;
import net.tiagofar78.prisonescape.game.prisonbuilding.PrisonEscapeLocation;
import net.tiagofar78.prisonescape.game.prisonbuilding.Vault;
import net.tiagofar78.prisonescape.game.prisonbuilding.WallCrack;
import net.tiagofar78.prisonescape.items.FunctionalItem;
import net.tiagofar78.prisonescape.items.Item;
import net.tiagofar78.prisonescape.items.SearchItem;
import net.tiagofar78.prisonescape.items.ToolItem;
import net.tiagofar78.prisonescape.kits.PoliceKit;
import net.tiagofar78.prisonescape.kits.PrisionerKit;
import net.tiagofar78.prisonescape.kits.TeamSelectorKit;
Expand Down Expand Up @@ -515,6 +517,13 @@ public int playerInteract(String playerName, PrisonEscapeLocation blockLocation,
BukkitTeleporter.teleport(player, destination);
return 0;
}

Obstacle obstacle = _prison.getObstacle(blockLocation);
if (obstacle != null) {
if (obstacleTookDamage(player, obstacle, item) == 0) {
return 0;
}
}
}

if (item.isFunctional()) {
Expand Down Expand Up @@ -816,6 +825,25 @@ public int playerFixWallCrack(PrisonEscapePlayer player, WallCrack crack) {
return 0;
}

public int obstacleTookDamage(PrisonEscapePlayer player, Obstacle obstacle, Item item) {
if (!_prisionersTeam.isOnTeam(player)) {
return -1;
}

if (!item.isTool()) {
return 0; // TODO maybe send a message to use right item
}

double returnCode = obstacle.takeDamage((ToolItem) item);
if (returnCode == -1) {
// TODO maybe send a message to use right item
} else if (returnCode == 0) {
obstacle.removeFromWorld();
}

return 0;
}

// ########################################
// # Util #
// ########################################
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package net.tiagofar78.prisonescape.game.prisonbuilding;

import net.tiagofar78.prisonescape.bukkit.BukkitWorldEditor;
import net.tiagofar78.prisonescape.items.MetalShovelItem;
import net.tiagofar78.prisonescape.items.MetalSpoonItem;
import net.tiagofar78.prisonescape.items.PlasticShovelItem;
import net.tiagofar78.prisonescape.items.PlasticSpoonItem;
import net.tiagofar78.prisonescape.items.ToolItem;

public class Dirt extends Obstacle {

private PrisonEscapeLocation _upperCornerLocation;
private PrisonEscapeLocation _lowerCornerLocation;

public Dirt(PrisonEscapeLocation upperCornerLocation, PrisonEscapeLocation lowerCornerLocation) {
_upperCornerLocation = upperCornerLocation;
_lowerCornerLocation = lowerCornerLocation;
}

@Override
public boolean isEffectiveTool(ToolItem tool) {
return tool instanceof PlasticSpoonItem || tool instanceof MetalSpoonItem || tool instanceof PlasticShovelItem || tool instanceof MetalShovelItem;
}

@Override
public boolean contains(PrisonEscapeLocation location) {
int x = location.getX();
int y = location.getY();
int z = location.getZ();

return isBetweenCorners(x, y, z) && BukkitWorldEditor.isDirtBlock(x, y, z);
}

private boolean isBetweenCorners(int x, int y, int z) {
return _lowerCornerLocation.getX() <= x && x <= _upperCornerLocation.getX() && _lowerCornerLocation
.getY() <= y && y <= _upperCornerLocation.getY() && _lowerCornerLocation
.getZ() <= z && z <= _upperCornerLocation.getZ();
}

@Override
public void removeFromWorld() {
BukkitWorldEditor.clearDirtFromMazePart(_upperCornerLocation, _lowerCornerLocation);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package net.tiagofar78.prisonescape.game.prisonbuilding;

import net.tiagofar78.prisonescape.bukkit.BukkitWorldEditor;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Maze {

private static final int CELL_SIDE_SIZE = 5;

private class Cell {
public int start;
public int end;

public Cell(int start, int end) {
this.start = start;
this.end = end;
}

@Override
public String toString() {
return "( " + start + ", " + end + ")";
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof Cell))
return false;

Cell vec = (Cell) obj;
return vec.start == start && vec.end == end;
}

@Override
public int hashCode() {
return this.toString().hashCode();
}
}

public List<Dirt> buildMaze(PrisonEscapeLocation upperCornerLocation, List<String> mazeFormat) {
if (!isValidFormat(mazeFormat)) {
throw new IllegalArgumentException("Illegal maze format. All rows must have same length.");
}

int height = mazeFormat.size();
int width = mazeFormat.get(0).length();

fillWithDirt(upperCornerLocation, width, height);
raiseWalls(upperCornerLocation, width, height);
clearExits(upperCornerLocation, mazeFormat);
clearSpawnPoints(upperCornerLocation, mazeFormat);

return getDirts(upperCornerLocation, mazeFormat);
}

private void fillWithDirt(PrisonEscapeLocation upperCornerLocation, int width, int height) {
PrisonEscapeLocation lowerCornerLocation = new PrisonEscapeLocation(upperCornerLocation).add(
-width * CELL_SIDE_SIZE + 1,
-2,
-height * CELL_SIDE_SIZE + 1
);

PrisonEscapeLocation dirtUpperCorner = new PrisonEscapeLocation(upperCornerLocation).add(-1, 0, -1);
PrisonEscapeLocation dirtLowerCorner = new PrisonEscapeLocation(lowerCornerLocation).add(1, 0, 1);
BukkitWorldEditor.fillMazeWithDirt(dirtUpperCorner, dirtLowerCorner);
}

private void raiseWalls(PrisonEscapeLocation upperCornerLocation, int width, int height) {
List<Cell> mazeSteped = generateMaze(width, height);
for (int z = 0; z < height; z++) {
for (int x = 0; x < width; x++) {
int current = (z * width) + x;
int lower = ((z + 1) * width) + x;
if (!mazeSteped.contains(new Cell(current, lower)) && z != height - 1) { // Check if there should be a horizontal wall
PrisonEscapeLocation upperCorner = new PrisonEscapeLocation(upperCornerLocation).add(
-x * CELL_SIDE_SIZE,
0,
(-z - 1) * CELL_SIDE_SIZE + 1
);
PrisonEscapeLocation lowerCorner = new PrisonEscapeLocation(upperCornerLocation).add(
(-x - 1) * CELL_SIDE_SIZE + 1,
-2,
(-z - 1) * CELL_SIDE_SIZE
);

BukkitWorldEditor.raiseMazeWall(upperCorner, lowerCorner);
}

if (!mazeSteped.contains(new Cell(current, current + 1)) && x != width - 1) {// Check if there should be a veritcal wall
PrisonEscapeLocation upperCorner = new PrisonEscapeLocation(upperCornerLocation).add(
(-x - 1) * CELL_SIDE_SIZE + 1,
0,
-z * CELL_SIDE_SIZE
);
PrisonEscapeLocation lowerCorner = new PrisonEscapeLocation(upperCornerLocation).add(
(-x - 1) * CELL_SIDE_SIZE,
-2,
(-z - 1) * CELL_SIDE_SIZE + 1
);

BukkitWorldEditor.raiseMazeWall(upperCorner, lowerCorner);
}
}
}
}

private void clearExits(PrisonEscapeLocation upperCornerLocation, List<String> mazeFormat) {
int height = mazeFormat.size();
int width = mazeFormat.get(0).length();

for (int z = 0; z < height; z++) {
String line = mazeFormat.get(z);
for (int x = 0; x < width; x++) {
if (line.charAt(x) == 'E') {
PrisonEscapeLocation upperSpawnLoc = getPartUpperLocation(upperCornerLocation, x, z);
PrisonEscapeLocation lowerSpawnLoc = getPartLowerLocation(upperCornerLocation, x, z, width, height);

BukkitWorldEditor.clearDirtFromMazePart(upperSpawnLoc, lowerSpawnLoc);
}
}
}
}

private void clearSpawnPoints(PrisonEscapeLocation upperCornerLocation, List<String> mazeFormat) {
int height = mazeFormat.size();
int width = mazeFormat.get(0).length();

for (int z = 0; z < height; z++) {
String line = mazeFormat.get(z);
for (int x = 0; x < width; x++) {
if (line.charAt(x) == 'S') {
PrisonEscapeLocation upperSpawnLoc = getPartUpperLocation(upperCornerLocation, x, z);
PrisonEscapeLocation lowerSpawnLoc = getPartLowerLocation(upperCornerLocation, x, z, width, height);

BukkitWorldEditor.clearMazePart(upperSpawnLoc, lowerSpawnLoc);
}
}
}
}

private PrisonEscapeLocation getPartUpperLocation(PrisonEscapeLocation upperMazeLocation, int x, int z) {
int upperX = x == 0 ? -x * CELL_SIDE_SIZE - 1 : -x * CELL_SIDE_SIZE;
int upperZ = z == 0 ? -z * CELL_SIDE_SIZE - 1 : -z * CELL_SIDE_SIZE;

return new PrisonEscapeLocation(upperMazeLocation).add(upperX, 0, upperZ);
}

private PrisonEscapeLocation getPartLowerLocation(
PrisonEscapeLocation upperMazeLocation,
int x,
int z,
int width,
int height
) {
int lowerX = x == width - 1 ? (-x - 1) * CELL_SIDE_SIZE + 2 : (-x - 1) * CELL_SIDE_SIZE + 1;
int lowerZ = z == height - 1 ? (-z - 1) * CELL_SIDE_SIZE + 2 : (-z - 1) * CELL_SIDE_SIZE + 1;

return new PrisonEscapeLocation(upperMazeLocation).add(lowerX, -2, lowerZ);
}

private boolean isValidFormat(List<String> format) {
if (format.size() == 0) {
return false;
}

int width = format.get(0).length();
for (String row : format) {
if (row.length() != width) {
return false;
}
}

return true;
}

private List<Dirt> getDirts(PrisonEscapeLocation upperCornerLocation, List<String> mazeFormat) {
List<Dirt> dirts = new ArrayList<>();

int height = mazeFormat.size();
int width = mazeFormat.get(0).length();

for (int z = 0; z < height; z++) {
String line = mazeFormat.get(z);
for (int x = 0; x < width; x++) {
if (line.charAt(x) == '#') {
PrisonEscapeLocation upperDirtLoc = getPartUpperLocation(upperCornerLocation, x, z);
PrisonEscapeLocation lowerDirtLoc = getPartLowerLocation(upperCornerLocation, x, z, width, height);

dirts.add(new Dirt(upperDirtLoc, lowerDirtLoc));
}
}
}

return dirts;
}

// Prim algorithm
private List<Cell> generateMaze(int width, int height) {
List<Cell> maze = new ArrayList<>();

List<Integer> visited = new ArrayList<>();
List<Cell> toVisit = new ArrayList<>();

visited.add(0);
toVisit.add(new Cell(0, 1));
toVisit.add(new Cell(0, width));

Random rand = new Random();

while (toVisit.size() > 0) {
int randomIndex = rand.nextInt(toVisit.size());
Cell nextPath = toVisit.remove(randomIndex);

if (visited.contains(nextPath.end))
continue;

if (nextPath.start > nextPath.end)
maze.add(new Cell(nextPath.end, nextPath.start));
else
maze.add(nextPath);

visited.add(nextPath.end);

int above = nextPath.end - width;
if (above > 0 && !visited.contains(above))
toVisit.add(new Cell(nextPath.end, above));

int left = nextPath.end - 1;
if (left % width != width - 1 && !visited.contains(left))
toVisit.add(new Cell(nextPath.end, left));

int right = nextPath.end + 1;
if (right % width != 0 && !visited.contains(right))
toVisit.add(new Cell(nextPath.end, right));

int below = nextPath.end + width;
if (below < width * height && !visited.contains(below))
toVisit.add(new Cell(nextPath.end, below));
}

return maze;
}
}
Loading
Loading