diff --git a/build.gradle b/build.gradle index 56fd47d1..3562ce67 100644 --- a/build.gradle +++ b/build.gradle @@ -174,6 +174,12 @@ project(":core") { compile group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1' compile group: 'com.jcraft', name: 'jzlib', version: '1.1.3' } + + dependencies { + testCompile 'junit:junit:4.12' + testCompile "com.badlogicgames.gdx:gdx-backend-headless:1.9.9" + testCompile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + } } project(":server") { diff --git a/core/build.gradle b/core/build.gradle index 42ff9fd9..5e4e04b9 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -4,6 +4,7 @@ sourceCompatibility = 1.7 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' sourceSets.main.java.srcDirs = [ "src/" ] +sourceSets.test.java.srcDirs = [ "test/" ] eclipse.project { diff --git a/core/src/gdx/diablo/Char.java b/core/src/gdx/diablo/Char.java index 8c00b9a7..5f8a5a8f 100644 --- a/core/src/gdx/diablo/Char.java +++ b/core/src/gdx/diablo/Char.java @@ -31,7 +31,7 @@ public class Char { public String armType; public float angle; - public Animation.COFAnimation animation; + public Animation animation; public Char(CharClass charClass) { this.charClass = charClass; @@ -115,7 +115,7 @@ public class Char { // FIXME: dispose/unload old animation layer //if (animation != null) animation.dispose(); Animation oldAnim = animation; - animation = new Animation.COFAnimation(cof); + animation = Animation.newAnimation(cof); if (oldAnim != null) animation.setDirection(oldAnim.getDirection()); String helm = "cap"; diff --git a/core/src/gdx/diablo/codec/Animation.java b/core/src/gdx/diablo/codec/Animation.java index 7d52fc38..7cbff818 100644 --- a/core/src/gdx/diablo/codec/Animation.java +++ b/core/src/gdx/diablo/codec/Animation.java @@ -2,8 +2,6 @@ package gdx.diablo.codec; import com.google.common.base.Preconditions; -import android.support.annotation.Nullable; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; @@ -12,9 +10,9 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.math.Affine2; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.scenes.scene2d.utils.BaseDrawable; -import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Bits; +import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import gdx.diablo.BlendMode; @@ -22,64 +20,108 @@ import gdx.diablo.Diablo; import gdx.diablo.codec.util.BBox; import gdx.diablo.graphics.PaletteIndexedBatch; -public abstract class Animation extends BaseDrawable { +public class Animation extends BaseDrawable { private static final String TAG = "Animation"; + private static final int NUM_LAYERS = 16; private static final float FRAMES_PER_SECOND = 25f; private static final float FRAME_DURATION = 1 / FRAMES_PER_SECOND; - final Bits dirs; - - private final int numDirections; - private final int numFrames; + private static final Color SHADOW_TINT = new Color(0, 0, 0, 0.5f); + private static final Affine2 SHADOW_TRANSFORM = new Affine2(); + private int numDirections; + private int numFrames; private int direction; private int frame; private boolean looping; private float frameDuration; private float elapsedTime; + private Layer layers[]; + private COF cof; + private boolean drawShadow; + //private Bits cache[]; - private final CopyOnWriteArraySet ANIMATION_LISTENERS; + private final Set ANIMATION_LISTENERS; - public Animation(int directions, int framesPerDir) { - this(directions, framesPerDir, 0, new Bits()); - } - public Animation(int directions, int framesPerDir, int d) { - this(directions, framesPerDir, d, new Bits()); + Animation() { + this(0, 0, new Layer[NUM_LAYERS]); } - public Animation(int directions, int framesPerDir, int d, Bits dirs) { + Animation(int directions, int framesPerDir) { + this(directions, framesPerDir, new Layer[NUM_LAYERS]); + } + + Animation(int directions, int framesPerDir, Layer[] layers) { numDirections = directions; numFrames = framesPerDir; - this.dirs = dirs; + this.layers = layers; looping = true; + drawShadow = false; frameDuration = FRAME_DURATION; ANIMATION_LISTENERS = new CopyOnWriteArraySet<>(); - - dirs.set(d); } - public static Animation newAnimation(Layer layer) { - return new AnimationImpl(layer); + public static Animation newAnimation(DC dc) { + return Animation.builder().layer(dc).build(); } - public static Animation newAnimation(DC anim) { - return new AnimationImpl(anim); + public static Animation newAnimation(COF cof) { + Animation animation = new Animation(); + animation.reset(cof); + return animation; } - public static Animation newAnimation(DC anim, int d) { - return new AnimationImpl(anim, d); + public boolean reset(COF cof) { + if (this.cof != cof) { + this.cof = cof; + numDirections = cof.getNumDirections(); + numFrames = cof.getNumFramesPerDir(); + drawShadow = true; + setFrameDelta(cof.getAnimRate()); + + if (direction >= numDirections) direction = 0; + if (frame >= numFrames) { + frame = 0; + elapsedTime = 0; + } + + return true; + } + + return false; } - protected void loadAll() { - for (int d = dirs.nextSetBit(0); d >= 0; d = dirs.nextSetBit(d + 1)) { - load(d); + public static Builder builder() { + return new Builder(); + } + + //protected void loadAll() { + // for (int d = dirs.nextSetBit(0); d >= 0; d = dirs.nextSetBit(d + 1)) { + // load(d); + // } + //} + + protected void load(int d) { + for (Layer l : layers) if (l != null) l.load(d); + } + + public Animation setLayer(int component, DC dc) { + layers[component] = dc != null ? new Layer(dc).load(direction) : null; + return this; + } + + public Layer getLayer(int component) { + return layers[component]; + } + + public void setShadow(boolean b) { + if (b != drawShadow) { + drawShadow = b; } } - protected abstract void load(int d); - public int getNumDirections() { return numDirections; } @@ -95,7 +137,7 @@ public abstract class Animation extends BaseDrawable { public void setDirection(int d) { if (d != direction) { Preconditions.checkArgument(0 <= d && d < numDirections, "Invalid direction: " + d); - if (!dirs.get(d)) load(d); + load(d); direction = d; } } @@ -152,13 +194,121 @@ public abstract class Animation extends BaseDrawable { if (frame == numFrames - 1) notifyAnimationFinished(); } + public void drawDebug(ShapeRenderer shapes, float x, float y) { + if (cof == null) { + boolean reset = !shapes.isDrawing(); + if (reset) { + shapes.begin(ShapeRenderer.ShapeType.Line); + } else { + shapes.set(ShapeRenderer.ShapeType.Line); + } + + shapes.setColor(Color.RED); + shapes.line(x, y, x + 50, y); + shapes.setColor(Color.GREEN); + shapes.line(x, y, x, y + 50); + shapes.setColor(Color.BLUE); + shapes.line(x, y, x + 15, y - 20); + + BBox box = getBox(); + shapes.setColor(layers[0].DEBUG_COLOR); + shapes.rect(x + box.xMin, y - box.yMax, box.width, box.height); + + if (reset) { + shapes.end(); + } + } else { + int d = DC.Direction.toReadDir(direction, cof.getNumDirections()); + int f = frame; + for (int l = 0; l < cof.getNumLayers(); l++) { + int component = cof.getLayerOrder(d, f, l); + Layer layer = layers[component]; + if (layer != null) layer.drawDebug(shapes, d, f, x, y); + } + } + } + public void draw(Batch batch, float x, float y) { draw(batch, x, y, getMinWidth(), getMinHeight()); } - public abstract void drawDebug(ShapeRenderer shapes, float x, float y); + @Override + public void draw(Batch batch, float x, float y, float width, float height) { + draw((PaletteIndexedBatch) batch, x, y); + } - public abstract BBox getBox(); + public void draw(PaletteIndexedBatch batch, float x, float y) { + if (cof == null) { + if (drawShadow) { + for (Layer layer : layers) { + if (layer == null) continue; + drawShadow(batch, layer, x, y); + } + batch.resetBlendMode(); + } + + for (Layer layer : layers) { + if (layer == null) continue; + drawLayer(batch, layer, x, y); + } + batch.resetBlendMode(); + batch.resetColormap(); + } else { + int d = DC.Direction.toReadDir(direction, cof.getNumDirections()); + int f = frame; + if (drawShadow) { + for (int l = 0; l < cof.getNumLayers(); l++) { + int component = cof.getLayerOrder(d, f, l); + Layer layer = layers[component]; + if (layer != null) { + COF.Layer cofLayer = cof.getComponent(component); + if (cofLayer.shadow == 0x1) { + drawShadow(batch, layer, x, y); + } + } + } + batch.resetBlendMode(); + } + + // TODO: Layer blend modes should correspond with the cof trans levels + for (int l = 0; l < cof.getNumLayers(); l++) { + int component = cof.getLayerOrder(d, f, l); + Layer layer = layers[component]; + if (layer != null) drawLayer(batch, layer, x, y); + } + batch.resetBlendMode(); + batch.resetColormap(); + } + } + + public void drawShadow(PaletteIndexedBatch batch, Layer layer, float x, float y) { + int d = direction; + int f = frame; + + DC dc = layer.dc; + BBox box = dc.getBox(d, f); + + SHADOW_TRANSFORM.idt(); + SHADOW_TRANSFORM.preTranslate(box.xMin, -(box.yMax / 2)); + SHADOW_TRANSFORM.preShear(-1.0f, 0); + SHADOW_TRANSFORM.preTranslate(x, y); + SHADOW_TRANSFORM.scale(1, 0.5f); + + if (layer.regions[d] == null) layer.load(d); + TextureRegion region = layer.regions[d][f]; + batch.setBlendMode(BlendMode.TINT_BLACKS, SHADOW_TINT); + batch.draw(region, region.getRegionWidth(), region.getRegionHeight(), SHADOW_TRANSFORM); + } + + public void drawLayer(PaletteIndexedBatch batch, Layer layer, float x, float y) { + layer.draw(batch, direction, frame, x, y); + } + + public BBox getBox() { + return cof == null + ? layers[0].dc.getDirection(direction).box + : cof.box; + } @Override public float getMinWidth() { @@ -170,10 +320,6 @@ public abstract class Animation extends BaseDrawable { return getBox().height; } - public CompositeAnimation composite() { - throw new UnsupportedOperationException(); - } - private void notifyAnimationFinished() { for (AnimationListener l : ANIMATION_LISTENERS) { l.onFinished(this); @@ -185,11 +331,11 @@ public abstract class Animation extends BaseDrawable { return ANIMATION_LISTENERS.add(l); } - public boolean removeAnimationListener(@Nullable Object o) { + public boolean removeAnimationListener(Object o) { return o != null && ANIMATION_LISTENERS.remove(o); } - public boolean containsAnimationListener(@Nullable Object o) { + public boolean containsAnimationListener(Object o) { return o != null && ANIMATION_LISTENERS.contains(o); } @@ -198,35 +344,27 @@ public abstract class Animation extends BaseDrawable { } public static class Layer { - public static Layer from(DC anim) { - return new Layer(anim); - } + private final Color DEBUG_COLOR = new Color(MathUtils.random(), MathUtils.random(), MathUtils.random(), 1); - public static Layer from(DC anim, int blendMode) { - return new Layer(anim, blendMode); - } - - final DC base; + final DC dc; final TextureRegion regions[][]; final int numDirections; final int numFrames; - int blendMode; + int blendMode; Index transform; - int transformColor; + int transformColor; - private final Color DEBUG_COLOR = new Color(MathUtils.random(), MathUtils.random(), MathUtils.random(), 1); - - Layer(DC anim) { - this(anim, BlendMode.ID); + Layer(DC dc) { + this(dc, BlendMode.ID); } - Layer(DC anim, int blendMode) { + Layer(DC dc, int blendMode) { + this.dc = dc; this.blendMode = blendMode; - numDirections = anim.getNumDirections(); - numFrames = anim.getNumFramesPerDir(); - base = anim; + numDirections = dc.getNumDirections(); + numFrames = dc.getNumFramesPerDir(); regions = new TextureRegion[numDirections][]; transform = null; transformColor = 0; @@ -242,10 +380,10 @@ public abstract class Animation extends BaseDrawable { protected Layer load(int d) { if (regions[d] != null) return this; - base.loadDirection(d); + dc.loadDirection(d); regions[d] = new TextureRegion[numFrames]; for (int f = 0; f < numFrames; f++) { - regions[d][f] = base.getTexture(d, f); + regions[d][f] = dc.getTexture(d, f); } return this; @@ -256,7 +394,7 @@ public abstract class Animation extends BaseDrawable { } public void setTransform(Index colormap, int id) { - //if ( colormap != null) System.out.println("----> " + colormap + "; " + id); + //if (colormap != null) System.out.println("----> " + colormap + "; " + id); transform = colormap; transformColor = colormap == null ? 0 : id; } @@ -269,28 +407,8 @@ public abstract class Animation extends BaseDrawable { } } - /* - public void setTransform(byte packedTransform) { - if ((packedTransform & 0xFF) == 0xFF) { - transform = 0; - transformColor = 0; - } else { - transform = packedTransform >>> 4; - transformColor = packedTransform & 0xF; - } - } - - public void setTransform(int transform) { - this.transform = transform; - } - - public void setTransformColor(int colorId) { - this.transformColor = colorId; - } - */ - protected void draw(Batch batch, int d, int f, float x, float y) { - BBox box = base.getBox(d, f); + BBox box = dc.getBox(d, f); x += box.xMin; y -= box.yMax; if (regions[d] == null) load(d); @@ -315,7 +433,7 @@ public abstract class Animation extends BaseDrawable { shapeRenderer.setColor(Color.BLUE); shapeRenderer.line(x, y, x + 20, y - 10); - BBox box = base.getDirection(d).box; + BBox box = dc.getDirection(d).box; shapeRenderer.setColor(DEBUG_COLOR); shapeRenderer.rect(x + box.xMin, y - box.yMax, box.width, box.height); @@ -325,260 +443,26 @@ public abstract class Animation extends BaseDrawable { } } - public static class AnimationImpl extends Animation { - final Layer layer; + public static class Builder { + int size = 0; + Layer layers[] = new Layer[NUM_LAYERS]; - AnimationImpl(DC base) { - super(base.getNumDirections(), base.getNumFramesPerDir()); - layer = new Layer(base); - loadAll(); + public Builder layer(DC dc) { + return layer(new Layer(dc)); } - AnimationImpl(DC base, int d) { - super(base.getNumDirections(), base.getNumFramesPerDir(), d); - layer = new Layer(base); - loadAll(); + public Builder layer(DC dc, int blendMode) { + return layer(new Layer(dc, blendMode)); } - AnimationImpl(Layer layer) { - super(layer.numDirections, layer.numFrames); - this.layer = layer; - loadAll(); - } - - @Override - public CompositeAnimation composite() { - return new CompositeAnimation(this); - } - - @Override - protected void load(int d) { - layer.load(d); - } - - @Override - public void draw(Batch batch, float x, float y, float width, float height) { - layer.draw(batch, getDirection(), getFrame(), x, y); - } - - @Override - public void drawDebug(ShapeRenderer shapes, float x, float y) { - layer.drawDebug(shapes, getDirection(), getFrame(), x, y); - } - - @Override - public BBox getBox() { - return layer.base.getDirection(getDirection()).box; - } - } - - public static class CompositeAnimation extends Animation { - private static final Color SHADOW_TINT = new Color(0, 0, 0, 0.5f); - private static final Affine2 SHADOW_TRANSFORM = new Affine2(); - - static final int DEFAULT_LAYERS = 4; - - final Array layers; - - public CompositeAnimation(Animation anim) { - super(anim.numDirections, anim.numFrames, anim.direction, anim.dirs); - layers = new Array<>(DEFAULT_LAYERS); - if (anim instanceof AnimationImpl) { - AnimationImpl impl = (AnimationImpl) anim; - layers.add(impl.layer); - } else if (anim instanceof CompositeAnimation) { - CompositeAnimation impl = (CompositeAnimation) anim; - layers.addAll(impl.layers); - } else { - throw new UnsupportedOperationException(); - } - } - - public CompositeAnimation(Layer base) { - super(base.numFrames, base.numDirections); - layers = new Array<>(DEFAULT_LAYERS); - addLayer(base); - } - - public CompositeAnimation(Layer... layers) { - super(layers[0].numDirections, layers[0].numFrames); - this.layers = new Array<>(layers); - } - - public CompositeAnimation(DC... anims) { - super(anims[0].getNumDirections(), anims[0].getNumFramesPerDir()); - this.layers = new Array<>(anims.length); - for (DC anim : anims) addLayer(Layer.from(anim)); - } - - public CompositeAnimation(int directions, int framesPerDir, int numLayers) { - super(directions, framesPerDir); - layers = new Array<>(numLayers); - for (int i = 0; i < numLayers; i++) { - layers.add(null); - } - } - - @Override - protected void load(int d) { - for (Layer l : layers) if (l != null) l.load(d); - } - - public CompositeAnimation addAll(Layer[] layers) { - for (Layer layer : layers) addLayer(layer); + public Builder layer(Layer layer) { + layers[size++] = layer; return this; } - public CompositeAnimation addLayer(Layer layer) { - return addLayer(layer, layer.blendMode); - } - - public CompositeAnimation addLayer(Layer layer, int blendMode) { - layer.blendMode = blendMode; - layers.add(layer.loadAll(dirs)); - return this; - } - - public CompositeAnimation setLayer(int layer, DC anim) { - layers.set(layer, new Layer(anim).loadAll(dirs)); - return this; - } - - public Layer getLayer(int i) { - return layers.get(i); - } - - public void drawShadow(Batch batch, Layer layer, float x, float y) { - int d = getDirection(); - int f = getFrame(); - - DC base = layer.base; - BBox box = base.getBox(d, f); - - SHADOW_TRANSFORM.idt(); - SHADOW_TRANSFORM.preTranslate(box.xMin, -(box.yMax / 2)); - SHADOW_TRANSFORM.preShear(-1.0f, 0); - SHADOW_TRANSFORM.preTranslate(x, y); - SHADOW_TRANSFORM.scale(1, 0.5f); - - if (layer.regions[d] == null) layer.load(d); - TextureRegion region = layer.regions[d][f]; - ((PaletteIndexedBatch) batch).setBlendMode(BlendMode.TINT_BLACKS, SHADOW_TINT); - batch.draw(region, region.getRegionWidth(), region.getRegionHeight(), SHADOW_TRANSFORM); - } - - public void drawLayer(Batch batch, Layer layer, float x, float y) { - layer.draw(batch, getDirection(), getFrame(), x, y); - } - - @Override - public void draw(Batch batch, float x, float y, float width, float height) { - for (int i = 0; i < layers.size; i++) { - Layer layer = layers.get(i); - if (layer == null) { - continue; - } - - drawLayer(batch, layer, x, y); - } - - ((PaletteIndexedBatch) batch).resetBlendMode(); - ((PaletteIndexedBatch) batch).resetColormap(); - } - - @Override - public void drawDebug(ShapeRenderer shapes, float x, float y) { - boolean reset = !shapes.isDrawing(); - if (reset) { - shapes.begin(ShapeRenderer.ShapeType.Line); - } else { - shapes.set(ShapeRenderer.ShapeType.Line); - } - - shapes.setColor(Color.RED); - shapes.line(x, y, x + 50, y); - shapes.setColor(Color.GREEN); - shapes.line(x, y, x, y + 50); - shapes.setColor(Color.BLUE); - shapes.line(x, y, x + 15, y - 20); - - BBox box = getBox(); - shapes.setColor(layers.first().DEBUG_COLOR); - shapes.rect(x + box.xMin, y - box.yMax, box.width, box.height); - - if (reset) { - shapes.end(); - } - } - - @Override - public BBox getBox() { - return layers.first().base.getDirection(super.direction).box; - } - } - - public static class COFAnimation extends CompositeAnimation { - - final COF cof; - boolean drawShadow = true; - - public COFAnimation(COF cof) { - // TODO: 15 needs to be a variable - super(cof.getNumDirections(), cof.getNumFramesPerDir(), 15); - this.cof = cof; - setFrameDelta(cof.getAnimRate()); - } - - public COF getCOF() { - return cof; - } - - public void setShadow(boolean b) { - if (b != drawShadow) { - drawShadow = b; - } - } - - @Override - public void draw(Batch batch, float x, float y, float width, float height) { - int d = DC.Direction.toReadDir(getDirection(), cof.getNumDirections()); - int f = getFrame(); - for (int l = 0; l < cof.getNumLayers(); l++) { - int component = cof.getLayerOrder(d, f, l); - Layer layer = layers.get(component); - if (layer != null) { - COF.Layer cofLayer = cof.getComponent(component); - if (drawShadow && cofLayer.shadow == 0x1) { - drawShadow(batch, layer, x, y); - } - } - } - ((PaletteIndexedBatch) batch).resetBlendMode(); - - // TODO: Layer blend modes should correspond with the cof trans levels - for (int l = 0; l < cof.getNumLayers(); l++) { - int component = cof.getLayerOrder(d, f, l); - Layer layer = layers.get(component); - if (layer != null) drawLayer(batch, layer, x, y); - } - ((PaletteIndexedBatch) batch).resetBlendMode(); - ((PaletteIndexedBatch) batch).resetColormap(); - } - - @Override - public void drawDebug(ShapeRenderer shapes, float x, float y) { - int d = DC.Direction.toReadDir(getDirection(), cof.getNumDirections()); - int f = getFrame(); - for (int l = 0; l < cof.getNumLayers(); l++) { - int component = cof.getLayerOrder(d, f, l); - Layer layer = layers.get(component); - if (layer != null) layer.drawDebug(shapes, d, f, x, y); - } - } - - @Override - public BBox getBox() { - return cof.box; + public Animation build() { + Layer first = layers[0]; + return new Animation(first.numDirections, first.numFrames, layers); } } } diff --git a/core/src/gdx/diablo/codec/Animation.java.bak2 b/core/src/gdx/diablo/codec/Animation.java.bak2 new file mode 100644 index 00000000..7d52fc38 --- /dev/null +++ b/core/src/gdx/diablo/codec/Animation.java.bak2 @@ -0,0 +1,584 @@ +package gdx.diablo.codec; + +import com.google.common.base.Preconditions; + +import android.support.annotation.Nullable; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Affine2; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.scenes.scene2d.utils.BaseDrawable; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Bits; + +import java.util.concurrent.CopyOnWriteArraySet; + +import gdx.diablo.BlendMode; +import gdx.diablo.Diablo; +import gdx.diablo.codec.util.BBox; +import gdx.diablo.graphics.PaletteIndexedBatch; + +public abstract class Animation extends BaseDrawable { + private static final String TAG = "Animation"; + + private static final float FRAMES_PER_SECOND = 25f; + private static final float FRAME_DURATION = 1 / FRAMES_PER_SECOND; + + final Bits dirs; + + private final int numDirections; + private final int numFrames; + + private int direction; + private int frame; + private boolean looping; + private float frameDuration; + private float elapsedTime; + + private final CopyOnWriteArraySet ANIMATION_LISTENERS; + + public Animation(int directions, int framesPerDir) { + this(directions, framesPerDir, 0, new Bits()); + } + public Animation(int directions, int framesPerDir, int d) { + this(directions, framesPerDir, d, new Bits()); + } + + public Animation(int directions, int framesPerDir, int d, Bits dirs) { + numDirections = directions; + numFrames = framesPerDir; + this.dirs = dirs; + looping = true; + frameDuration = FRAME_DURATION; + + ANIMATION_LISTENERS = new CopyOnWriteArraySet<>(); + + dirs.set(d); + } + + public static Animation newAnimation(Layer layer) { + return new AnimationImpl(layer); + } + + public static Animation newAnimation(DC anim) { + return new AnimationImpl(anim); + } + + public static Animation newAnimation(DC anim, int d) { + return new AnimationImpl(anim, d); + } + + protected void loadAll() { + for (int d = dirs.nextSetBit(0); d >= 0; d = dirs.nextSetBit(d + 1)) { + load(d); + } + } + + protected abstract void load(int d); + + public int getNumDirections() { + return numDirections; + } + + public int getNumFramesPerDir() { + return numFrames; + } + + public int getDirection() { + return direction; + } + + public void setDirection(int d) { + if (d != direction) { + Preconditions.checkArgument(0 <= d && d < numDirections, "Invalid direction: " + d); + if (!dirs.get(d)) load(d); + direction = d; + } + } + + public int getFrame() { + return frame; + } + + public void setFrame(int f) { + if (f != frame) { + Preconditions.checkArgument(0 <= f && f < numFrames, "Invalid frame: " + f); + frame = f; + elapsedTime = frameDuration * frame; + if (frame == numFrames - 1) notifyAnimationFinished(); + } + } + + public boolean isLooping() { + return looping; + } + + public void setLooping(boolean b) { + looping = b; + } + + public float getFrameDuration() { + return frameDuration; + } + + public void setFrameDuration(float f) { + frameDuration = f; + elapsedTime = frameDuration * frame; + } + + public void setFrameDelta(int delta) { + setFrameDuration(256f / (delta * FRAMES_PER_SECOND)); + } + + public int getKeyFrameIndex(float stateTime) { + if (numFrames == 1) return 0; + int frameNumber = (int) (stateTime / frameDuration); + return looping + ? frameNumber % numFrames + : Math.min(numFrames - 1, frameNumber); + } + + public void act() { + act(Gdx.graphics.getDeltaTime()); + } + + public void act(float delta) { + elapsedTime += delta; + frame = getKeyFrameIndex(elapsedTime); + if (frame == numFrames - 1) notifyAnimationFinished(); + } + + public void draw(Batch batch, float x, float y) { + draw(batch, x, y, getMinWidth(), getMinHeight()); + } + + public abstract void drawDebug(ShapeRenderer shapes, float x, float y); + + public abstract BBox getBox(); + + @Override + public float getMinWidth() { + return getBox().width; + } + + @Override + public float getMinHeight() { + return getBox().height; + } + + public CompositeAnimation composite() { + throw new UnsupportedOperationException(); + } + + private void notifyAnimationFinished() { + for (AnimationListener l : ANIMATION_LISTENERS) { + l.onFinished(this); + } + } + + public boolean addAnimationListener(AnimationListener l) { + Preconditions.checkArgument(l != null, "l cannot be null"); + return ANIMATION_LISTENERS.add(l); + } + + public boolean removeAnimationListener(@Nullable Object o) { + return o != null && ANIMATION_LISTENERS.remove(o); + } + + public boolean containsAnimationListener(@Nullable Object o) { + return o != null && ANIMATION_LISTENERS.contains(o); + } + + public interface AnimationListener { + void onFinished(Animation animation); + } + + public static class Layer { + public static Layer from(DC anim) { + return new Layer(anim); + } + + public static Layer from(DC anim, int blendMode) { + return new Layer(anim, blendMode); + } + + final DC base; + final TextureRegion regions[][]; + + final int numDirections; + final int numFrames; + + int blendMode; + Index transform; + int transformColor; + + private final Color DEBUG_COLOR = new Color(MathUtils.random(), MathUtils.random(), MathUtils.random(), 1); + + Layer(DC anim) { + this(anim, BlendMode.ID); + } + + Layer(DC anim, int blendMode) { + this.blendMode = blendMode; + numDirections = anim.getNumDirections(); + numFrames = anim.getNumFramesPerDir(); + base = anim; + regions = new TextureRegion[numDirections][]; + transform = null; + transformColor = 0; + } + + protected Layer loadAll(Bits dirs) { + for (int d = dirs.nextSetBit(0); d >= 0; d = dirs.nextSetBit(d + 1)) { + load(d); + } + + return this; + } + + protected Layer load(int d) { + if (regions[d] != null) return this; + base.loadDirection(d); + regions[d] = new TextureRegion[numFrames]; + for (int f = 0; f < numFrames; f++) { + regions[d][f] = base.getTexture(d, f); + } + + return this; + } + + public void setBlendMode(int blendMode) { + this.blendMode = blendMode; + } + + public void setTransform(Index colormap, int id) { + //if ( colormap != null) System.out.println("----> " + colormap + "; " + id); + transform = colormap; + transformColor = colormap == null ? 0 : id; + } + + public void setTransform(byte packedTransform) { + if ((packedTransform & 0xFF) == 0xFF) { + setTransform(null, 0); + } else { + setTransform(Diablo.colormaps.get(packedTransform >>> 5), packedTransform & 0x1F); + } + } + + /* + public void setTransform(byte packedTransform) { + if ((packedTransform & 0xFF) == 0xFF) { + transform = 0; + transformColor = 0; + } else { + transform = packedTransform >>> 4; + transformColor = packedTransform & 0xF; + } + } + + public void setTransform(int transform) { + this.transform = transform; + } + + public void setTransformColor(int colorId) { + this.transformColor = colorId; + } + */ + + protected void draw(Batch batch, int d, int f, float x, float y) { + BBox box = base.getBox(d, f); + x += box.xMin; + y -= box.yMax; + if (regions[d] == null) load(d); + PaletteIndexedBatch b = (PaletteIndexedBatch) batch; + b.setBlendMode(blendMode); + b.setColormap(transform, transformColor); + b.draw(regions[d][f], x, y); + } + + protected void drawDebug(ShapeRenderer shapeRenderer, int d, int f, float x, float y) { + boolean reset = !shapeRenderer.isDrawing(); + if (reset) { + shapeRenderer.begin(ShapeRenderer.ShapeType.Line); + } else { + shapeRenderer.set(ShapeRenderer.ShapeType.Line); + } + + shapeRenderer.setColor(Color.RED); + shapeRenderer.line(x, y, x + 40, y); + shapeRenderer.setColor(Color.GREEN); + shapeRenderer.line(x, y, x, y + 20); + shapeRenderer.setColor(Color.BLUE); + shapeRenderer.line(x, y, x + 20, y - 10); + + BBox box = base.getDirection(d).box; + shapeRenderer.setColor(DEBUG_COLOR); + shapeRenderer.rect(x + box.xMin, y - box.yMax, box.width, box.height); + + if (reset) { + shapeRenderer.end(); + } + } + } + + public static class AnimationImpl extends Animation { + final Layer layer; + + AnimationImpl(DC base) { + super(base.getNumDirections(), base.getNumFramesPerDir()); + layer = new Layer(base); + loadAll(); + } + + AnimationImpl(DC base, int d) { + super(base.getNumDirections(), base.getNumFramesPerDir(), d); + layer = new Layer(base); + loadAll(); + } + + AnimationImpl(Layer layer) { + super(layer.numDirections, layer.numFrames); + this.layer = layer; + loadAll(); + } + + @Override + public CompositeAnimation composite() { + return new CompositeAnimation(this); + } + + @Override + protected void load(int d) { + layer.load(d); + } + + @Override + public void draw(Batch batch, float x, float y, float width, float height) { + layer.draw(batch, getDirection(), getFrame(), x, y); + } + + @Override + public void drawDebug(ShapeRenderer shapes, float x, float y) { + layer.drawDebug(shapes, getDirection(), getFrame(), x, y); + } + + @Override + public BBox getBox() { + return layer.base.getDirection(getDirection()).box; + } + } + + public static class CompositeAnimation extends Animation { + private static final Color SHADOW_TINT = new Color(0, 0, 0, 0.5f); + private static final Affine2 SHADOW_TRANSFORM = new Affine2(); + + static final int DEFAULT_LAYERS = 4; + + final Array layers; + + public CompositeAnimation(Animation anim) { + super(anim.numDirections, anim.numFrames, anim.direction, anim.dirs); + layers = new Array<>(DEFAULT_LAYERS); + if (anim instanceof AnimationImpl) { + AnimationImpl impl = (AnimationImpl) anim; + layers.add(impl.layer); + } else if (anim instanceof CompositeAnimation) { + CompositeAnimation impl = (CompositeAnimation) anim; + layers.addAll(impl.layers); + } else { + throw new UnsupportedOperationException(); + } + } + + public CompositeAnimation(Layer base) { + super(base.numFrames, base.numDirections); + layers = new Array<>(DEFAULT_LAYERS); + addLayer(base); + } + + public CompositeAnimation(Layer... layers) { + super(layers[0].numDirections, layers[0].numFrames); + this.layers = new Array<>(layers); + } + + public CompositeAnimation(DC... anims) { + super(anims[0].getNumDirections(), anims[0].getNumFramesPerDir()); + this.layers = new Array<>(anims.length); + for (DC anim : anims) addLayer(Layer.from(anim)); + } + + public CompositeAnimation(int directions, int framesPerDir, int numLayers) { + super(directions, framesPerDir); + layers = new Array<>(numLayers); + for (int i = 0; i < numLayers; i++) { + layers.add(null); + } + } + + @Override + protected void load(int d) { + for (Layer l : layers) if (l != null) l.load(d); + } + + public CompositeAnimation addAll(Layer[] layers) { + for (Layer layer : layers) addLayer(layer); + return this; + } + + public CompositeAnimation addLayer(Layer layer) { + return addLayer(layer, layer.blendMode); + } + + public CompositeAnimation addLayer(Layer layer, int blendMode) { + layer.blendMode = blendMode; + layers.add(layer.loadAll(dirs)); + return this; + } + + public CompositeAnimation setLayer(int layer, DC anim) { + layers.set(layer, new Layer(anim).loadAll(dirs)); + return this; + } + + public Layer getLayer(int i) { + return layers.get(i); + } + + public void drawShadow(Batch batch, Layer layer, float x, float y) { + int d = getDirection(); + int f = getFrame(); + + DC base = layer.base; + BBox box = base.getBox(d, f); + + SHADOW_TRANSFORM.idt(); + SHADOW_TRANSFORM.preTranslate(box.xMin, -(box.yMax / 2)); + SHADOW_TRANSFORM.preShear(-1.0f, 0); + SHADOW_TRANSFORM.preTranslate(x, y); + SHADOW_TRANSFORM.scale(1, 0.5f); + + if (layer.regions[d] == null) layer.load(d); + TextureRegion region = layer.regions[d][f]; + ((PaletteIndexedBatch) batch).setBlendMode(BlendMode.TINT_BLACKS, SHADOW_TINT); + batch.draw(region, region.getRegionWidth(), region.getRegionHeight(), SHADOW_TRANSFORM); + } + + public void drawLayer(Batch batch, Layer layer, float x, float y) { + layer.draw(batch, getDirection(), getFrame(), x, y); + } + + @Override + public void draw(Batch batch, float x, float y, float width, float height) { + for (int i = 0; i < layers.size; i++) { + Layer layer = layers.get(i); + if (layer == null) { + continue; + } + + drawLayer(batch, layer, x, y); + } + + ((PaletteIndexedBatch) batch).resetBlendMode(); + ((PaletteIndexedBatch) batch).resetColormap(); + } + + @Override + public void drawDebug(ShapeRenderer shapes, float x, float y) { + boolean reset = !shapes.isDrawing(); + if (reset) { + shapes.begin(ShapeRenderer.ShapeType.Line); + } else { + shapes.set(ShapeRenderer.ShapeType.Line); + } + + shapes.setColor(Color.RED); + shapes.line(x, y, x + 50, y); + shapes.setColor(Color.GREEN); + shapes.line(x, y, x, y + 50); + shapes.setColor(Color.BLUE); + shapes.line(x, y, x + 15, y - 20); + + BBox box = getBox(); + shapes.setColor(layers.first().DEBUG_COLOR); + shapes.rect(x + box.xMin, y - box.yMax, box.width, box.height); + + if (reset) { + shapes.end(); + } + } + + @Override + public BBox getBox() { + return layers.first().base.getDirection(super.direction).box; + } + } + + public static class COFAnimation extends CompositeAnimation { + + final COF cof; + boolean drawShadow = true; + + public COFAnimation(COF cof) { + // TODO: 15 needs to be a variable + super(cof.getNumDirections(), cof.getNumFramesPerDir(), 15); + this.cof = cof; + setFrameDelta(cof.getAnimRate()); + } + + public COF getCOF() { + return cof; + } + + public void setShadow(boolean b) { + if (b != drawShadow) { + drawShadow = b; + } + } + + @Override + public void draw(Batch batch, float x, float y, float width, float height) { + int d = DC.Direction.toReadDir(getDirection(), cof.getNumDirections()); + int f = getFrame(); + for (int l = 0; l < cof.getNumLayers(); l++) { + int component = cof.getLayerOrder(d, f, l); + Layer layer = layers.get(component); + if (layer != null) { + COF.Layer cofLayer = cof.getComponent(component); + if (drawShadow && cofLayer.shadow == 0x1) { + drawShadow(batch, layer, x, y); + } + } + } + ((PaletteIndexedBatch) batch).resetBlendMode(); + + // TODO: Layer blend modes should correspond with the cof trans levels + for (int l = 0; l < cof.getNumLayers(); l++) { + int component = cof.getLayerOrder(d, f, l); + Layer layer = layers.get(component); + if (layer != null) drawLayer(batch, layer, x, y); + } + ((PaletteIndexedBatch) batch).resetBlendMode(); + ((PaletteIndexedBatch) batch).resetColormap(); + } + + @Override + public void drawDebug(ShapeRenderer shapes, float x, float y) { + int d = DC.Direction.toReadDir(getDirection(), cof.getNumDirections()); + int f = getFrame(); + for (int l = 0; l < cof.getNumLayers(); l++) { + int component = cof.getLayerOrder(d, f, l); + Layer layer = layers.get(component); + if (layer != null) layer.drawDebug(shapes, d, f, x, y); + } + } + + @Override + public BBox getBox() { + return cof.box; + } + } +} diff --git a/core/src/gdx/diablo/codec/D2S.java b/core/src/gdx/diablo/codec/D2S.java index 62c726af..bbbe5ee3 100644 --- a/core/src/gdx/diablo/codec/D2S.java +++ b/core/src/gdx/diablo/codec/D2S.java @@ -30,7 +30,7 @@ import gdx.diablo.util.DebugUtils; public class D2S { private static final String TAG = "D2S"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = !true; private static final boolean DEBUG_HEADER = DEBUG && true; private static final boolean DEBUG_QUESTS = DEBUG && true; private static final boolean DEBUG_WAYPOINTS = DEBUG && true; diff --git a/core/src/gdx/diablo/codec/excel/PlrType.java b/core/src/gdx/diablo/codec/excel/PlrType.java index 60ba41c6..8a11b9f4 100644 --- a/core/src/gdx/diablo/codec/excel/PlrType.java +++ b/core/src/gdx/diablo/codec/excel/PlrType.java @@ -1,6 +1,14 @@ package gdx.diablo.codec.excel; -public class PlrType extends Excel{ +public class PlrType extends Excel { + public static final int AM = 0; + public static final int SO = 1; + public static final int NE = 2; + public static final int PA = 3; + public static final int BA = 4; + public static final int DZ = 5; + public static final int AS = 6; + public static class Entry extends Excel.Entry { @Override public String toString() { diff --git a/core/src/gdx/diablo/entity/Player.java b/core/src/gdx/diablo/entity/Player.java index 63b4f5d8..2a4efd50 100644 --- a/core/src/gdx/diablo/entity/Player.java +++ b/core/src/gdx/diablo/entity/Player.java @@ -60,7 +60,7 @@ public class Player { boolean dirty; String cofId; - Animation.COFAnimation anim; + Animation anim; EnumMap equipped; Array inventory; @@ -335,7 +335,7 @@ public class Player { //if (animation != null) animation.dispose(); Animation oldAnim = anim; - anim = new Animation.COFAnimation(cof); + anim = Animation.newAnimation(cof); // TODO: This might be a problem anim.setDirection(oldAnim != null ? oldAnim.getDirection() : getDirection()); diff --git a/core/src/gdx/diablo/entity3/Component.java b/core/src/gdx/diablo/entity3/Component.java new file mode 100644 index 00000000..b4d14c3e --- /dev/null +++ b/core/src/gdx/diablo/entity3/Component.java @@ -0,0 +1,46 @@ +package gdx.diablo.entity3; + +import com.badlogic.gdx.Gdx; + +public enum Component { + HD, + TR, + LG, + RA, + LA, + RH, + LH, + SH, + S1, + S2, + S3, + S4, + S5, + S6, + S7, + S8; + + public static Component valueOf(int i) { + switch (i) { + case 0x0: return HD; + case 0x1: return TR; + case 0x2: return LG; + case 0x3: return RA; + case 0x4: return LA; + case 0x5: return RH; + case 0x6: return LH; + case 0x7: return SH; + case 0x8: return S1; + case 0x9: return S2; + case 0xA: return S3; + case 0xB: return S4; + case 0xC: return S5; + case 0xD: return S6; + case 0xE: return S7; + case 0xF: return S8; + default: + Gdx.app.error("Component", "Unknown component: " + i); + return null; + } + } +} diff --git a/core/src/gdx/diablo/entity3/Entity.java b/core/src/gdx/diablo/entity3/Entity.java new file mode 100644 index 00000000..b84cbe17 --- /dev/null +++ b/core/src/gdx/diablo/entity3/Entity.java @@ -0,0 +1,293 @@ +package gdx.diablo.entity3; + +import android.support.annotation.CallSuper; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.assets.AssetDescriptor; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.GridPoint2; +import com.badlogic.gdx.math.MathUtils; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ObjectUtils; + +import java.util.Arrays; + +import gdx.diablo.Diablo; +import gdx.diablo.codec.Animation; +import gdx.diablo.codec.COF; +import gdx.diablo.codec.COFD2; +import gdx.diablo.codec.DCC; +import gdx.diablo.entity.Direction; +import gdx.diablo.graphics.PaletteIndexedBatch; +import gdx.diablo.item.Item; +import gdx.diablo.map.DT1.Tile; + +public class Entity { + private static final String TAG = "Entity"; + private static final boolean DEBUG = true; + private static final boolean DEBUG_COMPONENTS = DEBUG && true; + private static final boolean DEBUG_DIRTY = DEBUG && true; + private static final boolean DEBUG_ASSETS = DEBUG && true; + private static final boolean DEBUG_WCLASS = DEBUG && true; + + protected enum EntType { + OBJECT, + MONSTER, + CHARS; + + public final String PATH = "data\\global\\" + name() + "\\"; + } + + public static final class Dirty { + public static final int NONE = 0; + public static final int HD = 1 << 0; + public static final int TR = 1 << 1; + public static final int LG = 1 << 2; + public static final int RA = 1 << 3; + public static final int LA = 1 << 4; + public static final int RH = 1 << 5; + public static final int LH = 1 << 6; + public static final int SH = 1 << 7; + public static final int S1 = 1 << 8; + public static final int S2 = 1 << 9; + public static final int S3 = 1 << 10; + public static final int S4 = 1 << 11; + public static final int S5 = 1 << 12; + public static final int S6 = 1 << 13; + public static final int S7 = 1 << 14; + public static final int S8 = 1 << 15; + + public static String toString(int bits) { + StringBuilder builder = new StringBuilder(); + if (bits == NONE) { + builder.append("NONE"); + } else { + if ((bits & HD) == HD) builder.append("HD").append("|"); + if ((bits & TR) == TR) builder.append("TR").append("|"); + if ((bits & LG) == LG) builder.append("LG").append("|"); + if ((bits & RA) == RA) builder.append("RA").append("|"); + if ((bits & LA) == LA) builder.append("LA").append("|"); + if ((bits & RH) == RH) builder.append("RH").append("|"); + if ((bits & LH) == LH) builder.append("LH").append("|"); + if ((bits & SH) == SH) builder.append("SH").append("|"); + if ((bits & S1) == S1) builder.append("S1").append("|"); + if ((bits & S2) == S2) builder.append("S2").append("|"); + if ((bits & S3) == S3) builder.append("S3").append("|"); + if ((bits & S4) == S4) builder.append("S4").append("|"); + if ((bits & S5) == S5) builder.append("S5").append("|"); + if ((bits & S6) == S6) builder.append("S6").append("|"); + if ((bits & S7) == S7) builder.append("S7").append("|"); + if ((bits & S8) == S8) builder.append("S8").append("|"); + if (builder.length() > 0) builder.setLength(builder.length() - 1); + } + return builder.toString(); + } + } + + private final int ALL_DIRTY = 0x0000FFFF; + protected static final String DEFAULT_LAYER = "LIT"; + private static final String[] DEFAULT_LAYERS; + static { + DEFAULT_LAYERS = new String[16]; + Arrays.fill(DEFAULT_LAYERS, DEFAULT_LAYER); + } + + GridPoint2 origin = new GridPoint2(); + float angle = MathUtils.PI * 3 / 2; + + int dirty; + String type; + String mode; + String code; + String layers[]; + String weaponClass; + + EntType entType; + Animation animation; + + Entity(String type) { + this(type, EntType.OBJECT); + } + + Entity(String type, EntType entType) { + this.type = type; + this.entType = entType; + mode = code = "NU"; + weaponClass = "HTH"; + layers = DEFAULT_LAYERS; + invalidate(); + } + + public void setMode(String mode) { + setMode(mode, mode); + } + + public void setMode(String mode, String code) { + if (!this.mode.equals(mode)) { + this.mode = mode; + invalidate(); + } + + this.code = code; + } + + public void setWeaponClass(String wclass) { + if (!weaponClass.equals(wclass)) { + if (DEBUG_WCLASS) Gdx.app.debug(TAG, "wclass: " + weaponClass + " -> " + wclass); + weaponClass = wclass; + invalidate(); + } + } + + public void setArmType(Component component, String armType) { + if (layers == DEFAULT_LAYERS) { + if (!armType.equalsIgnoreCase(DEFAULT_LAYER)) { + layers = ArrayUtils.clone(DEFAULT_LAYERS); + } else { + return; + } + } + + int ordinal = component.ordinal(); + if (layers[ordinal].equalsIgnoreCase(armType)) { + return; + } + + if (DEBUG_COMPONENTS) Gdx.app.debug(TAG, "layer " + ordinal + " " + layers[ordinal] + " -> " + armType); + layers[ordinal] = armType; + dirty |= (1 << ordinal); + } + + protected Item getItem(Component component) { + return null; + } + + public final void invalidate() { + dirty = ALL_DIRTY; + } + + public final void validate() { + if (dirty == 0) { + return; + } + + update(); + } + + @CallSuper + protected void update() { + String path = type + mode + weaponClass; + Gdx.app.log(TAG, path); + + COF cof = getCOFs().lookup(path); + Gdx.app.log(TAG, ObjectUtils.toString(cof)); + + boolean changed; + if (animation == null) { + animation = Animation.newAnimation(cof); + changed = true; + } else { + changed = animation.reset(cof); + } + + if (changed) { + dirty = ALL_DIRTY; + animation.setDirection(getDirection()); + } + + if (DEBUG_DIRTY) Gdx.app.debug(TAG, "dirty layers: " + Dirty.toString(dirty)); + for (int l = 0; l < cof.getNumLayers(); l++) { + COF.Layer layer = cof.getLayer(l); + if (((1 << layer.component) & dirty) == 0) { + continue; + } + + final int c = layer.component; + final Component comp = Component.valueOf(c); + if (comp == null) continue; + String component = comp.name(); + String armType = layers[c]; + String weaponClass = layer.weaponClass; + path = entType.PATH + type + "\\" + component + "\\" + type + component + armType + mode + weaponClass + ".dcc"; + if (armType.isEmpty()) { + animation.setLayer(c, null); + continue; + } + Gdx.app.log(TAG, path); + + if (DEBUG_ASSETS) { + AssetDescriptor descriptor = new AssetDescriptor<>(path, DCC.class); + Diablo.assets.load(descriptor); + Diablo.assets.finishLoadingAsset(descriptor); + DCC dcc = Diablo.assets.get(descriptor); + animation.setLayer(c, dcc); + } + + Item item = getItem(comp); + if (item != null) { + animation.getLayer(layer.component).setTransform(item.charColormap, item.charColorIndex); + } + } + + dirty = 0; + } + + protected COFD2 getCOFs() { + return Diablo.cofs.active; + } + + public void drawDebug(ShapeRenderer shapes) { + float x = +(origin.x * Tile.SUBTILE_WIDTH50) - (origin.y * Tile.SUBTILE_WIDTH50); + float y = -(origin.x * Tile.SUBTILE_HEIGHT50) - (origin.y * Tile.SUBTILE_HEIGHT50); + + final float R = 32; + shapes.setColor(Color.RED); + shapes.line(x, y, x + MathUtils.cos(angle) * R, y + MathUtils.sin(angle) * R); + + float rounded = Direction.radiansToDirection16Radians(angle); + shapes.setColor(Color.GREEN); + shapes.line(x, y, x + MathUtils.cos(rounded) * R * 0.5f, y + MathUtils.sin(rounded) * R * 0.5f); + } + + public void draw(Batch batch) { + draw((PaletteIndexedBatch) batch); + } + + public void draw(PaletteIndexedBatch batch) { + validate(); + animation.act(); + float x = +(origin.x * Tile.SUBTILE_WIDTH50) - (origin.y * Tile.SUBTILE_WIDTH50); + float y = -(origin.x * Tile.SUBTILE_HEIGHT50) - (origin.y * Tile.SUBTILE_HEIGHT50); + animation.draw(batch, x, y); + } + + public void setAngle(float rad) { + if (angle != rad) { + angle = rad; + if (animation != null) animation.setDirection(getDirection()); + } + } + + public int getDirection() { + return Direction.radiansToDirection(angle, 16); + } + + public GridPoint2 origin() { + return origin; + } + + public void move() { + if (!mode.equalsIgnoreCase("WL") + && !mode.equalsIgnoreCase("RN") + && !mode.equalsIgnoreCase("TW")) { + return; + } + + int x = Direction.getOffX(angle); + int y = Direction.getOffY(angle); + origin.add(x, y); + } +} diff --git a/core/src/gdx/diablo/entity3/Player.java b/core/src/gdx/diablo/entity3/Player.java new file mode 100644 index 00000000..23092709 --- /dev/null +++ b/core/src/gdx/diablo/entity3/Player.java @@ -0,0 +1,326 @@ +package gdx.diablo.entity3; + +import com.google.common.base.Preconditions; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.GdxRuntimeException; + +import org.apache.commons.lang3.ObjectUtils; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import gdx.diablo.CharClass; +import gdx.diablo.Diablo; +import gdx.diablo.codec.COFD2; +import gdx.diablo.codec.D2S; +import gdx.diablo.codec.excel.Armor; +import gdx.diablo.codec.excel.Weapons; +import gdx.diablo.item.BodyLoc; +import gdx.diablo.item.Item; + +public class Player extends Entity { + private static final String TAG = "Player"; + private static final boolean DEBUG = true; + private static final boolean DEBUG_WCLASS = DEBUG && !true; + + public enum Slot { + HEAD, NECK, TORS, RARM, LARM, RRIN, LRIN, BELT, FEET, GLOV; + + public BodyLoc toBodyLoc(boolean alternate) { + return toBodyLoc(this, alternate); + } + + public static BodyLoc toBodyLoc(Slot slot, boolean alternate) { + switch (slot) { + case HEAD: return BodyLoc.HEAD; + case NECK: return BodyLoc.NECK; + case TORS: return BodyLoc.TORS; + case RARM: return alternate ? BodyLoc.RARM2 : BodyLoc.RARM; + case LARM: return alternate ? BodyLoc.LARM2 : BodyLoc.LARM; + case RRIN: return BodyLoc.RRIN; + case LRIN: return BodyLoc.LRIN; + case BELT: return BodyLoc.BELT; + case FEET: return BodyLoc.FEET; + case GLOV: return BodyLoc.GLOV; + default: + throw new GdxRuntimeException("Invalid slot: " + slot); + } + } + } + + D2S d2s; + boolean alternate; + EnumMap equipped = new EnumMap<>(BodyLoc.class); + Array inventory = new Array<>(); + final Set SLOT_LISTENERS = new CopyOnWriteArraySet<>(); + public Stats stats; + + + public Player(String name, CharClass clazz) { + super(null); + throw new UnsupportedOperationException(); + } + + public Player(D2S d2s) { + super(Diablo.files.PlrType.get(d2s.charClass).Token, EntType.CHARS); + this.d2s = d2s; + this.stats = new Stats(); + equipped.putAll(d2s.items.equipped); + inventory.addAll(d2s.items.inventory); + + + for (Map.Entry entry : equipped.entrySet()) { + entry.getValue().load(); + //if (DEBUG_EQUIPPED) Gdx.app.debug(TAG, entry.getKey() + ": " + entry.getValue()); + } + + for (Item item : inventory) { + item.load(); + //if (DEBUG_INVENTORY) Gdx.app.debug(TAG, item.gridX + "," + item.gridY + ": " + item); + } + } + + public Item getSlot(Slot slot) { + BodyLoc loc = slot.toBodyLoc(alternate); + return getSlot(loc); + } + + public Item getSlot(BodyLoc loc) { + return equipped.get(loc); + } + + public Item setSlot(Slot slot, Item item) { + Preconditions.checkState(item == null || getSlot(slot) == null, "Slot must be empty first!"); + BodyLoc loc = slot.toBodyLoc(alternate); + return setSlot(loc, item); + } + + public Item setSlot(BodyLoc loc, Item item) { + Item oldItem = equipped.put(loc, item); + + //invalidate(); + //setArmType(slot, item.base.alternateGfx); + int components = loc.components(); + if (components > 0) dirty |= components; + updateWeaponClass(); + + notifySlotChanged(loc, oldItem, item); + return oldItem; + } + + @Override + protected Item getItem(Component component) { + switch (component) { + case HD: return getSlot(Slot.HEAD); + case TR: + case RA: + case LA: + case S1: + case S2: return getSlot(Slot.TORS); + // TODO: Shield/weapons? + default: return super.getItem(component); + } + } + + public boolean isAlternate() { + return alternate; + } + + public void setAlternate(boolean b) { + if (alternate != b) { + alternate = b; + updateWeaponClass(); + } + } + + @Override + protected COFD2 getCOFs() { + return Diablo.cofs.chars_cof; + } + + public void update() { + updateWeaponClass(); + + Item head = getSlot(Slot.HEAD); + setArmType(Component.HD, head != null ? head.base.alternateGfx : "LIT"); + + Item body = getSlot(Slot.TORS); + if (body != null) { + Armor.Entry armor = body.getBase(); + setArmType(Component.TR, Diablo.files.ArmType.get(armor.Torso).Token); + setArmType(Component.LG, Diablo.files.ArmType.get(armor.Legs ).Token); + setArmType(Component.RA, Diablo.files.ArmType.get(armor.rArm ).Token); + setArmType(Component.LA, Diablo.files.ArmType.get(armor.lArm ).Token); + setArmType(Component.S1, Diablo.files.ArmType.get(armor.lSPad).Token); + setArmType(Component.S2, Diablo.files.ArmType.get(armor.rSPad).Token); + } else { + setArmType(Component.TR, DEFAULT_LAYER); + setArmType(Component.LG, DEFAULT_LAYER); + setArmType(Component.RA, DEFAULT_LAYER); + setArmType(Component.LA, DEFAULT_LAYER); + setArmType(Component.S1, DEFAULT_LAYER); + setArmType(Component.S2, DEFAULT_LAYER); + } + + super.update(); + } + + private void updateWeaponClass() { + Item RH = null, LH = null, SH = null; + Item rArm = getSlot(Slot.RARM); + if (rArm != null) { + if (rArm.type.is("weap")) { + RH = rArm; + } else if (rArm.type.is("shld")) { + SH = rArm; + } + } + + Item lArm = getSlot(Slot.LARM); + if (lArm != null) { + if (lArm.type.is("weap")) { + LH = lArm; + } else if (lArm.type.is("shld")) { + SH = lArm; + } + } + + if (DEBUG_WCLASS) { + Gdx.app.debug(TAG, "RH = " + RH); + Gdx.app.debug(TAG, "LH = " + LH); + Gdx.app.debug(TAG, "SH = " + SH); + } + + if (LH != null && RH != null) { + Weapons.Entry LHEntry = LH.getBase(); + Weapons.Entry RHEntry = RH.getBase(); + if ( LHEntry.wclass.equals("1hs") && RHEntry.wclass.equals("1hs")) { + setWeaponClass("1SS"); // Left Swing Right Swing + } else if (LHEntry.wclass.equals("1hs") && RHEntry.wclass.equals("1ht")) { + setWeaponClass("1ST"); // Left Swing Right Thrust + } else if (LHEntry.wclass.equals("1ht") && RHEntry.wclass.equals("1hs")) { + setWeaponClass("1JS"); // Left Jab Right Swing + } else if (LHEntry.wclass.equals("1ht") && RHEntry.wclass.equals("1ht")) { + setWeaponClass("1JT"); // Left Jab Right Thrust + } else if (LH.type.is("miss") || RH.type.is("miss")) { + setWeaponClass(LH.type.is("miss") ? LHEntry.wclass : RHEntry.wclass); + } else if (LH.type.is("h2h") || RH.type.is("h2h")) { + setWeaponClass("HT2"); // Two Hand-to-Hand + } else { + setWeaponClass("HTH"); + Gdx.app.error(TAG, String.format( + "Unknown weapon combination: LH=%s RH=%s", LHEntry.wclass, RHEntry.wclass)); + } + } else if (LH != null || RH != null) { + RH = ObjectUtils.firstNonNull(RH, LH); + LH = null; + if (RH.type.is("bow")) { + LH = RH; + RH = null; + Weapons.Entry LHEntry = LH.getBase(); + setWeaponClass(LHEntry.wclass); + } else if (RH.type.is("weap")) { // make sure weap and not e.g. misl, might not be required + Weapons.Entry RHEntry = RH.getBase(); + setWeaponClass(RHEntry.wclass); + } else { + setWeaponClass("HTH"); + } + } else { + setWeaponClass("HTH"); + } + + if (RH != null) setArmType(Component.RH, RH.base.alternateGfx); + if (LH != null) setArmType(Component.LH, LH.base.alternateGfx); + if (SH != null) setArmType(Component.SH, SH.base.alternateGfx); + else setArmType(Component.SH, ""); + } + + private void notifySlotChanged(BodyLoc bodyLoc, Item oldItem, Item item) { + for (SlotListener l : SLOT_LISTENERS) l.onChanged(this, bodyLoc, oldItem, item); + } + + public boolean addSlotListener(SlotListener l) { + boolean added = SLOT_LISTENERS.add(l); + return added; + } + + public boolean containsSlotListener(Object o) { + return o != null && SLOT_LISTENERS.contains(o); + } + + public boolean removeSlotListener(Object o) { + return o != null && SLOT_LISTENERS.remove(o); + } + + public boolean clearSlotListeners() { + boolean empty = SLOT_LISTENERS.isEmpty(); + SLOT_LISTENERS.clear(); + return !empty; + } + + public interface SlotListener { + void onChanged(Player player, BodyLoc bodyLoc, Item oldItem, Item item); + } + + public Array getInventory() { + return inventory; + } + + public class Stats { + public int getClassId() { + return d2s.charClass; + } + + public CharClass getCharClass() { + return CharClass.get(d2s.charClass); + } + + public String getName() { + return d2s.name; + } + + public int getLevel() { + return d2s.stats.level; + } + + public long getExperience() { + return d2s.stats.xp; + } + + public int getStrength() { + return d2s.stats.strength; + } + + public int getDexterity() { + return d2s.stats.dexterity; + } + + public int getVitality() { + return d2s.stats.vitality; + } + + public int getEnergy() { + return d2s.stats.energy; + } + + public int getFireResistance() { + return 0; + } + + public int getColdResistance() { + return 0; + } + + public int getLightningResistance() { + return 0; + } + + public int getPoisonResistance() { + return 0; + } + } +} diff --git a/core/src/gdx/diablo/item/BodyLoc.java b/core/src/gdx/diablo/item/BodyLoc.java index 594a802f..296b53db 100644 --- a/core/src/gdx/diablo/item/BodyLoc.java +++ b/core/src/gdx/diablo/item/BodyLoc.java @@ -2,20 +2,22 @@ package gdx.diablo.item; import com.badlogic.gdx.Gdx; +import static gdx.diablo.entity3.Entity.Dirty.*; + public enum BodyLoc { NONE, - HEAD, + HEAD(HD), NECK, - TORS, - RARM, - LARM, + TORS(TR|LG|LA|RA|S1|S2), + RARM(RH|LH|SH), + LARM(RH|LH|SH), RRIN, LRIN, BELT, - FEET, + FEET(LG), GLOV, - RARM2, - LARM2; + RARM2(RH|LH|SH), + LARM2(RH|LH|SH); public static BodyLoc valueOf(int i) { switch (i) { @@ -37,4 +39,18 @@ public enum BodyLoc { return null; } } + + final int components; + + BodyLoc() { + this.components = -1; + } + + BodyLoc(int components) { + this.components = components; + } + + public int components() { + return components; + } } diff --git a/core/src/gdx/diablo/panel/CharacterPanel.java b/core/src/gdx/diablo/panel/CharacterPanel.java index 30a26ca0..1e9b903a 100644 --- a/core/src/gdx/diablo/panel/CharacterPanel.java +++ b/core/src/gdx/diablo/panel/CharacterPanel.java @@ -16,7 +16,7 @@ import java.text.NumberFormat; import gdx.diablo.Cvars; import gdx.diablo.Diablo; import gdx.diablo.codec.DC6; -import gdx.diablo.entity.Player; +import gdx.diablo.entity3.Player; import gdx.diablo.loader.DC6Loader; import gdx.diablo.screen.GameScreen; import gdx.diablo.widget.Button; @@ -58,7 +58,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { Player player = gameScreen.player; - Label name = new Label(player.getName(), Diablo.fonts.font16); + Label name = new Label(player.stats.getName(), Diablo.fonts.font16); name.setPosition(12, getHeight() - 24); name.setSize(168, 13); name.setAlignment(Align.center); @@ -68,17 +68,17 @@ public class CharacterPanel extends WidgetGroup implements Disposable { level.setPosition(12, getHeight() - 65); level.setSize(42, 33); level.add(new Label(4057, Diablo.fonts.ReallyTheLastSucker)).row(); - level.add(new Label(Integer.toString(player.getLevel()), Diablo.fonts.font16)).growY().row(); + level.add(new Label(Integer.toString(player.stats.getLevel()), Diablo.fonts.font16)).growY().row(); addActor(level); Table exp = new Table(); exp.setPosition(66, getHeight() - 65); exp.setSize(114, 33); exp.add(new Label(4058, Diablo.fonts.ReallyTheLastSucker)).row(); - exp.add(new Label(NumberFormat.getInstance(Cvars.Client.Locale.get()).format(player.getExperience()), Diablo.fonts.font16)).growY().row(); + exp.add(new Label(NumberFormat.getInstance(Cvars.Client.Locale.get()).format(player.stats.getExperience()), Diablo.fonts.font16)).growY().row(); addActor(exp); - Label clazz = new Label(player.getCharClass().name, Diablo.fonts.font16); + Label clazz = new Label(player.stats.getCharClass().name, Diablo.fonts.font16); clazz.setPosition(194, getHeight() - 24); clazz.setSize(114, 13); clazz.setAlignment(Align.center); @@ -97,7 +97,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { strLabel.setAlignment(Align.center); addActor(strLabel); - Label str = new Label(Integer.toString(player.getStrength()), Diablo.fonts.font16); + Label str = new Label(Integer.toString(player.stats.getStrength()), Diablo.fonts.font16); str.setPosition(78, getHeight() - 100); str.setSize(36, 16); str.setAlignment(Align.center); @@ -109,7 +109,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { dexLabel.setAlignment(Align.center); addActor(dexLabel); - Label dex = new Label(Integer.toString(player.getDexterity()), Diablo.fonts.font16); + Label dex = new Label(Integer.toString(player.stats.getDexterity()), Diablo.fonts.font16); dex.setPosition(78, getHeight() - 162); dex.setSize(36, 16); dex.setAlignment(Align.center); @@ -121,7 +121,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { vitLabel.setAlignment(Align.center); addActor(vitLabel); - Label vit = new Label(Integer.toString(player.getVitality()), Diablo.fonts.font16); + Label vit = new Label(Integer.toString(player.stats.getVitality()), Diablo.fonts.font16); vit.setPosition(78, getHeight() - 248); vit.setSize(36, 16); vit.setAlignment(Align.center); @@ -133,7 +133,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { eneLabel.setAlignment(Align.center); addActor(eneLabel); - Label ene = new Label(Integer.toString(player.getEnergy()), Diablo.fonts.font16); + Label ene = new Label(Integer.toString(player.stats.getEnergy()), Diablo.fonts.font16); ene.setPosition(78, getHeight() - 310); ene.setSize(36, 16); ene.setAlignment(Align.center); @@ -145,7 +145,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { fireResLabel.setAlignment(Align.center); addActor(fireResLabel); - Label fireRes = new Label(Integer.toString(player.getFireResistance()), Diablo.fonts.font16); + Label fireRes = new Label(Integer.toString(player.stats.getFireResistance()), Diablo.fonts.font16); fireRes.setPosition(273, getHeight() - 349); fireRes.setSize(36, 16); fireRes.setAlignment(Align.center); @@ -157,7 +157,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { coldResLabel.setAlignment(Align.center); addActor(coldResLabel); - Label coldRes = new Label(Integer.toString(player.getColdResistance()), Diablo.fonts.font16); + Label coldRes = new Label(Integer.toString(player.stats.getColdResistance()), Diablo.fonts.font16); coldRes.setPosition(273, getHeight() - 373); coldRes.setSize(36, 16); coldRes.setAlignment(Align.center); @@ -169,7 +169,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { lightningResLabel.setAlignment(Align.center); addActor(lightningResLabel); - Label lightningRes = new Label(Integer.toString(player.getLightningResistance()), Diablo.fonts.font16); + Label lightningRes = new Label(Integer.toString(player.stats.getLightningResistance()), Diablo.fonts.font16); lightningRes.setPosition(273, getHeight() - 397); lightningRes.setSize(36, 16); lightningRes.setAlignment(Align.center); @@ -181,7 +181,7 @@ public class CharacterPanel extends WidgetGroup implements Disposable { poisonResLabel.setAlignment(Align.center); addActor(poisonResLabel); - Label poisonRes = new Label(Integer.toString(player.getPoisonResistance()), Diablo.fonts.font16); + Label poisonRes = new Label(Integer.toString(player.stats.getPoisonResistance()), Diablo.fonts.font16); poisonRes.setPosition(273, getHeight() - 421); poisonRes.setSize(36, 16); poisonRes.setAlignment(Align.center); diff --git a/core/src/gdx/diablo/panel/InventoryPanel.java b/core/src/gdx/diablo/panel/InventoryPanel.java index 9cd64c8d..f8ac7474 100644 --- a/core/src/gdx/diablo/panel/InventoryPanel.java +++ b/core/src/gdx/diablo/panel/InventoryPanel.java @@ -22,7 +22,7 @@ import gdx.diablo.codec.DC6; import gdx.diablo.codec.excel.BodyLocs; import gdx.diablo.codec.excel.Inventory; import gdx.diablo.codec.util.BBox; -import gdx.diablo.entity.Player; +import gdx.diablo.entity3.Player; import gdx.diablo.graphics.PaletteIndexedBatch; import gdx.diablo.item.BodyLoc; import gdx.diablo.item.Item; @@ -99,7 +99,7 @@ public class InventoryPanel extends WidgetGroup implements Disposable { }); addActor(btnExit); - inventory = Diablo.files.inventory.getClass(gameScreen.player.getClassId()); + inventory = Diablo.files.inventory.getClass(gameScreen.player.stats.getClassId()); Diablo.assets.load(inv_armorDescriptor); Diablo.assets.load(inv_beltDescriptor); @@ -207,7 +207,7 @@ public class InventoryPanel extends WidgetGroup implements Disposable { for (int i = BodyLocs.HEAD; i < BodyLocs.NUM_LOCS; i++) { if (bodyParts[i] == null) continue; bodyParts[i].slot = i; - bodyParts[i].item = gameScreen.player.getBodyLoc(BodyLoc.valueOf(i)); + bodyParts[i].item = gameScreen.player.getSlot(BodyLoc.valueOf(i)); bodyParts[i].setBodyPart(Diablo.files.bodylocs.get(i).Code); } @@ -312,11 +312,11 @@ public class InventoryPanel extends WidgetGroup implements Disposable { Diablo.cursor.setItem(item); item = cursor; - //gameScreen.player.setSlot(slot, item); + gameScreen.player.setSlot(BodyLoc.valueOf(slot), item); } else { Diablo.cursor.setItem(item); item = null; - //gameScreen.player.setSlot(slot, null); + gameScreen.player.setSlot(BodyLoc.valueOf(slot), null); } } }); diff --git a/core/src/gdx/diablo/screen/CreateCharacterScreen.java b/core/src/gdx/diablo/screen/CreateCharacterScreen.java index 6be84b62..700d3209 100644 --- a/core/src/gdx/diablo/screen/CreateCharacterScreen.java +++ b/core/src/gdx/diablo/screen/CreateCharacterScreen.java @@ -26,7 +26,7 @@ import gdx.diablo.CharClass; import gdx.diablo.Diablo; import gdx.diablo.codec.Animation; import gdx.diablo.codec.DC6; -import gdx.diablo.entity.Player; +import gdx.diablo.entity3.Player; import gdx.diablo.graphics.PaletteIndexedBatch; import gdx.diablo.loader.DC6Loader; import gdx.diablo.widget.CharButton; diff --git a/core/src/gdx/diablo/screen/GameScreen.java b/core/src/gdx/diablo/screen/GameScreen.java index bbd9b76b..540d2592 100644 --- a/core/src/gdx/diablo/screen/GameScreen.java +++ b/core/src/gdx/diablo/screen/GameScreen.java @@ -24,11 +24,10 @@ import com.badlogic.gdx.utils.Timer; import gdx.diablo.Diablo; import gdx.diablo.Keys; -import gdx.diablo.entity.Player; +import gdx.diablo.entity3.Player; import gdx.diablo.graphics.PaletteIndexedBatch; import gdx.diablo.key.MappedKey; import gdx.diablo.key.MappedKeyStateAdapter; -import gdx.diablo.map.DT1.Tile; import gdx.diablo.map.Map; import gdx.diablo.map.MapLoader; import gdx.diablo.map.MapRenderer; @@ -246,9 +245,10 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable //int spx = + (character.x * Tile.SUBTILE_WIDTH50) - (character.y * Tile.SUBTILE_WIDTH50); //int spy = - (character.x * Tile.SUBTILE_HEIGHT50) - (character.y * Tile.SUBTILE_HEIGHT50); //character.draw(b, spx, spy); - int spx = + (player.getOrigin().x * Tile.SUBTILE_WIDTH50) - (player.getOrigin().y * Tile.SUBTILE_WIDTH50); - int spy = - (player.getOrigin().x * Tile.SUBTILE_HEIGHT50) - (player.getOrigin().y * Tile.SUBTILE_HEIGHT50); - player.draw(b, spx, spy); + //int spx = + (player.getOrigin().x * Tile.SUBTILE_WIDTH50) - (player.getOrigin().y * Tile.SUBTILE_WIDTH50); + //int spy = - (player.getOrigin().x * Tile.SUBTILE_HEIGHT50) - (player.getOrigin().y * Tile.SUBTILE_HEIGHT50); + //player.draw(b, spx, spy); + player.draw(b); b.end(); b.setProjectionMatrix(Diablo.viewport.getCamera().combined); @@ -256,7 +256,8 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable Diablo.shapes.setProjectionMatrix(camera.combined); Diablo.shapes.begin(ShapeRenderer.ShapeType.Line); mapRenderer.renderDebug(Diablo.shapes); - player.drawDebug(Diablo.shapes, spx, spy); + //player.drawDebug(Diablo.shapes, spx, spy); + player.drawDebug(Diablo.shapes); Diablo.shapes.end(); stage.act(); @@ -283,7 +284,7 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable //character.x = origin.x; //character.y = origin.y; - player.getOrigin().set(origin); + player.origin().set(origin); Gdx.app.debug(TAG, player.toString()); Keys.Esc.addStateListener(mappedKeyStateListener); @@ -298,7 +299,7 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable @Override public void run() { player.move(); - mapRenderer.setPosition(player.getOrigin()); + mapRenderer.setPosition(player.origin()); } }, 0, 1 / 25f); } diff --git a/core/src/gdx/diablo/screen/LoginScreen.java b/core/src/gdx/diablo/screen/LoginScreen.java index 4d458ff7..46f1fbb6 100644 --- a/core/src/gdx/diablo/screen/LoginScreen.java +++ b/core/src/gdx/diablo/screen/LoginScreen.java @@ -85,17 +85,19 @@ public class LoginScreen extends ScreenAdapter { if (D2logoLeft == null) { Diablo.assets.finishLoadingAsset(D2logoBlackLeftDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireLeftDescriptor); - D2logoLeft = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackLeftDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY)); + D2logoLeft = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackLeftDescriptor)) + .layer(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY) + .build(); } if (D2logoRight == null) { Diablo.assets.finishLoadingAsset(D2logoBlackRightDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireRightDescriptor); - D2logoRight = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackRightDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY)); + D2logoRight = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackRightDescriptor)) + .layer(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY) + .build(); } TextButton.TextButtonStyle style = new TextButton.TextButtonStyle() {{ diff --git a/core/src/gdx/diablo/screen/MenuScreen.java b/core/src/gdx/diablo/screen/MenuScreen.java index 90dc3a22..12a8d9f0 100644 --- a/core/src/gdx/diablo/screen/MenuScreen.java +++ b/core/src/gdx/diablo/screen/MenuScreen.java @@ -75,17 +75,19 @@ public class MenuScreen extends ScreenAdapter { if (D2logoLeft == null) { Diablo.assets.finishLoadingAsset(D2logoBlackLeftDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireLeftDescriptor); - D2logoLeft = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackLeftDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY)); + D2logoLeft = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackLeftDescriptor)) + .layer(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY) + .build(); } if (D2logoRight == null) { Diablo.assets.finishLoadingAsset(D2logoBlackRightDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireRightDescriptor); - D2logoRight = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackRightDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY)); + D2logoRight = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackRightDescriptor)) + .layer(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY) + .build(); } TextButton.TextButtonStyle style = new TextButton.TextButtonStyle() {{ diff --git a/core/src/gdx/diablo/screen/MultiplayerScreen.java b/core/src/gdx/diablo/screen/MultiplayerScreen.java index 3fd6beb0..82ba1488 100644 --- a/core/src/gdx/diablo/screen/MultiplayerScreen.java +++ b/core/src/gdx/diablo/screen/MultiplayerScreen.java @@ -70,17 +70,19 @@ public class MultiplayerScreen extends ScreenAdapter { if (D2logoLeft == null) { Diablo.assets.finishLoadingAsset(D2logoBlackLeftDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireLeftDescriptor); - D2logoLeft = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackLeftDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY)); + D2logoLeft = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackLeftDescriptor)) + .layer(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY) + .build(); } if (D2logoRight == null) { Diablo.assets.finishLoadingAsset(D2logoBlackRightDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireRightDescriptor); - D2logoRight = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackRightDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY)); + D2logoRight = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackRightDescriptor)) + .layer(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY) + .build(); } TextButton.TextButtonStyle style = new TextButton.TextButtonStyle() {{ diff --git a/core/src/gdx/diablo/screen/SelectCharacterScreen.java b/core/src/gdx/diablo/screen/SelectCharacterScreen.java index 187aff07..ec6e1e5c 100644 --- a/core/src/gdx/diablo/screen/SelectCharacterScreen.java +++ b/core/src/gdx/diablo/screen/SelectCharacterScreen.java @@ -17,7 +17,7 @@ import com.badlogic.gdx.utils.Array; import gdx.diablo.Diablo; import gdx.diablo.codec.D2S; import gdx.diablo.codec.DC6; -import gdx.diablo.entity.Player; +import gdx.diablo.entity3.Player; import gdx.diablo.graphics.PaletteIndexedBatch; import gdx.diablo.loader.DC6Loader; import gdx.diablo.widget.SelectButton; @@ -60,8 +60,7 @@ public class SelectCharacterScreen extends ScreenAdapter { Diablo.client.popScreen(); } else if (actor == btnOK) { assert selected != null; - Diablo.client.clearAndSet(new LoadingScreen(new GameScreen(new Player(selected.getD2S() - )))); + Diablo.client.clearAndSet(new LoadingScreen(new GameScreen(new Player(selected.getD2S())))); } else if (actor == btnCreateNewCharacter) { Diablo.client.pushScreen(new CreateCharacterScreen()); } diff --git a/core/src/gdx/diablo/screen/SplashScreen.java b/core/src/gdx/diablo/screen/SplashScreen.java index 43ed8c4b..ed57744f 100644 --- a/core/src/gdx/diablo/screen/SplashScreen.java +++ b/core/src/gdx/diablo/screen/SplashScreen.java @@ -27,8 +27,8 @@ public class SplashScreen extends ScreenAdapter { final AssetDescriptor D2logoFireLeftDescriptor = new AssetDescriptor<>("data\\global\\ui\\FrontEnd\\D2logoFireLeft.DC6", DC6.class); final AssetDescriptor D2logoBlackRightDescriptor = new AssetDescriptor<>("data\\global\\ui\\FrontEnd\\D2logoBlackRight.DC6", DC6.class); final AssetDescriptor D2logoFireRightDescriptor = new AssetDescriptor<>("data\\global\\ui\\FrontEnd\\D2logoFireRight.DC6", DC6.class); - Animation.CompositeAnimation D2logoLeft; - Animation.CompositeAnimation D2logoRight; + Animation D2logoLeft; + Animation D2logoRight; GlyphLayout pressContinueGlyphs; @@ -57,15 +57,17 @@ public class SplashScreen extends ScreenAdapter { Diablo.assets.finishLoadingAsset(D2logoBlackLeftDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireLeftDescriptor); - D2logoLeft = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackLeftDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY)); + D2logoLeft = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackLeftDescriptor)) + .layer(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY) + .build(); Diablo.assets.finishLoadingAsset(D2logoBlackRightDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireRightDescriptor); - D2logoRight = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackRightDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY)); + D2logoRight = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackRightDescriptor)) + .layer(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY) + .build(); String press_to_continue; // TODO: Update message for controllers press_any_button diff --git a/core/src/gdx/diablo/screen/TCPIPScreen.java b/core/src/gdx/diablo/screen/TCPIPScreen.java index fdf50523..b3990338 100644 --- a/core/src/gdx/diablo/screen/TCPIPScreen.java +++ b/core/src/gdx/diablo/screen/TCPIPScreen.java @@ -85,17 +85,19 @@ public class TCPIPScreen extends ScreenAdapter { if (D2logoLeft == null) { Diablo.assets.finishLoadingAsset(D2logoBlackLeftDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireLeftDescriptor); - D2logoLeft = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackLeftDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY)); + D2logoLeft = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackLeftDescriptor)) + .layer(Diablo.assets.get(D2logoFireLeftDescriptor), BlendMode.LUMINOSITY) + .build(); } if (D2logoRight == null) { Diablo.assets.finishLoadingAsset(D2logoBlackRightDescriptor); Diablo.assets.finishLoadingAsset(D2logoFireRightDescriptor); - D2logoRight = new Animation.CompositeAnimation( - Animation.Layer.from(Diablo.assets.get(D2logoBlackRightDescriptor)), - Animation.Layer.from(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY)); + D2logoRight = Animation.builder() + .layer(Diablo.assets.get(D2logoBlackRightDescriptor)) + .layer(Diablo.assets.get(D2logoFireRightDescriptor), BlendMode.LUMINOSITY) + .build(); } TextButton.TextButtonStyle style = new TextButton.TextButtonStyle() {{ diff --git a/core/src/gdx/diablo/widget/BNetConnectDialog.java b/core/src/gdx/diablo/widget/BNetConnectDialog.java new file mode 100644 index 00000000..84931bfd --- /dev/null +++ b/core/src/gdx/diablo/widget/BNetConnectDialog.java @@ -0,0 +1,139 @@ +package gdx.diablo.widget; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Net; +import com.badlogic.gdx.assets.AssetDescriptor; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.net.HttpRequestBuilder; +import com.badlogic.gdx.scenes.scene2d.Action; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; + +import gdx.diablo.Diablo; +import gdx.diablo.codec.DC6; +import gdx.diablo.loader.DC6Loader; + +public class BNetConnectDialog extends Dialog { + final AssetDescriptor PopUp_340x224Descriptor = new AssetDescriptor<>("data\\global\\ui\\FrontEnd\\PopUp_340x224.dc6", DC6.class, DC6Loader.DC6Parameters.COMBINE); + final AssetDescriptor MediumButtonBlankDescriptor = new AssetDescriptor<>("data\\global\\ui\\FrontEnd\\MediumButtonBlank.dc6", DC6.class, DC6Loader.DC6Parameters.COMBINE); + + Label status; + + public BNetConnectDialog() { + Diablo.assets.load(PopUp_340x224Descriptor); + Diablo.assets.load(MediumButtonBlankDescriptor); + + setDebug(true, true); + } + + public void create() { + Diablo.assets.finishLoadingAsset(PopUp_340x224Descriptor); + TextureRegion PopUp_340x224 = Diablo.assets.get(PopUp_340x224Descriptor).getTexture(); + setBackground(new TextureRegionDrawable(PopUp_340x224)); + + getContentTable().add(new Table() {{ + add(new Label(5171, Diablo.fonts.font30) {{ + setWrap(true); + setAlignment(Align.center); + }}).width(220).row(); + add(status = new Label("", Diablo.fonts.font24)).growY().row(); + add(new Label("*", Diablo.fonts.font24)).row(); + setWidth(220); + pad(10); + }}).growY(); + + Table buttonTable = getButtonTable(); + Button btnCancel = new TextButton(5134, new TextButton.TextButtonStyle() {{ + Diablo.assets.finishLoadingAsset(MediumButtonBlankDescriptor); + DC6 MediumButtonBlank = Diablo.assets.get(MediumButtonBlankDescriptor); + up = new TextureRegionDrawable(MediumButtonBlank.getTexture(0)); + down = new TextureRegionDrawable(MediumButtonBlank.getTexture(1)); + font = Diablo.fonts.fontexocet10; + }}); + btnCancel.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + hide(null); + } + }); + buttonTable.add(btnCancel); + buttonTable.padBottom(10); + } + + @Override + public com.badlogic.gdx.scenes.scene2d.ui.Dialog show(Stage stage, Action action) { + setPosition( + Diablo.VIRTUAL_WIDTH_CENTER - 340 / 2, + Diablo.VIRTUAL_HEIGHT_CENTER - 224 / 2); + return super.show(stage, action); + } + + @Override + public void hide(Action action) { + super.hide(action); + } + + @Override + public void dispose() { + Diablo.assets.unload(PopUp_340x224Descriptor.fileName); + Diablo.assets.unload(MediumButtonBlankDescriptor.fileName); + } + + public void connect(Stage stage) { + show(stage, null); + queryGateway(); + findServer(); + accessAccount(); + checkVersion(); + } + + private void queryGateway() { + status.setText(5172); + findServer(); + } + + private void findServer() { + status.setText(5173); + Net.HttpRequest request = new HttpRequestBuilder() + .newRequest() + .method(Net.HttpMethods.GET) + .url("http://hydra:6112/find-server") + .build(); + Gdx.net.sendHttpRequest(request, new Net.HttpResponseListener() { + @Override + public void handleHttpResponse(Net.HttpResponse httpResponse) { + accessAccount(); + } + + @Override + public void failed(Throwable t) { + BNetConnectDialog.this.failed(t.getMessage()); + } + + @Override + public void cancelled() { + BNetConnectDialog.this.failed("cancelled"); + } + }); + } + + private void accessAccount() { + status.setText(5174); + checkVersion(); + } + + private void checkVersion() { + status.setText(5175); + connected(); + } + + protected void connected() { + } + + protected void failed(String message) { + } +} diff --git a/core/src/gdx/diablo/widget/CharButton.java b/core/src/gdx/diablo/widget/CharButton.java index d2ede699..0dd677cc 100644 --- a/core/src/gdx/diablo/widget/CharButton.java +++ b/core/src/gdx/diablo/widget/CharButton.java @@ -189,12 +189,13 @@ public class CharButton extends Widget implements Disposable { state = State.FW; if (fw == null) { Diablo.assets.finishLoadingAsset(fwDesc); - fw = Animation.newAnimation(Diablo.assets.get(fwDesc)); + Animation.Builder builder = Animation.builder() + .layer(Diablo.assets.get(fwDesc)); if (charClass.fws) { Diablo.assets.finishLoadingAsset(fwsDesc); - Animation.Layer composite = Animation.Layer.from(Diablo.assets.get(fwsDesc)); - fw = fw.composite().addLayer(composite, charClass.blendSpecial); + builder.layer(Diablo.assets.get(fwsDesc), charClass.blendSpecial); } + fw = builder.build(); fw.setLooping(false); fw.addAnimationListener(new Animation.AnimationListener() { @Override @@ -202,12 +203,13 @@ public class CharButton extends Widget implements Disposable { state = State.NU3; if (nu3 == null) { Diablo.assets.finishLoadingAsset(nu3Desc); - nu3 = Animation.newAnimation(Diablo.assets.get(nu3Desc)); + Animation.Builder builder = Animation.builder() + .layer(Diablo.assets.get(nu3Desc)); if (charClass.nu3s) { Diablo.assets.finishLoadingAsset(nu3sDesc); - Animation.Layer composite = Animation.Layer.from(Diablo.assets.get(nu3sDesc)); - nu3 = nu3.composite().addLayer(composite, charClass.blendSpecial); + builder.layer(Diablo.assets.get(nu3sDesc), charClass.blendSpecial); } + nu3 = builder.build(); } setActive(nu3); } @@ -227,12 +229,13 @@ public class CharButton extends Widget implements Disposable { state = State.BW; if (bw == null) { Diablo.assets.finishLoadingAsset(bwDesc); - bw = Animation.newAnimation(Diablo.assets.get(bwDesc)); + Animation.Builder builder = Animation.builder() + .layer(Diablo.assets.get(bwDesc)); if (charClass.bws) { Diablo.assets.finishLoadingAsset(bwsDesc); - Animation.Layer composite = Animation.Layer.from(Diablo.assets.get(bwsDesc)); - bw = bw.composite().addLayer(composite, charClass.blendSpecial); + builder.layer(Diablo.assets.get(bwsDesc), charClass.blendSpecial); } + bw = builder.build(); bw.setLooping(false); bw.addAnimationListener(new Animation.AnimationListener() { @Override diff --git a/core/src/gdx/diablo/widget/CharacterPreview.java b/core/src/gdx/diablo/widget/CharacterPreview.java index 332352b5..662f38aa 100644 --- a/core/src/gdx/diablo/widget/CharacterPreview.java +++ b/core/src/gdx/diablo/widget/CharacterPreview.java @@ -22,7 +22,7 @@ public class CharacterPreview extends Widget implements Disposable { D2S d2s; AssetDescriptor[] assets; - Animation.COFAnimation anim; + Animation anim; public CharacterPreview() {} @@ -56,7 +56,7 @@ public class CharacterPreview extends Widget implements Disposable { } //System.out.println(Arrays.toString(armorClasses)); - anim = new Animation.COFAnimation(cof); + anim = Animation.newAnimation(cof); anim.setDirection(Direction.DOWN); anim.setShadow(false); if (assets == null) assets = new AssetDescriptor[COF.Component.NUM_COMPONENTS]; diff --git a/core/src/gdx/diablo/widget/Dialog.java b/core/src/gdx/diablo/widget/Dialog.java new file mode 100644 index 00000000..e4952154 --- /dev/null +++ b/core/src/gdx/diablo/widget/Dialog.java @@ -0,0 +1,16 @@ +package gdx.diablo.widget; + +import com.badlogic.gdx.utils.Disposable; + +import gdx.diablo.Diablo; + +public class Dialog extends com.badlogic.gdx.scenes.scene2d.ui.Dialog implements Disposable { + public Dialog() { + super("", new WindowStyle() {{ + titleFont = Diablo.fonts.font16; + }}); + } + + @Override + public void dispose() {} +} diff --git a/core/src/gdx/diablo/widget/ItemGrid.java b/core/src/gdx/diablo/widget/ItemGrid.java index 280214f2..50e475ca 100644 --- a/core/src/gdx/diablo/widget/ItemGrid.java +++ b/core/src/gdx/diablo/widget/ItemGrid.java @@ -20,7 +20,7 @@ import gdx.diablo.BlendMode; import gdx.diablo.Diablo; import gdx.diablo.codec.excel.Inventory; import gdx.diablo.codec.excel.ItemEntry; -import gdx.diablo.entity.Player; +import gdx.diablo.entity3.Player; import gdx.diablo.graphics.PaletteIndexedBatch; import gdx.diablo.item.Item; diff --git a/core/test/gdx/diablo/entity3/EntityTest.java b/core/test/gdx/diablo/entity3/EntityTest.java new file mode 100644 index 00000000..bae797ac --- /dev/null +++ b/core/test/gdx/diablo/entity3/EntityTest.java @@ -0,0 +1,86 @@ +package gdx.diablo.entity3; + +import com.badlogic.gdx.Application; +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.backends.headless.HeadlessApplicationConfiguration; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; + +import gdx.diablo.COFs; +import gdx.diablo.Diablo; +import gdx.diablo.Files; +import gdx.diablo.codec.D2S; +import gdx.diablo.codec.StringTBLs; +import gdx.diablo.mpq.MPQFileHandleResolver; + +public class EntityTest { + @BeforeClass + public static void setUp() throws Exception { + final AtomicBoolean block = new AtomicBoolean(true); + HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration(); + new HeadlessApplication(new ApplicationAdapter() { + @Override + public void create() { + Gdx.app.setLogLevel(Application.LOG_DEBUG); + MPQFileHandleResolver resolver = Diablo.mpqs = new MPQFileHandleResolver(); + resolver.add(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\patch_d2.mpq")); + resolver.add(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\d2exp.mpq")); + resolver.add(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\d2data.mpq")); + Diablo.assets = new AssetManager(resolver); + Diablo.cofs = new COFs(Diablo.assets); + Diablo.files = new Files(Diablo.assets); + Diablo.string = new StringTBLs(resolver); + block.set(false); + } + + @Override + public void dispose() { + Diablo.assets.dispose(); + } + }, config); + while (block.get()); + } + + @AfterClass + public static void tearDown() throws Exception { + Gdx.app.exit(); + } + + @Test + public void validateStatic() { + Entity entity = new Entity("AF"); + entity.setMode("NU"); + entity.setWeaponClass("HTH"); + entity.validate(); + } + + @Test + public void validateMonster() { + Entity entity = new Entity("BH", Entity.EntType.MONSTER); + entity.setMode("NU"); + entity.setWeaponClass("HTH"); + entity.validate(); + } + + @Test + public void validatePlayer() { + D2S d2s = D2S.loadFromFile(Gdx.files.local("test/Tirant.d2s")); + Player entity = new Player(d2s); + entity.setMode("TN"); + entity.setWeaponClass("1hs"); + entity.validate(); + + entity.setSlot(Player.Slot.HEAD, null); + entity.validate(); + + entity.setMode("RN"); + entity.validate(); + } +} \ No newline at end of file diff --git a/tester/src/gdx/diablo/tester/cof/Tester1101.java b/tester/src/gdx/diablo/tester/cof/Tester1101.java index c2cf7748..bed125c1 100644 --- a/tester/src/gdx/diablo/tester/cof/Tester1101.java +++ b/tester/src/gdx/diablo/tester/cof/Tester1101.java @@ -42,7 +42,7 @@ public class Tester1101 extends ApplicationAdapter { Gdx.app.setLogLevel(Application.LOG_DEBUG); MPQ d2data = MPQ.loadFromFile(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\d2data.mpq")); COF cof = COF.loadFromStream(d2data.read("data\\global\\objects\\TO\\COF\\toonhth.cof")); - animation = new Animation.COFAnimation(cof); + animation = Animation.newAnimation(cof); palette = Palette.loadFromStream(d2data.read(Palettes.ACT1)).render();