diff --git a/src/client/java/minicraft/core/Renderer.java b/src/client/java/minicraft/core/Renderer.java index 8d92bab9d..8e92f4774 100644 --- a/src/client/java/minicraft/core/Renderer.java +++ b/src/client/java/minicraft/core/Renderer.java @@ -336,19 +336,19 @@ private static void renderGui() { } // This renders the potions overlay - if (player.showpotioneffects && player.potioneffects.size() > 0) { + if (player.showPotionEffects && player.potioneffects.size() > 0) { @SuppressWarnings("unchecked") Map.Entry[] effects = player.potioneffects.entrySet().toArray(new Map.Entry[0]); // The key is potion type, value is remaining potion duration. - if (!player.simpPotionEffects) { + if (!player.simplifyPotionEffects) { for (int i = 0; i < effects.length; i++) { PotionType pType = effects[i].getKey(); int pTime = effects[i].getValue() / Updater.normSpeed; int minutes = pTime / 60; int seconds = pTime % 60; - Font.drawBackground(Localization.getLocalized("minicraft.display.gui.potion_effects.hide_hint", input.getMapping("potionEffects")), screen, 180, 9); + Font.drawBackground(Localization.getLocalized("minicraft.display.gui.potion_effects.hide_hint", input.getMapping("POTION-EFFECTS")), screen, 180, 9); Font.drawBackground(Localization.getLocalized("minicraft.display.gui.potion_effects.potion_dur", pType, minutes, seconds), screen, 180, 17 + i * Font.textHeight() + potionRenderOffset, pType.dispColor); } } else { diff --git a/src/client/java/minicraft/core/io/InputHandler.java b/src/client/java/minicraft/core/io/InputHandler.java index 0123050d9..f9f7b0b40 100644 --- a/src/client/java/minicraft/core/io/InputHandler.java +++ b/src/client/java/minicraft/core/io/InputHandler.java @@ -148,10 +148,11 @@ private void initKeyMap() { keymap.put("SELECT", "ENTER"); keymap.put("EXIT", "ESCAPE"); - keymap.put("QUICKSAVE", "R"); // Saves the game while still playing + keymap.put("QUICK-SAVE", "R"); // Saves the game while still playing - keymap.put("ATTACK", "C|SPACE|ENTER"); // Attack action references "C" key - keymap.put("MENU", "X|E"); // And so on... menu does various things. + keymap.put("ATTACK", "C|SPACE"); // Attack/destroy action references "C" key + keymap.put("USE", "X|ENTER"); // Use action references "X" key (formerly "menu") + keymap.put("INVENTORY", "E"); // Open/close player inventory menu and exit action of some displays. keymap.put("CRAFT", "Z|SHIFT-E"); // Open/close personal crafting window. keymap.put("PICKUP", "V|P"); // Pickup torches / furniture; this replaces the power glove. keymap.put("DROP-ONE", "Q"); // Drops the item in your hand, or selected in your inventory, by ones; it won't drop an entire stack @@ -166,12 +167,11 @@ private void initKeyMap() { keymap.put("PAUSE", "ESCAPE"); // Pause the Game. - keymap.put("POTIONEFFECTS", "P"); // Toggle potion effect display - keymap.put("SIMPPOTIONEFFECTS", "O"); // Whether to simplify the potion effect display - keymap.put("EXPANDQUESTDISPLAY", "L"); // Expands the quest display - keymap.put("TOGGLEHUD", "F1"); // Toggle HUD + keymap.put("POTION-EFFECTS", "P"); // Toggle potion effect display + keymap.put("SIMPLIFY-POTION-EFFECTS", "O"); // Whether to simplify the potion effect display + keymap.put("EXPAND-QUEST-DISPLAY", "L"); // Expands the quest display + keymap.put("TOGGLE-HUD", "F1"); // Toggle HUD keymap.put("SCREENSHOT", "F2"); // To make screenshot - keymap.put("INFO", "SHIFT-I"); // Toggle player stats display keymap.put("FULLSCREEN", "F11"); } @@ -194,16 +194,17 @@ private void initButtonMap() { buttonMap.put("EXIT", ControllerButton.B); buttonMap.put("ATTACK", ControllerButton.A); - buttonMap.put("MENU", ControllerButton.X); + buttonMap.put("USE", ControllerButton.B); + buttonMap.put("INVENTORY", ControllerButton.X); buttonMap.put("CRAFT", ControllerButton.Y); - buttonMap.put("PICKUP", ControllerButton.LEFTBUMPER); + buttonMap.put("PICKUP", ControllerButton.LEFTSTICK); buttonMap.put("SEARCHER-BAR", ControllerButton.START); buttonMap.put("PAUSE", ControllerButton.START); - buttonMap.put("DROP-ONE", ControllerButton.RIGHTBUMPER); - buttonMap.put("DROP-STACK", ControllerButton.RIGHTSTICK); + buttonMap.put("DROP-ONE", ControllerButton.LEFTBUMPER); + buttonMap.put("DROP-STACK", ControllerButton.RIGHTBUMPER); } public void resetKeyBindings() { diff --git a/src/client/java/minicraft/entity/Arrow.java b/src/client/java/minicraft/entity/Arrow.java index 8b565c286..a693b7382 100644 --- a/src/client/java/minicraft/entity/Arrow.java +++ b/src/client/java/minicraft/entity/Arrow.java @@ -7,7 +7,12 @@ import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.util.DamageSource; import minicraft.util.Logging; +import org.jetbrains.annotations.Nullable; import javax.security.auth.DestroyFailedException; @@ -71,8 +76,8 @@ public void tick() { if (hit instanceof Mob && hit != owner) { Mob mob = (Mob) hit; damage += (hit instanceof Player ? 0 : 3) + (criticalHit ? 0 : 1); // Extra damage bonus. - damage = mob.calculateEntityDamage(this, damage); - mob.hurt(owner, damage, dir); //normal hurting to other mobs + mob.hurt(new DamageSource(DamageSource.DamageType.ARROW, owner, this, null), + dir, damage); // normal hurting to other mobs } if (!level.getTile(x >> 4, y >> 4).mayPass(level, x >> 4, y >> 4, this) @@ -92,6 +97,29 @@ public boolean isSolid() { return false; } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } + @Override public void render(Screen screen) { screen.render(x - 4, y - 4, sprite); diff --git a/src/client/java/minicraft/entity/Direction.java b/src/client/java/minicraft/entity/Direction.java index 291be85f9..dc00b47a1 100644 --- a/src/client/java/minicraft/entity/Direction.java +++ b/src/client/java/minicraft/entity/Direction.java @@ -46,4 +46,8 @@ public static Direction getDirection(int dir) { public int getDir() { return ordinal() - 1; } + + public Direction getOpposite() { + return Direction.getDirection(getDir() ^ 0b11); + } } diff --git a/src/client/java/minicraft/entity/Entity.java b/src/client/java/minicraft/entity/Entity.java index 5fb210357..b511b9d85 100644 --- a/src/client/java/minicraft/entity/Entity.java +++ b/src/client/java/minicraft/entity/Entity.java @@ -1,13 +1,16 @@ package minicraft.entity; import minicraft.core.Action; +import minicraft.core.Game; import minicraft.core.Updater; import minicraft.entity.mob.Player; import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; import minicraft.item.Item; import minicraft.level.Level; +import minicraft.level.tile.Tile; import minicraft.network.Network; +import minicraft.util.DamageSource; import minicraft.util.Logging; import org.jetbrains.annotations.Nullable; @@ -33,6 +36,19 @@ public abstract class Entity implements Tickable { * These bit shift operators are used to easily get the X & Y coordinates of a tile that the entity is standing on. */ + /* + * In total there are 3 types of active entity interactions: attack, use and take. + * While only players can use and take entities and tiles, generally all mobs may attack other entities and tiles. + * This is because players could use different keys for different interactions, but not for mob AIs. + * However, not all entities are able to be attacked (as well as use and take). + * Tiles can also attack entities in the similar sense. + * In the process of damage/hurting calculations and handling, the flow is like: + * - 1. Attack: interaction triggered by damage source; damage with bonus intended to emit is calculated here + * - With a method if there exists an AI in the source + * - 2. Hurt: target entity receives damage from damage source; calculation includes armors and shields + * - 3. Handle damage: final damage value is passed to this when all damage calculations are completed + */ + // Entity coordinates are per pixel, not per tile; each tile is 16x16 entity pixels. protected final Random random = new Random(); public int x, y; // x, y entity coordinates on the map @@ -141,17 +157,92 @@ public int getLightRadius() { protected void touchedBy(Entity entity) { } + public boolean isFireImmune() { + return false; + } + + /** + * The amount of damage to attack when the item has no damage attribute set. + * @return amount of damage by fists + */ + protected int baseDamage() { + return 1; + } + + /** + * An indicator for which the entity is attackable by certain entity, even under certain conditions. + * This is invoked each time an entity is being targetted regardless it is interacted. + * Most probably used by Player. + * @return {@code false} if not attackable and {@link #hurt(DamageSource, Direction, int)} would not be invoked + * when triggered. + */ + public abstract boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir); + + /** + * An indicator for which the entity is attackable by certain entity, even under certain conditions. + * This is invoked each time an entity is being targetted regardless it is interacted. + * Most probably used by Player. + * Though the usefulness of this is doubtable. + * @return {@code false} if not attackable and {@link #hurt(DamageSource, Direction, int)} would not be + * invoked when triggered. + */ + public abstract boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir); + + public boolean isInvulnerableTo(DamageSource source) { + return isRemoved() || + source.getCausingEntity() instanceof Player && Game.isMode("minicraft.settings.mode.creative") || + source.getDamageType().isFireRelated() && isFireImmune(); + } + /** - * Interacts with the entity this method is called on - * @param player The player attacking - * @param item The item the player attacked with + * An indicator for which the entity is attackable by certain entity, even under certain conditions. + * This is invoked each time an entity is being targetted regardless it is interacted. + * Most probably used by Player. + * @return {@code false} if not attackable and {@link #use(Player, Item, Direction)} would not be invoked + * when triggered. + */ + public abstract boolean isUsable(); + + // TODO Here, attackDir may be changed to use an angle instead of axis to perform more accurate actions. + + /** + * Hurt the entity directly, based on only damage and a direction + * Usually this is invoked by {@link #hurt(DamageSource, Direction, int)}.

