removed some unnecessary files

This commit is contained in:
Collin Smith
2019-02-12 02:23:18 -08:00
parent 5d3f5dc4b6
commit a73e0539c3
38 changed files with 274 additions and 3540 deletions

View File

@ -1,26 +0,0 @@
package gdx.diablo.assets;
public class AssetDescriptor<T> {
public static <T> AssetDescriptor<T> of(String fileName, Class<T> type) {
return of(fileName, type, null);
}
public static <T> AssetDescriptor<T> of(String fileName, Class<T> type, AssetLoader.Parameters<T> params) {
return new AssetDescriptor<>(fileName, type, params);
}
public final String fileName;
public final Class<T> type;
public final AssetLoader.Parameters params;
public AssetDescriptor(String fileName, Class<T> type, AssetLoader.Parameters<T> params) {
this.fileName = fileName.replace('\\', '/');
this.type = type;
this.params = params;
}
@Override
public String toString() {
return fileName + ", " + type.getName();
}
}

View File

@ -1,18 +0,0 @@
package gdx.diablo.assets;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
public abstract class AssetLoader<T, P extends AssetLoader.Parameters<T>> {
private FileHandleResolver resolver;
public AssetLoader(FileHandleResolver resolver) {
this.resolver = resolver;
}
public FileHandle resolve(String fileName) {
return resolver.resolve(fileName);
}
public interface Parameters<T> {}
}

View File

@ -1,45 +0,0 @@
package gdx.diablo.assets.async;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.GdxRuntimeException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class AsyncExecutor implements Disposable {
private final ExecutorService executor;
public AsyncExecutor(int maxConcurrent) {
executor = Executors.newFixedThreadPool(maxConcurrent, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "AsyncExecutor-Thread");
thread.setDaemon(true);
return thread;
}
});
}
@Override
public void dispose() {
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new GdxRuntimeException("Couldn't shutdown loading thread", e);
}
}
public <T> AsyncResult<T> submit(final AsyncTask<T> task) {
if (executor.isShutdown()) throw new GdxRuntimeException("Cannot run tasks on an executor that has been shutdown (disposed)");
return new AsyncResult<>(executor.submit(new Callable<T>() {
@Override
public T call() throws Exception {
return task.call();
}
}));
}
}

View File

@ -1,28 +0,0 @@
package gdx.diablo.assets.async;
import com.badlogic.gdx.utils.GdxRuntimeException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class AsyncResult<T> {
private final Future<T> future;
AsyncResult(Future<T> future) {
this.future = future;
}
public boolean isDown() {
return future.isDone();
}
public T get() {
try {
return future.get();
} catch (InterruptedException e) {
return null;
} catch (ExecutionException e) {
throw new GdxRuntimeException(e.getCause());
}
}
}

View File

@ -1,5 +0,0 @@
package gdx.diablo.assets.async;
public interface AsyncTask<T> {
T call() throws Exception;
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.engine.component;
public class LayerComponent {
private LayerComponent() {}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.engine.component;
public class ModeComponent {
private ModeComponent() {}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.engine.component;
public class PositionComponent {
private PositionComponent() {}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.engine.component;
public class VelocityComponent {
private VelocityComponent() {}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.engine.component;
public class WeaponClassComponent {
private WeaponClassComponent() {}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.engine.system;
public class MovementSystem {
private MovementSystem() {}
}

View File

@ -0,0 +1,21 @@
package gdx.diablo.engine.system;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import gdx.diablo.engine.component.WeaponClassComponent;
public class WeaponSystem extends IteratingSystem {
private ComponentMapper<WeaponClassComponent> wc = ComponentMapper.getFor(WeaponClassComponent.class);
public WeaponSystem() {
super(Family.all(WeaponClassComponent.class).get());
}
@Override
protected void processEntity(Entity entity, float delta) {
}
}

View File

@ -1,46 +0,0 @@
package gdx.diablo.entity2;
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;
}
}
}

View File

@ -1,87 +0,0 @@
package gdx.diablo.entity2;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.math.Vector2;
import java.util.EnumMap;
import gdx.diablo.codec.Animation;
import gdx.diablo.graphics.PaletteIndexedBatch;
public class Entity {
/**
* x, y (src)
* angle (radians)
* scalar (movement speed)
*
* x, y (dst)
*/
Vector2 origin;
Vector2 velocity;
String mode;
String code;
String armorType;
String weaponClass;
EnumMap<Component, Animation.Layer> components = new EnumMap<>(Component.class);
Animation.COFAnimation animation;
Entity() {
mode = code = "NU";
armorType = "LIT";
weaponClass = "HTH";
}
public void setMode(String mode) {
setMode(mode, mode);
}
public void setMode(String mode, String code) {
this.mode = mode;
this.code = code;
}
/*
Entity(Excel<M> excel, String mode) {
this(excel.get(mode));
}
Entity(Excel<M> excel) {
this(excel, "NU");
}
*/
/*
public M getMode() {
return mode;
}
public void setMode(M mode) {
this.mode = mode;
}
public String getCode() {
return mode.getCode();
}
*/
public int getX() {
return 0;
}
public int getY() {
return 0;
}
public void setComponent(Component component, Animation.Layer value) {
}
public void draw(Batch batch) {
draw((PaletteIndexedBatch) batch);
}
public void draw(PaletteIndexedBatch batch) {
}
}

View File

@ -1,7 +0,0 @@
package gdx.diablo.entity2;
public class Object extends Entity {
public Object() {
//super(Diablo.files.ObjMode);
}
}

View File

@ -1,115 +0,0 @@
package gdx.diablo.entity2;
import com.badlogic.gdx.Gdx;
import java.util.EnumMap;
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";
public enum Slot {
HEAD,
NECK,
TORS,
RARM,
LARM,
RRIN,
LRIN,
BELT,
FEET,
GLOV;
}
boolean dirty;
boolean alternate;
EnumMap<BodyLoc, Item> equipped = new EnumMap<>(BodyLoc.class);
public Player() {
//super(Diablo.files.PlrMode);
}
public Item getSlot(Slot slot) {
switch (slot) {
case HEAD: return equipped.get(BodyLoc.HEAD);
case NECK: return equipped.get(BodyLoc.NECK);
case TORS: return equipped.get(BodyLoc.TORS);
case RARM: return equipped.get(alternate ? BodyLoc.RARM2 : BodyLoc.RARM);
case LARM: return equipped.get(alternate ? BodyLoc.LARM2 : BodyLoc.LARM);
case RRIN: return equipped.get(BodyLoc.RRIN);
case LRIN: return equipped.get(BodyLoc.LRIN);
case BELT: return equipped.get(BodyLoc.BELT);
case FEET: return equipped.get(BodyLoc.FEET);
case GLOV: return equipped.get(BodyLoc.GLOV);
default:
Gdx.app.error(TAG, "Invalid slot: " + slot);
return null;
}
}
public void update() {
if (!dirty) {
return;
} else {
dirty = false;
}
Item rArm = getSlot(Slot.RARM);
if (rArm != null && rArm.type.is("weap")) {
Weapons.Entry entry = rArm.getBase();
if (entry._2handed) {
weaponClass = entry._2handedwclass;
} else {
weaponClass = entry.wclass;
}
} else {
weaponClass = "HTH";
}
Item lArm = getSlot(Slot.LARM);
if (lArm != null) {
if (lArm.type.is("weap") && rArm != null && rArm.type.is("weap")) {
} else if (lArm.type.is("shld")) {
}
}
if (lArm != null && lArm.type.is("weap")) {
weaponClass = ((Weapons.Entry) lArm.base).wclass;
}
// TODO: add support for barb (1js,1jt,1ss,1st) / assassin (ht1,ht2) customs
Item weapon = null;
if (rArm != null && rArm.type.is("weap")) {
weapon = rArm;
} else if (lArm != null && lArm.type.is("weap")) {
weapon = lArm;
}
String wclass = null;
if (weapon == null) {
wclass = "hth";
} else {
Weapons.Entry weaponEntry = weapon.getBase();
wclass = weaponEntry.wclass;
}
// TODO: custom code for barbarian _1or2handed
if (rArm != null && lArm != null) {
// if rArm and lArm are weapons
// if only one is weapon
/*
if (rArm.type.is("weap")) {
Weapons.Entry rArmEntry = rArm.getBase();
}
*/
} else if (rArm != null) {
} else if (lArm != null) {
}
}
}

View File

@ -1,46 +0,0 @@
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;
}
}
}

View File

@ -1,337 +0,0 @@
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.DS1;
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 static Entity create(DS1 ds1, DS1.Object obj) {
final int type = obj.type;
switch (type) {
case DS1.Object.DYNAMIC_TYPE:
throw new UnsupportedOperationException("Unsupported type: " + type);
case DS1.Object.STATIC_TYPE:
return null;
default:
throw new AssertionError("Unsupported type: " + type);
}
}
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) {
final AssetDescriptor<DCC> descriptor = new AssetDescriptor<>(path, DCC.class);
Diablo.assets.load(descriptor);
Diablo.assets.finishLoadingAsset(descriptor);
DCC dcc = Diablo.assets.get(descriptor);
animation.setLayer(c, dcc);
/*Runnable loader = new Runnable() {
@Override
public void run() {
if (!Diablo.assets.isLoaded(descriptor)) {
Gdx.app.postRunnable(this);
return;
}
DCC dcc = Diablo.assets.get(descriptor);
animation.setLayer(c, dcc);
Item item = getItem(comp);
if (item != null) {
animation.getLayer(c).setTransform(item.charColormap, item.charColorIndex);
}
}
};*/
//Gdx.app.postRunnable(loader);
}
//if (BodyLoc.TORS.contains(c)) {
Item item = getItem(comp);
if (item != null) {
// FIXME: colors don't look right for sorc Tirant circlet changing hair color
// putting a ruby in a white circlet not change color on item or character
// circlets and other items with hidden magic level might work different?
animation.getLayer(layer.component).setTransform(item.charColormap, item.charColorIndex);
//System.out.println(item.getName() + ": " + 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() {
int numDirs = animation.getNumDirections();
return Direction.radiansToDirection(angle, numDirs);
}
public GridPoint2 origin() {
return origin;
}
// TODO: Delete
public void setOrigin(GridPoint2 origin) {
this.origin = 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);
}
}

View File

@ -1,353 +0,0 @@
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 implements Cloneable {
@Override
public Player clone() {
try {
return (Player) super.clone();
} catch (CloneNotSupportedException t) {
throw new GdxRuntimeException(t);
}
}
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<BodyLoc, Item> equipped = new EnumMap<>(BodyLoc.class);
Array<Item> inventory = new Array<>();
final Set<SlotListener> SLOT_LISTENERS = new CopyOnWriteArraySet<>();
public Stats stats;
public Player(String name, CharClass clazz) {
super(Diablo.files.PlrType.get(clazz.id).Token, EntType.CHARS);
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);
setMode("TN");
for (Map.Entry<BodyLoc, Item> 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();
Item LH = getSlot(BodyLoc.LARM);
Item RH = getSlot(BodyLoc.RARM);
Item LH2 = getSlot(BodyLoc.LARM2);
Item RH2 = getSlot(BodyLoc.RARM2);
if (b) {
notifyAlternate(LH2, RH2);
} else {
notifyAlternate(LH, RH);
}
}
}
@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");
}
setArmType(Component.RH, RH != null ? RH.base.alternateGfx : "");
setArmType(Component.LH, LH != null ? LH.base.alternateGfx : "");
setArmType(Component.SH, SH != null ? SH.base.alternateGfx : "");
}
private void notifySlotChanged(BodyLoc bodyLoc, Item oldItem, Item item) {
for (SlotListener l : SLOT_LISTENERS) l.onChanged(this, bodyLoc, oldItem, item);
}
private void notifyAlternate(Item LH, Item RH) {
for (SlotListener l : SLOT_LISTENERS) l.onAlternate(this, LH, RH);
}
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);
void onAlternate(Player player, Item LH, Item RH);
}
public static class SlotAdapter implements SlotListener {
@Override public void onChanged(Player player, BodyLoc bodyLoc, Item oldItem, Item item) {}
@Override public void onAlternate(Player player, Item LH, Item RH) {}
}
public Array<Item> 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;
}
}
}

View File

