diff --git a/api/src/infinity/es/Damage.java b/api/src/infinity/es/Damage.java index d7258ec4..48ea2d7b 100644 --- a/api/src/infinity/es/Damage.java +++ b/api/src/infinity/es/Damage.java @@ -26,6 +26,7 @@ package infinity.es; import com.simsilica.es.EntityComponent; +import com.simsilica.ext.mphys.ShapeInfo; /** * This component is carried by the bomb and holds the intended damage (of the producer). The @@ -35,10 +36,22 @@ */ public class Damage implements EntityComponent { + private final long explosionDecay; private final int intendedDamage; + private final ShapeInfo explosionShape; - public Damage(final int intendedDamage) { + public ShapeInfo getExplosionShape() { + return explosionShape; + } + + public long getExplosionDecay() { + return explosionDecay; + } + + public Damage(long explosionDecay, final int intendedDamage, ShapeInfo explosionShape) { + this.explosionDecay = explosionDecay; this.intendedDamage = intendedDamage; + this.explosionShape = explosionShape; } public int getIntendedDamage() { diff --git a/api/src/infinity/es/ShapeNames.java b/api/src/infinity/es/ShapeNames.java index d34d6c68..2b99c7d8 100644 --- a/api/src/infinity/es/ShapeNames.java +++ b/api/src/infinity/es/ShapeNames.java @@ -19,10 +19,6 @@ */ public class ShapeNames { - private ShapeNames(){ - throw new InfinityRunTimeException("This class should not be instantiated"); - } - public static final String SHIP_SHARK = "ship_shark"; public static final String SHIP_WARBIRD = "ship_warbird"; public static final String SHIP_JAVELIN = "ship_javelin"; @@ -33,35 +29,31 @@ private ShapeNames(){ public static final String SHIP_LANCASTER = "ship_lancaster"; public static final String GRAV_SPHERE = "gravSphere"; public static final String THRUST = "thrust"; - public static final String EXPLOSION = "explosion"; - public static final String BULLETL1 = "bullet_l1"; public static final String BULLETL2 = "bullet_l2"; public static final String BULLETL3 = "bullet_l3"; public static final String BULLETL4 = "bullet_l4"; - public static final String BOMBL1 = "bomb_l1"; public static final String BOMBL2 = "bomb_l2"; public static final String BOMBL3 = "bomb_l3"; public static final String BOMBL4 = "bomb_l4"; - public static final String MINEL1 = "mine_l1"; public static final String MINEL2 = "mine_l2"; public static final String MINEL3 = "mine_l3"; public static final String MINEL4 = "mine_l4"; - public static final String EMPL1 = "emp_l1"; public static final String EMPL2 = "emp_l2"; public static final String EMPL3 = "emp_l3"; public static final String EMPL4 = "emp_l4"; - public static final String THOR = "thor"; public static final String BURST = "burst"; - public static final String PRIZE = "bounty"; public static final String ARENA = "arena"; public static final String MAPTILE = "maptile"; - public static final String EXPLOSION2 = "explosion2"; + public static final String EXPLOSION = "explosionEffect"; + public static final String EXPLODE_0 = "explode0"; + public static final String EXPLODE_1 = "explode1"; + public static final String EXPLODE_2 = "explode2"; public static final String OVER1 = "over1"; public static final String OVER2 = "over2"; public static final String OVER5 = "over5"; @@ -71,8 +63,13 @@ private ShapeNames(){ public static final String FLAG = "flag"; public static final String DOOR = "door"; + private ShapeNames() { + throw new InfinityRunTimeException("This class should not be instantiated"); + } + /** * Creates a ship shape based on the ship type. + * * @param ship the ship type * @param ed the entity data * @return the shape info diff --git a/api/src/infinity/es/ship/weapons/Bounce.java b/api/src/infinity/es/ship/weapons/Bounce.java new file mode 100644 index 00000000..9c6a037c --- /dev/null +++ b/api/src/infinity/es/ship/weapons/Bounce.java @@ -0,0 +1,24 @@ +package infinity.es.ship.weapons; + +import com.simsilica.es.EntityComponent; + +/** + * A component that indicates that an entity can bounce a certain number of times. This is used + * on bullets and bombs. + */ +public class Bounce implements EntityComponent { + + private final int bounces; + + public Bounce(final int bounces) { + this.bounces = bounces; + } + + public int getBounces() { + return bounces; + } + + public Bounce decreaseBounces() { + return new Bounce(bounces - 1); + } +} diff --git a/api/src/infinity/sim/CoreViewConstants.java b/api/src/infinity/sim/CoreViewConstants.java index 348c19c6..7115ebf7 100644 --- a/api/src/infinity/sim/CoreViewConstants.java +++ b/api/src/infinity/sim/CoreViewConstants.java @@ -47,7 +47,9 @@ public class CoreViewConstants { public static final float FLAGSIZE = 1; public static final float BASESIZE = 5f; public static final float BURSTSIZE = 0.25f; - public static final float EXPLOSION2SIZE = 2f; + public static final float EXPLOSION2SIZE = 3f; + public static final float EXPLOSION1SIZE = 2f; + public static final float EXPLOSION0SIZE = 0.5f; public static final float WORMHOLESIZE = 4f; public static final float OVER1SIZE = 1f; public static final float OVER2SIZE = 2f; @@ -58,6 +60,8 @@ public class CoreViewConstants { public static final int ARENASIZE = 1024; // Decays must be in milliseconds public static final long EXPLOSION2DECAY = 2000; + public static final long EXPLOSION1DECAY = 1500; + public static final long EXPLOSION0DECAY = 500; public static final long WARPDECAY = 800; public static final long REPELDECAY = 400; // LightSize radius diff --git a/api/src/infinity/sim/GameEntities.java b/api/src/infinity/sim/GameEntities.java index 97ca6443..76be02ae 100644 --- a/api/src/infinity/sim/GameEntities.java +++ b/api/src/infinity/sim/GameEntities.java @@ -214,19 +214,19 @@ public static EntityId createBullet( * return lastTileInfo; } */ // Explosion is for now only visual, so only object type and position - public static EntityId createExplosion2( + public static EntityId createExplosion( final EntityData ed, @SuppressWarnings("unused") final EntityId owner, final PhysicsSpace phys, final long createdTime, final Vec3d pos, - final long decayMillis) { + final long decayMillis, + final ShapeInfo shapeInfo){ final EntityId lastExplosion = ed.createEntity(); // Explosion is a ghost ed.setComponents( - lastExplosion, - ShapeInfo.create(ShapeNames.EXPLOSION2, 0, ed), + lastExplosion,shapeInfo, new SpawnPosition(phys.getGrid(), pos), new Decay( createdTime, diff --git a/infinity/assets/Materials/Explode0MaterialLight.j3m b/infinity/assets/Materials/Explode0MaterialLight.j3m new file mode 100644 index 00000000..b74be211 --- /dev/null +++ b/infinity/assets/Materials/Explode0MaterialLight.j3m @@ -0,0 +1,20 @@ +Material Explode2MaterialLight : MatDefs/Multiline/AnimateMultilineSpriteLightShader.j3md { + MaterialParameters { + numTilesX : 7 + numTilesY : 1 + Speed : 20 + numTilesOffsetX : 0 + numTilesOffsetY : 0 + + DiffuseMap : Flip Textures/Subspace/explode0.bm2 + UseMaterialColors : true + Specular : 1.0 1.0 1.0 1.0 + Diffuse : 1.0 1.0 1.0 1.0 + Shininess : 1.0 + + } + AdditionalRenderState { + Blend Alpha + Wireframe Off + } +} diff --git a/infinity/assets/Materials/Explode0MaterialUnshaded.j3m b/infinity/assets/Materials/Explode0MaterialUnshaded.j3m new file mode 100644 index 00000000..fa68095f --- /dev/null +++ b/infinity/assets/Materials/Explode0MaterialUnshaded.j3m @@ -0,0 +1,15 @@ +Material Explode2MaterialUnshaded : MatDefs/Multiline/AnimateMultilineSpriteUnshaded.j3md { + MaterialParameters { + ColorMap : Flip Textures/Subspace/explode0.bm2 + numTilesX : 7 + numTilesY : 1 + Speed : 20 + numTilesOffsetX : 0 + numTilesOffsetY : 0 + + } + AdditionalRenderState { + Blend Alpha + Wireframe Off + } +} diff --git a/infinity/assets/Materials/Explode1MaterialLight.j3m b/infinity/assets/Materials/Explode1MaterialLight.j3m new file mode 100644 index 00000000..b04e8369 --- /dev/null +++ b/infinity/assets/Materials/Explode1MaterialLight.j3m @@ -0,0 +1,20 @@ +Material Explode2MaterialLight : MatDefs/Multiline/AnimateMultilineSpriteLightShader.j3md { + MaterialParameters { + numTilesX : 7 + numTilesY : 1 + Speed : 20 + numTilesOffsetX : 0 + numTilesOffsetY : 0 + + DiffuseMap : Flip Textures/Subspace/explode1.bm2 + UseMaterialColors : true + Specular : 1.0 1.0 1.0 1.0 + Diffuse : 1.0 1.0 1.0 1.0 + Shininess : 1.0 + + } + AdditionalRenderState { + Blend Alpha + Wireframe Off + } +} diff --git a/infinity/assets/Materials/Explode1MaterialUnshaded.j3m b/infinity/assets/Materials/Explode1MaterialUnshaded.j3m new file mode 100644 index 00000000..6f26ffaa --- /dev/null +++ b/infinity/assets/Materials/Explode1MaterialUnshaded.j3m @@ -0,0 +1,15 @@ +Material Explode2MaterialUnshaded : MatDefs/Multiline/AnimateMultilineSpriteUnshaded.j3md { + MaterialParameters { + ColorMap : Flip Textures/Subspace/explode1.bm2 + numTilesX : 7 + numTilesY : 1 + Speed : 20 + numTilesOffsetX : 0 + numTilesOffsetY : 0 + + } + AdditionalRenderState { + Blend Alpha + Wireframe Off + } +} diff --git a/infinity/src/main/java/infinity/client/states/SISpatialFactory.java b/infinity/src/main/java/infinity/client/states/SISpatialFactory.java index fbff1e76..061202ce 100644 --- a/infinity/src/main/java/infinity/client/states/SISpatialFactory.java +++ b/infinity/src/main/java/infinity/client/states/SISpatialFactory.java @@ -137,7 +137,11 @@ public Spatial createModel(EntityId id, String shapeName, Mass mass) { return createBounty(); case ShapeNames.ARENA: return createArena(); - case ShapeNames.EXPLOSION2: + case ShapeNames.EXPLODE_0: + return createExplosion0(); + case ShapeNames.EXPLODE_1: + return createExplosion1(); + case ShapeNames.EXPLODE_2: return createExplosion2(); case ShapeNames.OVER5: return createOver5(); @@ -586,6 +590,46 @@ private Spatial createArena() { return geom; } + private Spatial createExplosion1() { + final Quad quad = new Quad(CoreViewConstants.EXPLOSION1SIZE, CoreViewConstants.EXPLOSION1SIZE); + final float halfSize = CoreViewConstants.EXPLOSION1SIZE * 0.5f; + quad.setBuffer(VertexBuffer.Type.Position, 3, getVerticesQuad(halfSize)); + quad.setBuffer(VertexBuffer.Type.Normal, 3, BufferUtils.createFloatBuffer(getNormalsQuad())); + quad.updateBound(); + final Geometry geom = new Geometry("Bomb", quad); + + if (UNSHADED) { + geom.setMaterial(assets.loadMaterial("Materials/Explode1MaterialUnshaded.j3m")); + } else { + geom.setMaterial(assets.loadMaterial("Materials/Explode1MaterialLight.j3m")); + } + + geom.getMaterial().setFloat(STARTTIME, timer.getTimeInSeconds()); + + geom.setQueueBucket(RenderQueue.Bucket.Transparent); + return geom; + } + + + private Spatial createExplosion0() { + final Quad quad = new Quad(CoreViewConstants.EXPLOSION0SIZE, CoreViewConstants.EXPLOSION0SIZE); + final float halfSize = CoreViewConstants.EXPLOSION0SIZE * 0.5f; + quad.setBuffer(VertexBuffer.Type.Position, 3, getVerticesQuad(halfSize)); + quad.setBuffer(VertexBuffer.Type.Normal, 3, BufferUtils.createFloatBuffer(getNormalsQuad())); + quad.updateBound(); + final Geometry geom = new Geometry("Bomb", quad); + + if (UNSHADED) { + geom.setMaterial(assets.loadMaterial("Materials/Explode0MaterialUnshaded.j3m")); + } else { + geom.setMaterial(assets.loadMaterial("Materials/Explode0MaterialLight.j3m")); + } + + geom.getMaterial().setFloat(STARTTIME, timer.getTimeInSeconds()); + + geom.setQueueBucket(RenderQueue.Bucket.Transparent); + return geom; + } private Spatial createExplosion2() { final Quad quad = new Quad(CoreViewConstants.EXPLOSION2SIZE, CoreViewConstants.EXPLOSION2SIZE); diff --git a/infinity/src/main/java/infinity/systems/ActionSystem.java b/infinity/src/main/java/infinity/systems/ActionSystem.java index 7b1181ec..2fe597d3 100644 --- a/infinity/src/main/java/infinity/systems/ActionSystem.java +++ b/infinity/src/main/java/infinity/systems/ActionSystem.java @@ -11,6 +11,7 @@ import com.simsilica.es.EntityId; import com.simsilica.es.EntitySet; import com.simsilica.ext.mphys.MPhysSystem; +import com.simsilica.ext.mphys.ShapeInfo; import com.simsilica.mathd.Quatd; import com.simsilica.mathd.Vec3d; import com.simsilica.mblock.phys.MBlockShape; @@ -22,11 +23,13 @@ import com.simsilica.sim.AbstractGameSystem; import com.simsilica.sim.SimTime; import infinity.es.Damage; +import infinity.es.ShapeNames; import infinity.es.ship.actions.Thor; import infinity.es.ship.actions.ThorCurrentCount; import infinity.es.ship.actions.ThorFireDelay; import infinity.sim.CoreGameConstants; import infinity.sim.CorePhysicsConstants; +import infinity.sim.CoreViewConstants; import infinity.sim.GameEntities; import infinity.sim.GameSounds; import infinity.sim.util.InfinityRunTimeException; @@ -165,7 +168,8 @@ private void createThor(Entity requesterEntity, final long time, ActionPosition info.attackVelocity, CoreGameConstants.BULLETDECAY); - ed.setComponent(gunProjectile, new Damage(CoreGameConstants.THORDAMAGE)); + ed.setComponent(gunProjectile, new Damage(CoreViewConstants.EXPLOSION1DECAY, CoreGameConstants.THORDAMAGE, ShapeInfo.create( + ShapeNames.EXPLODE_1, 1, ed))); } private boolean createSound(Entity requesterEntity, byte flag, long time, ActionPosition info) { @@ -300,6 +304,10 @@ public void newContact(Contact contact) { } } + public boolean isThor(EntityId idOne) { + return thorProjectiles.containsId(idOne); + } + /** A class that holds the position information needed to create an attack. */ private static class ActionPosition { diff --git a/infinity/src/main/java/infinity/systems/WeaponsSystem.java b/infinity/src/main/java/infinity/systems/WeaponsSystem.java index 7add54ba..4935f118 100644 --- a/infinity/src/main/java/infinity/systems/WeaponsSystem.java +++ b/infinity/src/main/java/infinity/systems/WeaponsSystem.java @@ -14,6 +14,7 @@ import com.simsilica.es.EntitySet; import com.simsilica.es.common.Decay; import com.simsilica.ext.mphys.MPhysSystem; +import com.simsilica.ext.mphys.ShapeInfo; import com.simsilica.mathd.Quatd; import com.simsilica.mathd.Vec3d; import com.simsilica.mblock.phys.MBlockShape; @@ -27,23 +28,26 @@ import infinity.es.Damage; import infinity.es.Frequency; import infinity.es.GravityWell; +import infinity.es.ShapeNames; import infinity.es.ship.Energy; import infinity.es.ship.actions.Burst; -import infinity.es.ship.actions.ThorCurrentCount; -import infinity.es.ship.weapons.BombCurrentLevel; +import infinity.es.ship.actions.Thor; import infinity.es.ship.weapons.BombCost; +import infinity.es.ship.weapons.BombCurrentLevel; import infinity.es.ship.weapons.BombFireDelay; +import infinity.es.ship.weapons.Bounce; import infinity.es.ship.weapons.GravityBomb; import infinity.es.ship.weapons.GravityBombCost; import infinity.es.ship.weapons.GravityBombFireDelay; -import infinity.es.ship.weapons.GunCurrentLevel; import infinity.es.ship.weapons.GunCost; +import infinity.es.ship.weapons.GunCurrentLevel; import infinity.es.ship.weapons.GunFireDelay; -import infinity.es.ship.weapons.MineCurrentLevel; import infinity.es.ship.weapons.MineCost; +import infinity.es.ship.weapons.MineCurrentLevel; import infinity.es.ship.weapons.MineFireDelay; import infinity.sim.CoreGameConstants; import infinity.sim.CorePhysicsConstants; +import infinity.sim.CoreViewConstants; import infinity.sim.GameEntities; import infinity.sim.GameSounds; import infinity.sim.util.InfinityRunTimeException; @@ -162,8 +166,8 @@ public void update(final SimTime tpf) { * one by one * * Not sure if this is needed or there is a queue system already in place by the session - * framework. 25-02-2023: Maybe the right way is to create "attack entities" that are then handled through - * an entityset. + * framework. 25-02-2023: Maybe the right way is to create "attack entities" that are + * then handled through an entityset. */ final Iterator iterator = sessionAttackCreations.iterator(); while (iterator.hasNext()) { @@ -389,8 +393,8 @@ private void createProjectileGun(Entity requesterEntity, final long time, Attack EntityId requester = requesterEntity.getId(); GunCurrentLevel gunCurrentLevel = this.guns.getEntity(requester).get(GunCurrentLevel.class); - GunCost gc = this.guns.getEntity(requester).get(GunCost.class); - final String bulletShape = CoreGameConstants.BULLETLEVELPREPENDTEXT + gunCurrentLevel.getLevel().level; + final String bulletShape = + CoreGameConstants.BULLETLEVELPREPENDTEXT + gunCurrentLevel.getLevel().level; EntityId gunProjectile; gunProjectile = @@ -404,15 +408,20 @@ private void createProjectileGun(Entity requesterEntity, final long time, Attack CoreGameConstants.BULLETDECAY, bulletShape); - ed.setComponent(gunProjectile, new Damage(CoreGameConstants.BULLETDAMAGE)); + ed.setComponent( + gunProjectile, + new Damage( + CoreViewConstants.EXPLOSION0DECAY, + CoreGameConstants.BULLETDAMAGE, + ShapeInfo.create(ShapeNames.EXPLODE_0, CoreViewConstants.EXPLOSION0SIZE, ed))); } private void createProjectileBomb(Entity requesterEntity, long time, AttackPosition info) { EntityId requester = requesterEntity.getId(); BombCurrentLevel bombCurrentLevel = this.bombs.getEntity(requester).get(BombCurrentLevel.class); - BombCost bc = this.bombs.getEntity(requester).get(BombCost.class); - final String bombShape = CoreGameConstants.BOMBLEVELPREPENDTEXT + bombCurrentLevel.getLevel().level; + final String bombShape = + CoreGameConstants.BOMBLEVELPREPENDTEXT + bombCurrentLevel.getLevel().level; final EntityId bombProjectile = GameEntities.createBomb( @@ -424,7 +433,12 @@ private void createProjectileBomb(Entity requesterEntity, long time, AttackPosit info.getAttackVelocity(), CoreGameConstants.BULLETDECAY, bombShape); - ed.setComponent(bombProjectile, new Damage(CoreGameConstants.BOMBDAMAGE)); + ed.setComponent( + bombProjectile, + new Damage( + CoreViewConstants.EXPLOSION1DECAY, + CoreGameConstants.BOMBDAMAGE, + ShapeInfo.create(ShapeNames.EXPLODE_1, CoreViewConstants.EXPLOSION1SIZE, ed))); } private void createProjectileGravBomb(Entity requesterEntity, long time, AttackPosition info) { @@ -451,7 +465,12 @@ private void createProjectileGravBomb(Entity requesterEntity, long time, AttackP delayedComponents, CoreGameConstants.BOMBLEVELPREPENDTEXT + gravityBomb.getLevel()); - ed.setComponent(projectile, new Damage(CoreGameConstants.GRAVBOMBDAMAGE)); + ed.setComponent( + projectile, + new Damage( + CoreViewConstants.EXPLOSION1DECAY, + CoreGameConstants.GRAVBOMBDAMAGE, + ShapeInfo.create(ShapeNames.EXPLODE_1, CoreViewConstants.EXPLOSION1SIZE, ed))); } private void createProjectileBurst(Entity requesterEntity, long time) { @@ -481,7 +500,12 @@ private void createProjectileBurst(Entity requesterEntity, long time) { info.getLocation(), info.getAttackVelocity(), CoreGameConstants.BULLETDECAY); - ed.setComponent(projectile, new Damage(20)); + ed.setComponent( + projectile, + new Damage( + CoreViewConstants.EXPLOSION0DECAY, + 20, + ShapeInfo.create(ShapeNames.EXPLODE_0, CoreViewConstants.EXPLOSION0SIZE, ed))); } } @@ -513,7 +537,8 @@ private boolean createProjectileMine(Entity requesterEntity, long time, AttackPo MineCurrentLevel mineCurrentLevel = this.mines.getEntity(requester).get(MineCurrentLevel.class); MineCost mc = this.mines.getEntity(requester).get(MineCost.class); - final String mineShape = CoreGameConstants.MINELEVELPREPENDTEXT + mineCurrentLevel.getLevel().level; + final String mineShape = + CoreGameConstants.MINELEVELPREPENDTEXT + mineCurrentLevel.getLevel().level; final EntityId mineProjectile = GameEntities.createMine( @@ -524,7 +549,12 @@ private boolean createProjectileMine(Entity requesterEntity, long time, AttackPo info.getLocation(), CoreGameConstants.MINEDECAY, mineShape); - ed.setComponent(mineProjectile, new Damage(mc.getCost())); + ed.setComponent( + mineProjectile, + new Damage( + CoreViewConstants.EXPLOSION1DECAY, + mc.getCost(), + ShapeInfo.create(ShapeNames.EXPLODE_1, CoreViewConstants.EXPLOSION1SIZE, ed))); return true; } @@ -537,7 +567,8 @@ private boolean createSound(Entity requesterEntity, byte flag, long time, Attack ed, requester, physicsSpace, time, info.location, gunCurrentLevel.getLevel()); return true; case BOMB: - BombCurrentLevel bombCurrentLevel = this.bombs.getEntity(requester).get(BombCurrentLevel.class); + BombCurrentLevel bombCurrentLevel = + this.bombs.getEntity(requester).get(BombCurrentLevel.class); GameSounds.createBombSound( ed, requester, physicsSpace, time, info.location, bombCurrentLevel.getLevel()); return true; @@ -547,7 +578,8 @@ private boolean createSound(Entity requesterEntity, byte flag, long time, Attack ed, requester, physicsSpace, time, info.location, entityGravBomb.getLevel()); return true; case MINE: - MineCurrentLevel mineCurrentLevel = this.mines.getEntity(requester).get(MineCurrentLevel.class); + MineCurrentLevel mineCurrentLevel = + this.mines.getEntity(requester).get(MineCurrentLevel.class); GameSounds.createMineSound( ed, requester, physicsSpace, time, info.location, mineCurrentLevel.getLevel()); break; @@ -659,53 +691,85 @@ public void sessionAttack(final EntityId attacker, final byte flag) { sessionAttackCreations.add(new Attack(attacker, flag)); } + /** + * The case of our bomb hitting ourselves is handled in the ContactSystem. Here we want to handle + * the case where an entity that has a Damage component hits an entity that has a Health + * component. We also want the handle the case where a projectile hits the world. + * + *

We cannot be sure that the entitysets are updated, so we have to inquire about the entities + * here and now. + * + * @param contact the contact + */ @Override public void newContact(Contact contact) { RigidBody body1 = contact.body1; AbstractBody body2 = contact.body2; EntityId idOne = body1.id; + Entity entity1 = ed.getEntity(idOne, Damage.class, Bounce.class, Thor.class, Energy.class); - // The case of our bomb hitting ourselves is handled in the ContactSystem. - // Here we want to handle the case where an entity that has a Damage component hits an entity - // that has a Health component. We also want the handle the case where a projectile hits the - // world. if (body2 instanceof RigidBody) { + EntityId idTwo = body2.id; + Entity entity2 = ed.getEntity(idTwo, Damage.class, Energy.class); log.debug("WeaponsSystem contact detected between: {} and {}", body1.id, body2.id); - EntityId idTwo = body2.id; - - EntityId damageId; - EntityId energyId; - if (damageEntities.containsId(idOne) && energyEntities.containsId(idTwo)) { - damageId = idOne; - energyId = idTwo; - } else if (damageEntities.containsId(idTwo) && energyEntities.containsId(idOne)) { - damageId = idTwo; - energyId = idOne; + Entity damageEntity; + Entity energyEntity; + if (entity1.get(Damage.class) != null && entity2.get(Energy.class) != null) { + damageEntity = entity1; + energyEntity = entity2; + } else if (entity2.get(Damage.class) != null && entity1.get(Energy.class) != null) { + damageEntity = entity2; + energyEntity = entity1; } else { return; } - Entity damageEntity = damageEntities.getEntity(damageId); - Entity energyEntity = energyEntities.getEntity(energyId); - - energySystem.damage(energyEntity.getId(), damageEntity.get(Damage.class).getIntendedDamage()); - - // TODO Find the right decay time based on animation - GameEntities.createExplosion2( - ed, EntityId.NULL_ID, physicsSpace, time.getTime(), contact.contactPoint, 2000); - ed.setComponent(damageId, Decay.duration(time.getTime(), 0)); + Damage damage = damageEntity.get(Damage.class); + + energySystem.damage(energyEntity.getId(), damage.getIntendedDamage()); + GameEntities.createExplosion( + ed, + EntityId.NULL_ID, + physicsSpace, + time.getTime(), + contact.contactPoint, + damage.getExplosionDecay(), + damage.getExplosionShape()); + ed.setComponent(damageEntity.getId(), Decay.duration(time.getTime(), 0)); contact.disable(); - } else if (body2 == null && damageEntities.containsId(idOne)) { + } else if (body2 == null + && entity1.get(Damage.class) != null + && entity1.get(Thor.class) == null) { // body2 = null means that body1 is hitting the world - // TODO: Check if projectile should bouncy or not - // - // Retain all energy in the contact - contact.restitution = 1; - // Remove all friction so ingoing angle and outgoing angle are the same - contact.friction = 0; + // thors are handled in the action system + Damage damage = entity1.get(Damage.class); + + Bounce bounce = ed.getComponent(idOne, Bounce.class); + if (bounce != null) { + // Retain all energy in the contact + contact.restitution = 1; + // Remove all friction so ingoing angle and outgoing angle are the same + contact.friction = 0; + if (bounce.getBounces() == 1) { + ed.removeComponent(idOne, Bounce.class); + } else { + ed.setComponent(idOne, bounce.decreaseBounces()); + } + } else { + GameEntities.createExplosion( + ed, + EntityId.NULL_ID, + physicsSpace, + time.getTime(), + contact.contactPoint, + damage.getExplosionDecay(), + damage.getExplosionShape()); + ed.setComponent(idOne, Decay.duration(time.getTime(), 0)); + contact.disable(); + } } }