Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Explicitly separate rigidly definite player interaction actions #552

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/client/java/minicraft/core/Renderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<PotionType, Integer>[] 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 {
Expand Down
25 changes: 13 additions & 12 deletions src/client/java/minicraft/core/io/InputHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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");
}
Expand All @@ -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() {
Expand Down
32 changes: 30 additions & 2 deletions src/client/java/minicraft/entity/Arrow.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/client/java/minicraft/entity/Direction.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ public static Direction getDirection(int dir) {
public int getDir() {
return ordinal() - 1;
}

public Direction getOpposite() {
return Direction.getDirection(getDir() ^ 0b11);
}
}
101 changes: 96 additions & 5 deletions src/client/java/minicraft/entity/Entity.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -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)}.<p>
* 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.
*/
Expand Down Expand Up @@ -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();
}

Expand Down
26 changes: 26 additions & 0 deletions src/client/java/minicraft/entity/ExplosionTileTicker.java
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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;
}
}
28 changes: 28 additions & 0 deletions src/client/java/minicraft/entity/FireSpark.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down
Loading
Loading