@ -1,589 +0,0 @@
package gdx.diablo.map2;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.StreamUtils;
import org.apache.commons.io.EndianUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import gdx.diablo.util.BufferUtils;
public class DS1 {
private static final String TAG = "DS1";
private static final boolean DEBUG = true;
private static final boolean DEBUG_FILES = DEBUG && true;
private static final boolean DEBUG_SIZES = DEBUG && true;
private static final boolean DEBUG_LAYERS = DEBUG && true;
private static final boolean DEBUG_CELLS = DEBUG && !true;
private static final boolean DEBUG_OBJECTS = DEBUG && true;
private static final boolean DEBUG_GROUPS = DEBUG && true;
private static final boolean DEBUG_PATHS = DEBUG && true;
private static final boolean DEBUG_STREAM = DEBUG && true;
private static final boolean DEBUG_PROPS = DEBUG && true;
private static final int ACT_MAX = 5;
private static final int DWORD = 4;
public static final int MAX_FLOOR_LAYERS = 2;
public static final int MAX_SHADOW_LAYERS = 1;
public static final int MAX_WALL_LAYERS = 4;
public static final int FLOOR_OFFSET = 0;
public static final int SHADOW_OFFSET = FLOOR_OFFSET + MAX_FLOOR_LAYERS;
public static final int WALL_OFFSET = SHADOW_OFFSET + MAX_SHADOW_LAYERS;
public static final int MAX_LAYERS = WALL_OFFSET + MAX_WALL_LAYERS;
public static final int WALL_LAYER = 1;
public static final int ORIENT_LAYER = 5;
public static final int FLOOR_LAYER = 9;
public static final int SHADOW_LAYER = 11;
public static final int TAG_LAYER = 12;
public static final int STREAM_LAYERS = 12;
public static final int WALL_LAYER_1 = WALL_LAYER;
public static final int WALL_LAYER_2 = WALL_LAYER + 1;
public static final int WALL_LAYER_3 = WALL_LAYER + 2;
public static final int WALL_LAYER_4 = WALL_LAYER + 3;
public static final int ORIENT_LAYER_1 = ORIENT_LAYER;
public static final int ORIENT_LAYER_2 = ORIENT_LAYER + 1;
public static final int ORIENT_LAYER_3 = ORIENT_LAYER + 2;
public static final int ORIENT_LAYER_4 = ORIENT_LAYER + 3;
public static final int FLOOR_LAYER_1 = FLOOR_LAYER;
public static final int FLOOR_LAYER_2 = FLOOR_LAYER + 1;
private static final short ORIENTATION_TABLE[] = {
0x00, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, 0x05, 0x05, 0x06,
0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x14
};
int version;
int width;
int height;
int act;
int tagType;
int numFiles;
String files[];
int numWalls;
int numFloors;
int numTags;
int numShadows;
int numLayers;
int layerStream[];
int wallLine, wallLen;
Cell walls[];
int floorLine, floorLen;
Cell floors[];
int shadowLine, shadowLen;
Cell shadows[];
int tagLine, tagLen;
int tags[];
int numObjects;
Object objects[];
int numGroups;
Group groups[];
int numPaths;
Path paths[];
IntMap<GridPoint2> specials;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("version", version)
.append("width", width)
.append("height", height)
.append("act", act)
.append("tagType", tagType)
.append("numFiles", numFiles)
.append("numWalls", numWalls)
.append("numFloors", numFloors)
.append("numTags", numTags)
.append("numShadows", numShadows)
.append("layerStream", Arrays.toString(Arrays.copyOf(layerStream, numLayers)))
.append("floorLine", floorLine)
.append("floorLen", floorLen)
.append("shadowLine", shadowLine)
.append("shadowLen", shadowLen)
.append("tagLine", tagLine)
.append("tagLen", tagLen)
.append("wallLine", wallLine)
.append("wallLen", wallLen)
.append("numObjects", numObjects)
.append("numGroups", numGroups)
.append("numPaths", numPaths)
.toString();
}
public GridPoint2 find(int id) {
return specials.get(id);
}
public GridPoint2 find(int orientation, int mainIndex, int subIndex) {
int id = DT1.Tile.Index.create(orientation, mainIndex, subIndex);
return find(id);
}
public static DS1 loadFromFile(FileHandle handle) {
return loadFromStream(handle.read());
}
public static DS1 loadFromStream(InputStream in) {
try {
DS1 ds1 = new DS1().read(in);
if (DEBUG) Gdx.app.debug(TAG, ds1.toString());
if (ds1.version < 9 || 13 < ds1.version) {
// FIXME: version 9 <= 13 causes crash here /w 4B remaining, why?
assert in.available() == 0 : in.available() + "B available!";
} else if (DEBUG_STREAM && in.available() > 0) {
Gdx.app.error(TAG, in.available() + "B still available in stream!");
}
return ds1;
} catch (Throwable t) {
throw new GdxRuntimeException("Couldn't read DS1.", t);
} finally {
StreamUtils.closeQuietly(in);
}
}
private DS1 read(InputStream in) throws IOException {
version = EndianUtils.readSwappedInteger(in);
width = EndianUtils.readSwappedInteger(in) + 1;
height = EndianUtils.readSwappedInteger(in) + 1;
act = version < 8 ? 1 : Math.min(EndianUtils.readSwappedInteger(in) + 1, ACT_MAX);
tagType = version < 10 ? 0 : EndianUtils.readSwappedInteger(in);
numFiles = version < 3 ? 0 : EndianUtils.readSwappedInteger(in);
files = numFiles == 0 ? ArrayUtils.EMPTY_STRING_ARRAY : new String[numFiles];
for (int i = 0; i < numFiles; i++) {
files[i] = BufferUtils.readString(in);
if (DEBUG_FILES) Gdx.app.debug(TAG, "file[" + i + "] = " + files[i]);
}
if (9 <= version && version <= 13) IOUtils.skipFully(in, 2 * DWORD);
if (version < 4) {
numWalls = 1;
numFloors = 1;
numTags = 1;
numShadows = 1;
} else {
numWalls = EndianUtils.readSwappedInteger(in);
numFloors = version < 16 ? 1 : EndianUtils.readSwappedInteger(in);
numTags = (tagType == 1 || tagType == 2) ? 1 : 0;
numShadows = 1;
}
if (DEBUG_SIZES) Gdx.app.debug(TAG, String.format("layers: (2 * %d walls) + %d floors + %d shadow + %d tag", numWalls, numFloors, numShadows, numTags));
layerStream = new int[STREAM_LAYERS];
if (version < 4) {
numLayers = 5;
layerStream[0] = WALL_LAYER;
layerStream[1] = FLOOR_LAYER;
layerStream[2] = ORIENT_LAYER;
layerStream[3] = TAG_LAYER;
layerStream[4] = SHADOW_LAYER;
} else {
numLayers = 0;
for (int i = 0; i < numWalls; i++) {
layerStream[numLayers++] = WALL_LAYER + i;
layerStream[numLayers++] = ORIENT_LAYER + i;
}
for (int i = 0; i < numFloors; i++) {
layerStream[numLayers++] = FLOOR_LAYER + i;
}
if (numShadows > 0) {
layerStream[numLayers++] = SHADOW_LAYER;
}
if (numTags > 0) {
layerStream[numLayers++] = TAG_LAYER;
}
}
floorLine = width * numFloors;
floorLen = floorLine * height;
floors = new Cell[floorLen];
int floorOffset[] = new int[numFloors];
for (int i = 0; i < numFloors; i++) {
floorOffset[i] = i;
}
shadowLine = width * numShadows;
shadowLen = shadowLine * height;
shadows = new Cell[shadowLen];
int shadowOffset[] = new int[numShadows];
for (int i = 0; i < numShadows; i++) {
shadowOffset[i] = i;
}
tagLine = width * numTags;
tagLen = tagLine * height;
tags = new int[tagLen];
int tagOffset[] = new int[numTags];
for (int i = 0; i < numTags; i++) {
tagOffset[i] = i;
}
wallLine = width * numWalls;
wallLen = wallLine * height;
walls = new Cell[wallLen];
int wallOffset[] = new int[numWalls], orientationOffset[] = new int[numWalls];
for (int i = 0; i < numWalls; i++) {
wallOffset[i] = orientationOffset[i] = i;
}
if (DEBUG_LAYERS) Gdx.app.debug(TAG, "floorLine=" + floorLine + "; floorLen=" + floorLen);
if (DEBUG_LAYERS) Gdx.app.debug(TAG, "shadowLine=" + shadowLine + "; shadowLen=" + shadowLen);
if (DEBUG_LAYERS) Gdx.app.debug(TAG, "tagLine=" + tagLine + "; tagLen=" + tagLen);
if (DEBUG_LAYERS) Gdx.app.debug(TAG, "wallLine=" + wallLine + "; wallLen=" + wallLen);
if (DEBUG_LAYERS) Gdx.app.debug(TAG, "layerStream=" + Arrays.toString(Arrays.copyOf(layerStream, numLayers)));
specials = new IntMap<>();
for (int l = 0, layer, i, id; l < numLayers; l++) {
layer = layerStream[l];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
switch (layer) {
// wall
case WALL_LAYER_1: case WALL_LAYER_2: case WALL_LAYER_3: case WALL_LAYER_4:
i = layer - WALL_LAYER;
id = wallOffset[i];
assert walls[id] == null;
walls[id] = new Cell().read(in);
wallOffset[i] += numWalls;
break;
// orientation
case ORIENT_LAYER_1: case ORIENT_LAYER_2: case ORIENT_LAYER_3: case ORIENT_LAYER_4:
i = layer - ORIENT_LAYER;
id = orientationOffset[i];
Cell wall = walls[id];
assert wall != null;
int j = EndianUtils.readSwappedInteger(in);
wall.setOrientation(version < 7 ? ORIENTATION_TABLE[j] : j);
orientationOffset[i] += numWalls;
if (!Orientation.isSpecial(wall.orientation)) {
break;
}
specials.put(wall.id, new GridPoint2(x, y));
if (DEBUG_PROPS) {
int mainIndex = (wall.value & 0x03F00000) >>> 20;
int subIndex = (wall.value & 0x0000FF00) >>> 8;
int first = (wall.value & 0xFC000000) >>> 26;
int second = (wall.value & 0x000F0000) >>> 16;
int third = (wall.value & 0x000000FF);
Gdx.app.debug(TAG, String.format("%d (%2d,%2d) %08X %2d,%2d,%2d %02X %02X %X %02X %02X",
l, x, y, wall.value,
mainIndex, wall.orientation, subIndex,
first, mainIndex, second, subIndex, third));
}
break;
// floor
case FLOOR_LAYER_1: case FLOOR_LAYER_2:
i = layer - FLOOR_LAYER;
id = floorOffset[i];
assert floors[id] == null;
floors[id] = new Cell().read(in);
floorOffset[i] += numFloors;
break;
// shadow
case SHADOW_LAYER:
i = layer - SHADOW_LAYER;
id = shadowOffset[i];
assert shadows[id] == null;
shadows[id] = new Cell().read(in);
shadowOffset[i] += numShadows;
break;
// tag
case TAG_LAYER:
i = layer - TAG_LAYER;
id = tagOffset[i];
tags[id] = EndianUtils.readSwappedInteger(in);
tagOffset[i] += numTags;
break;
// error
default:
Gdx.app.error(TAG, "Unknown layer: " + layer);
}
}
}
}
if (DEBUG_CELLS) {
for (int i = 0; i < wallLen; i++) Gdx.app.debug(TAG, "walls[" + i + "]=" + walls[i].toString());
for (int i = 0; i < floorLen; i++) Gdx.app.debug(TAG, "floors[" + i + "]=" + floors[i].toString());
for (int i = 0; i < shadowLen; i++) Gdx.app.debug(TAG, "shadows[" + i + "]=" + shadows[i].toString());
Gdx.app.debug(TAG, "tags=" + Arrays.toString(tags));
}
int maxSubtileWidth = width * 5;
int maxSubtileHeight = height * 5;
numObjects = version < 2 ? 0 : EndianUtils.readSwappedInteger(in);
objects = numObjects == 0 ? Object.EMPTY_OBJECT_ARRAY : new Object[numObjects];
for (int i = 0; i < numObjects; i++) {
try {
Object object = objects[i] = new Object().read(version, in);
if (DEBUG_OBJECTS) Gdx.app.debug(TAG, object.toString());
if (object.x < 0 || maxSubtileWidth <= object.x
|| object.y < 0 || maxSubtileHeight <= object.y) {
Gdx.app.error(TAG, "Object out of DS1 bounds: " + object);
}
} catch (Throwable t) {
// Don't care, invalid object, skip it. Log it for posterity.
Gdx.app.error(TAG, t.getMessage(), t);
}
}
if (version >= 12 && (tagType == 1 || tagType == 2)) {
if (version >= 18) IOUtils.skip(in, DWORD);
numGroups = EndianUtils.readSwappedInteger(in);
groups = numGroups == 0 ? Group.EMPTY_GROUP_ARRAY : new Group[numGroups];
for (int i = 0; i < numGroups; i++) {
groups[i] = new Group().read(version, in);
if (DEBUG_GROUPS) Gdx.app.debug(TAG, groups[i].toString());
}
} else {
numGroups = 0;
groups = Group.EMPTY_GROUP_ARRAY;
}
if (version >= 14 && in.available() >= DWORD) {
numPaths = EndianUtils.readSwappedInteger(in);
paths = numPaths == 0 ? Path.EMPTY_PATH_ARRAY : new Path[numPaths];
for (int i = 0; i < numPaths; i++) {
Path path = paths[i] = new Path().read(version, objects, in);
if (DEBUG_PATHS) Gdx.app.debug(TAG, path.toString());
}
} else {
numPaths = 0;
paths = Path.EMPTY_PATH_ARRAY;
}
width -= 1;
height -= 1;
return this;
}
static class Cell {
// 0x03F00000
private static final int MAIN_INDEX_OFFSET = 20;
private static final int MAIN_INDEX_BITS = 0x3F;
// 0x0000FF00
private static final int SUB_INDEX_OFFSET = 8;
private static final int SUB_INDEX_BITS = 0xFF;
public static final int MASK_MAIN_INDEX = MAIN_INDEX_BITS << MAIN_INDEX_OFFSET;
public static final int SUB_MAIN_INDEX = SUB_INDEX_BITS << SUB_INDEX_OFFSET;
public static final int MASK_UNWALKABLE = 0x00020000;
int id;
int value;
short mainIndex;
short subIndex;
short orientation;
Cell read(InputStream in) throws IOException {
value = EndianUtils.readSwappedInteger(in);
mainIndex = (short) ((value >>> MAIN_INDEX_OFFSET) & MAIN_INDEX_BITS);
subIndex = (short) ((value >>> SUB_INDEX_OFFSET) & SUB_INDEX_BITS);
orientation = Orientation.FLOOR;
id = DT1.Tile.Index.create(orientation, mainIndex, subIndex);
return updateIndex();
}
void setOrientation(int orientation) {
this.orientation = (short) orientation;
updateIndex();
}
Cell updateIndex() {
id = DT1.Tile.Index.create(orientation, mainIndex, subIndex);
return this;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", Integer.toHexString(id))
.append("value", Integer.toHexString(value))
.append("mainIndex", mainIndex)
.append("subIndex", subIndex)
.append("orientation", orientation)
.build();
}
}
public static class Object {
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
public static final int DYNAMIC_TYPE = 1;
public static final int STATIC_TYPE = 2;
int type;
int id;
int x;
int y;
int ds1Flags;
Object read(int version, InputStream in) throws IOException {
type = EndianUtils.readSwappedInteger(in);
id = EndianUtils.readSwappedInteger(in);
x = EndianUtils.readSwappedInteger(in);
y = EndianUtils.readSwappedInteger(in);
ds1Flags = version < 6 ? 0 : EndianUtils.readSwappedInteger(in);
return this;
}
String getType() {
switch (type) {
case DYNAMIC_TYPE: return "DYNAMIC_TYPE";
case STATIC_TYPE: return "STATIC_TYPE";
default: return Integer.toString(type);
}
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("type", getType())
.append("id", id)
.append("x", x)
.append("y", y)
.append("ds1Flags", "0x" + Integer.toHexString(ds1Flags))
.build();
}
}
static class Group {
public static final Group[] EMPTY_GROUP_ARRAY = new Group[0];
int x;
int y;
int width;
int height;
int unk;
Group read(int version, InputStream in) throws IOException {
if (in.available() >= DWORD) x = EndianUtils.readSwappedInteger(in);
if (in.available() >= DWORD) y = EndianUtils.readSwappedInteger(in);
if (in.available() >= DWORD) width = EndianUtils.readSwappedInteger(in);
if (in.available() >= DWORD) height = EndianUtils.readSwappedInteger(in);
if (version >= 13) {
if (in.available() >= DWORD) unk = EndianUtils.readSwappedInteger(in);
}
return this;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("x", x)
.append("y", y)
.append("width", width)
.append("height", height)
.append("unk", unk)
.build();
}
}
public static class Path {
public static final Path[] EMPTY_PATH_ARRAY = new Path[0];
int numPoints;
Point points[];
int x;
int y;
Path read(int version, Object[] objects, InputStream in) throws IOException {
numPoints = EndianUtils.readSwappedInteger(in);
points = new Point[numPoints];
x = EndianUtils.readSwappedInteger(in);
y = EndianUtils.readSwappedInteger(in);
Object object = null;
for (int i = 0; i < objects.length; i++) {
Object tmp = objects[i];
if (tmp == null) continue;
if (tmp.x != x || tmp.y != y) continue;
if (object != null) Gdx.app.error(TAG, "More than one object is located at path position: " + this);
object = tmp;
}
if (object == null) {
Gdx.app.error(TAG, "No object associated with path: " + this);
int skip = version >= 15 ? 12 : 8;
for (int p = 0; p < numPoints; p++) {
in.skip(skip);
}
return this;
}
for (int p = 0; p < numPoints; p++) points[p] = new Point().read(version, in);
return this;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("x", x)
.append("y", y)
.append("numPoints", numPoints)
.append("points", Arrays.toString(points))
.build();
}
static class Point {
int x;
int y;
int action;
Point read(int version, InputStream in) throws IOException {
x = EndianUtils.readSwappedInteger(in);
y = EndianUtils.readSwappedInteger(in);
action = version < 15 ? 1 : EndianUtils.readSwappedInteger(in);
return this;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("x", x)
.append("y", y)
.append("action", action)
.build();
}
}
}
}

