Improved entity path debug rendering

Included reference to source DS1.Object in StaticEntity and Monster classes
Added reference to DS1.Path in DS1.Object owner (assumes 1 path per object)
Moved path debug rendering to Entity from MapRenderer
Added Entity.drawDebugPath(ShapeRenderer)
This commit is contained in:
Collin Smith 2019-02-15 02:09:17 -08:00
parent dda1c4b47d
commit 1d781c5b8f
5 changed files with 97 additions and 65 deletions

View File

@ -330,6 +330,8 @@ public class Entity {
shapes.line(x, y, x + MathUtils.cos(rounded) * R * 0.5f, y + MathUtils.sin(rounded) * R * 0.5f); shapes.line(x, y, x + MathUtils.cos(rounded) * R * 0.5f, y + MathUtils.sin(rounded) * R * 0.5f);
} }
public void drawDebugPath(ShapeRenderer shapes) {}
public void draw(Batch batch) { public void draw(Batch batch) {
draw((PaletteIndexedBatch) batch); draw((PaletteIndexedBatch) batch);
} }

View File

@ -1,6 +1,8 @@
package gdx.diablo.entity; package gdx.diablo.entity;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.MathUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -9,15 +11,18 @@ import gdx.diablo.Diablo;
import gdx.diablo.codec.excel.MonStats; import gdx.diablo.codec.excel.MonStats;
import gdx.diablo.codec.excel.MonStats2; import gdx.diablo.codec.excel.MonStats2;
import gdx.diablo.map.DS1; import gdx.diablo.map.DS1;
import gdx.diablo.map.DT1.Tile;
public class Monster extends Entity { public class Monster extends Entity {
private static final String TAG = "Monster"; private static final String TAG = "Monster";
MonStats.Entry monstats; DS1.Object object;
MonStats.Entry monstats;
MonStats2.Entry monstats2; MonStats2.Entry monstats2;
public Monster(MonStats.Entry monstats) { public Monster(DS1.Object object, MonStats.Entry monstats) {
super(monstats.Code, EntType.MONSTER); super(monstats.Code, EntType.MONSTER);
this.object = object;
this.monstats = monstats; this.monstats = monstats;
this.monstats2 = Diablo.files.monstats2.get(monstats.MonStatsEx); this.monstats2 = Diablo.files.monstats2.get(monstats.MonStatsEx);
setWeaponClass(monstats2.BaseW); setWeaponClass(monstats2.BaseW);
@ -40,7 +45,47 @@ public class Monster extends Entity {
Gdx.app.debug(TAG, "Monster: " + monstats); Gdx.app.debug(TAG, "Monster: " + monstats);
if (monstats == null) return null; // TODO: Which ones fall under this case? Some static entities did, none here yet in testing. if (monstats == null) return null; // TODO: Which ones fall under this case? Some static entities did, none here yet in testing.
//if (!object.Draw) return null; // TODO: Not yet //if (!object.Draw) return null; // TODO: Not yet
return new Monster(monstats); return new Monster(obj, monstats);
} }
@Override
public void drawDebugPath(ShapeRenderer shapes) {
DS1.Path path = object.path;
if (path == null) return;
float p1x = +(position.x * Tile.SUBTILE_WIDTH50) - (position.y * Tile.SUBTILE_WIDTH50);
float p1y = -(position.x * Tile.SUBTILE_HEIGHT50) - (position.y * Tile.SUBTILE_HEIGHT50);
float p2x = 0, p2y = 0;
for (int i = 0; i < path.numPoints; i++) {
DS1.Path.Point point = path.points[i];
p2x = +(point.x * Tile.SUBTILE_WIDTH50) - (point.y * Tile.SUBTILE_WIDTH50);
p2y = -(point.x * Tile.SUBTILE_HEIGHT50) - (point.y * Tile.SUBTILE_HEIGHT50);
shapes.setColor(Color.PURPLE);
shapes.rectLine(p1x, p1y, p2x, p2y, 2);
p1x = p2x;
p1y = p2y;
}
if (path.numPoints > 1) {
DS1.Path.Point point = path.points[0];
p1x = +(point.x * Tile.SUBTILE_WIDTH50) - (point.y * Tile.SUBTILE_WIDTH50);
p1y = -(point.x * Tile.SUBTILE_HEIGHT50) - (point.y * Tile.SUBTILE_HEIGHT50);
shapes.setColor(Color.PURPLE);
shapes.rectLine(p1x, p1y, p2x, p2y, 2);
}
final float BOX_SIZE = 8;
final float HALF_BOX = BOX_SIZE / 2;
p1x = +(position.x * Tile.SUBTILE_WIDTH50) - (position.y * Tile.SUBTILE_WIDTH50);
p1y = -(position.x * Tile.SUBTILE_HEIGHT50) - (position.y * Tile.SUBTILE_HEIGHT50);
shapes.setColor(Color.WHITE);
shapes.rect(p1x - HALF_BOX, p1y - HALF_BOX, BOX_SIZE, BOX_SIZE);
for (int i = 0; i < path.numPoints; i++) {
DS1.Path.Point point = path.points[i];
p1x = +(point.x * Tile.SUBTILE_WIDTH50) - (point.y * Tile.SUBTILE_WIDTH50);
p1y = -(point.x * Tile.SUBTILE_HEIGHT50) - (point.y * Tile.SUBTILE_HEIGHT50);
shapes.setColor(Color.WHITE);
shapes.rect(p1x - HALF_BOX, p1y - HALF_BOX, BOX_SIZE, BOX_SIZE);
}
}
} }

View File

@ -9,11 +9,13 @@ import gdx.diablo.map.DS1;
public class StaticEntity extends Entity { public class StaticEntity extends Entity {
private static final String TAG = "StaticEntity"; private static final String TAG = "StaticEntity";
Objects.Entry object; DS1.Object object;
Objects.Entry base;
public StaticEntity(Objects.Entry object) { public StaticEntity(DS1.Object object, Objects.Entry base) {
super(object.Token, EntType.OBJECT); super(base.Token, EntType.OBJECT);
this.object = object; this.object = object;
this.base = base;
init(); init();
} }
@ -21,10 +23,10 @@ public class StaticEntity extends Entity {
assert obj.type == DS1.Object.STATIC_TYPE; assert obj.type == DS1.Object.STATIC_TYPE;
int id = Diablo.files.obj.getType2(ds1.getAct(), obj.id); int id = Diablo.files.obj.getType2(ds1.getAct(), obj.id);
Objects.Entry object = Diablo.files.objects.get(id); Objects.Entry base = Diablo.files.objects.get(id);
if (object == null) return null; // TODO: Which ones fall under this case? if (base == null) return null; // TODO: Which ones fall under this case?
if (!object.Draw) return null; // TODO: Not yet if (!base.Draw) return null; // TODO: Not yet
return new StaticEntity(object); return new StaticEntity(obj, base);
} }
@Override @Override
@ -32,17 +34,17 @@ public class StaticEntity extends Entity {
super.update(); super.update();
int mode = Diablo.files.ObjMode.index(this.mode); int mode = Diablo.files.ObjMode.index(this.mode);
//System.out.println(getName() + " " + this.mode + "(" + mode + ") " + object.FrameDelta[mode]); //System.out.println(getName() + " " + this.mode + "(" + mode + ") " + object.FrameDelta[mode]);
animation.setLooping(object.CycleAnim[mode]); animation.setLooping(base.CycleAnim[mode]);
animation.setFrame(object.Start[mode]); animation.setFrame(base.Start[mode]);
animation.setFrameDelta(object.FrameDelta[mode]); // FIXME: anim framedelta looks too quick animation.setFrameDelta(base.FrameDelta[mode]); // FIXME: anim framedelta looks too quick
} }
public String getName() { public String getName() {
return object == null ? toString() : object.Name + "(" + object.Id + ")"; return base == null ? toString() : base.Name + "(" + base.Id + ")";
} }
private void init() { private void init() {
switch (object.InitFn) { switch (base.InitFn) {
case 0: case 0:
break; break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
@ -70,12 +72,12 @@ public class StaticEntity extends Entity {
case 79: case 79:
break; break;
default: default:
Gdx.app.error(TAG, "Invalid InitFn for " + getName() + ": " + object.InitFn); Gdx.app.error(TAG, "Invalid InitFn for " + getName() + ": " + base.InitFn);
} }
} }
private void operate() { private void operate() {
switch (object.OperateFn) { switch (base.OperateFn) {
case 0: case 0:
break; break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:
@ -88,30 +90,30 @@ public class StaticEntity extends Entity {
case 70: case 71: case 72: case 73: case 70: case 71: case 72: case 73:
break; break;
default: default:
Gdx.app.error(TAG, "Invalid OperateFn for " + getName() + ": " + object.OperateFn); Gdx.app.error(TAG, "Invalid OperateFn for " + getName() + ": " + base.OperateFn);
} }
} }
private void populate() { private void populate() {
switch (object.PopulateFn) { switch (base.PopulateFn) {
case 0: case 0:
break; break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:
break; break;
default: default:
Gdx.app.error(TAG, "Invalid PopulateFn for " + getName() + ": " + object.PopulateFn); Gdx.app.error(TAG, "Invalid PopulateFn for " + getName() + ": " + base.PopulateFn);
} }
} }
private void client() { private void client() {
switch (object.ClientFn) { switch (base.ClientFn) {
case 0: case 0:
break; break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:
case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18:
break; break;
default: default:
Gdx.app.error(TAG, "Invalid ClientFn for " + getName() + ": " + object.ClientFn); Gdx.app.error(TAG, "Invalid ClientFn for " + getName() + ": " + base.ClientFn);
} }
} }
} }

View File

@ -473,11 +473,12 @@ public class DS1 {
public static final int DYNAMIC_TYPE = 1; public static final int DYNAMIC_TYPE = 1;
public static final int STATIC_TYPE = 2; public static final int STATIC_TYPE = 2;
public int type; public int type;
public int id; public int id;
public int x; public int x;
public int y; public int y;
public int flags; public int flags;
public Path path;
Object read(int version, InputStream in) throws IOException { Object read(int version, InputStream in) throws IOException {
type = EndianUtils.readSwappedInteger(in); type = EndianUtils.readSwappedInteger(in);
@ -485,6 +486,7 @@ public class DS1 {
x = EndianUtils.readSwappedInteger(in); x = EndianUtils.readSwappedInteger(in);
y = EndianUtils.readSwappedInteger(in); y = EndianUtils.readSwappedInteger(in);
flags = version < 6 ? 0 : EndianUtils.readSwappedInteger(in); flags = version < 6 ? 0 : EndianUtils.readSwappedInteger(in);
path = null;
return this; return this;
} }
@ -498,13 +500,14 @@ public class DS1 {
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this) ToStringBuilder builder = new ToStringBuilder(this)
.append("type", getType()) .append("type", getType())
.append("id", id) .append("id", id)
.append("x", x) .append("x", x)
.append("y", y) .append("y", y)
.append("ds1Flags", String.format("%08x", flags)) .append("ds1Flags", String.format("%08x", flags));
.build(); if (path != null) builder.append("path", path);
return builder.build();
} }
} }
@ -540,14 +543,14 @@ public class DS1 {
} }
} }
static class Path { public static class Path {
public static final Path[] EMPTY_PATH_ARRAY = new Path[0]; public static final Path[] EMPTY_PATH_ARRAY = new Path[0];
int numPoints; public int numPoints;
Point points[]; public Point points[];
int x; public int x;
int y; public int y;
Path read(int version, Object[] objects, InputStream in) throws IOException { Path read(int version, Object[] objects, InputStream in) throws IOException {
numPoints = EndianUtils.readSwappedInteger(in); numPoints = EndianUtils.readSwappedInteger(in);
@ -575,6 +578,7 @@ public class DS1 {
} }
for (int p = 0; p < numPoints; p++) points[p] = new Point().read(version, in); for (int p = 0; p < numPoints; p++) points[p] = new Point().read(version, in);
object.path = this;
return this; return this;
} }
@ -588,10 +592,10 @@ public class DS1 {
.build(); .build();
} }
static class Point { public static class Point {
int x; public int x;
int y; public int y;
int action; public int action;
Point read(int version, InputStream in) throws IOException { Point read(int version, InputStream in) throws IOException {
x = EndianUtils.readSwappedInteger(in); x = EndianUtils.readSwappedInteger(in);

View File

@ -745,32 +745,11 @@ public class MapRenderer {
for (x = 0; x < size; x++) { for (x = 0; x < size; x++) {
Map.Zone zone = map.getZone(stx, sty); Map.Zone zone = map.getZone(stx, sty);
if (zone != null) { if (zone != null) {
Map.Preset preset = zone.getGrid(tx, ty); for (Entity entity : zone.entities) {
if (preset != null) { Vector3 position = entity.position();
for (int i = 0; i < preset.ds1.numPaths; i++) { if ((stx <= position.x && position.x < stx + Tile.SUBTILE_SIZE)
DS1.Path path = preset.ds1.paths[i]; && (sty <= position.y && position.y < sty + Tile.SUBTILE_SIZE)) {
if ((stx <= path.x && path.x < stx + Tile.SUBTILE_SIZE) entity.drawDebugPath(shapes);
&& (sty <= path.y && path.y < sty + Tile.SUBTILE_SIZE)) {
DS1.Path.Point prevPoint = null;
for (int j = 0; j < path.numPoints; j++) {
DS1.Path.Point point = path.points[j];
if (prevPoint != null) {
float p1x = +(prevPoint.x * Tile.SUBTILE_WIDTH50) - (prevPoint.y * Tile.SUBTILE_WIDTH50);
float p1y = -(prevPoint.x * Tile.SUBTILE_HEIGHT50) - (prevPoint.y * Tile.SUBTILE_HEIGHT50);
float p2x = +(point.x * Tile.SUBTILE_WIDTH50) - (point.y * Tile.SUBTILE_WIDTH50);
float p2y = -(point.x * Tile.SUBTILE_HEIGHT50) - (point.y * Tile.SUBTILE_HEIGHT50);
shapes.setColor(Color.PURPLE);
shapes.rectLine(p1x, p1y, p2x, p2y, 2);
shapes.setColor(Color.WHITE);
shapes.rect(p1x - 4, p1y - 4, 8, 8);
if (j == path.numPoints - 1) {
shapes.rect(p2x - 4, p2y - 4, 8, 8);
}
}
prevPoint = point;
}
}
} }
} }
} }