Player can now attack; +base of inventory system
This commit is contained in:
@@ -201,4 +201,10 @@ public class Coord implements IonObjBundled, IonObjBinary {
|
||||
{
|
||||
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.Step;
|
||||
import mightypork.gamecore.util.math.constraints.vect.Vect;
|
||||
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.level.Level;
|
||||
|
||||
@@ -96,15 +99,29 @@ public abstract class PlayerControl {
|
||||
*/
|
||||
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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import mightypork.gamecore.util.ion.IonBundle;
|
||||
import mightypork.gamecore.util.ion.IonObjBundled;
|
||||
import mightypork.rogue.world.item.Item;
|
||||
|
||||
|
||||
/**
|
||||
* Player information stored in world.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
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 level;
|
||||
|
||||
private final List<Item> inventory = new ArrayList<>();
|
||||
private int selectedWeapon = -1;
|
||||
private Inventory inventory = new Inventory(INV_SIZE);
|
||||
|
||||
private int selectedWeapon = NO_WEAPON;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -25,7 +39,8 @@ public class PlayerInfo implements IonObjBundled {
|
||||
eid = bundle.get("eid", eid);
|
||||
level = bundle.get("floor", level);
|
||||
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("floor", level);
|
||||
bundle.put("weapon", selectedWeapon);
|
||||
bundle.putSequence("inv", inventory);
|
||||
bundle.put("inv", inventory);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,4 +84,17 @@ public class PlayerInfo implements IonObjBundled {
|
||||
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.rogue.world.entity.Entities;
|
||||
import mightypork.rogue.world.entity.Entity;
|
||||
import mightypork.rogue.world.item.Item;
|
||||
import mightypork.rogue.world.level.Level;
|
||||
|
||||
|
||||
@@ -155,6 +156,28 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
|
||||
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
|
||||
|
||||
@@ -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 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
|
||||
public void onKilled()
|
||||
{
|
||||
getLevel().freeTile(getCoord());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
public void run()
|
||||
{
|
||||
if (chasing) return;
|
||||
//System.out.println("Mob looks around.");
|
||||
lookForTarget();
|
||||
}
|
||||
};
|
||||
@@ -40,7 +39,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
public void run()
|
||||
{
|
||||
if (chasing) return;
|
||||
//System.out.println("Mob going to sleep");
|
||||
sleeping = true;
|
||||
}
|
||||
};
|
||||
@@ -54,12 +52,8 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
|
||||
final Entity prey = getPreyEntity();
|
||||
|
||||
if (prey == null || prey.isDead()) {
|
||||
//System.out.println("prey dead?");
|
||||
return;
|
||||
}
|
||||
if (prey == null || prey.isDead()) return;
|
||||
|
||||
//System.out.println("Timed prey attack");
|
||||
attackPrey(prey);
|
||||
}
|
||||
};
|
||||
@@ -98,12 +92,13 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
@Override
|
||||
public void onStepFinished()
|
||||
{
|
||||
if (entity.isDead()) return;
|
||||
|
||||
//System.out.println("monster ai step finished.");
|
||||
if (chasing) {
|
||||
//System.out.println("chasing..");
|
||||
final Entity prey = getPreyEntity();
|
||||
if (!isPreyValid(prey)) {
|
||||
//System.out.println("prey dead or null, stop chasing: " + prey + ", prey.isdead " + prey.isDead());
|
||||
stopChasing();
|
||||
return;
|
||||
}
|
||||
@@ -113,14 +108,9 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPreyInAttackRange(prey)) {
|
||||
//System.out.println("prey in attack range");
|
||||
return; // attacking
|
||||
} else {
|
||||
if (!isPreyInAttackRange(prey)) {
|
||||
stepTowardsPrey(prey);
|
||||
}
|
||||
} else {
|
||||
//System.out.println("not chasing.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +165,8 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
if (entity.isDead()) return;
|
||||
|
||||
timerFindPrey.update(delta);
|
||||
timerSleepStart.update(delta);
|
||||
timerAttack.update(delta);
|
||||
@@ -188,7 +180,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
}
|
||||
|
||||
if (!isPreyInAttackRange(prey)) {
|
||||
//System.out.println("-upd STEP--");
|
||||
stepTowardsPrey(prey);
|
||||
}
|
||||
}
|
||||
@@ -203,22 +194,17 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
|
||||
private void lookForTarget()
|
||||
{
|
||||
if (entity.isDead()) return;
|
||||
|
||||
if (shouldSkipScan()) return; // not hungry right now
|
||||
|
||||
//System.out.println("- Lookin for prey, r=" + getScanRadius());
|
||||
|
||||
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) {
|
||||
//System.out.println("-- Prey in sight: " + prey);
|
||||
//System.out.println("-- path would be: " + entity.getCoord() + "->" + prey.getCoord());
|
||||
|
||||
// check if reachable without leaving room
|
||||
final List<Coord> noDoorPath = noDoorPf.findPath(entity.getCoord(), prey.getCoord());
|
||||
|
||||
if (noDoorPath == null) {
|
||||
//System.out.println("-- Could not navigate to prey, aborting.");
|
||||
return; // cant reach, give up
|
||||
}
|
||||
if (noDoorPath == null) return; // cant reach, give up
|
||||
|
||||
startChasing(prey);
|
||||
}
|
||||
@@ -245,7 +231,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
|
||||
private void startChasing(Entity prey)
|
||||
{
|
||||
//System.out.println("start chasing");
|
||||
if (entity.isDead()) return;
|
||||
|
||||
preyId = prey.getEntityId();
|
||||
chasing = true;
|
||||
@@ -263,7 +249,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
|
||||
private void stopChasing()
|
||||
{
|
||||
//System.out.println("stop chasing.");
|
||||
chasing = false;
|
||||
preyId = -1;
|
||||
timerSleepStart.restart();
|
||||
@@ -281,15 +266,12 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
|
||||
private void stepTowardsPrey(Entity prey)
|
||||
{
|
||||
//System.out.println("stepTowardsPrey");
|
||||
if (!isPreyValid(prey)) {
|
||||
//System.out.println("prey dead?");
|
||||
return;
|
||||
}
|
||||
if (entity.isDead()) return;
|
||||
|
||||
if (!isPreyValid(prey)) return;
|
||||
|
||||
// if close enough
|
||||
if (isPreyInAttackRange(prey)) {
|
||||
//System.out.println("attack");
|
||||
attackPrey(prey);
|
||||
return;
|
||||
}
|
||||
@@ -297,7 +279,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
final List<Step> preyPath = getPathToPrey(prey);
|
||||
|
||||
if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) {
|
||||
//System.out.println("no path");
|
||||
stopChasing();
|
||||
return;
|
||||
}
|
||||
@@ -309,10 +290,9 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
|
||||
private void attackPrey(Entity prey)
|
||||
{
|
||||
if (!isPreyInAttackRange(prey)) {
|
||||
//System.out.println("prey out of attack range, cant attack");
|
||||
return;
|
||||
}
|
||||
if (entity.isDead()) return;
|
||||
|
||||
if (!isPreyInAttackRange(prey)) return;
|
||||
|
||||
prey.receiveAttack(entity, getAttackStrength());
|
||||
}
|
||||
@@ -353,7 +333,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
@DefaultImpl
|
||||
protected double getAttackDistance()
|
||||
{
|
||||
return 1.6;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,10 +22,11 @@ public class PlayerEntity extends Entity {
|
||||
public PlayerAi(Entity entity)
|
||||
{
|
||||
super(entity);
|
||||
setDespawnDelay(3);
|
||||
setDespawnDelay(2);
|
||||
|
||||
health.setMaxHealth(12);
|
||||
health.fill(); // fill health bar to max
|
||||
health.setHitCooldownTime(0.5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ public class RatAi extends MonsterAi {
|
||||
{
|
||||
super(entity);
|
||||
|
||||
setAttackTime(1);
|
||||
setScanTime(1);
|
||||
setAttackTime(1.2);
|
||||
setScanTime(1.5);
|
||||
setSleepTime(10);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class RatAi extends MonsterAi {
|
||||
@Override
|
||||
protected double getAttackDistance()
|
||||
{
|
||||
return 1.42;
|
||||
return 1.43;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,10 +28,11 @@ public class RatEntity extends Entity {
|
||||
pos.addMoveListener(ai);
|
||||
|
||||
pos.setStepTime(0.5);
|
||||
setDespawnDelay(3);
|
||||
setDespawnDelay(2);
|
||||
|
||||
health.setMaxHealth(3 + rand.nextInt(3));
|
||||
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 maxHealth = 1;
|
||||
private double hitCooldownTime = 0.3;
|
||||
protected boolean dead = false;
|
||||
|
||||
private double timeSinceLastDamage = Integer.MAX_VALUE;
|
||||
@@ -94,6 +95,8 @@ public class EntityModuleHealth extends EntityModule {
|
||||
|
||||
public void receiveDamage(int attackStrength)
|
||||
{
|
||||
if (timeSinceLastDamage < hitCooldownTime) return;
|
||||
|
||||
setHealth(health - attackStrength);
|
||||
timeSinceLastDamage = 0;
|
||||
}
|
||||
@@ -119,4 +122,15 @@ public class EntityModuleHealth extends EntityModule {
|
||||
{
|
||||
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();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import mightypork.gamecore.input.events.MouseButtonEvent;
|
||||
import mightypork.gamecore.input.events.MouseButtonListener;
|
||||
import mightypork.gamecore.render.Render;
|
||||
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.pal.RGB;
|
||||
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)
|
||||
* @return position on map (tiles)
|
||||
*/
|
||||
public Coord toWorldPos(Vect pos)
|
||||
public Vect toWorldPos(Vect pos)
|
||||
{
|
||||
return worldRenderer.getClickedTile(pos);
|
||||
}
|
||||
|
||||
@@ -45,13 +45,19 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
|
||||
{
|
||||
if (isImmobile()) return false;
|
||||
|
||||
final Coord pos = mapView.toWorldPos(mouse);
|
||||
final Tile t = mapView.plc.getLevel().getTile(pos);
|
||||
final Vect pos = mapView.toWorldPos(mouse);
|
||||
|
||||
if (button == BTN && !down && t.onClick()) {
|
||||
return true;
|
||||
if (button == BTN && !down) {
|
||||
// try to click tile
|
||||
|
||||
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 (troToNav(mouse)) return true;
|
||||
return mouseWalk(mouse);
|
||||
@@ -66,7 +72,8 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
|
||||
if (isImmobile()) return false;
|
||||
|
||||
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;
|
||||
|
||||
final Tile t = mapView.plc.getLevel().getTile(clicked);
|
||||
@@ -82,7 +89,7 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
|
||||
if (isImmobile()) return false;
|
||||
|
||||
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;
|
||||
|
||||
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 ItemRenderer renderer;
|
||||
private int amount = 1;
|
||||
|
||||
|
||||
public Item(ItemModel model)
|
||||
@@ -39,6 +40,7 @@ public abstract class Item implements IonObjBlob {
|
||||
@DefaultImpl
|
||||
public void save(IonOutput out) throws IOException
|
||||
{
|
||||
out.writeIntShort(amount);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +48,7 @@ public abstract class Item implements IonObjBlob {
|
||||
@DefaultImpl
|
||||
public void load(IonInput in) throws IOException
|
||||
{
|
||||
amount = in.readIntShort();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,4 +56,96 @@ public abstract class Item implements IonObjBlob {
|
||||
{
|
||||
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.world.item.Item;
|
||||
import mightypork.rogue.world.item.ItemModel;
|
||||
import mightypork.rogue.world.item.ItemRenderer;
|
||||
import mightypork.rogue.world.item.render.QuadItemRenderer;
|
||||
|
||||
|
||||
public class ItemMeat extends Item {
|
||||
public class ItemMeat extends ItemBaseFood {
|
||||
|
||||
public ItemMeat(ItemModel model)
|
||||
{
|
||||
@@ -22,4 +21,11 @@ public class ItemMeat extends Item {
|
||||
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.floodfill.FillContext;
|
||||
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.rogue.world.World;
|
||||
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 {
|
||||
|
||||
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;
|
||||
private static final Comparator<Entity> ENTITY_RENDER_CMP = new EntityRenderComparator();
|
||||
|
||||
private final Coord size = Coord.zero();
|
||||
private World world;
|
||||
@@ -49,7 +72,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
|
||||
private Tile[][] tiles;
|
||||
|
||||
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;
|
||||
|
||||
@@ -57,6 +80,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
|
||||
public long seed;
|
||||
|
||||
private transient NoiseGen noiseGen;
|
||||
private double timeSinceLastEntitySort;
|
||||
|
||||
|
||||
public Level()
|
||||
@@ -231,6 +255,13 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
timeSinceLastEntitySort += delta;
|
||||
|
||||
if (timeSinceLastEntitySort > 0.2) {
|
||||
Collections.sort(entitySet, ENTITY_RENDER_CMP);
|
||||
timeSinceLastEntitySort = 0;
|
||||
}
|
||||
|
||||
// just update them all
|
||||
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
|
||||
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
|
||||
*
|
||||
* @param self the querying entity - to provide position, and to be excluded
|
||||
* from the search.
|
||||
* @param pos the attack origin
|
||||
* @param type wanted entity type
|
||||
* @param radius search radius; -1 for unlimited.
|
||||
* @return
|
||||
*/
|
||||
public Entity getClosestEntity(Entity self, EntityType type, double radius)
|
||||
public Entity getClosestEntity(Vect pos, EntityType type, double radius)
|
||||
{
|
||||
Entity closest = null;
|
||||
double minDist = Double.MAX_VALUE;
|
||||
|
||||
if (type == EntityType.MONSTER) System.out.println("Finding entity in range " + radius + " of " + pos);
|
||||
|
||||
for (final Entity e : entitySet) {
|
||||
if (e == self) continue;
|
||||
if (e.isDead()) continue;
|
||||
|
||||
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) {
|
||||
minDist = dist;
|
||||
|
||||
Reference in New Issue
Block a user