View File

@ -1,43 +0,0 @@
package gdx.diablo.map2;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetLoaderParameters;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
public class DS1Loader extends AsynchronousAssetLoader<DS1, DS1Loader.DS1LoaderParameters> {
DS1 ds1;
public DS1Loader(FileHandleResolver resolver) {
super(resolver);
}
@Override
public void loadAsync(AssetManager assets, String fileName, FileHandle file, DS1LoaderParameters params) {
ds1 = DS1.loadFromStream(file.read());
}
@Override
public DS1 loadSync(AssetManager assets, String fileName, FileHandle file, DS1LoaderParameters params) {
DS1 ds1 = this.ds1;
if (ds1 == null) {
ds1 = DS1.loadFromStream(file.read());
} else {
this.ds1 = null;
}
return ds1;
}
@Override
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, DS1LoaderParameters params) {
return null;
}
public static class DS1LoaderParameters extends AssetLoaderParameters<DS1> {}
}

View File

@ -1,501 +0,0 @@
package gdx.diablo.map2;
import com.google.common.base.Preconditions;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.StreamUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import gdx.diablo.Diablo;
import gdx.diablo.codec.Palette;
import gdx.diablo.graphics.PaletteIndexedPixmap;
import gdx.diablo.util.BufferUtils;
// TODO: In production, skip unused data (zeros/unknowns)
public class DT1 implements Disposable {
private static final String TAG = "DT1";
private static final boolean DEBUG = true;
private static final boolean DEBUG_TILE_HEADERS = DEBUG && !true;
private static final boolean DEBUG_BLOCK_HEADERS = DEBUG && !true;
private static final int X_JUMP[] = { 14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14 };
private static final int PIXEL_WIDTH[] = { 4, 8, 12, 16, 20, 24, 28, 32, 28, 24, 20, 16, 12, 8, 4 };
String fileName;
Header header;
Tile tiles[];
Texture textures[];
private DT1(String fileName, Header header, Tile[] tiles) {
this.fileName = fileName;
this.header = header;
this.tiles = tiles;
Diablo.dt1s.add(this);
}
public int getVersion1() {
return header.version1;
}
public int getVersion2() {
return header.version2;
}
public int getNumTiles() {
return header.numTiles;
}
public Tile getTile(int i) {
return tiles[i];
}
@Override
public void dispose() {
if (textures == null) return;
for (Texture texture : textures) texture.dispose();
Diablo.dt1s.remove(this);
}
public TextureRegion getTexture(int i) {
return new TextureRegion(textures[i]);
}
public void prepareTextures() {
Preconditions.checkState(textures == null, "textures have already been prepared");
textures = new Texture[header.numTiles];
for (int i = 0; i < header.numTiles; i++) {
Texture texture = new Texture(new PixmapTextureData(tiles[i].pixmap, null, false, false, false));
//texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
texture.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
textures[i] = tiles[i].texture = texture;
}
}
public static DT1 loadFromFile(FileHandle handle) {
return loadFromStream(handle.path(), handle.read());
}
public static DT1 loadFromStream(String fileName, InputStream in) {
try {
Header header = new Header(in);
if (DEBUG) Gdx.app.debug(TAG, header.toString());
if (header.version1 != 0x7)
throw new GdxRuntimeException("Unknown version1: " + header.version1);
if (header.version2 != 0x6)
throw new GdxRuntimeException("Unknown version2: " + header.version2);
Tile[] tiles = new Tile[header.numTiles];
for (int i = 0; i < header.numTiles; i++) {
Tile tile = tiles[i] = new Tile(in);
if (DEBUG_TILE_HEADERS) Gdx.app.debug(TAG, tile.toString());
}
for (Tile tile : tiles) {
Block[] blockHeaders = tile.blocks = new Block[tile.numBlocks];
for (int i = 0; i < tile.numBlocks; i++) {
blockHeaders[i] = new Block(in);
if (DEBUG_BLOCK_HEADERS) Gdx.app.debug(TAG, blockHeaders[i].toString());
}
for (Block blockHeader : blockHeaders) {
blockHeader.colormap = IOUtils.readFully(in, blockHeader.length);
}
tile.createPixmap();
}
assert in.available() == 0;
return new DT1(fileName, header, tiles);
} catch (Throwable t) {
throw new GdxRuntimeException("Couldn't read DT1", t);
} finally {
StreamUtils.closeQuietly(in);
}
}
private static boolean allZeros(byte[] zeros) {
for (byte b : zeros) {
if (b != 0) return false;
}
return true;
}
static class Header {
static final int SIZE = 276;
int version1;
int version2;
byte zeros[];
int numTiles;
int tileOffset;
Header(InputStream in) throws IOException {
ByteBuffer buffer = ByteBuffer.wrap(IOUtils.readFully(in, SIZE)).order(ByteOrder.LITTLE_ENDIAN);
version1 = buffer.getInt();
version2 = buffer.getInt();
zeros = BufferUtils.readBytes(buffer, 260);
numTiles = buffer.getInt();
tileOffset = buffer.getInt();
assert !buffer.hasRemaining();
assert allZeros(zeros) : "Expected 260 zeros, got: " + Arrays.toString(zeros);
assert tileOffset == SIZE : "Expected first tile header to be located at 276: " + tileOffset;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("version1", version1)
.append("version2", version2)
//.append("zeros", Arrays.toString(zeros))
.append("numTiles", numTiles)
.append("tileOffset", "0x" + Integer.toHexString(tileOffset))
.toString();
}
}
public static class Tile {
static final int SIZE = 96;
public static final int WIDTH = 160;
public static final int HEIGHT = 80;
public static final int SUBTILE_SIZE = 5;
public static final int NUM_SUBTILES = SUBTILE_SIZE * SUBTILE_SIZE;
public static final int SUBTILE_WIDTH = WIDTH / SUBTILE_SIZE;
public static final int SUBTILE_HEIGHT = HEIGHT / SUBTILE_SIZE;
public static final int[][] SUBTILE_INDEX/* = {
{0, 5, 10, 15, 20},
{1, 6, 11, 16, 21},
{2, 7, 12, 17, 22},
{3, 8, 13, 18, 23},
{4, 9, 14, 19, 24},
}*/;
static {
SUBTILE_INDEX = new int[SUBTILE_SIZE][SUBTILE_SIZE];
for (int y = 0, i = 0; y < SUBTILE_SIZE; y++) {
for (int x = 0; x < SUBTILE_SIZE; x++, i++) {
SUBTILE_INDEX[x][y] = i;
}
}
}
public static final int[][] SUBTILE_OFFSET/* = {
{64, 64}, {80, 56}, {96, 48}, {112, 40}, {128, 32},
{48, 56}, {64, 48}, {80, 40}, { 96, 32}, {112, 24},
{32, 48}, {48, 40}, {64, 32}, { 80, 24}, { 96, 16},
{16, 40}, {32, 32}, {48, 24}, { 64, 16}, { 80, 8},
{ 0, 32}, {16, 24}, {32, 16}, { 48, 8}, { 64, 0},
}*/;
static {
SUBTILE_OFFSET = new int[NUM_SUBTILES][2];
final int halfSubtileWidth = SUBTILE_WIDTH / 2;
final int halfSubtileHeight = SUBTILE_HEIGHT / 2;
for (int y = 0, i = 0; y < SUBTILE_SIZE; y++) {
int px = (WIDTH / 2) - halfSubtileWidth - (y * halfSubtileWidth);
int py = HEIGHT - SUBTILE_HEIGHT - (y * halfSubtileHeight);
for (int x = 0; x < SUBTILE_SIZE; x++, i++) {
SUBTILE_OFFSET[i][0] = px;
SUBTILE_OFFSET[i][1] = py;
px += halfSubtileWidth;
py -= halfSubtileHeight;
}
}
}
public static final int FLAG_BLOCK_WALK = 1 << 0;
public static final int FLAG_BLOCK_LIGHT_LOS = 1 << 1;
public static final int FLAG_BLOCK_JUMP = 1 << 2;
public static final int FLAG_BLOCK_PLAYER_WALK = 1 << 3;
public static final int FLAG_BLOCK_UNKNOWN1 = 1 << 4;
public static final int FLAG_BLOCK_LIGHT = 1 << 5;
public static final int FLAG_BLOCK_UNKNOWN2 = 1 << 6;
public static final int FLAG_BLOCK_UNKNOWN3 = 1 << 7;
public int direction;
public short roofHeight;
public byte soundIndex;
public byte animated;
public int height;
public int width;
public byte zeros1[];
public int orientation;
public int mainIndex;
public int subIndex;
public int rarity; // frame index if animated
public byte unknown[];
public byte tileFlags[];
public byte zeros2[];
public int blockHeadersPointer;
public int blockDataLength;
public int numBlocks;
public byte zeros3[];
Block blocks[];
Pixmap pixmap;
Texture texture;
int id;
/**
* zeros3 is not all zeros all of the time. This might correlate with unknown. I need to figure
* out what these variables mean, I'm fairly certain zeros3 is 3 ints, or at least the second
* 4 bytes are used somewhere.
*
* data\global\tiles\expansion\Town\shrine.dt1
* data\global\tiles\expansion\Town\trees.dt1
*
* unknown in above is same F6 62 FF 00 (16737014)
* but zeros3 is different:
* 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 6C B0 08 0B 00 00 00 00
*
* data\global\tiles\expansion\Town\tent.dt1
* F3 65 FF 00 (16737779)
* 00 00 00 00 4C 00 37 0B 00 00 00 00
*/
Tile(InputStream in) throws IOException {
ByteBuffer buffer = ByteBuffer.wrap(IOUtils.readFully(in, SIZE)).order(ByteOrder.LITTLE_ENDIAN);
direction = buffer.getInt();
roofHeight = buffer.getShort();
soundIndex = buffer.get();
animated = buffer.get();
height = buffer.getInt();
width = buffer.getInt();
zeros1 = BufferUtils.readBytes(buffer, 4);
orientation = buffer.getInt();
mainIndex = buffer.getInt();
subIndex = buffer.getInt();
rarity = buffer.getInt();
unknown = BufferUtils.readBytes(buffer, 4);
tileFlags = BufferUtils.readBytes(buffer, NUM_SUBTILES);
zeros2 = BufferUtils.readBytes(buffer, 7);
blockHeadersPointer = buffer.getInt();
blockDataLength = buffer.getInt();
numBlocks = buffer.getInt();
zeros3 = BufferUtils.readBytes(buffer, 12);
id = Index.create(orientation, mainIndex, subIndex);
assert !buffer.hasRemaining();
assert allZeros(zeros1) : "Expected 4 zeros, got: " + Arrays.toString(zeros1);
assert allZeros(zeros2) : "Expected 7 zeros, got: " + Arrays.toString(zeros2);
//assert allZeros(zeros3) : "Expected 12 zeros, got: " + Arrays.toString(zeros3);
}
public int getNumBlocks() {
return numBlocks;
}
public Block getBlock(int i) {
return blocks[i];
}
public boolean isSpecial() {
return Orientation.isSpecial(orientation);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", "0x" + Integer.toHexString(id))
.append("direction", direction)
.append("roofHeight", roofHeight)
.append("soundIndex", soundIndex)
.append("animated", animated)
.append("height", height)
.append("width", width)
//.append("zeros1", Arrays.toString(zeros1))
.append("orientation", orientation)
.append("mainIndex", mainIndex)
.append("subIndex", subIndex)
.append("rarity", rarity)
.append("unknown", Arrays.toString(unknown))
.append("tileFlags", Arrays.toString(tileFlags))
//.append("zeros2", Arrays.toString(zeros2))
.append("blockHeadersPointer", "0x" + Integer.toHexString(blockHeadersPointer))
.append("blockDataLength", blockDataLength)
.append("numBlocks", numBlocks)
//.append("zeros3", Arrays.toString(zeros3))
.toString();
}
public void createPixmap() {
Preconditions.checkState(pixmap == null, "pixmap should be null");
int absWidth = width;
int absHeight = -height;
if (isSpecial()) {
absWidth = WIDTH;
}
int y_add = 96;
if (orientation == Orientation.FLOOR || orientation == Orientation.ROOF) {
if (height != 0) {
height = -80;
absHeight = 80;
y_add = 0;
}
} else if (orientation < Orientation.ROOF) {
if (height != 0) {
height += 32;
absHeight -= 32;
y_add = absHeight;
}
}
int x0, y0, length, format;
byte[] data;
pixmap = new PaletteIndexedPixmap(absWidth, absHeight);
for (Block block : blocks) {
x0 = block.x;
y0 = y_add + block.y;
data = block.colormap;
length = block.length;
format = block.format;
if (format == 0x0001) {
drawIsometricBlock(x0, y0, data, length);
} else {
drawRLEBlock(x0, y0, data, length);
}
}
}
private void drawIsometricBlock(int x0, int y0, byte[] data, int length) {
if (length != 256) {
Gdx.app.error(TAG, "Blocks should be 256 bytes, was " + length);
return;
}
int x, y = 0, n, i = 0;
while (length > 0) {
x = X_JUMP[y];
n = PIXEL_WIDTH[y];
length -= n;
while (n > 0) {
pixmap.drawPixel(x0 + x, y0 + y, Palette.a8(data[i]));
i++;
x++;
n--;
}
y++;
}
}
private void drawRLEBlock(int x0, int y0, byte[] data, int length) {
int i = 0, b1, b2;
int x = 0, y = 0;
while (length > 0) {
b1 = data[i] & 0xFF;
b2 = data[i + 1] & 0xFF;
i += 2;
length -= 2;
if (b1 > 0 || b2 > 0) {
x += b1;
length -= b2;
while (b2 > 0) {
pixmap.drawPixel(x0 + x, y0 + y, Palette.a8(data[i]));
i++;
x++;
b2--;
}
} else {
x = 0;
y++;
}
}
}
public static class Index {
private static final int MAIN_INDEX_OFFSET = 16;
private static final int MAIN_INDEX_BITS = 0xFF;
private static final int SUB_INDEX_OFFSET = 8;
private static final int SUB_INDEX_BITS = 0xFF;
private static final int ORIENTATION_OFFSET = 0;
private static final int ORIENTATION_BITS = 0xFF;
public static int create(int orientation, int mainIndex, int subIndex) {
return (mainIndex & MAIN_INDEX_BITS) << MAIN_INDEX_OFFSET
| (subIndex & SUB_INDEX_BITS) << SUB_INDEX_OFFSET
| (orientation & ORIENTATION_BITS) << ORIENTATION_OFFSET;
}
public static int mainIndex(int index) {
return (index >>> MAIN_INDEX_OFFSET) & MAIN_INDEX_BITS;
}
public static int subIndex(int index) {
return (index >>> SUB_INDEX_OFFSET) & SUB_INDEX_BITS;
}
public static int orientation(int index) {
return (index >>> ORIENTATION_OFFSET) & ORIENTATION_BITS;
}
}
}
public static class Block {
static final int SIZE = 20;
public short x;
public short y;
public byte zeros1[];
public byte gridX;
public byte gridY;
public short format;
public int length;
public byte zeros2[];
public int fileOffset;
public byte colormap[];
Block(InputStream in) throws IOException {
ByteBuffer buffer = ByteBuffer.wrap(IOUtils.readFully(in, SIZE)).order(ByteOrder.LITTLE_ENDIAN);
x = buffer.getShort();
y = buffer.getShort();
zeros1 = BufferUtils.readBytes(buffer, 2);
gridX = buffer.get();
gridY = buffer.get();
format = buffer.getShort();
length = buffer.getInt();
zeros2 = BufferUtils.readBytes(buffer, 2);
fileOffset = buffer.getInt();
assert !buffer.hasRemaining();
assert allZeros(zeros1) : "Expected 2 zeros, got: " + Arrays.toString(zeros1);
assert allZeros(zeros2) : "Expected 2 zeros, got: " + Arrays.toString(zeros2);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("x", x)
.append("y", y)
//.append("zeros1", Arrays.toString(zeros1))
.append("gridX", gridX)
.append("gridY", gridY)
.append("format", format)
.append("length", length)
//.append("zeros2", Arrays.toString(zeros2))
.append("fileOffset", "0x" + Integer.toHexString(fileOffset))
.toString();
}
}
}

