Initial commit
This commit is contained in:
3
Java/Microcraft/src/META-INF/MANIFEST.MF
Normal file
3
Java/Microcraft/src/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: com.jdh.microcraft.Main
|
||||
|
||||
221
Java/Microcraft/src/com/jdh/microcraft/GameState.java
Normal file
221
Java/Microcraft/src/com/jdh/microcraft/GameState.java
Normal file
@@ -0,0 +1,221 @@
|
||||
package com.jdh.microcraft;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.SpawnProperties;
|
||||
import com.jdh.microcraft.entity.mob.EntityAirWizard;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gui.*;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.gen.LevelGenerator;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
import com.jdh.microcraft.util.Time;
|
||||
import com.jdh.microcraft.util.Window;
|
||||
|
||||
public class GameState implements State {
|
||||
private static final int LEVEL_DEPTH_OFFSET = LevelGenerator.UNDERWORLD_LEVELS;
|
||||
|
||||
// all world levels
|
||||
private final Level[] levels = new Level[LevelGenerator.OVERWORLD_LEVELS + LevelGenerator.UNDERWORLD_LEVELS];
|
||||
|
||||
// current level depth, ranges from [-UNDERWORLD_LEVELS, OVERWORLD_LEVELS)
|
||||
private int levelDepth;
|
||||
|
||||
// global, must be kept on game state to keep unique across levels
|
||||
private int nextEntityId, nextItemInstanceId;
|
||||
|
||||
// overall game difficulty multiplier
|
||||
public double difficulty;
|
||||
|
||||
public int score;
|
||||
public long playerDiedTicks;
|
||||
|
||||
public HUD hud;
|
||||
public Menu menu;
|
||||
|
||||
private final int playerColor;
|
||||
|
||||
public GameState(double difficulty, int playerColor) {
|
||||
this.difficulty = difficulty;
|
||||
this.playerColor = playerColor;
|
||||
this.nextEntityId = 1;
|
||||
this.nextItemInstanceId = 1;
|
||||
this.score = 0;
|
||||
this.playerDiedTicks = 0;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
// generate levels
|
||||
for (int i = 0; i < levels.length; i++) {
|
||||
this.levels[i] = new Level(Global.ticks + Time.now() + i, i - LEVEL_DEPTH_OFFSET, 256, 256);
|
||||
LevelGenerator.getGenerator(this.levels[i]).generate();
|
||||
}
|
||||
|
||||
// generate stairs
|
||||
Global.mainMenu.loadingMenu.setProgress(
|
||||
Font.Colors.YELLOW + "PLACING STAIRS...", 0.0);
|
||||
for (int i = 0; i < levels.length - 1; i++) {
|
||||
LevelGenerator.getStairsGenerator(this.levels[i], this.levels[i + 1]).generate();
|
||||
Global.mainMenu.loadingMenu.setProgress(i / (double) levels.length);
|
||||
}
|
||||
|
||||
// spawn entities
|
||||
Global.mainMenu.loadingMenu.setProgress(
|
||||
Font.Colors.YELLOW + "SPAWNING...", 0.0);
|
||||
for (int i = 0; i < levels.length; i++) {
|
||||
Level level = this.levels[i];
|
||||
|
||||
level.addEntitySpawns(SpawnProperties.getSpawnProperties(level));
|
||||
level.populate();
|
||||
|
||||
if (level.depth == 1) {
|
||||
EntityAirWizard wizard = new EntityAirWizard(level);
|
||||
level.spawnOnTile(wizard, Tile.CLOUD.id, level.width / 2, (level.height / 2) - 6);
|
||||
}
|
||||
|
||||
Global.mainMenu.loadingMenu.setProgress(i / (double) levels.length);
|
||||
}
|
||||
|
||||
// spawn player in overworld
|
||||
Level level = this.getLevel(0);
|
||||
this.setLevel(level.depth);
|
||||
|
||||
EntityPlayer player = new EntityPlayer(level, playerColor);
|
||||
this.hud = new HUD(player);
|
||||
|
||||
player.x = Level.toPixel(level.width / 2);
|
||||
player.y = Level.toPixel((level.height / 2) + 1);
|
||||
player.updateCamera();
|
||||
level.addEntity(player);
|
||||
|
||||
this.setMenu(new WelcomeMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (!Window.hasFocus()) {
|
||||
if (!(this.menu instanceof FocusMenu)) {
|
||||
this.setMenu(new FocusMenu(this.menu));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// death screen
|
||||
if (!(this.menu instanceof LoseMenu) &&
|
||||
this.playerDiedTicks != 0 &&
|
||||
(this.playerDiedTicks + 120) <= Global.ticks) {
|
||||
Sound.LOSE.play();
|
||||
this.setMenu(new LoseMenu());
|
||||
}
|
||||
|
||||
this.hud.tick();
|
||||
|
||||
if (this.menu != null) {
|
||||
Menu oldMenu = this.menu;
|
||||
this.menu.tick();
|
||||
|
||||
// interact pressed + nothing closed = close the current menu
|
||||
if (oldMenu == this.menu &&
|
||||
ControlHandler.INTERACT.pressedTick()) {
|
||||
this.setMenu(null);
|
||||
}
|
||||
} else {
|
||||
this.getCurrentLevel().tick();
|
||||
|
||||
// don't allow toggles on ticks where a new menu was opened
|
||||
if (this.menu != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// menu controls
|
||||
if (ControlHandler.MENU_QUIT.pressedTick()) {
|
||||
if (this.menu == null) {
|
||||
this.setMenu(new PauseMenu());
|
||||
} else {
|
||||
// quit the current menu
|
||||
Global.game.setMenu(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if (this.menu != null) {
|
||||
this.menu.update();
|
||||
} else {
|
||||
this.getCurrentLevel().update();
|
||||
}
|
||||
|
||||
this.hud.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Level level = this.getCurrentLevel();
|
||||
level.render();
|
||||
Renderer.clearLights();
|
||||
|
||||
if (level.depth < 0) {
|
||||
Renderer.addLights(this.getCurrentLevel().getLights(Renderer.getAABB()));
|
||||
Renderer.light(-111);
|
||||
}
|
||||
|
||||
Renderer.pushCamera();
|
||||
Renderer.camera.tx = 0;
|
||||
Renderer.camera.ty = 0;
|
||||
this.hud.render();
|
||||
|
||||
if (this.menu != null) {
|
||||
this.menu.render();
|
||||
}
|
||||
Renderer.popCamera();
|
||||
}
|
||||
|
||||
public void setMenu(Menu menu) {
|
||||
if (this.menu != null) {
|
||||
this.menu.destroy();
|
||||
}
|
||||
|
||||
if (menu != null) {
|
||||
menu.init();
|
||||
}
|
||||
|
||||
this.menu = menu;
|
||||
}
|
||||
|
||||
public Menu getMenu() {
|
||||
return this.menu;
|
||||
}
|
||||
|
||||
public Level getCurrentLevel() {
|
||||
return this.levels[this.levelDepth + LEVEL_DEPTH_OFFSET];
|
||||
}
|
||||
|
||||
public Level getLevel(int depth) {
|
||||
assert (this.isDepthValid(depth));
|
||||
return this.levels[depth + LEVEL_DEPTH_OFFSET];
|
||||
}
|
||||
|
||||
public void setLevel(int depth) {
|
||||
assert (this.isDepthValid(depth));
|
||||
this.levelDepth = depth;
|
||||
}
|
||||
|
||||
public boolean isDepthValid(int depth) {
|
||||
return depth >= -LEVEL_DEPTH_OFFSET && depth < LevelGenerator.OVERWORLD_LEVELS;
|
||||
}
|
||||
|
||||
public int getNextEntityId() {
|
||||
return this.nextEntityId++;
|
||||
}
|
||||
|
||||
public int getNextItemInstanceId() {
|
||||
return this.nextItemInstanceId++;
|
||||
}
|
||||
}
|
||||
60
Java/Microcraft/src/com/jdh/microcraft/Global.java
Normal file
60
Java/Microcraft/src/com/jdh/microcraft/Global.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package com.jdh.microcraft;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gui.mainmenu.MainMenu;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.Time;
|
||||
import com.jdh.microcraft.util.Window;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
// Encapsulates (statically) all game state
|
||||
public class Global {
|
||||
public enum StateType {
|
||||
MENU, GAME
|
||||
}
|
||||
|
||||
public static StateType currentStateType;
|
||||
public static GameState game;
|
||||
public static MainMenuState mainMenu;
|
||||
public static State currentState;
|
||||
public static Random random = new Random(Time.now());
|
||||
public static long ticks = 0, frames = 0;
|
||||
|
||||
public static void setState(StateType state) {
|
||||
Global.currentStateType = state;
|
||||
|
||||
Renderer.reset();
|
||||
|
||||
switch (state) {
|
||||
case GAME -> {
|
||||
Sound.START.play();
|
||||
Global.game = new GameState(
|
||||
Global.mainMenu.difficultySelectMenu.getSelectedDifficulty(),
|
||||
Color.get(
|
||||
Global.mainMenu.colorSelectMenu.colors
|
||||
));
|
||||
Global.mainMenu.menu = Global.mainMenu.loadingMenu;
|
||||
Global.mainMenu.loadingMenu.setProgress("LOADING", 0.0);
|
||||
Global.game.init();
|
||||
Global.currentState = Global.game;
|
||||
}
|
||||
case MENU -> {
|
||||
Global.game = null;
|
||||
Global.mainMenu.mainMenu = new MainMenu();
|
||||
Global.mainMenu.menu = Global.mainMenu.mainMenu;
|
||||
Global.currentState = Global.mainMenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLoadingInfo(String text, double progress) {
|
||||
Global.mainMenu.loadingMenu.progress = progress;
|
||||
Global.mainMenu.loadingMenu.text = text;
|
||||
|
||||
Renderer.clear();
|
||||
Global.mainMenu.loadingMenu.render();
|
||||
Window.renderFrame();
|
||||
}
|
||||
}
|
||||
92
Java/Microcraft/src/com/jdh/microcraft/Main.java
Normal file
92
Java/Microcraft/src/com/jdh/microcraft/Main.java
Normal file
@@ -0,0 +1,92 @@
|
||||
package com.jdh.microcraft;
|
||||
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.util.Keyboard;
|
||||
import com.jdh.microcraft.util.Window;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystemNotFoundException;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Main implements Runnable {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("CWD is " + Paths.get("").toAbsolutePath().toString());
|
||||
|
||||
// initialize FS
|
||||
Optional<URI> testURI = Optional.ofNullable(Main.class.getResource("/tiles.png")).map(url -> {
|
||||
try {
|
||||
return url.toURI();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
});
|
||||
|
||||
if (testURI.isPresent() && testURI.get().getScheme().equals("jar")) {
|
||||
for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
|
||||
if (provider.getScheme().equalsIgnoreCase("jar")) {
|
||||
try {
|
||||
provider.getFileSystem(testURI.get());
|
||||
} catch (FileSystemNotFoundException e) {
|
||||
try {
|
||||
provider.newFileSystem(testURI.get(), Map.of());
|
||||
} catch (IOException ioe) {
|
||||
throw new Error(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
Window.init("MICROCRAFT", screen.width / 2, screen.height / 2);
|
||||
new Thread(new Main()).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Window.loop(
|
||||
this::init,
|
||||
this::destroy,
|
||||
this::tick,
|
||||
this::update,
|
||||
this::render
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
Global.mainMenu = new MainMenuState();
|
||||
Global.currentState = Global.mainMenu;
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
Global.ticks++;
|
||||
Keyboard.tick();
|
||||
Global.currentState.tick();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
Keyboard.update();
|
||||
Global.currentState.update();
|
||||
}
|
||||
|
||||
private void render() {
|
||||
Global.frames++;
|
||||
Renderer.clear();
|
||||
Global.currentState.render();
|
||||
}
|
||||
}
|
||||
45
Java/Microcraft/src/com/jdh/microcraft/MainMenuState.java
Normal file
45
Java/Microcraft/src/com/jdh/microcraft/MainMenuState.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.jdh.microcraft;
|
||||
|
||||
import com.jdh.microcraft.gui.ColorSelectMenu;
|
||||
import com.jdh.microcraft.gui.DifficultySelectMenu;
|
||||
import com.jdh.microcraft.gui.Menu;
|
||||
import com.jdh.microcraft.gui.mainmenu.AboutMenu;
|
||||
import com.jdh.microcraft.gui.mainmenu.HowToPlayMenu;
|
||||
import com.jdh.microcraft.gui.mainmenu.LoadingMenu;
|
||||
import com.jdh.microcraft.gui.mainmenu.MainMenu;
|
||||
|
||||
public class MainMenuState implements State {
|
||||
public Menu menu;
|
||||
|
||||
public MainMenu mainMenu;
|
||||
public LoadingMenu loadingMenu;
|
||||
public HowToPlayMenu howToPlayMenu;
|
||||
public AboutMenu aboutMenu;
|
||||
public ColorSelectMenu colorSelectMenu;
|
||||
public DifficultySelectMenu difficultySelectMenu;
|
||||
|
||||
public MainMenuState() {
|
||||
this.mainMenu = new MainMenu();
|
||||
this.loadingMenu = new LoadingMenu();
|
||||
this.howToPlayMenu = new HowToPlayMenu();
|
||||
this.aboutMenu = new AboutMenu();
|
||||
this.colorSelectMenu = new ColorSelectMenu();
|
||||
this.difficultySelectMenu = new DifficultySelectMenu();
|
||||
this.menu = this.mainMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
this.menu.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
this.menu.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
this.menu.render();
|
||||
}
|
||||
}
|
||||
7
Java/Microcraft/src/com/jdh/microcraft/State.java
Normal file
7
Java/Microcraft/src/com/jdh/microcraft/State.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package com.jdh.microcraft;
|
||||
|
||||
public interface State {
|
||||
void tick();
|
||||
void update();
|
||||
void render();
|
||||
}
|
||||
235
Java/Microcraft/src/com/jdh/microcraft/entity/Entity.java
Normal file
235
Java/Microcraft/src/com/jdh/microcraft/entity/Entity.java
Normal file
@@ -0,0 +1,235 @@
|
||||
package com.jdh.microcraft.entity;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.ai.AI;
|
||||
import com.jdh.microcraft.gfx.Light;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.LevelEntityMetadata;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.level.tile.TileLiquid;
|
||||
import com.jdh.microcraft.level.tile.TileStair;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Entity {
|
||||
// current location
|
||||
public int x, y;
|
||||
|
||||
// size
|
||||
public int width, height;
|
||||
|
||||
// level this entity belongs to
|
||||
public Level level;
|
||||
|
||||
// set to true on ticks where entity moves
|
||||
public boolean moving;
|
||||
|
||||
// set to true if the entity is in a liquid
|
||||
public boolean swimming;
|
||||
|
||||
// true if the entity is currently on stairs (onStairs) or has entered stairs this tick (onStairsTick)
|
||||
public boolean onStairs;
|
||||
|
||||
// metadata about this entity, tracked by the current level
|
||||
public final LevelEntityMetadata metadata;
|
||||
|
||||
// current tile locations, managed by Level
|
||||
// location of CENTER of entity
|
||||
public int tileX = -1, tileY = -1;
|
||||
|
||||
// unique entity id
|
||||
public final int id;
|
||||
|
||||
// entity AI, optional
|
||||
public AI ai;
|
||||
|
||||
// current direction and direction last tick
|
||||
protected Direction direction = Direction.DOWN;
|
||||
private Direction lastDirection;
|
||||
|
||||
// positions at the LAST tick
|
||||
private int lastX, lastY;
|
||||
|
||||
// knockback velocity
|
||||
private double kx, ky;
|
||||
|
||||
public Entity(Level level) {
|
||||
this.level = level;
|
||||
this.id = Global.game.getNextEntityId();
|
||||
this.width = 6;
|
||||
this.height = 6;
|
||||
this.metadata = new LevelEntityMetadata(this);
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return this.direction;
|
||||
}
|
||||
|
||||
public Light getLight() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.metadata.remove = true;
|
||||
}
|
||||
|
||||
// schedules this entity to be moved to another level on the next tick
|
||||
public void moveLevel(int depth, int x, int y) {
|
||||
this.metadata.moveLevel(depth, x, y);
|
||||
}
|
||||
|
||||
// called when this entity moves between levels
|
||||
public void onDepthChange(int prevDepth) {
|
||||
|
||||
}
|
||||
|
||||
public void knockback(double strength, Direction d) {
|
||||
this.knockback(strength, d.x, d.y);
|
||||
}
|
||||
|
||||
public void knockback(double strength, int x, int y) {
|
||||
this.kx = Math.signum(x) * strength;
|
||||
this.ky = Math.signum(y) * strength;
|
||||
}
|
||||
|
||||
public int getRenderOffsetX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getRenderOffsetY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void onDirectionChange() {
|
||||
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
this.moving = this.lastX != this.x || this.lastY != this.y;
|
||||
|
||||
int dx = this.x - this.lastX, dy = this.y - this.lastY;
|
||||
if (dx != 0 || dy != 0) {
|
||||
this.direction = Direction.get(dx, dy);
|
||||
}
|
||||
|
||||
if (this.direction != this.lastDirection) {
|
||||
this.onDirectionChange();
|
||||
}
|
||||
|
||||
this.lastDirection = this.direction;
|
||||
|
||||
this.lastX = this.x;
|
||||
this.lastY = this.y;
|
||||
this.swimming = Tile.TILES[this.level.getTile(this.tileX, this.tileY)] instanceof TileLiquid;
|
||||
this.onStairs = Tile.TILES[this.level.getTile(this.tileX, this.tileY)] instanceof TileStair;
|
||||
|
||||
// apply knockback
|
||||
this.move(
|
||||
FMath.tickedDoubleToInt(Global.ticks, this.kx),
|
||||
FMath.tickedDoubleToInt(Global.ticks, this.ky)
|
||||
);
|
||||
this.kx *= 0.85;
|
||||
this.ky *= 0.85;
|
||||
|
||||
if (this.ai != null) {
|
||||
this.ai.tick();
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (this.ai != null) {
|
||||
this.ai.update();
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
|
||||
}
|
||||
|
||||
public boolean collides(Entity e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void collide(Entity e) {
|
||||
|
||||
}
|
||||
|
||||
// called if THIS entity hits E
|
||||
public boolean hit(Entity e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// called when E hits THIS entity
|
||||
public void onHit(Entity e) {
|
||||
|
||||
}
|
||||
|
||||
public boolean interact(Entity e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void move(int dx, int dy) {
|
||||
this.moveAxis(dx, 0);
|
||||
this.moveAxis(0, dy);
|
||||
}
|
||||
|
||||
// moves along a single axis
|
||||
protected boolean moveAxis(int dx, int dy) {
|
||||
assert(dx == 0 || dy == 0);
|
||||
int ox = this.x, oy = this.y;
|
||||
this.x += dx;
|
||||
this.y += dy;
|
||||
|
||||
// deny any movement that would move this entity off of the map
|
||||
if (this.x < 0 || this.y < 0 ||
|
||||
(this.x + this.width) >= Level.toPixel(this.level.width) ||
|
||||
(this.y + this.height >= Level.toPixel(this.level.height))) {
|
||||
this.x = ox;
|
||||
this.y = oy;
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Entity> entities = level.getEntityCollisions(this);
|
||||
for (Entity e : entities) {
|
||||
if (e != this && this.collides(e) && e.collides(this)) {
|
||||
this.collide(e);
|
||||
e.collide(this);
|
||||
|
||||
// deny movement if it is TOWARDS the colliding entity
|
||||
if ((dx != 0 && FMath.sameSign(dx, e.x - this.x)) ||
|
||||
(dy != 0 && FMath.sameSign(dy, e.y - this.y))) {
|
||||
this.x = ox;
|
||||
this.y = oy;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int[] p : level.getTileCollisions(this)) {
|
||||
Tile t = Tile.TILES[level.getTile(p[0], p[1])];
|
||||
t.bump(level, p[0], p[1], this);
|
||||
|
||||
if (t.collides(level, p[0], p[1], this)) {
|
||||
this.x = ox;
|
||||
this.y = oy;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canSwimIn(Tile tile, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getCenterX() {
|
||||
return this.x + (this.width / 2);
|
||||
}
|
||||
|
||||
public int getCenterY() {
|
||||
return this.y + (this.height / 2);
|
||||
}
|
||||
}
|
||||
115
Java/Microcraft/src/com/jdh/microcraft/entity/EntityItem.java
Normal file
115
Java/Microcraft/src/com/jdh/microcraft/entity/EntityItem.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package com.jdh.microcraft.entity;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.entity.projectile.EntityProjectile;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.Time;
|
||||
|
||||
public class EntityItem extends Entity {
|
||||
public final ItemStack stack;
|
||||
public int timeToLive, timeToPickup;
|
||||
|
||||
private int z;
|
||||
private double vx, vy, vz, dx, dy;
|
||||
|
||||
public EntityItem(Level level, ItemStack stack, int x, int y, double vx, double vy, double vz) {
|
||||
super(level);
|
||||
this.stack = stack;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = 4;
|
||||
this.vx = vx;
|
||||
this.vy = vy;
|
||||
this.vz = vz;
|
||||
this.dx = 0;
|
||||
this.dy = 0;
|
||||
this.timeToLive = Time.TPS * (180 + Global.random.nextInt(60));
|
||||
this.timeToPickup = 20;
|
||||
this.width = 8;
|
||||
this.height = 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Entity e) {
|
||||
return e instanceof EntityMob ?
|
||||
((EntityMob) e).canPickup(this) && this.timeToPickup == 0 :
|
||||
!(e instanceof EntityItem);
|
||||
}
|
||||
|
||||
public static EntityItem spawn(Level level, ItemStack stack, int x, int y, Direction d) {
|
||||
Global.random.setSeed(stack.hashCode() + (x * 31) ^ (y * 17));
|
||||
EntityItem result = new EntityItem(
|
||||
level, stack, x, y,
|
||||
d.x * (0.5 + Global.random.nextDouble() * 0.1),
|
||||
d.y * (0.5 + Global.random.nextDouble() * 0.1),
|
||||
1.0 + (Global.random.nextDouble() * 0.2)
|
||||
);
|
||||
level.addEntity(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static EntityItem spawn(Level level, ItemStack stack, int x, int y) {
|
||||
Global.random.setSeed(stack.hashCode() + (x * 31) ^ (y * 17));
|
||||
EntityItem result = new EntityItem(
|
||||
level, stack, x, y,
|
||||
(Global.random.nextBoolean() ? -1.0 : 1.0) * (0.3 + Global.random.nextDouble() * 0.1),
|
||||
(Global.random.nextBoolean() ? -1.0 : 1.0) * (0.3 + Global.random.nextDouble() * 0.1),
|
||||
1.0 + (Global.random.nextDouble() * 0.2)
|
||||
);
|
||||
level.addEntity(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean canPickup(Entity e) {
|
||||
return this.timeToPickup == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (--this.timeToLive == 0) {
|
||||
this.remove();
|
||||
}
|
||||
|
||||
this.timeToPickup = Math.max(this.timeToPickup - 1, 0);
|
||||
|
||||
this.dx += this.vx;
|
||||
this.dy += this.vy;
|
||||
|
||||
while (Math.abs(this.dx) >= 1.0) {
|
||||
if (!this.moveAxis((int) Math.signum(this.dx), 0)) {
|
||||
this.vx *= -0.8;
|
||||
}
|
||||
this.dx += -Math.signum(this.dx);
|
||||
}
|
||||
|
||||
while (Math.abs(this.dy) >= 1.0) {
|
||||
if (!this.moveAxis(0, (int) Math.signum(this.dy))) {
|
||||
this.vy *= -0.8;
|
||||
}
|
||||
this.dy += -Math.signum(this.dy);
|
||||
}
|
||||
|
||||
this.z += this.vz;
|
||||
|
||||
// bounce
|
||||
if (this.z < 0) {
|
||||
this.z = 0;
|
||||
this.vx *= 0.4;
|
||||
this.vy *= 0.4;
|
||||
this.vz *= -0.6;
|
||||
}
|
||||
|
||||
// gravity
|
||||
this.vz -= 0.2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
this.stack.instance.item.render(this.stack.instance, this.level, this.x, this.y);
|
||||
}
|
||||
}
|
||||
289
Java/Microcraft/src/com/jdh/microcraft/entity/EntityPlayer.java
Normal file
289
Java/Microcraft/src/com/jdh/microcraft/entity/EntityPlayer.java
Normal file
@@ -0,0 +1,289 @@
|
||||
package com.jdh.microcraft.entity;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntityHumanoid;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmashParticle;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Light;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gui.PlayerInventoryMenu;
|
||||
import com.jdh.microcraft.gui.TransitionMenu;
|
||||
import com.jdh.microcraft.gui.crafting.InventoryCraftingMenu;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.consumable.ItemConsumable;
|
||||
import com.jdh.microcraft.item.tool.ItemTool;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class EntityPlayer extends EntityHumanoid {
|
||||
// maintains a list of the previous N equipped items, used so when
|
||||
// this.equipped is null we can go back to the last existing item from this
|
||||
// list in the player's current inventory. fx.:
|
||||
// - player has sword equipped
|
||||
// - player picks up lantern, lantern is equipped
|
||||
// - player puts down lantern
|
||||
// - sword should be re-equipped
|
||||
private final List<Integer> lastEquippedItems;
|
||||
|
||||
private final int color;
|
||||
|
||||
public EntityPlayer(Level level, int color) {
|
||||
super(level, new Inventory(256));
|
||||
this.lastEquippedItems = new ArrayList<>();
|
||||
this.color = color;
|
||||
|
||||
ItemStack glove = new ItemStack(new ItemInstance(Item.GLOVE, 0), 1);
|
||||
this.inventory.add(glove);
|
||||
this.equipped = glove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hurt(int amount, boolean ignoreArmor) {
|
||||
if (super.hurt(amount, ignoreArmor)) {
|
||||
Sound.PLAYER_HURT.play();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Light getLight() {
|
||||
Light parent = super.getLight();
|
||||
return parent != null ? parent : new Light(
|
||||
this.x + (this.width / 2),
|
||||
this.y + (this.height / 2),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
EntitySmashParticle.spawn(
|
||||
this.level,
|
||||
this.getCenterX(), this.getCenterY(),
|
||||
this.getColor(),
|
||||
10, 30
|
||||
);
|
||||
Global.game.playerDiedTicks = Global.ticks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPickup(EntityItem e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pickup(ItemStack stack) {
|
||||
super.pickup(stack);
|
||||
Sound.PICKUP.play();
|
||||
Global.game.score++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDepthChange(int prevDepth) {
|
||||
super.onDepthChange(prevDepth);
|
||||
Global.game.setLevel(this.level.depth);
|
||||
Global.game.setMenu(new TransitionMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
// track currently equipped item
|
||||
if (this.equipped != null &&
|
||||
(this.lastEquippedItems.size() == 0 ||
|
||||
this.lastEquippedItems.get(0) != this.equipped.instance.id)) {
|
||||
this.lastEquippedItems.add(0, this.equipped.instance.id);
|
||||
}
|
||||
|
||||
// if nothing is equipped, try to equip previously equipped items
|
||||
// if there are no previous items to equip, equip the POW GLOVE
|
||||
if (this.equipped == null) {
|
||||
while (this.lastEquippedItems.size() != 0 && this.equipped == null) {
|
||||
this.equipped = this.inventory.findByInstanceId(
|
||||
this.lastEquippedItems.remove(0));
|
||||
}
|
||||
|
||||
if (this.equipped == null) {
|
||||
this.equipped = this.inventory.find(Item.GLOVE);
|
||||
}
|
||||
}
|
||||
|
||||
// crafting menu
|
||||
if (ControlHandler.TOGGLE_CRAFTING.pressedTick()) {
|
||||
Global.game.setMenu(new InventoryCraftingMenu(this));
|
||||
return;
|
||||
}
|
||||
|
||||
// item dropping
|
||||
if (ControlHandler.DROP.pressedTick() &&
|
||||
this.equipped != null &&
|
||||
this.equipped.instance.item.isDroppable()) {
|
||||
this.drop(this.equipped);
|
||||
}
|
||||
|
||||
// get tile player is currently facing
|
||||
int fx = this.getFacingTileX(), fy = this.getFacingTileY();
|
||||
Tile ft = Tile.TILES[level.getTile(fx, fy)];
|
||||
|
||||
// entities in this tile and the tile being faced, excluding this one
|
||||
List<Entity> facingEntities = Stream.concat(
|
||||
level.getEntities(this.tileX, this.tileY).stream(),
|
||||
level.getEntities(fx, fy).stream()
|
||||
).filter(e -> e != this).collect(Collectors.toList());
|
||||
|
||||
if (ControlHandler.INTERACT.pressedTick()) {
|
||||
boolean interactEntity = false, interactTile = false;
|
||||
|
||||
if (!this.swimming) {
|
||||
// try to interact with facing entities
|
||||
for (Entity e : facingEntities) {
|
||||
interactEntity |= e.interact(this);
|
||||
}
|
||||
|
||||
// interact with facing tile if no entities were interacted with
|
||||
if (!interactEntity) {
|
||||
interactTile = ft.interact(this.level, fx, fy, this);
|
||||
}
|
||||
}
|
||||
|
||||
// toggle inventory
|
||||
if (!interactEntity && !interactTile) {
|
||||
Global.game.setMenu(new PlayerInventoryMenu(this, true));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.swimming && ControlHandler.HIT.pressedTick()) {
|
||||
this.updateAnimationFrame(true);
|
||||
|
||||
boolean hitEntity = false;
|
||||
for (Entity e : facingEntities) {
|
||||
if (this.hit(e)) {
|
||||
e.onHit(this);
|
||||
hitEntity = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hitEntity) {
|
||||
this.animateAction();
|
||||
} else if (this.equipped.instance.item instanceof ItemConsumable) {
|
||||
this.equipped.instance.item.use(this.equipped.instance, level, this.tileX, this.tileY, this);
|
||||
} else if (this.equipped.instance.item instanceof ItemTool) {
|
||||
// try to use the active tool on the facing tile
|
||||
ItemTool tool = (ItemTool) this.equipped.instance.item;
|
||||
boolean ideal = (ft.getIdealTools() & tool.type) != 0,
|
||||
usable = (ft.getUsableTools() & tool.type) != 0;
|
||||
|
||||
if (ideal || usable) {
|
||||
int staminaCost = (int) (tool.getStaminaCostMultiplier() *
|
||||
(ideal ?
|
||||
(1 + Global.random.nextInt(2)) :
|
||||
(3 + Global.random.nextInt(3))));
|
||||
if (this.takeStamina(staminaCost)) {
|
||||
Item equippedItem = this.equipped.instance.item;
|
||||
if (ft.hit(this.level, fx, fy, this)) {
|
||||
this.animateHit(equippedItem, fx, fy);
|
||||
} else {
|
||||
// give stamina back if hit failed
|
||||
this.stamina += staminaCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try to use the active item on the facing tile
|
||||
Item equippedItem = this.equipped.instance.item;
|
||||
if (equippedItem.use(this.equipped.instance, level, fx, fy, this)) {
|
||||
this.animateHit(equippedItem, fx, fy);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hitTicks == 0 && !hitEntity) {
|
||||
// no hit? animate an action
|
||||
this.animateAction();
|
||||
Sound.MISS.play();
|
||||
} else {
|
||||
Sound.HIT.play();
|
||||
}
|
||||
}
|
||||
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
if (ControlHandler.UP.down()) {
|
||||
dy--;
|
||||
}
|
||||
|
||||
if (ControlHandler.DOWN.down()) {
|
||||
dy++;
|
||||
}
|
||||
|
||||
if (ControlHandler.LEFT.down()) {
|
||||
dx--;
|
||||
}
|
||||
|
||||
if (ControlHandler.RIGHT.down()) {
|
||||
dx++;
|
||||
}
|
||||
|
||||
if (!this.swimming || Global.ticks % 2 == 0) {
|
||||
this.move(dx, dy);
|
||||
}
|
||||
|
||||
// override entity direction, the player should be able to change their
|
||||
// direction even when stationary
|
||||
if (dx != 0 || dy != 0) {
|
||||
this.direction = Direction.get(dx, dy);
|
||||
}
|
||||
|
||||
// center camera on the player
|
||||
this.updateCamera();
|
||||
}
|
||||
|
||||
// updates current renderer camera to track the player
|
||||
public void updateCamera() {
|
||||
Renderer.camera.centerOn(
|
||||
this.x + (this.width / 2), this.y + (this.height / 2),
|
||||
0, 0,
|
||||
Level.toPixel(this.level.width), Level.toPixel(this.level.height)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStaminaRechargeRate() {
|
||||
return 0.11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStamina() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return this.color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHurtColor() {
|
||||
return Color.addAll(this.color, 222);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.jdh.microcraft.entity;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntitySkeleton;
|
||||
import com.jdh.microcraft.entity.mob.EntitySlime;
|
||||
import com.jdh.microcraft.entity.mob.EntityZombie;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class SpawnProperties {
|
||||
public final Class<? extends Entity> cls;
|
||||
public final Function<Level, Entity> spawnFunction;
|
||||
public final int chance, cap;
|
||||
|
||||
// chance is spawn rate/minute
|
||||
// cap and chance are per 128x128 area
|
||||
public SpawnProperties(Level level, Class<? extends Entity> cls, Function<Level, Entity> spawnFunction, int chance, int cap) {
|
||||
this.cls = cls;
|
||||
this.spawnFunction = spawnFunction;
|
||||
|
||||
double scale = ((level.width * level.height) / (128.0 * 128.0)) * Global.game.difficulty;
|
||||
this.chance = (int) (chance * scale);
|
||||
this.cap = (int) (cap * scale);
|
||||
}
|
||||
|
||||
public static List<SpawnProperties> getSpawnProperties(Level level) {
|
||||
return switch (level.depth) {
|
||||
case 1 -> List.of(
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createBlueSlime, 50, 4),
|
||||
new SpawnProperties(level, EntitySkeleton.class, EntitySkeleton::createSkeleton, 100, 4)
|
||||
);
|
||||
case 0 -> List.of(
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createGreenSlime, 300, 24),
|
||||
new SpawnProperties(level, EntityZombie.class, EntityZombie::createEasyZombie, 80, 3)
|
||||
);
|
||||
case -1 -> List.of(
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createGreenSlime, 200, 24),
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createBlueSlime, 100, 4),
|
||||
new SpawnProperties(level, EntityZombie.class, EntityZombie::createEasyZombie, 200, 20),
|
||||
new SpawnProperties(level, EntitySkeleton.class, EntitySkeleton::createSkeleton, 200, 24)
|
||||
);
|
||||
case -2 -> List.of(
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createGreenSlime, 200, 32),
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createBlueSlime, 220, 32),
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createRedSlime, 80, 4),
|
||||
new SpawnProperties(level, EntityZombie.class, EntityZombie::createMediumZombie, 200, 24),
|
||||
new SpawnProperties(level, EntitySkeleton.class, EntitySkeleton::createSkeleton, 250, 24)
|
||||
);
|
||||
case -3 -> List.of(
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createGreenSlime, 100, 32),
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createBlueSlime, 100, 32),
|
||||
new SpawnProperties(level, EntitySlime.class, EntitySlime::createRedSlime, 400, 32),
|
||||
new SpawnProperties(level, EntityZombie.class, EntityZombie::createHardZombie, 250, 32),
|
||||
new SpawnProperties(level, EntitySkeleton.class, EntitySkeleton::createSkeleton, 250, 32)
|
||||
);
|
||||
default -> List.of();
|
||||
};
|
||||
}
|
||||
}
|
||||
19
Java/Microcraft/src/com/jdh/microcraft/entity/ai/AI.java
Normal file
19
Java/Microcraft/src/com/jdh/microcraft/entity/ai/AI.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
|
||||
public class AI {
|
||||
protected final Entity entity;
|
||||
|
||||
public AI(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.attack.WizardAttackBeam;
|
||||
import com.jdh.microcraft.entity.attack.WizardAttackBurst;
|
||||
import com.jdh.microcraft.entity.attack.WizardAttackSpiral;
|
||||
import com.jdh.microcraft.entity.mob.EntityAirWizard;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
|
||||
public class AIAirWizard extends AIHostileHumanoid {
|
||||
private long lastAttack;
|
||||
private final EntityAirWizard wizard;
|
||||
|
||||
private Direction randomDirection;
|
||||
|
||||
public AIAirWizard(EntityAirWizard wizard) {
|
||||
super(wizard, 0.75, 3.0 * wizard.strength);
|
||||
this.wizard = wizard;
|
||||
this.lastAttack = Global.ticks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (this.wizard.attack == null) {
|
||||
super.tick();
|
||||
} else {
|
||||
// move randomly
|
||||
if (this.randomDirection == null || Global.random.nextInt(80) == 0) {
|
||||
this.randomDirection = Direction.ALL.get(Global.random.nextInt(4));
|
||||
}
|
||||
|
||||
this.moveTowards(
|
||||
this.wizard.x + this.randomDirection.x * 10,
|
||||
this.wizard.y + this.randomDirection.y * 10
|
||||
);
|
||||
}
|
||||
|
||||
if ((Global.ticks - this.lastAttack) > 120 + Global.random.nextInt(480)) {
|
||||
this.wizard.attack = switch (Global.random.nextInt(3)) {
|
||||
case 0 -> new WizardAttackBurst(this.wizard);
|
||||
case 1 -> new WizardAttackSpiral(this.wizard);
|
||||
default -> new WizardAttackBeam(this.wizard);
|
||||
};
|
||||
|
||||
if (Renderer.inBounds(this.wizard.getCenterX(), this.wizard.getCenterY())) {
|
||||
Sound.WIZARD_ATTACK.play();
|
||||
}
|
||||
|
||||
this.lastAttack = Global.ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntityHumanoid;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public class AIHostileHumanoid extends AIHostileMob {
|
||||
private final EntityHumanoid humanoid;
|
||||
private final double speed, strength;
|
||||
|
||||
private Direction randomMoveDirection;
|
||||
|
||||
public AIHostileHumanoid(EntityHumanoid humanoid, double speed, double strength) {
|
||||
super(humanoid, strength);
|
||||
this.humanoid = humanoid;
|
||||
this.speed = speed;
|
||||
this.strength = strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveTowards(int x, int y) {
|
||||
double dx = FMath.sign(x - this.humanoid.x),
|
||||
dy = FMath.sign(y - this.humanoid.y),
|
||||
l = FMath.norm(dx, dy);
|
||||
|
||||
dx /= l;
|
||||
dy /= l;
|
||||
dx = Double.isNaN(dx) ? 0 : dx;
|
||||
dy = Double.isNaN(dy) ? 0 : dy;
|
||||
|
||||
dx *= this.speed;
|
||||
dy *= this.speed;
|
||||
|
||||
if (!this.humanoid.swimming || Global.ticks % 2 == 0) {
|
||||
int mx = FMath.tickedDoubleToInt(Global.ticks, dx),
|
||||
my = FMath.tickedDoubleToInt(Global.ticks, dy);
|
||||
|
||||
if (this.shouldMove(mx, 0)) {
|
||||
this.humanoid.move(mx, 0);
|
||||
}
|
||||
|
||||
if (this.shouldMove(0, my)) {
|
||||
this.humanoid.move(0, my);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.target == null) {
|
||||
if (this.randomMoveDirection == null && Global.random.nextInt(240) == 0) {
|
||||
this.randomMoveDirection = Direction.ALL.get(Global.random.nextInt(4));
|
||||
} else if (this.randomMoveDirection != null) {
|
||||
this.moveTowards(
|
||||
this.humanoid.x + this.randomMoveDirection.x * 10,
|
||||
this.humanoid.y + this.randomMoveDirection.y * 10
|
||||
);
|
||||
|
||||
if (Global.random.nextInt(120) == 0) {
|
||||
this.randomMoveDirection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.level.tile.TileLava;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
import com.jdh.microcraft.util.Time;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class AIHostileMob extends AI {
|
||||
protected final double sightDistance;
|
||||
protected final int targetPermanenceTicks;
|
||||
|
||||
protected final double strength;
|
||||
protected int ticksSinceTargetSeen;
|
||||
public Entity target;
|
||||
|
||||
public AIHostileMob(Entity entity, double strength) {
|
||||
super(entity);
|
||||
this.strength = strength;
|
||||
this.sightDistance = (16 * 10) * this.strength;
|
||||
this.targetPermanenceTicks = (int) (180 * this.strength);
|
||||
}
|
||||
|
||||
// avoid really dangerous stuff
|
||||
protected boolean shouldMove(int dx, int dy) {
|
||||
int cx = this.entity.getCenterX() + dx,
|
||||
cy = this.entity.getCenterY() + dy,
|
||||
tx = Level.toTile(cx),
|
||||
ty = Level.toTile(cy);
|
||||
|
||||
return !(Tile.TILES[this.entity.level.getTile(tx, ty)] instanceof TileLava);
|
||||
}
|
||||
|
||||
protected abstract void moveTowards(int x, int y);
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.entity.level.player != null &&
|
||||
FMath.norm(this.entity.x - this.entity.level.player.x,
|
||||
this.entity.y - this.entity.level.player.y) <= this.sightDistance) {
|
||||
this.target = this.entity.level.player;
|
||||
this.ticksSinceTargetSeen = 0;
|
||||
} else {
|
||||
this.ticksSinceTargetSeen++;
|
||||
|
||||
// lose target if it has been too long
|
||||
if (this.ticksSinceTargetSeen >= this.targetPermanenceTicks) {
|
||||
this.target = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.target != null) {
|
||||
int tcx = this.target.x + (this.target.width / 2),
|
||||
tcy = this.target.y + (this.target.height / 2),
|
||||
tdx = tcx - this.entity.x,
|
||||
tdy = tcy - this.entity.y;
|
||||
|
||||
double pd = this.getPreferredTargetDistance(),
|
||||
pdt = this.getPreferredTargetDistanceThreshold();
|
||||
|
||||
if (Math.abs(tdx) - pd > pdt ||
|
||||
Math.abs(tdy) - pd > pdt) {
|
||||
this.moveTowards(this.target.x, this.target.y);
|
||||
} else if (pd != 0.0 && pdt != 0.0) {
|
||||
// ranged mobs: strafe in directions not towards the target
|
||||
Global.random.setSeed(Global.ticks / Time.TPS);
|
||||
if (Global.random.nextInt(3) == 0) {
|
||||
Direction td = Direction.get(tdx, tdy);
|
||||
Direction strafeDir = new ArrayList<>(Direction.ALL)
|
||||
.stream()
|
||||
.filter(d -> d != td && d != td.opposite())
|
||||
.collect(Collectors.toList())
|
||||
.get(Global.random.nextInt(2));
|
||||
this.moveTowards(this.entity.x + strafeDir.x, this.entity.y + strafeDir.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected double getPreferredTargetDistance() {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
protected double getPreferredTargetDistanceThreshold() {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.entity.mob.EntitySkeleton;
|
||||
|
||||
public class AISkeleton extends AIHostileHumanoid {
|
||||
private final EntitySkeleton skeleton;
|
||||
|
||||
public AISkeleton(EntitySkeleton skeleton) {
|
||||
super(skeleton, 0.5 * skeleton.strength, skeleton.strength);
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.target != null) {
|
||||
this.skeleton.shoot(this.target.x, this.target.y);
|
||||
}
|
||||
}
|
||||
|
||||
protected double getPreferredTargetDistance() {
|
||||
return 16 * 3;
|
||||
}
|
||||
|
||||
protected double getPreferredTargetDistanceThreshold() {
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntitySlime;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
|
||||
public class AISlime extends AIHostileMob {
|
||||
private final EntitySlime slime;
|
||||
|
||||
private long lastJump;
|
||||
private final int jumpDelay;
|
||||
|
||||
public AISlime(EntitySlime slime) {
|
||||
super(slime, slime.strength);
|
||||
this.slime = slime;
|
||||
this.jumpDelay = (int) Math.max(140 - (20 * slime.strength), 60);
|
||||
}
|
||||
|
||||
private boolean canJump() {
|
||||
return Global.ticks - this.lastJump >= this.jumpDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveTowards(int x, int y) {
|
||||
if (!this.slime.jumping && this.canJump()) {
|
||||
this.lastJump = Global.ticks;
|
||||
this.slime.jump(x - this.slime.x, y - this.slime.y, 0.5 * slime.strength);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
Global.random.setSeed(Global.ticks * this.slime.id);
|
||||
if (this.target == null && Global.random.nextInt(180) == 0) {
|
||||
this.lastJump = Global.ticks;
|
||||
this.slime.jump(Direction.ALL.get(Global.random.nextInt(4)), 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.jdh.microcraft.entity.ai;
|
||||
|
||||
import com.jdh.microcraft.entity.mob.EntityZombie;
|
||||
|
||||
public class AIZombie extends AIHostileHumanoid {
|
||||
public AIZombie(EntityZombie zombie) {
|
||||
super(zombie, 0.45 * zombie.strength, zombie.strength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.jdh.microcraft.entity.attack;
|
||||
|
||||
import com.jdh.microcraft.entity.mob.EntityAirWizard;
|
||||
|
||||
public abstract class WizardAttack {
|
||||
protected final EntityAirWizard wizard;
|
||||
public int time;
|
||||
|
||||
public WizardAttack(EntityAirWizard wizard, int time) {
|
||||
this.wizard = wizard;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public boolean done() {
|
||||
return this.time <= 0;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
this.time--;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.jdh.microcraft.entity.attack;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.ai.AIHostileMob;
|
||||
import com.jdh.microcraft.entity.mob.EntityAirWizard;
|
||||
import com.jdh.microcraft.entity.projectile.EntityAirBlast;
|
||||
|
||||
public class WizardAttackBeam extends WizardAttack {
|
||||
public WizardAttackBeam(EntityAirWizard wizard) {
|
||||
super(wizard, 60);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if ((Global.ticks % 2) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
AIHostileMob ai = (AIHostileMob) this.wizard.ai;
|
||||
if (ai.target != null) {
|
||||
this.wizard.level.addEntity(
|
||||
new EntityAirBlast(
|
||||
this.wizard.level, this.wizard,
|
||||
this.wizard.getCenterX(), this.wizard.getCenterY(),
|
||||
ai.target.getCenterX(), ai.target.getCenterY(),
|
||||
1.4,
|
||||
(int) (3 * this.wizard.strength))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.jdh.microcraft.entity.attack;
|
||||
|
||||
import com.jdh.microcraft.entity.mob.EntityAirWizard;
|
||||
import com.jdh.microcraft.entity.projectile.EntityAirBlast;
|
||||
|
||||
public class WizardAttackBurst extends WizardAttack {
|
||||
private static final int SIZE = 32;
|
||||
|
||||
private boolean attacked = false;
|
||||
|
||||
public WizardAttackBurst(EntityAirWizard wizard) {
|
||||
super(wizard, 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.attacked) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.attacked = true;
|
||||
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
int dx = (int) (Math.cos((i / (double) SIZE) * (2 * Math.PI)) * 16),
|
||||
dy = (int) (Math.sin((i / (double) SIZE) * (2 * Math.PI)) * 16);
|
||||
|
||||
this.wizard.level.addEntity(
|
||||
new EntityAirBlast(
|
||||
this.wizard.level, this.wizard,
|
||||
this.wizard.getCenterX() + dx,
|
||||
this.wizard.getCenterY() + dy,
|
||||
this.wizard.getCenterX() + dx * 10,
|
||||
this.wizard.getCenterY() + dy * 10,
|
||||
1.2,
|
||||
(int) (3 * this.wizard.strength)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.jdh.microcraft.entity.attack;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntityAirWizard;
|
||||
import com.jdh.microcraft.entity.projectile.EntityAirBlast;
|
||||
|
||||
public class WizardAttackSpiral extends WizardAttack {
|
||||
public WizardAttackSpiral(EntityAirWizard wizard) {
|
||||
super(wizard, 240);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if ((Global.ticks % 2) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int dx = (int) (Math.cos(((Global.ticks % 60) / 60.0) * (2 * Math.PI)) * 16),
|
||||
dy = (int) (Math.sin(((Global.ticks % 60) / 60.0) * (2 * Math.PI)) * 16);
|
||||
|
||||
this.wizard.level.addEntity(
|
||||
new EntityAirBlast(
|
||||
this.wizard.level, this.wizard,
|
||||
this.wizard.getCenterX() + dx,
|
||||
this.wizard.getCenterY() + dy,
|
||||
this.wizard.getCenterX() + dx * 10,
|
||||
this.wizard.getCenterY() + dy * 10,
|
||||
1.4,
|
||||
(int) (3 * this.wizard.strength)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.crafting.AnvilCraftingMenu;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityAnvil extends EntityFurniture {
|
||||
public EntityAnvil(Level level) {
|
||||
super(level, Item.ANVIL, 15, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interact(Entity e) {
|
||||
if (!(e instanceof EntityPlayer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.game.setMenu(new AnvilCraftingMenu((EntityPlayer) e, this));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.ChestMenu;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityChest extends EntityFurniture {
|
||||
public Inventory inventory = new Inventory(512);
|
||||
|
||||
public EntityChest(Level level) {
|
||||
super(level, Item.CHEST, 15, 13);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hit(Entity e) {
|
||||
if (super.hit(e)) {
|
||||
for (ItemStack s : this.inventory.stacks) {
|
||||
EntityItem.spawn(this.level, s, Level.toCenter(e.tileX), Level.toCenter(e.tileY));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interact(Entity e) {
|
||||
if (!(e instanceof EntityPlayer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.game.setMenu(new ChestMenu((EntityPlayer) e, this));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.crafting.BenchCraftingMenu;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityCraftingBench extends EntityFurniture {
|
||||
public EntityCraftingBench(Level level) {
|
||||
super(level, Item.CRAFTING_BENCH, 15, 12);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interact(Entity e) {
|
||||
if (!(e instanceof EntityPlayer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.game.setMenu(new BenchCraftingMenu((EntityPlayer) e, this));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.crafting.FurnaceMenu;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityFurnace extends EntityFurniture {
|
||||
public EntityFurnace(Level level) {
|
||||
super(level, Item.FURNACE, 15, 14);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interact(Entity e) {
|
||||
if (!(e instanceof EntityPlayer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.game.setMenu(new FurnaceMenu((EntityPlayer) e, this));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.entity.projectile.EntityProjectile;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.furniture.ItemFurniture;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class EntityFurniture extends Entity {
|
||||
private final ItemFurniture item;
|
||||
private int pushTime;
|
||||
|
||||
public EntityFurniture(Level level, ItemFurniture item, int width, int height) {
|
||||
super(level);
|
||||
this.item = item;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (int j = 0; j <= 1; j++) {
|
||||
Renderer.render(
|
||||
this.getSpriteOffsetX() + i, this.getSpriteOffsetY() + j,
|
||||
this.x + this.getRenderOffsetX() + (i * 8),
|
||||
this.y + this.getRenderOffsetY() + (j * 8),
|
||||
this.getColor(), Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Entity e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
super.collide(e);
|
||||
|
||||
if (e instanceof EntityMob) {
|
||||
this.pushTime++;
|
||||
|
||||
if (this.pushTime == 3) {
|
||||
// push in the direction the mob is moving
|
||||
EntityMob mob = ((EntityMob) e);
|
||||
Direction d = mob.getDirection();
|
||||
this.move(d.x, d.y);
|
||||
this.pushTime = 0;
|
||||
}
|
||||
} else if (e instanceof EntityProjectile) {
|
||||
for (ItemStack s : this.getDrops()) {
|
||||
EntityItem.spawn(level, s, Level.toCenter(this.tileX), Level.toCenter(this.tileY));
|
||||
}
|
||||
this.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHit(Entity e) {
|
||||
if (!(e instanceof EntityMob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ItemStack s : this.getDrops()) {
|
||||
EntityItem.spawn(level, s, Level.toCenter(this.tileX), Level.toCenter(this.tileY));
|
||||
}
|
||||
this.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSwimIn(Tile tile, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected List<ItemStack> getDrops() {
|
||||
return List.of(new ItemStack(new ItemInstance(this.item)));
|
||||
}
|
||||
|
||||
public int getSpriteOffsetX() {
|
||||
return this.item.getTileSpriteX();
|
||||
}
|
||||
|
||||
public int getSpriteOffsetY() {
|
||||
return this.item.getTileSpriteY();
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return this.item.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract boolean interact(Entity e);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.gfx.Light;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityLantern extends EntityFurniture {
|
||||
public static final int LIGHT_POWER = 6;
|
||||
|
||||
public EntityLantern(Level level) {
|
||||
super(level, Item.LANTERN, 13, 13);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderOffsetX() {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderOffsetY() {
|
||||
return -3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Light getLight() {
|
||||
return new Light(
|
||||
this.getCenterX(),
|
||||
this.getCenterY(),
|
||||
LIGHT_POWER
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interact(Entity e) {
|
||||
ItemStack s = new ItemStack(new ItemInstance(Item.LANTERN, 0), 1);
|
||||
|
||||
if (e instanceof EntityMob && ((EntityMob) e).inventory.add(s)) {
|
||||
EntityMob mob = (EntityMob) e;
|
||||
mob.equipped = s;
|
||||
this.remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.jdh.microcraft.entity.furniture;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.crafting.OvenMenu;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityOven extends EntityFurniture {
|
||||
public EntityOven(Level level) {
|
||||
super(level, Item.OVEN, 15, 13);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean interact(Entity e) {
|
||||
if (!(e instanceof EntityPlayer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.game.setMenu(new OvenMenu((EntityPlayer) e, this));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.jdh.microcraft.entity.mob;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.ai.AIAirWizard;
|
||||
import com.jdh.microcraft.entity.attack.WizardAttack;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmokeParticle;
|
||||
import com.jdh.microcraft.entity.projectile.EntityProjectile;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gui.WinMenu;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
|
||||
public class EntityAirWizard extends EntityHumanoid {
|
||||
public final double strength = 1.0 * Global.game.difficulty;
|
||||
|
||||
public WizardAttack attack;
|
||||
|
||||
public EntityAirWizard(Level level) {
|
||||
super(level, Inventory.NONE);
|
||||
this.health = this.getMaxHealth();
|
||||
this.stamina = this.getMaxStamina();
|
||||
this.ai = new AIAirWizard(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
Sound.WIZARD_DEATH.play();
|
||||
Global.game.score += 5000;
|
||||
Global.game.setMenu(new WinMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hurt(int amount) {
|
||||
return super.hurt(amount == 1 ? 0 : amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Entity e) {
|
||||
return !(e instanceof EntityProjectile) && super.collides(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
if (e instanceof EntityPlayer) {
|
||||
this.hit(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (Global.random.nextInt(10) == 0) {
|
||||
EntitySmokeParticle.spawn(this.level, this.getCenterX(), this.getCenterY(), Tile.CLOUD.getColor(), 1, 4);
|
||||
}
|
||||
|
||||
if (this.attack != null) {
|
||||
if (this.attack.done()) {
|
||||
this.attack = null;
|
||||
} else {
|
||||
this.attack.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHitDamage(Entity e) {
|
||||
return (int) ((2 + Global.random.nextInt(5)) * this.strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseSpriteX() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseSpriteY() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCarrySpriteX() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCarrySpriteY() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(111, 224, 441, 555);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHurtColor() {
|
||||
return Color.get(444, 335, 552, 555);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStaminaRechargeRate() {
|
||||
return 0.3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStamina() {
|
||||
return (int) (this.strength * 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return (int) (this.strength * 80);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package com.jdh.microcraft.entity.mob;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Light;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.armor.*;
|
||||
import com.jdh.microcraft.item.tool.ItemTool;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.level.tile.TileLiquid;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
|
||||
public abstract class EntityHumanoid extends EntityMob {
|
||||
public static final int BASE_SPRITE_X = 0, BASE_SPRITE_Y = 11;
|
||||
public static final int CARRY_SPRITE_X = 0, CARRY_SPRITE_Y = 9;
|
||||
private static final int SWIM_SPRITE_X = 9, SWIM_SPRITE_Y = 11;
|
||||
|
||||
private static final int SWIM_COLOR = Color.get(334, 445, 555, 555);
|
||||
|
||||
// current sprite location
|
||||
private int spriteX, spriteY;
|
||||
|
||||
// current animation frame ticks and flipped/frame state
|
||||
private int animationTicks;
|
||||
private boolean animationFlipped, animationXFrame;
|
||||
|
||||
// equipped armor
|
||||
public ItemStack[] armor = new ItemStack[ItemArmor.NUM_TYPES];
|
||||
|
||||
public EntityHumanoid(Level level, Inventory inventory) {
|
||||
super(level, inventory);
|
||||
this.width = 11;
|
||||
this.height = 11;
|
||||
this.animationTicks = this.getAnimationFrameTicks();
|
||||
this.updateAnimationFrame(false);
|
||||
}
|
||||
|
||||
// level must be in [1..3]
|
||||
public static void giveRandomEquipment(EntityHumanoid entity, int level, boolean armor, boolean weapon) {
|
||||
assert (level >= 1 && level <= 3);
|
||||
Item[][] armorTable = new Item[][]{
|
||||
{Item.IRON_HELMET, Item.IRON_CHESTPLATE, Item.IRON_LEGGINGS, Item.IRON_BOOTS},
|
||||
{Item.GOLD_HELMET, Item.GOLD_CHESTPLATE, Item.GOLD_LEGGINGS, Item.GOLD_BOOTS},
|
||||
{Item.GOLD_HELMET, Item.GOLD_CHESTPLATE, Item.GOLD_LEGGINGS, Item.GOLD_BOOTS}
|
||||
};
|
||||
|
||||
Item[][] weaponTable = new Item[][]{
|
||||
{Item.ROCK_SWORD, Item.ROCK_AXE},
|
||||
{Item.IRON_SWORD, Item.IRON_AXE},
|
||||
{Item.GOLD_SWORD, Item.GEM_SWORD, Item.MITHRIL_SWORD}
|
||||
};
|
||||
|
||||
if (armor) {
|
||||
for (int i = 0; i < ItemArmor.NUM_TYPES; i++) {
|
||||
if (Global.random.nextInt((4 - level) * 7) == 0) {
|
||||
ItemStack item = new ItemStack(new ItemInstance(armorTable[level - 1][i], 0), 1);
|
||||
entity.armor[i] = item;
|
||||
entity.inventory.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weapon && Global.random.nextInt((4 - level) * 8) == 0) {
|
||||
ItemStack item = new ItemStack(
|
||||
new ItemInstance(
|
||||
weaponTable[level - 1][Global.random.nextInt(weaponTable[level - 1].length)],
|
||||
0),
|
||||
1
|
||||
);
|
||||
entity.equipped = item;
|
||||
entity.inventory.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItem(Item item, int count) {
|
||||
ItemStack removed = super.removeItem(item, count);
|
||||
|
||||
for (int i = 0; i < this.armor.length; i++) {
|
||||
if (this.armor[i] == removed) {
|
||||
this.armor[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
|
||||
for (ItemStack s : this.inventory.stacks) {
|
||||
EntityItem.spawn(this.level, s, this.getCenterX(), this.getCenterY());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pickup(ItemStack stack) {
|
||||
super.pickup(stack);
|
||||
|
||||
if (stack.instance.item instanceof ItemArmor) {
|
||||
ItemArmor armor = (ItemArmor) stack.instance.item;
|
||||
if (this.armor[armor.slot] == null) {
|
||||
this.armor[armor.slot] = stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int getAnimationFrameTicks() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
public boolean hurt(int amount, boolean ignoreArmor) {
|
||||
if (ignoreArmor) {
|
||||
return super.hurt(amount);
|
||||
}
|
||||
|
||||
double reduction = 0;
|
||||
for (ItemStack s : this.armor) {
|
||||
if (s != null) {
|
||||
reduction += ((ItemArmor) s.instance.item).getDamageReduction(s.instance);
|
||||
}
|
||||
}
|
||||
|
||||
reduction = reduction > 0 ? Global.random.nextInt(Math.max((int) (reduction / 2.5), 2)) : 0;
|
||||
return super.hurt((int) Math.max(amount - reduction, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hurt(int amount) {
|
||||
return this.hurt(amount, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Light getLight() {
|
||||
if (this.equipped != null) {
|
||||
int power = this.equipped.instance.item.getLightPower();
|
||||
if (power > 0) {
|
||||
return new Light(
|
||||
this.getCenterX(),
|
||||
this.getCenterY(),
|
||||
power
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHitDamage(Entity e) {
|
||||
return (this.equipped != null && (this.equipped.instance.item instanceof ItemTool)) ?
|
||||
((ItemTool) this.equipped.instance.item).getDamage(this.equipped.instance) : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderOffsetX() {
|
||||
return -3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderOffsetY() {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDirectionChange() {
|
||||
super.onDirectionChange();
|
||||
this.updateAnimationFrame(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
// drowning
|
||||
if (this.swimming && (Global.ticks % 60) == 0) {
|
||||
if (this.stamina == 0) {
|
||||
this.hurt(1, true);
|
||||
} else {
|
||||
this.takeStamina(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.moving) {
|
||||
this.animationTicks--;
|
||||
|
||||
if (this.animationTicks == 0) {
|
||||
this.updateAnimationFrame(true);
|
||||
}
|
||||
}
|
||||
|
||||
// pick the correct current animation frame but don't switch
|
||||
this.updateAnimationFrame(false);
|
||||
}
|
||||
|
||||
protected boolean carrying() {
|
||||
return this.equipped != null && this.equipped.instance.item.carry(this);
|
||||
}
|
||||
|
||||
public int getBaseSpriteX() {
|
||||
return BASE_SPRITE_X;
|
||||
}
|
||||
|
||||
public int getBaseSpriteY() {
|
||||
return BASE_SPRITE_Y;
|
||||
}
|
||||
|
||||
public int getCarrySpriteX() {
|
||||
return CARRY_SPRITE_X;
|
||||
}
|
||||
|
||||
public int getCarrySpriteY() {
|
||||
return CARRY_SPRITE_Y;
|
||||
}
|
||||
|
||||
protected int getSpritesheetOffsetX() {
|
||||
return this.carrying() ? this.getCarrySpriteX() : this.getBaseSpriteX();
|
||||
}
|
||||
|
||||
protected int getSpritesheetOffsetY() {
|
||||
return this.carrying() ? this.getCarrySpriteY() : this.getBaseSpriteY();
|
||||
}
|
||||
|
||||
protected void updateAnimationFrame(boolean switchFrame) {
|
||||
if (switchFrame) {
|
||||
this.animationTicks = this.getAnimationFrameTicks();
|
||||
}
|
||||
|
||||
this.spriteY = this.getSpritesheetOffsetY();
|
||||
|
||||
switch (this.direction) {
|
||||
case NORTH, SOUTH -> {
|
||||
if (switchFrame) {
|
||||
this.animationFlipped = !this.animationFlipped;
|
||||
}
|
||||
|
||||
this.spriteX = this.getSpritesheetOffsetX() +
|
||||
(this.direction == Direction.NORTH ? 2 : 0);
|
||||
}
|
||||
case EAST, WEST -> {
|
||||
if (switchFrame) {
|
||||
this.animationXFrame = !this.animationXFrame;
|
||||
}
|
||||
|
||||
this.animationFlipped = this.direction == Direction.LEFT;
|
||||
this.spriteX = this.getSpritesheetOffsetX() +
|
||||
(this.animationXFrame ? 4 : 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void renderArmor(ItemArmor item) {
|
||||
if (this.swimming && item.type != ItemArmor.TYPE_HELMET) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sx = this.spriteX - this.getCarrySpriteX(),
|
||||
sy = this.spriteY - this.getCarrySpriteY();
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (int j = 0; j <= 1; j++) {
|
||||
Renderer.render(
|
||||
sx + item.getSpriteBaseX() + (this.animationFlipped ? (1 - i) : i),
|
||||
sy + item.getSpriteBaseY() + j,
|
||||
this.x + (i * 8) + this.getRenderOffsetX(),
|
||||
this.y + (j * 8) + this.getRenderOffsetY(),
|
||||
item.getColor(),
|
||||
this.animationFlipped ? Renderer.FLIP_X : Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
// flash with hurt color on hurt
|
||||
int color = this.invulnerableTicks > 0 && ((Global.ticks / 4) % 2) == 0 ?
|
||||
this.getHurtColor() :
|
||||
this.getColor();
|
||||
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (int j = 0; j <= (this.swimming ? 0 : 1); j++) {
|
||||
Renderer.render(
|
||||
this.spriteX + (this.animationFlipped ? (1 - i) : i), this.spriteY + j,
|
||||
this.x + (i * 8) + this.getRenderOffsetX(),
|
||||
this.y + (j * 8) + this.getRenderOffsetY(),
|
||||
color,
|
||||
this.animationFlipped ? Renderer.FLIP_X : Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// render armor
|
||||
for (ItemStack s : this.armor) {
|
||||
if (s != null) {
|
||||
this.renderArmor((ItemArmor) s.instance.item);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.swimming) {
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
Renderer.render(
|
||||
SWIM_SPRITE_X, SWIM_SPRITE_Y,
|
||||
this.x + (i * 8) + this.getRenderOffsetX(),
|
||||
this.y + 2 + this.getRenderOffsetY(),
|
||||
SWIM_COLOR,
|
||||
i == 0 ? Renderer.FLIP_NONE : Renderer.FLIP_X
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// render carrying item
|
||||
if (this.equipped != null && this.equipped.instance.item.carry(this)) {
|
||||
this.equipped.instance.item.renderCarry(this.equipped.instance, this.level, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSwimIn(Tile tile, int x, int y) {
|
||||
return tile instanceof TileLiquid;
|
||||
}
|
||||
|
||||
public abstract int getColor();
|
||||
|
||||
public abstract int getHurtColor();
|
||||
}
|
||||
327
Java/Microcraft/src/com/jdh/microcraft/entity/mob/EntityMob.java
Normal file
327
Java/Microcraft/src/com/jdh/microcraft/entity/mob/EntityMob.java
Normal file
@@ -0,0 +1,327 @@
|
||||
package com.jdh.microcraft.entity.mob;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.furniture.EntityFurniture;
|
||||
import com.jdh.microcraft.entity.particle.EntityTextParticle;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public abstract class EntityMob extends Entity {
|
||||
private static final int HIT_SPRITE_X = 9, HIT_SPRITE_Y = 12;
|
||||
private static final int HIT_COLOR = Color.get(222, 533, 544, 555);
|
||||
private static final int ACTION_SPRITE_X = 8, ACTION_SPRITE_Y = 11;
|
||||
private static final int ACTION_COLOR = Color.get(555, 555, 555, 555);
|
||||
private static final int ACTION_TICKS = 6;
|
||||
private static final int HIT_TICKS = 4;
|
||||
private static final int USE_ITEM_TICKS = 4;
|
||||
|
||||
private static final int STAMINA_RECHARGE_DELAY_TICKS = 40;
|
||||
private static final int INVULNERABLE_TICKS = 30;
|
||||
|
||||
protected int actionTicks;
|
||||
protected int hitTicks, hitX, hitY;
|
||||
|
||||
protected Item useItem;
|
||||
protected int useItemTicks;
|
||||
|
||||
public int health, stamina;
|
||||
public int invulnerableTicks;
|
||||
public int staminaRechargeDelayTicks;
|
||||
|
||||
public final Inventory inventory;
|
||||
public ItemStack equipped;
|
||||
|
||||
public EntityMob(Level level, Inventory inventory) {
|
||||
super(level);
|
||||
this.health = this.getMaxHealth();
|
||||
this.stamina = this.getMaxStamina();
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
public void drop(ItemStack stack) {
|
||||
assert(this.inventory.contains(stack));
|
||||
|
||||
assert(stack.instance.item.isDroppable());
|
||||
EntityItem item = EntityItem.spawn(
|
||||
this.level,
|
||||
this.removeItem(this.equipped.instance.item, this.equipped.size),
|
||||
this.getCenterX(), this.getCenterY(),
|
||||
this.getDirection()
|
||||
);
|
||||
item.timeToPickup = 80;
|
||||
}
|
||||
|
||||
public int getFacingTileX() {
|
||||
return switch (this.direction) {
|
||||
case EAST -> tileX + 1;
|
||||
case WEST -> tileX - 1;
|
||||
default -> tileX;
|
||||
};
|
||||
}
|
||||
|
||||
public int getFacingTileY() {
|
||||
return switch (this.direction) {
|
||||
case NORTH -> tileY - 1;
|
||||
case SOUTH -> tileY + 1;
|
||||
default -> tileY;
|
||||
};
|
||||
}
|
||||
|
||||
public ItemStack removeItem(Item item, int count) {
|
||||
ItemStack removed = this.inventory.remove(item, count);
|
||||
|
||||
// remove equipped item if equipped stack was removed
|
||||
if (this.equipped == removed && count == this.equipped.size) {
|
||||
this.equipped = null;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDirectionChange() {
|
||||
this.actionTicks = 0;
|
||||
this.useItemTicks = 0;
|
||||
this.hitTicks = 0;
|
||||
}
|
||||
|
||||
public int getHitDamage(Entity e) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean canPickup(EntityItem e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void pickup(ItemStack stack) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hit(Entity e) {
|
||||
if (!this.swimming && e instanceof EntityMob && this.takeApproxStamina(2)) {
|
||||
EntityMob mob = (EntityMob) e;
|
||||
mob.hurt(Math.max(this.getHitDamage(e), 1), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return e instanceof EntityFurniture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
super.collide(e);
|
||||
|
||||
if (!e.metadata.remove && e instanceof EntityItem &&
|
||||
((EntityItem) e).canPickup(this) &&
|
||||
this.canPickup(((EntityItem) e))) {
|
||||
EntityItem item = ((EntityItem) e);
|
||||
if (this.inventory.add(item.stack)) {
|
||||
this.pickup(item.stack);
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Entity e) {
|
||||
return !(e instanceof EntityMob && this.swimming);
|
||||
}
|
||||
|
||||
protected void animateHit(Item used, int x, int y) {
|
||||
this.useItem = used;
|
||||
this.useItemTicks = USE_ITEM_TICKS;
|
||||
this.hitTicks = HIT_TICKS;
|
||||
this.hitX = Level.toPixel(x);
|
||||
this.hitY = Level.toPixel(y);
|
||||
}
|
||||
|
||||
protected void animateAction() {
|
||||
this.actionTicks = ACTION_TICKS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
// used item
|
||||
if (this.useItemTicks > 0) {
|
||||
ItemInstance instance = new ItemInstance(this.useItem, 0);
|
||||
switch (this.direction) {
|
||||
case NORTH -> this.useItem.render(
|
||||
instance, this.level,
|
||||
this.x + 2, this.y - 6);
|
||||
case SOUTH -> this.useItem.render(
|
||||
instance, this.level,
|
||||
this.x + 2, this.y + this.height);
|
||||
case EAST -> this.useItem.render(
|
||||
instance, this.level,
|
||||
this.x + this.width, this.y + 2);
|
||||
case WEST -> this.useItem.render(
|
||||
instance, this.level,
|
||||
this.x - 6, this.y + 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hitTicks > 0) {
|
||||
Renderer.render(HIT_SPRITE_X, HIT_SPRITE_Y,
|
||||
this.hitX + 0, this.hitY + 0, HIT_COLOR, Renderer.FLIP_Y);
|
||||
Renderer.render(HIT_SPRITE_X, HIT_SPRITE_Y,
|
||||
this.hitX + 8, this.hitY + 0, HIT_COLOR, Renderer.FLIP_XY);
|
||||
Renderer.render(HIT_SPRITE_X, HIT_SPRITE_Y,
|
||||
this.hitX + 0, this.hitY + 8, HIT_COLOR, Renderer.FLIP_NONE);
|
||||
Renderer.render(HIT_SPRITE_X, HIT_SPRITE_Y,
|
||||
this.hitX + 8, this.hitY + 8, HIT_COLOR, Renderer.FLIP_X);
|
||||
} else if (this.actionTicks > 0) {
|
||||
int px = this.x + this.getRenderOffsetX(), py = this.y + this.getRenderOffsetY();
|
||||
|
||||
switch (this.direction) {
|
||||
case NORTH -> {
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y,
|
||||
px, py - 4, ACTION_COLOR, Renderer.FLIP_X);
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y,
|
||||
px + 8, py - 4, ACTION_COLOR, Renderer.FLIP_NONE);
|
||||
}
|
||||
case SOUTH -> {
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y,
|
||||
px, py + this.height + 1, ACTION_COLOR, Renderer.FLIP_XY);
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y,
|
||||
px + 8, py + this.height + 1, ACTION_COLOR, Renderer.FLIP_Y);
|
||||
}
|
||||
case EAST -> {
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y + 1,
|
||||
px + this.width, py + 0, ACTION_COLOR, Renderer.FLIP_NONE);
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y + 1,
|
||||
px + this.width, py + 8, ACTION_COLOR, Renderer.FLIP_Y);
|
||||
}
|
||||
case WEST -> {
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y + 1,
|
||||
px - 4, py + 0, ACTION_COLOR, Renderer.FLIP_X);
|
||||
Renderer.render(ACTION_SPRITE_X, ACTION_SPRITE_Y + 1,
|
||||
px - 4, py + 8, ACTION_COLOR, Renderer.FLIP_XY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void heal(int amount) {
|
||||
assert (amount >= 0);
|
||||
this.health = Math.min(this.health + amount, this.getMaxHealth());
|
||||
}
|
||||
|
||||
// hurt from entity
|
||||
public boolean hurt(int amount, Entity e) {
|
||||
return this.hurt(
|
||||
amount,
|
||||
this.moving ?
|
||||
this.getDirection().opposite() :
|
||||
Direction.get(this.x - e.x, this.y - e.y)
|
||||
);
|
||||
}
|
||||
|
||||
// hurt with knockback
|
||||
public boolean hurt(int amount, Direction direction) {
|
||||
if (this.hurt(amount)) {
|
||||
this.knockback(4.0, direction);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hurt(int amount) {
|
||||
assert (amount >= 0);
|
||||
if (this.invulnerableTicks > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityTextParticle.spawn(
|
||||
this.level, this.x, this.y,
|
||||
Integer.toString(amount),
|
||||
amount == 0 ? 114 : 500);
|
||||
|
||||
this.invulnerableTicks = INVULNERABLE_TICKS;
|
||||
this.health -= amount;
|
||||
|
||||
if (this.health <= 0) {
|
||||
this.die();
|
||||
this.remove();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// amount is not exact, it's a multiplier. the true amount is random.
|
||||
public boolean takeApproxStamina(int amount) {
|
||||
return this.takeStamina(amount - 1 + Global.random.nextInt(1 + amount + (amount / 2)));
|
||||
}
|
||||
|
||||
// returns true if stamina was taken
|
||||
public boolean takeStamina(int amount) {
|
||||
if (this.stamina - amount >= 0) {
|
||||
this.stamina -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void rechargeStamina() {
|
||||
if (this.swimming) {
|
||||
return;
|
||||
}
|
||||
|
||||
double rr = this.getStaminaRechargeRate();
|
||||
if (rr >= 1.0) {
|
||||
this.stamina += (int) rr;
|
||||
} else if (Global.ticks % ((int) (1.0 / this.getStaminaRechargeRate())) == 0) {
|
||||
this.stamina++;
|
||||
}
|
||||
|
||||
this.stamina = FMath.clamp(this.stamina, 1, this.getMaxStamina());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
this.invulnerableTicks = Math.max(this.invulnerableTicks - 1, 0);
|
||||
this.hitTicks = Math.max(this.hitTicks - 1, 0);
|
||||
this.actionTicks = Math.max(this.actionTicks - 1, 0);
|
||||
this.useItemTicks = Math.max(this.useItemTicks - 1, 0);
|
||||
|
||||
this.staminaRechargeDelayTicks = Math.max(this.staminaRechargeDelayTicks - 1, 0);
|
||||
|
||||
if (this.staminaRechargeDelayTicks > 0) {
|
||||
this.staminaRechargeDelayTicks--;
|
||||
|
||||
if (this.staminaRechargeDelayTicks == 0) {
|
||||
this.rechargeStamina();
|
||||
}
|
||||
} else if (this.stamina <= 0) {
|
||||
this.staminaRechargeDelayTicks = STAMINA_RECHARGE_DELAY_TICKS;
|
||||
this.stamina = 0;
|
||||
} else if (this.stamina != this.getMaxStamina()) {
|
||||
this.rechargeStamina();
|
||||
}
|
||||
}
|
||||
|
||||
public void die() {
|
||||
|
||||
}
|
||||
|
||||
// per tick
|
||||
public abstract double getStaminaRechargeRate();
|
||||
|
||||
public abstract int getMaxStamina();
|
||||
|
||||
public abstract int getMaxHealth();
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.jdh.microcraft.entity.mob;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.ai.AISkeleton;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmashParticle;
|
||||
import com.jdh.microcraft.entity.projectile.EntityArrow;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
|
||||
public class EntitySkeleton extends EntityHumanoid {
|
||||
private static final Item[] LOOT_TABLE = {
|
||||
Item.GEM, Item.GOLD_INGOT,
|
||||
Item.COAL, Item.COAL, Item.IRON_INGOT, Item.IRON_INGOT,
|
||||
Item.COAL, Item.COAL, Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE,
|
||||
Item.GLASS, Item.GLASS, Item.GLASS, Item.PIE, Item.IRON_ORE,
|
||||
Item.ROCK, Item.ROCK, Item.ROCK, Item.ROCK, Item.SAND, Item.SAND, Item.SAND
|
||||
};
|
||||
|
||||
private long lastShotTicks;
|
||||
public final double strength;
|
||||
|
||||
public EntitySkeleton(Level level, int x, int y, double strength) {
|
||||
super(level, new Inventory(4));
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.strength = strength * Global.game.difficulty;
|
||||
this.ai = new AISkeleton(this);
|
||||
this.health = this.getMaxHealth();
|
||||
this.stamina = this.getMaxStamina();
|
||||
}
|
||||
|
||||
public static EntitySkeleton createSkeleton(Level level) {
|
||||
EntitySkeleton skeleton = new EntitySkeleton(level, 0, 0, 1.0);
|
||||
EntityHumanoid.giveRandomEquipment(skeleton, 1, true, false);
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
private boolean canShoot() {
|
||||
return (Global.ticks - this.lastShotTicks) >= Math.max(180 - (30 * this.strength), 80);
|
||||
}
|
||||
|
||||
public void shoot(int dx, int dy) {
|
||||
if (Tile.TILES[this.level.getTile(this.getFacingTileX(), this.getFacingTileY())].isSolid()) {
|
||||
// only shoot if facing tile is empty
|
||||
return;
|
||||
} else if (!this.canShoot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateAnimationFrame(true);
|
||||
this.lastShotTicks = Global.ticks;
|
||||
this.level.addEntity(new EntityArrow(
|
||||
this.level, this,
|
||||
this.getCenterX(), this.getCenterY(),
|
||||
dx, dy,
|
||||
2.0,
|
||||
(int) (1 * this.strength + Global.random.nextInt((int) (2 * this.strength)))
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getAnimationFrameTicks() {
|
||||
return Math.max(12 - ((int) (2.0 / this.strength)), 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
EntitySmashParticle.spawn(this.level, this.x, this.y, this.getColor(), 4, 8);
|
||||
|
||||
for (int i = Global.random.nextInt(3); i > 0; i--) {
|
||||
EntityItem.spawn(
|
||||
this.level,
|
||||
new ItemStack(new ItemInstance(Item.BONE)),
|
||||
this.x, this.y
|
||||
);
|
||||
}
|
||||
|
||||
if (Global.random.nextBoolean()) {
|
||||
EntityItem.spawn(
|
||||
this.level,
|
||||
new ItemStack(new ItemInstance(LOOT_TABLE[Global.random.nextInt(LOOT_TABLE.length)], 0), 1),
|
||||
this.x, this.y
|
||||
);
|
||||
}
|
||||
|
||||
Global.game.score += 25 * this.strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHitDamage(Entity e) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
super.collide(e);
|
||||
|
||||
if (e instanceof EntityPlayer) {
|
||||
this.hit(e);
|
||||
e.onHit(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(331, 555, 555, 554);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHurtColor() {
|
||||
return Color.get(444, 555, 555, 554);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStaminaRechargeRate() {
|
||||
return 0.2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStamina() {
|
||||
return (int) (this.strength * 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return (int) (this.strength * 10);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.jdh.microcraft.entity.mob;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.ai.AISlime;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmashParticle;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public class EntitySlime extends EntityMob {
|
||||
private static final int BASE_SPRITE_X = 16, BASE_SPRITE_Y = 3;
|
||||
|
||||
public boolean jumping;
|
||||
private double vx, vy, vz;
|
||||
|
||||
private final boolean jumpTrail;
|
||||
private final int color, hitColor, trailColor;
|
||||
public final double strength;
|
||||
|
||||
public EntitySlime(Level level, int x, int y, int color, int hitColor,
|
||||
boolean jumpTrail, int trailColor, double strength) {
|
||||
super(level, Inventory.NONE);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
this.hitColor = hitColor;
|
||||
this.jumpTrail = jumpTrail;
|
||||
this.trailColor = trailColor;
|
||||
this.strength = strength * Global.game.difficulty;
|
||||
this.width = 12;
|
||||
this.height = 8;
|
||||
this.health = this.getMaxHealth();
|
||||
this.stamina = this.getMaxStamina();
|
||||
this.ai = new AISlime(this);
|
||||
}
|
||||
|
||||
public static EntitySlime createGreenSlime(Level level) {
|
||||
return new EntitySlime(
|
||||
level,
|
||||
0, 0,
|
||||
Color.get(010, 020, 151, 353),
|
||||
Color.get(010, 020, 353, 454),
|
||||
false, 0,
|
||||
0.6
|
||||
);
|
||||
}
|
||||
|
||||
public static EntitySlime createBlueSlime(Level level) {
|
||||
return new EntitySlime(
|
||||
level,
|
||||
0, 0,
|
||||
Color.get(001, 002, 114, 225),
|
||||
Color.get(001, 002, 335, 445),
|
||||
false, 0,
|
||||
1.0
|
||||
);
|
||||
}
|
||||
|
||||
public static EntitySlime createRedSlime(Level level) {
|
||||
return new EntitySlime(
|
||||
level,
|
||||
0, 0,
|
||||
Color.get(100, 200, 411, 522),
|
||||
Color.get(100, 200, 533, 544),
|
||||
true, Color.get(330, 440, 550, 551),
|
||||
1.15
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHitDamage(Entity e) {
|
||||
return (int) (this.strength + Global.random.nextInt((int) (4 * this.strength)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
super.collide(e);
|
||||
|
||||
if (e instanceof EntityPlayer) {
|
||||
this.hit(e);
|
||||
e.onHit(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
EntitySmashParticle.spawn(this.level, this.x, this.y, this.color, 4, 10);
|
||||
|
||||
for (int i = 1 + Global.random.nextInt(1 + (2 * (int) this.strength)); i > 0; i--) {
|
||||
EntityItem.spawn(
|
||||
this.level,
|
||||
new ItemStack(new ItemInstance(Item.SLIME, 0), 1),
|
||||
this.x, this.y
|
||||
);
|
||||
}
|
||||
|
||||
Global.game.score += 20 * this.strength;
|
||||
}
|
||||
|
||||
public void jump(double dx, double dy, double v) {
|
||||
double l = FMath.norm(dx, dy);
|
||||
this.jumping = true;
|
||||
this.vx = 5.0 * (dx / l) * v;
|
||||
this.vy = 5.0 * (dy / l) * v;
|
||||
this.vz = 5.0 * v;
|
||||
}
|
||||
|
||||
public void jump(Direction d, double v) {
|
||||
this.jump(
|
||||
d.x + (d == Direction.NORTH || d == Direction.SOUTH ? 0.1 : 0.0),
|
||||
d.y + (d == Direction.EAST || d == Direction.WEST ? 0.3 : 0.0),
|
||||
v
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.jumping && this.jumpTrail && Global.random.nextInt(6) == 0) {
|
||||
EntitySmashParticle.spawn(this.level, this.x, this.y, this.trailColor, 2, 4);
|
||||
}
|
||||
|
||||
if (this.vz > 0.0) {
|
||||
this.vx *= 0.97;
|
||||
this.vy *= 0.97;
|
||||
this.vz -= 0.11;
|
||||
} else if (this.vz <= 0.0) {
|
||||
this.jumping = false;
|
||||
this.vz = 0.0;
|
||||
this.vx *= 0.6;
|
||||
this.vy *= 0.6;
|
||||
}
|
||||
|
||||
if (Math.abs(this.vx) < 0.001) {
|
||||
this.vx = 0.0;
|
||||
}
|
||||
|
||||
if (Math.abs(this.vy) < 0.001) {
|
||||
this.vy = 0.0;
|
||||
}
|
||||
|
||||
this.move(
|
||||
FMath.tickedDoubleToInt(Global.ticks, this.vx),
|
||||
FMath.tickedDoubleToInt(Global.ticks, this.vy)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderOffsetX() {
|
||||
return -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderOffsetY() {
|
||||
return -8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
Global.random.setSeed(this.id);
|
||||
int color = this.invulnerableTicks > 0 && ((Global.ticks / 4) % 2) == 0 ? this.hitColor : this.color;
|
||||
boolean sprite = this.jumping || ((Global.ticks + this.id) / 30) % 2 == 0;
|
||||
int sx = sprite ? BASE_SPRITE_X + 2 : BASE_SPRITE_X, sy = BASE_SPRITE_Y;
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (int j = 0; j <= 1; j++) {
|
||||
Renderer.render(
|
||||
sx + i, sy + j,
|
||||
this.x + this.getRenderOffsetX() + (i * 8),
|
||||
this.y + this.getRenderOffsetY() + (j * 8),
|
||||
color, Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStaminaRechargeRate() {
|
||||
return 0.2 * this.strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStamina() {
|
||||
return (int) (10 * this.strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return (int) (10 * this.strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSwimIn(Tile tile, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.jdh.microcraft.entity.mob;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.ai.AIZombie;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmashParticle;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.armor.ItemArmor;
|
||||
import com.jdh.microcraft.item.tool.ItemTool;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityZombie extends EntityHumanoid {
|
||||
private static final Item[] LOOT_TABLE = {
|
||||
Item.GEM, Item.GOLD_INGOT, Item.MITHRIL_INGOT,
|
||||
Item.IRON_INGOT, Item.IRON_INGOT, Item.IRON_INGOT, Item.IRON_INGOT,
|
||||
Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE,
|
||||
Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE, Item.IRON_ORE,
|
||||
Item.ROCK, Item.ROCK, Item.ROCK, Item.ROCK, Item.ROCK, Item.ROCK, Item.ROCK
|
||||
};
|
||||
|
||||
private final int pantsColor, shirtColor;
|
||||
public final double strength;
|
||||
|
||||
public EntityZombie(Level level, int x, int y, double strength) {
|
||||
super(level, new Inventory(5));
|
||||
this.strength = strength * Global.game.difficulty;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.pantsColor = Color.randomRGB(1, 5);
|
||||
this.shirtColor = Color.randomRGB(1, 5);
|
||||
this.ai = new AIZombie(this);
|
||||
this.health = this.getMaxHealth();
|
||||
this.stamina = this.getMaxStamina();
|
||||
}
|
||||
|
||||
public static EntityZombie createEasyZombie(Level level) {
|
||||
EntityZombie zombie = new EntityZombie(
|
||||
level, 0, 0, 0.9
|
||||
);
|
||||
EntityHumanoid.giveRandomEquipment(zombie, 1, true, true);
|
||||
return zombie;
|
||||
}
|
||||
|
||||
public static EntityZombie createMediumZombie(Level level) {
|
||||
EntityZombie zombie = new EntityZombie(
|
||||
level, 0, 0, 1.0
|
||||
);
|
||||
EntityHumanoid.giveRandomEquipment(zombie, 2, true, true);
|
||||
return zombie;
|
||||
}
|
||||
|
||||
|
||||
public static EntityZombie createHardZombie(Level level) {
|
||||
EntityZombie zombie = new EntityZombie(
|
||||
level, 0, 0, 1.15
|
||||
);
|
||||
EntityHumanoid.giveRandomEquipment(zombie, 3, true, true);
|
||||
return zombie;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getAnimationFrameTicks() {
|
||||
return Math.max(10 - ((int) (2.0 / this.strength)), 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
EntitySmashParticle.spawn(this.level, this.x, this.y, this.getColor(), 4, 8);
|
||||
|
||||
if (Global.random.nextBoolean()) {
|
||||
EntityItem.spawn(
|
||||
this.level,
|
||||
new ItemStack(new ItemInstance(LOOT_TABLE[Global.random.nextInt(LOOT_TABLE.length)], 0), 1),
|
||||
this.x, this.y
|
||||
);
|
||||
}
|
||||
|
||||
Global.game.score += 30 * this.strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHitDamage(Entity e) {
|
||||
return (int) (super.getHitDamage(e) * this.strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
super.collide(e);
|
||||
|
||||
if (e instanceof EntityPlayer) {
|
||||
this.hit(e);
|
||||
e.onHit(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPickup(EntityItem e) {
|
||||
return (e.stack.instance.item instanceof ItemTool && this.equipped == null) ||
|
||||
(e.stack.instance.item instanceof ItemArmor &&
|
||||
this.armor[((ItemArmor) e.stack.instance.item).slot] == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pickup(ItemStack stack) {
|
||||
super.pickup(stack);
|
||||
if (stack.instance.item instanceof ItemTool && this.equipped == null) {
|
||||
this.equipped = stack;
|
||||
} else if (stack.instance.item instanceof ItemArmor) {
|
||||
ItemArmor armor = (ItemArmor) stack.instance.item;
|
||||
if (this.armor[armor.slot] == null) {
|
||||
this.armor[armor.slot] = stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(000, this.pantsColor, this.shirtColor, 141);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHurtColor() {
|
||||
return Color.get(544, Color.add(this.pantsColor, 222), Color.add(this.shirtColor, 222), 555);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStaminaRechargeRate() {
|
||||
return 0.15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStamina() {
|
||||
return (int) (10 * this.strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHealth() {
|
||||
return (int) (10 * this.strength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.jdh.microcraft.entity.particle;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
|
||||
public class EntityParticle extends Entity {
|
||||
protected int timeToLive;
|
||||
protected double vx, vy, dx, dy;
|
||||
protected boolean gravity;
|
||||
|
||||
public EntityParticle(Level level, int x, int y) {
|
||||
super(level);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = 2;
|
||||
this.height = 2;
|
||||
this.timeToLive = 45 + Global.random.nextInt(60);
|
||||
this.vx = (Global.random.nextBoolean() ? -1.0 : 1.0) * (0.2 + (Global.random.nextDouble() * 0.4));
|
||||
this.vy = -(0.8 + (Global.random.nextDouble() * 0.5));
|
||||
this.gravity = true;
|
||||
}
|
||||
|
||||
protected int getRenderX() {
|
||||
return (int) (this.x + this.dx);
|
||||
}
|
||||
|
||||
protected int getRenderY() {
|
||||
return (int) (this.y + this.dy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (--this.timeToLive == 0) {
|
||||
this.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
this.dx += this.vx;
|
||||
this.dy += this.vy;
|
||||
|
||||
if (this.gravity && this.dy >= 8.0) {
|
||||
// bounce at bottom
|
||||
this.vx *= 0.3;
|
||||
this.vy *= (this.vy > 0 ? -1.0 : 1.0) * 0.4;
|
||||
} else if (Math.abs(this.vy) < 0.01) {
|
||||
// clamp small values
|
||||
this.vx = 0.0;
|
||||
this.vy = 0.0;
|
||||
} else if (this.gravity) {
|
||||
// gravity
|
||||
this.vy += 0.1;
|
||||
}
|
||||
|
||||
if (Math.abs(this.vx) < 0.01) {
|
||||
this.vx = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Entity e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSwimIn(Tile tile, int x, int y) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.jdh.microcraft.entity.particle;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntitySmashParticle extends EntityParticle {
|
||||
private static final int SPRITE_X = 12, SPRITE_Y = 2;
|
||||
|
||||
private final int color;
|
||||
|
||||
public EntitySmashParticle(Level level, int x, int y, int color) {
|
||||
super(level, x, y);
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static void spawn(Level level, int x, int y, int color, int min, int max) {
|
||||
int n = min + Global.random.nextInt(max - min + 1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
level.addEntity(new EntitySmashParticle(level, x, y, color));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Global.random.setSeed(this.id);
|
||||
Renderer.render(
|
||||
SPRITE_X, SPRITE_Y, this.getRenderX(), this.getRenderY(), color,
|
||||
(Global.random.nextBoolean() ? Renderer.FLIP_X : Renderer.FLIP_NONE) |
|
||||
(Global.random.nextBoolean() ? Renderer.FLIP_Y : Renderer.FLIP_NONE)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.jdh.microcraft.entity.particle;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntitySmokeParticle extends EntityParticle {
|
||||
private static final int SPRITE_X = 12, SPRITE_Y = 2;
|
||||
|
||||
private final int color;
|
||||
|
||||
public EntitySmokeParticle(Level level, int x, int y, int color) {
|
||||
super(level, x, y);
|
||||
this.color = color;
|
||||
this.gravity = false;
|
||||
this.vx = (Global.random.nextBoolean() ? -1.0 : 1.0) * (0.1 + (Global.random.nextDouble() * 0.1));
|
||||
this.vy = -(0.4 + (Global.random.nextDouble() * 0.3));
|
||||
}
|
||||
|
||||
public static void spawn(Level level, int x, int y, int color, int min, int max) {
|
||||
int n = min + Global.random.nextInt(max - min + 1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
level.addEntity(new EntitySmokeParticle(level, x, y, color));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Global.random.setSeed(this.id);
|
||||
Renderer.render(
|
||||
SPRITE_X, SPRITE_Y, this.getRenderX(), this.getRenderY(), color,
|
||||
(Global.random.nextBoolean() ? Renderer.FLIP_X : Renderer.FLIP_NONE) |
|
||||
(Global.random.nextBoolean() ? Renderer.FLIP_Y : Renderer.FLIP_NONE)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.jdh.microcraft.entity.particle;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityTextParticle extends EntityParticle {
|
||||
private final String text;
|
||||
private final int color;
|
||||
|
||||
public EntityTextParticle(Level level, int x, int y, String text, int color) {
|
||||
super(level, x, y);
|
||||
this.text = text;
|
||||
this.color = color;
|
||||
this.timeToLive = 30 + Global.random.nextInt(30);
|
||||
}
|
||||
|
||||
public static void spawn(Level level, int x, int y, String text, int color) {
|
||||
level.addEntity(new EntityTextParticle(level, x, y, text, color));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Global.random.setSeed(this.id);
|
||||
Font.render(this.text, this.getRenderX() + 1, this.getRenderY() + 1, Color.add(this.color, -222));
|
||||
Font.render(this.text, this.getRenderX(), this.getRenderY(), this.color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.jdh.microcraft.entity.projectile;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityAirBlast extends EntityProjectile {
|
||||
public EntityAirBlast(Level level, Entity shooter, int x, int y, int dx, int dy, double s, int damage) {
|
||||
super(level, shooter, x, y, dx, dy, s, damage, 180);
|
||||
this.width = 4;
|
||||
this.height = 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hit(Entity e) {
|
||||
if (e instanceof EntityItem) {
|
||||
e.remove();
|
||||
return true;
|
||||
} else if (!(e instanceof EntityMob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
((EntityMob) e).hurt(this.damage, this);
|
||||
this.remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean moveAxis(int dx, int dy) {
|
||||
if (!super.moveAxis(dx, dy)) {
|
||||
this.remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(222, 333, 445, 555);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHorizontalSpriteX() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHorizontalSpriteY() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVerticalSpriteX() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVerticalSpriteY() {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.jdh.microcraft.entity.projectile;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
public class EntityArrow extends EntityProjectile {
|
||||
public EntityArrow(Level level, Entity shooter, int x, int y, int dx, int dy, double s, int damage) {
|
||||
super(level, shooter, x, y, dx, dy, s, damage, 180);
|
||||
this.width = 4;
|
||||
this.height = 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hit(Entity e) {
|
||||
if (e instanceof EntityItem) {
|
||||
e.remove();
|
||||
return true;
|
||||
} else if (!(e instanceof EntityMob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
((EntityMob) e).hurt(this.damage, this);
|
||||
this.remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(220, 330, 333, 444);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHorizontalSpriteX() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHorizontalSpriteY() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVerticalSpriteX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVerticalSpriteY() {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.jdh.microcraft.entity.projectile;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.EntityItem;
|
||||
import com.jdh.microcraft.entity.furniture.EntityFurnace;
|
||||
import com.jdh.microcraft.entity.furniture.EntityFurniture;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
import com.jdh.microcraft.util.Direction;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public abstract class EntityProjectile extends Entity {
|
||||
protected final int damage;
|
||||
protected final Entity shooter;
|
||||
private int timeToLive;
|
||||
private double vx, vy;
|
||||
|
||||
public EntityProjectile(Level level, Entity shooter, int x, int y, int dx, int dy, double s, int damage, int ttl) {
|
||||
super(level);
|
||||
this.shooter = shooter;
|
||||
this.damage = damage;
|
||||
this.timeToLive = ttl;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
// compute velocities in direction of dx, dy
|
||||
double xx = FMath.sign(dx - this.x),
|
||||
yy = FMath.sign(dy - this.y),
|
||||
l = FMath.norm(xx, yy);
|
||||
|
||||
xx = (xx / l) * s;
|
||||
yy = (yy / l) * s;
|
||||
this.vx = Double.isNaN(xx) ? 0 : xx;
|
||||
this.vy = Double.isNaN(yy) ? 0 : yy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
this.move(
|
||||
FMath.tickedDoubleToInt(Global.ticks, this.vx),
|
||||
FMath.tickedDoubleToInt(Global.ticks, this.vy)
|
||||
);
|
||||
|
||||
if (--this.timeToLive == 0) {
|
||||
this.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
int sx = 0, sy = 0, flip = 0;
|
||||
|
||||
switch (this.direction) {
|
||||
case NORTH, SOUTH -> {
|
||||
sx = this.getVerticalSpriteX();
|
||||
sy = this.getVerticalSpriteY();
|
||||
flip = this.direction == Direction.SOUTH ? Renderer.FLIP_Y : 0;
|
||||
}
|
||||
case EAST, WEST -> {
|
||||
sx = this.getHorizontalSpriteX();
|
||||
sy = this.getHorizontalSpriteY();
|
||||
flip = this.direction == Direction.WEST ? Renderer.FLIP_X : 0;
|
||||
}
|
||||
}
|
||||
|
||||
Renderer.render(
|
||||
sx, sy,
|
||||
this.x + this.getRenderOffsetX(), this.y + this.getRenderOffsetY(),
|
||||
this.getColor(), flip
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Entity e) {
|
||||
return e != this.shooter &&
|
||||
!(e instanceof EntityProjectile) &&
|
||||
(Math.abs(this.vx) > 0.0 || Math.abs(this.vy) > 0.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collide(Entity e) {
|
||||
super.collide(e);
|
||||
|
||||
if (this.hit(e)) {
|
||||
e.onHit(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean moveAxis(int dx, int dy) {
|
||||
if (!super.moveAxis(dx, dy)) {
|
||||
this.vx = 0.0;
|
||||
this.vy = 0.0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSwimIn(Tile tile, int x, int y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract boolean hit(Entity e);
|
||||
|
||||
public abstract int getColor();
|
||||
|
||||
protected abstract int getHorizontalSpriteX();
|
||||
|
||||
protected abstract int getHorizontalSpriteY();
|
||||
|
||||
protected abstract int getVerticalSpriteX();
|
||||
|
||||
protected abstract int getVerticalSpriteY();
|
||||
}
|
||||
13
Java/Microcraft/src/com/jdh/microcraft/gfx/Camera.java
Normal file
13
Java/Microcraft/src/com/jdh/microcraft/gfx/Camera.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public class Camera {
|
||||
// translation
|
||||
public int tx = 0, ty = 0;
|
||||
|
||||
public void centerOn(int x, int y, int minX, int minY, int maxX, int maxY) {
|
||||
this.tx = FMath.clamp(x - (Renderer.WIDTH / 2), minX, maxX - Renderer.WIDTH);
|
||||
this.ty = FMath.clamp(y - (Renderer.HEIGHT / 2), minY, maxY - Renderer.HEIGHT);
|
||||
}
|
||||
}
|
||||
87
Java/Microcraft/src/com/jdh/microcraft/gfx/Color.java
Normal file
87
Java/Microcraft/src/com/jdh/microcraft/gfx/Color.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public class Color {
|
||||
// get(a, b, c, d) but with array elements
|
||||
public static int get(int[] abcd) {
|
||||
return Color.get(abcd[0], abcd[1], abcd[2], abcd[3]);
|
||||
}
|
||||
|
||||
// gets color palette integer of specified 4 colors in format RGB where each component is one (base 10) digit
|
||||
public static int get(int a, int b, int c, int d) {
|
||||
return ((Color.map(d) & 0xFF) << 24) |
|
||||
((Color.map(c) & 0xFF) << 16) |
|
||||
((Color.map(b) & 0xFF) << 8) |
|
||||
(Color.map(a) & 0xFF);
|
||||
}
|
||||
|
||||
// replaces color c component i with RGB triple x
|
||||
public static int withComponent(int c, int x, int i) {
|
||||
return (c & ~(0xFF << (i * 8))) | ((Color.map(x) & 0xFF) << (i * 8));
|
||||
}
|
||||
|
||||
// gets a single component of a color as a triple
|
||||
public static int component(int c, int i) {
|
||||
return Color.iToRGB((c >> (i * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
// palette index to rgb triple
|
||||
public static int iToRGB(int i) {
|
||||
int r = i / 36,
|
||||
g = ((i - (r * 36)) / 6),
|
||||
b = ((i - (r * 36)) % 6);
|
||||
return (r * 100) + (g * 10) + b;
|
||||
}
|
||||
|
||||
// maps RGB (where R, G, B are base 10 digits in [0..5]) to palette index
|
||||
public static int map(int d) {
|
||||
if (d < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((d / 100) % 10) * 36 + ((d / 10) % 10) * 6 + (d % 10);
|
||||
}
|
||||
|
||||
// adds and clamps a single RGB triple
|
||||
public static int add(int c, int v) {
|
||||
return FMath.clamp(((c / 100) % 10) + ((v / 100) % 10), 0, 5) * 100 +
|
||||
FMath.clamp(((c / 10) % 10) + ((v / 10) % 10), 0, 5) * 10 +
|
||||
FMath.clamp((c % 10) + (v % 10), 0, 5);
|
||||
}
|
||||
|
||||
// multiplies and clamps a single RGB triple
|
||||
public static int mul(int c, int v) {
|
||||
return FMath.clamp(((c / 100) % 10) * ((v / 100) % 10), 0, 5) * 100 +
|
||||
FMath.clamp(((c / 10) % 10) * ((v / 10) % 10), 0, 5) * 10 +
|
||||
FMath.clamp((c % 10) * (v % 10), 0, 5);
|
||||
}
|
||||
|
||||
// adds and clamps all RGB triples in a color
|
||||
public static int addAll(int c, int v) {
|
||||
return get(
|
||||
add(component(c, 0), v),
|
||||
add(component(c, 1), v),
|
||||
add(component(c, 2), v),
|
||||
add(component(c, 3), v)
|
||||
);
|
||||
}
|
||||
|
||||
public static int randomRGB(int min, int max) {
|
||||
return
|
||||
(Global.random.nextInt(max - min + 1)) * 100 +
|
||||
(Global.random.nextInt(max - min + 1)) * 10 +
|
||||
(Global.random.nextInt(max - min + 1));
|
||||
}
|
||||
|
||||
// gets r, g, or b from an RGB triple
|
||||
public static int getRGBComponent(int rgb, int i) {
|
||||
return (rgb / ((int) Math.pow(10, i))) % 10;
|
||||
}
|
||||
|
||||
// gets RGB triple from R, G, B components in 0..5 range
|
||||
public static int getRGB(int r, int g, int b) {
|
||||
return (r * 100) + (g * 10) + b;
|
||||
}
|
||||
}
|
||||
125
Java/Microcraft/src/com/jdh/microcraft/gfx/Font.java
Normal file
125
Java/Microcraft/src/com/jdh/microcraft/gfx/Font.java
Normal file
@@ -0,0 +1,125 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Font {
|
||||
public enum Colors {
|
||||
RED('R', 500),
|
||||
ORANGE('O', 441),
|
||||
YELLOW('Y', 550),
|
||||
GREEN('G', 050),
|
||||
BLUE('B', 005),
|
||||
PURPLE('P', 404),
|
||||
PINK('I', 533),
|
||||
WHITE('W', 555),
|
||||
GREY('E', 333),
|
||||
BLACK('L', 000),
|
||||
DARK_GREY('D', 111);
|
||||
|
||||
public final char c;
|
||||
public final int color;
|
||||
|
||||
Colors(char c, int color) {
|
||||
this.c = c;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "$" + this.c;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int BASE_OFFSET_X = 0, BASE_OFFSET_Y = 13;
|
||||
private static final String[] LAYOUT = {
|
||||
"ABCDEFGHIJKLMNOP",
|
||||
"QRSTUVWXYZ!/<>:+",
|
||||
"1234567890&=().?"
|
||||
};
|
||||
|
||||
public static int width(String s) {
|
||||
int w = 0;
|
||||
|
||||
char[] chars = s.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
if (chars[i] == '$' && i != (chars.length - 1)) {
|
||||
if (chars[i + 1] != '$') {
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
w += 8;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
public static int offset(char c) {
|
||||
for (int i = 0; i < LAYOUT.length; i++) {
|
||||
int j;
|
||||
if ((j = LAYOUT[i].indexOf(c)) != -1) {
|
||||
return ((BASE_OFFSET_Y + i) * Renderer.spritesheet.sizeSprites) + (BASE_OFFSET_X + j);
|
||||
}
|
||||
}
|
||||
|
||||
// character not found -> ?
|
||||
return 15 * Renderer.spritesheet.sizeSprites + 15;
|
||||
}
|
||||
|
||||
public static void render(char c, int x, int y, int color) {
|
||||
Font.render(c, x, y, color, -1);
|
||||
}
|
||||
|
||||
public static void render(char c, int x, int y, int color, int backgroundColor) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backgroundColor != -1) {
|
||||
Renderer.fill(x, y, 8, 8, backgroundColor);
|
||||
}
|
||||
|
||||
Renderer.render(
|
||||
Font.offset(c),
|
||||
x, y,
|
||||
Color.get(color, color, color, color),
|
||||
Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
|
||||
public static void render(String s, int x, int y, int color) {
|
||||
Font.render(s, x, y, color, -1);
|
||||
}
|
||||
|
||||
// color, backgroundColor should be single RGB digit triple
|
||||
// no background if backgroundColor == -1
|
||||
public static void render(String s, int x, int y, int color, int backgroundColor) {
|
||||
int count = 0;
|
||||
int currentColor = color;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = Character.toUpperCase(s.charAt(i));
|
||||
|
||||
if (c == '$' && (i != (s.length() - 1))) {
|
||||
char n = s.charAt(i + 1);
|
||||
|
||||
if (n == '$') {
|
||||
continue;
|
||||
} else {
|
||||
Optional<Colors> cl = Arrays.stream(Colors.values()).filter(e -> e.c == n).findFirst();
|
||||
|
||||
if (cl.isEmpty()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
currentColor = cl.get().color;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
render(c, x + (count * 8), y, currentColor, backgroundColor);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Java/Microcraft/src/com/jdh/microcraft/gfx/Light.java
Normal file
11
Java/Microcraft/src/com/jdh/microcraft/gfx/Light.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
public class Light {
|
||||
public final int x, y, power;
|
||||
|
||||
public Light(int x, int y, int power) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.power = power;
|
||||
}
|
||||
}
|
||||
224
Java/Microcraft/src/com/jdh/microcraft/gfx/Renderer.java
Normal file
224
Java/Microcraft/src/com/jdh/microcraft/gfx/Renderer.java
Normal file
@@ -0,0 +1,224 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
import com.jdh.microcraft.util.AABB;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Renderer {
|
||||
public static final int[] DITHER = new int[]{0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5};
|
||||
|
||||
// renderer flags
|
||||
public static final int FLIP_NONE = 0x00, FLIP_X = 0x01, FLIP_Y = 0x02, FLIP_XY = FLIP_X | FLIP_Y;
|
||||
|
||||
// target width/height
|
||||
public static final int WIDTH = 256, HEIGHT = 144;
|
||||
|
||||
// screen pixels, each entry in [0..216) referring to palette entry
|
||||
// palette is determined by Window
|
||||
public static int[] pixels = new int[WIDTH * HEIGHT];
|
||||
|
||||
// global spritesheet
|
||||
public static Spritesheet spritesheet = new Spritesheet("/tiles.png", 8);
|
||||
|
||||
// stored camera stack
|
||||
private static Stack<Camera> cameraStack = new Stack<>();
|
||||
|
||||
// lights
|
||||
private static List<Light> lights = new ArrayList<>();
|
||||
|
||||
// current camera
|
||||
public static Camera camera = new Camera();
|
||||
|
||||
// generates color palette, 24-bpp RGB
|
||||
public static int[] generatePalette() {
|
||||
int[] result = new int[256];
|
||||
|
||||
int i = 0;
|
||||
for (int r = 0; r < 6; r++) {
|
||||
for (int g = 0; g < 6; g++) {
|
||||
for (int b = 0; b < 6; b++) {
|
||||
int rr = (r * 255) / 5,
|
||||
gg = (g * 255) / 5,
|
||||
bb = (b * 255) / 5,
|
||||
m = (rr * 30 + gg * 59 + bb * 11) / 100;
|
||||
|
||||
result[i++] = ((((rr + m) / 2) * 230 / 255 + 10) << 16) |
|
||||
((((gg + m) / 2) * 230 / 255 + 10) << 8) |
|
||||
((((bb + m) / 2) * 230 / 255 + 10) << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
Renderer.clear();
|
||||
Renderer.clearLights();
|
||||
Renderer.cameraStack.clear();
|
||||
Renderer.camera = new Camera();
|
||||
}
|
||||
|
||||
public static void pushCamera() {
|
||||
Renderer.cameraStack.push(Renderer.camera);
|
||||
Renderer.camera = new Camera();
|
||||
}
|
||||
|
||||
public static void popCamera() {
|
||||
Renderer.camera = Renderer.cameraStack.pop();
|
||||
}
|
||||
|
||||
public static void clearLights() {
|
||||
Renderer.lights.clear();
|
||||
}
|
||||
|
||||
public static void addLights(Collection<Light> lights) {
|
||||
Renderer.lights.addAll(lights);
|
||||
}
|
||||
|
||||
public static AABB getAABB() {
|
||||
return new AABB(
|
||||
Renderer.camera.tx,
|
||||
Renderer.camera.ty,
|
||||
Renderer.camera.tx + Renderer.WIDTH,
|
||||
Renderer.camera.ty + Renderer.HEIGHT
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean inBounds(int x, int y) {
|
||||
int xt = x - Renderer.camera.tx, yt = y - Renderer.camera.ty;
|
||||
return xt >= 0 && yt >= 0 && xt < Renderer.WIDTH && yt < Renderer.HEIGHT;
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
Arrays.fill(Renderer.pixels, 0);
|
||||
}
|
||||
|
||||
public static void fill(int x, int y, int w, int h, int color) {
|
||||
int xt = x - Renderer.camera.tx, yt = y - Renderer.camera.ty;
|
||||
|
||||
// check if entirely offscreen
|
||||
if (xt + w < 0 || yt + h < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int yy = yt; yy < yt + h && yy < Renderer.HEIGHT; yy++) {
|
||||
if (yy < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int xx = xt; xx < xt + w && xx < Renderer.WIDTH; xx++) {
|
||||
if (xx < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Renderer.pixels[yy * Renderer.WIDTH + xx] = Color.map(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void render(Sprite sprite, int x, int y, int color) {
|
||||
int xt = x - Renderer.camera.tx, yt = y - Renderer.camera.ty;
|
||||
|
||||
if (xt + sprite.width < 0 || yt + sprite.height < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int yy = yt, ys = 0; yy < yt + sprite.height && yy < Renderer.HEIGHT; yy++, ys++) {
|
||||
if (yy < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int xx = xt, xs = 0; xx < xt + sprite.width && xx < Renderer.WIDTH; xx++, xs++) {
|
||||
if (xx < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int p = sprite.pixels[ys * sprite.width + xs];
|
||||
if (p >= 0) {
|
||||
Renderer.pixels[yy * Renderer.WIDTH + xx] = (color >> (p * 8)) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void render(int s, int x, int y, int color, int flags) {
|
||||
Renderer.render(
|
||||
s % Renderer.spritesheet.sizeSprites,
|
||||
s / Renderer.spritesheet.sizeSprites,
|
||||
x, y, color, flags
|
||||
);
|
||||
}
|
||||
|
||||
public static void render(int sx, int sy, int x, int y, int color, int flags) {
|
||||
int posX = x - camera.tx, posY = y - camera.ty,
|
||||
minX = sx * Renderer.spritesheet.size, minY = sy * Renderer.spritesheet.size,
|
||||
maxX = minX + Renderer.spritesheet.size, maxY = minY + Renderer.spritesheet.size;
|
||||
|
||||
// sprite will not be shown at all
|
||||
if (posX + Renderer.spritesheet.size < 0 || posY + Renderer.spritesheet.size < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int ys = minY, yr = posY; ys < maxY && yr < Renderer.HEIGHT; ys++, yr++) {
|
||||
if (yr < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int xs = minX, xr = posX; xs < maxX && xr < Renderer.WIDTH; xs++, xr++) {
|
||||
if (xr < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int p = Renderer.spritesheet.pixels[
|
||||
((flags & FLIP_Y) == 0 ? ys : (Renderer.spritesheet.size - (ys - minY) - 1 + minY))
|
||||
* Renderer.spritesheet.width +
|
||||
((flags & FLIP_X) == 0 ? xs : (Renderer.spritesheet.size - (xs - minX) - 1 + minX))];
|
||||
|
||||
if (p >= 0) {
|
||||
Renderer.pixels[yr * Renderer.WIDTH + xr] = (color >> (p * 8)) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lights the current frame stored by the renderer
|
||||
public static void light(int d) {
|
||||
AABB aabb = Renderer.getAABB();
|
||||
|
||||
// compute (approx.) lights which affect this frame
|
||||
Light[] lights = Renderer.lights.stream()
|
||||
.filter(l -> {
|
||||
int p = l.power * 16;
|
||||
return AABB.collide(
|
||||
aabb.minX, aabb.minY, aabb.maxX, aabb.maxY,
|
||||
l.x - p, l.y - p, l.x + p, l.y + p
|
||||
);
|
||||
}).toArray(Light[]::new);
|
||||
|
||||
int[] oldPixels = Renderer.pixels.clone();
|
||||
Arrays.fill(Renderer.pixels, 0);
|
||||
|
||||
int tx = Renderer.camera.tx, ty = Renderer.camera.ty;
|
||||
|
||||
for (int i = 0; i < (Renderer.WIDTH * Renderer.HEIGHT); i++) {
|
||||
int x = i % Renderer.WIDTH, y = i / Renderer.WIDTH;
|
||||
|
||||
// compute contribution from each light
|
||||
for (Light l : lights) {
|
||||
int dx = l.x - (x + tx),
|
||||
dy = l.y - (y + ty),
|
||||
dist = (int) FMath.norm(dx, dy);
|
||||
|
||||
if (dist < (l.power * 4) ||
|
||||
(dist / l.power) <= DITHER[(((Math.abs(dy) % 4) * 4) + (Math.abs(dx) % 4))]) {
|
||||
Renderer.pixels[i] = d != 0 ?
|
||||
Color.map(Color.add(Color.iToRGB(oldPixels[i]), d)) :
|
||||
oldPixels[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Java/Microcraft/src/com/jdh/microcraft/gfx/Sprite.java
Normal file
37
Java/Microcraft/src/com/jdh/microcraft/gfx/Sprite.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
import com.jdh.microcraft.Main;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Sprite {
|
||||
// sprite size in pixels
|
||||
public int width, height;
|
||||
|
||||
// sprite pixels, mapped into [0..3] space
|
||||
public int[] pixels;
|
||||
|
||||
public Sprite(String path) {
|
||||
BufferedImage image;
|
||||
|
||||
try {
|
||||
image = ImageIO.read(Main.class.getResourceAsStream(path));
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
this.width = image.getWidth();
|
||||
this.height = image.getHeight();
|
||||
this.pixels = new int[this.width * this.height];
|
||||
|
||||
int[] imagePixels = image.getRGB(
|
||||
0, 0, image.getWidth(), image.getHeight(),
|
||||
null, 0, image.getWidth());
|
||||
|
||||
for (int i = 0; i < this.width * this.height; i++) {
|
||||
this.pixels[i] = ((imagePixels[i] >> 24) & 0xFF) != 0xFF ? -1 : (imagePixels[i] & 0xFF) / 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Java/Microcraft/src/com/jdh/microcraft/gfx/Spritesheet.java
Normal file
48
Java/Microcraft/src/com/jdh/microcraft/gfx/Spritesheet.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.jdh.microcraft.gfx;
|
||||
|
||||
import com.jdh.microcraft.Main;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Spritesheet {
|
||||
// spritesheet size in pixels
|
||||
public int width, height;
|
||||
|
||||
// spritesheet sprite size
|
||||
public int size;
|
||||
|
||||
// spritesheet size in sprites
|
||||
public int sizeSprites;
|
||||
|
||||
// spritesheet pixels, mapped into [0..3] space
|
||||
public int[] pixels;
|
||||
|
||||
public Spritesheet(String path, int size) {
|
||||
this.size = size;
|
||||
|
||||
BufferedImage image;
|
||||
|
||||
try {
|
||||
image = ImageIO.read(Main.class.getResourceAsStream(path));
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
this.width = image.getWidth();
|
||||
this.height = image.getHeight();
|
||||
this.pixels = new int[this.width * this.height];
|
||||
|
||||
assert(this.width == this.height);
|
||||
this.sizeSprites = this.width / this.size;
|
||||
|
||||
int[] imagePixels = image.getRGB(
|
||||
0, 0, image.getWidth(), image.getHeight(),
|
||||
null, 0, image.getWidth());
|
||||
|
||||
for (int i = 0; i < this.width * this.height; i++) {
|
||||
this.pixels[i] = ((imagePixels[i] >> 24) & 0xFF) != 0xFF ? -1 : (imagePixels[i] & 0xFF) / 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Java/Microcraft/src/com/jdh/microcraft/gui/ChestMenu.java
Normal file
106
Java/Microcraft/src/com/jdh/microcraft/gui/ChestMenu.java
Normal file
@@ -0,0 +1,106 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.furniture.EntityChest;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChestMenu extends Menu {
|
||||
private class ChestPlayerInventoryMenu extends PlayerInventoryMenu {
|
||||
public ChestPlayerInventoryMenu(EntityPlayer player) {
|
||||
super(player, false);
|
||||
this.focused = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ChestInventoryMenu extends InventoryMenu {
|
||||
public ChestInventoryMenu(EntityChest chest) {
|
||||
super(chest.inventory, false);
|
||||
this.focused = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CHEST";
|
||||
}
|
||||
}
|
||||
|
||||
private final ChestPlayerInventoryMenu playerMenu;
|
||||
private final ChestInventoryMenu chestMenu;
|
||||
private final List<Menu> submenus;
|
||||
|
||||
public ChestMenu(EntityPlayer player, EntityChest chest) {
|
||||
this.playerMenu = new ChestPlayerInventoryMenu(player);
|
||||
this.chestMenu = new ChestInventoryMenu(chest);
|
||||
this.submenus = List.of(this.playerMenu, this.chestMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
for (Menu m : this.submenus) {
|
||||
m.init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
for (Menu m : this.submenus) {
|
||||
m.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (ControlHandler.MENU_LEFT.pressedTick() && !this.playerMenu.focused) {
|
||||
this.playerMenu.focused = true;
|
||||
this.chestMenu.focused = false;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_RIGHT.pressedTick() && !this.chestMenu.focused) {
|
||||
this.playerMenu.focused = false;
|
||||
this.chestMenu.focused = true;
|
||||
}
|
||||
|
||||
boolean drop = ControlHandler.DROP.pressedTick();
|
||||
if (ControlHandler.MENU_SELECT.pressedTick() || drop) {
|
||||
InventoryMenu from = this.playerMenu.focused ? this.playerMenu : this.chestMenu,
|
||||
to = from == this.playerMenu ? this.chestMenu : this.playerMenu;
|
||||
|
||||
List<ItemStack> fromItems = from.getItems();
|
||||
if (from.selectedIndex >= 0 && from.selectedIndex < fromItems.size()) {
|
||||
ItemStack s = fromItems.get(from.selectedIndex);
|
||||
|
||||
if (s.instance.item.isDroppable()) {
|
||||
to.inventory.add(from.inventory.remove(s.instance.item, drop ? 1 : s.size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Menu m : this.submenus) {
|
||||
m.tick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
for (Menu m : this.submenus) {
|
||||
m.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
for (Menu m : this.submenus) {
|
||||
m.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
184
Java/Microcraft/src/com/jdh/microcraft/gui/ColorSelectMenu.java
Normal file
184
Java/Microcraft/src/com/jdh/microcraft/gui/ColorSelectMenu.java
Normal file
@@ -0,0 +1,184 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.mob.EntityHumanoid;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public class ColorSelectMenu extends Menu {
|
||||
private static final String[] TITLE = new String[]{
|
||||
"CHOOSE YOUR",
|
||||
Font.Colors.YELLOW + "APPEARANCE"
|
||||
};
|
||||
|
||||
private static final String[] LABELS = new String[]{
|
||||
"OUTLINE/HAIR", "PANTS", "SHIRT", "SKIN"
|
||||
};
|
||||
|
||||
private static final String[] COLOR_LABELS = new String[]{
|
||||
"R", "G", "B"
|
||||
};
|
||||
|
||||
private static final String[] INSTRUCTIONS = new String[] {
|
||||
Font.Colors.GREY + "(" + Font.Colors.YELLOW + "X" + Font.Colors.GREY + " TO DECREASE/" +
|
||||
Font.Colors.YELLOW + "C" + Font.Colors.GREY + " TO INCREASE)",
|
||||
Font.Colors.GREY + "(" + Font.Colors.YELLOW + "R" + Font.Colors.GREY + " TO RANDOMIZE" +
|
||||
Font.Colors.GREY + ")",
|
||||
"",
|
||||
Font.Colors.GREY + "PRESS " + Font.Colors.YELLOW + "ENTER"
|
||||
};
|
||||
|
||||
public int[] colors;
|
||||
private int colorIndex, rgbIndex;
|
||||
|
||||
public ColorSelectMenu() {
|
||||
this.colorIndex = 0;
|
||||
this.rgbIndex = 0;
|
||||
this.randomize();
|
||||
}
|
||||
|
||||
private void randomize() {
|
||||
this.colors = new int[]{
|
||||
Color.randomRGB(0, 2),
|
||||
Color.randomRGB(0, 5),
|
||||
Color.randomRGB(0, 5),
|
||||
Color.randomRGB(0, 5)
|
||||
};
|
||||
}
|
||||
|
||||
// updates currently selected color component by the specified change (d)
|
||||
private void updateCurrentComponent(int d) {
|
||||
int rgb = this.colors[this.colorIndex];
|
||||
int[] components = {
|
||||
Color.getRGBComponent(rgb, 0),
|
||||
Color.getRGBComponent(rgb, 1),
|
||||
Color.getRGBComponent(rgb, 2)
|
||||
};
|
||||
components[2 - this.rgbIndex] = FMath.clamp(components[2 - this.rgbIndex] + d, 0, 5);
|
||||
this.colors[this.colorIndex] = Color.getRGB(
|
||||
components[2],
|
||||
components[1],
|
||||
components[0]
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (ControlHandler.MENU_UP.pressedTick() && this.colorIndex > 0) {
|
||||
this.colorIndex--;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_DOWN.pressedTick() && this.colorIndex < (LABELS.length - 1)) {
|
||||
this.colorIndex++;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_LEFT.pressedTick() && this.rgbIndex > 0) {
|
||||
this.rgbIndex--;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_RIGHT.pressedTick() && this.rgbIndex < (COLOR_LABELS.length - 1)) {
|
||||
this.rgbIndex++;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_INCREASE.pressedTick()) {
|
||||
this.updateCurrentComponent(+1);
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_DECREASE.pressedTick()) {
|
||||
this.updateCurrentComponent(-1);
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_QUIT.pressedTick()) {
|
||||
Global.mainMenu.menu = Global.mainMenu.mainMenu;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_SELECT.pressedTick()) {
|
||||
Sound.CRAFT.play();
|
||||
Global.mainMenu.menu = Global.mainMenu.difficultySelectMenu;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_RANDOMIZE.pressedTick()) {
|
||||
this.randomize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
int y = 8;
|
||||
for (String s : TITLE) {
|
||||
Font.render(s, (Renderer.WIDTH - Font.width(s)) / 2, y, 555);
|
||||
y += 8;
|
||||
}
|
||||
|
||||
y += 8;
|
||||
|
||||
int px = (Renderer.WIDTH - 16) / 2, py = y,
|
||||
sx = EntityHumanoid.BASE_SPRITE_X, sy = EntityHumanoid.BASE_SPRITE_Y;
|
||||
|
||||
boolean flip = (Global.ticks / 15) % 2 == 0;
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (int j = 0; j <= 1; j++) {
|
||||
Renderer.render(
|
||||
sx + (flip ? (1 - i) : i), sy + j,
|
||||
px + (i * 8), py + (j * 8),
|
||||
Color.get(colors[0], colors[1], colors[2], colors[3]),
|
||||
flip ? Renderer.FLIP_X : Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
y += 24;
|
||||
|
||||
// labels/colors
|
||||
int maxWidth = 0;
|
||||
for (String label : LABELS) {
|
||||
int w = Font.width(label);
|
||||
if (w > maxWidth) {
|
||||
maxWidth = w;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int x = (Renderer.WIDTH - (maxWidth + 8 + (24 * 3) + 4 + 8)) / 2;
|
||||
|
||||
if (i == this.colorIndex) {
|
||||
Font.render(">", x - 8, y, 555);
|
||||
}
|
||||
|
||||
Font.render(LABELS[i], x, y, i == this.colorIndex ? 555 : 333);
|
||||
|
||||
x += maxWidth + 8;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
Font.render(COLOR_LABELS[j], x, y, (i == this.colorIndex && j == this.rgbIndex) ? 550 : 333);
|
||||
Renderer.fill(
|
||||
x + 12, y, 8, 8,
|
||||
Color.getRGBComponent(this.colors[i], 2 - j) * (int) Math.pow(10, 2 - j)
|
||||
);
|
||||
x += 24;
|
||||
}
|
||||
|
||||
x += 4;
|
||||
Renderer.fill(x, y, 8, 8, this.colors[i]);
|
||||
x += 8;
|
||||
|
||||
if (i == this.colorIndex) {
|
||||
Font.render("<", x, y, 555);
|
||||
}
|
||||
|
||||
y += 12;
|
||||
}
|
||||
y += 8;
|
||||
|
||||
for (String s : INSTRUCTIONS) {
|
||||
Font.render(s, (Renderer.WIDTH - Font.width(s)) / 2, y, 555);
|
||||
y += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
97
Java/Microcraft/src/com/jdh/microcraft/gui/DialogMenu.java
Normal file
97
Java/Microcraft/src/com/jdh/microcraft/gui/DialogMenu.java
Normal file
@@ -0,0 +1,97 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.util.Keyboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class DialogMenu extends Menu {
|
||||
protected final String title;
|
||||
protected final String[] lines;
|
||||
protected final int w;
|
||||
protected final int h;
|
||||
protected final Runnable onClose;
|
||||
protected final int x, y;
|
||||
|
||||
public DialogMenu(String title, String[] lines, int w, int h, Runnable onClose) {
|
||||
this.title = title;
|
||||
this.lines = lines;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.x = (Renderer.WIDTH - (this.w * 8)) / 2;
|
||||
this.y = (Renderer.HEIGHT - (this.h * 8)) / 2;
|
||||
this.onClose = onClose;
|
||||
this.focused = true;
|
||||
}
|
||||
|
||||
protected boolean shouldCenterText() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean showPressAnyKey() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean shouldAlignToMaxWidth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String[] getLines() {
|
||||
return this.lines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
this.renderMenu(title, x, y, this.w, this.h);
|
||||
|
||||
List<String> allLines = new ArrayList<>(Arrays.asList(this.getLines()));
|
||||
|
||||
if (this.showPressAnyKey()) {
|
||||
allLines.add(" ");
|
||||
allLines.add(Font.Colors.GREY + "PRESS ANY KEY");
|
||||
}
|
||||
|
||||
int maxWidth = 0;
|
||||
for (String line : this.getLines()) {
|
||||
maxWidth = Math.max(maxWidth, Font.width(line));
|
||||
}
|
||||
|
||||
for (int i = 0; i < allLines.size(); i++) {
|
||||
String s = allLines.get(i);
|
||||
|
||||
int tx;
|
||||
if (this.shouldCenterText() ||
|
||||
(this.shouldAlignToMaxWidth() && i == (allLines.size() - 1))) {
|
||||
tx = x + (((this.w * 8) - Font.width(s)) / 2);
|
||||
} else if (this.shouldAlignToMaxWidth()) {
|
||||
tx = x + (((this.w * 8) - maxWidth) / 2);
|
||||
} else {
|
||||
tx = x + 8;
|
||||
}
|
||||
|
||||
Font.render(s, tx, y + ((i + 1) * 8), 555, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.showPressAnyKey()) {
|
||||
for (Keyboard.Key k : Keyboard.keys) {
|
||||
if (k.pressedTick) {
|
||||
if (Global.game != null) {
|
||||
Global.game.setMenu(null);
|
||||
}
|
||||
this.onClose.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
public class DifficultySelectMenu extends Menu {
|
||||
private static final String[] TITLE = {
|
||||
Font.Colors.WHITE + "CHOOSE YOUR",
|
||||
Font.Colors.RED + "DIFFICULTY"
|
||||
};
|
||||
|
||||
private static final String[] INSTRUCTIONS = new String[] {
|
||||
Font.Colors.GREY + "PRESS " + Font.Colors.YELLOW + "ENTER" + Font.Colors.GREY + " TO START!"
|
||||
};
|
||||
|
||||
private static final int COUNT = 5;
|
||||
|
||||
private static final String[] DIFFICULTY_NAMES = {
|
||||
"TOO EASY",
|
||||
"EASY",
|
||||
"NORMAL",
|
||||
"KINDA HARD",
|
||||
"HARD"
|
||||
};
|
||||
|
||||
private static final double[] DIFFICULTY_VALUES = {
|
||||
0.70,
|
||||
0.85,
|
||||
1.0,
|
||||
1.15,
|
||||
1.30
|
||||
};
|
||||
|
||||
private int index;
|
||||
|
||||
public DifficultySelectMenu() {
|
||||
this.index = 2;
|
||||
}
|
||||
|
||||
public double getSelectedDifficulty() {
|
||||
return DIFFICULTY_VALUES[this.index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (ControlHandler.MENU_UP.pressedTick() && this.index > 0) {
|
||||
this.index--;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_DOWN.pressedTick() && this.index < (COUNT - 1)) {
|
||||
this.index++;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_QUIT.pressedTick()) {
|
||||
Global.mainMenu.menu = Global.mainMenu.colorSelectMenu;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_SELECT.pressedTick()) {
|
||||
Global.setState(Global.StateType.GAME);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
int y = 8;
|
||||
for (String s : TITLE) {
|
||||
Font.render(s, (Renderer.WIDTH - Font.width(s)) / 2, y, 555);
|
||||
y += 8;
|
||||
}
|
||||
|
||||
y += 32;
|
||||
|
||||
int maxWidth = 0;
|
||||
for (String s : DIFFICULTY_NAMES) {
|
||||
maxWidth = Math.max(maxWidth, Font.width(s));
|
||||
}
|
||||
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
String s = DIFFICULTY_NAMES[i];
|
||||
Font.render(
|
||||
s,
|
||||
(Renderer.WIDTH - Font.width(s)) / 2, y + (i * 8),
|
||||
i == this.index ? 555 : 333);
|
||||
}
|
||||
|
||||
Font.render(">", ((Renderer.WIDTH - maxWidth) / 2) - 8, y + (this.index * 8), 555);
|
||||
Font.render("<", (Renderer.WIDTH + maxWidth) / 2, y + (this.index * 8), 555);
|
||||
|
||||
for (String s : INSTRUCTIONS) {
|
||||
Font.render(s, (Renderer.WIDTH - Font.width(s)) / 2, Renderer.HEIGHT - 8, 555);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Java/Microcraft/src/com/jdh/microcraft/gui/FocusMenu.java
Normal file
31
Java/Microcraft/src/com/jdh/microcraft/gui/FocusMenu.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.util.Window;
|
||||
|
||||
public class FocusMenu extends DialogMenu {
|
||||
private final Menu oldMenu;
|
||||
|
||||
public FocusMenu(Menu oldMenu) {
|
||||
super("", new String[] { " ", "CLICK TO FOCUS!" }, 16, 5, () -> {});
|
||||
this.oldMenu = oldMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldCenterText() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showPressAnyKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
if (Window.hasFocus()) {
|
||||
Global.game.setMenu(this.oldMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Java/Microcraft/src/com/jdh/microcraft/gui/HUD.java
Normal file
74
Java/Microcraft/src/com/jdh/microcraft/gui/HUD.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
|
||||
public class HUD extends Menu {
|
||||
private static final int HEALTH_SPRITE_X = 10, HEALTH_SPRITE_Y = 11;
|
||||
private static final int STAMINA_SPRITE_X = 10, STAMINA_SPRITE_Y = 12;
|
||||
|
||||
private final EntityPlayer player;
|
||||
|
||||
public HUD(EntityPlayer player) {
|
||||
this.player = player;
|
||||
this.focused = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
Renderer.fill(0, Renderer.HEIGHT - 16, Renderer.WIDTH, 16, 000);
|
||||
|
||||
// health
|
||||
for (int i = 0; i < this.player.getMaxHealth(); i++) {
|
||||
boolean flashing = this.player.health <= 2 && ((Global.frames / 10) % 2) == 0;
|
||||
Renderer.render(
|
||||
HEALTH_SPRITE_X, HEALTH_SPRITE_Y,
|
||||
2 + (i * 8), Renderer.HEIGHT - 16,
|
||||
i < this.player.health ?
|
||||
(flashing ?
|
||||
Color.get(311, 511, 533, 555) :
|
||||
Color.get(100, 400, 511, 533)
|
||||
) :
|
||||
Color.get(100, 111, 222, 333),
|
||||
Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
|
||||
// stamina
|
||||
for (int i = 0; i < this.player.getMaxStamina(); i++) {
|
||||
boolean flashing = this.player.staminaRechargeDelayTicks > 0 && Global.frames % 3 == 0;
|
||||
Renderer.render(
|
||||
STAMINA_SPRITE_X, STAMINA_SPRITE_Y,
|
||||
2 + (i * 8), Renderer.HEIGHT - 8,
|
||||
i < this.player.stamina ?
|
||||
Color.get(110, 331, 441, 551) :
|
||||
(flashing ?
|
||||
Color.get(333, 444, 555, 555) :
|
||||
Color.get(110, 222, 333, 444)),
|
||||
Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
|
||||
// equipped item
|
||||
if (player.equipped != null) {
|
||||
this.player.equipped.instance.item.renderIcon(
|
||||
this.player.equipped.instance,
|
||||
Renderer.WIDTH - 100, Renderer.HEIGHT - 12
|
||||
);
|
||||
|
||||
int xx = Renderer.WIDTH - 90;
|
||||
if (player.equipped.size > 1) {
|
||||
String s = Integer.toString(player.equipped.size);
|
||||
Font.render(s, xx, Renderer.HEIGHT - 12, 444);
|
||||
xx += Font.width(s) + 8;
|
||||
}
|
||||
Font.render(
|
||||
this.player.equipped.instance.item.getName(),
|
||||
xx, Renderer.HEIGHT - 12, 555
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class InventoryMenu extends ItemSelectMenu {
|
||||
protected final Inventory inventory;
|
||||
|
||||
public InventoryMenu(Inventory inventory, boolean leftSide) {
|
||||
super(leftSide, ControlHandler.MENU_UP, ControlHandler.MENU_DOWN);
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getItems() {
|
||||
// give a sorted list of items with POW GLOVE always on top
|
||||
return inventory.stacks.stream()
|
||||
.filter(s -> s.instance.item.showInMenu())
|
||||
.sorted(Comparator
|
||||
.<ItemStack, Boolean>comparing(s -> s.instance.item.id != Item.GLOVE.id)
|
||||
.thenComparing(s -> s.instance.item.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemTextColor(int index) {
|
||||
return 555;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "INVENTORY";
|
||||
}
|
||||
}
|
||||
62
Java/Microcraft/src/com/jdh/microcraft/gui/ItemListMenu.java
Normal file
62
Java/Microcraft/src/com/jdh/microcraft/gui/ItemListMenu.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ItemListMenu extends Menu {
|
||||
public final int x, y, width, height;
|
||||
private int offset = 0;
|
||||
|
||||
public ItemListMenu(int x, int y, int width, int height) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
protected void setOffset(int offset) {
|
||||
this.offset = FMath.clamp(offset, 0,this.getItems().size());
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
List<ItemStack> items = this.getItems();
|
||||
|
||||
this.renderMenu(this.getName(), this.x, this.y, this.width, this.height);
|
||||
|
||||
// render item list
|
||||
for (int i = 0, j = offset; i < this.height - 2 && j < items.size(); i++, j++) {
|
||||
int yy = this.y + ((i + 1) * 8);
|
||||
ItemStack stack = items.get(j);
|
||||
int color = this.getItemTextColor(j);
|
||||
stack.instance.item.renderIcon(stack.instance, x + 8, yy);
|
||||
|
||||
int xx = x + 16;
|
||||
if (stack.size > 1) {
|
||||
String s = Integer.toString(stack.size);
|
||||
Font.render(s, xx, yy, Color.add(color, -111));
|
||||
xx += Font.width(s) + 8;
|
||||
}
|
||||
|
||||
Font.render(this.getItemName(j), xx, yy, color);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract List<ItemStack> getItems();
|
||||
|
||||
public abstract String getItemName(int index);
|
||||
|
||||
public abstract int getItemTextColor(int index);
|
||||
|
||||
public abstract String getName();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.util.Control;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ItemSelectMenu extends ItemListMenu {
|
||||
private static final int WIDTH = 14, HEIGHT = (Renderer.HEIGHT - 32) / 8;
|
||||
|
||||
protected final boolean leftSide;
|
||||
protected final Control up, down;
|
||||
protected int selectedIndex = 0;
|
||||
|
||||
public ItemSelectMenu(boolean leftSide, Control up, Control down) {
|
||||
super(
|
||||
leftSide ? 8 : (8 + WIDTH * 8 + 16), 8,
|
||||
14, (Renderer.HEIGHT - 32) / 8
|
||||
);
|
||||
this.leftSide = leftSide;
|
||||
this.up = up;
|
||||
this.down = down;
|
||||
}
|
||||
|
||||
protected void updateOffset() {
|
||||
if (this.selectedIndex < this.getOffset()) {
|
||||
this.setOffset(this.selectedIndex);
|
||||
}
|
||||
|
||||
if (this.selectedIndex >= this.getOffset() + (HEIGHT - 2)) {
|
||||
this.setOffset(this.selectedIndex - (HEIGHT - 2) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
List<ItemStack> items = this.getItems();
|
||||
|
||||
if (this.focused) {
|
||||
if (this.up.pressedTick() && this.selectedIndex > 0) {
|
||||
this.selectedIndex--;
|
||||
}
|
||||
|
||||
if (this.down.pressedTick() && this.selectedIndex < (items.size() - 1)) {
|
||||
this.selectedIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// clamp selection index if its gone out of bounds
|
||||
this.selectedIndex = FMath.clamp(this.selectedIndex, 0, items.size() - 1);
|
||||
this.updateOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
// render selection indicator
|
||||
if (this.selectedIndex != -1) {
|
||||
int color = this.focused ? 555 : 333;
|
||||
int yy = this.y + (((this.selectedIndex - this.getOffset()) + 1) * 8);
|
||||
Font.render(">", this.x, yy, color, Menu.MENU_BG_COLOR);
|
||||
Font.render("<", this.x + ((WIDTH - 1) * 8), yy, color, Menu.MENU_BG_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemName(int index) {
|
||||
return this.getItems().get(index).instance.item.getName();
|
||||
}
|
||||
}
|
||||
14
Java/Microcraft/src/com/jdh/microcraft/gui/LoseMenu.java
Normal file
14
Java/Microcraft/src/com/jdh/microcraft/gui/LoseMenu.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
|
||||
public class LoseMenu extends DialogMenu {
|
||||
public LoseMenu() {
|
||||
super(":(", new String[]{
|
||||
"",
|
||||
"YOU " + Font.Colors.RED + "DIED",
|
||||
"SCORE: " + Font.Colors.YELLOW + Global.game.score,
|
||||
}, 22, 8, () -> Global.setState(Global.StateType.MENU));
|
||||
}
|
||||
}
|
||||
75
Java/Microcraft/src/com/jdh/microcraft/gui/Menu.java
Normal file
75
Java/Microcraft/src/com/jdh/microcraft/gui/Menu.java
Normal file
@@ -0,0 +1,75 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
|
||||
public class Menu {
|
||||
public boolean focused = false;
|
||||
|
||||
private static final int MENU_SPRITES_X = 11, MENU_SPRITES_Y = 11;
|
||||
public static final int MENU_BG_COLOR = 115;
|
||||
|
||||
protected void renderMenu(String title, int x, int y, int wt, int ht) {
|
||||
int color = this.focused ?
|
||||
Color.get(111, 333, MENU_BG_COLOR, 444) :
|
||||
Color.get(000, 111, MENU_BG_COLOR, 222);
|
||||
|
||||
// corners
|
||||
Renderer.render(MENU_SPRITES_X, MENU_SPRITES_Y,
|
||||
x, y, color, Renderer.FLIP_NONE);
|
||||
Renderer.render(MENU_SPRITES_X, MENU_SPRITES_Y,
|
||||
x + ((wt - 1) * 8), y, color, Renderer.FLIP_X);
|
||||
Renderer.render(MENU_SPRITES_X, MENU_SPRITES_Y,
|
||||
x, y + ((ht - 1) * 8), color, Renderer.FLIP_Y);
|
||||
Renderer.render(MENU_SPRITES_X, MENU_SPRITES_Y,
|
||||
x + ((wt - 1) * 8), y + ((ht - 1) * 8), color, Renderer.FLIP_XY);
|
||||
|
||||
// vertical sides
|
||||
for (int i = 0; i < (ht - 2); i++) {
|
||||
Renderer.render(MENU_SPRITES_X, MENU_SPRITES_Y + 1,
|
||||
x, y + ((i + 1) * 8), color, Renderer.FLIP_NONE);
|
||||
Renderer.render(MENU_SPRITES_X, MENU_SPRITES_Y + 1,
|
||||
x + ((wt - 1) * 8), y + ((i + 1) * 8), color, Renderer.FLIP_X);
|
||||
}
|
||||
|
||||
// horizontal sides
|
||||
for (int i = 0; i < (wt - 2); i++) {
|
||||
Renderer.render(MENU_SPRITES_X + 1, MENU_SPRITES_Y,
|
||||
x + ((i + 1) * 8), y, color, Renderer.FLIP_NONE);
|
||||
Renderer.render(MENU_SPRITES_X + 1, MENU_SPRITES_Y,
|
||||
x + ((i + 1) * 8), y + ((ht - 1) * 8), color, Renderer.FLIP_Y);
|
||||
}
|
||||
|
||||
// center
|
||||
Renderer.fill(
|
||||
x + 8, y + 8,
|
||||
(wt - 2) * 8, (ht - 2) * 8,
|
||||
MENU_BG_COLOR
|
||||
);
|
||||
|
||||
// title
|
||||
int titleX = x + (((wt * 8) / 2) - (Font.width(title) / 2));
|
||||
Font.render(title, titleX, y, this.focused ? 551 : 331, MENU_BG_COLOR);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
||||
}
|
||||
|
||||
public void render() {
|
||||
|
||||
}
|
||||
}
|
||||
54
Java/Microcraft/src/com/jdh/microcraft/gui/PauseMenu.java
Normal file
54
Java/Microcraft/src/com/jdh/microcraft/gui/PauseMenu.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
public class PauseMenu extends DialogMenu {
|
||||
private boolean onYes;
|
||||
|
||||
public PauseMenu() {
|
||||
super("", new String[]{}, 20, 4, () -> {});
|
||||
this.onYes = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showPressAnyKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldCenterText() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getLines() {
|
||||
return new String[] {
|
||||
"EXIT TO MAIN MENU?",
|
||||
(this.onYes ? Font.Colors.YELLOW : Font.Colors.GREY) + "YES" +
|
||||
(this.onYes ? Font.Colors.GREY : Font.Colors.YELLOW) + " NO"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (ControlHandler.MENU_SELECT.pressedTick()) {
|
||||
if (this.onYes) {
|
||||
Global.setState(Global.StateType.MENU);
|
||||
} else {
|
||||
Global.game.setMenu(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_LEFT.pressedTick() && !this.onYes) {
|
||||
this.onYes = true;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_RIGHT.pressedTick() && this.onYes) {
|
||||
this.onYes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.crafting.InventoryCraftingMenu;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.armor.*;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlayerInventoryMenu extends InventoryMenu {
|
||||
private class PlayerArmorMenu extends ItemListMenu {
|
||||
public PlayerArmorMenu() {
|
||||
super(
|
||||
PlayerInventoryMenu.this.x + (PlayerInventoryMenu.this.width + 2) * 8,
|
||||
PlayerInventoryMenu.this.y,
|
||||
14, 6
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getItems() {
|
||||
return Arrays.stream(PlayerInventoryMenu.this.player.armor)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemName(int index) {
|
||||
return this.getItems().get(index).instance.item.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemTextColor(int index) {
|
||||
return 444;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ARMOR";
|
||||
}
|
||||
}
|
||||
|
||||
private final PlayerArmorMenu armorMenu;
|
||||
private final EntityPlayer player;
|
||||
private final boolean showArmor;
|
||||
|
||||
public PlayerInventoryMenu(EntityPlayer player, boolean showArmor) {
|
||||
super(player.inventory, true);
|
||||
this.player = player;
|
||||
this.showArmor = showArmor;
|
||||
this.focused = true;
|
||||
this.armorMenu = new PlayerArmorMenu();
|
||||
|
||||
List<ItemStack> items = this.getItems();
|
||||
int selected = items.indexOf(this.player.equipped);
|
||||
this.selectedIndex = selected == -1 ? 0 : selected;
|
||||
this.updateOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
List<ItemStack> items = this.getItems();
|
||||
ItemStack selectedItem = this.selectedIndex >= 0 && this.selectedIndex < items.size() ?
|
||||
items.get(this.selectedIndex) : null;
|
||||
this.player.equipped = selectedItem;
|
||||
|
||||
if (this.showArmor) {
|
||||
if (ControlHandler.MENU_EQUIP.pressedTick() &&
|
||||
selectedItem != null &&
|
||||
selectedItem.instance.item instanceof ItemArmor) {
|
||||
ItemArmor armor = (ItemArmor) selectedItem.instance.item;
|
||||
|
||||
if (this.player.armor[armor.slot] == selectedItem) {
|
||||
this.player.armor[armor.slot] = null;
|
||||
} else {
|
||||
Sound.EQUIP.play();
|
||||
this.player.armor[armor.slot] = selectedItem;
|
||||
}
|
||||
}
|
||||
|
||||
this.armorMenu.tick();
|
||||
}
|
||||
|
||||
if (ControlHandler.DROP.pressedTick() &&
|
||||
selectedItem != null &&
|
||||
selectedItem.instance.item.isDroppable()) {
|
||||
this.player.drop(selectedItem);
|
||||
}
|
||||
|
||||
if (ControlHandler.TOGGLE_CRAFTING.pressedTick()) {
|
||||
// direct inventory -> crafting transition
|
||||
Global.game.setMenu(new InventoryCraftingMenu(this.player));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
if (this.showArmor) {
|
||||
this.armorMenu.render();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if (this.showArmor) {
|
||||
this.armorMenu.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.util.FMath;
|
||||
|
||||
public class TransitionMenu extends Menu {
|
||||
private static final int TIME = 10;
|
||||
|
||||
// time to live
|
||||
private int ticks;
|
||||
|
||||
public TransitionMenu() {
|
||||
this.ticks = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (++this.ticks == TIME) {
|
||||
Global.game.setMenu(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
for (int y = 0; y < Renderer.HEIGHT / 8; y++) {
|
||||
for (int x = 0; x < Renderer.WIDTH / 8; x++) {
|
||||
int distance = (int) (
|
||||
FMath.norm(
|
||||
((double) (x * 8) - (double) (Renderer.WIDTH / 2)) / (Renderer.WIDTH / 2),
|
||||
((double) (y * 8) - (double) (Renderer.HEIGHT / 2)) / (Renderer.HEIGHT / 2)
|
||||
) * TIME);
|
||||
|
||||
if (distance > this.ticks) {
|
||||
Renderer.fill(x * 8, y * 8, 8, 8, 000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Java/Microcraft/src/com/jdh/microcraft/gui/WelcomeMenu.java
Normal file
17
Java/Microcraft/src/com/jdh/microcraft/gui/WelcomeMenu.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
|
||||
public class WelcomeMenu extends DialogMenu {
|
||||
public WelcomeMenu() {
|
||||
super("WELCOME", new String[]{
|
||||
"",
|
||||
"YOU MUST DEFEAT ",
|
||||
"THE EVIL " + Font.Colors.RED + "AIR WIZARD!",
|
||||
"",
|
||||
"ONE SHOULD GO " + Font.Colors.GREEN + "DOWN",
|
||||
"BEFORE MAKING A",
|
||||
"WAY" + Font.Colors.YELLOW + " UP",
|
||||
}, 22, 11, () -> {});
|
||||
}
|
||||
}
|
||||
25
Java/Microcraft/src/com/jdh/microcraft/gui/WinMenu.java
Normal file
25
Java/Microcraft/src/com/jdh/microcraft/gui/WinMenu.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.jdh.microcraft.gui;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
|
||||
public class WinMenu extends DialogMenu {
|
||||
private int ticks;
|
||||
|
||||
public WinMenu() {
|
||||
super("YAY!", new String[]{
|
||||
"",
|
||||
"YOU WIN! ",
|
||||
"THE EVIL " + Font.Colors.RED + "AIR WIZARD",
|
||||
"HAS BEEN " + Font.Colors.YELLOW + "BESTED.",
|
||||
"SCORE: " + Font.Colors.YELLOW + Global.game.score,
|
||||
}, 22, 10, () -> Global.setState(Global.StateType.MENU));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (++this.ticks > 120) {
|
||||
super.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.furniture.EntityAnvil;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
|
||||
public class AnvilCraftingMenu extends FurnitureCraftingMenu {
|
||||
public AnvilCraftingMenu(EntityPlayer player, EntityAnvil anvil) {
|
||||
super(player, anvil);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStation() {
|
||||
return Recipe.STATION_ANVIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ANVIL";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.furniture.EntityCraftingBench;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
|
||||
public class BenchCraftingMenu extends FurnitureCraftingMenu {
|
||||
public BenchCraftingMenu(EntityPlayer player, EntityCraftingBench bench) {
|
||||
super(player, bench);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStation() {
|
||||
return Recipe.STATION_ALL_CRAFTING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CRAFTING";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.ItemListMenu;
|
||||
import com.jdh.microcraft.gui.ItemSelectMenu;
|
||||
import com.jdh.microcraft.gui.Menu;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.Control;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class CraftingMenu extends Menu {
|
||||
private class CraftingList extends ItemSelectMenu {
|
||||
private final Control craft;
|
||||
|
||||
public CraftingList(Control up, Control down, Control craft) {
|
||||
super(true, up, down);
|
||||
this.craft = craft;
|
||||
this.focused = true;
|
||||
}
|
||||
|
||||
public Recipe getSelectedRecipe() {
|
||||
if (CraftingMenu.this.recipes.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CraftingMenu.this.recipes.get(this.selectedIndex);
|
||||
}
|
||||
|
||||
private boolean canCraft(int index) {
|
||||
return this.selectedIndex < CraftingMenu.this.recipes.size() &&
|
||||
CraftingMenu.this.recipes.get(index)
|
||||
.canMake(CraftingMenu.this.player.inventory, CraftingMenu.this.getStation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (this.craft.pressedTick() && this.canCraft(this.selectedIndex)) {
|
||||
ItemStack result = this.getSelectedRecipe().make(CraftingMenu.this.player.inventory);
|
||||
CraftingMenu.this.player.inventory.add(result);
|
||||
CraftingMenu.this.onCraft(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getItems() {
|
||||
return CraftingMenu.this.items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemTextColor(int index) {
|
||||
return this.canCraft(index) ? 555 : 333;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return CraftingMenu.this.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class HaveMenu extends ItemListMenu {
|
||||
public HaveMenu() {
|
||||
super(
|
||||
CraftingMenu.this.craftingList.x + (CraftingMenu.this.craftingList.width + 2) * 8,
|
||||
CraftingMenu.this.craftingList.y,
|
||||
10, 3
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getItems() {
|
||||
Recipe recipe = CraftingMenu.this.craftingList.getSelectedRecipe();
|
||||
return recipe == null ?
|
||||
List.of() :
|
||||
List.of(new ItemStack(recipe.result.instance, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemName(int index) {
|
||||
Recipe recipe = CraftingMenu.this.craftingList.getSelectedRecipe();
|
||||
assert (recipe != null);
|
||||
|
||||
return Integer.toString(CraftingMenu.this.player.inventory.count(recipe.result.instance.item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemTextColor(int index) {
|
||||
return 555;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HAVE";
|
||||
}
|
||||
}
|
||||
|
||||
private class CostMenu extends ItemListMenu {
|
||||
public CostMenu() {
|
||||
super(
|
||||
CraftingMenu.this.craftingList.x + (CraftingMenu.this.craftingList.width + 2) * 8,
|
||||
CraftingMenu.this.craftingList.y + (CraftingMenu.this.haveMenu.height + 1) * 8,
|
||||
10, CraftingMenu.this.craftingList.height - CraftingMenu.this.haveMenu.height - 1
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getItems() {
|
||||
Recipe recipe = CraftingMenu.this.craftingList.getSelectedRecipe();
|
||||
return recipe == null ?
|
||||
List.of() :
|
||||
recipe.ingredients.stream()
|
||||
.map(i -> new ItemStack(new ItemInstance(i.item, 0), 0))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemName(int index) {
|
||||
Recipe recipe = CraftingMenu.this.craftingList.getSelectedRecipe();
|
||||
assert (recipe != null);
|
||||
|
||||
ItemStack item = this.getItems().get(index);
|
||||
int have = CraftingMenu.this.player.inventory.count(item.instance.item),
|
||||
required = recipe.ingredients.stream()
|
||||
.filter(i -> i.item.id == item.instance.item.id)
|
||||
.findFirst().get().count;
|
||||
return required + "/" + have;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemTextColor(int index) {
|
||||
return 555;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "COST";
|
||||
}
|
||||
}
|
||||
|
||||
protected final CraftingList craftingList;
|
||||
protected final HaveMenu haveMenu;
|
||||
protected final CostMenu costMenu;
|
||||
protected final List<Menu> submenus;
|
||||
|
||||
protected final EntityPlayer player;
|
||||
protected final List<Recipe> recipes;
|
||||
protected final List<ItemStack> items;
|
||||
|
||||
public CraftingMenu(EntityPlayer player) {
|
||||
this.player = player;
|
||||
this.recipes = Item.STATION_RECIPES.get(this.getStation());
|
||||
this.items = this.recipes.stream().map(r -> r.result).collect(Collectors.toList());
|
||||
this.craftingList = new CraftingList(ControlHandler.MENU_UP, ControlHandler.MENU_DOWN, ControlHandler.MENU_SELECT);
|
||||
this.haveMenu = new HaveMenu();
|
||||
this.costMenu = new CostMenu();
|
||||
this.submenus = List.of(this.craftingList, this.haveMenu, this.costMenu);
|
||||
this.sort();
|
||||
}
|
||||
|
||||
private void sort() {
|
||||
this.recipes.sort(
|
||||
(var a, var b) -> {
|
||||
boolean ma = a.canMake(this.player.inventory, this.getStation()),
|
||||
mb = b.canMake(this.player.inventory, this.getStation());
|
||||
return ma == mb ? String.CASE_INSENSITIVE_ORDER.compare(
|
||||
a.result.instance.item.getName(),
|
||||
b.result.instance.item.getName()
|
||||
) : (ma ? -1 : 1);
|
||||
}
|
||||
);
|
||||
|
||||
this.items.clear();
|
||||
for (Recipe r : this.recipes) {
|
||||
this.items.add(r.result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
for (Menu m : submenus) {
|
||||
m.init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
for (Menu m : submenus) {
|
||||
m.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
this.sort();
|
||||
|
||||
for (Menu m : submenus) {
|
||||
m.tick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
for (Menu m : submenus) {
|
||||
m.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
for (Menu m : submenus) {
|
||||
m.render();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onCraft(ItemStack stack) {
|
||||
Sound.CRAFT.play();
|
||||
}
|
||||
|
||||
public abstract int getStation();
|
||||
|
||||
public abstract String getName();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.furniture.EntityFurnace;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmokeParticle;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
|
||||
public class FurnaceMenu extends FurnitureCraftingMenu {
|
||||
public FurnaceMenu(EntityPlayer player, EntityFurnace furnace) {
|
||||
super(player, furnace);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCraft(ItemStack stack) {
|
||||
super.onCraft(stack);
|
||||
EntitySmokeParticle.spawn(
|
||||
this.furniture.level,
|
||||
this.furniture.getCenterX(), this.furniture.getCenterY(),
|
||||
Item.COAL.getColor(),
|
||||
3, 6
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStation() {
|
||||
return Recipe.STATION_FURNACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FURNACE";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.furniture.EntityFurniture;
|
||||
|
||||
public abstract class FurnitureCraftingMenu extends CraftingMenu {
|
||||
protected final EntityFurniture furniture;
|
||||
|
||||
public FurnitureCraftingMenu(EntityPlayer player, EntityFurniture furniture) {
|
||||
super(player);
|
||||
this.furniture = furniture;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.gui.PlayerInventoryMenu;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
public class InventoryCraftingMenu extends CraftingMenu {
|
||||
public InventoryCraftingMenu(EntityPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (ControlHandler.TOGGLE_CRAFTING.pressedTick()) {
|
||||
Global.game.setMenu(null);
|
||||
}
|
||||
|
||||
if (ControlHandler.INTERACT.pressedTick()) {
|
||||
// allow direct crafting -> inventory transitions
|
||||
Global.game.setMenu(new PlayerInventoryMenu(this.player, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStation() {
|
||||
return Recipe.STATION_INVENTORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CRAFTING";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.jdh.microcraft.gui.crafting;
|
||||
|
||||
import com.jdh.microcraft.entity.EntityPlayer;
|
||||
import com.jdh.microcraft.entity.furniture.EntityOven;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmokeParticle;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
|
||||
public class OvenMenu extends FurnitureCraftingMenu {
|
||||
public OvenMenu(EntityPlayer player, EntityOven oven) {
|
||||
super(player, oven);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCraft(ItemStack stack) {
|
||||
super.onCraft(stack);
|
||||
EntitySmokeParticle.spawn(
|
||||
this.furniture.level,
|
||||
this.furniture.getCenterX(), this.furniture.getCenterY(),
|
||||
Item.COAL.getColor(),
|
||||
2, 5
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStation() {
|
||||
return Recipe.STATION_OVEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "OVEN";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.jdh.microcraft.gui.mainmenu;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gui.DialogMenu;
|
||||
|
||||
public class AboutMenu extends DialogMenu {
|
||||
public AboutMenu() {
|
||||
super(
|
||||
"ABOUT",
|
||||
new String [] {
|
||||
"",
|
||||
Font.Colors.YELLOW + "MINICRAFT " + Font.Colors.WHITE + "MADE BY " + Font.Colors.YELLOW + "NOTCH",
|
||||
"FOR " + Font.Colors.BLUE + "LUDUM DARE 22" + Font.Colors.WHITE + " IN 2011.",
|
||||
"",
|
||||
"",
|
||||
Font.Colors.GREEN + "MICROCRAFT" + Font.Colors.WHITE + " REMAKE BY " + Font.Colors.GREEN + "JDH",
|
||||
"FOR " + Font.Colors.ORANGE + "FUN" + Font.Colors.WHITE + " IN 2020.",
|
||||
"",
|
||||
Font.Colors.GREY + "GITHUB.COM/JDAH",
|
||||
Font.Colors.GREY + "YOUTUBE.COM/C/JDHVIDEO"
|
||||
},
|
||||
Renderer.WIDTH / 8, Renderer.HEIGHT / 8,
|
||||
() -> Global.mainMenu.menu = Global.mainMenu.mainMenu
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldCenterText() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.jdh.microcraft.gui.mainmenu;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gui.DialogMenu;
|
||||
|
||||
public class HowToPlayMenu extends DialogMenu {
|
||||
public HowToPlayMenu() {
|
||||
super(
|
||||
"HOW TO PLAY",
|
||||
new String [] {
|
||||
" ",
|
||||
Font.Colors.GREY + "USE THE " + Font.Colors.GREEN + "POW GLOVE " + Font.Colors.GREY + "TO HIT.",
|
||||
Font.Colors.GREY + "GEAR UP TO FIGHT THE " + Font.Colors.RED + "WIZARD" + Font.Colors.GREY + ".",
|
||||
"",
|
||||
Font.Colors.YELLOW + " WASD" + Font.Colors.WHITE + " TO MOVE",
|
||||
Font.Colors.YELLOW + "SPACE" + Font.Colors.WHITE + " TO HIT",
|
||||
Font.Colors.YELLOW + " E" + Font.Colors.WHITE + " FOR INVENTORY",
|
||||
Font.Colors.YELLOW + " E" + Font.Colors.WHITE + " TO USE",
|
||||
Font.Colors.YELLOW + "ENTER" + Font.Colors.WHITE + " TO SELECT",
|
||||
Font.Colors.YELLOW + " C" + Font.Colors.WHITE + " TO CRAFT",
|
||||
Font.Colors.YELLOW + " Z" + Font.Colors.WHITE + " TO EQUIP",
|
||||
Font.Colors.YELLOW + " Q" + Font.Colors.WHITE + " TO DROP"
|
||||
},
|
||||
Renderer.WIDTH / 8, Renderer.HEIGHT / 8,
|
||||
() -> Global.mainMenu.menu = Global.mainMenu.mainMenu
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAlignToMaxWidth() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.jdh.microcraft.gui.mainmenu;
|
||||
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gui.Menu;
|
||||
import com.jdh.microcraft.util.Window;
|
||||
|
||||
public class LoadingMenu extends Menu {
|
||||
private static final int PROGRESS_WIDTH = 128, PROGRESS_HEIGHT = 4;
|
||||
|
||||
public String text;
|
||||
public double progress;
|
||||
|
||||
public LoadingMenu() {
|
||||
this.text = "LOADING";
|
||||
this.progress = 50.0;
|
||||
}
|
||||
|
||||
public void setProgress(double progress) {
|
||||
this.setProgress(this.text, progress);
|
||||
}
|
||||
|
||||
public void setProgress(String text, double progress) {
|
||||
assert(progress >= 0.0 && progress <= 1.0);
|
||||
|
||||
this.text = text;
|
||||
this.progress = progress;
|
||||
|
||||
Renderer.clear();
|
||||
this.render();
|
||||
Window.renderFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
int y = (Renderer.HEIGHT / 2) - 8;
|
||||
Font.render(
|
||||
this.text,
|
||||
(Renderer.WIDTH - Font.width(this.text)) / 2, y,
|
||||
555
|
||||
);
|
||||
|
||||
Renderer.fill(
|
||||
(Renderer.WIDTH - PROGRESS_WIDTH) / 2, y + 12,
|
||||
PROGRESS_WIDTH, PROGRESS_HEIGHT,
|
||||
333
|
||||
);
|
||||
Renderer.fill(
|
||||
(Renderer.WIDTH - PROGRESS_WIDTH) / 2, y + 12,
|
||||
(int) (PROGRESS_WIDTH * this.progress), PROGRESS_HEIGHT,
|
||||
151
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.jdh.microcraft.gui.mainmenu;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.gfx.Font;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.gfx.Sprite;
|
||||
import com.jdh.microcraft.gui.Menu;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
import com.jdh.microcraft.util.ControlHandler;
|
||||
|
||||
public class MainMenu extends Menu {
|
||||
private static final Sprite LOGO = new Sprite("/logo.png");
|
||||
private static final int LOGO_Y = 32;
|
||||
|
||||
private static final String[] OPTIONS = {
|
||||
"START",
|
||||
"HOW TO PLAY",
|
||||
"ABOUT",
|
||||
"QUIT"
|
||||
};
|
||||
|
||||
private static final Runnable[] FUNCTIONS = {
|
||||
() -> {
|
||||
Sound.CRAFT.play();
|
||||
Global.mainMenu.menu = Global.mainMenu.colorSelectMenu;
|
||||
},
|
||||
() -> {
|
||||
Sound.CRAFT.play();
|
||||
Global.mainMenu.menu = Global.mainMenu.howToPlayMenu;
|
||||
},
|
||||
() -> {
|
||||
Sound.CRAFT.play();
|
||||
Global.mainMenu.menu = Global.mainMenu.aboutMenu;
|
||||
},
|
||||
() -> System.exit(0)
|
||||
};
|
||||
|
||||
private int index;
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
super.render();
|
||||
|
||||
Renderer.render(
|
||||
LOGO,
|
||||
(Renderer.WIDTH - LOGO.width) / 2,
|
||||
LOGO_Y,
|
||||
Color.get(112, 114, 151, 225)
|
||||
);
|
||||
|
||||
int y = LOGO_Y + LOGO.height + 16;
|
||||
for (int i = 0; i < OPTIONS.length; i++) {
|
||||
String s = OPTIONS[i];
|
||||
int color = 333;
|
||||
|
||||
if (i == this.index) {
|
||||
s = "> " + s + " <";
|
||||
color = 555;
|
||||
}
|
||||
|
||||
Font.render(
|
||||
s,
|
||||
(Renderer.WIDTH - Font.width(s)) / 2,
|
||||
y + (i * 8),
|
||||
color
|
||||
);
|
||||
}
|
||||
|
||||
Font.render(
|
||||
Font.Colors.DARK_GREY + "ORIGINALLY BY" + Font.Colors.GREY + " NOTCH",
|
||||
0, Renderer.HEIGHT - 16, 555
|
||||
);
|
||||
Font.render(
|
||||
Font.Colors.DARK_GREY + "REMAKE BY" + Font.Colors.BLUE + " JDH" +
|
||||
Font.Colors.DARK_GREY + " (github.com/jdah)",
|
||||
0, Renderer.HEIGHT - 8, 555);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (ControlHandler.MENU_UP.pressedTick() && this.index > 0) {
|
||||
this.index--;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_DOWN.pressedTick() && this.index < (OPTIONS.length - 1)) {
|
||||
this.index++;
|
||||
}
|
||||
|
||||
if (ControlHandler.MENU_SELECT.pressedTick()) {
|
||||
FUNCTIONS[this.index].run();
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Java/Microcraft/src/com/jdh/microcraft/item/Inventory.java
Normal file
79
Java/Microcraft/src/com/jdh/microcraft/item/Inventory.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package com.jdh.microcraft.item;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Inventory {
|
||||
public static final Inventory NONE = new Inventory(0);
|
||||
|
||||
public List<ItemStack> stacks;
|
||||
public int maxSize;
|
||||
|
||||
public Inventory(int maxSize) {
|
||||
this.stacks = new ArrayList<>();
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
public boolean contains(Item item, int count) {
|
||||
return this.stacks.stream().anyMatch(s -> s.instance.item.id == item.id && s.size >= count);
|
||||
}
|
||||
|
||||
public boolean contains(ItemStack stack) {
|
||||
return this.stacks.stream().anyMatch(s -> s.equals(stack));
|
||||
}
|
||||
|
||||
public ItemStack remove(Item item, int count) {
|
||||
assert(this.contains(item, count));
|
||||
for (var it = this.stacks.iterator(); it.hasNext(); ) {
|
||||
ItemStack s = it.next();
|
||||
if (s.instance.item.id == item.id) {
|
||||
assert((s.size - count) >= 0);
|
||||
if ((s.size - count) == 0) {
|
||||
it.remove();
|
||||
return s;
|
||||
} else {
|
||||
s.size -= count;
|
||||
return new ItemStack(new ItemInstance(s.instance), count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean add(ItemStack stack) {
|
||||
// attempt to stack
|
||||
for (ItemStack s : this.stacks) {
|
||||
if (s.instance.item.id == stack.instance.item.id &&
|
||||
s.instance.item.isStackable()) {
|
||||
s.size += stack.size;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// could not stack, try to add to inventory
|
||||
if (this.stacks.size() < this.maxSize) {
|
||||
this.stacks.add(stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ItemStack findById(int id) {
|
||||
return this.stacks.stream().filter(s -> s.instance.item.id == id).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public ItemStack findByInstanceId(int id) {
|
||||
return this.stacks.stream().filter(s -> s.instance.id == id).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public ItemStack find(Item item) {
|
||||
return this.stacks.stream().filter(s -> s.instance.item.id == item.id).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public int count(Item item) {
|
||||
return this.stacks.stream().filter(s -> s.instance.item.id == item.id).mapToInt(s -> s.size).sum();
|
||||
}
|
||||
}
|
||||
191
Java/Microcraft/src/com/jdh/microcraft/item/Item.java
Normal file
191
Java/Microcraft/src/com/jdh/microcraft/item/Item.java
Normal file
@@ -0,0 +1,191 @@
|
||||
package com.jdh.microcraft.item;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.armor.*;
|
||||
import com.jdh.microcraft.item.consumable.ItemApple;
|
||||
import com.jdh.microcraft.item.consumable.ItemBread;
|
||||
import com.jdh.microcraft.item.consumable.ItemCactusGoo;
|
||||
import com.jdh.microcraft.item.consumable.ItemPie;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.furniture.*;
|
||||
import com.jdh.microcraft.item.resource.*;
|
||||
import com.jdh.microcraft.item.tool.*;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class Item {
|
||||
public static final Item[] ITEMS = new Item[256];
|
||||
|
||||
public static final ItemGlove GLOVE = new ItemGlove(1);
|
||||
public static final ItemRock ROCK = new ItemRock(2);
|
||||
public static final ItemWood WOOD = new ItemWood(3);
|
||||
public static final ItemOre GOLD_ORE = new ItemOre(4, Metal.GOLD);
|
||||
public static final ItemIngot GOLD_INGOT = new ItemIngot(5, Metal.GOLD);
|
||||
public static final ItemOre IRON_ORE = new ItemOre(6, Metal.IRON);
|
||||
public static final ItemIngot IRON_INGOT = new ItemIngot(7, Metal.IRON);
|
||||
|
||||
public static final ItemSword WOOD_SWORD = new ItemSword(8, Recipe.STATION_BENCH, Material.WOOD);
|
||||
public static final ItemShovel WOOD_SHOVEL = new ItemShovel(9, Recipe.STATION_BENCH, Material.WOOD);
|
||||
public static final ItemPickaxe WOOD_PICKAXE = new ItemPickaxe(10, Recipe.STATION_BENCH, Material.WOOD);
|
||||
public static final ItemAxe WOOD_AXE = new ItemAxe(11, Recipe.STATION_BENCH, Material.WOOD);
|
||||
public static final ItemHoe WOOD_HOE = new ItemHoe(12, Recipe.STATION_BENCH, Material.WOOD);
|
||||
|
||||
public static final ItemSword GOLD_SWORD = new ItemSword(13, Recipe.STATION_ANVIL, Material.GOLD);
|
||||
public static final ItemShovel GOLD_SHOVEL = new ItemShovel(14, Recipe.STATION_ANVIL, Material.GOLD);
|
||||
public static final ItemPickaxe GOLD_PICKAXE = new ItemPickaxe(15, Recipe.STATION_ANVIL, Material.GOLD);
|
||||
public static final ItemAxe GOLD_AXE = new ItemAxe(16, Recipe.STATION_ANVIL, Material.GOLD);
|
||||
public static final ItemHoe GOLD_HOE = new ItemHoe(17, Recipe.STATION_ANVIL, Material.GOLD);
|
||||
|
||||
public static final ItemSword IRON_SWORD = new ItemSword(18, Recipe.STATION_ANVIL, Material.IRON);
|
||||
public static final ItemShovel IRON_SHOVEL = new ItemShovel(19, Recipe.STATION_ANVIL, Material.IRON);
|
||||
public static final ItemPickaxe IRON_PICKAXE = new ItemPickaxe(20, Recipe.STATION_ANVIL, Material.IRON);
|
||||
public static final ItemAxe IRON_AXE = new ItemAxe(21, Recipe.STATION_ANVIL, Material.IRON);
|
||||
public static final ItemHoe IRON_HOE = new ItemHoe(22, Recipe.STATION_ANVIL, Material.IRON);
|
||||
|
||||
public static final ItemSword GEM_SWORD = new ItemSword(23, Recipe.STATION_ANVIL, Material.GEM);
|
||||
public static final ItemShovel GEM_SHOVEL = new ItemShovel(24, Recipe.STATION_ANVIL, Material.GEM);
|
||||
public static final ItemPickaxe GEM_PICKAXE = new ItemPickaxe(25, Recipe.STATION_ANVIL, Material.GEM);
|
||||
public static final ItemAxe GEM_AXE = new ItemAxe(26, Recipe.STATION_ANVIL, Material.GEM);
|
||||
public static final ItemHoe GEM_HOE = new ItemHoe(27, Recipe.STATION_ANVIL, Material.GEM);
|
||||
|
||||
public static final ItemCactus CACTUS = new ItemCactus(28);
|
||||
public static final ItemSeed SEED = new ItemSeed(29);
|
||||
public static final ItemSand SAND = new ItemSand(30);
|
||||
public static final ItemWheat WHEAT = new ItemWheat(31);
|
||||
public static final ItemBread BREAD = new ItemBread(32);
|
||||
public static final ItemGem GEM = new ItemGem(33);
|
||||
public static final ItemFlower POPPY = new ItemFlower(34, "POPPY", Tile.POPPY);
|
||||
public static final ItemFlower DAISY = new ItemFlower(35, "DAISY", Tile.DAISY);
|
||||
|
||||
public static final ItemCraftingBench CRAFTING_BENCH = new ItemCraftingBench(36);
|
||||
public static final ItemFurnace FURNACE = new ItemFurnace(37);
|
||||
public static final ItemOven OVEN = new ItemOven(38);
|
||||
public static final ItemChest CHEST = new ItemChest(39);
|
||||
public static final ItemAnvil ANVIL = new ItemAnvil(40);
|
||||
public static final ItemApple APPLE = new ItemApple(41);
|
||||
public static final ItemSapling SAPLING = new ItemSapling(42);
|
||||
|
||||
public static final ItemSword ROCK_SWORD = new ItemSword(43, Recipe.STATION_BENCH, Material.ROCK);
|
||||
public static final ItemShovel ROCK_SHOVEL = new ItemShovel(44, Recipe.STATION_BENCH, Material.ROCK);
|
||||
public static final ItemPickaxe ROCK_PICKAXE = new ItemPickaxe(45, Recipe.STATION_BENCH, Material.ROCK);
|
||||
public static final ItemAxe ROCK_AXE = new ItemAxe(46, Recipe.STATION_BENCH, Material.ROCK);
|
||||
public static final ItemHoe ROCK_HOE = new ItemHoe(47, Recipe.STATION_BENCH, Material.ROCK);
|
||||
|
||||
public static final ItemCoal COAL = new ItemCoal(48);
|
||||
public static final ItemGlass GLASS = new ItemGlass(49);
|
||||
public static final ItemPie PIE = new ItemPie(50);
|
||||
|
||||
public static final ItemOre MITHRIL_ORE = new ItemOre(51, Metal.MITHRIL);
|
||||
public static final ItemIngot MITHRIL_INGOT = new ItemIngot(52, Metal.MITHRIL);
|
||||
|
||||
public static final ItemSword MITHRIL_SWORD = new ItemSword(53, Recipe.STATION_ANVIL, Material.MITHRIL);
|
||||
public static final ItemShovel MITHRIL_SHOVEL = new ItemShovel(54, Recipe.STATION_ANVIL, Material.MITHRIL);
|
||||
public static final ItemPickaxe MITHRIL_PICKAXE = new ItemPickaxe(55, Recipe.STATION_ANVIL, Material.MITHRIL);
|
||||
public static final ItemAxe MITHRIL_AXE = new ItemAxe(56, Recipe.STATION_ANVIL, Material.MITHRIL);
|
||||
public static final ItemHoe MITHRIL_HOE = new ItemHoe(57, Recipe.STATION_ANVIL, Material.MITHRIL);
|
||||
|
||||
public static final ItemSlime SLIME = new ItemSlime(58);
|
||||
public static final ItemLantern LANTERN = new ItemLantern(59);
|
||||
|
||||
public static final ItemHelmet IRON_HELMET = new ItemHelmet(60, ItemArmor.TYPE_HELMET, Material.IRON);
|
||||
public static final ItemChestplate IRON_CHESTPLATE = new ItemChestplate(61, ItemArmor.TYPE_CHESTPLATE, Material.IRON);
|
||||
public static final ItemLeggings IRON_LEGGINGS = new ItemLeggings(62, ItemArmor.TYPE_LEGGINGS, Material.IRON);
|
||||
public static final ItemBoots IRON_BOOTS = new ItemBoots(63, ItemArmor.TYPE_BOOTS, Material.IRON);
|
||||
|
||||
public static final ItemHelmet GOLD_HELMET = new ItemHelmet(64, ItemArmor.TYPE_HELMET, Material.GOLD);
|
||||
public static final ItemChestplate GOLD_CHESTPLATE = new ItemChestplate(65, ItemArmor.TYPE_CHESTPLATE, Material.GOLD);
|
||||
public static final ItemLeggings GOLD_LEGGINGS = new ItemLeggings(66, ItemArmor.TYPE_LEGGINGS, Material.GOLD);
|
||||
public static final ItemBoots GOLD_BOOTS = new ItemBoots(67, ItemArmor.TYPE_BOOTS, Material.GOLD);
|
||||
|
||||
public static final ItemHelmet MITHRIL_HELMET = new ItemHelmet(68, ItemArmor.TYPE_HELMET, Material.MITHRIL);
|
||||
public static final ItemChestplate MITHRIL_CHESTPLATE = new ItemChestplate(69, ItemArmor.TYPE_CHESTPLATE, Material.MITHRIL);
|
||||
public static final ItemLeggings MITHRIL_LEGGINGS = new ItemLeggings(70, ItemArmor.TYPE_LEGGINGS, Material.MITHRIL);
|
||||
public static final ItemBoots MITHRIL_BOOTS = new ItemBoots(71, ItemArmor.TYPE_BOOTS, Material.MITHRIL);
|
||||
|
||||
public static final ItemCactusGoo CACTUS_GOO = new ItemCactusGoo(72);
|
||||
public static final ItemBone BONE = new ItemBone(73);
|
||||
public static final ItemBonemeal BONEMEAL = new ItemBonemeal(74);
|
||||
|
||||
// all available crafting recipes
|
||||
public static final List<Recipe> RECIPES = Arrays.stream(ITEMS)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(i -> i.getRecipes().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// recipes for each crafting station
|
||||
public static final Map<Integer, List<Recipe>> STATION_RECIPES = Map.of(
|
||||
Recipe.STATION_INVENTORY,
|
||||
RECIPES.stream().filter(r -> (r.station & Recipe.STATION_INVENTORY) != 0).collect(Collectors.toList()),
|
||||
Recipe.STATION_BENCH,
|
||||
RECIPES.stream().filter(r -> (r.station & Recipe.STATION_BENCH) != 0).collect(Collectors.toList()),
|
||||
Recipe.STATION_ALL_CRAFTING,
|
||||
RECIPES.stream().filter(r -> (r.station & Recipe.STATION_ALL_CRAFTING) != 0).collect(Collectors.toList()),
|
||||
Recipe.STATION_OVEN,
|
||||
RECIPES.stream().filter(r -> (r.station & Recipe.STATION_OVEN) != 0).collect(Collectors.toList()),
|
||||
Recipe.STATION_FURNACE,
|
||||
RECIPES.stream().filter(r -> (r.station & Recipe.STATION_FURNACE) != 0).collect(Collectors.toList()),
|
||||
Recipe.STATION_ANVIL,
|
||||
RECIPES.stream().filter(r -> (r.station & Recipe.STATION_ANVIL) != 0).collect(Collectors.toList())
|
||||
);
|
||||
|
||||
public final int id;
|
||||
|
||||
public Item(int id) {
|
||||
this.id = id;
|
||||
assert(Item.ITEMS[id] == null);
|
||||
Item.ITEMS[id] = this;
|
||||
}
|
||||
|
||||
public boolean use(ItemInstance instance, Level level, int x, int y, Entity e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// render this item in the world
|
||||
public void render(ItemInstance instance, Level level, int x, int y) {
|
||||
Renderer.render(this.getIconX(), this.getIconY(), x, y, this.getColor(), Renderer.FLIP_NONE);
|
||||
}
|
||||
|
||||
// render this item in a menu (as an icon)
|
||||
public void renderIcon(ItemInstance instance, int x, int y) {
|
||||
Renderer.render(this.getIconX(), this.getIconY(), x, y, this.getColor(), Renderer.FLIP_NONE);
|
||||
}
|
||||
|
||||
// render this item being carried by an entity
|
||||
public void renderCarry(ItemInstance instance, Level Level, Entity e) {
|
||||
|
||||
}
|
||||
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
public boolean carry(Entity e) { return false; }
|
||||
|
||||
public int getLightPower() { return 0; }
|
||||
|
||||
public boolean isEquippable() { return false; }
|
||||
|
||||
public boolean isStackable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDroppable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean showInMenu() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract int getColor();
|
||||
|
||||
public abstract int getIconX();
|
||||
|
||||
public abstract int getIconY();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.jdh.microcraft.item;
|
||||
|
||||
import com.jdh.microcraft.Global;
|
||||
|
||||
public class ItemInstance {
|
||||
public Item item;
|
||||
public int data, id;
|
||||
|
||||
public ItemInstance(ItemInstance instance) {
|
||||
this(instance.item, instance.data);
|
||||
}
|
||||
|
||||
public ItemInstance(Item item) {
|
||||
this(item, 0);
|
||||
}
|
||||
|
||||
public ItemInstance(Item item, int data) {
|
||||
this.item = item;
|
||||
this.data = data;
|
||||
this.id = Global.game.getNextItemInstanceId();
|
||||
}
|
||||
}
|
||||
30
Java/Microcraft/src/com/jdh/microcraft/item/ItemStack.java
Normal file
30
Java/Microcraft/src/com/jdh/microcraft/item/ItemStack.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.jdh.microcraft.item;
|
||||
|
||||
public class ItemStack {
|
||||
public ItemInstance instance;
|
||||
public int size;
|
||||
|
||||
public ItemStack(ItemStack stack) {
|
||||
this(new ItemInstance(stack.instance), stack.size);
|
||||
}
|
||||
|
||||
public ItemStack(Item item) {
|
||||
this(new ItemInstance(item));
|
||||
}
|
||||
|
||||
public ItemStack(Item item, int size) {
|
||||
this(new ItemInstance(item), size);
|
||||
}
|
||||
|
||||
public ItemStack(ItemInstance instance) {
|
||||
this(instance, 1);
|
||||
}
|
||||
|
||||
public ItemStack(ItemInstance instance, int size) {
|
||||
assert(size > 0);
|
||||
assert(size == 1 || instance.item.isStackable());
|
||||
|
||||
this.instance = instance;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
52
Java/Microcraft/src/com/jdh/microcraft/item/Material.java
Normal file
52
Java/Microcraft/src/com/jdh/microcraft/item/Material.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package com.jdh.microcraft.item;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.resource.ItemGem;
|
||||
import com.jdh.microcraft.item.resource.ItemWood;
|
||||
import com.jdh.microcraft.level.tile.TileRock;
|
||||
|
||||
public class Material {
|
||||
public static final Material BASE =
|
||||
new Material("BASE", 0, 0.5, 0, 0);
|
||||
public static final Material WOOD =
|
||||
new Material("WOOD", 3 /* WOOD */, 0.8,
|
||||
Color.get(110, 220, ItemWood.BASE_COLOR, Color.add(ItemWood.BASE_COLOR, 111)),
|
||||
0);
|
||||
public static final Material ROCK =
|
||||
new Material("ROCK", 2 /* ROCK */, 1.2,
|
||||
Color.get(110, 220, TileRock.BASE_COLOR, Color.add(TileRock.BASE_COLOR, 111)),
|
||||
0);
|
||||
public static final Material IRON =
|
||||
new Material("IRON", 7 /* IRON_INGOT */, 2.0,
|
||||
Color.get(110, 330, Metal.IRON.baseColor, Color.add(Metal.IRON.baseColor, 111)),
|
||||
Metal.IRON.color);
|
||||
public static final Material GOLD =
|
||||
new Material("GOLD", 5 /* GOLD_INGOT */, 3.0,
|
||||
Color.get(110, 330, Metal.GOLD.baseColor, Color.add(Metal.GOLD.baseColor, 111)),
|
||||
Metal.GOLD.color);
|
||||
public static final Material GEM =
|
||||
new Material("GEM", 33 /* GEM */, 5.0,
|
||||
Color.get(110, 330, ItemGem.BASE_COLOR, Color.add(ItemGem.BASE_COLOR, 111)),
|
||||
0);
|
||||
public static final Material MITHRIL =
|
||||
new Material("MITH", 52 /* MITHRIL_INGOT */, 10.0,
|
||||
Color.get(110, 330, Metal.MITHRIL.baseColor, Color.add(Metal.MITHRIL.baseColor, 111)),
|
||||
Metal.MITHRIL.color);
|
||||
|
||||
public final String name;
|
||||
public final int baseId;
|
||||
public final double efficiency;
|
||||
public final int toolColor, armorColor;
|
||||
|
||||
public Material(String name, int baseId, double efficiency, int toolColor, int armorColor) {
|
||||
this.name = name;
|
||||
this.baseId = baseId;
|
||||
this.efficiency = efficiency;
|
||||
this.toolColor = toolColor;
|
||||
this.armorColor = armorColor;
|
||||
}
|
||||
|
||||
public Item getBase() {
|
||||
return Item.ITEMS[this.baseId];
|
||||
}
|
||||
}
|
||||
37
Java/Microcraft/src/com/jdh/microcraft/item/Metal.java
Normal file
37
Java/Microcraft/src/com/jdh/microcraft/item/Metal.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package com.jdh.microcraft.item;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.resource.ItemIngot;
|
||||
import com.jdh.microcraft.item.resource.ItemOre;
|
||||
|
||||
public class Metal {
|
||||
public static final Metal GOLD =
|
||||
new Metal("GOLD",4, 5,
|
||||
441, Color.get(221, 331, 441, 553));
|
||||
public static final Metal IRON =
|
||||
new Metal("IRON", 6, 7,
|
||||
444, Color.get(222, 333, 444, 555));
|
||||
public static final Metal MITHRIL =
|
||||
new Metal("MITH", 51, 52,
|
||||
334, Color.get(222, 224, 335, 555));
|
||||
|
||||
public final String name;
|
||||
public final int oreId, ingotId;
|
||||
public final int baseColor, color;
|
||||
|
||||
public Metal(String name, int oreId, int ingotId, int baseColor, int color) {
|
||||
this.name = name;
|
||||
this.baseColor = baseColor;
|
||||
this.color = color;
|
||||
this.oreId = oreId;
|
||||
this.ingotId = ingotId;
|
||||
}
|
||||
|
||||
public ItemOre getOre() {
|
||||
return (ItemOre) Item.ITEMS[this.oreId];
|
||||
}
|
||||
|
||||
public ItemIngot getIngot() {
|
||||
return (ItemIngot) Item.ITEMS[this.ingotId];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.jdh.microcraft.item.armor;
|
||||
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.Material;
|
||||
|
||||
public abstract class ItemArmor extends Item {
|
||||
public static final int NUM_TYPES = 4;
|
||||
|
||||
public static final int
|
||||
TYPE_NONE = 0,
|
||||
TYPE_HELMET = 1 << 0,
|
||||
TYPE_CHESTPLATE = 1 << 1,
|
||||
TYPE_LEGGINGS = 1 << 2,
|
||||
TYPE_BOOTS = 1 << 3;
|
||||
|
||||
public static final Class[] CLASSES = new Class[]{
|
||||
ItemHelmet.class,
|
||||
ItemChestplate.class,
|
||||
ItemLeggings.class,
|
||||
ItemBoots.class
|
||||
};
|
||||
|
||||
public final int type, slot;
|
||||
public final Material material;
|
||||
|
||||
public ItemArmor(int id, int slot, int type, Material material) {
|
||||
super(id);
|
||||
this.slot = slot;
|
||||
this.type = type;
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStackable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public double getDamageReduction(ItemInstance instance) {
|
||||
return this.material.efficiency *
|
||||
switch (this.type) {
|
||||
case TYPE_HELMET -> 0.55;
|
||||
case TYPE_CHESTPLATE -> 1.0;
|
||||
case TYPE_LEGGINGS -> 0.8;
|
||||
case TYPE_BOOTS -> 0.65;
|
||||
default -> throw new IllegalStateException("Unexpected value: " + this.type);
|
||||
};
|
||||
}
|
||||
|
||||
public abstract int getSpriteBaseX();
|
||||
|
||||
public abstract int getSpriteBaseY();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.jdh.microcraft.item.armor;
|
||||
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.Material;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemBoots extends ItemArmor {
|
||||
public ItemBoots(int id, int type, Material material) {
|
||||
super(id, 3, type, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_ANVIL,
|
||||
new RecipeIngredient(this.material.getBase(), 4)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseY() {
|
||||
return 28;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.material.name + " BOOTS";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return this.material.armorColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.jdh.microcraft.item.armor;
|
||||
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.Material;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemChestplate extends ItemArmor {
|
||||
public ItemChestplate(int id, int type, Material material) {
|
||||
super(id, 1, type, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_ANVIL,
|
||||
new RecipeIngredient(this.material.getBase(), 8)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseY() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.material.name + " CHEST";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return this.material.armorColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.jdh.microcraft.item.armor;
|
||||
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.Material;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemHelmet extends ItemArmor {
|
||||
public ItemHelmet(int id, int type, Material material) {
|
||||
super(id, 0, type, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_ANVIL,
|
||||
new RecipeIngredient(this.material.getBase(), 4)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseY() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.material.name + " HELM";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return this.material.armorColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.jdh.microcraft.item.armor;
|
||||
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.Material;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemLeggings extends ItemArmor {
|
||||
public ItemLeggings(int id, int type, Material material) {
|
||||
super(id, 2, type, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_ANVIL,
|
||||
new RecipeIngredient(this.material.getBase(), 6)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpriteBaseY() {
|
||||
return 24;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.material.name + " LEGS";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return this.material.armorColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.jdh.microcraft.item.consumable;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
|
||||
public class ItemApple extends ItemFood {
|
||||
public ItemApple(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFoodValue() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "APPLE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(100, 300, 422, 533);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.jdh.microcraft.item.consumable;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemBread extends ItemFood {
|
||||
public ItemBread(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFoodValue() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_OVEN,
|
||||
new RecipeIngredient(Item.WHEAT, 3),
|
||||
new RecipeIngredient(Item.WOOD, 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "BREAD";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(110, 221, 331, 441);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.jdh.microcraft.item.consumable;
|
||||
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
import com.jdh.microcraft.level.tile.Tile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemCactusGoo extends ItemFood {
|
||||
public ItemCactusGoo(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(this),
|
||||
Recipe.STATION_ALL_CRAFTING,
|
||||
new RecipeIngredient(Item.CACTUS)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFoodValue() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "GOO";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Tile.CACTUS.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.jdh.microcraft.item.consumable;
|
||||
|
||||
import com.jdh.microcraft.item.Item;
|
||||
|
||||
public abstract class ItemConsumable extends Item {
|
||||
public ItemConsumable(int id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.jdh.microcraft.item.consumable;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.entity.particle.EntitySmashParticle;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
import com.jdh.microcraft.sound.Sound;
|
||||
|
||||
public abstract class ItemFood extends ItemConsumable {
|
||||
public ItemFood(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(ItemInstance instance, Level level, int x, int y, Entity e) {
|
||||
if (!(e instanceof EntityMob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityMob mob = ((EntityMob) e);
|
||||
mob.heal(this.getFoodValue());
|
||||
mob.removeItem(this, 1);
|
||||
|
||||
Sound.EQUIP.play();
|
||||
EntitySmashParticle.spawn(level, e.getCenterX(), e.getCenterY(), this.getColor(), 3, 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract int getFoodValue();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.jdh.microcraft.item.consumable;
|
||||
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemPie extends ItemFood {
|
||||
public ItemPie(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_OVEN,
|
||||
new RecipeIngredient(Item.APPLE, 1),
|
||||
new RecipeIngredient(Item.WHEAT, 4),
|
||||
new RecipeIngredient(Item.WOOD, 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFoodValue() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PIE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(111, 333, 551, 422);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.jdh.microcraft.item.crafting;
|
||||
|
||||
import com.jdh.microcraft.item.Inventory;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Recipe {
|
||||
public static final int
|
||||
STATION_INVENTORY = 1 << 0,
|
||||
STATION_BENCH = 1 << 1,
|
||||
STATION_ALL_CRAFTING = STATION_BENCH | STATION_INVENTORY,
|
||||
STATION_FURNACE = 1 << 2,
|
||||
STATION_OVEN = 1 << 3,
|
||||
STATION_ANVIL = 1 << 4;
|
||||
|
||||
public final ItemStack result;
|
||||
public final int station;
|
||||
public final List<RecipeIngredient> ingredients;
|
||||
|
||||
public Recipe(ItemStack result, int station, RecipeIngredient... ingredients) {
|
||||
this.result = result;
|
||||
this.station = station;
|
||||
|
||||
// deduplicate ingredients
|
||||
this.ingredients = new ArrayList<>();
|
||||
for (RecipeIngredient a : ingredients) {
|
||||
boolean add = true;
|
||||
|
||||
for (RecipeIngredient b : this.ingredients) {
|
||||
if (a.item.id == b.item.id) {
|
||||
b.count += a.count;
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
this.ingredients.add(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canMake(Inventory inventory, int station) {
|
||||
if ((this.station & station) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<RecipeIngredient> requirements = new ArrayList<>(this.ingredients);
|
||||
|
||||
for (ItemStack stack : inventory.stacks) {
|
||||
requirements.removeIf(req -> stack.instance.item.id == req.item.id && stack.size >= req.count);
|
||||
}
|
||||
|
||||
return requirements.size() == 0;
|
||||
}
|
||||
|
||||
public ItemStack make(Inventory inventory) {
|
||||
for (RecipeIngredient ingredient : this.ingredients) {
|
||||
for (var it = inventory.stacks.iterator(); it.hasNext(); ) {
|
||||
ItemStack stack = it.next();
|
||||
if (ingredient.item.id == stack.instance.item.id) {
|
||||
assert (stack.size >= ingredient.count);
|
||||
stack.size -= ingredient.count;
|
||||
|
||||
if (stack.size == 0) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ItemStack(this.result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jdh.microcraft.item.crafting;
|
||||
|
||||
import com.jdh.microcraft.item.Item;
|
||||
|
||||
public class RecipeIngredient {
|
||||
public Item item;
|
||||
public int count;
|
||||
|
||||
public RecipeIngredient(Item item) {
|
||||
this(item, 1);
|
||||
}
|
||||
|
||||
public RecipeIngredient(Item item, int count) {
|
||||
this.item = item;
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.jdh.microcraft.item.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.furniture.EntityAnvil;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemAnvil extends ItemFurniture {
|
||||
public ItemAnvil(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_BENCH,
|
||||
new RecipeIngredient(Item.IRON_INGOT, 8)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Level level) {
|
||||
return new EntityAnvil(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteX() {
|
||||
return 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ANVIL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(111, 222, 333, 444);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.jdh.microcraft.item.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.furniture.EntityChest;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemChest extends ItemFurniture {
|
||||
public ItemChest(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_BENCH,
|
||||
new RecipeIngredient(Item.WOOD, 10)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Level level) {
|
||||
return new EntityChest(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteX() {
|
||||
return 13;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CHEST";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(110, 221, 331, 441);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.jdh.microcraft.item.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.furniture.EntityCraftingBench;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemCraftingBench extends ItemFurniture {
|
||||
public ItemCraftingBench(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_ALL_CRAFTING,
|
||||
new RecipeIngredient(Item.WOOD, 6)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Level level) {
|
||||
return new EntityCraftingBench(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteX() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CRFT BENCH";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(110, 220, 330, 330);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.jdh.microcraft.item.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.furniture.EntityFurnace;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemFurnace extends ItemFurniture {
|
||||
public ItemFurnace(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_BENCH,
|
||||
new RecipeIngredient(Item.ROCK, 20),
|
||||
new RecipeIngredient(Item.COAL, 8)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Level level) {
|
||||
return new EntityFurnace(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteX() {
|
||||
return 13;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteY() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "FURNACE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(111, 333, 444, 530);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.jdh.microcraft.item.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.mob.EntityMob;
|
||||
import com.jdh.microcraft.gfx.Renderer;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ItemFurniture extends Item {
|
||||
public ItemFurniture(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderCarry(ItemInstance instance, Level Level, Entity e) {
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (int j = 0; j <= 1; j++) {
|
||||
Renderer.render(
|
||||
this.getTileSpriteX() + i, this.getTileSpriteY() + j,
|
||||
e.x + e.getRenderOffsetX() + (i * 8), e.y + e.getRenderOffsetY() - 14 + (j * 8),
|
||||
this.getColor(), Renderer.FLIP_NONE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean carry(Entity e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean use(ItemInstance instance, Level level, int x, int y, Entity e) {
|
||||
if (!(e instanceof EntityMob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityMob mob = (EntityMob) e;
|
||||
Entity fe = this.createEntity(level);
|
||||
fe.x = Level.toPixel(mob.getFacingTileX());
|
||||
fe.y = Level.toPixel(mob.getFacingTileY());
|
||||
|
||||
// cannot place if tile colliding
|
||||
if (level.getTileCollisions(fe).size() > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// cannot place if entity which is not placing is colliding
|
||||
List<Entity> collidingEntities = level.getEntityCollisions(fe);
|
||||
if (collidingEntities.size() > 1 ||
|
||||
(collidingEntities.size() == 1 && collidingEntities.get(0) != e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove from inventory
|
||||
mob.removeItem(instance.item, 1);
|
||||
|
||||
// place in world
|
||||
level.addEntity(fe);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStackable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract Entity createEntity(Level level);
|
||||
|
||||
public abstract int getTileSpriteX();
|
||||
|
||||
public abstract int getTileSpriteY();
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.jdh.microcraft.item.furniture;
|
||||
|
||||
import com.jdh.microcraft.entity.Entity;
|
||||
import com.jdh.microcraft.entity.furniture.EntityLantern;
|
||||
import com.jdh.microcraft.gfx.Color;
|
||||
import com.jdh.microcraft.item.Item;
|
||||
import com.jdh.microcraft.item.ItemInstance;
|
||||
import com.jdh.microcraft.item.ItemStack;
|
||||
import com.jdh.microcraft.item.crafting.Recipe;
|
||||
import com.jdh.microcraft.item.crafting.RecipeIngredient;
|
||||
import com.jdh.microcraft.level.Level;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemLantern extends ItemFurniture {
|
||||
public ItemLantern(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightPower() {
|
||||
return EntityLantern.LIGHT_POWER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Recipe> getRecipes() {
|
||||
return List.of(
|
||||
new Recipe(
|
||||
new ItemStack(new ItemInstance(this, 0), 1),
|
||||
Recipe.STATION_BENCH,
|
||||
new RecipeIngredient(Item.IRON_INGOT, 1),
|
||||
new RecipeIngredient(Item.GLASS, 4),
|
||||
new RecipeIngredient(Item.SLIME, 8)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Level level) {
|
||||
return new EntityLantern(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteX() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTileSpriteY() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LANTERN";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return Color.get(111, 222, 333, 552);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconX() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconY() {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user