Player can now attack; +base of inventory system

v5stable
Ondřej Hruška 11 years ago
parent 98826985e1
commit 5c329e8636
  1. 6
      src/mightypork/gamecore/util/math/algo/Coord.java
  2. 155
      src/mightypork/rogue/world/Inventory.java
  3. 25
      src/mightypork/rogue/world/PlayerControl.java
  4. 40
      src/mightypork/rogue/world/PlayerInfo.java
  5. 23
      src/mightypork/rogue/world/World.java
  6. 4
      src/mightypork/rogue/world/WorldRenderer.java
  7. 1
      src/mightypork/rogue/world/entity/Entity.java
  8. 56
      src/mightypork/rogue/world/entity/entities/MonsterAi.java
  9. 3
      src/mightypork/rogue/world/entity/entities/PlayerEntity.java
  10. 6
      src/mightypork/rogue/world/entity/entities/RatAi.java
  11. 3
      src/mightypork/rogue/world/entity/entities/RatEntity.java
  12. 14
      src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java
  13. 2
      src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java
  14. 3
      src/mightypork/rogue/world/gui/MapView.java
  15. 21
      src/mightypork/rogue/world/gui/interaction/MIPMouse.java
  16. 95
      src/mightypork/rogue/world/item/Item.java
  17. 7
      src/mightypork/rogue/world/item/ItemType.java
  18. 37
      src/mightypork/rogue/world/item/items/ItemBaseFood.java
  19. 37
      src/mightypork/rogue/world/item/items/ItemBaseWeapon.java
  20. 10
      src/mightypork/rogue/world/item/items/ItemMeat.java
  21. 47
      src/mightypork/rogue/world/level/Level.java

@ -201,4 +201,10 @@ public class Coord implements IonObjBundled, IonObjBinary {
{ {
return ION_MARK; return ION_MARK;
} }
public static Coord fromVect(Vect vect)
{
return make((int) Math.floor(vect.x()), (int) Math.floor(vect.y()));
}
} }

@ -0,0 +1,155 @@
package mightypork.rogue.world;
import java.io.IOException;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonObjBinary;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.Items;
public class Inventory implements IonObjBinary {
private static final short ION_MARK = 0;
private Item[] items;
public Inventory(int size)
{
this.items = new Item[size];
}
public Inventory()
{
// ION constructor
}
@Override
public void load(IonInput in) throws IOException
{
final int size = in.readIntByte();
items = new Item[size];
// for all items in sequence
while (in.hasNextEntry()) {
// load item index
final int i = in.readIntByte();
// load item
setItem(i, Items.loadItem(in));
}
}
@Override
public void save(IonOutput out) throws IOException
{
// write length
out.writeIntByte(getSize());
// find items that are writable
for (int i = 0; i < getSize(); i++) {
final Item item = getItem(i);
if (item != null && !item.isEmpty()) {
// start sequence entry
out.startEntry();
// write index
out.writeIntByte(i);
// write item at index
Items.saveItem(out, item);
}
}
// close sequence
out.endSequence();
}
@Override
public short getIonMark()
{
return ION_MARK;
}
/**
* Get item in a slot
*
* @param i slot number
* @return item in the slot; can be null.
*/
public Item getItem(int i)
{
verifyIndex(i);
final Item itm = items[i];
if (itm == null || itm.isEmpty()) return null;
return itm;
}
private void verifyIndex(int i)
{
if (i < 0 || i > getSize()) {
throw new IndexOutOfBoundsException("Invalid inventory index: " + i + ", size: " + getSize());
}
}
/**
* Put item in a slot
*
* @param i slot number
* @param item item to store
*/
public void setItem(int i, Item item)
{
verifyIndex(i);
items[i] = item;
}
/**
* @return inventory size
*/
public int getSize()
{
return items.length;
}
/**
* Add an item, try to merge first.
*
* @param stored stored item
* @return true if the item was entirely added, and is now empty.
*/
public boolean addItem(Item stored)
{
// try to merge with another item
for (int i = 0; i < getSize(); i++) {
final Item itm = getItem(i);
if (itm != null && itm.canStackWith(stored)) {
if (itm.addItem(stored)) return true;
}
}
// try to place in a free slot
for (int i = 0; i < getSize(); i++) {
final Item itm = getItem(i);
if (itm == null) {
setItem(i, stored.split(stored.getAmount())); // store a copy, empty the original item.
return true;
}
}
// could not insert.
return false;
}
}