View File

@ -1,44 +0,0 @@
package gdx.diablo.map2;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetLoaderParameters;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
public class DT1Loader extends AsynchronousAssetLoader<DT1, DT1Loader.DT1LoaderParameters> {
DT1 dt1;
public DT1Loader(FileHandleResolver resolver) {
super(resolver);
}
@Override
public void loadAsync(AssetManager assets, String fileName, FileHandle file, DT1LoaderParameters params) {
dt1 = DT1.loadFromStream(fileName, file.read());
}
@Override
public DT1 loadSync(AssetManager assets, String fileName, FileHandle file, DT1LoaderParameters params) {
DT1 dt1 = this.dt1;
if (dt1 == null) {
dt1 = DT1.loadFromStream(fileName, file.read());
} else {
this.dt1 = null;
}
dt1.prepareTextures();
return dt1;
}
@Override
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, DT1LoaderParameters params) {
return null;
}
public static class DT1LoaderParameters extends AssetLoaderParameters<DT1> {}
}

View File

@ -1,72 +0,0 @@
package gdx.diablo.map2;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntIntMap;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectSet;
public class DT1s {
// TODO: tiles and prob are both keyed with tile ID, can speed up if using one map to Pair<prob, tiles>
ObjectSet<DT1> dt1s = new ObjectSet<>();
IntMap<Array<DT1.Tile>> tiles = new IntMap<>();
IntIntMap prob = new IntIntMap();
void add(DT1.Tile tile) {
//if (tile.rarity == 0) return;
Array<DT1.Tile> tiles = this.tiles.get(tile.id);
if (tiles == null) this.tiles.put(tile.id, tiles = new Array<>());
tiles.add(tile);
prob.getAndIncrement(tile.id, 0, tile.rarity);
}
void remove(DT1.Tile tile) {
//if (tile.rarity == 0) return;
Array<DT1.Tile> tiles = this.tiles.get(tile.id);
if (tiles == null) return;
tiles.removeValue(tile, true);
prob.getAndIncrement(tile.id, 0, -tile.rarity);
}
public boolean add(DT1 dt1) {
if (!dt1s.add(dt1)) return false;
for (DT1.Tile tile : dt1.tiles) add(tile);
return true;
}
public boolean remove(DT1 dt1) {
if (!dt1s.remove(dt1)) return false;
for (DT1.Tile tile : dt1.tiles) remove(tile);
return true;
}
public DT1.Tile get(int orientation, int mainIndex, int subIndex) {
int id = DT1.Tile.Index.create(orientation, mainIndex, subIndex);
Array<DT1.Tile> tiles = this.tiles.get(id);
return next(id, tiles);
}
public DT1.Tile get(DS1.Cell cell) {
Array<DT1.Tile> tiles = this.tiles.get(cell.id);
return next(cell.id, tiles);
}
public DT1.Tile get(int id) {
Array<DT1.Tile> tiles = this.tiles.get(id);
return next(id, tiles);
}
private DT1.Tile next(int id, Array<DT1.Tile> tiles) {
if (tiles == null) return null;
int sum = prob.get(id, 0);
int random = sum == 0 ? 0 : MathUtils.random(sum - 1);
for (DT1.Tile tile : tiles) {
random -= tile.rarity;
if (random <= 0) {
return tile;
}
}
return null;
}
}