+ * Note that using {@link #hurt(DamageSource, Direction, int)} is more recommended. + * @param damage The amount of damage to hurt the entity with + * @param attackDir The direction this entity was attacked from + */ + protected abstract void handleDamage(DamageSource source, Direction attackDir, int damage); + + /** + * Attacks the entity this method is called on + * @param source The cause of damage * @param attackDir The direction to interact + * @param damage The amount of damage intended to emit this time * @return If the interaction was successful */ - public boolean interact(Player player, @Nullable Item item, Direction attackDir) { + public abstract boolean hurt(DamageSource source, Direction attackDir, int damage); + + public static Direction getInteractionDir(Entity attacker, Entity hurt) { + return Direction.getDirection(hurt.x - attacker.x, hurt.y - attacker.y); + } + + /** + * Called when the player presses the USE key in front of this. + */ + public boolean use(Player player, @Nullable Item item, Direction attackDir) { return false; } + /** + * Picks up this entity + * @param player The player interacting + * @return the item picked up; {@code null} if picking up failed + */ + public @Nullable Item take(Player player) { + return null; + } + /** * Moves an entity horizontally and vertically. Returns whether entity was unimpeded in it's movement. */ @@ -309,7 +400,7 @@ public void handleDespawn() { /** * This exists as a way to signify that the entity has been removed through player action and/or world action; basically, it's actually gone, not just removed from a level because it's out of range or something. Calls to this method are used to, say, drop items. */ - public void die() { + public void die() { // TODO damage type remove(); } diff --git a/src/client/java/minicraft/entity/ExplosionTileTicker.java b/src/client/java/minicraft/entity/ExplosionTileTicker.java index 5331a82f4..f4dbbad43 100644 --- a/src/client/java/minicraft/entity/ExplosionTileTicker.java +++ b/src/client/java/minicraft/entity/ExplosionTileTicker.java @@ -1,10 +1,13 @@ package minicraft.entity; import minicraft.gfx.Screen; +import minicraft.item.Item; import minicraft.level.Level; import minicraft.level.tile.ExplodedTile; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; // This is a kind of tile entity. Maybe this should be savable. public class ExplosionTileTicker extends Entity { @@ -53,4 +56,27 @@ public void tick() { tick++; } + + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } } diff --git a/src/client/java/minicraft/entity/FireSpark.java b/src/client/java/minicraft/entity/FireSpark.java index 6a67764de..71a83d62c 100644 --- a/src/client/java/minicraft/entity/FireSpark.java +++ b/src/client/java/minicraft/entity/FireSpark.java @@ -6,6 +6,11 @@ import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker; +import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class FireSpark extends Entity { private static final SpriteLinker.LinkedSprite sprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "spark"); @@ -82,6 +87,29 @@ public boolean isSolid() { return false; } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } + @Override public void render(Screen screen) { int randmirror = 0; diff --git a/src/client/java/minicraft/entity/ItemEntity.java b/src/client/java/minicraft/entity/ItemEntity.java index f12622bf1..d5c500733 100644 --- a/src/client/java/minicraft/entity/ItemEntity.java +++ b/src/client/java/minicraft/entity/ItemEntity.java @@ -4,6 +4,10 @@ import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -145,6 +149,29 @@ protected void touchedBy(Entity entity) { } } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } + @Override protected List getDataPrints() { List prints = super.getDataPrints(); diff --git a/src/client/java/minicraft/entity/Spark.java b/src/client/java/minicraft/entity/Spark.java index 049d45d88..3a66b546a 100644 --- a/src/client/java/minicraft/entity/Spark.java +++ b/src/client/java/minicraft/entity/Spark.java @@ -7,6 +7,11 @@ import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class Spark extends Entity { private final int lifeTime; // How much time until the spark disappears @@ -51,7 +56,8 @@ public void tick() { Player player = getClosestPlayer(); if (player != null && player.isWithin(0, this)) { - player.hurt(owner, 1); + player.hurt(new DamageSource(DamageSource.DamageType.SPARK, owner, this, null), + getInteractionDir(this, player), 1); } } @@ -62,6 +68,29 @@ public boolean isSolid() { return false; } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } + @Override public void render(Screen screen) { int randmirror = 0; diff --git a/src/client/java/minicraft/entity/furniture/Bed.java b/src/client/java/minicraft/entity/furniture/Bed.java index d385e937a..b4f7553de 100644 --- a/src/client/java/minicraft/entity/furniture/Bed.java +++ b/src/client/java/minicraft/entity/furniture/Bed.java @@ -3,14 +3,17 @@ import minicraft.core.Game; import minicraft.core.Updater; import minicraft.core.io.Localization; +import minicraft.entity.Direction; import minicraft.entity.mob.Player; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.DyeItem; +import minicraft.item.Item; import minicraft.level.Level; import minicraft.util.MyUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -48,7 +51,7 @@ public Bed(DyeItem.DyeColor color) { /** * Called when the player attempts to get in bed. */ - public boolean use(Player player) { + public boolean use(Player player, @Nullable Item item, Direction attackDir) { if (checkCanSleep(player)) { // If it is late enough in the day to sleep... // Set the player spawn coord. to their current position, in tile coords (hence " >> 4") diff --git a/src/client/java/minicraft/entity/furniture/Chest.java b/src/client/java/minicraft/entity/furniture/Chest.java index bba338890..3e8209e5f 100644 --- a/src/client/java/minicraft/entity/furniture/Chest.java +++ b/src/client/java/minicraft/entity/furniture/Chest.java @@ -39,10 +39,8 @@ public Chest(String name, LinkedSprite itemSprite) { inventory = new Inventory(); // Initialize the inventory. } - /** - * This is what occurs when the player uses the "Menu" command near this - */ - public boolean use(Player player) { + @Override + public boolean use(Player player, @Nullable Item item, Direction attackDir) { Game.setDisplay(new ContainerDisplay(player, this)); return true; } @@ -70,10 +68,10 @@ public void populateInvRandom(Random random, String lootTable, @SuppressWarnings } @Override - public boolean interact(Player player, @Nullable Item item, Direction attackDir) { + public @Nullable Item take(Player player) { if (inventory.invSize() == 0) - return super.interact(player, item, attackDir); - return false; + return super.take(player); + return null; // TODO a state that the item cannot be put into inventory } @Override diff --git a/src/client/java/minicraft/entity/furniture/Composter.java b/src/client/java/minicraft/entity/furniture/Composter.java index 079d90795..d6e2374c6 100644 --- a/src/client/java/minicraft/entity/furniture/Composter.java +++ b/src/client/java/minicraft/entity/furniture/Composter.java @@ -22,7 +22,7 @@ public Composter() { } @Override - public boolean interact(Player player, @Nullable Item item, Direction attackDir) { + public boolean use(Player player, @Nullable Item item, Direction attackDir) { if (compost == MAX_COMPOST) { compost = 0; StackableItem i = (StackableItem) Items.get("Fertilizer").copy(); diff --git a/src/client/java/minicraft/entity/furniture/Crafter.java b/src/client/java/minicraft/entity/furniture/Crafter.java index a3e2af5f2..594885286 100644 --- a/src/client/java/minicraft/entity/furniture/Crafter.java +++ b/src/client/java/minicraft/entity/furniture/Crafter.java @@ -1,13 +1,16 @@ package minicraft.entity.furniture; import minicraft.core.Game; +import minicraft.entity.Direction; import minicraft.entity.mob.Player; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.item.Recipe; import minicraft.item.Recipes; import minicraft.screen.CraftingDisplay; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -50,7 +53,7 @@ public Crafter(Crafter.Type type) { this.type = type; } - public boolean use(Player player) { + public boolean use(Player player, @Nullable Item item, Direction attackDir) { Game.setDisplay(new CraftingDisplay(type.recipes, (type.name().equalsIgnoreCase("DyeVat") ? "Dye Vat" : type.name()), player)); return true; } diff --git a/src/client/java/minicraft/entity/furniture/DeathChest.java b/src/client/java/minicraft/entity/furniture/DeathChest.java index a1fb4d030..dc648e32f 100644 --- a/src/client/java/minicraft/entity/furniture/DeathChest.java +++ b/src/client/java/minicraft/entity/furniture/DeathChest.java @@ -4,6 +4,7 @@ import minicraft.core.Updater; import minicraft.core.io.Localization; import minicraft.core.io.Settings; +import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; import minicraft.gfx.Color; @@ -13,7 +14,7 @@ import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Inventory; import minicraft.item.Item; -import minicraft.item.StackableItem; +import org.jetbrains.annotations.Nullable; public class DeathChest extends Chest { private static LinkedSprite normalSprite = new LinkedSprite(SpriteType.Entity, "chest"); @@ -91,13 +92,10 @@ public void render(Screen screen) { Font.draw(timeString, screen, x - Font.textWidth(timeString) / 2, y - Font.textHeight() - getBounds().getHeight() / 2, Color.WHITE); } - public boolean use(Player player) { + public boolean use(Player player, @Nullable Item item, Direction attackDir) { return false; } // can't open it, just walk into it. - public void take(Player player) { - } // can't grab a death chest. - @Override public void touchedBy(Entity other) { if (other instanceof Player) { diff --git a/src/client/java/minicraft/entity/furniture/DungeonChest.java b/src/client/java/minicraft/entity/furniture/DungeonChest.java index faf63c717..d57d9bb61 100644 --- a/src/client/java/minicraft/entity/furniture/DungeonChest.java +++ b/src/client/java/minicraft/entity/furniture/DungeonChest.java @@ -46,7 +46,7 @@ public DungeonChest(@Nullable Random random, boolean unlocked) { return new DungeonChest(null, !this.isLocked); } - public boolean use(Player player) { + public boolean use(Player player, @Nullable Item item, Direction attackDir) { if (isLocked) { boolean activeKey = player.activeItem != null && player.activeItem.equals(Items.get("Key")); boolean invKey = player.getInventory().count(Items.get("key")) > 0; @@ -71,11 +71,11 @@ public boolean use(Player player) { level.dropItem(x, y, 5, Items.get("Gold Apple")); } - return super.use(player); // the player unlocked the chest. + return super.use(player, item, attackDir); // the player unlocked the chest. } return false; // the chest is locked, and the player has no key. - } else return super.use(player); // the chest was already unlocked. + } else return super.use(player, item, attackDir); // the chest was already unlocked. } /** @@ -110,9 +110,9 @@ protected void touchedBy(Entity entity) { } @Override - public boolean interact(Player player, @Nullable Item item, Direction attackDir) { + public @Nullable Item take(Player player) { if (!isLocked) - return super.interact(player, item, attackDir); - return false; + return super.take(player); + return null; } } diff --git a/src/client/java/minicraft/entity/furniture/Furniture.java b/src/client/java/minicraft/entity/furniture/Furniture.java index 2f0cc22a8..9ef56e903 100644 --- a/src/client/java/minicraft/entity/furniture/Furniture.java +++ b/src/client/java/minicraft/entity/furniture/Furniture.java @@ -8,7 +8,9 @@ import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.item.FurnitureItem; import minicraft.item.Item; -import minicraft.item.PowerGloveItem; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.util.DamageSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -76,13 +78,6 @@ public void render(Screen screen) { screen.render(x - 8, y - 8, sprite); } - /** - * Called when the player presses the MENU key in front of this. - */ - public boolean use(Player player) { - return false; - } - @Override public boolean blocks(Entity e) { return true; // Furniture blocks all entities, even non-solid ones like arrows. @@ -94,21 +89,38 @@ protected void touchedBy(Entity entity) { tryPush((Player) entity); } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return true; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return true; + } + + @Override + public boolean isUsable() { + return true; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } + /** - * Used in PowerGloveItem.java to let the user pick up furniture. + * Lets the user pick up furniture. * @param player The player picking up the furniture. */ @Override - public boolean interact(Player player, @Nullable Item item, Direction attackDir) { - if (item instanceof PowerGloveItem) { - Sound.play("monsterhurt"); - remove(); - if (player.activeItem != null && !(player.activeItem instanceof PowerGloveItem)) - player.getLevel().dropItem(player.x, player.y, player.activeItem); // Put whatever item the player is holding into their inventory - player.activeItem = new FurnitureItem(this); // Make this the player's current item. - return true; - } - return false; + public @Nullable Item take(Player player) { + Sound.play("monsterhurt"); + remove(); + return new FurnitureItem(this); } /** diff --git a/src/client/java/minicraft/entity/furniture/KnightStatue.java b/src/client/java/minicraft/entity/furniture/KnightStatue.java index e2a6f5219..044c0020f 100644 --- a/src/client/java/minicraft/entity/furniture/KnightStatue.java +++ b/src/client/java/minicraft/entity/furniture/KnightStatue.java @@ -19,7 +19,7 @@ public KnightStatue(int health) { } @Override - public boolean interact(Player player, Item heldItem, Direction attackDir) { + public boolean use(Player player, Item heldItem, Direction attackDir) { if (!ObsidianKnight.active) { if (touches == 0) { // Touched the first time. Game.notifications.add(Localization.getLocalized("minicraft.notifications.statue_tapped")); diff --git a/src/client/java/minicraft/entity/furniture/Spawner.java b/src/client/java/minicraft/entity/furniture/Spawner.java index 3a9f74479..33c2cd21c 100644 --- a/src/client/java/minicraft/entity/furniture/Spawner.java +++ b/src/client/java/minicraft/entity/furniture/Spawner.java @@ -4,6 +4,7 @@ import minicraft.core.Updater; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Cow; import minicraft.entity.mob.Creeper; import minicraft.entity.mob.EnemyMob; @@ -28,7 +29,9 @@ import minicraft.item.PowerGloveItem; import minicraft.item.ToolItem; import minicraft.item.ToolType; +import minicraft.util.DamageSource; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; import java.util.ArrayList; @@ -173,51 +176,40 @@ private void trySpawn() { } @Override - public boolean interact(Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { - ToolItem tool = (ToolItem) item; - + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + if (source.getCausingEntity() instanceof Player) { + Item item = source.getItem(); Sound.play("monsterhurt"); - - int dmg; + int dmg = item instanceof ToolItem ? ((ToolItem) item).getAttackDamageBonus(this) : 1; if (Game.isMode("minicraft.settings.mode.creative")) dmg = health; - else { - dmg = tool.level + random.nextInt(2); - - if (tool.type == ToolType.Pickaxe) - dmg += random.nextInt(5) + 2; - - if (player.potioneffects.containsKey(PotionType.Haste)) - dmg *= 2; - } health -= dmg; level.add(new TextParticle("" + dmg, x, y, Color.get(-1, 200, 300, 400))); if (health <= 0) { level.remove(this); Sound.play("death"); - player.addScore(500); + ((Player) source.getCausingEntity()).addScore(500); } return true; } - if (item instanceof PowerGloveItem && Game.isMode("minicraft.settings.mode.creative")) { + return false; + } + + @Override + public @Nullable Item take(Player player) { + if (Game.isMode("minicraft.settings.mode.creative")) { level.remove(this); - if (!(player.activeItem instanceof PowerGloveItem)) - player.getLevel().dropItem(player.x, player.y, player.activeItem); - player.activeItem = new FurnitureItem(this); - return true; + return new FurnitureItem(this); } - if (item == null) return use(player); - - return false; + return null; } @Override - public boolean use(Player player) { + public boolean use(Player player, @Nullable Item item, Direction attackDir) { if (Game.isMode("minicraft.settings.mode.creative") && mob instanceof EnemyMob) { lvl++; if (lvl > maxMobLevel) lvl = 1; diff --git a/src/client/java/minicraft/entity/furniture/Tnt.java b/src/client/java/minicraft/entity/furniture/Tnt.java index de02d17c7..1fae2aa69 100644 --- a/src/client/java/minicraft/entity/furniture/Tnt.java +++ b/src/client/java/minicraft/entity/furniture/Tnt.java @@ -17,6 +17,7 @@ import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; import minicraft.screen.AchievementsDisplay; +import org.jetbrains.annotations.Nullable; import javax.swing.Timer; @@ -99,17 +100,18 @@ public void render(Screen screen) { } @Override - public boolean interact(Player player, Item heldItem, Direction attackDir) { - if (heldItem instanceof PowerGloveItem) { - if (!fuseLit) { - return super.interact(player, heldItem, attackDir); - } - } else { - if (!fuseLit) { - fuseLit = true; - Sound.play("fuse"); - return true; - } + public @Nullable Item take(Player player) { + if (!fuseLit) + return super.take(player); + return null; + } + + @Override + public boolean use(Player player, @Nullable Item item, Direction attackDir) { + if (!fuseLit) { + fuseLit = true; + Sound.play("fuse"); + return true; } return false; diff --git a/src/client/java/minicraft/entity/mob/AirWizard.java b/src/client/java/minicraft/entity/mob/AirWizard.java index 8f2c2705e..ce389d425 100644 --- a/src/client/java/minicraft/entity/mob/AirWizard.java +++ b/src/client/java/minicraft/entity/mob/AirWizard.java @@ -3,6 +3,7 @@ import minicraft.core.Game; import minicraft.core.Updater; import minicraft.core.io.Localization; +import minicraft.core.io.Settings; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; @@ -11,9 +12,12 @@ import minicraft.gfx.Font; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.item.Item; import minicraft.item.Items; import minicraft.network.Analytics; import minicraft.screen.AchievementsDisplay; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class AirWizard extends EnemyMob { private static final LinkedSprite[][][] sprites = new LinkedSprite[][][] { @@ -117,11 +121,11 @@ public void tick() { } @Override - public void doHurt(int damage, Direction attackDir) { - super.doHurt(damage, attackDir); + public boolean hurt(DamageSource source, Direction attackDir, int damage) { if (attackDelay == 0 && attackTime == 0) { attackDelay = 60 * 2; } + return super.hurt(source, attackDir, damage); } @Override @@ -151,7 +155,7 @@ public void render(Screen screen) { protected void touchedBy(Entity entity) { if (entity instanceof Player) { // If the entity is the Player, then deal them 1 damage points. - ((Player) entity).hurt(this, 1); + attack(entity); } } diff --git a/src/client/java/minicraft/entity/mob/Creeper.java b/src/client/java/minicraft/entity/mob/Creeper.java index 94860cc37..9b70716e4 100644 --- a/src/client/java/minicraft/entity/mob/Creeper.java +++ b/src/client/java/minicraft/entity/mob/Creeper.java @@ -12,6 +12,7 @@ import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.item.Items; import minicraft.level.tile.Tiles; +import minicraft.util.DamageSource; import java.util.ArrayList; import java.util.List; @@ -97,7 +98,9 @@ public void tick() { int distx = Math.abs(mob.x - x); int disty = Math.abs(mob.y - y); float distDiag = (float) Math.sqrt(distx * distx + disty * disty); - mob.hurt(this, (int) (lvlDamage * (1 / (distDiag + 1)) + Settings.getIdx("diff"))); + entity.hurt(new DamageSource(DamageSource.DamageType.EXPLOSION, this, null), + getInteractionDir(this, mob), + (int) (lvlDamage * (1 / (distDiag + 1)) + Settings.getIdx("diff"))); } else if (entity instanceof Spawner) { spawners.add(entity); } @@ -155,7 +158,7 @@ protected void touchedBy(Entity entity) { fuseTime = MAX_FUSE_TIME; fuseLit = true; } - ((Player) entity).hurt(this, 1); + attack(entity); } } diff --git a/src/client/java/minicraft/entity/mob/EnemyMob.java b/src/client/java/minicraft/entity/mob/EnemyMob.java index 0788005ec..b8b3e4d9b 100644 --- a/src/client/java/minicraft/entity/mob/EnemyMob.java +++ b/src/client/java/minicraft/entity/mob/EnemyMob.java @@ -3,13 +3,17 @@ import minicraft.core.Game; import minicraft.core.Updater; import minicraft.core.io.Settings; +import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.furniture.Bed; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.item.Item; import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class EnemyMob extends MobAi { @@ -108,13 +112,33 @@ public void render(Screen screen) { @Override protected void touchedBy(Entity entity) { // If an entity (like the player) touches the enemy mob - super.touchedBy(entity); // Hurts the player, damage is based on lvl. if (entity instanceof Player) { - ((Player) entity).hurt(this, lvl * (Settings.get("diff").equals("minicraft.settings.difficulty.hard") ? 2 : 1)); + attack(entity); } } + @Override + public boolean attack(Entity entity) { + return hurt(new DamageSource(DamageSource.DamageType.GENERIC, this, null), dir, + lvl * (Settings.get("diff").equals("minicraft.settings.difficulty.hard") ? 2 : 1)); + } + + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return true; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return true; + } + + @Override + public boolean isUsable() { + return false; + } + public void die() { super.die(50 * lvl, 1); } diff --git a/src/client/java/minicraft/entity/mob/Mob.java b/src/client/java/minicraft/entity/mob/Mob.java index c19efad36..43b6b2096 100644 --- a/src/client/java/minicraft/entity/mob/Mob.java +++ b/src/client/java/minicraft/entity/mob/Mob.java @@ -1,7 +1,7 @@ package minicraft.entity.mob; -import minicraft.core.Game; import minicraft.core.Renderer; +import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.furniture.Tnt; @@ -10,9 +10,13 @@ import minicraft.gfx.Color; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.item.PotionType; +import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public abstract class Mob extends Entity { @@ -54,7 +58,8 @@ public void tick() { noActionTime++; if (level != null && level.getTile(x >> 4, y >> 4) == Tiles.get("lava")) // If we are trying to swim in lava - hurt(Tiles.get("lava"), x, y, 4); // Inflict 4 damage to ourselves, sourced from the lava Tile, with the direction as the opposite of ours. + // Inflict 4 damage to ourselves, sourced from the lava Tile, with the direction as the opposite of ours. + hurt(new DamageSource(DamageSource.DamageType.LAVA, level, x, y, Tiles.get("lava")), Direction.NONE, 4); if (canBurn()) { if (this.burningDuration > 0) { @@ -62,13 +67,9 @@ public void tick() { if (this.burningDuration % 10 == 0) level.add(new BurnParticle(x - 8 + (random.nextInt(8) - 4), y - 8 + (random.nextInt(8) - 4))); this.burningDuration--; - if (this instanceof Player) { - if (this.burningDuration % 70 == 0 && !Renderer.player.potioneffects.containsKey(PotionType.Lava)) - hurt(this, 1, Direction.NONE); //burning damage - } else { - if (this.burningDuration % 70 == 0) - hurt(this, 2, Direction.NONE); //burning damage - } + // TODO different damage? + hurt(new DamageSource(DamageSource.DamageType.ON_FIRE, level, x, y, null), // TODO last attacker + Direction.NONE, this instanceof Player ? 1 : 2); //burning damage } } @@ -79,11 +80,11 @@ public void tick() { /// The code below checks the direction of the knockback, moves the Mob accordingly, and brings the knockback closer to 0. int xd = 0, yd = 0; if (xKnockback != 0) { - xd = (int) Math.ceil(xKnockback / 2); + xd = (int) Math.ceil(xKnockback / 2F); xKnockback -= xKnockback / Math.abs(xKnockback); } if (yKnockback != 0) { - yd = (int) Math.ceil(yKnockback / 2); + yd = (int) Math.ceil(yKnockback / 2F); yKnockback -= yKnockback / Math.abs(yKnockback); } @@ -219,37 +220,12 @@ public boolean isSwimming() { } /** - * Do damage to the mob this method is called on. - * @param tile The tile that hurt the player - * @param x The x position of the mob - * @param y The x position of the mob - * @param damage The amount of damage to hurt the mob with + * Attacks an entity + * @param entity The entity to attack + * @return If the interaction was successful */ - public void hurt(Tile tile, int x, int y, int damage) { // Hurt the mob, when the source of damage is a tile - Direction attackDir = Direction.getDirection(dir.getDir() ^ 1); // Set attackDir to our own direction, inverted. XORing it with 1 flips the rightmost bit in the variable, this effectively adds one when even, and subtracts one when odd. - if (!(tile == Tiles.get("lava") && this instanceof Player && ((Player) this).potioneffects.containsKey(PotionType.Lava))) - doHurt(damage, tile.mayPass(level, x, y, this) ? Direction.NONE : attackDir); // Call the method that actually performs damage, and set it to no particular direction - } - - /** - * Do damage to the mob this method is called on. - * @param mob The mob that hurt this mob - * @param damage The amount of damage to hurt the mob with - */ - public void hurt(Mob mob, int damage) { - hurt(mob, damage, getAttackDir(mob, this)); - } - - /** - * Do damage to the mob this method is called on. - * @param mob The mob that hurt this mob - * @param damage The amount of damage to hurt the mob with - * @param attackDir The direction this mob was attacked from - */ - public void hurt(Mob mob, int damage, Direction attackDir) { // Hurt the mob, when the source is another mob - if (mob instanceof Player && Game.isMode("minicraft.settings.mode.creative") && mob != this) - doHurt(health, attackDir); // Kill the mob instantly - else doHurt(damage, attackDir); // Call the method that actually performs damage, and use our provided attackDir + public boolean attack(Entity entity) { + return false; } /** @@ -265,19 +241,33 @@ public void burn(int sec) { * @param dmg The amount of damage the explosion does. */ public void onExploded(Tnt tnt, int dmg) { - doHurt(dmg, getAttackDir(tnt, this)); + hurt(new DamageSource(DamageSource.DamageType.EXPLOSION, tnt, null), + getInteractionDir(tnt, this), dmg); } - /** - * Hurt the mob, based on only damage and a direction - * This is overridden in Player.java - * @param damage The amount of damage to hurt the mob with - * @param attackDir The direction this mob was attacked from - */ - protected void doHurt(int damage, Direction attackDir) { + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + handleDamage(source, attackDir, damage); + return true; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) { if (isRemoved() || hurtTime > 0) return; // If the mob has been hurt recently and hasn't cooled down, don't continue + Player player = getClosestPlayer(); + if (player != null) { // If there is a player in the level + + /// Play the hurt sound only if the player is less than 80 entity coordinates away; or 5 tiles away. + int xd = player.x - x; + int yd = player.y - y; + if (xd * xd + yd * yd < 80 * 80) { + Sound.play("monsterhurt"); + } + } + level.add(new TextParticle("" + damage, x, y, Color.RED)); // Make a text particle at this position in this level, bright red and displaying the damage inflicted + health -= damage; // Actually change the health // Add the knockback in the correct direction @@ -298,17 +288,4 @@ public void heal(int heal) { // Restore health on the mob if (health > (Player.baseHealth + Player.extraHealth)) health = (Player.baseHealth + Player.extraHealth); // If our health has exceeded our maximum, lower it back down to said maximum } - - protected static Direction getAttackDir(Entity attacker, Entity hurt) { - return Direction.getDirection(hurt.x - attacker.x, hurt.y - attacker.y); - } - - /** - * This checks how the {@code attacker} can damage this mob. - * @param attacker The attacker entity. - * @return The calculated damage. - */ - public int calculateEntityDamage(Entity attacker, int damage) { - return damage; - } } diff --git a/src/client/java/minicraft/entity/mob/MobAi.java b/src/client/java/minicraft/entity/mob/MobAi.java index 00c2df1eb..e7d1c06b8 100644 --- a/src/client/java/minicraft/entity/mob/MobAi.java +++ b/src/client/java/minicraft/entity/mob/MobAi.java @@ -147,26 +147,6 @@ public boolean move(int xd, int yd) { return super.move(xd, yd); } - @Override - public void doHurt(int damage, Direction attackDir) { - if (isRemoved() || hurtTime > 0) - return; // If the mob has been hurt recently and hasn't cooled down, don't continue - - Player player = getClosestPlayer(); - if (player != null) { // If there is a player in the level - - /// Play the hurt sound only if the player is less than 80 entity coordinates away; or 5 tiles away. - int xd = player.x - x; - int yd = player.y - y; - if (xd * xd + yd * yd < 80 * 80) { - Sound.play("monsterhurt"); - } - } - level.add(new TextParticle("" + damage, x, y, Color.RED)); // Make a text particle at this position in this level, bright red and displaying the damage inflicted - - super.doHurt(damage, attackDir); - } - @Override public boolean canWool() { return true; diff --git a/src/client/java/minicraft/entity/mob/ObsidianKnight.java b/src/client/java/minicraft/entity/mob/ObsidianKnight.java index 5d874e1a5..f14d97ccf 100644 --- a/src/client/java/minicraft/entity/mob/ObsidianKnight.java +++ b/src/client/java/minicraft/entity/mob/ObsidianKnight.java @@ -14,8 +14,13 @@ import minicraft.gfx.Font; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker; +import minicraft.item.Item; import minicraft.item.Items; +import minicraft.level.Level; +import minicraft.level.tile.Tile; import minicraft.screen.AchievementsDisplay; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Range; public class ObsidianKnight extends EnemyMob { @@ -199,11 +204,17 @@ public void tick() { } @Override - public void doHurt(int damage, Direction attackDir) { - super.doHurt(damage, attackDir); + public boolean hurt(DamageSource source, Direction attackDir, int damage) { if (attackDelay == 0 && attackTime == 0) { attackDelay = 60 * 2; } + + if (source.getDirectEntity() instanceof Arrow && phase == 0) { + source.getDirectEntity().remove(); + return false; + } + + return super.hurt(source, attackDir, damage); } @Override @@ -233,7 +244,7 @@ public void render(Screen screen) { protected void touchedBy(Entity entity) { if (entity instanceof Player) { // If the entity is the Player, then deal them 2 damage points. - ((Player) entity).hurt(this, 2); + attack(entity); if (attackPhase == AttackPhase.Dashing) { dashTime = Math.max(dashTime - 10, 0); } @@ -273,14 +284,4 @@ public void die() { super.die(); // Calls the die() method in EnemyMob.java } - - @Override - public int calculateEntityDamage(Entity attacker, int damage) { - if (attacker instanceof Arrow && phase == 0) { - attacker.remove(); - return 0; - } - - return super.calculateEntityDamage(attacker, damage); - } } diff --git a/src/client/java/minicraft/entity/mob/PassiveMob.java b/src/client/java/minicraft/entity/mob/PassiveMob.java index e6ec7f6cb..8cde1db95 100644 --- a/src/client/java/minicraft/entity/mob/PassiveMob.java +++ b/src/client/java/minicraft/entity/mob/PassiveMob.java @@ -3,11 +3,15 @@ import minicraft.core.Game; import minicraft.core.Updater; import minicraft.core.io.Settings; +import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.item.Item; import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; +import org.jetbrains.annotations.Nullable; public class PassiveMob extends MobAi { protected int color; @@ -42,6 +46,21 @@ public void render(Screen screen) { super.render(screen); } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return true; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return true; + } + + @Override + public boolean isUsable() { + return false; + } + @Override public void randomizeWalkDir(boolean byChance) { if (xmov == 0 && ymov == 0 && random.nextInt(5) == 0 || byChance || random.nextInt(randomWalkChance) == 0) { diff --git a/src/client/java/minicraft/entity/mob/Player.java b/src/client/java/minicraft/entity/mob/Player.java index 385e78052..bbcdaa89c 100644 --- a/src/client/java/minicraft/entity/mob/Player.java +++ b/src/client/java/minicraft/entity/mob/Player.java @@ -6,7 +6,6 @@ import minicraft.core.io.InputHandler; import minicraft.core.io.Settings; import minicraft.core.io.Sound; -import minicraft.entity.Arrow; import minicraft.entity.ClientTickable; import minicraft.entity.Direction; import minicraft.entity.Entity; @@ -39,7 +38,6 @@ import minicraft.item.StackableItem; import minicraft.item.TileItem; import minicraft.item.ToolItem; -import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; @@ -54,6 +52,7 @@ import minicraft.screen.SkinDisplay; import minicraft.screen.WorldSelectDisplay; import minicraft.util.AdvancementElement; +import minicraft.util.DamageSource; import minicraft.util.Logging; import minicraft.util.Vector2; import org.jetbrains.annotations.Nullable; @@ -91,12 +90,9 @@ public class Player extends Mob implements ItemHolder, ClientTickable { private final Inventory inventory; - public Item activeItem; - Item attackItem; // attackItem is useful again b/c of the power glove. - private Item prevItem; // Holds the item held before using the POW glove. + public @Nullable Item activeItem; int attackTime; - public Direction attackDir; private int onStairDelay; // The delay before changing levels. private int onFallDelay; // The delay before falling b/c we're on an InfiniteFallTile @@ -121,8 +117,8 @@ public class Player extends Mob implements ItemHolder, ClientTickable { private int hungerStarveDelay; // The delay between each time the hunger bar decreases your health public HashMap potioneffects; // The potion effects currently applied to the player - public boolean showpotioneffects; // Whether to display the current potion effects on screen - public boolean simpPotionEffects; + public boolean showPotionEffects; // Whether to display the current potion effects on screen + public boolean simplifyPotionEffects; public boolean renderGUI; public int questExpanding; // Lets the display keeps expanded. private int cooldowninfo; // Prevents you from toggling the info pane on and off super fast. @@ -187,15 +183,14 @@ public void updateInv(String items) { }; potioneffects = new HashMap<>(); - showpotioneffects = true; - simpPotionEffects = false; + showPotionEffects = true; + simplifyPotionEffects = false; renderGUI = true; cooldowninfo = 0; regentick = 0; questExpanding = 0; - attackDir = dir; armor = 0; curArmor = null; armorDamageBuffer = 0; @@ -319,20 +314,20 @@ public void tick() { if (cooldowninfo > 0) cooldowninfo--; if (questExpanding > 0) questExpanding--; - if (input.inputPressed("potionEffects") && cooldowninfo == 0) { + if (input.inputPressed("POTION-EFFECTS") && cooldowninfo == 0) { cooldowninfo = 10; - showpotioneffects = !showpotioneffects; + showPotionEffects = !showPotionEffects; } - if (input.inputPressed("simpPotionEffects")) { - simpPotionEffects = !simpPotionEffects; + if (input.inputPressed("SIMPLIFY-POTION-EFFECTS")) { + simplifyPotionEffects = !simplifyPotionEffects; } - if (input.inputPressed("toggleHUD")) { + if (input.inputPressed("TOGGLE-HUD")) { renderGUI = !renderGUI; } - if (input.inputPressed("expandQuestDisplay")) { + if (input.inputPressed("EXPAND-QUEST-DISPLAY")) { questExpanding = 30; } @@ -433,7 +428,8 @@ public void tick() { if (hunger == 0 && health > minStarveHealth[diffIdx]) { if (hungerStarveDelay > 0) hungerStarveDelay--; if (hungerStarveDelay == 0) { - directHurt(1, Direction.NONE); // Do 1 damage to the player + hurt(new DamageSource(DamageSource.DamageType.STARVE), + Direction.NONE, 1); // Do 1 damage to the player } } } @@ -486,7 +482,9 @@ public void tick() { if (isSwimming() && tickTime % 60 == 0 && !potioneffects.containsKey(PotionType.Swim)) { // If drowning... :P if (stamina > 0) payStamina(1); // Take away stamina - else directHurt(1, Direction.NONE); // If no stamina, take damage. + else + hurt(new DamageSource(DamageSource.DamageType.DROWN), + Direction.NONE, 1); // If no stamina, take damage. } if (activeItem != null && (input.inputPressed("drop-one") || input.inputPressed("drop-stack"))) { @@ -507,28 +505,36 @@ public void tick() { level.dropItem(x, y, drop); } - if ((activeItem == null || !activeItem.used_pending) && (input.inputPressed("attack")) && stamina != 0 && onFallDelay <= 0) { // This only allows attacks when such action is possible. + if (input.inputPressed("attack") && stamina != 0 && onFallDelay <= 0) { // This only allows attacks when such action is possible. if (!potioneffects.containsKey(PotionType.Energy)) stamina--; staminaRecharge = 0; attack(); } - if ((input.inputPressed("menu") || input.inputPressed("craft")) && activeItem != null) { - tryAddToInvOrDrop(activeItem); + if (input.inputPressed("USE") && stamina != 0 && onFallDelay <= 0) { // This only allows interactions when such action is possible. + if (!potioneffects.containsKey(PotionType.Energy)) stamina--; + staminaRecharge = 0; - activeItem = null; - if (isFishing) { - isFishing = false; - fishingTicks = maxFishingTicks; - } + use(); + } + + if (input.inputPressed("pickup") && (activeItem == null) && stamina != 0 && onFallDelay <= 0) { + if (!potioneffects.containsKey(PotionType.Energy)) stamina--; + staminaRecharge = 0; + + pickup(); + } + + if ((input.inputPressed("INVENTORY") || input.inputPressed("craft")) && activeItem != null) { + resolveHoldingItem(); } if (Game.getDisplay() == null) { - if (input.inputPressed("craft") && !use()) { + if (input.inputPressed("craft")) { // obtain SHIFT modifier input with E Game.setDisplay(new CraftingDisplay(Recipes.craftRecipes, "minicraft.displays.crafting", this, true)); return; - } else if (input.inputPressed("menu") && !use()) { // !use() = no furniture in front of the player; this prevents player inventory from opening (will open furniture inventory instead) + } else if (input.inputPressed("INVENTORY")) { Game.setDisplay(new PlayerInvDisplay(this)); return; } else if (input.inputPressed("pause")) { @@ -539,7 +545,7 @@ public void tick() { return; } - if (input.inputDown("quicksave") && !Updater.saving) { + if (input.inputDown("QUICK-SAVE") && !Updater.saving) { Updater.saving = true; LoadingDisplay.setPercentage(0); new Save(WorldSelectDisplay.getWorldName()); @@ -550,44 +556,26 @@ public void tick() { PotionItem.applyPotion(this, potionType, false); } } - - if (input.inputPressed("pickup") && (activeItem == null || !activeItem.used_pending)) { - if (!(activeItem instanceof PowerGloveItem)) { // If you are not already holding a power glove (aka in the middle of a separate interaction)... - prevItem = activeItem; // Then save the current item... - if (isFishing) { - isFishing = false; - fishingTicks = maxFishingTicks; - } - activeItem = new PowerGloveItem(); // and replace it with a power glove. - } - attack(); // Attack (with the power glove) - resolveHeldItem(); - } } if (attackTime > 0) { attackTime--; - if (attackTime == 0) attackItem = null; // null the attackItem once we are done attacking. } } } /** - * Removes an held item and places it back into the inventory. - * Looks complicated to so it can handle the powerglove. + * Removes a holding item and places it back into the inventory. */ - public void resolveHeldItem() { - if (!(activeItem instanceof PowerGloveItem)) { // If you are now holding something other than a power glove... - if (prevItem != null) { // and you had a previous item that we should care about... - tryAddToInvOrDrop(prevItem); // Then add that previous item to your inventory so it isn't lost. - } // If something other than a power glove is being held, but the previous item is null, then nothing happens; nothing added to inventory, and current item remains as the new one. - } else - activeItem = prevItem; // Otherwise, if you're holding a power glove, then the held item didn't change, so we can remove the power glove and make it what it was before. - - prevItem = null; // This is no longer of use. - - if (activeItem instanceof PowerGloveItem) // If, for some odd reason, you are still holding a power glove at this point, then null it because it's useless and shouldn't remain in hand. - activeItem = null; + public void resolveHoldingItem() { + if (activeItem != null) { + tryAddToInvOrDrop(activeItem); + activeItem = null; // Removed + if (isFishing) { + isFishing = false; + fishingTicks = maxFishingTicks; + } + } } /** @@ -596,17 +584,11 @@ public void resolveHeldItem() { protected void attack() { // walkDist is not synced, so this can happen for both the client and server. walkDist += 8; // Increase the walkDist (changes the sprite, like you moved your arm) + attackTime = activeItem == null ? 5 : 10; - if (isFishing) { - isFishing = false; - fishingTicks = maxFishingTicks; - } - - if (activeItem != null && !activeItem.interactsWithWorld()) { - attackDir = dir; // Make the attack direction equal the current direction - attackItem = activeItem; // Make attackItem equal activeItem - activeItem.interactOn(Tiles.get("rock"), level, 0, 0, this, attackDir); - if (activeItem.isDepleted()) { + // If the interaction between you and an entity is successful, then return. + if (attack(getInteractionBox(INTERACT_DIST))) { + if (activeItem != null && activeItem.isDepleted()) { activeItem = null; if (isFishing) { isFishing = false; @@ -614,91 +596,90 @@ protected void attack() { } } return; - } - - attackDir = dir; // Make the attack direction equal the current direction - attackItem = activeItem; // Make attackItem equal activeItem - - // If we are holding an item. - if (activeItem != null) { - attackTime = 10; - boolean done = false; - - // Fire a bow if we have the stamina and an arrow. - if (activeItem instanceof ToolItem && stamina - 1 >= 0) { - ToolItem tool = (ToolItem) activeItem; - if (tool.type == ToolType.Bow && tool.dur > 0 && inventory.count(Items.arrowItem) > 0) { + } // Then there is no entity hitbox blocking the player hitting the tile. - inventory.removeItem(Items.arrowItem); - level.add(new Arrow(this, attackDir, tool.level)); - attackTime = 10; + // Attempt to interact with the tile. + Point t = getInteractionTile(); - if (!Game.isMode("minicraft.settings.mode.creative")) tool.dur--; - - AchievementsDisplay.setAchievement("minicraft.achievement.bow", true); + // If the target coordinates are a valid tile. + if (t.x >= 0 && t.y >= 0 && t.x < level.w && t.y < level.h) { + Tile tile = level.getTile(t.x, t.y); + boolean successful = false; + if (activeItem != null && activeItem.attackOn(tile, level, t.x, t.y, this, dir)) + successful = true; + if (tile.hurt(level, t.x, t.y, this, activeItem, dir, random.nextInt(baseDamage() + 1))) + successful = true; + if (successful) + Logging.PLAYER.info("Attacked tile {} at ({}, {}, {}) with {}", tile, level.depth, t.x, t.y, activeItem); - return; + if (successful && activeItem != null && activeItem.isDepleted()) { + // If the activeItem has 0 items left, then "destroy" it. + activeItem = null; + if (isFishing) { + isFishing = false; + fishingTicks = maxFishingTicks; } } + } + } - // If the interaction between you and an entity is successful, then return. - if (interact(getInteractionBox(INTERACT_DIST))) { - if (activeItem.isDepleted()) - activeItem = null; - return; - } - - // Attempt to interact with the tile. - Point t = getInteractionTile(); - - // If the target coordinates are a valid tile. - if (t.x >= 0 && t.y >= 0 && t.x < level.w && t.y < level.h) { + protected void use() { + // walkDist is not synced, so this can happen for both the client and server. + walkDist += 8; // Increase the walkDist (changes the sprite, like you moved your arm) + attackTime = activeItem == null ? 5 : 10; - // Get any entities (except dropped items and particles) on the tile. - List tileEntities = level.getEntitiesInTiles(t.x, t.y, t.x, t.y, false, ItemEntity.class, Particle.class); + if (isFishing) { + isFishing = false; + fishingTicks = maxFishingTicks; + } - // If there are no other entities than us on the tile. - if (tileEntities.size() == 0 || tileEntities.size() == 1 && tileEntities.get(0) == this) { - Tile tile = level.getTile(t.x, t.y); + // If the interaction between you and an entity is successful, then return. + if (use(getInteractionBox(INTERACT_DIST))) return; - // If the item successfully interacts with the target tile. - if (activeItem.interactOn(tile, level, t.x, t.y, this, attackDir)) { - done = true; + // Attempt to interact with the tile. + Point t = getInteractionTile(); - // Returns true if the target tile successfully interacts with the item. - } else if (tile.interact(level, t.x, t.y, this, activeItem, attackDir)) { - done = true; - } - } + // If the target coordinates are a valid tile. + if (t.x >= 0 && t.y >= 0 && t.x < level.w && t.y < level.h) { + Tile tile = level.getTile(t.x, t.y); + boolean successful = false; + if (activeItem != null && activeItem.useOn(tile, level, t.x, t.y, this, dir)) + successful = true; + if (tile.use(level, t.x, t.y, this, activeItem, dir)) + successful = true; + if (successful) + Logging.PLAYER.info("Used item {} on tile ({}, {}, {}).", activeItem, level.depth, t.x, t.y); - if (activeItem.isDepleted()) { - // If the activeItem has 0 items left, then "destroy" it. - activeItem = null; - if (isFishing) { - isFishing = false; - fishingTicks = maxFishingTicks; - } + if (successful && activeItem != null && activeItem.isDepleted()) { + // If the activeItem has 0 items left, then "destroy" it. + activeItem = null; + if (isFishing) { + isFishing = false; + fishingTicks = maxFishingTicks; } } - if (done) return; // Skip the rest if interaction was handled } + } - if (activeItem == null || activeItem.canAttack()) { // If there is no active item, OR if the item can be used to attack... - attackTime = 5; - // Attacks the enemy in the appropriate direction. - boolean used = hurt(getInteractionBox(ATTACK_DIST)); + protected void pickup() { + List entities = level.getEntitiesInRect(getInteractionBox(INTERACT_DIST)); // Gets the entities within the 4 points + boolean blocked = false; + for (Entity e : entities) + if (e != this) { + blocked |= !(e instanceof ItemEntity || e instanceof Particle); + if ((activeItem = e.take(this)) != null) + return; + } - // Attempts to hurt the tile in the appropriate direction. + if (!blocked) { + // Attempt to interact with the tile. Point t = getInteractionTile(); - // Check if tile is in bounds of the map. + // If the target coordinates are a valid tile. if (t.x >= 0 && t.y >= 0 && t.x < level.w && t.y < level.h) { Tile tile = level.getTile(t.x, t.y); - used = tile.hurt(level, t.x, t.y, this, random.nextInt(3) + 1, attackDir) || used; + activeItem = tile.take(level, t.x, t.y, this); } - - if (used && activeItem instanceof ToolItem) - ((ToolItem) activeItem).payDurability(); } } @@ -781,63 +762,40 @@ private void goFishing() { fishingTicks = maxFishingTicks; // If you didn't catch anything, try again in 120 ticks } - private boolean use() { - return use(getInteractionBox(INTERACT_DIST)); - } - - /** - * called by other use method; this serves as a buffer in case there is no entity in front of the player. - */ + /** called by other use method; this serves as a buffer in case there is no entity in front of the player. */ private boolean use(Rectangle area) { List entities = level.getEntitiesInRect(area); // Gets the entities within the 4 points for (Entity e : entities) { - if (e instanceof Furniture && ((Furniture) e).use(this)) - return true; // If the entity is not the player, then call it's use method, and return the result. Only some furniture classes use this. + if (e != this && e.use(this, activeItem, dir)) + return true; // If the entity is not the player, then call it's use method, and return the result. } return false; } - /** - * same, but for interaction. - */ - private boolean interact(Rectangle area) { - List entities = level.getEntitiesInRect(area); - for (Entity e : entities) { - if (e != this && e.interact(this, activeItem, attackDir)) - return true; // This is the ONLY place that the Entity.interact method is actually called. - } - return false; - } - - /** - * same, but for attacking. - */ - private boolean hurt(Rectangle area) { + /** called by other attack method; this serves as a buffer in case there is no entity in front of the player. */ + private boolean attack(Rectangle area) { List entities = level.getEntitiesInRect(area); - int maxDmg = 0; + boolean blocked = false; for (Entity e : entities) { - if (e != this && e instanceof Mob) { - int dmg = getAttackDamage(e); - maxDmg = Math.max(dmg, maxDmg); - ((Mob) e).hurt(this, dmg, attackDir); + if (e != this && e.isAttackable(this, activeItem, dir) && + !e.isInvulnerableTo(new DamageSource(DamageSource.DamageType.GENERIC, this, activeItem))) { + blocked |= !(e instanceof ItemEntity || e instanceof Particle); + if (attack(e)) { + Logging.PLAYER.info("Attacked {} with {}.", e, activeItem); + } } - if (e instanceof Furniture) - e.interact(this, null, attackDir); } - return maxDmg > 0; + // Returns whether there is any entity hitbox blocking interaction on target tile + return blocked; } - /** - * Calculates how much damage the player will do. - * @param e Entity being attacked. - * @return How much damage the player does. - */ - private int getAttackDamage(Entity e) { - int dmg = random.nextInt(2) + 1; + @Override + public boolean attack(Entity entity) { + int dmg = random.nextInt(2) + baseDamage(); if (activeItem != null && activeItem instanceof ToolItem) { - dmg += ((ToolItem) activeItem).getAttackDamageBonus(e); // Sword/Axe are more effective at dealing damage. + dmg += ((ToolItem) activeItem).getAttackDamageBonus(entity); // Sword/Axe are more effective at dealing damage. } - return dmg; + return entity.hurt(new DamageSource(DamageSource.DamageType.GENERIC, this, activeItem), dir, dmg); } /** @@ -921,33 +879,33 @@ public void render(Screen screen) { // Renders slashes: if (attackTime > 0) { - switch (attackDir) { + switch (dir) { case UP: // If currently attacking upwards... screen.render(xo + 0, yo - 4, 3, 0, 0, hudSheet.getSheet()); // Render left half-slash screen.render(xo + 8, yo - 4, 3, 0, 1, hudSheet.getSheet()); // Render right half-slash (mirror of left). - if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { // If the player had an item when they last attacked... - screen.render(xo + 4, yo - 4, attackItem.sprite.getSprite(), 1, false); // Then render the icon of the item, mirrored + if (activeItem != null) { // If the player had an item when they last attacked... + screen.render(xo + 4, yo - 4, activeItem.sprite.getSprite(), 1, false); // Then render the icon of the item, mirrored } break; case LEFT: // Attacking to the left... (Same as above) screen.render(xo - 4, yo, 4, 0, 1, hudSheet.getSheet()); screen.render(xo - 4, yo + 8, 4, 0, 3, hudSheet.getSheet()); - if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { - screen.render(xo - 4, yo + 4, attackItem.sprite.getSprite(), 1, false); + if (activeItem != null) { + screen.render(xo - 4, yo + 4, activeItem.sprite.getSprite(), 1, false); } break; case RIGHT: // Attacking to the right (Same as above) screen.render(xo + 8 + 4, yo, 4, 0, 0, hudSheet.getSheet()); screen.render(xo + 8 + 4, yo + 8, 4, 0, 2, hudSheet.getSheet()); - if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { - screen.render(xo + 8 + 4, yo + 4, attackItem.sprite.getSprite()); + if (activeItem != null) { + screen.render(xo + 8 + 4, yo + 4, activeItem.sprite.getSprite()); } break; case DOWN: // Attacking downwards (Same as above) screen.render(xo + 0, yo + 8 + 4, 3, 0, 2, hudSheet.getSheet()); screen.render(xo + 8, yo + 8 + 4, 3, 0, 3, hudSheet.getSheet()); - if (attackItem != null && !(attackItem instanceof PowerGloveItem)) { - screen.render(xo + 4, yo + 8 + 4, attackItem.sprite.getSprite()); + if (activeItem != null) { + screen.render(xo + 4, yo + 8 + 4, activeItem.sprite.getSprite()); } break; case NONE: @@ -956,7 +914,7 @@ public void render(Screen screen) { } // Renders the fishing rods when fishing - if (isFishing) { + if (isFishing && activeItem != null) { switch (dir) { case UP: screen.render(xo + 4, yo - 4, activeItem.sprite.getSprite(), 1, false); @@ -989,6 +947,7 @@ public void pickupItem(ItemEntity itemEntity) { boolean successful = false; // If there is any item successfully added to the player boolean remove = false; // Whether to remove the item entity (when empty) if (itemEntity.item instanceof StackableItem && ((StackableItem) itemEntity.item).stacksWith(activeItem)) { // Picked up item equals the one in your hand + assert activeItem != null; int toAdd = Math.min(((StackableItem) activeItem).count + ((StackableItem) itemEntity.item).count, ((StackableItem) activeItem).maxCount) - ((StackableItem) activeItem).count; if (toAdd > 0) { @@ -1126,6 +1085,21 @@ public int getLightRadius() { return r; // Return light radius } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return true; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return true; + } + + @Override + public boolean isUsable() { + return false; + } + /** * What happens when the player dies */ @@ -1156,19 +1130,15 @@ public void onExploded(Tnt tnt, int dmg) { payStamina(dmg * 2); } - /** - * Hurt the player. - * @param damage How much damage to do to player. - * @param attackDir What direction to attack. - */ - public void hurt(int damage, Direction attackDir) { - doHurt(damage, attackDir); + @Override + public boolean isFireImmune() { + return potioneffects.containsKey(PotionType.Lava); } @Override - protected void doHurt(int damage, Direction attackDir) { + public boolean hurt(DamageSource source, Direction attackDir, int damage) { if (Game.isMode("minicraft.settings.mode.creative") || hurtTime > 0 || Bed.inBed(this)) - return; // Can't get hurt in creative, hurt cooldown, or while someone is in bed + return false; // Can't get hurt in creative, hurt cooldown, or while someone is in bed int healthDam = 0, armorDam = 0; if (this == Game.player) { @@ -1199,34 +1169,12 @@ protected void doHurt(int damage, Direction attackDir) { if (healthDam > 0 || this != Game.player) { level.add(new TextParticle("" + damage, x, y, Color.get(-1, 504))); - if (this == Game.player) super.doHurt(healthDam, attackDir); // Sets knockback, and takes away health. - } - - Sound.play("playerhurt"); - hurtTime = playerHurtTime; - } - - /** - * Hurt the player directly. Don't use the armor as a shield. - * @param damage Amount of damage to do to player - * @param attackDir The direction of attack. - */ - private void directHurt(int damage, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative") || hurtTime > 0 || Bed.inBed(this)) - return; // Can't get hurt in creative, hurt cooldown, or while someone is in bed - - int healthDam = 0; - if (this == Game.player) { - healthDam = damage; // Subtract that amount - } - - if (healthDam > 0 || this != Game.player) { - level.add(new TextParticle("" + damage, x, y, Color.get(-1, 504))); - if (this == Game.player) super.doHurt(healthDam, attackDir); // Sets knockback, and takes away health. + if (this == Game.player) handleDamage(source, attackDir, healthDam); // Sets knockback, and takes away health. } Sound.play("playerhurt"); hurtTime = playerHurtTime; + return true; } @Override diff --git a/src/client/java/minicraft/entity/mob/Sheep.java b/src/client/java/minicraft/entity/mob/Sheep.java index 63a18cc3a..0960252b3 100644 --- a/src/client/java/minicraft/entity/mob/Sheep.java +++ b/src/client/java/minicraft/entity/mob/Sheep.java @@ -5,6 +5,7 @@ import minicraft.core.io.Settings; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.item.Item; @@ -77,7 +78,8 @@ public void tick() { } } - public boolean interact(Player player, @Nullable Item item, Direction attackDir) { + @Override + public boolean use(Player player, @Nullable Item item, Direction attackDir) { if (item instanceof ToolItem) { if (!cut && ((ToolItem) item).type == ToolType.Shears) { cut = true; diff --git a/src/client/java/minicraft/entity/mob/Snake.java b/src/client/java/minicraft/entity/mob/Snake.java index 81c66b340..c4f65ccf4 100644 --- a/src/client/java/minicraft/entity/mob/Snake.java +++ b/src/client/java/minicraft/entity/mob/Snake.java @@ -4,6 +4,7 @@ import minicraft.entity.Entity; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.item.Items; +import minicraft.util.DamageSource; public class Snake extends EnemyMob { private static LinkedSprite[][][] sprites = new LinkedSprite[][][] { @@ -18,11 +19,9 @@ public Snake(int lvl) { } @Override - protected void touchedBy(Entity entity) { - if (entity instanceof Player) { - int damage = lvl + Settings.getIdx("diff"); - ((Player) entity).hurt(this, damage); - } + public boolean attack(Entity entity) { + return hurt(new DamageSource( DamageSource.DamageType.GENERIC,this, null), dir, + lvl + Settings.getIdx("diff")); } public void die() { diff --git a/src/client/java/minicraft/entity/particle/Particle.java b/src/client/java/minicraft/entity/particle/Particle.java index 04e0382ec..209262efb 100644 --- a/src/client/java/minicraft/entity/particle/Particle.java +++ b/src/client/java/minicraft/entity/particle/Particle.java @@ -1,10 +1,16 @@ package minicraft.entity.particle; import minicraft.entity.ClientTickable; +import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.util.DamageSource; import minicraft.util.Logging; +import org.jetbrains.annotations.Nullable; import javax.security.auth.DestroyFailedException; @@ -58,4 +64,27 @@ public void render(Screen screen) { public boolean isSolid() { return false; } + + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } } diff --git a/src/client/java/minicraft/item/ArmorItem.java b/src/client/java/minicraft/item/ArmorItem.java index 80304ef3f..829e49c94 100644 --- a/src/client/java/minicraft/item/ArmorItem.java +++ b/src/client/java/minicraft/item/ArmorItem.java @@ -39,7 +39,7 @@ private ArmorItem(String name, LinkedSprite sprite, int count, float health, int staminaCost = 9; } - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; if (player.curArmor == null && player.payStamina(staminaCost)) { player.curArmor = this; // Set the current armor being worn to this. @@ -50,11 +50,6 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, return super.interactOn(success); } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull ArmorItem copy() { return new ArmorItem(getName(), sprite, count, armor, level); } diff --git a/src/client/java/minicraft/item/BookItem.java b/src/client/java/minicraft/item/BookItem.java index 2a3b8bf4d..9f9bafff2 100644 --- a/src/client/java/minicraft/item/BookItem.java +++ b/src/client/java/minicraft/item/BookItem.java @@ -41,16 +41,11 @@ private BookItem(String title, LinkedSprite sprite, BookContent book, boolean ha this.hasTitlePage = hasTitlePage; } - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { Game.setDisplay(new BookDisplay(book.collect(), hasTitlePage)); return true; } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull BookItem copy() { return new BookItem(getName(), sprite, book, hasTitlePage); } diff --git a/src/client/java/minicraft/item/BucketItem.java b/src/client/java/minicraft/item/BucketItem.java index 608c6e8c2..5b21e5bd8 100644 --- a/src/client/java/minicraft/item/BucketItem.java +++ b/src/client/java/minicraft/item/BucketItem.java @@ -57,7 +57,7 @@ private BucketItem(Fill fill, int count) { this.filling = fill; } - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { Fill fill = getFilling(tile); if (fill == null) return false; diff --git a/src/client/java/minicraft/item/ClothingItem.java b/src/client/java/minicraft/item/ClothingItem.java index f23922640..36fbc62dc 100644 --- a/src/client/java/minicraft/item/ClothingItem.java +++ b/src/client/java/minicraft/item/ClothingItem.java @@ -42,7 +42,7 @@ private ClothingItem(String name, int count, LinkedSprite sprite, int pcol) { } // Put on clothes - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (player.shirtColor == playerCol) { return false; } else { @@ -60,11 +60,6 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, } } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull ClothingItem copy() { return new ClothingItem(getName(), count, sprite, playerCol); } diff --git a/src/client/java/minicraft/item/FishingRodItem.java b/src/client/java/minicraft/item/FishingRodItem.java index 957ed1017..4f5148965 100644 --- a/src/client/java/minicraft/item/FishingRodItem.java +++ b/src/client/java/minicraft/item/FishingRodItem.java @@ -58,7 +58,7 @@ public static int getChance(int idx, int level) { } @Override - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (tile == Tiles.get("water") && !player.isSwimming()) { // Make sure not to use it if swimming uses++; player.isFishing = true; @@ -69,11 +69,6 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, return false; } - @Override - public boolean canAttack() { - return false; - } - @Override public boolean isDepleted() { if (random.nextInt(100) > 120 - uses + level * 6) { // Breaking is random, the lower the level, and the more times you use it, the higher the chance diff --git a/src/client/java/minicraft/item/FoodItem.java b/src/client/java/minicraft/item/FoodItem.java index 1be9c9e81..58c0e88e7 100644 --- a/src/client/java/minicraft/item/FoodItem.java +++ b/src/client/java/minicraft/item/FoodItem.java @@ -44,7 +44,7 @@ private FoodItem(String name, LinkedSprite sprite, int count, int feed) { /** * What happens when the player uses the item on a tile */ - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; if (count > 0 && player.hunger < Player.maxHunger && player.payStamina(staminaCost)) { // If the player has hunger to fill, and stamina to pay... player.hunger = Math.min(player.hunger + feed, Player.maxHunger); // Restore the hunger @@ -54,11 +54,6 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, return super.interactOn(success); } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull FoodItem copy() { return new FoodItem(getName(), sprite, count, feed); } diff --git a/src/client/java/minicraft/item/FurnitureItem.java b/src/client/java/minicraft/item/FurnitureItem.java index a6bcb86df..37157cf75 100644 --- a/src/client/java/minicraft/item/FurnitureItem.java +++ b/src/client/java/minicraft/item/FurnitureItem.java @@ -77,17 +77,8 @@ public FurnitureItem(Furniture furniture) { placed = false; } - /** - * Determines if you can attack enemies with furniture (you can't) - */ - public boolean canAttack() { - return false; - } - - /** - * What happens when you press the "Attack" key with the furniture in your hands - */ - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + /** What happens when you press the "Attack" key with the furniture in your hands */ + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (tile.mayPass(level, xt, yt, furniture)) { // If the furniture can go on the tile Sound.play("craft"); diff --git a/src/client/java/minicraft/item/HeartItem.java b/src/client/java/minicraft/item/HeartItem.java index 632d5d2b3..ffda1e028 100644 --- a/src/client/java/minicraft/item/HeartItem.java +++ b/src/client/java/minicraft/item/HeartItem.java @@ -36,7 +36,7 @@ private HeartItem(String name, SpriteLinker.LinkedSprite sprite, int count, int /** * What happens when the player uses the item on a tile */ - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; if ((Player.baseHealth + Player.extraHealth) < Player.maxHealth) { @@ -51,11 +51,6 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, return super.interactOn(success); } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull HeartItem copy() { return new HeartItem(getName(), sprite, count, health); } diff --git a/src/client/java/minicraft/item/Item.java b/src/client/java/minicraft/item/Item.java index 2761d3b2c..4605f0b31 100644 --- a/src/client/java/minicraft/item/Item.java +++ b/src/client/java/minicraft/item/Item.java @@ -19,7 +19,7 @@ public abstract class Item { private final String name; public LinkedSprite sprite; - public boolean used_pending = false; // This is for multiplayer, when an item has been used, and is pending server response as to the outcome, this is set to true so it cannot be used again unless the server responds that the item wasn't used. Which should basically replace the item anyway, soo... yeah. this never gets set back. +// public boolean used_pending = false; // This is for multiplayer, when an item has been used, and is pending server response as to the outcome, this is set to true so it cannot be used again unless the server responds that the item wasn't used. Which should basically replace the item anyway, soo... yeah. this never gets set back. protected Item(String name) { sprite = SpriteLinker.missingTexture(SpriteType.Item); @@ -40,24 +40,20 @@ public void renderHUD(Screen screen, int x, int y, int fontColor) { Font.drawBackground(dispName, screen, x + 8, y, fontColor); } - /** - * Determines what happens when the player interacts with a tile - */ - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + /** Determines what happens when the player attacks a tile */ + public boolean attackOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { return false; } - /** - * Returning true causes this item to be removed from the player's active item slot - */ - public boolean isDepleted() { + /** Determines what happens when the player interacts with a tile */ + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { return false; } /** - * Returns if the item can attack mobs or not + * Returning true causes this item to be removed from the player's active item slot */ - public boolean canAttack() { + public boolean isDepleted() { return false; } @@ -106,8 +102,4 @@ public final String getName() { public String getDisplayName() { return " " + Localization.getLocalized(getName()); } - - public boolean interactsWithWorld() { - return true; - } } diff --git a/src/client/java/minicraft/item/PotionItem.java b/src/client/java/minicraft/item/PotionItem.java index 55ca3775e..e3e0316fb 100644 --- a/src/client/java/minicraft/item/PotionItem.java +++ b/src/client/java/minicraft/item/PotionItem.java @@ -35,7 +35,7 @@ private PotionItem(PotionType type, int count) { } // The return value is used to determine if the potion was used, which means being discarded. - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (type.equals(PotionType.Lava)) { AchievementsDisplay.setAchievement("minicraft.achievement.lava", true); } @@ -78,11 +78,6 @@ public int hashCode() { return super.hashCode() + type.name.hashCode(); } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull PotionItem copy() { return new PotionItem(type, count); } diff --git a/src/client/java/minicraft/item/PotionType.java b/src/client/java/minicraft/item/PotionType.java index 67714a2be..45bc30019 100644 --- a/src/client/java/minicraft/item/PotionType.java +++ b/src/client/java/minicraft/item/PotionType.java @@ -31,7 +31,7 @@ public boolean toggleEffect(Player player, boolean addEffect) { Time(Color.get(1, 163), 1800), Lava(Color.get(1, 199, 58, 58), 7200), Shield(Color.get(1, 84, 84, 204), 5400), - Haste(Color.get(1, 201, 71, 201), 4800), + Haste(Color.get(1, 201, 71, 201), 4800), // Currently no use Escape(Color.get(1, 222, 162, 162), 0) { public boolean toggleEffect(Player player, boolean addEffect) { diff --git a/src/client/java/minicraft/item/SummonItem.java b/src/client/java/minicraft/item/SummonItem.java index bf0d73df0..04280660b 100644 --- a/src/client/java/minicraft/item/SummonItem.java +++ b/src/client/java/minicraft/item/SummonItem.java @@ -43,7 +43,7 @@ private SummonItem(String name, LinkedSprite sprite, int count, String mob) { /** * What happens when the player uses the item on a tile */ - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; switch (mob) { @@ -109,11 +109,6 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, return super.interactOn(success); } - @Override - public boolean interactsWithWorld() { - return false; - } - public @NotNull SummonItem copy() { return new SummonItem(getName(), sprite, count, mob); } diff --git a/src/client/java/minicraft/item/TileItem.java b/src/client/java/minicraft/item/TileItem.java index c6e1d87b4..4a5ab3c78 100644 --- a/src/client/java/minicraft/item/TileItem.java +++ b/src/client/java/minicraft/item/TileItem.java @@ -160,7 +160,7 @@ public static int getTileData(@Nullable TileModel model, Tile tile, Tile target, } } - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { for (String tilename : validTiles) { if (tile.matches(level.getData(xt, yt), tilename)) { Tile t = TileModel.getTile(model); diff --git a/src/client/java/minicraft/item/ToolItem.java b/src/client/java/minicraft/item/ToolItem.java index 6a8c945db..53b4c8bcb 100644 --- a/src/client/java/minicraft/item/ToolItem.java +++ b/src/client/java/minicraft/item/ToolItem.java @@ -2,10 +2,17 @@ import minicraft.core.Game; import minicraft.core.io.Localization; +import minicraft.entity.Arrow; +import minicraft.entity.Direction; import minicraft.entity.Entity; +import minicraft.entity.furniture.Spawner; import minicraft.entity.mob.Mob; +import minicraft.entity.mob.Player; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.screen.AchievementsDisplay; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -76,11 +83,19 @@ public boolean isDepleted() { return dur <= 0 && type.durability > 0; } - /** - * You can attack mobs with tools. - */ - public boolean canAttack() { - return type != ToolType.Shears; + @Override + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + Inventory inventory = player.getInventory(); + // Fire a bow if the player has the stamina and an arrow. + if (type == ToolType.Bow && player.payStamina(1) && inventory.count(Items.arrowItem) > 0) { + inventory.removeItem(Items.arrowItem); + level.add(new Arrow(player, attackDir, this.level)); + if (!Game.isMode("minicraft.settings.mode.creative")) dur--; + AchievementsDisplay.setAchievement("minicraft.achievement.bow",true); + return true; + } + + return super.useOn(tile, level, xt, yt, player, attackDir); } public boolean payDurability() { @@ -110,6 +125,11 @@ public int getAttackDamageBonus(Entity e) { } else if (type == ToolType.Pickaxe) return (level + 1) + random.nextInt(2); // Wood: 3-6 damage; gem: 15-66 damage. return 1; + } else if (e instanceof Spawner) { + if (type == ToolType.Pickaxe) { + return 3 + level + random.nextInt(7); + } else + return 1 + level + random.nextInt(2); } return 0; diff --git a/src/client/java/minicraft/item/WateringCanItem.java b/src/client/java/minicraft/item/WateringCanItem.java index 8786ab011..fb50c1042 100644 --- a/src/client/java/minicraft/item/WateringCanItem.java +++ b/src/client/java/minicraft/item/WateringCanItem.java @@ -46,7 +46,7 @@ protected WateringCanItem(String name) { } @Override - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + public boolean useOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (tile instanceof WaterTile) { content = CAPACITY; updateSprite(); diff --git a/src/client/java/minicraft/level/tile/BossDoorTile.java b/src/client/java/minicraft/level/tile/BossDoorTile.java index 581030dd5..71e0f444e 100644 --- a/src/client/java/minicraft/level/tile/BossDoorTile.java +++ b/src/client/java/minicraft/level/tile/BossDoorTile.java @@ -4,12 +4,14 @@ import minicraft.core.io.Localization; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.entity.mob.ObsidianKnight; import minicraft.entity.mob.Player; import minicraft.item.Item; import minicraft.item.ToolItem; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class BossDoorTile extends DoorTile { private static final String doorMsg = "minicraft.notification.defeat_obsidian_knight_first"; @@ -18,12 +20,13 @@ protected BossDoorTile() { super(Material.Obsidian, "Boss Door"); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if ((!ObsidianKnight.beaten || ObsidianKnight.active) && !Game.isMode("minicraft.settings.mode.creative")) { + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if ((!ObsidianKnight.beaten || ObsidianKnight.active) && !Game.isMode("minicraft.settings.mode.creative") && source instanceof Player) { if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(1)) { + if (((Player) source).payStamina(1)) { Game.notifications.add(Localization.getLocalized(doorMsg)); Sound.play("monsterhurt"); return true; @@ -34,18 +37,16 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D return false; } - return super.interact(level, xt, yt, player, item, attackDir); + return super.hurt(level, x, y, source, item, attackDir, damage); } @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - if (source instanceof Player) { - if (ObsidianKnight.active && !Game.isMode("minicraft.settings.mode.creative")) { - Game.notifications.add(doorMsg); - return true; - } + public boolean use(Level level, int xt, int yt, Player player, @Nullable Item item, Direction attackDir) { + if (ObsidianKnight.active && !Game.isMode("minicraft.settings.mode.creative")) { + Game.notifications.add(doorMsg); + return true; } - return super.hurt(level, x, y, source, dmg, attackDir); + return super.use(level, xt, yt, player, item, attackDir); } } diff --git a/src/client/java/minicraft/level/tile/BossFloorTile.java b/src/client/java/minicraft/level/tile/BossFloorTile.java index b7ac654c5..95393ed26 100644 --- a/src/client/java/minicraft/level/tile/BossFloorTile.java +++ b/src/client/java/minicraft/level/tile/BossFloorTile.java @@ -4,11 +4,13 @@ import minicraft.core.io.Localization; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.ObsidianKnight; import minicraft.entity.mob.Player; import minicraft.item.Item; import minicraft.item.ToolItem; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class BossFloorTile extends FloorTile { private static final String floorMsg = "minicraft.notification.defeat_obsidian_knight_first"; @@ -17,12 +19,13 @@ protected BossFloorTile() { super(Material.Obsidian, "Boss Floor"); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if ((!ObsidianKnight.beaten || ObsidianKnight.active) && !Game.isMode("minicraft.settings.mode.creative")) { + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if ((!ObsidianKnight.beaten || ObsidianKnight.active) && !Game.isMode("minicraft.settings.mode.creative") && source instanceof Player) { if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(1)) { + if (((Player) source).payStamina(1)) { Game.notifications.add(Localization.getLocalized(floorMsg)); Sound.play("monsterhurt"); return true; @@ -33,6 +36,6 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D return false; } - return super.interact(level, xt, yt, player, item, attackDir); + return super.hurt(level, x, y, source, item, attackDir, damage); } } diff --git a/src/client/java/minicraft/level/tile/BossWallTile.java b/src/client/java/minicraft/level/tile/BossWallTile.java index 54c2d7f82..b0c2c843c 100644 --- a/src/client/java/minicraft/level/tile/BossWallTile.java +++ b/src/client/java/minicraft/level/tile/BossWallTile.java @@ -4,6 +4,7 @@ import minicraft.core.io.Localization; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.ObsidianKnight; import minicraft.entity.mob.Player; import minicraft.gfx.SpriteAnimation; @@ -11,6 +12,7 @@ import minicraft.item.Item; import minicraft.item.ToolItem; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class BossWallTile extends WallTile { private static SpriteAnimation obsidian = new SpriteAnimation(SpriteLinker.SpriteType.Tile, "obsidian_wall") @@ -23,12 +25,13 @@ protected BossWallTile() { sprite = obsidian; // Renewing the connectivity. } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if ((!ObsidianKnight.beaten || ObsidianKnight.active) && !Game.isMode("minicraft.settings.mode.creative")) { + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if ((!ObsidianKnight.beaten || ObsidianKnight.active) && !Game.isMode("minicraft.settings.mode.creative") && source instanceof Player) { if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(1)) { + if (((Player) source).payStamina(1)) { Game.notifications.add(Localization.getLocalized(wallMsg)); Sound.play("monsterhurt"); return true; @@ -39,6 +42,6 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D return false; } - return super.interact(level, xt, yt, player, item, attackDir); + return super.hurt(level, x, y, source, item, attackDir, damage); } } diff --git a/src/client/java/minicraft/level/tile/CactusTile.java b/src/client/java/minicraft/level/tile/CactusTile.java index 8f076592a..daac66fa5 100644 --- a/src/client/java/minicraft/level/tile/CactusTile.java +++ b/src/client/java/minicraft/level/tile/CactusTile.java @@ -12,10 +12,15 @@ import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.item.Items; import minicraft.level.Level; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class CactusTile extends Tile { + private static final int MAX_HEALTH = 10; + private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "cactus"); protected CactusTile(String name) { @@ -31,14 +36,22 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return false; } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + handleDamage(level, x, y, source, item, MAX_HEALTH); + } else + handleDamage(level, x, y, source, item, damage); + return true; + } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { int damage = level.getData(x, y) + dmg; - int cHealth = 10; - if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = cHealth; level.add(new SmashParticle(x << 4, y << 4)); level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); - if (damage >= cHealth) { + if (damage >= MAX_HEALTH) { //int count = random.nextInt(2) + 2; level.setTile(x, y, Tiles.get("sand")); Sound.play("monsterhurt"); @@ -46,7 +59,6 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at } else { level.setData(x, y, damage); } - return true; } @Override @@ -59,13 +71,14 @@ public void bumpedInto(Level level, int x, int y, Entity entity) { if (!(entity instanceof Mob)) return; Mob m = (Mob) entity; if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) { - m.hurt(this, x, y, 1); - } - if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) { - m.hurt(this, x, y, 1); - } - if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { - m.hurt(this, x, y, 2); + m.hurt(new DamageSource(DamageSource.DamageType.CACTUS, level, (x << 4) + 8, (y << 4) + 8, this), + m.dir.getOpposite(), 1); + } else if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) { + m.hurt(new DamageSource(DamageSource.DamageType.CACTUS, level, (x << 4) + 8, (y << 4) + 8, this), + m.dir.getOpposite(), 1); + } else if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { + m.hurt(new DamageSource(DamageSource.DamageType.CACTUS, level, (x << 4) + 8, (y << 4) + 8, this), + m.dir.getOpposite(), 2); } } diff --git a/src/client/java/minicraft/level/tile/CloudTile.java b/src/client/java/minicraft/level/tile/CloudTile.java index 869ffb0f1..6a7cf6e48 100644 --- a/src/client/java/minicraft/level/tile/CloudTile.java +++ b/src/client/java/minicraft/level/tile/CloudTile.java @@ -1,9 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -12,6 +16,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class CloudTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "cloud") @@ -26,21 +31,37 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return true; } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - // We don't want the tile to break when attacked with just anything, even in creative mode - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Infinite Fall")); // Would allow you to shovel cloud, I think. + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, 1, 3, Items.get("Cloud")); + return true; + } + + // We don't want the tile to break when attacked with just anything + if (source instanceof Player && item instanceof ToolItem) { ToolItem tool = (ToolItem) item; - if (tool.type == ToolType.Shovel && player.payStamina(5)) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Infinite Fall")); // Would allow you to shovel cloud, I think. + if (tool.type == ToolType.Shovel && ((Player) source).payStamina(5)) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Infinite Fall")); // Would allow you to shovel cloud, I think. Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, 1, 3, Items.get("Cloud")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 1, 3, Items.get("Cloud")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/ConnectTile.java b/src/client/java/minicraft/level/tile/ConnectTile.java index f46f1a197..d7e144e8c 100644 --- a/src/client/java/minicraft/level/tile/ConnectTile.java +++ b/src/client/java/minicraft/level/tile/ConnectTile.java @@ -4,7 +4,9 @@ import minicraft.entity.Entity; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; // TODO Remove this. // IMPORTANT: This tile should never be used for anything, it only exists to allow tiles right next to the edge of the world to connect to it @@ -18,6 +20,9 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return false; } + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} + @Override public boolean maySpawn() { return false; diff --git a/src/client/java/minicraft/level/tile/DecorTile.java b/src/client/java/minicraft/level/tile/DecorTile.java index a3ee6968c..0d2bdeaa2 100644 --- a/src/client/java/minicraft/level/tile/DecorTile.java +++ b/src/client/java/minicraft/level/tile/DecorTile.java @@ -1,9 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; @@ -12,6 +16,7 @@ import minicraft.item.ToolItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class DecorTile extends Tile { private static final SpriteAnimation stoneSprite = new SpriteAnimation(SpriteType.Tile, "ornate_stone"); @@ -55,16 +60,48 @@ public void render(Screen screen, Level level, int x, int y) { screen.render(x * 16 + 0, y * 16, sprite.getCurrentFrame().getSprite().spritePixels[0][0]); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + if (level.depth == 1) { + level.setTile(x, y, Tiles.get("Cloud")); + } else { + level.setTile(x, y, Tiles.get("Hole")); + } + Item drop; + switch (thisType) { + case ORNATE_STONE: + drop = Items.get("Ornate Stone"); + break; + case ORNATE_OBSIDIAN: + drop = Items.get("Ornate Obsidian"); + break; + case ORNATE_WOOD: + drop = Items.get("Ornate Wood"); + break; + default: + throw new IllegalStateException("Unexpected value: " + thisType); + } + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, drop); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == mType.getRequiredTool()) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); if (level.depth == 1) { - level.setTile(xt, yt, Tiles.get("Cloud")); + level.setTile(x, y, Tiles.get("Cloud")); } else { - level.setTile(xt, yt, Tiles.get("Hole")); + level.setTile(x, y, Tiles.get("Hole")); } Item drop; switch (thisType) { @@ -81,15 +118,17 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D throw new IllegalStateException("Unexpected value: " + thisType); } Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, drop); + level.dropItem((x << 4) + 8, (y << 4) + 8, drop); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/DirtTile.java b/src/client/java/minicraft/level/tile/DirtTile.java index 32bdf3112..6d801a5ec 100644 --- a/src/client/java/minicraft/level/tile/DirtTile.java +++ b/src/client/java/minicraft/level/tile/DirtTile.java @@ -1,8 +1,12 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; @@ -13,6 +17,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class DirtTile extends Tile { private static SpriteAnimation[] levelSprite = new SpriteAnimation[] { @@ -54,33 +59,49 @@ public void render(Screen screen, Level level, int x, int y) { levelSprite[dIdx(level.depth)].render(screen, level, x, y); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Hole")); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Dirt")); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Hole")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Dirt")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Dirt")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } if (tool.type == ToolType.Hoe) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Farmland")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Farmland")); Sound.play("monsterhurt"); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/DoorTile.java b/src/client/java/minicraft/level/tile/DoorTile.java index 495595c7a..769e69bd7 100644 --- a/src/client/java/minicraft/level/tile/DoorTile.java +++ b/src/client/java/minicraft/level/tile/DoorTile.java @@ -1,10 +1,14 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; @@ -13,6 +17,7 @@ import minicraft.item.ToolItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class DoorTile extends Tile { protected Material type; @@ -49,31 +54,46 @@ public void render(Screen screen, Level level, int x, int y) { curSprite.render(screen, level, x, y); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get((short) (id + 3))); // Will get the corresponding floor tile. + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get(type.name() + " Door")); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get((short) (id + 3))); // Will get the corresponding floor tile. + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get((short) (id + 3))); // Will get the corresponding floor tile. Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get(type.name() + " Door")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get(type.name() + " Door")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - if (source instanceof Player) { - boolean closed = level.getData(x, y) == 0; - level.setData(x, y, closed ? 1 : 0); - } - return false; + @Override + public boolean use(Level level, int xt, int yt, Player player, @Nullable Item item, Direction attackDir) { + boolean closed = level.getData(xt, yt) == 0; + level.setData(xt, yt, closed ? 1 : 0); + return true; } public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/ExplodedTile.java b/src/client/java/minicraft/level/tile/ExplodedTile.java index b79123d94..05dc831a7 100644 --- a/src/client/java/minicraft/level/tile/ExplodedTile.java +++ b/src/client/java/minicraft/level/tile/ExplodedTile.java @@ -3,7 +3,9 @@ import minicraft.entity.Entity; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; /// This class is for tiles WHILE THEY ARE EXPLODING public class ExplodedTile extends Tile { @@ -27,4 +29,7 @@ public boolean connectsToSand(Level level, int x, int y) { public boolean mayPass(Level level, int x, int y, Entity e) { return true; } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} } diff --git a/src/client/java/minicraft/level/tile/FenceTile.java b/src/client/java/minicraft/level/tile/FenceTile.java index c62f84ab6..fb83d0b92 100644 --- a/src/client/java/minicraft/level/tile/FenceTile.java +++ b/src/client/java/minicraft/level/tile/FenceTile.java @@ -7,6 +7,8 @@ import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; @@ -15,6 +17,7 @@ import minicraft.item.ToolItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class FenceTile extends Tile { @@ -101,39 +104,36 @@ public void render(Screen screen, Level level, int x, int y) { } @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - hurt(level, x, y, dmg); - return true; + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); } @Override - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative")) - return false; // Go directly to hurt method - if (item instanceof ToolItem) { + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.add(new SmashParticle(x * 16, y * 16)); + Sound.play("monsterhurt"); + level.dropItem(x * 16 + 8, y * 16 + 8, Items.get(name)); + level.setTile(x, y, Tiles.get((short) level.getData(x, y))); + return true; + } else if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get(name)); - level.setTile(xt, yt, Tiles.get((short) level.getData(xt, yt))); + level.dropItem(x * 16 + 8, y * 16 + 8, Items.get(name)); + level.setTile(x, y, Tiles.get((short) level.getData(x, y))); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; - } - public void hurt(Level level, int x, int y, int dmg) { - if (Game.isMode("minicraft.settings.mode.creative")) { - level.add(new SmashParticle(x * 16, y * 16)); - Sound.play("monsterhurt"); - level.dropItem(x * 16 + 8, y * 16 + 8, Items.get(name)); - level.setTile(x, y, Tiles.get((short) level.getData(x, y))); - } + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/FloorTile.java b/src/client/java/minicraft/level/tile/FloorTile.java index 466cfafc0..4da592330 100644 --- a/src/client/java/minicraft/level/tile/FloorTile.java +++ b/src/client/java/minicraft/level/tile/FloorTile.java @@ -1,9 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -11,6 +15,7 @@ import minicraft.item.ToolItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class FloorTile extends Tile { protected Material type; @@ -36,16 +41,37 @@ protected FloorTile(Material type, String name) { } } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + if (level.depth == 1) { + level.setTile(x, y, Tiles.get("Cloud")); + } else { + level.setTile(x, y, Tiles.get("Hole")); + } + Item drop; + switch (type) { + case Wood: + drop = Items.get("Plank"); + break; + default: + drop = Items.get(type.name() + " Brick"); + break; + } + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, drop); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); if (level.depth == 1) { - level.setTile(xt, yt, Tiles.get("Cloud")); + level.setTile(x, y, Tiles.get("Cloud")); } else { - level.setTile(xt, yt, Tiles.get("Hole")); + level.setTile(x, y, Tiles.get("Hole")); } Item drop; switch (type) { @@ -57,18 +83,26 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D break; } Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, drop); + level.dropItem((x << 4) + 8, (y << 4) + 8, drop); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } public boolean mayPass(Level level, int x, int y, Entity e) { return true; } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } } diff --git a/src/client/java/minicraft/level/tile/FlowerTile.java b/src/client/java/minicraft/level/tile/FlowerTile.java index eb34b1097..55ea874bd 100644 --- a/src/client/java/minicraft/level/tile/FlowerTile.java +++ b/src/client/java/minicraft/level/tile/FlowerTile.java @@ -1,7 +1,9 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; import minicraft.gfx.Screen; @@ -13,6 +15,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class FlowerTile extends Tile { public enum FlowerVariant { @@ -80,11 +83,23 @@ public void render(Screen screen, Level level, int x, int y) { FlowerVariant.values()[level.getData(x, y)].sprite.render(screen, level, x, y); } - public boolean interact(Level level, int x, int y, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Grass")); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Flower")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Rose")); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shovel) { - if (player.payStamina(2 - tool.level) && tool.payDurability()) { + if (((Player) source).payStamina(2 - tool.level) && tool.payDurability()) { int data = level.getData(x, y); level.setTile(x, y, Tiles.get("Grass")); Sound.play("monsterhurt"); @@ -96,10 +111,7 @@ public boolean interact(Level level, int x, int y, Player player, Item item, Dir } } } - return false; - } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get(FlowerVariant.values()[level.getData(x, y)].name)); level.setTile(x, y, Tiles.get("Grass")); return true; diff --git a/src/client/java/minicraft/level/tile/GrassTile.java b/src/client/java/minicraft/level/tile/GrassTile.java index 4e66b4118..62fe9bdd1 100644 --- a/src/client/java/minicraft/level/tile/GrassTile.java +++ b/src/client/java/minicraft/level/tile/GrassTile.java @@ -1,8 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; @@ -12,6 +17,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class GrassTile extends Tile { private static final SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "grass") @@ -50,44 +56,62 @@ public void render(Screen screen, Level level, int x, int y) { sprite.render(screen, level, x, y); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Dirt")); + Sound.play("monsterhurt"); + if (random.nextInt(5) == 0) { // 20% chance to drop Grass seeds + level.dropItem((x << 4) + 8, (y << 4) + 8, 1, Items.get("Grass Seeds")); + } + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Dirt")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Dirt")); Sound.play("monsterhurt"); if (random.nextInt(5) == 0) { // 20% chance to drop Grass seeds - level.dropItem((xt << 4) + 8, (yt << 4) + 8, 1, Items.get("Grass Seeds")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 1, Items.get("Grass Seeds")); } AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } if (tool.type == ToolType.Hoe) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Farmland")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Farmland")); Sound.play("monsterhurt"); if (random.nextInt(5) != 0) { // 80% chance to drop Wheat seeds - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Wheat Seeds")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Wheat Seeds")); } AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } if (tool.type == ToolType.Pickaxe) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - level.setTile(xt, yt, Tiles.get("Path")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + level.setTile(x, y, Tiles.get("Path")); Sound.play("monsterhurt"); } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/HardRockTile.java b/src/client/java/minicraft/level/tile/HardRockTile.java index 84bc8f2b5..50854caed 100644 --- a/src/client/java/minicraft/level/tile/HardRockTile.java +++ b/src/client/java/minicraft/level/tile/HardRockTile.java @@ -18,8 +18,11 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class HardRockTile extends Tile { + private static final int MAX_HEALTH = 200; + // Theoretically the full sprite should never be used, so we can use a placeholder private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "hardrock") .setConnectionChecker((level, x, y, tile, side) -> tile instanceof HardRockTile) @@ -33,43 +36,43 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return false; } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - hurt(level, x, y, 0); - return true; - } + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + handleDamage(level, x, y, source, item, MAX_HEALTH); + return true; + } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative")) - return false; // Go directly to hurt method - if (item instanceof ToolItem) { + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; // If we are hitting with a gem pickaxe. if (tool.type == ToolType.Pickaxe && tool.level == 4) { - if (player.payStamina(2) && tool.payDurability()) { - int data = level.getData(xt, yt); - hurt(level, xt, yt, tool.getDamage()); + if (((Player) source).payStamina(2) && tool.payDurability()) { + int data = level.getData(x, y); + handleDamage(level, x, y, source, item, tool.getDamage()); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } else { Game.notifications.add("minicraft.notification.gem_pickaxe_required"); } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } - public void hurt(Level level, int x, int y, int dmg) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { int damage = level.getData(x, y) + dmg; - int hrHealth = 200; - if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = hrHealth; level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); - if (damage >= hrHealth) { + if (damage >= MAX_HEALTH) { level.setTile(x, y, Tiles.get("dirt")); level.dropItem((x << 4) + 8, (y << 4) + 8, 1, 3, Items.get("Stone")); level.dropItem((x << 4) + 8, (y << 4) + 8, 0, 1, Items.get("Coal")); diff --git a/src/client/java/minicraft/level/tile/HoleTile.java b/src/client/java/minicraft/level/tile/HoleTile.java index a55474fd9..ce6a289a8 100644 --- a/src/client/java/minicraft/level/tile/HoleTile.java +++ b/src/client/java/minicraft/level/tile/HoleTile.java @@ -4,7 +4,9 @@ import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class HoleTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "hole") @@ -35,4 +37,7 @@ public void render(Screen screen, Level level, int x, int y) { public boolean mayPass(Level level, int x, int y, Entity e) { return e.canSwim(); } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} } diff --git a/src/client/java/minicraft/level/tile/InfiniteFallTile.java b/src/client/java/minicraft/level/tile/InfiniteFallTile.java index 4b660d852..453ecb3f0 100644 --- a/src/client/java/minicraft/level/tile/InfiniteFallTile.java +++ b/src/client/java/minicraft/level/tile/InfiniteFallTile.java @@ -7,7 +7,9 @@ import minicraft.entity.mob.Player; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class InfiniteFallTile extends Tile { @@ -28,4 +30,7 @@ public boolean tick(Level level, int xt, int yt) { public boolean mayPass(Level level, int x, int y, Entity e) { return e instanceof AirWizard || e instanceof Arrow || e instanceof Player && Game.isMode("minicraft.settings.mode.creative"); } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} } diff --git a/src/client/java/minicraft/level/tile/LavaBrickTile.java b/src/client/java/minicraft/level/tile/LavaBrickTile.java index 5400df3ae..89da886fb 100644 --- a/src/client/java/minicraft/level/tile/LavaBrickTile.java +++ b/src/client/java/minicraft/level/tile/LavaBrickTile.java @@ -1,10 +1,14 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -12,33 +16,51 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class LavaBrickTile extends Tile { protected LavaBrickTile(String name) { super(name, new SpriteAnimation(SpriteType.Tile, "missing_tile")); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Lava")); + Sound.play("monsterhurt"); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Pickaxe) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Lava")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Lava")); Sound.play("monsterhurt"); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } public void bumpedInto(Level level, int x, int y, Entity entity) { if (entity instanceof Mob) - ((Mob) entity).hurt(this, x, y, 3); + entity.hurt(new DamageSource(DamageSource.DamageType.HOT_FLOOR, level, (x << 4) + 8, (y << 4) + 8, this), + Direction.NONE, 3); } public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/LavaTile.java b/src/client/java/minicraft/level/tile/LavaTile.java index 7ab019118..aefb72d68 100644 --- a/src/client/java/minicraft/level/tile/LavaTile.java +++ b/src/client/java/minicraft/level/tile/LavaTile.java @@ -4,7 +4,9 @@ import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class LavaTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "lava") @@ -54,4 +56,7 @@ public boolean tick(Level level, int xt, int yt) { public int getLightRadius(Level level, int x, int y) { return 6; } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} } diff --git a/src/client/java/minicraft/level/tile/MaterialTile.java b/src/client/java/minicraft/level/tile/MaterialTile.java index c3220f9c6..75786bac5 100644 --- a/src/client/java/minicraft/level/tile/MaterialTile.java +++ b/src/client/java/minicraft/level/tile/MaterialTile.java @@ -1,9 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -11,6 +15,7 @@ import minicraft.item.ToolItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class MaterialTile extends Tile { protected Material type; @@ -30,16 +35,45 @@ protected MaterialTile(Material type) { } } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + if (level.depth == 1) { + level.setTile(x, y, Tiles.get("Cloud")); + } else { + level.setTile(x, y, Tiles.get("Hole")); + } + Item drop; + switch (type) { + case Stone: + drop = Items.get("Stone"); + break; + case Obsidian: + drop = Items.get("Raw Obsidian"); + break; + default: + throw new IllegalStateException("Unexpected value: " + type); + } + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, drop); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); if (level.depth == 1) { - level.setTile(xt, yt, Tiles.get("Cloud")); + level.setTile(x, y, Tiles.get("Cloud")); } else { - level.setTile(xt, yt, Tiles.get("Hole")); + level.setTile(x, y, Tiles.get("Hole")); } Item drop; switch (type) { @@ -53,15 +87,17 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D throw new IllegalStateException("Unexpected value: " + type); } Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, drop); + level.dropItem((x << 4) + 8, (y << 4) + 8, drop); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/OreTile.java b/src/client/java/minicraft/level/tile/OreTile.java index e34470f95..39ecc77a5 100644 --- a/src/client/java/minicraft/level/tile/OreTile.java +++ b/src/client/java/minicraft/level/tile/OreTile.java @@ -19,6 +19,7 @@ import minicraft.level.Level; import minicraft.screen.AchievementsDisplay; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; /// this is all the spikey stuff (except "cloud cactus") public class OreTile extends Tile { @@ -61,35 +62,37 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return false; } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - hurt(level, x, y, 0); - return true; - } + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + handleDamage(level, x, y, source, item, 100); + return true; + } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative")) - return false; // Go directly to hurt method - if (item instanceof ToolItem) { + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Pickaxe) { - if (player.payStamina(6 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - hurt(level, xt, yt, tool.getDamage()); + if (((Player) source).payStamina(6 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + handleDamage(level, x, y, source, tool, tool.getDamage()); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } public Item getOre() { return type.getOre(); } - public void hurt(Level level, int x, int y, int dmg) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { int damage = level.getData(x, y) + dmg; int oreH = random.nextInt(10) * 4 + 20; if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = oreH; diff --git a/src/client/java/minicraft/level/tile/PathTile.java b/src/client/java/minicraft/level/tile/PathTile.java index 781604b40..9b924d8f2 100644 --- a/src/client/java/minicraft/level/tile/PathTile.java +++ b/src/client/java/minicraft/level/tile/PathTile.java @@ -1,8 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -11,6 +16,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class PathTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "path"); @@ -25,22 +31,38 @@ public boolean connectsToGrass(Level level, int x, int y) { return true; } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Hole")); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Dirt")); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Hole")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Dirt")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Dirt")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/RockTile.java b/src/client/java/minicraft/level/tile/RockTile.java index 6fde9871f..ff838d3dc 100644 --- a/src/client/java/minicraft/level/tile/RockTile.java +++ b/src/client/java/minicraft/level/tile/RockTile.java @@ -19,16 +19,18 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; // This is the normal stone you see underground and on the surface, that drops coal and stone. public class RockTile extends Tile { + private static final int MAX_HEALTH = 50; + private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "rock") .setConnectionChecker((level, x, y, tile, side) -> tile instanceof RockTile) .setSingletonWithConnective(true); private boolean dropCoal = false; - private int maxHealth = 50; private int damage; @@ -45,44 +47,42 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return false; } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - dropCoal = false; // Can only be reached when player hits w/o pickaxe, so remove ability to get coal - hurt(level, x, y, dmg); - return true; - } + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + handleDamage(level, x, y, source, item, MAX_HEALTH); + return true; + } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + // Can only be reached when player hits w/o pickaxe, so remove ability to get coal + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; - if (tool.type == ToolType.Pickaxe && player.payStamina(5 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); + if (tool.type == ToolType.Pickaxe && ((Player) source).payStamina(5 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); // Drop coal since we use a pickaxe. - dropCoal = true; - hurt(level, xt, yt, tool.getDamage()); + handleDamage(level, x, y, source, item, tool.getDamage()); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } - public void hurt(Level level, int x, int y, int dmg) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { damage = level.getData(x, y) + dmg; - if (Game.isMode("minicraft.settings.mode.creative")) { - dmg = damage = maxHealth; - dropCoal = true; - } - level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); - if (damage >= maxHealth) { + if (damage >= MAX_HEALTH) { int stone = 1; - if (dropCoal) { +// if (dropCoal) { stone += random.nextInt(3) + 1; int coal = 1; @@ -91,7 +91,7 @@ public void hurt(Level level, int x, int y, int dmg) { } level.dropItem((x << 4) + 8, (y << 4) + 8, 0, coal, Items.get("Coal")); - } +// } level.dropItem((x << 4) + 8, (y << 4) + 8, stone, Items.get("Stone")); level.setTile(x, y, Tiles.get("Dirt")); diff --git a/src/client/java/minicraft/level/tile/SandTile.java b/src/client/java/minicraft/level/tile/SandTile.java index 960dcde72..0674ffc32 100644 --- a/src/client/java/minicraft/level/tile/SandTile.java +++ b/src/client/java/minicraft/level/tile/SandTile.java @@ -1,11 +1,15 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; import minicraft.entity.particle.SandParticle; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; @@ -15,6 +19,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class SandTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "sand") @@ -61,22 +66,38 @@ public void steppedOn(Level level, int x, int y, Entity entity) { } } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Hole")); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Sand")); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Hole")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Sand")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Sand")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/SaplingTile.java b/src/client/java/minicraft/level/tile/SaplingTile.java index c871d2841..6a83ea3ea 100644 --- a/src/client/java/minicraft/level/tile/SaplingTile.java +++ b/src/client/java/minicraft/level/tile/SaplingTile.java @@ -2,11 +2,14 @@ import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class SaplingTile extends Tile { private static final SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "sapling"); @@ -54,7 +57,11 @@ public boolean tick(Level level, int x, int y) { return true; } - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { level.setTile(x, y, onType); Sound.play("monsterhurt"); return true; diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java index 88fb97ff5..92f4efdad 100644 --- a/src/client/java/minicraft/level/tile/SignTile.java +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -7,6 +7,9 @@ import minicraft.entity.Entity; import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker; @@ -19,6 +22,7 @@ import minicraft.screen.SignDisplay; import minicraft.screen.SignDisplayMenu; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; public class SignTile extends Tile { @@ -46,35 +50,43 @@ public void render(Screen screen, Level level, int x, int y) { sprite.render(screen, level, x, y); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item != null) { - if (item instanceof ToolItem && ((ToolItem) item).type == ToolType.Axe) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get((short) data)); - SignDisplay.removeSign(level.depth, xt, yt); - Sound.play("monsterhurt"); - level.dropItem(xt*16+8, yt*16+8, Items.get("Sign")); - AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( - new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); - return true; - } - } else { // TODO Add a way to lock signs - Game.setDisplay(new SignDisplay(level, xt, yt)); - return true; - } + @Override + public boolean use(Level level, int xt, int yt, Player player, @Nullable Item item, Direction attackDir) { + Game.setDisplay(new SignDisplay(level, xt, yt)); + return true; // TODO Add a way to lock signs + } - return false; + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); } @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - if (source instanceof Player) { - Game.setDisplay(new SignDisplay(level, x, y)); + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get((short) data)); + SignDisplay.removeSign(level.depth, x, y); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Sign")); + return true; + } + + if (item instanceof ToolItem && ((ToolItem) item).type == ToolType.Axe) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get((short) data)); + SignDisplay.removeSign(level.depth, x, y); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Sign")); + AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( + new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( + item, this, data, x, y, level.depth)); return true; } - return false; + handleDamage(level, x, y, source, item, 0); + return true; } @Override diff --git a/src/client/java/minicraft/level/tile/StairsTile.java b/src/client/java/minicraft/level/tile/StairsTile.java index 58d07c39c..8871201a8 100644 --- a/src/client/java/minicraft/level/tile/StairsTile.java +++ b/src/client/java/minicraft/level/tile/StairsTile.java @@ -2,7 +2,6 @@ import minicraft.core.Game; import minicraft.core.io.Sound; -import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.furniture.Furniture; import minicraft.entity.mob.Player; @@ -10,9 +9,8 @@ import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; -import minicraft.item.PowerGloveItem; import minicraft.level.Level; -import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class StairsTile extends Tile { private static SpriteAnimation down = new SpriteAnimation(SpriteType.Tile, "stairs_down"); @@ -37,20 +35,15 @@ public boolean mayPass(Level level, int x, int y, Entity e) { } @Override - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - super.interact(level, xt, yt, player, item, attackDir); + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} + @Override + public @Nullable Item take(Level level, int x, int y, Player player) { // Makes it so you can remove the stairs if you are in creative and debug mode. - if (item instanceof PowerGloveItem && Game.isMode("minicraft.settings.mode.creative")) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Grass")); + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Grass")); Sound.play("monsterhurt"); - AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( - new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); - return true; - } else { - return false; } + return null; } } diff --git a/src/client/java/minicraft/level/tile/Tile.java b/src/client/java/minicraft/level/tile/Tile.java index 68a53a053..041063d06 100644 --- a/src/client/java/minicraft/level/tile/Tile.java +++ b/src/client/java/minicraft/level/tile/Tile.java @@ -3,13 +3,13 @@ import minicraft.core.World; import minicraft.entity.Direction; import minicraft.entity.Entity; -import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.item.Item; import minicraft.item.ToolType; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; import java.util.Random; @@ -89,28 +89,16 @@ public int getLightRadius(Level level, int x, int y) { } /** - * Hurt the tile with a specified amount of damage. - * @param level The level this happened on. - * @param x X pos of the tile. - * @param y Y pos of the tile. - * @param source The mob that damaged the tile. - * @param dmg Damage to taken. - * @param attackDir The direction of the player hitting. - * @return If the damage was applied. - */ - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - return false; - } - - /** - * Hurt the tile with a specified amount of damage. + * Hurt the tile with a specified amount of damage directly. This is supposed to be used internally. + * Using {@link #hurt(Level, int, int, Entity, Item, Direction, int)} is more recommended. * @param level The level this happened on. * @param x X position of the tile. * @param y Y position of the tile. + * @param source The entity performed the interaction. + * @param item The item the entity is holding. * @param dmg The damage taken. */ - public void hurt(Level level, int x, int y, int dmg) { - } + protected abstract void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg); /** * What happens when you run into the tile (ex: run into a cactus) @@ -134,6 +122,21 @@ public void steppedOn(Level level, int xt, int yt, Entity entity) { /** * Called when you hit an item on a tile (ex: Pickaxe on rock). * @param level The level the player is on. + * @param x X position of the player in tile coordinates (32x per tile). + * @param y Y position of the player in tile coordinates (32px per tile). + * @param source The entity attacking. + * @param item The item the player is currently holding. + * @param attackDir The direction of the player attacking. + * @param damage The amount of damage intended to emit this time + * @return Was the operation successful? + */ + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + return false; + } + + /** + * Called when you use an item on a tile (ex: Pickaxe on rock). + * @param level The level the player is on. * @param xt X position of the player in tile coordinates (32x per tile). * @param yt Y position of the player in tile coordinates (32px per tile). * @param player The player who called this method. @@ -141,10 +144,22 @@ public void steppedOn(Level level, int xt, int yt, Entity entity) { * @param attackDir The direction of the player attacking. * @return Was the operation successful? */ - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + public boolean use(Level level, int xt, int yt, Player player, @Nullable Item item, Direction attackDir) { return false; } + /** + * Picks up this tile + * @param level + * @param x + * @param y + * @param player The player interacting + * @return the item picked up; {@code null} if picking up failed + */ + public @Nullable Item take(Level level, int x, int y, Player player) { + return null; + } + /** * Executed when the tile is exploded. * The call for this method is done just before the tiles are changed to exploded tiles. @@ -181,7 +196,7 @@ public int getData(String data) { /** * @deprecated Similar to {@link #getData(String)}. Also, param {@code thisData} is unused. - * The current only usage is in {@link minicraft.item.TileItem#interactOn(Tile, Level, int, int, Player, Direction)}. + * The current only usage is in {@link minicraft.item.TileItem#useOn(Tile, Level, int, int, Player, Direction)}. */ @Deprecated public boolean matches(int thisData, String tileInfo) { diff --git a/src/client/java/minicraft/level/tile/TorchTile.java b/src/client/java/minicraft/level/tile/TorchTile.java index f60626698..a900526b2 100644 --- a/src/client/java/minicraft/level/tile/TorchTile.java +++ b/src/client/java/minicraft/level/tile/TorchTile.java @@ -1,16 +1,20 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; import minicraft.item.Items; -import minicraft.item.PowerGloveItem; import minicraft.level.Level; -import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class TorchTile extends Tile { protected TorchTile() { @@ -41,18 +45,32 @@ public int getLightRadius(Level level, int x, int y) { return 5; } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof PowerGloveItem) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get((short) data)); + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public @Nullable Item take(Level level, int x, int y, Player player) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get((short) data)); + Sound.play("monsterhurt"); + return Items.get("Torch"); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get((short) data)); Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Torch")); - AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( - new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Torch")); return true; - } else { - return false; } + + // Hard torch? + handleDamage(level, x, y, source, item, 0); + return true; } } diff --git a/src/client/java/minicraft/level/tile/TreeTile.java b/src/client/java/minicraft/level/tile/TreeTile.java index 6b9a76160..1a0e09fd6 100644 --- a/src/client/java/minicraft/level/tile/TreeTile.java +++ b/src/client/java/minicraft/level/tile/TreeTile.java @@ -20,8 +20,11 @@ import minicraft.level.Level; import minicraft.screen.AchievementsDisplay; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class TreeTile extends Tile { + private static final int MAX_HEALTH = 20; + private static final LinkedSprite oakSprite = new LinkedSprite(SpriteType.Tile, "oak"); private static final LinkedSprite oakSpriteFull = new LinkedSprite(SpriteType.Tile, "oak_full"); private static final LinkedSprite spruceSprite = new LinkedSprite(SpriteType.Tile, "spruce"); @@ -121,44 +124,41 @@ public boolean mayPass(Level level, int x, int y, Entity e) { } @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - hurt(level, x, y, dmg); - return true; - } + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + handleDamage(level, x, y, source, item, MAX_HEALTH); + return true; // Go directly to hurt method + } - @Override - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative")) - return false; // Go directly to hurt method - if (item instanceof ToolItem) { + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Axe) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - hurt(level, xt, yt, tool.getDamage()); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + hurt(level, x, y, source, item, attackDir, tool.getDamage()); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } - public void hurt(Level level, int x, int y, int dmg) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { if (random.nextInt(100) == 0) level.dropItem(x * 16 + 8, y * 16 + 8, Items.get("Apple")); int damage = level.getData(x, y) + dmg; - int treeHealth = 20; - if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = treeHealth; - level.add(new SmashParticle(x * 16, y * 16)); Sound.play("monsterhurt"); level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); - if (damage >= treeHealth) { + if (damage >= MAX_HEALTH) { level.dropItem(x * 16 + 8, y * 16 + 8, 1, 3, Items.get("Wood")); level.dropItem(x * 16 + 8, y * 16 + 8, 0, 2, Items.get("Acorn")); level.setTile(x, y, Tiles.get("Grass")); diff --git a/src/client/java/minicraft/level/tile/WallTile.java b/src/client/java/minicraft/level/tile/WallTile.java index 48466fd54..ce1bea91a 100644 --- a/src/client/java/minicraft/level/tile/WallTile.java +++ b/src/client/java/minicraft/level/tile/WallTile.java @@ -18,8 +18,11 @@ import minicraft.item.ToolItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; public class WallTile extends Tile { + private static final int MAX_HEALTH = 100; + private static SpriteAnimation wood = new SpriteAnimation(SpriteType.Tile, "wood_wall") .setConnectionChecker((level, x, y, tile, side) -> tile instanceof WallTile); private static SpriteAnimation stone = new SpriteAnimation(SpriteType.Tile, "stone_wall") @@ -55,29 +58,22 @@ public boolean mayPass(Level level, int x, int y, Entity e) { } @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative") || level.depth != -3 || type != Material.Obsidian || AirWizard.beaten) { - hurt(level, x, y, 0); + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + handleDamage(level, x, y, source, item, MAX_HEALTH); return true; - } else { - Game.notifications.add(Localization.getLocalized(obrickMsg)); - return false; } - } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative")) - return false; // Go directly to hurt method - if (item instanceof ToolItem) { + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == type.getRequiredTool()) { if (level.depth != -3 || type != Material.Obsidian || AirWizard.beaten) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - hurt(level, xt, yt, tool.getDamage()); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + hurt(level, x, y, source, item, attackDir, tool.getDamage()); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } else { @@ -85,19 +81,19 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } - public void hurt(Level level, int x, int y, int dmg) { + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { int damage = level.getData(x, y) + dmg; - int sbwHealth = 100; - if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = sbwHealth; - level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); - if (damage >= sbwHealth) { + if (damage >= MAX_HEALTH) { String itemName = "", tilename = ""; switch (type) { // Get what tile to set and what item to drop case Wood: { diff --git a/src/client/java/minicraft/level/tile/WaterTile.java b/src/client/java/minicraft/level/tile/WaterTile.java index cf99612e0..f5597b6c8 100644 --- a/src/client/java/minicraft/level/tile/WaterTile.java +++ b/src/client/java/minicraft/level/tile/WaterTile.java @@ -4,7 +4,9 @@ import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; import minicraft.level.Level; +import org.jetbrains.annotations.Nullable; public class WaterTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "water") @@ -31,6 +33,9 @@ public boolean mayPass(Level level, int x, int y, Entity e) { return e.canSwim(); } + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) {} + @Override public boolean tick(Level level, int xt, int yt) { int xn = xt; diff --git a/src/client/java/minicraft/level/tile/WoolTile.java b/src/client/java/minicraft/level/tile/WoolTile.java index a7a7d2ac1..4ed69e05d 100644 --- a/src/client/java/minicraft/level/tile/WoolTile.java +++ b/src/client/java/minicraft/level/tile/WoolTile.java @@ -1,9 +1,13 @@ package minicraft.level.tile; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.DyeItem; @@ -13,6 +17,7 @@ import minicraft.item.ToolType; import minicraft.level.Level; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -29,23 +34,39 @@ public WoolTile(DyeItem.DyeColor color) { super(color.toString().replace('_', ' ') + " Wool", sprites.get(color)); } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Hole")); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get(name)); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shears) { - if (player.payStamina(3 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Hole")); + if (((Player) source).payStamina(3 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get(name)); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get(name)); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; + } + + @Override + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); } public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/entity/SignTileEntity.java b/src/client/java/minicraft/level/tile/entity/SignTileEntity.java index 719c7e7e5..01fbf3ba9 100644 --- a/src/client/java/minicraft/level/tile/entity/SignTileEntity.java +++ b/src/client/java/minicraft/level/tile/entity/SignTileEntity.java @@ -2,9 +2,15 @@ import minicraft.core.Game; import minicraft.core.Renderer; +import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.gfx.Screen; +import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; import minicraft.screen.SignDisplayMenu; +import minicraft.util.DamageSource; +import org.jetbrains.annotations.Nullable; public class SignTileEntity extends Entity { public SignTileEntity() { @@ -19,6 +25,29 @@ public boolean isSolid() { return false; } + @Override + public boolean isAttackable(Entity source, @Nullable Item item, Direction attackDir) { + return false; + } + + @Override + public boolean isAttackable(Tile source, Level level, int x, int y, Direction attackDir) { + return false; + } + + @Override + public boolean isUsable() { + return false; + } + + @Override + protected void handleDamage(DamageSource source, Direction attackDir, int damage) {} + + @Override + public boolean hurt(DamageSource source, Direction attackDir, int damage) { + return false; + } + @Override public void tick() { int xt = x >> 4, yt = y >> 4; diff --git a/src/client/java/minicraft/level/tile/farming/CropTile.java b/src/client/java/minicraft/level/tile/farming/CropTile.java index 6291fa75b..af2d6c1b6 100644 --- a/src/client/java/minicraft/level/tile/farming/CropTile.java +++ b/src/client/java/minicraft/level/tile/farming/CropTile.java @@ -30,8 +30,13 @@ protected CropTile(String name, @Nullable String seed) { } @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { harvest(level, x, y, source); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + handleDamage(level, x, y, source, item, damage); return true; } @@ -102,7 +107,7 @@ public boolean tick(Level level, int xt, int yt) { private static final SpriteLinker.LinkedSprite particleSprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "glint"); @Override - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + public boolean use(Level level, int xt, int yt, Player player, @Nullable Item item, Direction attackDir) { if (item instanceof StackableItem && item.getName().equalsIgnoreCase("Fertilizer")) { ((StackableItem) item).count--; Random random = new Random(); @@ -127,7 +132,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D return true; } - return super.interact(level, xt, yt, player, item, attackDir); + return false; } /** diff --git a/src/client/java/minicraft/level/tile/farming/FarmTile.java b/src/client/java/minicraft/level/tile/farming/FarmTile.java index 6205714dd..0931203f5 100644 --- a/src/client/java/minicraft/level/tile/farming/FarmTile.java +++ b/src/client/java/minicraft/level/tile/farming/FarmTile.java @@ -1,12 +1,18 @@ package minicraft.level.tile.farming; +import minicraft.core.Game; import minicraft.core.io.Sound; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Color; import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; +import minicraft.item.Items; import minicraft.item.ToolItem; import minicraft.item.ToolType; import minicraft.level.Level; @@ -14,6 +20,7 @@ import minicraft.level.tile.Tiles; import minicraft.level.tile.WaterTile; import minicraft.util.AdvancementElement; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -30,22 +37,37 @@ protected FarmTile(String name, SpriteAnimation sprite) { } @Override - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { + protected void handleDamage(Level level, int x, int y, Entity source, @Nullable Item item, int dmg) { + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); + } + + @Override + public boolean hurt(Level level, int x, int y, Entity source, @Nullable Item item, Direction attackDir, int damage) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.setTile(x, y, Tiles.get("Hole")); + Sound.play("monsterhurt"); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Dirt")); + return true; + } + + if (item instanceof ToolItem && source instanceof Player) { ToolItem tool = (ToolItem) item; if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { - int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Dirt")); + if (((Player) source).payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(x, y); + level.setTile(x, y, Tiles.get("Dirt")); Sound.play("monsterhurt"); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( - item, this, data, xt, yt, level.depth)); + item, this, data, x, y, level.depth)); return true; } } } - return false; + + handleDamage(level, x, y, source, item, 0); + return true; } @Override diff --git a/src/client/java/minicraft/screen/BookDisplay.java b/src/client/java/minicraft/screen/BookDisplay.java index d46684d82..015a7912c 100644 --- a/src/client/java/minicraft/screen/BookDisplay.java +++ b/src/client/java/minicraft/screen/BookDisplay.java @@ -92,7 +92,7 @@ private void turnPage(int dir) { @Override public void tick(InputHandler input) { - if (input.inputPressed("menu") || input.inputPressed("exit")) Game.exitDisplay(); // Close the menu. + if (input.inputPressed("INVENTORY") || input.inputPressed("exit")) Game.exitDisplay(); // Close the menu. if (input.inputPressed("cursor-left")) turnPage(-1); // This is what turns the page back if (input.inputPressed("cursor-right")) turnPage(1); // This is what turns the page forward } diff --git a/src/client/java/minicraft/screen/ContainerDisplay.java b/src/client/java/minicraft/screen/ContainerDisplay.java index 05da5855e..66aba53c5 100644 --- a/src/client/java/minicraft/screen/ContainerDisplay.java +++ b/src/client/java/minicraft/screen/ContainerDisplay.java @@ -54,7 +54,6 @@ protected void onSelectionChange(int oldSel, int newSel) { if (oldSel == newSel) return; // this also serves as a protection against access to menus[0] when such may not exist. - int shift = 0; if (newSel == 0) shift = padding - menus[0].getBounds().getLeft(); @@ -268,7 +267,7 @@ public void tick(InputHandler input) { if (onScreenKeyboardMenu == null || !curMenu.isSearcherBarActive() && !onScreenKeyboardMenu.isVisible()) { super.tick(input); - if (input.inputPressed("menu") || chest.isRemoved()) { + if (input.inputPressed("INVENTORY") || chest.isRemoved()) { Game.setDisplay(null); return; } @@ -286,7 +285,7 @@ public void tick(InputHandler input) { if (!acted) curMenu.tick(input); - if (input.getMappedKey("menu").isClicked() || chest.isRemoved()) { + if (input.getMappedKey("menu").isClicked() || input.inputPressed("EXIT") || chest.isRemoved()) { Game.setDisplay(null); return; } @@ -301,7 +300,7 @@ public void tick(InputHandler input) { } if (mainMethod || !onScreenKeyboardMenu.isVisible()) - if (input.inputPressed("attack")) { + if (input.inputPressed("SELECT")) { if (curMenu.getEntries().length == 0) return; // switch inventories diff --git a/src/client/java/minicraft/screen/CraftingDisplay.java b/src/client/java/minicraft/screen/CraftingDisplay.java index b6635a8e1..187fbeaaa 100644 --- a/src/client/java/minicraft/screen/CraftingDisplay.java +++ b/src/client/java/minicraft/screen/CraftingDisplay.java @@ -120,7 +120,7 @@ public void tick(InputHandler input) { boolean mainMethod = false; if (onScreenKeyboardMenu == null || !recipeMenu.isSearcherBarActive() && !onScreenKeyboardMenu.isVisible()) { - if (input.inputPressed("menu") || (isPersonalCrafter && input.inputPressed("craft"))) { + if (input.inputPressed("INVENTORY") || (isPersonalCrafter && input.inputPressed("craft"))) { Game.exitDisplay(); return; } @@ -137,7 +137,7 @@ public void tick(InputHandler input) { if (!acted) recipeMenu.tick(input); - if (input.getMappedKey("menu").isClicked() || (isPersonalCrafter && input.inputPressed("craft"))) { + if (input.getMappedKey("menu").isClicked() || input.inputPressed("EXIT") || (isPersonalCrafter && input.inputPressed("craft"))) { Game.exitDisplay(); return; } @@ -158,7 +158,7 @@ public void tick(InputHandler input) { refreshData(); } - if ((input.inputPressed("select") || input.inputPressed("attack")) && recipeMenu.getSelection() >= 0) { + if ((input.inputPressed("select")) && recipeMenu.getSelection() >= 0) { // check the selected recipe if (recipes.length == 0) return; Recipe selectedRecipe = recipes[recipeMenu.getSelection()]; diff --git a/src/client/java/minicraft/screen/PauseDisplay.java b/src/client/java/minicraft/screen/PauseDisplay.java index 545f19b6a..ccdf745d5 100644 --- a/src/client/java/minicraft/screen/PauseDisplay.java +++ b/src/client/java/minicraft/screen/PauseDisplay.java @@ -24,7 +24,8 @@ public PauseDisplay() { new BlankEntry(), new SelectEntry("minicraft.displays.pause.return", () -> Game.setDisplay(null)), new SelectEntry("minicraft.display.options_display", () -> Game.setDisplay(new OptionsWorldDisplay())), - new SelectEntry("minicraft.displays.achievements", () -> Game.setDisplay(new AchievementsDisplay())) + new SelectEntry("minicraft.displays.achievements", () -> Game.setDisplay(new AchievementsDisplay())), + new SelectEntry("minicraft.displays.info.title", () -> Game.setDisplay(new InfoDisplay())) )); if (TutorialDisplayHandler.inQuests()) diff --git a/src/client/java/minicraft/screen/PlayerInvDisplay.java b/src/client/java/minicraft/screen/PlayerInvDisplay.java index 65373e58e..52d432507 100644 --- a/src/client/java/minicraft/screen/PlayerInvDisplay.java +++ b/src/client/java/minicraft/screen/PlayerInvDisplay.java @@ -87,7 +87,7 @@ public void tick(InputHandler input) { if (onScreenKeyboardMenu == null || !curMenu.isSearcherBarActive() && !onScreenKeyboardMenu.isVisible()) { super.tick(input); - if (input.inputPressed("menu")) { + if (input.inputPressed("INVENTORY")) { Game.exitDisplay(); return; } @@ -105,7 +105,7 @@ public void tick(InputHandler input) { if (!acted) curMenu.tick(input); - if (input.getMappedKey("menu").isClicked()) { // Should not listen button press. + if (input.getMappedKey("menu").isClicked() || input.inputPressed("EXIT")) { // Should not listen button press. Game.exitDisplay(); return; } @@ -127,7 +127,7 @@ public void tick(InputHandler input) { Inventory from, to; if (selection == 0) { - if (input.inputPressed("attack") && menus[0].getNumOptions() > 0) { + if (input.inputPressed("SELECT") && menus[0].getNumOptions() > 0) { player.activeItem = player.getInventory().remove(menus[0].getSelection()); Game.exitDisplay(); return; @@ -180,7 +180,7 @@ public void tick(InputHandler input) { } } else { - if (input.inputPressed("attack") && menus[0].getNumOptions() > 0) { + if (input.inputPressed("SELECT") && menus[0].getNumOptions() > 0) { player.activeItem = player.getInventory().remove(menus[0].getSelection()); Game.exitDisplay(); } diff --git a/src/client/java/minicraft/screen/TutorialDisplayHandler.java b/src/client/java/minicraft/screen/TutorialDisplayHandler.java index 84b9b3235..047713875 100644 --- a/src/client/java/minicraft/screen/TutorialDisplayHandler.java +++ b/src/client/java/minicraft/screen/TutorialDisplayHandler.java @@ -69,8 +69,8 @@ private static void loadTutorialElement(String criterionName, JSONObject json) { Game.input.getMapping("move-right"))))); controlGuides.add(new ControlGuide(1, "attack", () -> Localization.getLocalized("minicraft.control_guide.attack", Game.input.getMapping("attack")))); - controlGuides.add(new ControlGuide(1, "menu", - () -> Localization.getLocalized("minicraft.control_guide.menu", Game.input.getMapping("menu")))); + controlGuides.add(new ControlGuide(1, "inventory", + () -> Localization.getLocalized("minicraft.control_guide.menu", Game.input.getMapping("INVENTORY")))); controlGuides.add(new ControlGuide(1, "craft", () -> Localization.getLocalized("minicraft.control_guide.craft", Game.input.getMapping("craft")))); } @@ -168,7 +168,7 @@ private static void turnOffGuides() { public static void tick(InputHandler input) { if (currentGuide != null) { if (ControlGuide.animation > 0) ControlGuide.animation--; - if (input.getMappedKey("expandQuestDisplay").isClicked()) { + if (input.getMappedKey("EXPAND-QUEST-DISPLAY").isClicked()) { Logging.TUTORIAL.debug("Force-completed the guides."); turnOffGuides(); return; @@ -190,7 +190,7 @@ public static void tick(InputHandler input) { } if (currentOngoingElement != null) { - if (input.getMappedKey("expandQuestDisplay").isClicked() && Game.getDisplay() == null) { + if (input.getMappedKey("EXPAND-QUEST-DISPLAY").isClicked() && Game.getDisplay() == null) { Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig(currentOngoingElement.key, null, 4), currentOngoingElement.description)); } @@ -240,7 +240,7 @@ public static void render(Screen screen) { menu.render(screen); Rectangle bounds = menu.getBounds(); String text = Localization.getLocalized("minicraft.displays.tutorial_display_handler.display.element_examine_help", - Game.input.getMapping("expandQuestDisplay")); + Game.input.getMapping("EXPAND-QUEST-DISPLAY")); String[] lines = Font.getLines(text, Screen.w * 2 / 3, Screen.h, 0); for (int i = 0; i < lines.length; i++) Font.draw(lines[i], screen, bounds.getRight() - Font.textWidth(lines[i]), bounds.getBottom() + 8 * (1 + i), Color.GRAY); diff --git a/src/client/java/minicraft/util/DamageSource.java b/src/client/java/minicraft/util/DamageSource.java new file mode 100644 index 000000000..cbe460afc --- /dev/null +++ b/src/client/java/minicraft/util/DamageSource.java @@ -0,0 +1,134 @@ +/* + * SPDX-FileCopyrightText: 2024 Minicraft+ contributors + * SPDX-License-Identifier: GPL-3.0-only + */ + +package minicraft.util; + +import minicraft.core.Game; +import minicraft.entity.Entity; +import minicraft.gfx.Point; +import minicraft.item.Item; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DamageSource { + /* + * If the source with a particular type has certain data info available, then the instances must have + * such data info available, may be not null, except item, but other info must be null, otherwise there could + * be unexpected errors. + * The position is either of tile or directEntity, but all in entity coordinates (center of tile for tiles). + * Available data info: + * - tile: the tile type as the source + * - causingEntity: the entity causing the damage, aiming the target + * - directEntity: the entity directly causes damage to the target + * - item: the item the direct entity was holding to cause damage + */ + + public enum DamageType { + /** Data: tile or (item, causingEntity and directEntity) */ + GENERIC, + /** Fire tile; Data: tile */ + IN_FIRE, + /** When on fire, original source must refer to last attack source; Data: (causingEntity+directEntity) or tile */ + ON_FIRE, + /** Lava tile; Data: tile */ + LAVA, + /** Data: causingEntity and directEntity */ + EXPLOSION, + /** Data: N/A */ + DROWN, + /** Data: N/A */ + STARVE, + /** Data: (causingEntity or tile) and directEntity */ + ARROW, + /** Data: causingEntity and directEntity */ + SPARK, + /** Heat damage by floor tile; Data: tile */ + HOT_FLOOR, + /** Data: tile */ + CACTUS; + + public boolean isFireRelated() { + return this == IN_FIRE || this == ON_FIRE || this == LAVA || this == HOT_FLOOR; + } + } + + private final @NotNull DamageType damageType; + private final @NotNull Level level; + private final int x, y; + private final @Nullable Tile tile; + private final @Nullable Entity causingEntity, directEntity; + private final @Nullable Item item; + + public DamageSource(@NotNull DamageType damageType, @NotNull Level level, int x, int y, @Nullable Tile tile, + @Nullable Entity causingEntity, @Nullable Entity directEntity, @Nullable Item item) { + this.damageType = damageType; + this.level = level; + this.x = x; + this.y = y; + this.tile = tile; + this.causingEntity = causingEntity; + this.directEntity = directEntity; + this.item = item; + } + + public DamageSource(DamageType damageType, @NotNull Level level, int x, int y, + @NotNull Tile tile, @NotNull Entity directEntity, @Nullable Item item) { + this(damageType, level, x, y, tile, null, directEntity, item); + } + + public DamageSource(@NotNull DamageType damageType, @NotNull Level level, int x, int y, @NotNull Tile tile) { + this(damageType, level, x, y, tile, null, null, null); + } + + public DamageSource(@NotNull DamageType damageType, @NotNull Entity causingEntity, + @NotNull Entity directEntity, @Nullable Item item) { + this(damageType, directEntity.getLevel(), directEntity.x, directEntity.y, null, causingEntity, directEntity, item); + } + + public DamageSource(@NotNull DamageType damageType, @NotNull Entity entity, @Nullable Item item) { + this(damageType, entity, entity, item); + } + + public DamageSource(@NotNull DamageType damageType) { + this(damageType, Game.player, null); // placeholder + } + + public @NotNull DamageType getDamageType() { + return damageType; + } + + @NotNull + public Level getLevel() { + return level; + }; + + public Point getTilePosition() { + return new Point(x >> 4, y >> 4); + } + + /** Get position of damage source based on entity coordinates. */ + @NotNull + public Point getPosition() { + return new Point(x, y); + }; + + public @Nullable Tile getTile() { + return tile; + } + + public @Nullable Entity getCausingEntity() { + return causingEntity; + } + + public @Nullable Entity getDirectEntity() { + return directEntity; + } + + public @Nullable Item getItem() { + return item; + } +}