@ -6,7 +6,10 @@ import java.util.Set;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Step;
import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.rogue.world.World.PlayerFacade; import mightypork.rogue.world.World.PlayerFacade;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityType;
import mightypork.rogue.world.entity.modules.EntityMoveListener; import mightypork.rogue.world.entity.modules.EntityMoveListener;
import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.Level;
@ -96,15 +99,29 @@ public abstract class PlayerControl {
*/ */
public boolean clickTile(Step side) public boolean clickTile(Step side)
{ {
return clickTile(getPlayer().getCoord().add(side)); return clickTile(getPlayer().getCoord().add(side).toVect().add(0.5, 0.5));
} }
public boolean clickTile(Coord pos) public boolean clickTile(Vect pos)
{ {
if (pos.dist(getPlayer().getCoord()) > 8) return false; // too far //if (pos.dist(getPlayer().getVisualPos()).value() > 8) return false; // too far
return getLevel().getTile(pos).onClick(); if (pos.dist(getPlayer().getVisualPos().add(0.5, 0.5)).value() < 1.5) {
// 1st try to hit entity
final Entity prey = getLevel().getClosestEntity(pos, EntityType.MONSTER, 1.2);
if (prey != null) {
prey.receiveAttack(getPlayer().getEntity(), getPlayer().getAttackStrength());
return true;
}
//2nd try to click tile
System.out.println("do click: " + Coord.fromVect(pos));
return getLevel().getTile(Coord.fromVect(pos)).onClick();
}
return false;
} }

@ -2,21 +2,35 @@ package mightypork.rogue.world;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import mightypork.gamecore.util.ion.IonBundle; import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonObjBundled; import mightypork.gamecore.util.ion.IonObjBundled;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
/**
* Player information stored in world.
*
* @author MightyPork
*/
public class PlayerInfo implements IonObjBundled { public class PlayerInfo implements IonObjBundled {
/** Player inventory size */
private static final int INV_SIZE = 8;
/** Constant indicating that no weapon is selected. */
private static final int NO_WEAPON = -1;
/** Attack str with bare hands */
public static final int BARE_ATTACK = 1;
private int eid = -1; // marks not initialized private int eid = -1; // marks not initialized
private int level; private int level;
private final List<Item> inventory = new ArrayList<>(); private Inventory inventory = new Inventory(INV_SIZE);
private int selectedWeapon = -1;
private int selectedWeapon = NO_WEAPON;
@Override @Override
@ -25,7 +39,8 @@ public class PlayerInfo implements IonObjBundled {
eid = bundle.get("eid", eid); eid = bundle.get("eid", eid);
level = bundle.get("floor", level); level = bundle.get("floor", level);
selectedWeapon = bundle.get("weapon", selectedWeapon); selectedWeapon = bundle.get("weapon", selectedWeapon);
bundle.loadSequence("inv", inventory);
inventory = bundle.get("inv", inventory);
} }
@ -35,7 +50,7 @@ public class PlayerInfo implements IonObjBundled {
bundle.put("eid", eid); bundle.put("eid", eid);
bundle.put("floor", level); bundle.put("floor", level);
bundle.put("weapon", selectedWeapon); bundle.put("weapon", selectedWeapon);
bundle.putSequence("inv", inventory); bundle.put("inv", inventory);
} }
@ -69,4 +84,17 @@ public class PlayerInfo implements IonObjBundled {
return eid != -1; return eid != -1;
} }
public Inventory getInventory()
{
return inventory;
}
public Item getEquippedWeapon()
{
if (selectedWeapon == NO_WEAPON) return null;
return inventory.getItem(selectedWeapon);
}
} }

@ -17,6 +17,7 @@ import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.gamecore.util.math.timing.Pauseable; import mightypork.gamecore.util.math.timing.Pauseable;
import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.Level;
@ -155,6 +156,28 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
return playerEntity.health.getMaxHealth(); return playerEntity.health.getMaxHealth();
} }
public Inventory getInventory()
{
return playerInfo.getInventory();
}
public Entity getEntity()
{
return playerEntity;
}
public int getAttackStrength()
{
final Item weapon = playerInfo.getEquippedWeapon();
if (weapon == null) return PlayerInfo.BARE_ATTACK;
return Math.min(weapon.getAttackPoints(), playerInfo.BARE_ATTACK);
}
} }
// not saved stuffs // not saved stuffs