View File

@ -1,461 +0,0 @@
package gdx.diablo.map2;
import com.google.common.base.Preconditions;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntMap;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Arrays;
import gdx.diablo.Diablo;
import gdx.diablo.codec.excel.Levels;
import gdx.diablo.codec.excel.LvlPrest;
import gdx.diablo.codec.excel.LvlTypes;
public class Map {
private static final String TAG = "Map";
private static final boolean DEBUG = true;
private static final boolean DEBUG_BUILD = DEBUG && true;
public static final String TILES_PATH = "data/global/tiles/";
public static final int OUTDOOR_GRID_X = 8;
public static final int OUTDOOR_GRID_Y = 8;
private static final int DIRECTION_NORTH = 0;
private static final int DIRECTION_EAST = 1;
private static final int DIRECTION_SOUTH = 2;
private static final int DIRECTION_WEST = 3;
private static final int[] ACT_DEF = new int[]{1, 301, 529, 797, 863};
public static final int ID_MAP_ENTRY = DT1.Tile.Index.create(Orientation.SPECIAL_TILE_11, 30, 0);
public static final int ID_TOWN_ENTRY_1 = DT1.Tile.Index.create(Orientation.SPECIAL_TILE_10, 30, 0);
public static final int ID_TOWN_ENTRY_2 = DT1.Tile.Index.create(Orientation.SPECIAL_TILE_10, 31, 0);
public static final int ID_CORPSE_LOCATION = DT1.Tile.Index.create(Orientation.SPECIAL_TILE_10, 32, 0);
public static final int ID_TP_LOCATION = DT1.Tile.Index.create(Orientation.SPECIAL_TILE_10, 33, 0);
static IntMap<String> ID_TO_NAME;
static {
ID_TO_NAME = new IntMap<>();
ID_TO_NAME.put(ID_MAP_ENTRY, "ID_MAP_ENTRY");
ID_TO_NAME.put(ID_TOWN_ENTRY_1, "ID_TOWN_ENTRY_1");
ID_TO_NAME.put(ID_TOWN_ENTRY_2, "ID_TOWN_ENTRY_2");
ID_TO_NAME.put(ID_CORPSE_LOCATION, "ID_CORPSE_LOCATION");
ID_TO_NAME.put(ID_TP_LOCATION, "ID_TP_LOCATION");
}
public int width;
public int height;
public static Map build(int seed, int act, int diff) {
MathUtils.random.setSeed(seed);
Map map = new Map();
int def = ACT_DEF[act];
LvlPrest.Entry preset = Diablo.files.LvlPrest.get(def);
Levels.Entry level = Diablo.files.Levels.get(preset.LevelId);
if (DEBUG_BUILD) Gdx.app.debug(TAG, level.LevelName);
int fileId[] = new int[6];
int numFiles = getPresets(preset, fileId);
int select = MathUtils.random(numFiles - 1);
String fileName = preset.File[select];
if (DEBUG_BUILD) Gdx.app.debug(TAG, "Select " + fileName);
Zone zone = map.addZone(level, diff, preset, select);
map.width = zone.width;
map.height = zone.height;
Zone prev = zone;
level = Diablo.files.Levels.get(2);
zone = map.addZone(level, diff, 8, 8);
zone.x = prev.width - zone.width;
zone.y = -zone.height;
Preset SB = Preset.of(Diablo.files.LvlPrest.get(4), 0);
Preset EB = Preset.of(Diablo.files.LvlPrest.get(5), 0);
Preset NB = Preset.of(Diablo.files.LvlPrest.get(6), 0);
Preset WB = Preset.of(Diablo.files.LvlPrest.get(7), 0);
Preset NWB = Preset.of(Diablo.files.LvlPrest.get(9), 0);
Preset LRC = Preset.of(Diablo.files.LvlPrest.get(27), 0);
Preset UR = Preset.of(Diablo.files.LvlPrest.get(26), 3);
Preset URNB = Preset.of(Diablo.files.LvlPrest.get(26), 1);
Preset SWB = Preset.of(Diablo.files.LvlPrest.get(8), 0);
Preset LB = Preset.of(Diablo.files.LvlPrest.get(12), 0);
Preset FILL[] = Preset.of(Diablo.files.LvlPrest.get(29));
for (int x = 0; x < zone.gridsX; x++) {
for (int y = 0; y < zone.gridsY; y++) {
zone.presets[x][y] = FILL[MathUtils.random(FILL.length - 1)];
}
}
for (int y = 0; y < zone.gridsY; y++) {
zone.presets[0][y] = EB;
zone.presets[zone.gridsX - 2][y] = UR;
zone.presets[zone.gridsX - 1][y] = LRC;
}
for (int x = 1; x < zone.gridsX - 1; x++) {
zone.presets[x][0] = NB;
}
zone.presets[0][0] = NWB;
zone.presets[zone.gridsX - 2][0] = URNB;
zone.presets[zone.gridsX - 1][0] = LRC;
zone.presets[0][zone.gridsY - 1] = SWB;
zone.presets[1][zone.gridsY - 1] = SB;
zone.presets[2][zone.gridsY - 1] = SB;
zone.presets[3][zone.gridsY - 1] = LB;
zone.presets[6][zone.gridsY - 2] = Preset.of(Diablo.files.LvlPrest.get(47), 1);
return map;
}
public GridPoint2 find(int id) {
return zones.first().presets[0][0].ds1.find(id);
}
public GridPoint2 find(int orientation, int mainIndex, int subIndex) {
int id = DT1.Tile.Index.create(orientation, mainIndex, subIndex);
return find(id);
}
public String getSpecialName(int id) {
return ID_TO_NAME.get(id, "null");
}
private static int getPresets(LvlPrest.Entry preset, int[] fileIds) {
int numFiles = 0;
Arrays.fill(fileIds, -1);
for (int i = 0; i < preset.File.length; i++) {
if (preset.File[i].charAt(0) != '0') {
fileIds[numFiles++] = i;
}
}
return numFiles;
}
Array<Zone> zones = new Array<>();
public void load() {
for (Zone zone : zones) {
for (int x = 0; x < zone.gridsX; x++) {
for (int y = 0; y < zone.gridsY; y++) {
Map.Preset preset = zone.presets[x][y];
if (preset == null) continue;
Diablo.assets.load(TILES_PATH + preset.ds1Name, DS1.class);
int DT1Mask = preset.preset.Dt1Mask;
for (int i = 0; i < Integer.SIZE; i++) {
if ((DT1Mask & (1 << i)) != 0) {
String dt1 = TILES_PATH + zone.type.File[i];
Diablo.assets.load(dt1, DT1.class);
}
}
}
}
}
Diablo.assets.finishLoading();
for (Zone zone : zones) {
zone.load();
}
}
Zone addZone(Levels.Entry level, int diff, LvlPrest.Entry preset, int ds1) {
assert preset.LevelId != 0 : "presets should have an assigned level id";
Zone zone = addZone(level, diff, level.SizeX[diff], level.SizeY[diff]);
zone.presets[0][0] = Preset.of(preset, ds1);
return zone;
}
Zone addZone(Levels.Entry level, int diff, int gridSizeX, int gridSizeY) {
Zone zone = new Zone(gridSizeX, gridSizeY);
zone.level = level;
zone.type = Diablo.files.LvlTypes.get(level.LevelType);
zone.width = level.SizeX[diff];
zone.height = level.SizeY[diff];
zone.gridsX = zone.width / zone.gridSizeX;
zone.gridsY = zone.height / zone.gridSizeY;
zone.presets = new Preset[zone.gridsX][zone.gridsY];
zone.flags = new byte[zone.width * DT1.Tile.SUBTILE_SIZE][zone.height * DT1.Tile.SUBTILE_SIZE];
zones.add(zone);
return zone;
}
Zone getZone(int x, int y) {
for (Zone zone : zones) {
if (zone.contains(x, y)) {
return zone;
}
}
return null;
}
static class Zone {
int x, y;
int width, height;
int gridSizeX, gridSizeY;
int gridsX, gridsY;
Levels.Entry level;
LvlTypes.Entry type;
Preset presets[][];
Tile tiles[][][];
byte flags[][];
public Zone(int gridSizeX, int gridSizeY) {
this.gridSizeX = gridSizeX;
this.gridSizeY = gridSizeY;
}
public boolean contains(int x, int y) {
x -= this.x;
y -= this.y;
return 0 <= x && x < width
&& 0 <= y && y < height;
}
public Tile get(int layer, int x, int y) {
return tiles[layer] == null ? null : tiles[layer][x - this.x][y - this.y];
}
public int getLocalX(int x) {
return x - this.x;
}
public int getLocalY(int y) {
return y - this.y;
}
void load() {
Preconditions.checkState(tiles == null, "tiles have already been loaded");
tiles = new Tile[DS1.MAX_LAYERS][][];
for (int x = 0, gridX = 0, gridY = 0; x < gridsX; x++, gridX += gridSizeX, gridY = 0) {
for (int y = 0; y < gridsY; y++, gridY += gridSizeY) {
Preset preset = presets[x][y];
DS1 ds1 = Diablo.assets.get(TILES_PATH + preset.ds1Name);
preset.load(this, ds1, gridX, gridY);
}
}
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
if (level != null) {
builder
.append("name", level.LevelName)
.append("id", level.Id);
}
return builder
.append("x", x)
.append("y", y)
.append("width", width)
.append("height", height)
.build();
}
}
static class Tile {
DT1.Tile tile;
DS1.Cell cell;
//byte[] flags;
public static Tile of(DS1.Cell cell) {
return of(Diablo.dt1s.get(cell), cell);
}
public static Tile of(DT1.Tile tile, DS1.Cell cell) {
Tile t = new Tile();
t.tile = tile;
t.cell = cell;
//t.flags = new byte[DT1.Tile.NUM_SUBTILES];
return t;
}
}
static class Preset {
LvlPrest.Entry preset;
String ds1Name;
DS1 ds1;
public static Preset of(LvlPrest.Entry preset, int ds1) {
Preset p = new Preset();
p.preset = preset;
p.ds1Name = preset.File[ds1];
return p;
}
public static Preset of(LvlPrest.Entry preset, String ds1) {
Preset p = new Preset();
p.preset = preset;
p.ds1Name = ds1;
return p;
}
public static Preset[] of(LvlPrest.Entry preset) {
Preset[] presets = new Preset[preset.Files];
for (int i = 0; i < preset.Files; i++) {
presets[i] = Preset.of(preset, i);
}
return presets;
}
public void load(Zone zone, DS1 ds1, int x, int y) {
assert x + ds1.width <= zone.width : "x=" + x + "; ds1.width=" + ds1.width + "; zone.width=" + zone.width;
assert y + ds1.height <= zone.width : "y=" + y + "; ds1.height=" + ds1.height + "; zone.height=" + zone.height;
this.ds1 = ds1;
loadFloors(zone, DS1.FLOOR_OFFSET, x, y, ds1);
loadWalls(zone, DS1.WALL_OFFSET, x, y, ds1);
//loadLayer(zone, FLOOR_OFFSET, x, y, ds1.floors, ds1.numFloors, ds1.floorLine);
//loadLayer(zone, SHADOW_OFFSET, x, y, ds1.shadows, ds1.numShadows, ds1.shadowLine);
//loadLayer(zone, WALL_OFFSET, x, y, ds1.walls, ds1.numWalls, ds1.wallLine);
}
void loadLayer(Zone zone, int layer, int x, int y, DS1.Cell[] cells, int numLayers, int cellsLine) {
final int X_OFFS = x, Y_OFFS = y;
for (int i = 0, offsetX, offsetY; i < numLayers; i++, layer++) {
offsetX = X_OFFS;
offsetY = Y_OFFS;
if (zone.tiles[layer] == null) zone.tiles[layer] = new Tile[zone.width][zone.height];
for (y = 0; y < zone.height; y++, offsetY++, offsetX = X_OFFS) {
//int ptr = i + (y * cellsLine);
for (x = 0; x < zone.width; x++, offsetX++/*, ptr += numLayers*/) {
int ptr = (y * cellsLine) + (x * numLayers);
DS1.Cell cell = cells[ptr];
zone.tiles[layer][offsetX][offsetY] = Tile.of(cell);
}
}
}
}
void loadFloors(Zone zone, int layer, int x, int y, DS1 ds1) {
final int X_OFFS = x, Y_OFFS = y;
for (int i = 0, offsetX, offsetY; i < ds1.numFloors; i++, layer++) {
offsetX = X_OFFS;
offsetY = Y_OFFS;
if (zone.tiles[layer] == null) zone.tiles[layer] = new Tile[zone.width][zone.height];
for (y = 0; y < ds1.height; y++, offsetY++, offsetX = X_OFFS) {
for (x = 0; x < ds1.width; x++, offsetX++) {
int ptr = i + (y * ds1.floorLine) + (x * ds1.numFloors);
DS1.Cell cell = ds1.floors[ptr];
if ((cell.value & 0x00020000) != 0) {
int offsetX2 = offsetX * DT1.Tile.SUBTILE_SIZE;
int offsetY2 = offsetY * DT1.Tile.SUBTILE_SIZE;
for (int y2 = 0; y2 < DT1.Tile.SUBTILE_SIZE; y2++) {
for (int x2 = 0; x2 < DT1.Tile.SUBTILE_SIZE; x2++) {
zone.flags[offsetX2 + x2][offsetY2 + y2] |= 1;
}
}
}
if (ds1.numFloors == 1) {
if ((ds1.floors[0].value & 0xFF) == 0) {
int offsetX2 = offsetX * DT1.Tile.SUBTILE_SIZE;
int offsetY2 = offsetY * DT1.Tile.SUBTILE_SIZE;
for (int y2 = 0; y2 < DT1.Tile.SUBTILE_SIZE; y2++) {
for (int x2 = 0; x2 < DT1.Tile.SUBTILE_SIZE; x2++) {
zone.flags[offsetX2 + x2][offsetY2 + y2] |= 1;
}
}
}
} else if (ds1.numFloors == 2) {
if ((ds1.floors[0].value & 0xFF) == 0 && (ds1.floors[1].value & 0xFF) == 0) {
int offsetX2 = offsetX * DT1.Tile.SUBTILE_SIZE;
int offsetY2 = offsetY * DT1.Tile.SUBTILE_SIZE;
for (int y2 = 0; y2 < DT1.Tile.SUBTILE_SIZE; y2++) {
for (int x2 = 0; x2 < DT1.Tile.SUBTILE_SIZE; x2++) {
zone.flags[offsetX2 + x2][offsetY2 + y2] |= 1;
}
}
}
}
if ((cell.value & 0x80000000) != 0) {
continue;
}
Tile tile = zone.tiles[layer][offsetX][offsetY] = Tile.of(cell);
copyFlags(zone.flags, offsetX, offsetY, tile.tile);
}
}
}
}
void loadWalls(Zone zone, int layer, int x, int y, DS1 ds1) {
final int X_OFFS = x, Y_OFFS = y;
for (int i = 0, offsetX, offsetY; i < ds1.numWalls; i++, layer++) {
offsetX = X_OFFS;
offsetY = Y_OFFS;
if (zone.tiles[layer] == null) zone.tiles[layer] = new Tile[zone.width][zone.height];
for (y = 0; y < ds1.height; y++, offsetY++, offsetX = X_OFFS) {
for (x = 0; x < ds1.width; x++, offsetX++) {
int ptr = i + (y * ds1.wallLine) + (x * ds1.numWalls);
DS1.Cell cell = ds1.walls[ptr];
if ((cell.value & DS1.Cell.MASK_UNWALKABLE) != 0) {
int offsetX2 = offsetX * DT1.Tile.SUBTILE_SIZE;
int offsetY2 = offsetY * DT1.Tile.SUBTILE_SIZE;
for (int y2 = 0; y2 < DT1.Tile.SUBTILE_SIZE; y2++) {
for (int x2 = 0; x2 < DT1.Tile.SUBTILE_SIZE; x2++) {
zone.flags[offsetX2 + x2][offsetY2 + y2] |= 1;
}
}
}
if ((cell.value & 0x80000000) != 0) {
// This seems like all the special tiles, null usually means marker tile (start pos),
// non null usually means stuff like side of river, used for ?weather? ?rain drops?
if (!Orientation.isSpecial(cell.orientation)) {
//DT1.Tile tile = Diablo.dt1s.get(cell);
//System.out.println(x + ", " + y + " " + tile);
continue;
}
zone.tiles[layer][offsetX][offsetY] = Tile.of(cell);
continue;
}
if (cell.orientation == Orientation.FLOOR) {
continue;
}
Tile tile = zone.tiles[layer][offsetX][offsetY] = Tile.of(cell);
copyFlags(zone.flags, offsetX, offsetY, tile.tile);
// Special case, because LEFT_NORTH_CORNER_WALL don't seem to exist, but they contain
// collision data for RIGHT_NORTH_CORNER_WALL, ORing the data just in case some
// RIGHT_NORTH_CORNER_WALL actually does anything
if (cell.orientation == Orientation.RIGHT_NORTH_CORNER_WALL) {
DT1.Tile leftSide = Diablo.dt1s.get(Orientation.LEFT_NORTH_CORNER_WALL, cell.mainIndex, cell.subIndex);
copyFlags(zone.flags, offsetX, offsetY, leftSide);
}
}
}
}
}
static void copyFlags(byte[][] flags, int tx, int ty, DT1.Tile tile) {
int offsetX = tx * DT1.Tile.SUBTILE_SIZE;
int offsetY = ty * DT1.Tile.SUBTILE_SIZE;
// Note: walkable flags are stored inverted y-axis, this corrects it
for (int y = DT1.Tile.SUBTILE_SIZE - 1, t = 0; y >= 0; y--) {
for (int x = 0; x < DT1.Tile.SUBTILE_SIZE; x++, t++) {
flags[offsetX + x][offsetY + y] |= tile.tileFlags[t];
}
}
}
}
}

