From 3317794cb539413a0cde1333135b2e7f42952480 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Tue, 12 Nov 2019 19:40:22 -0800 Subject: [PATCH] Added PlayerSystem and Map.Zone tracking Created ZoneAwareComponent and ZoneUpdate tags Added factory method to create players within Engine --- core/src/com/riiablo/engine/Engine.java | 80 +++++++ .../engine/component/ZoneAwareComponent.java | 8 + .../riiablo/engine/component/ZoneUpdate.java | 8 + .../riiablo/engine/system/PlayerSystem.java | 217 ++++++++++++++++++ .../com/riiablo/engine/system/ZoneSystem.java | 33 +++ .../engine/system/ZoneUpdateSystem.java | 42 ++++ 6 files changed, 388 insertions(+) create mode 100644 core/src/com/riiablo/engine/component/ZoneAwareComponent.java create mode 100644 core/src/com/riiablo/engine/component/ZoneUpdate.java create mode 100644 core/src/com/riiablo/engine/system/PlayerSystem.java create mode 100644 core/src/com/riiablo/engine/system/ZoneSystem.java create mode 100644 core/src/com/riiablo/engine/system/ZoneUpdateSystem.java diff --git a/core/src/com/riiablo/engine/Engine.java b/core/src/com/riiablo/engine/Engine.java index 083196af..8d769316 100644 --- a/core/src/com/riiablo/engine/Engine.java +++ b/core/src/com/riiablo/engine/Engine.java @@ -8,6 +8,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.IntIntMap; +import com.riiablo.CharData; import com.riiablo.Riiablo; import com.riiablo.codec.COF; import com.riiablo.codec.excel.Levels; @@ -16,6 +17,7 @@ import com.riiablo.codec.excel.MonStats; import com.riiablo.codec.excel.MonStats2; import com.riiablo.codec.excel.Objects; import com.riiablo.codec.util.BBox; +import com.riiablo.engine.component.AngleComponent; import com.riiablo.engine.component.AnimationComponent; import com.riiablo.engine.component.BBoxComponent; import com.riiablo.engine.component.ClassnameComponent; @@ -25,11 +27,15 @@ import com.riiablo.engine.component.IdComponent; import com.riiablo.engine.component.LabelComponent; import com.riiablo.engine.component.MapComponent; import com.riiablo.engine.component.MonsterComponent; +import com.riiablo.engine.component.MovementModeComponent; import com.riiablo.engine.component.ObjectComponent; import com.riiablo.engine.component.PathComponent; +import com.riiablo.engine.component.PlayerComponent; import com.riiablo.engine.component.PositionComponent; import com.riiablo.engine.component.TypeComponent; +import com.riiablo.engine.component.VelocityComponent; import com.riiablo.engine.component.WarpComponent; +import com.riiablo.engine.component.ZoneAwareComponent; import com.riiablo.map.DS1; import com.riiablo.map.DT1; import com.riiablo.map.Map; @@ -78,6 +84,29 @@ public class Engine extends PooledEngine { public static final byte MODE_RN = 15; } + public static final class Player { + public static final byte MODE_DT = 0; + public static final byte MODE_NU = 1; + public static final byte MODE_WL = 2; + public static final byte MODE_RN = 3; + public static final byte MODE_GH = 4; + public static final byte MODE_TN = 5; + public static final byte MODE_TW = 6; + public static final byte MODE_A1 = 7; + public static final byte MODE_A2 = 8; + public static final byte MODE_BL = 9; + public static final byte MODE_SC = 10; + public static final byte MODE_TH = 11; + public static final byte MODE_KK = 12; + public static final byte MODE_S1 = 13; + public static final byte MODE_S2 = 14; + public static final byte MODE_S3 = 15; + public static final byte MODE_S4 = 16; + public static final byte MODE_DD = 17; + //public static final byte MODE_GH = 18; + //public static final byte MODE_GH = 19; + } + private static Label createLabel(String text) { Label label = new Label(Riiablo.fonts.font16); label.setAlignment(Align.center); @@ -361,6 +390,57 @@ public class Engine extends PooledEngine { return entity; } + public Entity createPlayer(Map map, Map.Zone zone, CharData charData, float x, float y) { + TypeComponent typeComponent = createComponent(TypeComponent.class); + typeComponent.type = TypeComponent.Type.PLR; + + PlayerComponent playerComponent = createComponent(PlayerComponent.class); + playerComponent.charData = charData; + + CofComponent cofComponent = createComponent(CofComponent.class); + cofComponent.mode = Player.MODE_TN; + + AnimationComponent animationComponent = createComponent(AnimationComponent.class); + + BBoxComponent boxComponent = createComponent(BBoxComponent.class); + boxComponent.box = animationComponent.animation.getBox(); + + PositionComponent positionComponent = createComponent(PositionComponent.class); + positionComponent.position.set(x, y); + + VelocityComponent velocityComponent = createComponent(VelocityComponent.class); + velocityComponent.walkSpeed = 6; + velocityComponent.runSpeed = 9; + + MovementModeComponent movementModeComponent = createComponent(MovementModeComponent.class); + movementModeComponent.NU = Player.MODE_TN; + movementModeComponent.WL = Player.MODE_TW; + movementModeComponent.RN = Player.MODE_RN; + + ZoneAwareComponent zoneAwareComponent = createComponent(ZoneAwareComponent.class); + + AngleComponent angleComponent = createComponent(AngleComponent.class); + + MapComponent mapComponent = createComponent(MapComponent.class); + mapComponent.map = map; + mapComponent.zone = zone; + + Entity entity = createEntity("player"); + entity.add(typeComponent); + entity.add(cofComponent); + entity.add(animationComponent); + entity.add(boxComponent); + entity.add(positionComponent); + entity.add(velocityComponent); + entity.add(movementModeComponent); + entity.add(angleComponent); + entity.add(mapComponent); + entity.add(playerComponent); + entity.add(zoneAwareComponent); + + return entity; + } + public static T getOrCreateComponent(Entity entity, com.badlogic.ashley.core.Engine engine, Class componentType, ComponentMapper componentMapper) { T instance = componentMapper.get(entity); if (instance == null) entity.add(instance = engine.createComponent(componentType)); diff --git a/core/src/com/riiablo/engine/component/ZoneAwareComponent.java b/core/src/com/riiablo/engine/component/ZoneAwareComponent.java new file mode 100644 index 00000000..edaea4dc --- /dev/null +++ b/core/src/com/riiablo/engine/component/ZoneAwareComponent.java @@ -0,0 +1,8 @@ +package com.riiablo.engine.component; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Pool; + +public class ZoneAwareComponent implements Component, Pool.Poolable { + @Override public void reset() {} +} diff --git a/core/src/com/riiablo/engine/component/ZoneUpdate.java b/core/src/com/riiablo/engine/component/ZoneUpdate.java new file mode 100644 index 00000000..1079e268 --- /dev/null +++ b/core/src/com/riiablo/engine/component/ZoneUpdate.java @@ -0,0 +1,8 @@ +package com.riiablo.engine.component; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Pool; + +public class ZoneUpdate implements Component, Pool.Poolable { + @Override public void reset() {} +} diff --git a/core/src/com/riiablo/engine/system/PlayerSystem.java b/core/src/com/riiablo/engine/system/PlayerSystem.java new file mode 100644 index 00000000..c0b391f1 --- /dev/null +++ b/core/src/com/riiablo/engine/system/PlayerSystem.java @@ -0,0 +1,217 @@ +package com.riiablo.engine.system; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.EntityListener; +import com.badlogic.ashley.core.EntitySystem; +import com.badlogic.ashley.core.Family; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectMap; +import com.riiablo.CharData; +import com.riiablo.Riiablo; +import com.riiablo.codec.COF; +import com.riiablo.codec.excel.Armor; +import com.riiablo.codec.excel.Weapons; +import com.riiablo.engine.component.CofComponent; +import com.riiablo.engine.component.PlayerComponent; +import com.riiablo.engine.component.TypeComponent; +import com.riiablo.engine.component.cof.AlphaUpdate; +import com.riiablo.engine.component.cof.TransformUpdate; +import com.riiablo.item.BodyLoc; +import com.riiablo.item.Item; + +import org.apache.commons.lang3.ObjectUtils; + +public class PlayerSystem extends EntitySystem implements EntityListener, CharData.EquippedListener { + private static final String TAG = "PlayerSystem"; + private static final boolean DEBUG = true; + private static final boolean DEBUG_STATE = DEBUG && !true; + + private static final String[] TOKENS = {"AM", "SO", "NE", "PA", "BA", "DZ", "AI"}; + + private final ComponentMapper charDataComponent = ComponentMapper.getFor(PlayerComponent.class); + private final ComponentMapper cofComponent = ComponentMapper.getFor(CofComponent.class); + private final Family family = Family.all(PlayerComponent.class, CofComponent.class).get(); + + private final ComponentMapper transformUpdate = ComponentMapper.getFor(TransformUpdate.class); + private final ComponentMapper alphaUpdate = ComponentMapper.getFor(AlphaUpdate.class); + + private final ObjectMap charDatas = new ObjectMap<>(); + + public PlayerSystem() { + setProcessing(false); + } + + @Override + public void addedToEngine(Engine engine) { + super.addedToEngine(engine); + engine.addEntityListener(family, this); + } + + @Override + public void removedFromEngine(Engine engine) { + super.removedFromEngine(engine); + engine.removeEntityListener(this); + } + + @Override + public void entityAdded(Entity entity) { + PlayerComponent playerComponent = this.charDataComponent.get(entity); + CharData charData = playerComponent.charData; + loadItems(charData.getD2S().items.items); + CofComponent cofComponent = this.cofComponent.get(entity); + cofComponent.token = TOKENS[charData.getD2S().header.charClass]; + updateWeaponClass(entity, charData, cofComponent); + updateArmorClass(entity, charData, cofComponent); + charDatas.put(charData, entity); + charData.addEquippedListener(this); + } + + @Override + public void entityRemoved(Entity entity) { + + } + + private void loadItems(Array items) { + for (Item item : items) { + //item.setOwner(this); + item.load(); + } + } + + private void updateWeaponClass(Entity entity, CharData charData, CofComponent cof) { + Item RH = null, LH = null, SH = null; + Item rArm = charData.getEquipped2(BodyLoc.RARM); + if (rArm != null) { + if (rArm.type.is(com.riiablo.item.Type.WEAP)) { + RH = rArm; + } else if (rArm.type.is(com.riiablo.item.Type.SHLD)) { + SH = rArm; + } + } + + Item lArm = charData.getEquipped2(BodyLoc.LARM); + if (lArm != null) { + if (lArm.type.is(com.riiablo.item.Type.WEAP)) { + LH = lArm; + } else if (lArm.type.is(com.riiablo.item.Type.SHLD)) { + SH = lArm; + } + } + + if (DEBUG_STATE) { + 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")) { + cof.wclass = CofComponent.WEAPON_1SS; // Left Swing Right Swing + } else if (LHEntry.wclass.equals("1hs") && RHEntry.wclass.equals("1ht")) { + cof.wclass = CofComponent.WEAPON_1ST; // Left Swing Right Thrust + } else if (LHEntry.wclass.equals("1ht") && RHEntry.wclass.equals("1hs")) { + cof.wclass = CofComponent.WEAPON_1JS; // Left Jab Right Swing + } else if (LHEntry.wclass.equals("1ht") && RHEntry.wclass.equals("1ht")) { + cof.wclass = CofComponent.WEAPON_1JT; // Left Jab Right Thrust + } else if (LH.type.is(com.riiablo.item.Type.MISS) || RH.type.is(com.riiablo.item.Type.MISS)) { + cof.wclass = Riiablo.files.WeaponClass.index(LH.type.is(com.riiablo.item.Type.MISS) ? LHEntry.wclass : RHEntry.wclass); + } else if (LH.type.is(com.riiablo.item.Type.H2H) || RH.type.is(com.riiablo.item.Type.H2H)) { + cof.wclass = CofComponent.WEAPON_HT2; // Two Hand-to-Hand + } else { + cof.wclass = CofComponent.WEAPON_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(com.riiablo.item.Type.BOW)) { + LH = RH; + RH = null; + Weapons.Entry LHEntry = LH.getBase(); + cof.wclass = Riiablo.files.WeaponClass.index(LHEntry.wclass); + } else if (RH.type.is(com.riiablo.item.Type.WEAP)) { // make sure weap and not e.g. misl, might not be required + Weapons.Entry RHEntry = RH.getBase(); + cof.wclass = Riiablo.files.WeaponClass.index(RHEntry.wclass); + } else { + cof.wclass = CofComponent.WEAPON_HTH; + } + } else { + cof.wclass = CofComponent.WEAPON_HTH; + } + + cof.component[COF.Component.RH] = RH != null ? TypeComponent.Type.PLR.getComponent(RH.base.alternateGfx) : CofComponent.COMPONENT_NIL; + cof.component[COF.Component.LH] = LH != null ? TypeComponent.Type.PLR.getComponent(LH.base.alternateGfx) : CofComponent.COMPONENT_NIL; + cof.component[COF.Component.SH] = SH != null ? TypeComponent.Type.PLR.getComponent(SH.base.alternateGfx) : CofComponent.COMPONENT_NIL; + + cof.alpha[COF.Component.RH] = RH != null && RH.isEthereal() ? Item.ETHEREAL_ALPHA : CofComponent.ALPHA_NULL; + cof.alpha[COF.Component.LH] = LH != null && LH.isEthereal() ? Item.ETHEREAL_ALPHA : CofComponent.ALPHA_NULL; + cof.alpha[COF.Component.SH] = SH != null && SH.isEthereal() ? Item.ETHEREAL_ALPHA : CofComponent.ALPHA_NULL; + com.riiablo.engine.Engine.getOrCreateComponent(entity, getEngine(), AlphaUpdate.class, this.alphaUpdate).flags |= BodyLoc.RARM.components(); + } + + private void updateArmorClass(Entity entity, CharData charData, CofComponent cof) { + Item head = charData.getEquipped(BodyLoc.HEAD); + cof.component[COF.Component.HD] = head != null ? TypeComponent.Type.PLR.getComponent(head.base.alternateGfx) : CofComponent.COMPONENT_LIT; + cof.transform[COF.Component.HD] = head != null ? (byte) ((head.base.Transform << 5) | (head.charColorIndex & 0x1F)) : CofComponent.TRANSFORM_NULL; + TransformUpdate transformUpdate = com.riiablo.engine.Engine.getOrCreateComponent(entity, getEngine(), TransformUpdate.class, this.transformUpdate); + transformUpdate.flags |= BodyLoc.HEAD.components(); + + Item body = charData.getEquipped(BodyLoc.TORS); + if (body != null) { + Armor.Entry armor = body.getBase(); + cof.component[COF.Component.TR] = (armor.Torso + 1); + cof.component[COF.Component.LG] = (armor.Legs + 1); + cof.component[COF.Component.RA] = (armor.rArm + 1); + cof.component[COF.Component.LA] = (armor.lArm + 1); + cof.component[COF.Component.S1] = (armor.lSPad + 1); + cof.component[COF.Component.S2] = (armor.rSPad + 1); + + byte packedTransform = (byte) ((body.base.Transform << 5) | (body.charColorIndex & 0x1F)); + cof.transform[COF.Component.TR] = packedTransform; + cof.transform[COF.Component.LG] = packedTransform; + cof.transform[COF.Component.RA] = packedTransform; + cof.transform[COF.Component.LA] = packedTransform; + cof.transform[COF.Component.S1] = packedTransform; + cof.transform[COF.Component.S2] = packedTransform; + transformUpdate.flags |= BodyLoc.TORS.components(); + } else { + cof.component[COF.Component.TR] = CofComponent.COMPONENT_LIT; + cof.component[COF.Component.LG] = CofComponent.COMPONENT_LIT; + cof.component[COF.Component.RA] = CofComponent.COMPONENT_LIT; + cof.component[COF.Component.LA] = CofComponent.COMPONENT_LIT; + cof.component[COF.Component.S1] = CofComponent.COMPONENT_LIT; + cof.component[COF.Component.S2] = CofComponent.COMPONENT_LIT; + + cof.transform[COF.Component.TR] = CofComponent.TRANSFORM_NULL; + cof.transform[COF.Component.LG] = CofComponent.TRANSFORM_NULL; + cof.transform[COF.Component.RA] = CofComponent.TRANSFORM_NULL; + cof.transform[COF.Component.LA] = CofComponent.TRANSFORM_NULL; + cof.transform[COF.Component.S1] = CofComponent.TRANSFORM_NULL; + cof.transform[COF.Component.S2] = CofComponent.TRANSFORM_NULL; + transformUpdate.flags |= BodyLoc.TORS.components(); + } + } + + @Override + public void onChanged(CharData client, BodyLoc bodyLoc, Item oldItem, Item item) { + Entity entity = charDatas.get(client); + CofComponent cofComponent = this.cofComponent.get(entity); + cofComponent.dirty |= bodyLoc.components(); + updateWeaponClass(entity, client, cofComponent); + updateArmorClass(entity, client, cofComponent); + } + + @Override + public void onAlternated(CharData client, int alternate, Item LH, Item RH) { + Entity entity = charDatas.get(client); + CofComponent cofComponent = this.cofComponent.get(entity); + updateWeaponClass(entity, client, cofComponent); + updateArmorClass(entity, client, cofComponent); + } +} diff --git a/core/src/com/riiablo/engine/system/ZoneSystem.java b/core/src/com/riiablo/engine/system/ZoneSystem.java new file mode 100644 index 00000000..e590d183 --- /dev/null +++ b/core/src/com/riiablo/engine/system/ZoneSystem.java @@ -0,0 +1,33 @@ +package com.riiablo.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 com.riiablo.engine.Engine; +import com.riiablo.engine.component.MapComponent; +import com.riiablo.engine.component.PositionComponent; +import com.riiablo.engine.component.ZoneAwareComponent; +import com.riiablo.engine.component.ZoneUpdate; +import com.riiablo.map.Map; + +public class ZoneSystem extends IteratingSystem { + private final ComponentMapper zoneUpdateComponent = ComponentMapper.getFor(ZoneUpdate.class); + private final ComponentMapper positionComponent = ComponentMapper.getFor(PositionComponent.class); + private final ComponentMapper mapComponent = ComponentMapper.getFor(MapComponent.class); + + public ZoneSystem() { + super(Family.all(ZoneAwareComponent.class, PositionComponent.class, MapComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float delta) { + PositionComponent positionComponent = this.positionComponent.get(entity); + MapComponent mapComponent = this.mapComponent.get(entity); + Map.Zone zone = mapComponent.map.getZone(positionComponent.position); + if (zone != mapComponent.zone) { + mapComponent.zone = zone; + Engine.getOrCreateComponent(entity, getEngine(), ZoneUpdate.class, zoneUpdateComponent); + } + } +} diff --git a/core/src/com/riiablo/engine/system/ZoneUpdateSystem.java b/core/src/com/riiablo/engine/system/ZoneUpdateSystem.java new file mode 100644 index 00000000..6629319c --- /dev/null +++ b/core/src/com/riiablo/engine/system/ZoneUpdateSystem.java @@ -0,0 +1,42 @@ +package com.riiablo.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 com.riiablo.engine.Engine; +import com.riiablo.engine.component.MapComponent; +import com.riiablo.engine.component.MovementModeComponent; +import com.riiablo.engine.component.PlayerComponent; +import com.riiablo.engine.component.ZoneUpdate; +import com.riiablo.map.Map; + +public class ZoneUpdateSystem extends IteratingSystem { + private final ComponentMapper mapComponent = ComponentMapper.getFor(MapComponent.class); + private final ComponentMapper playerComponent = ComponentMapper.getFor(PlayerComponent.class); + private final ComponentMapper movementModeComponent = ComponentMapper.getFor(MovementModeComponent.class); + + public ZoneUpdateSystem() { + super(Family.all(ZoneUpdate.class, MapComponent.class, MovementModeComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float delta) { + MapComponent mapComponent = this.mapComponent.get(entity); + Map.Zone zone = mapComponent.zone; + if (playerComponent.has(entity)) { + MovementModeComponent movementModeComponent = this.movementModeComponent.get(entity); + if (zone.isTown()) { + movementModeComponent.NU = Engine.Player.MODE_TN; + movementModeComponent.WL = Engine.Player.MODE_TW; + movementModeComponent.RN = Engine.Player.MODE_RN; + } else { + movementModeComponent.NU = Engine.Player.MODE_NU; + movementModeComponent.WL = Engine.Player.MODE_WL; + movementModeComponent.RN = Engine.Player.MODE_RN; + } + } + + entity.remove(ZoneUpdate.class); + } +}