From 89d2c78278fa118c3843ee0ab5478351faf17e00 Mon Sep 17 00:00:00 2001 From: Asser Fahrenholz Date: Sun, 26 Feb 2023 14:10:53 +0100 Subject: [PATCH] The Damage component now also holds information on how to display the impact visually (shape and duration). Not sure if this is best practice but for now its good enough. Also added visual display of the other types of explosions (small, medium, large). WeaponsSystem.java now checks for bounce-information on the projectile (will have to be added when creating projectile) --- api/src/infinity/es/Damage.java | 15 +- api/src/infinity/es/ShapeNames.java | 21 +-- api/src/infinity/es/ship/weapons/Bounce.java | 24 +++ api/src/infinity/sim/CoreViewConstants.java | 6 +- api/src/infinity/sim/GameEntities.java | 8 +- .../Materials/Explode0MaterialLight.j3m | 20 +++ .../Materials/Explode0MaterialUnshaded.j3m | 15 ++ .../Materials/Explode1MaterialLight.j3m | 20 +++ .../Materials/Explode1MaterialUnshaded.j3m | 15 ++ .../client/states/SISpatialFactory.java | 46 ++++- .../java/infinity/systems/ActionSystem.java | 10 +- .../java/infinity/systems/WeaponsSystem.java | 160 ++++++++++++------ 12 files changed, 292 insertions(+), 68 deletions(-) create mode 100644 api/src/infinity/es/ship/weapons/Bounce.java create mode 100644 infinity/assets/Materials/Explode0MaterialLight.j3m create mode 100644 infinity/assets/Materials/Explode0MaterialUnshaded.j3m create mode 100644 infinity/assets/Materials/Explode1MaterialLight.j3m create mode 100644 infinity/assets/Materials/Explode1MaterialUnshaded.j3m 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(); + } } }