View File

@ -1,588 +0,0 @@
package gdx.diablo.map2;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Rectangle;
import java.util.Arrays;
import gdx.diablo.Diablo;
import gdx.diablo.codec.FontTBL;
import gdx.diablo.graphics.PaletteIndexedBatch;
public class MapRenderer {
private static final String TAG = "MapRenderer";
private static final boolean DEBUG = true;
private static final boolean DEBUG_MATH = DEBUG && !true;
private static final boolean DEBUG_BUFFER = DEBUG && true;
private static final boolean DEBUG_SUBTILE = DEBUG && true;
private static final boolean DEBUG_TILE = DEBUG && true;
private static final boolean DEBUG_CAMERA = DEBUG && true;
private static final boolean DEBUG_OVERSCAN = DEBUG && true;
private static final boolean DEBUG_GRID = DEBUG && true;
private static final boolean DEBUG_WALKABLE = DEBUG && !true;
private static final boolean DEBUG_SPECIAL = DEBUG && true;
public static boolean RENDER_DEBUG_SUBTILE = DEBUG_SUBTILE;
public static boolean RENDER_DEBUG_TILE = DEBUG_TILE;
public static boolean RENDER_DEBUG_CAMERA = DEBUG_CAMERA;
public static boolean RENDER_DEBUG_OVERSCAN = DEBUG_OVERSCAN;
public static int RENDER_DEBUG_GRID = DEBUG_GRID ? 3 : 0;
public static int RENDER_DEBUG_WALKABLE = DEBUG_WALKABLE ? DS1.MAX_LAYERS + 1 : 0;
public static boolean RENDER_DEBUG_SPECIAL = DEBUG_SPECIAL;
private static final Color RENDER_DEBUG_GRID_COLOR_1 = new Color(0x3f3f3f3f);
private static final Color RENDER_DEBUG_GRID_COLOR_2 = new Color(0x7f7f7f3f);
private static final Color RENDER_DEBUG_GRID_COLOR_3 = new Color(0x0000ff3f);
public static int DEBUG_GRID_MODES = 3;
PaletteIndexedBatch batch;
OrthographicCamera camera;
Map map;
Rectangle viewBounds;
int[] viewBuffer;
float factor = -1.0f;
final int tileWidth = DT1.Tile.WIDTH;
final int tileHeight = DT1.Tile.HEIGHT;
final int halfTileWidth = tileWidth >>> 1;
final int halfTileHeight = tileHeight >>> 1;
final int subTileWidth = DT1.Tile.SUBTILE_WIDTH;
final int subTileHeight = DT1.Tile.SUBTILE_HEIGHT;
final int halfSubTileWidth = subTileWidth >>> 1;
final int halfSubTileHeight = subTileHeight >>> 1;
// subtile index in world-space
int x, y;
// subtile index in tile-space
int stx, sty;
// subtile index in tile-space 1D
int t;
// pixel offset of subtile in world-space
int spx, spy;
// tile index in world-space
int tx, ty;
// pixel offset of tile in world-space
int tpx, tpy;
int width, height;
int tilesX, tilesY;
int renderWidth, renderHeight;
// tile index of top right tile in render area
int startX, startY;
// tpx and tpy of startX, startY tile in world-space
int startPx, startPy;
private static final Color SHADOW_TINT = new Color(0, 0, 0, 0.5f);
public MapRenderer(PaletteIndexedBatch batch, OrthographicCamera camera) {
this.batch = batch;
this.camera = camera;
viewBounds = new Rectangle();
}
public void setMap(Map map) {
if (this.map != map) {
this.map = map;
}
}
public void update() {
float width = camera.viewportWidth * camera.zoom;
float height = camera.viewportHeight * camera.zoom;
float w = width * Math.abs(camera.up.y) + height * Math.abs(camera.up.x);
float h = height * Math.abs(camera.up.y) + width * Math.abs(camera.up.x);
float x = camera.position.x - w / 2;
float y = camera.position.y - h / 2;
viewBounds.set(x, y, width, height);
}
public void setFactor(float factor) {
if (this.factor != factor) {
this.factor = factor;
updateViewBuffer();
}
}
private void updateViewBuffer() {
/*
int width = (int) viewBounds.width;
int height = (int) viewBounds.height;
if (factor == 0) {
// FIXME: This isn't correct, but should be sufficiently large enough
width = 8 * width;
height = 8 * height;
} else {
width *= factor;
height *= factor;
}
*/
updateBounds();
// This will generate an array s.t. each cell is the length of tiles to render
final int viewBufferLen = tilesX + tilesY - 1;
final int viewBufferMax = tilesX * 2 - 1;
viewBuffer = new int[viewBufferLen];
int x, y;
for (x = 0, y = 1; y < viewBufferMax; x++, y += 2)
viewBuffer[x] = viewBuffer[viewBufferLen - 1 - x] = y;
while (viewBuffer[x] == 0)
viewBuffer[x++] = viewBufferMax;
if (DEBUG_BUFFER) Gdx.app.debug(TAG, "viewBuffer=" + Arrays.toString(viewBuffer));
}
public void setPosition(int x, int y) {
if (this.x != x || this.y != y) {
this.x = x;
this.y = y;
final int halfSubTileWidth = DT1.Tile.SUBTILE_WIDTH >>> 1;
final int halfSubTileHeight = DT1.Tile.SUBTILE_HEIGHT >>> 1;
int spx = (x * halfSubTileWidth) - (y * halfSubTileWidth);
int spy = -(x * halfSubTileHeight) - (y * halfSubTileHeight);
camera.position.set(spx, spy, 0);
runMath(x, y);
}
}
public void runMath(int x, int y) {
camera.update();
// subtile index in tile-space
stx = x < 0
? (x + 1) % DT1.Tile.SUBTILE_SIZE + (DT1.Tile.SUBTILE_SIZE - 1)
: x % DT1.Tile.SUBTILE_SIZE;
sty = y < 0
? (y + 1) % DT1.Tile.SUBTILE_SIZE + (DT1.Tile.SUBTILE_SIZE - 1)
: y % DT1.Tile.SUBTILE_SIZE;
t = DT1.Tile.SUBTILE_INDEX[stx][sty];
// pixel offset of subtile in world-space
spx = -halfSubTileWidth + (x * halfSubTileWidth) - (y * halfSubTileWidth);
spy = -halfSubTileHeight - (x * halfSubTileHeight) - (y * halfSubTileHeight);
// tile index in world-space
tx = x < 0
? ((x + 1) / DT1.Tile.SUBTILE_SIZE) - 1
: (x / DT1.Tile.SUBTILE_SIZE);
ty = y < 0
? ((y + 1) / DT1.Tile.SUBTILE_SIZE) - 1
: (y / DT1.Tile.SUBTILE_SIZE);
tpx = spx - DT1.Tile.SUBTILE_OFFSET[t][0];
tpy = spy - DT1.Tile.SUBTILE_OFFSET[t][1];
updateBounds();
final int offX = tilesX >>> 1;
final int offY = tilesY >>> 1;
startX = tx + offX - offY;
startY = ty - offX - offY;
startPx = tpx + renderWidth / 2 - halfTileWidth;
startPy = tpy + renderHeight / 2 - halfTileHeight;
if (DEBUG_MATH) {
Gdx.app.debug(TAG, String.format("(%2d,%2d){%d,%d}[%2d,%2d](%dx%d)[%dx%d] %d,%d%n",
x, y, stx, sty, tx, ty, width, height, tilesX, tilesY, spx, spy));
}
}
private void updateBounds() {
width = (int) camera.viewportWidth;
height = (int) camera.viewportHeight;
int minTilesX = ((width + tileWidth - 1) / tileWidth);
int minTilesY = ((height + tileHeight - 1) / tileHeight);
if ((minTilesX & 1) == 1) minTilesX++;
if ((minTilesY & 1) == 1) minTilesY++;
tilesX = minTilesX + 3; // pad width comfortably
tilesY = minTilesY + 7; // pad height for lower walls / upper walls
renderWidth = tilesX * tileWidth;
renderHeight = tilesY * tileHeight;
assert (tilesX & 1) == 1 && (tilesY & 1) == 1;
}
// TODO: render will overscan image in y-axis to accommodate walls, should change to wall only instead of entire frame
public void render(PaletteIndexedBatch batch) {
for (int i = 0, x, y; i < DS1.MAX_LAYERS; i++) {
int startX2 = startX;
int startY2 = startY;
int startPx2 = startPx;
int startPy2 = startPy;
for (y = 0; y < viewBuffer.length; y++) {
int dx = startX2;
int dy = startY2;
int px = startPx2;
int py = startPy2;
int size = viewBuffer[y];
for (x = 0; x < size; x++) {
Map.Zone zone = map.getZone(dx, dy);
if (zone != null) {
//Map.Tile[][] tiles = zone.tiles[i];
//if (tiles != null) {
Map.Tile tile = zone.get(i, dx, dy);
switch (i) {
case 0:
case 1:
//drawWalls(batch, tile, px, py, false);
drawFloors(batch, tile, px, py);
//batch.setBlendMode(BlendMode.SHADOW, SHADOW_TINT);
//drawShadows(batch, dx, dy, px, py);
//batch.resetBlendMode();
break;
case 2:
break;
case 3: case 4: case 5: case 6:
drawWalls(batch, tile, px, py, true);
break;
default:
//...
}
//}
}
dx++;
px += halfTileWidth;
py -= halfTileHeight;
}
startY2++;
if (y >= tilesX - 1) {
startX2++;
startPy2 -= tileHeight;
} else {
startX2--;
startPx2 -= tileWidth;
}
}
}
}
public void renderDebug(ShapeRenderer shapes) {
if (RENDER_DEBUG_GRID > 0)
renderDebugGrid(shapes);
if (RENDER_DEBUG_WALKABLE > 0)
renderDebugWalkable(shapes);
if (RENDER_DEBUG_TILE) {
shapes.setColor(Color.OLIVE);
drawDiamond(shapes, tpx, tpy, DT1.Tile.WIDTH, DT1.Tile.HEIGHT);
}
if (RENDER_DEBUG_SUBTILE) {
shapes.setColor(Color.WHITE);
drawDiamond(shapes, spx, spy, DT1.Tile.SUBTILE_WIDTH, DT1.Tile.SUBTILE_HEIGHT);
}
if (RENDER_DEBUG_CAMERA) {
shapes.setColor(Color.GREEN);
shapes.rect(
camera.position.x - camera.viewportWidth / 2,
camera.position.y - camera.viewportHeight / 2,
camera.viewportWidth + 1, camera.viewportHeight + 1);
}
if (RENDER_DEBUG_OVERSCAN) {
shapes.setColor(Color.GRAY);
shapes.rect(
tpx - renderWidth / 2 + halfTileWidth,
tpy - renderHeight / 2 + halfTileHeight,
renderWidth, renderHeight);
}
}
public void renderDebugWalkable(ShapeRenderer shapes) {
//if (RENDER_DEBUG_WALKABLE == DS1.MAX_LAYERS + 1) {
// return;
//}
final int[] WALKABLE_ID = {
20, 21, 22, 23, 24,
15, 16, 17, 18, 19,
10, 11, 12, 13, 14,
5, 6, 7, 8, 9,
0, 1, 2, 3, 4
};
ShapeRenderer.ShapeType shapeType = shapes.getCurrentType();
shapes.set(ShapeRenderer.ShapeType.Filled);
int startX2 = startX;
int startY2 = startY;
int startPx2 = startPx;
int startPy2 = startPy;
int x, y;
for (y = 0; y < viewBuffer.length; y++) {
int dx = startX2;
int dy = startY2;
int px = startPx2;
int py = startPy2;
int size = viewBuffer[y];
for (x = 0; x < size; x++) {
Map.Zone zone = map.getZone(dx, dy);
if (zone != null) {
if (RENDER_DEBUG_WALKABLE == DS1.MAX_LAYERS + 1) {
for (int sty = 0, t = 0; sty < DT1.Tile.SUBTILE_SIZE; sty++) {
for (int stx = 0; stx < DT1.Tile.SUBTILE_SIZE; stx++, t++) {
int flags = zone.flags[zone.getLocalX(dx) * DT1.Tile.SUBTILE_SIZE + stx][zone.getLocalY(dy) * DT1.Tile.SUBTILE_SIZE + sty] & 0xFF;
if (flags == 0) continue;
renderDebugWalkableTiles(shapes, px, py, t, flags);
}
}
} else {
//Map.Tile[][] tiles = zone.tiles[RENDER_DEBUG_WALKABLE - 1];
//if (tiles != null) {
Map.Tile tile = zone.get(RENDER_DEBUG_WALKABLE - 1, dx, dy);
for (int t = 0; tile != null && tile.tile != null && t < DT1.Tile.NUM_SUBTILES; t++) {
int flags = tile.tile.tileFlags[WALKABLE_ID[t]] & 0xFF;
if (flags == 0) continue;
renderDebugWalkableTiles(shapes, px, py, t, flags);
}
//}
}
}
dx++;
px += halfTileWidth;
py -= halfTileHeight;
}
startY2++;
if (y >= tilesX - 1) {
startX2++;
startPy2 -= tileHeight;
} else {
startX2--;
startPx2 -= tileWidth;
}
}
shapes.set(shapeType);
}
private void renderDebugWalkableTiles(ShapeRenderer shapes, int px, int py, int t, int flags) {
int offX = px + DT1.Tile.SUBTILE_OFFSET[t][0];
int offY = py + DT1.Tile.SUBTILE_OFFSET[t][1];
shapes.setColor(Color.CORAL);
drawDiamond(shapes, offX, offY, DT1.Tile.SUBTILE_WIDTH, DT1.Tile.SUBTILE_HEIGHT);
offY += halfSubTileHeight;
if ((flags & DT1.Tile.FLAG_BLOCK_WALK) != 0) {
shapes.setColor(Color.FIREBRICK);
shapes.triangle(
offX + 16, offY,
offX + 16, offY + 8,
offX + 24, offY + 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_LIGHT_LOS) != 0) {
shapes.setColor(Color.FOREST);
shapes.triangle(
offX + 16, offY,
offX + 32, offY,
offX + 24, offY + 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_JUMP) != 0) {
shapes.setColor(Color.ROYAL);
shapes.triangle(
offX + 16, offY,
offX + 32, offY,
offX + 24, offY - 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_PLAYER_WALK) != 0) {
shapes.setColor(Color.VIOLET);
shapes.triangle(
offX + 16, offY,
offX + 16, offY - 8,
offX + 24, offY - 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_UNKNOWN1) != 0) {
shapes.setColor(Color.GOLD);
shapes.triangle(
offX + 16, offY,
offX + 16, offY - 8,
offX + 8, offY - 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_LIGHT) != 0) {
shapes.setColor(Color.SKY);
shapes.triangle(
offX, offY,
offX + 16, offY,
offX + 8, offY - 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_UNKNOWN2) != 0) {
shapes.setColor(Color.WHITE);
shapes.triangle(
offX, offY,
offX + 16, offY,
offX + 8, offY + 4);
}
if ((flags & DT1.Tile.FLAG_BLOCK_UNKNOWN3) != 0) {
shapes.setColor(Color.SLATE);
shapes.triangle(
offX + 16, offY,
offX + 16, offY + 8,
offX + 8, offY + 4);
}
}
public void renderDebugGrid(ShapeRenderer shapes) {
int x, y;
switch (RENDER_DEBUG_GRID) {
case 1:
shapes.setColor(RENDER_DEBUG_GRID_COLOR_1);
int startPx2 = startPx;
int startPy2 = startPy;
for (y = 0; y < viewBuffer.length; y++) {
int px = startPx2;
int py = startPy2;
int size = viewBuffer[y];
for (x = 0; x < size; x++) {
for (int t = 0; t < DT1.Tile.NUM_SUBTILES; t++) {
drawDiamond(shapes,
px + DT1.Tile.SUBTILE_OFFSET[t][0], py + DT1.Tile.SUBTILE_OFFSET[t][1],
DT1.Tile.SUBTILE_WIDTH, DT1.Tile.SUBTILE_HEIGHT);
}
px += halfTileWidth;
py -= halfTileHeight;
}
if (y >= tilesX - 1) {
startPy2 -= tileHeight;
} else {
startPx2 -= tileWidth;
}
}
case 2:
shapes.setColor(RENDER_DEBUG_GRID_COLOR_2);
startPx2 = startPx;
startPy2 = startPy;
for (y = 0; y < viewBuffer.length; y++) {
int px = startPx2;
int py = startPy2;
int size = viewBuffer[y];
for (x = 0; x < size; x++) {
drawDiamond(shapes, px, py, DT1.Tile.WIDTH, DT1.Tile.HEIGHT);
px += halfTileWidth;
py -= halfTileHeight;
}
if (y >= tilesX - 1) {
startPy2 -= tileHeight;
} else {
startPx2 -= tileWidth;
}
}
case 3:
shapes.setColor(RENDER_DEBUG_GRID_COLOR_3);
ShapeRenderer.ShapeType shapeType = shapes.getCurrentType();
shapes.set(ShapeRenderer.ShapeType.Filled);
final int LINE_WIDTH = 2;
int startX2 = startX;
int startY2 = startY;
startPx2 = startPx;
startPy2 = startPy;
for (y = 0; y < viewBuffer.length; y++) {
int dx = startX2;
int dy = startY2;
int px = startPx2;
int py = startPy2;
int size = viewBuffer[y];
for (x = 0; x < size; x++) {
Map.Zone zone = map.getZone(dx, dy);
if (zone != null) {
int mod = dx < 0
? (dx + 1) % zone.gridSizeX + (zone.gridSizeX - 1)
: dx % zone.gridSizeX;
if (mod == 0)
shapes.rectLine(px, py + halfTileHeight, px + halfTileWidth, py + tileHeight, LINE_WIDTH);
else if (mod == zone.gridSizeX - 1)
shapes.rectLine(px + tileWidth, py + halfTileHeight, px + halfTileWidth, py, LINE_WIDTH);
mod = dy < 0
? (dy + 1) % zone.gridSizeY + (zone.gridSizeY - 1)
: dy % zone.gridSizeY;
if (mod == 0)
shapes.rectLine(px + halfTileWidth, py + tileHeight, px + tileWidth, py + halfTileHeight, LINE_WIDTH);
else if (mod == zone.gridSizeY - 1)
shapes.rectLine(px + halfTileWidth, py, px, py + halfTileHeight, LINE_WIDTH);
}
dx++;
px += halfTileWidth;
py -= halfTileHeight;
}
startY2++;
if (y >= tilesX - 1) {
startX2++;
startPy2 -= tileHeight;
} else {
startX2--;
startPx2 -= tileWidth;
}
}
shapes.set(shapeType);
default:
}
}
private static void drawDiamond(ShapeRenderer shapes, float x, float y, int width, int height) {
int hw = width >>> 1;
int hh = height >>> 1;
shapes.line(x , y + hh , x + hw , y + height);
shapes.line(x + hw , y + height, x + width, y + hh );
shapes.line(x + width, y + hh , x + hw , y );
shapes.line(x + hw , y , x , y + hh );
}
private void drawFloors(PaletteIndexedBatch batch, Map.Tile tile, int px, int py) {
if (tile == null) {
return;
}
batch.draw(tile.tile.texture, px, py, tile.tile.texture.getWidth() + 1, tile.tile.texture.getHeight() + 1);
}
private void drawWalls(PaletteIndexedBatch batch, Map.Tile tile, int px, int py, boolean upper) {
if (tile == null) {
return;
}
//RENDER_DEBUG_SPECIAL
if (Orientation.isSpecial(tile.cell.orientation)) {
if (!RENDER_DEBUG_SPECIAL) return;
FontTBL.BitmapFont font = Diablo.fonts.font16;
GlyphLayout layout = new GlyphLayout(font, map.getSpecialName(tile.cell.id));
font.draw(batch, layout,
px + DT1.Tile.WIDTH / 2 - layout.width / 2,
py + DT1.Tile.HEIGHT / 2 - layout.height / 2);
return;
}
if (tile.tile.orientation < Orientation.LEFT_WALL) {
return;
}
batch.draw(tile.tile.texture, px, tile.tile.orientation == Orientation.ROOF ? py + tile.tile.roofHeight : py);
if (tile.tile.orientation == Orientation.RIGHT_NORTH_CORNER_WALL) {
DT1.Tile sister = Diablo.dt1s.get(Orientation.LEFT_NORTH_CORNER_WALL, tile.tile.mainIndex, tile.tile.subIndex);
batch.draw(sister.texture, px, py);
}
}
}