@ -153,11 +153,11 @@ public class WorldRenderer extends RectProxy {
} }
public Coord getClickedTile(Vect clickPos) public Vect getClickedTile(Vect clickPos)
{ {
final int ts = (int) tileSize.value(); final int ts = (int) tileSize.value();
final Vect v = clickPos.sub(center().add(getOffset().mul(ts))); final Vect v = clickPos.sub(center().add(getOffset().mul(ts)));
return new Coord(v.xi() / ts, v.yi() / ts); return Vect.make(v.x() / ts, v.y() / ts);
} }
} }

@ -203,6 +203,7 @@ public abstract class Entity implements IonObjBundled, Updateable {
@DefaultImpl @DefaultImpl
public void onKilled() public void onKilled()
{ {
getLevel().freeTile(getCoord());
} }

@ -29,7 +29,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
public void run() public void run()
{ {
if (chasing) return; if (chasing) return;
//System.out.println("Mob looks around.");
lookForTarget(); lookForTarget();
} }
}; };
@ -40,7 +39,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
public void run() public void run()
{ {
if (chasing) return; if (chasing) return;
//System.out.println("Mob going to sleep");
sleeping = true; sleeping = true;
} }
}; };
@ -54,12 +52,8 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
final Entity prey = getPreyEntity(); final Entity prey = getPreyEntity();
if (prey == null || prey.isDead()) { if (prey == null || prey.isDead()) return;
//System.out.println("prey dead?");
return;
}
//System.out.println("Timed prey attack");
attackPrey(prey); attackPrey(prey);
} }
}; };
@ -98,12 +92,13 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
@Override @Override
public void onStepFinished() public void onStepFinished()
{ {
if (entity.isDead()) return;
//System.out.println("monster ai step finished."); //System.out.println("monster ai step finished.");
if (chasing) { if (chasing) {
//System.out.println("chasing.."); //System.out.println("chasing..");
final Entity prey = getPreyEntity(); final Entity prey = getPreyEntity();
if (!isPreyValid(prey)) { if (!isPreyValid(prey)) {
//System.out.println("prey dead or null, stop chasing: " + prey + ", prey.isdead " + prey.isDead());
stopChasing(); stopChasing();
return; return;
} }
@ -113,14 +108,9 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
return; return;
} }
if (isPreyInAttackRange(prey)) { if (!isPreyInAttackRange(prey)) {
//System.out.println("prey in attack range");
return; // attacking
} else {
stepTowardsPrey(prey); stepTowardsPrey(prey);
} }
} else {
//System.out.println("not chasing.");
} }
} }
@ -175,6 +165,8 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
@Override @Override
public void update(double delta) public void update(double delta)
{ {
if (entity.isDead()) return;
timerFindPrey.update(delta); timerFindPrey.update(delta);
timerSleepStart.update(delta); timerSleepStart.update(delta);
timerAttack.update(delta); timerAttack.update(delta);
@ -188,7 +180,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
} }
if (!isPreyInAttackRange(prey)) { if (!isPreyInAttackRange(prey)) {
//System.out.println("-upd STEP--");
stepTowardsPrey(prey); stepTowardsPrey(prey);
} }
} }
@ -203,22 +194,17 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private void lookForTarget() private void lookForTarget()
{ {
if (shouldSkipScan()) return; // not hungry right now if (entity.isDead()) return;
//System.out.println("- Lookin for prey, r=" + getScanRadius()); if (shouldSkipScan()) return; // not hungry right now
final Entity prey = entity.getLevel().getClosestEntity(entity, EntityType.PLAYER, getScanRadius()); final Entity prey = entity.getLevel().getClosestEntity(entity.pos.getVisualPos(), EntityType.PLAYER, getScanRadius());
if (prey != null) { if (prey != null) {
//System.out.println("-- Prey in sight: " + prey);
//System.out.println("-- path would be: " + entity.getCoord() + "->" + prey.getCoord());
// check if reachable without leaving room // check if reachable without leaving room
final List<Coord> noDoorPath = noDoorPf.findPath(entity.getCoord(), prey.getCoord()); final List<Coord> noDoorPath = noDoorPf.findPath(entity.getCoord(), prey.getCoord());
if (noDoorPath == null) { if (noDoorPath == null) return; // cant reach, give up
//System.out.println("-- Could not navigate to prey, aborting.");
return; // cant reach, give up
}
startChasing(prey); startChasing(prey);
} }
@ -245,7 +231,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private void startChasing(Entity prey) private void startChasing(Entity prey)
{ {
//System.out.println("start chasing"); if (entity.isDead()) return;
preyId = prey.getEntityId(); preyId = prey.getEntityId();
chasing = true; chasing = true;
@ -263,7 +249,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private void stopChasing() private void stopChasing()
{ {
//System.out.println("stop chasing.");
chasing = false; chasing = false;
preyId = -1; preyId = -1;
timerSleepStart.restart(); timerSleepStart.restart();
@ -281,15 +266,12 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private void stepTowardsPrey(Entity prey) private void stepTowardsPrey(Entity prey)
{ {
//System.out.println("stepTowardsPrey"); if (entity.isDead()) return;
if (!isPreyValid(prey)) {
//System.out.println("prey dead?"); if (!isPreyValid(prey)) return;
return;
}
// if close enough // if close enough
if (isPreyInAttackRange(prey)) { if (isPreyInAttackRange(prey)) {
//System.out.println("attack");
attackPrey(prey); attackPrey(prey);
return; return;
} }
@ -297,7 +279,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
final List<Step> preyPath = getPathToPrey(prey); final List<Step> preyPath = getPathToPrey(prey);
if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) { if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) {
//System.out.println("no path");
stopChasing(); stopChasing();
return; return;
} }
@ -309,10 +290,9 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private void attackPrey(Entity prey) private void attackPrey(Entity prey)
{ {
if (!isPreyInAttackRange(prey)) { if (entity.isDead()) return;
//System.out.println("prey out of attack range, cant attack");
return; if (!isPreyInAttackRange(prey)) return;
}
prey.receiveAttack(entity, getAttackStrength()); prey.receiveAttack(entity, getAttackStrength());
} }
@ -353,7 +333,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
@DefaultImpl @DefaultImpl
protected double getAttackDistance() protected double getAttackDistance()
{ {
return 1.6; return 1;
} }

@ -22,10 +22,11 @@ public class PlayerEntity extends Entity {
public PlayerAi(Entity entity) public PlayerAi(Entity entity)
{ {
super(entity); super(entity);
setDespawnDelay(3); setDespawnDelay(2);
health.setMaxHealth(12); health.setMaxHealth(12);
health.fill(); // fill health bar to max health.fill(); // fill health bar to max
health.setHitCooldownTime(0.5);
} }

@ -10,8 +10,8 @@ public class RatAi extends MonsterAi {
{ {
super(entity); super(entity);
setAttackTime(1); setAttackTime(1.2);
setScanTime(1); setScanTime(1.5);
setSleepTime(10); setSleepTime(10);
} }
@ -26,7 +26,7 @@ public class RatAi extends MonsterAi {
@Override @Override
protected double getAttackDistance() protected double getAttackDistance()
{ {
return 1.42; return 1.43;
} }

@ -28,10 +28,11 @@ public class RatEntity extends Entity {
pos.addMoveListener(ai); pos.addMoveListener(ai);
pos.setStepTime(0.5); pos.setStepTime(0.5);
setDespawnDelay(3); setDespawnDelay(2);
health.setMaxHealth(3 + rand.nextInt(3)); health.setMaxHealth(3 + rand.nextInt(3));
health.fill(); // fill health bar to max health.fill(); // fill health bar to max
health.setHitCooldownTime(0.2);
} }

@ -19,6 +19,7 @@ public class EntityModuleHealth extends EntityModule {
protected int health = 1; protected int health = 1;
protected int maxHealth = 1; protected int maxHealth = 1;
private double hitCooldownTime = 0.3;
protected boolean dead = false; protected boolean dead = false;
private double timeSinceLastDamage = Integer.MAX_VALUE; private double timeSinceLastDamage = Integer.MAX_VALUE;
@ -94,6 +95,8 @@ public class EntityModuleHealth extends EntityModule {
public void receiveDamage(int attackStrength) public void receiveDamage(int attackStrength)
{ {
if (timeSinceLastDamage < hitCooldownTime) return;
setHealth(health - attackStrength); setHealth(health - attackStrength);
timeSinceLastDamage = 0; timeSinceLastDamage = 0;
} }
@ -119,4 +122,15 @@ public class EntityModuleHealth extends EntityModule {
{ {
return timeSinceLastDamage; return timeSinceLastDamage;
} }
/**
* Set how long after hit another hit can be received.
*
* @param secs
*/
public void setHitCooldownTime(double secs)
{
this.hitCooldownTime = secs;
}
} }

@ -70,7 +70,7 @@ public class EntityRendererMobLR extends EntityRenderer {
final double hw = spriteRect.width().half().value(); final double hw = spriteRect.width().half().value();
Render.quadTextured(Vect.ZERO.expand(hw, hw, hw, hw), q, hue.withAlpha(entity.isDead() ? 1 - hurtTime / 3 : 1)); Render.quadTextured(Vect.ZERO.expand(hw, hw, hw, hw), q, hue.withAlpha(entity.isDead() ? 1 - hurtTime / 2 : 1));
Render.popMatrix(); Render.popMatrix();
} }
} }

@ -15,7 +15,6 @@ import mightypork.gamecore.input.events.MouseButtonEvent;
import mightypork.gamecore.input.events.MouseButtonListener; import mightypork.gamecore.input.events.MouseButtonListener;
import mightypork.gamecore.render.Render; import mightypork.gamecore.render.Render;
import mightypork.gamecore.util.math.Easing; import mightypork.gamecore.util.math.Easing;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.color.Color; import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.color.pal.RGB;
import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.num.Num;
@ -121,7 +120,7 @@ public class MapView extends InputComponent implements DelegatingClient, KeyList
* @param pos position on screen (px) * @param pos position on screen (px)
* @return position on map (tiles) * @return position on map (tiles)
*/ */
public Coord toWorldPos(Vect pos) public Vect toWorldPos(Vect pos)
{ {
return worldRenderer.getClickedTile(pos); return worldRenderer.getClickedTile(pos);
} }

@ -45,13 +45,19 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
{ {
if (isImmobile()) return false; if (isImmobile()) return false;
final Coord pos = mapView.toWorldPos(mouse); final Vect pos = mapView.toWorldPos(mouse);
final Tile t = mapView.plc.getLevel().getTile(pos);
if (button == BTN && !down) {
if (button == BTN && !down && t.onClick()) { // try to click tile
return true;
System.out.println("---");
System.out.println("Standing at: " + getPlayer().getCoord() + ", visual " + getPlayer().getVisualPos());
System.out.println("Click tile: " + pos + ", floored: " + pos.floor());
if (mapView.plc.clickTile(pos)) return true;
} }
final Tile t = mapView.plc.getLevel().getTile(Coord.fromVect(pos));
if (button == 1 && !down && t.isWalkable()) { if (button == 1 && !down && t.isWalkable()) {
if (troToNav(mouse)) return true; if (troToNav(mouse)) return true;
return mouseWalk(mouse); return mouseWalk(mouse);
@ -66,7 +72,8 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
if (isImmobile()) return false; if (isImmobile()) return false;
final Coord plpos = mapView.plc.getPlayer().getCoord(); final Coord plpos = mapView.plc.getPlayer().getCoord();
final Coord clicked = mapView.toWorldPos(mouse);
final Coord clicked = Coord.fromVect(mapView.toWorldPos(mouse));
if (clicked.equals(plpos)) return false; if (clicked.equals(plpos)) return false;
final Tile t = mapView.plc.getLevel().getTile(clicked); final Tile t = mapView.plc.getLevel().getTile(clicked);
@ -82,7 +89,7 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
if (isImmobile()) return false; if (isImmobile()) return false;
final Coord plpos = mapView.plc.getPlayer().getCoord(); final Coord plpos = mapView.plc.getPlayer().getCoord();
final Coord clicked = mapView.toWorldPos(pos); final Coord clicked = Coord.fromVect(mapView.toWorldPos(pos));
if (clicked.equals(plpos)) return false; if (clicked.equals(plpos)) return false;
final Polar p = Polar.fromCoord(clicked.x - plpos.x, clicked.y - plpos.y); final Polar p = Polar.fromCoord(clicked.x - plpos.x, clicked.y - plpos.y);

@ -14,6 +14,7 @@ public abstract class Item implements IonObjBlob {
private final ItemModel model; private final ItemModel model;
private ItemRenderer renderer; private ItemRenderer renderer;
private int amount = 1;
public Item(ItemModel model) public Item(ItemModel model)
@ -39,6 +40,7 @@ public abstract class Item implements IonObjBlob {
@DefaultImpl @DefaultImpl
public void save(IonOutput out) throws IOException public void save(IonOutput out) throws IOException
{ {
out.writeIntShort(amount);
} }
@ -46,6 +48,7 @@ public abstract class Item implements IonObjBlob {
@DefaultImpl @DefaultImpl
public void load(IonInput in) throws IOException public void load(IonInput in) throws IOException
{ {
amount = in.readIntShort();
} }
@ -53,4 +56,96 @@ public abstract class Item implements IonObjBlob {
{ {
return model; return model;
} }
@DefaultImpl
protected int getMaxStackSize()
{
return isStackable() ? 1 : 65535;
}
public boolean canStackWith(Item other)
{
return (getModel().id == other.getModel().id) && isStackable();
}
public abstract boolean isStackable();
/**
* Add another item to this item
*
* @param added added item
* @return if items are compatible and the added item was completely moved
* to this item, returns true and the added item should be
* discarded.
*/
public boolean addItem(Item added)
{
if (!canStackWith(added)) return false;
final int room = getMaxStackSize() - this.amount;
final int avail = added.amount;
final int moved = Math.min(room, avail);
this.amount += moved;
added.amount -= moved;
return added.isEmpty();
}
/**
* @return item amount in the stack
*/
public int getAmount()
{
return Math.max(0, amount);
}
/**
* Consume one item.
*
* @return true if the item is fully consumed and should be removed.
*/
public boolean consume()
{
if (isEmpty()) throw new RuntimeException("Item is empty, cannot consume.");
amount--;
return isEmpty();
}
public boolean isEmpty()
{
return getAmount() == 0;
}
public Item split(int removed)
{
if (isEmpty()) throw new RuntimeException("Item is empty, cannot split.");
final int realRemoved = Math.min(removed, amount);
final Item newItm = model.createItem();
newItm.amount = realRemoved;
this.amount -= realRemoved;
return newItm;
}
public abstract int getAttackPoints();
public abstract int getFoodPoints();
public abstract ItemType getType();
} }

@ -0,0 +1,7 @@
package mightypork.rogue.world.item;
public enum ItemType
{
FOOD, WEAPON;
}

@ -0,0 +1,37 @@
package mightypork.rogue.world.item.items;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemType;
public abstract class ItemBaseFood extends Item {
public ItemBaseFood(ItemModel model)
{
super(model);
}
@Override
public boolean isStackable()
{
return true;
}
@Override
public int getAttackPoints()
{
return 0;
}
@Override
public ItemType getType()
{
return ItemType.FOOD;
}
}

@ -0,0 +1,37 @@
package mightypork.rogue.world.item.items;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemType;
public abstract class ItemBaseWeapon extends Item {
public ItemBaseWeapon(ItemModel model)
{
super(model);
}
@Override
public boolean isStackable()
{
return false;
}
@Override
public int getFoodPoints()
{
return 0;
}
@Override
public ItemType getType()
{
return ItemType.WEAPON;
}
}

@ -2,13 +2,12 @@ package mightypork.rogue.world.item.items;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemModel; import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer; import mightypork.rogue.world.item.ItemRenderer;
import mightypork.rogue.world.item.render.QuadItemRenderer; import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemMeat extends Item { public class ItemMeat extends ItemBaseFood {
public ItemMeat(ItemModel model) public ItemMeat(ItemModel model)
{ {
@ -22,4 +21,11 @@ public class ItemMeat extends Item {
return new QuadItemRenderer(Res.txq("item.meat")); return new QuadItemRenderer(Res.txq("item.meat"));
} }
@Override
public int getFoodPoints()
{
return 4;
}
} }

@ -19,6 +19,7 @@ import mightypork.gamecore.util.math.algo.Sides;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Step;
import mightypork.gamecore.util.math.algo.floodfill.FillContext; import mightypork.gamecore.util.math.algo.floodfill.FillContext;
import mightypork.gamecore.util.math.algo.floodfill.FloodFill; import mightypork.gamecore.util.math.algo.floodfill.FloodFill;
import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.gamecore.util.math.noise.NoiseGen; import mightypork.gamecore.util.math.noise.NoiseGen;
import mightypork.rogue.world.World; import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entities;
@ -37,7 +38,29 @@ import mightypork.rogue.world.tile.Tiles;
*/ */
public class Level implements BusAccess, Updateable, DelegatingClient, ToggleableClient, IonObjBinary { public class Level implements BusAccess, Updateable, DelegatingClient, ToggleableClient, IonObjBinary {
private static class EntityRenderComparator implements Comparator<Entity> {
@Override
public int compare(Entity o1, Entity o2)
{
if (o1.isDead() && !o2.isDead()) {
return -1;
}
if (!o1.isDead() && o2.isDead()) {
return 1;
}
int c = Double.compare(o1.pos.getVisualPos().y(), o1.pos.getVisualPos().y());
if (c == 0) c = Double.compare(o1.pos.getVisualPos().x(), o1.pos.getVisualPos().x());
return c;
}
}
public static final int ION_MARK = 53; public static final int ION_MARK = 53;
private static final Comparator<Entity> ENTITY_RENDER_CMP = new EntityRenderComparator();
private final Coord size = Coord.zero(); private final Coord size = Coord.zero();
private World world; private World world;
@ -49,7 +72,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
private Tile[][] tiles; private Tile[][] tiles;
private final Map<Integer, Entity> entityMap = new HashMap<>(); private final Map<Integer, Entity> entityMap = new HashMap<>();
private final Set<Entity> entitySet = new HashSet<>(); private final List<Entity> entitySet = new LinkedList<>();
private int playerCount = 0; private int playerCount = 0;
@ -57,6 +80,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
public long seed; public long seed;
private transient NoiseGen noiseGen; private transient NoiseGen noiseGen;
private double timeSinceLastEntitySort;
public Level() public Level()
@ -231,6 +255,13 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
@Override @Override
public void update(double delta) public void update(double delta)
{ {
timeSinceLastEntitySort += delta;
if (timeSinceLastEntitySort > 0.2) {
Collections.sort(entitySet, ENTITY_RENDER_CMP);
timeSinceLastEntitySort = 0;
}
// just update them all // just update them all
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) { for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) { for (c.y = 0; c.y < size.y; c.y++) {
@ -505,23 +536,27 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
/** /**
* Get entity of type closest to coord * Get entity of type closest to coord
* *
* @param self the querying entity - to provide position, and to be excluded * @param pos the attack origin
* from the search.
* @param type wanted entity type * @param type wanted entity type
* @param radius search radius; -1 for unlimited. * @param radius search radius; -1 for unlimited.
* @return * @return
*/ */
public Entity getClosestEntity(Entity self, EntityType type, double radius) public Entity getClosestEntity(Vect pos, EntityType type, double radius)
{ {
Entity closest = null; Entity closest = null;
double minDist = Double.MAX_VALUE; double minDist = Double.MAX_VALUE;
if (type == EntityType.MONSTER) System.out.println("Finding entity in range " + radius + " of " + pos);
for (final Entity e : entitySet) { for (final Entity e : entitySet) {
if (e == self) continue;
if (e.isDead()) continue; if (e.isDead()) continue;
if (e.getType() == type) { if (e.getType() == type) {
final double dist = e.getCoord().dist(self.getCoord()); final double dist = e.pos.getVisualPos().dist(pos).value();
if (type == EntityType.MONSTER && dist < radius * 2) {
System.out.println("Entity " + e + ", dist: " + dist + ", standing at: " + e.pos.getCoord() + ", visual: " + e.pos.getVisualPos());
}
if (dist <= radius && dist < minDist) { if (dist <= radius && dist < minDist) {
minDist = dist; minDist = dist;

Loading…
Cancel
Save