View File

@ -1,20 +0,0 @@
package gdx.diablo.map2;
import com.badlogic.gdx.utils.async.AsyncTask;
public class MapZoneLoader implements AsyncTask<Void> {
private static final String TAG = "MapZoneLoader";
private static final boolean DEBUG = true;
Map map;
public MapZoneLoader(Map map) {
this.map = map;
}
@Override
public Void call() {
return null;
}
}

View File

@ -1,109 +0,0 @@
package gdx.diablo.map2;
public class Orientation {
/** Floors */
public static final int FLOOR = 0;
/** Left Wall */
public static final int LEFT_WALL = 1;
/** Right Wall */
public static final int RIGHT_WALL = 2;
/** Right part of north corner wall */
public static final int RIGHT_NORTH_CORNER_WALL = 3;
/** Left part of north corner wall */
public static final int LEFT_NORTH_CORNER_WALL = 4;
/** Left end wall */
public static final int LEFT_END_WALL = 5;
/** Right end wall */
public static final int RIGHT_END_WALL = 6;
/** South corner wall */
public static final int SOUTH_CORNER_WALL = 7;
/** Left wall with door */
public static final int LEFT_WALL_DOOR = 8;
/** Right wall with door */
public static final int RIGHT_WALL_DOOR = 9;
/** Special Cell */
public static final int SPECIAL_TILE_10 = 10;
/** Special Cell */
public static final int SPECIAL_TILE_11 = 11;
/** Pillars, columns and standalone objects */
public static final int PILLAR = 12;
/** Shadows */
public static final int SHADOW = 13;
/** Trees */
public static final int TREE = 14;
/** Roofs */
public static final int ROOF = 15;
/** Lower walls equivalent to Orientation 1
* @see #LEFT_WALL */
public static final int LOWER_LEFT_WALL = 16;
/** Lower walls equivalent to Orientation 2
* @see #RIGHT_WALL */
public static final int LOWER_RIGHT_WALL = 17;
/** Lower walls equivalent to Orientation 3 and 4
* @see #RIGHT_NORTH_CORNER_WALL
* @see #LEFT_NORTH_CORNER_WALL */
public static final int LOWER_NORTH_CORNER_WALL = 18;
/** Lower walls equivalent to Orientation 7
* @see #SOUTH_CORNER_WALL */
public static final int LOWER_SOUTH_CORNER_WALL = 19;
public static String toString(int orientation) {
switch (orientation) {
case FLOOR: return "FLOOR";
case LEFT_WALL: return "LEFT_WALL";
case RIGHT_WALL: return "RIGHT_WALL";
case RIGHT_NORTH_CORNER_WALL: return "RIGHT_NORTH_CORNER_WALL";
case LEFT_NORTH_CORNER_WALL: return "LEFT_NORTH_CORNER_WALL";
case LEFT_END_WALL: return "LEFT_END_WALL";
case RIGHT_END_WALL: return "RIGHT_END_WALL";
case SOUTH_CORNER_WALL: return "SOUTH_CORNER_WALL";
case LEFT_WALL_DOOR: return "LEFT_WALL_DOOR";
case RIGHT_WALL_DOOR: return "RIGHT_WALL_DOOR";
case SPECIAL_TILE_10: return "SPECIAL_TILE_10";
case SPECIAL_TILE_11: return "SPECIAL_TILE_11";
case PILLAR: return "PILLAR";
case SHADOW: return "SHADOW";
case TREE: return "TREE";
case ROOF: return "ROOF";
case LOWER_LEFT_WALL: return "LOWER_LEFT_WALL";
case LOWER_RIGHT_WALL: return "LOWER_RIGHT_WALL";
case LOWER_NORTH_CORNER_WALL: return "LOWER_NORTH_CORNER_WALL";
case LOWER_SOUTH_CORNER_WALL: return "LOWER_SOUTH_CORNER_WALL";
default: return "null";
}
}
public static int toDirection(int orientation) {
switch (orientation) {
case LEFT_WALL: case LEFT_END_WALL: case LEFT_WALL_DOOR:
return 1;
case RIGHT_WALL: case RIGHT_END_WALL: case RIGHT_WALL_DOOR:
return 2;
case FLOOR: case RIGHT_NORTH_CORNER_WALL: case LEFT_NORTH_CORNER_WALL: case PILLAR: case TREE:
return 3;
case SOUTH_CORNER_WALL:
return 4;
case ROOF:
return 5;
case LOWER_LEFT_WALL:
return 6;
case LOWER_RIGHT_WALL:
return 7;
case LOWER_NORTH_CORNER_WALL:
return 8;
case LOWER_SOUTH_CORNER_WALL:
return 9;
default: throw new AssertionError();
}
}
public static boolean isSpecial(int orientation) {
switch (orientation) {
case SPECIAL_TILE_10:
case SPECIAL_TILE_11:
return true;
default:
return false;
}
}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.net;
public class Codec {
private Codec() {}
}

View File

@ -0,0 +1,9 @@
package gdx.diablo.net;
import java.io.DataInputStream;
public class ConnectPacket {
ConnectPacket(DataInputStream in) {
}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.net;
public class Packet {
private Packet() {}
}

View File

@ -0,0 +1,7 @@
package gdx.diablo.net;
public class UploadD2SPacket {
private UploadD2SPacket() {}
}

View File

@ -0,0 +1,34 @@
package gdx.diablo.net.d2gs;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
import java.io.IOException;
import gdx.diablo.net.Codec;
public class WalkToLocationPacket extends Codec {
static final int SIZE = 4;
public int x;
public int y;
WalkToLocationPacket() {}
@Override
public void encode(LittleEndianDataOutputStream out) throws IOException {
out.writeShort(x);
out.writeShort(y);
}
@Override
public void decode(LittleEndianDataInputStream in) throws IOException {
x = in.readUnsignedShort();
y = in.readUnsignedShort();
}
@Override
public String toString() {
return x + ", " + y;
}
}

View File

@ -0,0 +1,34 @@
package gdx.diablo.net.d2gs;
import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
import java.io.IOException;
import gdx.diablo.net.Codec;
public class MoveToLocationPacket extends Codec {
static final int SIZE = 4;
public int x;
public int y;
MoveToLocationPacket() {}
@Override
public void encode(LittleEndianDataOutputStream out) throws IOException {
out.writeShort(x);
out.writeShort(y);
}
@Override
public void decode(LittleEndianDataInputStream in) throws IOException {
x = in.readUnsignedShort();
y = in.readUnsignedShort();
}
@Override
public String toString() {
return x + ", " + y;
}
}

View File

@ -0,0 +1,13 @@
package gdx.diablo.screen;
import com.badlogic.gdx.ScreenAdapter;
import gdx.diablo.entity3.Player;
public abstract class CharacterScreenAdapter extends ScreenAdapter {
public CharacterScreenAdapter(Player player) {
}
}

View File

@ -0,0 +1,5 @@
import static org.junit.Assert.*;
public class GameLogonPacketTest {
}

View File

@ -0,0 +1,49 @@
package gdx.diablo.net.d2gs;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import gdx.diablo.util.DebugUtils;
public class WalkToLocationPacketTest {
private static final int X = 0xFF;
private static final int Y = 0xFFFF;
private static final byte[] BYTES = new byte[]{(byte) 0xFF, 0x00, (byte) 0xFF, (byte) 0xFF};
@Test
public void encode() {
WalkToLocationPacket packet = new WalkToLocationPacket() {{
x = X;
y = Y;
}};
ByteArrayOutputStream out = new ByteArrayOutputStream(WalkToLocationPacket.SIZE);
try {
packet.encode(out);
} catch (Throwable t) {
System.err.println(t.getMessage());
}
byte[] bytes = out.toByteArray();
System.out.println(packet + " -> " + DebugUtils.toByteArray(bytes));
Assert.assertArrayEquals(BYTES, bytes);
}
@Test
public void decode() {
WalkToLocationPacket packet = new WalkToLocationPacket();
try {
ByteArrayInputStream in = new ByteArrayInputStream(BYTES);
packet.decode(in);
} catch (Throwable t) {
System.out.println(t.getMessage());
}
System.out.println(DebugUtils.toByteArray(BYTES) + " -> " + packet);
Assert.assertEquals(X, packet.x);
Assert.assertEquals(Y, packet.y);
}
}

View File

@ -0,0 +1,46 @@
package gdx.diablo.net.d2gs;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import gdx.diablo.util.DebugUtils;
public class MoveToLocationPacketTest {
@Test
public void encode() {
MoveToLocationPacket packet = new MoveToLocationPacket() {{
x = 31;
y = 63;
}};
ByteArrayOutputStream out = new ByteArrayOutputStream(MoveToLocationPacket.SIZE);
try {
packet.encode(out);
} catch (Throwable t) {
System.err.println(t.getMessage());
}
byte[] bytes = out.toByteArray();
System.out.println(DebugUtils.toByteArray(bytes));
Assert.assertArrayEquals(new byte[]{0x1F, 0x00, 0x3F, 0x00}, bytes);
}
@Test
public void decode() {
MoveToLocationPacket packet = new MoveToLocationPacket();
try {
ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0x1F, 0x00, 0x3F, 0x00});
packet.decode(in);
} catch (Throwable t) {
System.out.println(t.getMessage());
}
System.out.println(packet);
Assert.assertEquals(31, packet.x);
Assert.assertEquals(63, packet.y);
}
}