diff --git a/source/core/assets/images/mobs/firewizard.atlas b/source/core/assets/images/mobs/firewizard.atlas new file mode 100644 index 000000000..dacee9afe --- /dev/null +++ b/source/core/assets/images/mobs/firewizard.atlas @@ -0,0 +1,160 @@ + +firewizard.png +size: 2048, 128 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +firewizard_attack + rotate: false + xy: 492, 8 + size: 96, 72 + orig: 96, 72 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 296, 8 + size: 96, 72 + orig: 96, 72 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 2, 8 + size: 96, 72 + orig: 96, 72 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 394, 8 + size: 96, 72 + orig: 96, 72 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 198, 8 + size: 96, 72 + orig: 96, 72 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 688, 11 + size: 96, 69 + orig: 96, 69 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 590, 11 + size: 96, 69 + orig: 96, 69 + offset: 0, 0 + index: -1 +firewizard_attack + rotate: false + xy: 100, 8 + size: 96, 72 + orig: 96, 72 + offset: 0, 0 + index: -1 +firewizard_death + rotate: false + xy: 1389, 16 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +firewizard_death + rotate: false + xy: 1521, 16 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +firewizard_death + rotate: false + xy: 1323, 16 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +firewizard_death + rotate: false + xy: 1587, 16 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +firewizard_death + rotate: false + xy: 1455, 16 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 1189, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 988, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +firewizard_mov + rotate: false + xy: 786, 2 + size: 66, 78 + orig: 66, 78 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 1122, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 921, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 1256, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 1055, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +firewizard_move + rotate: false + xy: 854, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 854, 2 + size: 65, 78 + orig: 65, 78 + offset: 0, 0 + index: -1 \ No newline at end of file diff --git a/source/core/assets/images/mobs/firewizard.png b/source/core/assets/images/mobs/firewizard.png new file mode 100644 index 000000000..d612b5352 Binary files /dev/null and b/source/core/assets/images/mobs/firewizard.png differ diff --git a/source/core/assets/images/mobs/necromancer.atlas b/source/core/assets/images/mobs/necromancer.atlas new file mode 100644 index 000000000..b83e6c86f --- /dev/null +++ b/source/core/assets/images/mobs/necromancer.atlas @@ -0,0 +1,167 @@ + +necromancer.png +size: 2048, 256 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +necromancer_attack + rotate: false + xy: 304, 5 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 1558, 116 + size: 70, 110 + orig: 70, 110 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 1702, 121 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 1630, 121 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 1774, 121 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 160, 5 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 88, 5 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 232, 5 + size: 70, 105 + orig: 70, 105 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 2, 112 + size: 1554, 114 + orig: 1554, 114 + offset: 0, 0 + index: -1 +necromancer_attack + rotate: false + xy: 2, 2 + size: 84, 108 + orig: 84, 108 + offset: 0, 0 + index: -1 +necromancer_death + rotate: false + xy: 601, 37 + size: 73, 73 + orig: 73, 73 + offset: 0, 0 + index: -1 +necromancer_death + rotate: false + xy: 451, 37 + size: 73, 73 + orig: 73, 73 + offset: 0, 0 + index: -1 +necromancer_death + rotate: false + xy: 376, 37 + size: 73, 73 + orig: 73, 73 + offset: 0, 0 + index: -1 +necromancer_death + rotate: false + xy: 526, 37 + size: 73, 73 + orig: 73, 73 + offset: 0, 0 + index: -1 +necromancer_death + rotate: false + xy: 1921, 153 + size: 73, 73 + orig: 73, 73 + offset: 0, 0 + index: -1 +necromancer_death + rotate: false + xy: 1846, 153 + size: 73, 73 + orig: 73, 73 + offset: 0, 0 + index: -1 +necromancer_walk + rotate: false + xy: 676, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 +necromancer_walk + rotate: false + xy: 960, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 +necromancer_walk + rotate: false + xy: 818, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 +necromancer_walk + rotate: false + xy: 1031, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 +necromancer_walk + rotate: false + xy: 889, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 +necromancer_walk + rotate: false + xy: 747, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 747, 37 + size: 69, 73 + orig: 69, 73 + offset: 0, 0 + index: -1 \ No newline at end of file diff --git a/source/core/assets/images/mobs/necromancer.png b/source/core/assets/images/mobs/necromancer.png new file mode 100644 index 000000000..c86c5cc2c Binary files /dev/null and b/source/core/assets/images/mobs/necromancer.png differ diff --git a/source/core/assets/images/mobs/rocky.atlas b/source/core/assets/images/mobs/rocky.atlas new file mode 100644 index 000000000..c29e734ba --- /dev/null +++ b/source/core/assets/images/mobs/rocky.atlas @@ -0,0 +1,174 @@ + +rocky.png +size: 512, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +rocky_death + rotate: false + xy: 359, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 449, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 395, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 341, 6 + size: 16, 17 + orig: 16, 17 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 431, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 377, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 467, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_death + rotate: false + xy: 413, 7 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 231, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 319, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 275, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 209, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 297, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 253, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_move + rotate: false + xy: 187, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 164, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 95, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 49, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 141, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 2, 2 + size: 22, 21 + orig: 22, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 26, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 118, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +rocky_attack + rotate: false + xy: 72, 2 + size: 21, 21 + orig: 21, 21 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 253, 3 + size: 20, 20 + orig: 20, 20 + offset: 0, 0 + index: -1 \ No newline at end of file diff --git a/source/core/assets/images/mobs/rocky.png b/source/core/assets/images/mobs/rocky.png new file mode 100644 index 000000000..86375354a Binary files /dev/null and b/source/core/assets/images/mobs/rocky.png differ diff --git a/source/core/assets/sounds/mobs/archerArrow.mp3 b/source/core/assets/sounds/mobs/archerArrow.mp3 new file mode 100644 index 000000000..92c4ccfab Binary files /dev/null and b/source/core/assets/sounds/mobs/archerArrow.mp3 differ diff --git a/source/core/assets/sounds/mobs/coatAttack.mp3 b/source/core/assets/sounds/mobs/coatAttack.mp3 new file mode 100644 index 000000000..bac835ddd Binary files /dev/null and b/source/core/assets/sounds/mobs/coatAttack.mp3 differ diff --git a/source/core/assets/sounds/mobs/skeletonHit.mp3 b/source/core/assets/sounds/mobs/skeletonHit.mp3 new file mode 100644 index 000000000..5634cd4e2 Binary files /dev/null and b/source/core/assets/sounds/mobs/skeletonHit.mp3 differ diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index 5f2e7bbca..ab760cf1f 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -155,7 +155,10 @@ public class ForestGameArea extends GameArea { "images/bombship/bombship.atlas", "images/mobs/coat.atlas", "images/mobs/night_borne.atlas", - "images/mobs/arcane_archer.atlas" + "images/mobs/arcane_archer.atlas", + "images/mobs/necromancer.atlas", + "images/mobs/firewizard.atlas", + "images/mobs/rocky.atlas" }; private static final String[] forestSounds = { "sounds/Impact4.ogg", @@ -197,7 +200,11 @@ public class ForestGameArea extends GameArea { "sounds/mobBoss/patrickCast.mp3", "sounds/mobBoss/patrickThunder.mp3", "sounds/mobBoss/patrickHit.mp3", - "sounds/mobBoss/spawnDemonSlime.mp3" + "sounds/mobBoss/spawnDemonSlime.mp3", + "sounds/mobs/skeletonHit.mp3", + "sounds/mobs/coatAttack.mp3", + "sounds/mobs/archerArrow.mp3" + }; private static final String backgroundMusic = "sounds/background/Sci-Fi1.ogg"; @@ -236,37 +243,6 @@ private void stopWaveTimer() { } } - /** - * Cases to spawn a wave - */ -// private void spawnWave() { -// wave++; -// switch (wave) { -// case 1: -// case 2: -// spawnFireWorm(); -// spawnDragonKnight(); -// -// break; -// case 3: -// spawnSkeleton(); -// spawnWizard(); -// // mobBoss2 = spawnMobBoss2(); -// break; -// case 4: -// spawnWaterQueen(); -// spawnWaterSlime(); -// // mobBoss2 = spawnMobBoss2(); -// -// break; -// case 5: -// spawnDemonBoss(); -// default: -// // Handle other wave scenarios if needed -// break; -// } -// } - /** * Create the game area, including terrain, static entities (trees), dynamic entities (player) */ @@ -293,6 +269,12 @@ public void create() { // spawnSplittingXenoGrunt(17, 2); // spawnPatrick(); // spawnDemonBoss(); + // spawnSplittingRocky(17, 4); + // spawnFireWizard(17, 3); + // spawnNecromancer(17, 2); + + + spawnScrap(); spawnGapScanners(); @@ -306,10 +288,9 @@ public void create() { // spawnRicochetTower(); // spawnBombship(); } - + private void displayUI() { Entity ui = new Entity(); -// ui.addComponent(new GameAreaDisplay("Box Forest")); TODO: This should be the level name? ui.addComponent(ServiceLocator.getGameEndService().getDisplay()); ui.addComponent(ServiceLocator.getCurrencyService().getDisplay()); spawnEntity(ui); @@ -469,7 +450,7 @@ public void spawnMob(String entity, GridPoint2 randomPos, int health) { mob = NPCFactory.createSkeleton(health); break; case "DeflectWizard": - mob = NPCFactory.createDeflectWizard(health); + mob = NPCFactory.createWizard(health); break; case "WaterQueen": mob = NPCFactory.createWaterQueen(health); @@ -480,7 +461,6 @@ public void spawnMob(String entity, GridPoint2 randomPos, int health) { case "IceBoss": mob = MobBossFactory.createIceBoss(health); break; - case "Coat": mob = NPCFactory.createCoat(health); break; @@ -493,7 +473,15 @@ public void spawnMob(String entity, GridPoint2 randomPos, int health) { case "ArcaneArcher": mob = NPCFactory.createDodgingArcaneArcher(health); break; - + case "SplittingRocky": + mob = NPCFactory.createSplittingRocky(health); + break; + case "Necromancer": + mob = NPCFactory.createNecromancer(health); + break; + case "DeflectFireWizard": + mob = NPCFactory.createDeflectFireWizard(health); + break; case "PatrickBoss": mob = MobBossFactory.createPatrickBoss(health); break; @@ -518,6 +506,27 @@ public void spawnMob(String entity, GridPoint2 randomPos, int health) { // xenoGrunt.setScale(1.5f, 1.5f); // spawnEntityAt(xenoGrunt, pos, true, true); // } + // * TEMPORARY FOR TESTING + private void spawnSplittingRocky(int x, int y) { + GridPoint2 pos = new GridPoint2(x, y); + Entity rocky = NPCFactory.createSplittingRocky(60); + rocky.setScale(1.5f, 1.5f); + spawnEntityAt(rocky, pos, true, true); + } + + private void spawnFireWizard(int x, int y) { + GridPoint2 pos = new GridPoint2(x, y); + Entity firewiz = NPCFactory.createDeflectFireWizard(60); + firewiz.setScale(1.5f, 1.5f); + spawnEntityAt(firewiz, pos, true, true); + } + + private void spawnNecromancer(int x, int y) { + GridPoint2 pos = new GridPoint2(x, y); + Entity Necromancer = NPCFactory.createNecromancer(60); + Necromancer.setScale(1.5f, 1.5f); + spawnEntityAt(Necromancer, pos, true, true); + } // * TEMPORARY FOR TESTING // private void spawnDodgingDragonKnight(int x, int y) { diff --git a/source/core/src/main/com/csse3200/game/components/EffectComponent.java b/source/core/src/main/com/csse3200/game/components/EffectComponent.java new file mode 100644 index 000000000..32b32e3d3 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/EffectComponent.java @@ -0,0 +1,161 @@ +package com.csse3200.game.components; + +import com.badlogic.gdx.math.Vector2; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.tower.TowerUpgraderComponent; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.physics.components.PhysicsMovementComponent; +import com.csse3200.game.services.GameTime; +import com.csse3200.game.services.ServiceLocator; + +public class EffectComponent extends Component { + private static final long EFFECT_DURATION = 5000; + private final GameTime gameTime; + // effect flags + private boolean burnFlag; + private boolean slowFlag; + private boolean isSlowed; + private boolean stunFlag; + private boolean isStunned; + private boolean mob; + private Entity host; + private Entity target; + private long lastTimeBurned; + private long burnTime; + private long slowTime; + private long stunTime; + private Vector2 defaultTargetSpeed; + private PhysicsMovementComponent targetPhysics; + private static final Vector2 STUN_SPEED = new Vector2(0f,0f); + private static final long BURN_TICK = 1000; + + public EffectComponent(boolean mob) { + this.mob = mob; + this.gameTime = ServiceLocator.getTimeSource(); + } + + public void start() { + burnTime = 0; + slowTime = 0; + stunTime = 0; + } + + @Override + public void update() { + // update effect flags + burnFlag = burnTime > gameTime.getTime(); + slowFlag = slowTime > gameTime.getTime(); + stunFlag = stunTime > gameTime.getTime(); + + // apply burn effect + if (burnFlag && gameTime.getTime() > lastTimeBurned + BURN_TICK) { + burnEffect(); + } + + // apply slow effect + if (mob) { + if (target == null) { + return; + } + if (slowFlag) { + isSlowed = true; + Vector2 half_speed = new Vector2(defaultTargetSpeed.x / 2, defaultTargetSpeed.y / 2); + targetPhysics.setSpeed(half_speed); + } else if (isSlowed) { + isSlowed = false; + targetPhysics.setSpeed(defaultTargetSpeed); + } + } else { + if (slowFlag && !isSlowed) { + isSlowed = true; + target.getEvents().trigger("upgradeTower", + TowerUpgraderComponent.UPGRADE.FIRERATE, 2); + } else if (!slowFlag && isSlowed) { + isSlowed = false; + target.getEvents().trigger("upgradeTower", + TowerUpgraderComponent.UPGRADE.FIRERATE, 5); + } + } + + // apply stun effect + if (mob) { + if (stunFlag) { + if (defaultTargetSpeed == null) { + return; + } + targetPhysics.setSpeed(STUN_SPEED); + } else if (isStunned) { + if (target == null) { + return; + } + isStunned = false; + targetPhysics.setSpeed(defaultTargetSpeed); + } + } else { + if (stunFlag && !isStunned) { + stunEffect(true); + } else if (!stunFlag && isStunned) { + stunEffect(false); + } + } + } + public void applyEffect(ProjectileEffects effect, Entity host, Entity target) { + this.host = host; + this.target = target; + + targetPhysics = entity.getComponent(PhysicsMovementComponent.class); + if (targetPhysics == null) { + return; + } + defaultTargetSpeed = targetPhysics.getNormalSpeed(); + if (defaultTargetSpeed == null) { + defaultTargetSpeed = new Vector2(1f,1f); + } + switch (effect) { + case BURN -> { + burnFlag = true; + burnTime = gameTime.getTime() + EFFECT_DURATION; + lastTimeBurned = gameTime.getTime(); + } + case SLOW -> { + slowFlag = true; + slowTime = gameTime.getTime() + EFFECT_DURATION; + } + case STUN -> { + stunFlag = true; + stunTime = gameTime.getTime() + EFFECT_DURATION; + } + case FIREBALL -> {} + } + } + + private void burnEffect() { + CombatStatsComponent hostCombat = this.host.getComponent(CombatStatsComponent.class); + CombatStatsComponent targetCombat = this.target.getComponent(CombatStatsComponent.class); + targetCombat.hit(hostCombat); + lastTimeBurned = gameTime.getTime(); + } + + private void changeSpeed(Vector2 speed) { + PhysicsMovementComponent targetPhysics = target.getComponent( + PhysicsMovementComponent.class); + if (targetPhysics == null) { + return; + } + // Set mob speed + targetPhysics.setSpeed(speed); + } + + private void stunEffect(boolean stunned) { + isStunned = true; + AITaskComponent targetAI = target.getComponent(AITaskComponent.class); + if (targetAI == null) { + return; + } + if (stunned) { + targetAI.disposeAll(); + } else { + targetAI.restore(); + } + } +} \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/components/EffectsComponent.java b/source/core/src/main/com/csse3200/game/components/EffectsComponent.java index 10b8806a5..596bb71f2 100644 --- a/source/core/src/main/com/csse3200/game/components/EffectsComponent.java +++ b/source/core/src/main/com/csse3200/game/components/EffectsComponent.java @@ -75,16 +75,10 @@ private void onCollisionEnd(Fixture me, Fixture other) { } // Apply effect - if (effect == ProjectileEffects.FIREBALL) { - if (aoe) { - applyAoeEffect(ProjectileEffects.FIREBALL); - } + if (aoe) { + applyAoeEffect(effect); } else { - if (aoe) { - applyAoeEffect(effect); - } else { - applySingleEffect(effect, otherCombatStats, otherEntity); - } + applySingleEffect(effect, otherEntity); } } @@ -92,7 +86,7 @@ private void onCollisionEnd(Fixture me, Fixture other) { * Used for singe targeting projectiles to apply effects entity it collides with. * @param effect effect to be applied to entity */ - public void applySingleEffect(ProjectileEffects effect, CombatStatsComponent targetCombatStats, Entity targetEntity) { + public void applySingleEffect(ProjectileEffects effect, Entity targetEntity) { Entity hostEntity = getEntity(); CombatStatsComponent hostCombatStats = hostEntity.getComponent(CombatStatsComponent.class); @@ -101,15 +95,12 @@ public void applySingleEffect(ProjectileEffects effect, CombatStatsComponent tar return; } - // Apply effect - switch (effect) { - case FIREBALL -> {} - case BURN -> { - burnEffect(targetCombatStats, hostCombatStats); - } - case SLOW -> {slowEffect(targetEntity);} - case STUN -> {stunEffect(targetEntity);} + // apply effect + EffectComponent effectComponent = targetEntity.getComponent(EffectComponent.class); + if (effectComponent == null) { + return; } + effectComponent.applyEffect(effect, hostEntity, targetEntity); } /** * Used for aoe projectiles to apply effects to all entities within the area of effect (radius). @@ -137,19 +128,12 @@ public void applyAoeEffect(ProjectileEffects effect) { return; } - CombatStatsComponent targetCombatStats = targetEntity.getComponent(CombatStatsComponent.class); - if (targetCombatStats != null) { - switch (effect) { - case FIREBALL -> {fireballEffect(targetCombatStats, hostCombatStats);} - case BURN -> {burnEffect(targetCombatStats, hostCombatStats);} - case SLOW -> {slowEffect(targetEntity);} - case STUN -> { - stunEffect(targetEntity); - } - } - } else { + // apply effect + EffectComponent effectComponent = targetEntity.getComponent(EffectComponent.class); + if (effectComponent == null) { return; } + effectComponent.applyEffect(effect, hostEntity, targetEntity); } } @@ -162,35 +146,35 @@ private void fireballEffect(CombatStatsComponent target, CombatStatsComponent ho target.hit(host); } - /** - * Applies 5 ticks of damage from hosts' CombatStatsComponent over 5 seconds - * @param target CombatStatsComponent of entity hit by projectile - * @param host CombatStatsComponent of projectile - */ - private void burnEffect(CombatStatsComponent target, CombatStatsComponent host) { - // Ensure burn effects aren't applied multiple times by same projectile - if (burnEntities.contains(target, false)) { - return; - } - burnEntities.add(target); - // Create a timer task to apply the effect repeatedly - int numberOfTicks = 5; - long delay = 1; - Timer.schedule(new Timer.Task() { - private int count = 0; - - @Override - public void run() { - if (count < numberOfTicks) { - target.hit(host); - count++; - } else { - // Ensure to cancel the task when it's done - this.cancel(); - } - } - }, delay, delay); - } +// /** +// * Applies 5 ticks of damage from hosts' CombatStatsComponent over 5 seconds +// * @param target CombatStatsComponent of entity hit by projectile +// * @param host CombatStatsComponent of projectile +// */ +// private void burnEffect(CombatStatsComponent target, CombatStatsComponent host) { +// // Ensure burn effects aren't applied multiple times by same projectile +// if (burnEntities.contains(target, false)) { +// return; +// } +// burnEntities.add(target); +// // Create a timer task to apply the effect repeatedly +// int numberOfTicks = 5; +// long delay = 1; +// Timer.schedule(new Timer.Task() { +// private int count = 0; +// +// @Override +// public void run() { +// if (count < numberOfTicks) { +// target.hit(host); +// count++; +// } else { +// // Ensure to cancel the task when it's done +// this.cancel(); +// } +// } +// }, delay, delay); +// } /** * Applies slow effect to targetEntity. If entity is a mob, speed @@ -262,22 +246,22 @@ private void stunEffect(Entity targetEntity) { if (stunnedEntities.contains(targetEntity)) { return; } - + taskComponent.disposeAll(); stunnedEntities.add(targetEntity); - - new java.util.Timer().schedule( - new java.util.TimerTask() { - @Override - public void run() { - taskComponent.restore(); - for (int i = 0; i < stunnedEntities.size(); i++) { - if (stunnedEntities.get(i).equals(targetEntity)) { - stunnedEntities.remove(stunnedEntities.get(i)); + + new java.util.Timer().schedule( + new java.util.TimerTask() { + @Override + public void run() { + taskComponent.restore(); + for (int i = 0; i < stunnedEntities.size(); i++) { + if (stunnedEntities.get(i).equals(targetEntity)) { + stunnedEntities.remove(stunnedEntities.get(i)); + } + } + this.cancel(); } - } - this.cancel(); - } - }, 5000); + }, 5000); } -} +} \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/components/RicochetComponent.java b/source/core/src/main/com/csse3200/game/components/RicochetComponent.java index 4203dfa6a..37c8fce6b 100644 --- a/source/core/src/main/com/csse3200/game/components/RicochetComponent.java +++ b/source/core/src/main/com/csse3200/game/components/RicochetComponent.java @@ -16,8 +16,8 @@ public class RicochetComponent extends Component { private short targetLayer; private HitboxComponent hitBoxComponent; private int bounceCount; - private static int MAX_BOUNCE_Y_DIRECTION = 250; - private static int MIN_BOUNCE_Y_DIRECTION = -250; + private static final int MAX_BOUNCE_Y_DIRECTION = 250; + private static final int MIN_BOUNCE_Y_DIRECTION = -250; /** * Initialise a RicochetComponent that spawns another projectile upon collision. @@ -60,10 +60,10 @@ private void onCollisionEnd(Fixture me, Fixture other) { // Spawning of the projectile to be above (+ve) or below (-ve) upon // collision - int up_or_down = randomDirection <= 0 ? -1 : 1; + int upOrDown = randomDirection <= 0 ? -1 : 1; float newXPosition = (float) (projectile.getPosition().x - 0.75); - float newYPosition = (float) (projectile.getPosition().y + (0.65 * up_or_down)); + float newYPosition = (float) (projectile.getPosition().y + (0.65 * upOrDown)); // Prevent spawn of new projectile if it goes out of boundaries. if (newYPosition >= 8 || newYPosition <= 1 || newXPosition >= 17 || newXPosition <= 1) diff --git a/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java b/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java index 0a53d7d4b..09f5fcdc3 100644 --- a/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java +++ b/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java @@ -17,8 +17,8 @@ public class SplitFireworksComponent extends Component { private short targetLayer; private HitboxComponent hitboxComponent; private int amount; - private static int TOTAL_RANGE = 450; - private static double SPAWN_OFFSET_X = 1.75; + private static final int TOTAL_RANGE = 450; + private static final double SPAWN_OFFSET_X = 1.75; /** * Initialises a component that splits the projectile into multiple fireballs @@ -60,9 +60,9 @@ private void onCollisionEnd(Fixture me, Fixture other) { // * RIGHT NOW TARGET IS NPC, SUBJECT TO CHANGE // Speed is a bit faster than normal but can change. Entity newProjectile = ProjectileFactory.createFireworks(PhysicsLayer.NPC, - new Vector2(100, (float) (projectile.getPosition().y + (newDirection - (double) (TOTAL_RANGE/2)))), new Vector2(3f, 3f)); + new Vector2(100, (float) (projectile.getPosition().y + (newDirection - ((double) TOTAL_RANGE) / 2))), new Vector2(3f, 3f)); - newProjectile.setPosition(newXPosition, (float) projectile.getPosition().y); + newProjectile.setPosition(newXPosition, projectile.getPosition().y); newProjectile.setScale(0.5f, 0.5f); diff --git a/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java b/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java index 64678b2c0..2ff88df7e 100644 --- a/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java +++ b/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java @@ -29,7 +29,6 @@ public class TouchAttackComponent extends Component { private short targetLayer; private float knockbackForce = 0f; private boolean disposeOnHit = false; - private int aoeSize = 0; private CombatStatsComponent combatStats; private HitboxComponent hitboxComponent; diff --git a/source/core/src/main/com/csse3200/game/components/bosses/IceBabyAnimationController.java b/source/core/src/main/com/csse3200/game/components/bosses/IceBabyAnimationController.java index 96672a688..b12817cb9 100644 --- a/source/core/src/main/com/csse3200/game/components/bosses/IceBabyAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/bosses/IceBabyAnimationController.java @@ -38,7 +38,7 @@ public class IceBabyAnimationController extends Component { Sound mobSpawnSound = ServiceLocator.getResourceService().getAsset( MOB_SPAWN_SOUND, Sound.class); private static final String AOE_SOUND = "sounds/mobBoss/iceBabyAOE.mp3"; - Sound AOESound = ServiceLocator.getResourceService().getAsset( + Sound aoeSound = ServiceLocator.getResourceService().getAsset( AOE_SOUND, Sound.class); @Override @@ -70,8 +70,8 @@ void animateATK2() { } void animateATK3() { animator.startAnimation(ATK3_ANIM); - AOESound.setVolume(1000, 5.5f); - AOESound.play(); + aoeSound.setVolume(1000, 5.5f); + aoeSound.play(); } void animateDeath() { animator.startAnimation(DEATH_ANIM); diff --git a/source/core/src/main/com/csse3200/game/components/maingame/MainGameDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/MainGameDisplay.java index 88b7b7b8b..dcf22a4a2 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/MainGameDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/MainGameDisplay.java @@ -15,6 +15,8 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Array; import com.csse3200.game.GdxGame; +import com.csse3200.game.components.pausemenu.PauseMenuButtonComponent; +import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.PauseMenuFactory; import com.csse3200.game.screens.TowerType; import com.csse3200.game.services.ServiceLocator; @@ -32,10 +34,18 @@ public class MainGameDisplay extends UIComponent { private static final float Z_INDEX = 2f; private final Table towerTable = new Table(); private final Table buttonTable = new Table(); + private final Table progressTable = new Table(); + private final Table levelNameTable = new Table(); private final String[] sounds = { "sounds/ui/click/click_01.ogg", "sounds/ui/open_close/open_01.ogg" }; + private String level; + private static final String[] levels = { + "Desert Planet", + "Ice Planet", + "Lava Planet" + }; private Sound click; private Sound openSound; private final GdxGame game; @@ -46,13 +56,16 @@ public class MainGameDisplay extends UIComponent { private ImageButton tower3; private ImageButton tower4; private ImageButton tower5; + private LevelProgressBar progressbar; + private Entity pauseMenu; /** * The constructor for the display * @param screenSwitchHandle a handle back to the game entry point that manages screen switching */ - public MainGameDisplay(GdxGame screenSwitchHandle) { + public MainGameDisplay(GdxGame screenSwitchHandle, int level) { game = screenSwitchHandle; + this.level = levels[level]; } /** @@ -73,15 +86,21 @@ private void addActors() { // Create and position the tables that will hold the buttons. // Contains the tower build menu buttons - towerTable.top().padTop(80f); + towerTable.top().padTop(50f); towerTable.setFillParent(true); towerTable.setDebug(true); // Contains other buttons (just pause at this stage) - buttonTable.top().right().padTop(80f).padRight(80f); + buttonTable.top().right().padTop(50f).padRight(80f); buttonTable.setFillParent(true); + progressTable.top().center().setWidth(500f); + progressTable.setFillParent(true); + + levelNameTable.top().left().padLeft(20f).padTop(20f); + levelNameTable.setFillParent(true); + // Stores tower defaults, in case towers haven't been set in the tower select screen TowerType[] defaultTowers = { TowerType.TNT, @@ -144,17 +163,20 @@ public void changed(ChangeEvent changeEvent, Actor actor) { } }); + // Pause menu escape key opening listener stage.addListener( new InputListener() { @Override public boolean keyUp(InputEvent event, int keycode) { if ((keycode == Input.Keys.ESCAPE) && !ServiceLocator.getTimeSource().getPaused()) { - game.getScreen().pause(); openSound.play(0.4f); - PauseMenuFactory.createPauseMenu(game); + pauseMenu = PauseMenuFactory.createPauseMenu(game); ServiceLocator.getTimeSource().setPaused(true); return true; + } else if ((keycode == Input.Keys.ESCAPE) && ServiceLocator.getTimeSource().getPaused()) { + pauseMenu.dispose(); + return false; } return false; } @@ -283,19 +305,35 @@ public void clicked(InputEvent event, float x, float y) { TextTooltip tower5Tooltip = new TextTooltip(towers.get(4).getDescription(), getSkin()); tower5.addListener(tower5Tooltip); + progressbar = new LevelProgressBar(500, 10); + + levelNameTable.setSkin(getSkin()); + levelNameTable.add(this.level, "title"); // Scale all the tower build buttons down // Add all buttons to their respective tables and position them + towerTable.setSkin(getSkin()); towerTable.add(tower1).padRight(10f); towerTable.add(tower2).padRight(10f); towerTable.add(tower3).padRight(10f); towerTable.add(tower4).padRight(10f); towerTable.add(tower5).padRight(10f); + towerTable.row(); + towerTable.add("1", "small"); + towerTable.add("2", "small"); + towerTable.add("3", "small"); + towerTable.add("4", "small"); + towerTable.add("5", "small"); + towerTable.row().colspan(5).pad(20f); + towerTable.add(progressbar).fillX(); + buttonTable.add(pauseBtn); // Add tables to the stage + stage.addActor(buttonTable); stage.addActor(towerTable); + stage.addActor(levelNameTable); // Animate the tower select buttons int tower1Gap = Gdx.graphics.getWidth() /2 + (int) towerTable.getX()/2 + 400; @@ -320,6 +358,11 @@ public void draw(SpriteBatch batch) { towerUpdate(); } + public void updateLevelProgressBar() { + float totalSecs = ((float) ServiceLocator.getTimeSource().getTime() / 1000); + progressbar.setValue(totalSecs); + } + /** * Update function for the tower build menu buttons that is called with every draw, updates button states * depending on button selection and currency balance @@ -342,6 +385,7 @@ private void towerUpdate() { for (int i = 0; i < towerButtons.size; i++) { towerButtons.get(i).setDisabled(Integer.parseInt(towers.get(i).getPrice()) > balance); } + updateLevelProgressBar(); } /** @@ -356,13 +400,11 @@ private void towerToggle(ImageButton towerButton) { // set all buttons to off, disable if isDisabled for (ImageButton button : towerButtons) { button.setChecked(false); -// button.setDisabled(isDisabled); } } else { // set the button corresponding to towerButton to on, all others to off for (ImageButton button : towerButtons) { button.setChecked(button == towerButton); -// button.setDisabled(isDisabled && button == towerButton); } } } diff --git a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java index cad530e53..6b0d93bf1 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java @@ -28,7 +28,6 @@ public class UIElementsDisplay extends UIComponent { private final Table buttonTable = new Table(); private TextButton remainingMobsButton; private TextButton timerButton; - private LevelProgressBar progressbar; @Override public void create() { @@ -43,31 +42,23 @@ private void addActors() { remainingMobsButton = ButtonFactory.createButton("Mobs:" + ServiceLocator.getWaveService().getEnemyCount()); + remainingMobsButton.setPosition(Gdx.graphics.getWidth(), Gdx.graphics.getHeight() - 230); remainingMobsButton.addAction(new SequenceAction(Actions.moveTo(Gdx.graphics.getWidth() - 218, Gdx.graphics.getHeight() - 230, 1f, Interpolation.fastSlow))); - buttonTable.top().right().padTop(160f).padRight(80f); + buttonTable.top().right().padTop(130f).padRight(80f); buttonTable.setFillParent(true); - buttonTable.add(remainingMobsButton).right();//.padTop(10f).padRight(10f); + buttonTable.add(remainingMobsButton).right(); buttonTable.row(); - buttonTable.add(timerButton);//.padRight(10f); + buttonTable.add(timerButton); stage.addActor(buttonTable); - progressbar = new LevelProgressBar(500, 10); - progressbar.setPosition(500, Gdx.graphics.getHeight() - 200); - stage.addActor(progressbar); - createTimerButton(); } - public void updateLevelProgressBar() { - float totalSecs = ((float) ServiceLocator.getTimeSource().getTime() / 1000); - progressbar.setValue(totalSecs); - } - /** * This method updates the mob count button as mobs die in the game */ @@ -88,8 +79,6 @@ public void changed(ChangeEvent event, Actor actor) { */ public void createTimerButton() { -// timerButton = new ButtonFactory().createButton("Next wave in:" -// + (ServiceLocator.getWaveService().getNextWaveTime() / 1000)); timerButton = ButtonFactory.createButton("Next wave in:" + (ServiceLocator.getWaveService().getNextWaveTime() / 1000)); timerButton.setPosition(Gdx.graphics.getWidth(), Gdx.graphics.getHeight() - 300); @@ -103,27 +92,28 @@ public void createTimerButton() { * This method updates the text for timer button. */ public void updateTimerButton() { - int totalSecs = (int) ((ServiceLocator.getWaveService().getNextWaveTime() - - ServiceLocator.getTimeSource().getTime()) / 1000); + if (!(ServiceLocator.getWaveService().getGamePaused())) { + int totalSecs = (int) ((ServiceLocator.getWaveService().getNextWaveTime() + - ServiceLocator.getTimeSource().getTime()) / 1000); - // TODO : THESE SHOULD BE REMOVED AND PLACED WHEREVER THE BOSS MOB GETS SPAWNED - if (totalSecs % 20 == 0) { + // TODO : THESE SHOULD BE REMOVED AND PLACED WHEREVER THE BOSS MOB GETS SPAWNED + if (totalSecs % 20 == 0) { ServiceLocator.getMapService().shakeCameraMap(); ServiceLocator.getMapService().shakeCameraGrid(); - } - int seconds = totalSecs % 60; - int minutes = (totalSecs % 3600) / 60; - String finalTime = String.format("%02d:%02d", minutes, seconds); - if (ServiceLocator.getTimeSource().getTime() < ServiceLocator.getWaveService().getNextWaveTime()) { - if (!findActor(timerButton)) { - createTimerButton(); } - timerButton.setText("Next wave in: " + finalTime); - } else { - timerButton.addAction(new SequenceAction(Actions.fadeOut(1f), Actions.removeActor())); -// buttonTable.removeActor(timerButton); - stage.act(); - stage.draw(); + int seconds = totalSecs % 60; + int minutes = (totalSecs % 3600) / 60; + String finalTime = String.format("%02d:%02d", minutes, seconds); + if (ServiceLocator.getTimeSource().getTime() < ServiceLocator.getWaveService().getNextWaveTime()) { + if (!findActor(timerButton)) { + createTimerButton(); + } + timerButton.setText("Next wave in: " + finalTime); + } else { + timerButton.addAction(new SequenceAction(Actions.fadeOut(1f), Actions.removeActor())); + stage.act(); + stage.draw(); + } } } @@ -161,6 +151,5 @@ public float getZIndex() { public void dispose() { super.dispose(); buttonTable.clear(); - progressbar.clear(); } } diff --git a/source/core/src/main/com/csse3200/game/components/npc/ArcaneArcherAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/ArcaneArcherAnimationController.java index 2b63d0359..71fa5359d 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/ArcaneArcherAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/ArcaneArcherAnimationController.java @@ -4,6 +4,7 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.ServiceLocator; + import java.security.SecureRandom; /** @@ -18,6 +19,9 @@ public class ArcaneArcherAnimationController extends Component { AnimationRenderComponent animator; private SecureRandom rand = new SecureRandom(); + private static final String ATTACK_SOUND = "sounds/mobs/archerArrow.mp3"; + Sound attackSound = ServiceLocator.getResourceService().getAsset( + ATTACK_SOUND, Sound.class); @Override public void create() { @@ -28,7 +32,6 @@ public void create() { entity.getEvents().addListener("mob_death", this::animateDeath); entity.getEvents().addListener("mob_dodge", this::animateDodge); - } void animateWalk() { @@ -37,6 +40,8 @@ void animateWalk() { void animateAttack() { animator.startAnimation("arcane_archer_attack"); + attackSound.setVolume(1000, 5.5f); + attackSound.play(); } void animateDeath() { diff --git a/source/core/src/main/com/csse3200/game/components/npc/Boss1AnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/Boss1AnimationController.java new file mode 100644 index 000000000..85759befd --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/npc/Boss1AnimationController.java @@ -0,0 +1,49 @@ +package com.csse3200.game.components.npc; + +import com.csse3200.game.components.Component; +import com.csse3200.game.rendering.AnimationRenderComponent; + +/** + * This class listens to events relevant to a ghost entity's state and plays the animation when one + * of the events is triggered. + */ +public class Boss1AnimationController extends Component { + AnimationRenderComponent animator; + + @Override + public void create() { + super.create(); + animator = this.entity.getComponent(AnimationRenderComponent.class); + entity.getEvents().addListener("walkStart", this::animateWalk); + entity.getEvents().addListener("deadStart", this::animateDead); + entity.getEvents().addListener("idleStart", this::animateIdle); + entity.getEvents().addListener("chargingStart", this::animateCharging); + entity.getEvents().addListener("attack1Start", this::animateAttack1); + entity.getEvents().addListener("attack2Start", this::animateAttack2); + entity.getEvents().addListener("hurtStart", this::animateHurt); + } + + void animateHurt() { + animator.startAnimation("Hurt"); + } + void animateAttack2() { + animator.startAnimation("A2"); + } + void animateAttack1() { + animator.startAnimation("A1"); + } + void animateCharging() { + animator.startAnimation("Charging"); + } + void animateIdle() { + animator.startAnimation("Idle"); + } + + void animateDead() { + animator.startAnimation("boss_death"); + } + + void animateWalk() { + animator.startAnimation("Walk"); + } +} diff --git a/source/core/src/main/com/csse3200/game/components/npc/Boss2AnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/Boss2AnimationController.java new file mode 100644 index 000000000..bee80ad23 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/npc/Boss2AnimationController.java @@ -0,0 +1,49 @@ +package com.csse3200.game.components.npc; + +import com.csse3200.game.components.Component; +import com.csse3200.game.rendering.AnimationRenderComponent; + +/** + * This class listens to events relevant to a ghost entity's state and plays the animation when one + * of the events is triggered. + */ +public class Boss2AnimationController extends Component { + AnimationRenderComponent animator; + + @Override + public void create() { + super.create(); + animator = this.entity.getComponent(AnimationRenderComponent.class); + entity.getEvents().addListener("walkStart", this::animateWalk); + entity.getEvents().addListener("deadStart", this::animateDead); + entity.getEvents().addListener("idleStart", this::animateIdle); + entity.getEvents().addListener("chargingStart", this::animateCharging); + entity.getEvents().addListener("attack1Start", this::animateAttack1); + entity.getEvents().addListener("attack2Start", this::animateAttack2); + entity.getEvents().addListener("hurtStart", this::animateHurt); + } + + void animateHurt() { + animator.startAnimation("Hurt"); + } + void animateAttack2() { + animator.startAnimation("A2"); + } + void animateAttack1() { + animator.startAnimation("A1"); + } + void animateCharging() { + animator.startAnimation("Charging"); + } + void animateIdle() { + animator.startAnimation("Idle"); + } + + void animateDead() { + animator.startAnimation("boss_death"); + } + + void animateWalk() { + animator.startAnimation("Walk"); + } +} diff --git a/source/core/src/main/com/csse3200/game/components/npc/CoatAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/CoatAnimationController.java index 126054abe..e9bf8170e 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/CoatAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/CoatAnimationController.java @@ -4,6 +4,7 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.ServiceLocator; + import java.security.SecureRandom; /** @@ -17,6 +18,10 @@ public class CoatAnimationController extends Component { // COLLISION_SFX, Sound.class); AnimationRenderComponent animator; private SecureRandom rand = new SecureRandom(); + + private static final String ATTACK_SOUND = "sounds/mobs/coatAttack.mp3"; + Sound attackSound = ServiceLocator.getResourceService().getAsset( + ATTACK_SOUND, Sound.class); @Override @@ -26,8 +31,6 @@ public void create() { entity.getEvents().addListener("mob_walk", this::animateWalk); entity.getEvents().addListener("mob_attack", this::animateAttack); entity.getEvents().addListener("mob_death", this::animateDeath); - - } void animateWalk() { @@ -36,6 +39,8 @@ void animateWalk() { void animateAttack() { animator.startAnimation("coat_attack"); + attackSound.setVolume(1000, 5.5f); + attackSound.play(); } void animateDeath() { diff --git a/source/core/src/main/com/csse3200/game/components/npc/DragonKnightAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/DragonKnightAnimationController.java index 8466e1e23..6d9d54215 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/DragonKnightAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/DragonKnightAnimationController.java @@ -1,9 +1,7 @@ package com.csse3200.game.components.npc; -import com.badlogic.gdx.audio.Sound; import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.ServiceLocator; import java.security.SecureRandom; /** diff --git a/source/core/src/main/com/csse3200/game/components/npc/FirewizardAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/FirewizardAnimationController.java new file mode 100644 index 000000000..267c23404 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/npc/FirewizardAnimationController.java @@ -0,0 +1,36 @@ +package com.csse3200.game.components.npc; + +import com.csse3200.game.components.Component; +import com.csse3200.game.rendering.AnimationRenderComponent; + +import java.security.SecureRandom; + +public class FirewizardAnimationController extends Component { + + AnimationRenderComponent animator; + private SecureRandom rand = new SecureRandom(); + + + @Override + public void create() { + super.create(); + animator = this.entity.getComponent(AnimationRenderComponent.class); + entity.getEvents().addListener("mob_walk", this::animateWalk); + entity.getEvents().addListener("mob_attack", this::animateAttack); + entity.getEvents().addListener("mob_death", this::animateDeath); + + + } + + void animateWalk() { + animator.startAnimation("firewizard_move"); + } + + void animateAttack() { + animator.startAnimation("firewizard_attack"); + } + + void animateDeath() { + animator.startAnimation("firewizard_death"); + } +} diff --git a/source/core/src/main/com/csse3200/game/components/npc/NecromancerAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/NecromancerAnimationController.java new file mode 100644 index 000000000..3bdad9407 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/npc/NecromancerAnimationController.java @@ -0,0 +1,36 @@ +package com.csse3200.game.components.npc; + +import com.csse3200.game.components.Component; +import com.csse3200.game.rendering.AnimationRenderComponent; + +import java.security.SecureRandom; + +public class NecromancerAnimationController extends Component { + + AnimationRenderComponent animator; + private SecureRandom rand = new SecureRandom(); + + + @Override + public void create() { + super.create(); + animator = this.entity.getComponent(AnimationRenderComponent.class); + entity.getEvents().addListener("mob_walk", this::animateWalk); + entity.getEvents().addListener("mob_attack", this::animateAttack); + entity.getEvents().addListener("mob_death", this::animateDeath); + + + } + + void animateWalk() { + animator.startAnimation("necromancer_walk"); + } + + void animateAttack() { + animator.startAnimation("necromancer_attack"); + } + + void animateDeath() { + animator.startAnimation("necromancer_death"); + } +} diff --git a/source/core/src/main/com/csse3200/game/components/npc/NightBorneAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/NightBorneAnimationController.java index 53bad45c2..d821f6cca 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/NightBorneAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/NightBorneAnimationController.java @@ -1,9 +1,7 @@ package com.csse3200.game.components.npc; -import com.badlogic.gdx.audio.Sound; import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.ServiceLocator; import java.security.SecureRandom; /** diff --git a/source/core/src/main/com/csse3200/game/components/npc/RockyAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/RockyAnimationController.java new file mode 100644 index 000000000..f6743dd9d --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/npc/RockyAnimationController.java @@ -0,0 +1,36 @@ +package com.csse3200.game.components.npc; + +import com.csse3200.game.components.Component; +import com.csse3200.game.rendering.AnimationRenderComponent; + +import java.security.SecureRandom; + +public class RockyAnimationController extends Component { + AnimationRenderComponent animator; + private SecureRandom rand = new SecureRandom(); + + + @Override + public void create() { + super.create(); + animator = this.entity.getComponent(AnimationRenderComponent.class); + entity.getEvents().addListener("mob_walk", this::animateWalk); + entity.getEvents().addListener("mob_attack", this::animateAttack); + entity.getEvents().addListener("mob_death", this::animateDeath); + + + } + + void animateWalk() { + animator.startAnimation("rocky_move"); + } + + void animateAttack() { + animator.startAnimation("rocky_attack"); + } + + void animateDeath() { + animator.startAnimation("rocky_death"); + } + +} diff --git a/source/core/src/main/com/csse3200/game/components/npc/SkeletonAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/SkeletonAnimationController.java index cba3eacdb..d5ea57bfa 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/SkeletonAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/SkeletonAnimationController.java @@ -23,6 +23,10 @@ public class SkeletonAnimationController extends Component { Sound deathSound = ServiceLocator.getResourceService().getAsset( ATTACK_SOUND, Sound.class); + private static final String DEATH_SOUND = "sounds/mobs/skeletonHit.mp3"; + Sound attackSound = ServiceLocator.getResourceService().getAsset( + DEATH_SOUND, Sound.class); + @Override public void create() { super.create(); @@ -38,6 +42,8 @@ void animateWalk() { void animateAttack() { animator.startAnimation("skeleton_attack"); + attackSound.setVolume(1000, 0); + attackSound.play(); } void animateDeath() { diff --git a/source/core/src/main/com/csse3200/game/components/npc/SplitMoblings.java b/source/core/src/main/com/csse3200/game/components/npc/SplitMoblings.java index bb8578345..5896c2f10 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/SplitMoblings.java +++ b/source/core/src/main/com/csse3200/game/components/npc/SplitMoblings.java @@ -1,6 +1,7 @@ package com.csse3200.game.components.npc; import com.csse3200.game.components.Component; +import com.csse3200.game.components.tasks.mobtask.MobType; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.NPCFactory; import com.csse3200.game.services.ServiceLocator; @@ -17,24 +18,29 @@ */ public class SplitMoblings extends Component { private int amount; - private float scaleX, scaleY; + private MobType mobType; + private int baseMoblingHealth = 60; + private float scaleX; + private float scaleY; public static final float DEFAULT_MINIFIED_SCALE = 0.75f; public static final double OFFSET_DISTANCE = 1.5; public static final int FULL_CIRCLE_ANGLE = 360; public static final float MIN_X_BOUNDS = 1; public static final float MAX_X_BOUNDS = (float) 18.5; public static final float MIN_Y_BOUNDS = 0; - public static final float MAX_Y_BOUNDS = 6; + public static final float MAX_Y_BOUNDS = 5; public static final String DIE_START_EVENT = "splitDeath"; /** * Initialises a component that splits mob into multiple moblings. Amount of * moblings split based on the amount provided param. * - * @param amount Amount of moblings to be split. + * @param mobType Type of moblings split on death based on the MobType enum. + * @param amount Amount of moblings to be split. * @require amount > 0 */ - public SplitMoblings(int amount) { + public SplitMoblings(MobType mobType, int amount) { + this.mobType = mobType; this.amount = amount; scaleX = scaleY = DEFAULT_MINIFIED_SCALE; } @@ -44,12 +50,15 @@ public SplitMoblings(int amount) { * moblings split is based on the amount provided param. * The overalling scaling (x and y) is also altered in the param. * - * @param amount Amount of moblings to be split. - * @param scale X and Y scaling of the moblings in respect to the original size - * of the mobs. + * @param mobType Type of moblings split on death based on the MobType enum. + * @param amount Amount of moblings to be split. + * @param scale X and Y scaling of the moblings in respect to the original + * size + * of the mobs. * @require amount > 0 */ - public SplitMoblings(int amount, float scale) { + public SplitMoblings(MobType mobType, int amount, float scale) { + this.mobType = mobType; this.amount = amount; this.scaleX = this.scaleY = scale; } @@ -59,12 +68,14 @@ public SplitMoblings(int amount, float scale) { * moblings split is based on the amount provided param. * The individual scaling (x and y) is also altered in the param. * - * @param amount Amount of moblings to be split. - * @param scaleX X scaling of the moblings compared to original size. - * @param scaleY Y scaling of the moblings compared to original size. + * @param mobType Type of moblings split on death based on the MobType enum. + * @param amount Amount of moblings to be split. + * @param scaleX X scaling of the moblings compared to original size. + * @param scaleY Y scaling of the moblings compared to original size. * @require amount > 0 */ - public SplitMoblings(int amount, float scaleX, float scaleY) { + public SplitMoblings(MobType mobType, int amount, float scaleX, float scaleY) { + this.mobType = mobType; this.amount = amount; this.scaleX = scaleX; this.scaleY = scaleY; @@ -96,7 +107,7 @@ private void onDeath() { // Inspired by: // https://stackoverflow.com/questions/37145768/distribute-points-evenly-on-circle-circumference-in-quadrants-i-and-iv-only for (int i = 0; i < amount; i++) { - float currAngle = (float) (360 / amount) * i; + float currAngle = FULL_CIRCLE_ANGLE / (float) amount * i; double radians = currAngle * Math.PI / 180; float newX = entity.getPosition().x + (float) OFFSET_DISTANCE * @@ -122,15 +133,41 @@ private void onDeath() { */ public void spawnAdditionalMob(float positionX, float positionY, float initialScaleX, float initialScaleY) { - // MAKE A SWITCH CASE STATEMENT HERE, ASK JASON HOW TO // Entity waterSlime = NPCFactory.createBaseWaterSlime(60); - Entity waterSlime = NPCFactory.createNightBorne(60); - waterSlime.setPosition(positionX, positionY); + Entity entityType; + switch (mobType) { + case WATER_SLIME -> { + entityType = NPCFactory.createBaseWaterSlime(baseMoblingHealth); + } + + case NIGHT_BORNE -> { + entityType = NPCFactory.createNightBorne(baseMoblingHealth); + } + + case ROCKY -> { + entityType = NPCFactory.createRocky(baseMoblingHealth); + } + + default -> { + entityType = NPCFactory.createBaseWaterSlime(baseMoblingHealth); + } + } + + entityType.setPosition(positionX, positionY); + + switch (mobType) { + case NIGHT_BORNE -> { + entityType.setScale(initialScaleX, initialScaleY); + } + default -> { + entityType.setScale(initialScaleX * scaleX, initialScaleY * scaleY); + } + } + - waterSlime.setScale(initialScaleX * scaleX, initialScaleY * scaleY); - // waterSlime.setScale(initialScaleX, initialScaleY); + ServiceLocator.getEntityService().register(entityType); - ServiceLocator.getEntityService().register(waterSlime); + // ServiceLocator.getWaveService().setEnemyCount(ServiceLocator.getWaveService().getEnemyCount() + 1); //ServiceLocator.getWaveService().setEnemyCount(ServiceLocator.getWaveService().getEnemyCount() + 1); } @@ -150,7 +187,6 @@ private boolean withinBounds(float currX, float currY) { && currY <= MAX_Y_BOUNDS) { return true; } - ; return false; } } diff --git a/source/core/src/main/com/csse3200/game/components/npc/WaterSlimeAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/WaterSlimeAnimationController.java index 03adc1466..6909dad10 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/WaterSlimeAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/WaterSlimeAnimationController.java @@ -1,9 +1,7 @@ package com.csse3200.game.components.npc; -import com.badlogic.gdx.audio.Sound; import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.ServiceLocator; import java.security.SecureRandom; /** diff --git a/source/core/src/main/com/csse3200/game/components/npc/XenoAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/XenoAnimationController.java index 6c0d80159..d07dc4683 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/XenoAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/XenoAnimationController.java @@ -1,9 +1,7 @@ package com.csse3200.game.components.npc; -import com.badlogic.gdx.audio.Sound; import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.ServiceLocator; import java.security.SecureRandom; /** diff --git a/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuButtonComponent.java b/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuButtonComponent.java index 1a644ca19..5f37a68ed 100644 --- a/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuButtonComponent.java +++ b/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuButtonComponent.java @@ -55,7 +55,7 @@ public void create() { */ private void addActors() { - window = new Window("Game Paused", new Skin(Gdx.files.internal("images/ui/buttons/glass.json"))); + window = new Window("", new Skin(Gdx.files.internal("images/ui/buttons/glass.json"))); TextButton continueBtn = ButtonFactory.createButton("Continue"); continueBtn.pad(20f); @@ -105,23 +105,23 @@ public void changed(ChangeEvent changeEvent, Actor actor) { } }); - window.addListener( - new InputListener() { - - @Override - public boolean keyUp (InputEvent event, int keycode) { - if (keycode == Input.Keys.ESCAPE && ServiceLocator.getTimeSource().getPaused()) { - logger.debug("Closing pause menu with escape key"); - click.play(0.5f); - closeSound.play(0.5f); - ServiceLocator.getTimeSource().setPaused(false); - entity.dispose(); - return true; - } - return false; - } - } - ); +// window.addListener( +// new InputListener() { +// +// @Override +// public boolean keyUp (InputEvent event, int keycode) { +// if (keycode == Input.Keys.ESCAPE && ServiceLocator.getTimeSource().getPaused()) { +// logger.debug("Closing pause menu with escape key"); +// click.play(0.5f); +// closeSound.play(0.5f); +// ServiceLocator.getTimeSource().setPaused(false); +// entity.dispose(); +// return true; +// } +// return false; +// } +// } +// ); // window.setKeepWithinStage(true); window.setResizable(true); @@ -168,6 +168,9 @@ public float getZIndex() { @Override public void dispose() { + click.play(0.5f); + closeSound.play(0.5f); + ServiceLocator.getTimeSource().setPaused(false); window.clear(); window.remove(); super.dispose(); diff --git a/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponent.java b/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponent.java index e2c08c105..e581d47d1 100644 --- a/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponent.java +++ b/source/core/src/main/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponent.java @@ -20,6 +20,7 @@ public PauseMenuTimeStopComponent() { */ @Override public void create() { + ServiceLocator.getWaveService().toggleGamePause(); freezeList = ServiceLocator.getEntityService().getEntities(); for (Entity pauseTarget : freezeList) { if (pauseTarget.getId() != getEntity().getId()) { @@ -35,6 +36,7 @@ public void create() { */ @Override public void dispose() { + ServiceLocator.getWaveService().toggleGamePause(); for (Entity pauseTarget : freezeList) { pauseTarget.setEnabled(true); } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobAttackTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobAttackTask.java index 141317b91..c5fc7f0bf 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobAttackTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobAttackTask.java @@ -22,7 +22,7 @@ */ public class MobAttackTask extends DefaultTask implements PriorityTask { private static final int INTERVAL = 1; // time interval to scan for towers in - private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String STOW = "wanderStart"; @@ -33,15 +33,13 @@ public class MobAttackTask extends DefaultTask implements PriorityTask { private Fixture target; private final int priority; - private final float maxRange; - private Vector2 mobPosition = new Vector2(10f,10f); private final Vector2 maxRangePosition = new Vector2(); private final PhysicsEngine physics; private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); - private final long delay = 1000; // delay between shots + private static final long DELAY = 1000; // delay between shots private long startTime; private enum STATE { @@ -54,9 +52,8 @@ private enum STATE { * @param priority Task priority when targets are detected (0 when nothing detected). Must be a positive integer. * @param maxRange Maximum effective range of the weapon mob. This determines the detection distance of targets */ - public MobAttackTask(int priority, float maxRange) { + public MobAttackTask(int priority) { this.priority = priority; - this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -70,7 +67,7 @@ public MobAttackTask(int priority, float maxRange) { public void start() { super.start(); startTime = timeSource.getTime(); - this.mobPosition = owner.getEntity().getCenterPosition(); + Vector2 mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); @@ -122,25 +119,22 @@ public void updateMobState() { if (!isTargetVisible() || this.meleeOrProjectile() == null) { this.owner.getEntity().getEvents().trigger(STOW); mobState = STATE.STOW; - } else { - if (this.meleeOrProjectile() instanceof Melee) { + } else if (this.meleeOrProjectile() instanceof Melee) { TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class); HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class); attackComp.onCollisionStart(hitboxComp.getFixture(), target); this.owner.getEntity().getEvents().trigger("meleeStart"); - } else { + } else { Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); + newProjectile.setPosition(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); newProjectile.setScale(-1f, 1f); ServiceLocator.getEntityService().register(newProjectile); // System.out.printf("ANIMATION: " + owner.getEntity().getComponent(AnimationRenderComponent.class).getCurrentAnimation() + "\n"); this.owner.getEntity().getEvents().trigger(FIRING); mobState = STATE.STOW; - } } owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(true); - } case STOW -> { @@ -175,41 +169,20 @@ public void stop() { */ @Override public int getPriority() { - if (status == Status.ACTIVE) { - return getActivePriority(); - } - return getInactivePriority(); - } - - /** - * Fetches the active priority of the Task if a target is visible. - * @return (int) active priority if a target is visible, -1 otherwise - */ - private int getActivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { - return priority; - } - return -1; - } - - /** - * Fetches the inactive priority of the Task if a target is not visible. - * @return (int) -1 if a target is not visible, active priority otherwise - */ - private int getInactivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { + if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { return priority; } return -1; } /** - * Uses a raycast to determine whether there are any targets in detection range + * Uses a raycast to determine whether there are any targets in detection range. + * * @return true if a target is visible, false otherwise */ private boolean isTargetVisible() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f); - return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET_LAYER, hit); } /** @@ -237,6 +210,6 @@ private Weapon meleeOrProjectile() { private void setTarget() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f); - target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET_LAYER); } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobDeathTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobDeathTask.java index 615f0e1ff..478623bcf 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobDeathTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobDeathTask.java @@ -24,7 +24,6 @@ public class MobDeathTask extends DefaultTask implements PriorityTask { private final PhysicsEngine physics; private GameTime timeSource; private long endTime; - private final RaycastHit hit = new RaycastHit(); private int mobHealth; @@ -70,11 +69,6 @@ public void updateBossState() { } - @Override - public void stop() { - super.stop(); - } - @Override public int getPriority() { if (status == Status.ACTIVE) { @@ -98,11 +92,7 @@ private int getInactivePriority() { return -1; } private boolean mobIsDead(int mobhealth) { - - if (mobhealth <= 0) { - return true; - } - return false; + return mobhealth <= 0; } private void killMob() { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobDodgeTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobDodgeTask.java index 203f14c03..697904928 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobDodgeTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobDodgeTask.java @@ -1,8 +1,7 @@ package com.csse3200.game.components.tasks; -import com.badlogic.gdx.math.Vector2; -import com.csse3200.game.components.tasks.MobTask.MobTask; -import com.csse3200.game.components.tasks.MobTask.MobType; +import com.csse3200.game.components.tasks.mobtask.MobTask; +import com.csse3200.game.components.tasks.mobtask.MobType; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; @@ -24,7 +23,7 @@ public class MobDodgeTask extends MobTask { private long endTime; // Helps task wait between each interval. - private final int DELAY_INTERVAL = 500; + private static final int DELAY_INTERVAL = 500; /** * Initialises a mob dodge task with a specified wander range, wait time, and diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobMeleeAttackTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobMeleeAttackTask.java index 3ac8c6c3c..b76de16a4 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobMeleeAttackTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobMeleeAttackTask.java @@ -22,7 +22,7 @@ */ public class MobMeleeAttackTask extends DefaultTask implements PriorityTask { private static final int INTERVAL = 1; // time interval to scan for towers in - private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String STOW = "wanderStart"; @@ -33,15 +33,13 @@ public class MobMeleeAttackTask extends DefaultTask implements PriorityTask { private Fixture target; private final int priority; - private final float maxRange; - private Vector2 mobPosition = new Vector2(10f,10f); private final Vector2 maxRangePosition = new Vector2(); private final PhysicsEngine physics; private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); - private final long delay = 1000; // delay between shots + private static final long DELAY = 1000; // delay between shots private long startTime; private enum STATE { @@ -54,9 +52,8 @@ private enum STATE { * @param priority Task priority when targets are detected (0 when nothing detected). Must be a positive integer. * @param maxRange Maximum effective range of the weapon mob. This determines the detection distance of targets */ - public MobMeleeAttackTask(int priority, float maxRange) { + public MobMeleeAttackTask(int priority) { this.priority = priority; - this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -70,11 +67,11 @@ public MobMeleeAttackTask(int priority, float maxRange) { public void start() { super.start(); startTime = timeSource.getTime(); - this.mobPosition = owner.getEntity().getCenterPosition(); + Vector2 mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); -// owner.getEntity().getEvents().trigger("shootStart"); +// owner.getEntity().getEvents().trigger(FIRING); } /** @@ -122,25 +119,22 @@ public void updateMobState() { if (!isTargetVisible() || this.meleeOrProjectile() == null) { this.owner.getEntity().getEvents().trigger(STOW); mobState = STATE.STOW; + } else if (this.meleeOrProjectile() instanceof Melee) { + TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class); + HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class); + attackComp.onCollisionStart(hitboxComp.getFixture(), target); + this.owner.getEntity().getEvents().trigger(FIRING); } else { - if (this.meleeOrProjectile() instanceof Melee) { - TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class); - HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class); - attackComp.onCollisionStart(hitboxComp.getFixture(), target); - this.owner.getEntity().getEvents().trigger("shootStart"); - } else { - Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); - newProjectile.setScale(-0.0f, 0.0f); - ServiceLocator.getEntityService().register(newProjectile); + Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); + newProjectile.setPosition(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); + newProjectile.setScale(-0.0f, 0.0f); + ServiceLocator.getEntityService().register(newProjectile); // System.out.printf("ANIMATION: " + owner.getEntity().getComponent(AnimationRenderComponent.class).getCurrentAnimation() + "\n"); - this.owner.getEntity().getEvents().trigger(FIRING); - mobState = STATE.STOW; - } + this.owner.getEntity().getEvents().trigger(FIRING); + mobState = STATE.STOW; } owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(true); - } case STOW -> { @@ -175,29 +169,7 @@ public void stop() { */ @Override public int getPriority() { - if (status == Status.ACTIVE) { - return getActivePriority(); - } - return getInactivePriority(); - } - - /** - * Fetches the active priority of the Task if a target is visible. - * @return (int) active priority if a target is visible, -1 otherwise - */ - private int getActivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { - return priority; - } - return -1; - } - - /** - * Fetches the inactive priority of the Task if a target is not visible. - * @return (int) -1 if a target is not visible, active priority otherwise - */ - private int getInactivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { + if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { return priority; } return -1; @@ -209,7 +181,7 @@ private int getInactivePriority() { */ private boolean isTargetVisible() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 100f, owner.getEntity().getPosition().y - 2f); - return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET_LAYER, hit); } /** @@ -237,6 +209,6 @@ private Weapon meleeOrProjectile() { private void setTarget() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 100f, owner.getEntity().getPosition().y - 2f); - target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET_LAYER); } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobRangedAttackTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobRangedAttackTask.java index b10dad91f..021419a05 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobRangedAttackTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobRangedAttackTask.java @@ -22,7 +22,7 @@ */ public class MobRangedAttackTask extends DefaultTask implements PriorityTask { private static final int INTERVAL = 1; // time interval to scan for towers in - private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String STOW = "wanderStart"; @@ -33,15 +33,13 @@ public class MobRangedAttackTask extends DefaultTask implements PriorityTask { private Fixture target; private final int priority; - private final float maxRange; - private Vector2 mobPosition = new Vector2(10f,10f); private final Vector2 maxRangePosition = new Vector2(); private final PhysicsEngine physics; private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); - private final long delay = 1000; // delay between shots + private static final long DELAY = 1000; // delay between shots private long startTime; private enum STATE { @@ -52,11 +50,9 @@ private enum STATE { /** * @param priority Task priority when targets are detected (0 when nothing detected). Must be a positive integer. - * @param maxRange Maximum effective range of the weapon mob. This determines the detection distance of targets */ - public MobRangedAttackTask(int priority, float maxRange) { + public MobRangedAttackTask(int priority) { this.priority = priority; - this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -70,7 +66,7 @@ public MobRangedAttackTask(int priority, float maxRange) { public void start() { super.start(); startTime = timeSource.getTime(); - this.mobPosition = owner.getEntity().getCenterPosition(); + Vector2 mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); @@ -122,31 +118,28 @@ public void updateMobState() { if (!isTargetVisible() || this.meleeOrProjectile() == null) { this.owner.getEntity().getEvents().trigger(STOW); mobState = STATE.STOW; - } else { - if (this.meleeOrProjectile() instanceof Melee) { - TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class); - HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class); - attackComp.onCollisionStart(hitboxComp.getFixture(), target); - Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); - newProjectile.setScale(-1f, 1f); - ServiceLocator.getEntityService().register(newProjectile); + } else if (this.meleeOrProjectile() instanceof Melee) { + TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class); + HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class); + attackComp.onCollisionStart(hitboxComp.getFixture(), target); + Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); + newProjectile.setPosition(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); + newProjectile.setScale(-1f, 1f); + ServiceLocator.getEntityService().register(newProjectile); // System.out.printf("ANIMATION: " + owner.getEntity().getComponent(AnimationRenderComponent.class).getCurrentAnimation() + "\n"); - this.owner.getEntity().getEvents().trigger(FIRING); - } else { - Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); - newProjectile.setScale(-1f, 1f); - ServiceLocator.getEntityService().register(newProjectile); + this.owner.getEntity().getEvents().trigger(FIRING); + } else { + Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); + newProjectile.setPosition(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); + newProjectile.setScale(-1f, 1f); + ServiceLocator.getEntityService().register(newProjectile); // System.out.printf("ANIMATION: " + owner.getEntity().getComponent(AnimationRenderComponent.class).getCurrentAnimation() + "\n"); - this.owner.getEntity().getEvents().trigger(FIRING); - mobState = STATE.STOW; - } + this.owner.getEntity().getEvents().trigger(FIRING); + mobState = STATE.STOW; } owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(true); - } case STOW -> { @@ -181,29 +174,7 @@ public void stop() { */ @Override public int getPriority() { - if (status == Status.ACTIVE) { - return getActivePriority(); - } - return getInactivePriority(); - } - - /** - * Fetches the active priority of the Task if a target is visible. - * @return (int) active priority if a target is visible, -1 otherwise - */ - private int getActivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { - return priority; - } - return -1; - } - - /** - * Fetches the inactive priority of the Task if a target is not visible. - * @return (int) -1 if a target is not visible, active priority otherwise - */ - private int getInactivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { + if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { return priority; } return -1; @@ -215,7 +186,7 @@ private int getInactivePriority() { */ private boolean isTargetVisible() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 100f, owner.getEntity().getPosition().y - 2f); - return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET_LAYER, hit); } /** @@ -243,6 +214,6 @@ private Weapon meleeOrProjectile() { private void setTarget() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 100f, owner.getEntity().getPosition().y - 2f); - target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET_LAYER); } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobShootTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobShootTask.java index 40c50142a..2453c4941 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobShootTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobShootTask.java @@ -18,7 +18,7 @@ */ public class MobShootTask extends DefaultTask implements PriorityTask { private static final int INTERVAL = 1; // time interval to scan for towers in - private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String WALKING = "wanderStart"; @@ -29,15 +29,13 @@ public class MobShootTask extends DefaultTask implements PriorityTask { private Fixture target; private final int priority; - private final float maxRange; - private Vector2 mobPosition = new Vector2(10f,10f); private final Vector2 maxRangePosition = new Vector2(); private final PhysicsEngine physics; private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); - private final long delay = 1000; // delay between shots + private static final long DELAY = 1000; // delay between shots private long startTime; private enum STATE { @@ -48,11 +46,9 @@ private enum STATE { /** * @param priority Task priority when targets are detected (0 when nothing detected). Must be a positive integer. - * @param maxRange Maximum effective range of the weapon mob. This determines the detection distance of targets */ - public MobShootTask(int priority, float maxRange) { + public MobShootTask(int priority) { this.priority = priority; - this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -66,7 +62,7 @@ public MobShootTask(int priority, float maxRange) { public void start() { super.start(); startTime = timeSource.getTime(); - this.mobPosition = owner.getEntity().getCenterPosition(); + Vector2 mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); @@ -103,7 +99,7 @@ public void updateMobState() { case DEPLOY -> { // currently deploying, - if (isTargetVisible() != false) { + if (isTargetVisible()) { owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(false); this.owner.getEntity().getEvents().trigger(FIRING); mobState = STATE.FIRING; @@ -115,13 +111,13 @@ public void updateMobState() { case FIRING -> { // targets gone or cannot be attacked - stop firing - if (!isTargetVisible() == false) { + if (isTargetVisible()) { this.owner.getEntity().getEvents().trigger(WALKING); mobState = STATE.WALKING; } else { Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); + newProjectile.setPosition(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); newProjectile.setScale(-1f, 1f); ServiceLocator.getEntityService().register(newProjectile); @@ -167,29 +163,7 @@ public void stop() { */ @Override public int getPriority() { - if (status == Status.ACTIVE) { - return getActivePriority(); - } - return getInactivePriority(); - } - - /** - * Fetches the active priority of the Task if a target is visible. - * @return (int) active priority if a target is visible, -1 otherwise - */ - private int getActivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() != false) { - return priority; - } - return -1; - } - - /** - * Fetches the inactive priority of the Task if a target is not visible. - * @return (int) -1 if a target is not visible, active priority otherwise - */ - private int getInactivePriority() { - if ((startTime + delay) < timeSource.getTime() && isTargetVisible() != false) { + if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible()) { return priority; } return -1; @@ -201,7 +175,7 @@ private int getInactivePriority() { */ private boolean isTargetVisible() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f); - return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET_LAYER, hit); } /** @@ -229,6 +203,6 @@ private boolean isTargetVisible() { private void setTarget() { Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f); - target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET_LAYER); } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobTask.java index f0e20d117..5ad20684e 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobTask.java @@ -1,4 +1,4 @@ -package com.csse3200.game.components.tasks.MobTask; +package com.csse3200.game.components.tasks.mobtask; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Timer; @@ -35,13 +35,13 @@ public class MobTask extends DefaultTask implements PriorityTask { // Private variables private final MobType mobType; private State state = State.DEFAULT; - private State prevState; private Entity mob; private AnimationRenderComponent animation; private MovementTask movementTask; private Entity target; private GameTime gameTime; private long lastTimeAttacked; + private long dodgeEndTime; // Flags boolean melee; @@ -51,6 +51,7 @@ public class MobTask extends DefaultTask implements PriorityTask { boolean rangeAttackFlag = false; boolean meleeAttackFlag = false; boolean deathFlag = false; + boolean canDodge = false; // Enums private enum State { @@ -66,6 +67,17 @@ public MobTask(MobType mobType) { gameTime = ServiceLocator.getTimeSource(); } + /** + * constructor for the mob + * @param mobType type of mob it is + * @param canDodge ability to dodge projectiles + */ + public MobTask(MobType mobType, boolean canDodge) { + this.mobType = mobType; + gameTime = ServiceLocator.getTimeSource(); + this.canDodge = true; + } + /** * starts general mob sequence, starts its movement task and initialises * some of its variables @@ -84,6 +96,7 @@ public void start() { runFlag = true; changeState(State.RUN); lastTimeAttacked = gameTime.getTime(); + dodgeEndTime = gameTime.getTime(); if (melee) { mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_MOB_SPEED); @@ -109,6 +122,14 @@ public void update() { mob.setFlagForDelete(true); } + if(gameTime.getTime() >= dodgeEndTime) { + if (canDodge) { + mob.getEvents().trigger("dodgeIncomingEntity", + mob.getCenterPosition()); + } + dodgeEndTime = gameTime.getTime() + 500; // 500ms + } + switch (state) { case RUN -> { if (runFlag) { @@ -116,48 +137,33 @@ public void update() { animate(); runFlag = false; } - if (melee) { - if (enemyDetected()) { - if (gameTime.getTime() - lastTimeAttacked >= MELEE_ATTACK_SPEED) { - changeState(State.ATTACK); - meleeAttackFlag = true; - } - } - } else { - if (gameTime.getTime() - lastTimeAttacked >= RANGE_ATTACK_SPEED) { - changeState(State.ATTACK); - rangeAttackFlag = true; - } + if (melee && enemyDetected() && gameTime.getTime() - lastTimeAttacked >= MELEE_ATTACK_SPEED) { + changeState(State.ATTACK); + meleeAttackFlag = true; + } else if (gameTime.getTime() - lastTimeAttacked >= RANGE_ATTACK_SPEED) { + changeState(State.ATTACK); + rangeAttackFlag = true; } } case ATTACK -> { - if (melee) { - if (meleeAttackFlag) { - movementTask.stop(); - animate(); - meleeAttack(); - meleeAttackFlag = false; - } - if (animation.isFinished()) { - movementTask.start(); - changeState(State.RUN); - runFlag = true; - } + if (melee && meleeAttackFlag) { + movementTask.stop(); + animate(); + meleeAttack(); + meleeAttackFlag = false; + } else if (!melee && rangeAttackFlag) { + movementTask.stop(); + animate(); + rangeAttack(); + rangeAttackFlag = false; } - if (!melee) { - if (rangeAttackFlag) { - movementTask.stop(); - animate(); - rangeAttack(); - rangeAttackFlag = false; - } - if (animation.isFinished()) { - movementTask.start(); - changeState(State.RUN); - runFlag = true; - } + if (animation.isFinished()) { + movementTask.start(); + changeState(State.RUN); + runFlag = true; } } + case DEATH, DEFAULT -> {} } } @@ -238,11 +244,11 @@ private void animate() { } /** - * changes state of the mob + * Changes the state of the mob. + * * @param state state to change current state to */ private void changeState(State state) { - prevState = this.state; this.state = state; } @@ -252,19 +258,19 @@ private void changeState(State state) { */ private boolean enemyDetected() { // if there's an entity within x of - 1 of mob - Entity target = ServiceLocator.getEntityService().getEntityAtPosition( + Entity targetInFront = ServiceLocator.getEntityService().getEntityAtPosition( mob.getPosition().x - MELEE_ATTACK_RANGE, mob.getPosition().y); - if (target == null) { + if (targetInFront == null) { return false; } // layer checking - HitboxComponent targetHitbox = target.getComponent(HitboxComponent.class); + HitboxComponent targetHitbox = targetInFront.getComponent(HitboxComponent.class); if (targetHitbox == null) { return false; } if (PhysicsLayer.contains(PhysicsLayer.HUMANS, targetHitbox.getLayer())) { - this.target = target; + this.target = targetInFront; return true; } return false; @@ -314,4 +320,13 @@ private void rangeAttack() { public int getPriority() { return PRIORITY; } + + /** + * Sets dodge flag of the mob + * + * @param dodgeFlag If true, mob dodges projectile. + */ + public void setDodge(boolean dodgeFlag) { + this.canDodge = dodgeFlag; + } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobType.java b/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobType.java index 78adce9ad..8bf4e3b7e 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobType.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobTask/MobType.java @@ -1,4 +1,4 @@ -package com.csse3200.game.components.tasks.MobTask; +package com.csse3200.game.components.tasks.mobtask; public enum MobType { SKELETON(true), @@ -9,7 +9,10 @@ public enum MobType { DRAGON_KNIGHT(true), COAT(true), NIGHT_BORNE(true), - ARCANE_ARCHER(false); + ARCANE_ARCHER(false), + ROCKY(true), + NECROMANCER(true), + FIREWIZARD(true); private boolean isMelee; MobType(boolean melee) { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MobWanderTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MobWanderTask.java index 99d37afdc..e652ea84e 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MobWanderTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MobWanderTask.java @@ -19,22 +19,17 @@ public class MobWanderTask extends DefaultTask implements PriorityTask { private static final Logger logger = LoggerFactory.getLogger(MobWanderTask.class); - private final Vector2 wanderRange; private final float waitTime; private Vector2 startPos; private MovementTask movementTask; private WaitTask waitTask; private Task currentTask; private boolean isDead = false; - private Vector2 mobPosition; /** - * @param wanderRange Distance in X and Y the entity can move from its position when start() is - * called. * @param waitTime How long in seconds to wait between wandering. */ - public MobWanderTask(Vector2 wanderRange, float waitTime) { - this.wanderRange = wanderRange; + public MobWanderTask(float waitTime) { this.waitTime = waitTime; } @@ -66,12 +61,12 @@ public void start() { public void update() { // Update the position of the mob - mobPosition = owner.getEntity().getPosition(); + Vector2 mobPosition = owner.getEntity().getPosition(); // If the mob is at zero health, kill the mob, // play the death animation and stop the task // This method is the idea of Ahmad who very kindly helped with section, massive props to him for his help! - if (!isDead && owner.getEntity().getComponent(CombatStatsComponent.class).isDead()) { + if (!isDead && Boolean.TRUE.equals(owner.getEntity().getComponent(CombatStatsComponent.class).isDead())) { this.owner.getEntity().getEvents().trigger("dieStart"); currentTask.stop(); isDead = true; @@ -82,7 +77,7 @@ public void update() { else if (isDead && owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { // Drop scrap at the mobs location Entity scrap = DropFactory.createScrapDrop(); - scrap.setPosition(mobPosition.x,mobPosition.y); + scrap.setPosition(mobPosition.x, mobPosition.y); ServiceLocator.getEntityService().register(scrap); // Delete the mob and update count for number of mobs remaining in the wave diff --git a/source/core/src/main/com/csse3200/game/components/tasks/MoveToMiddleTask.java b/source/core/src/main/com/csse3200/game/components/tasks/MoveToMiddleTask.java index d9c62e604..2ec1a5ba8 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/MoveToMiddleTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/MoveToMiddleTask.java @@ -10,12 +10,7 @@ public class MoveToMiddleTask extends DefaultTask implements PriorityTask { private final float speed; private boolean hasReachedTarget = false; - private Status taskStatus; - - private Entity ownerEntity; // Store the owner entity - - public MoveToMiddleTask(Entity ownerEntity, Vector2 targetPosition, float speed) { - this.ownerEntity = ownerEntity; + public MoveToMiddleTask(Vector2 targetPosition, float speed) { this.targetPosition = targetPosition; this.speed = speed; } @@ -60,7 +55,7 @@ public void update() { } private void setStatus() { - Status taskStatus = Status.COMPLETED; + status = Status.COMPLETED; } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java index b6c6f7619..cdefde434 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java @@ -4,7 +4,6 @@ import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.ai.tasks.PriorityTask; import com.csse3200.game.components.CombatStatsComponent; -import com.csse3200.game.components.ProjectileEffects; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.ProjectileFactory; import com.csse3200.game.physics.PhysicsEngine; diff --git a/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java index 63c662417..7fc3e5728 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java @@ -4,7 +4,6 @@ import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.ai.tasks.PriorityTask; import com.csse3200.game.components.CombatStatsComponent; -import com.csse3200.game.components.ProjectileEffects; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.ProjectileFactory; import com.csse3200.game.physics.PhysicsEngine; diff --git a/source/core/src/main/com/csse3200/game/components/tasks/TrajectTask.java b/source/core/src/main/com/csse3200/game/components/tasks/TrajectTask.java index 9dbc8cf5c..14cd12923 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/TrajectTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/TrajectTask.java @@ -3,11 +3,10 @@ import com.badlogic.gdx.math.Vector2; import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.ai.tasks.PriorityTask; -import com.csse3200.game.services.GameTime; /** Trajects a projectile from an entity towards the enemy entities */ public class TrajectTask extends DefaultTask implements PriorityTask { - private final int priority = 10; + private static final int PRIORITY = 10; private MovementTask movementTask; private Vector2 destination; private static final String START = "startProjectile"; @@ -18,8 +17,6 @@ private enum STATE { } private STATE projectileState = STATE.START; - private GameTime projectSpawn; - /** * @param destination The destination that the projectile will move towards. */ @@ -43,11 +40,13 @@ public void start() { this.owner.getEntity().getEvents().trigger("startMobBoss"); } + /** + * Switches the state to FINAL if it is START. + */ public void switchProjectileState() { - switch (projectileState) { - case START: - this.owner.getEntity().getEvents().trigger(FINAL); - projectileState = STATE.FINAL; + if (projectileState == STATE.START) { + this.owner.getEntity().getEvents().trigger(FINAL); + projectileState = STATE.FINAL; } } @@ -70,6 +69,6 @@ public void stop() { @Override public int getPriority() { - return priority; + return PRIORITY; } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/DemonBossTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/DemonBossTask.java index 45d482fbc..38896b2b4 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/DemonBossTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/DemonBossTask.java @@ -12,12 +12,9 @@ import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.MobBossFactory; import com.csse3200.game.entities.factories.ProjectileFactory; -import com.csse3200.game.physics.PhysicsEngine; import com.csse3200.game.physics.PhysicsLayer; -import com.csse3200.game.physics.components.HitboxComponent; import com.csse3200.game.physics.components.PhysicsMovementComponent; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,13 +29,12 @@ public class DemonBossTask extends DefaultTask implements PriorityTask { // Constants private static final int PRIORITY = 3; private static final Vector2 DEMON_SPEED = new Vector2(1f, 1f); - private static final float STOP_DISTANCE = 0.1f; private static final float JUMP_DISTANCE = 3.0f; private static final double Y_TOP_BOUNDARY = 5.5; private static final double Y_BOT_BOUNDARY = 0.5; private static final int BREATH_ANIM_TIME = 2; private static final int SMASH_RADIUS = 3; - private static final int MOVE_FORWARD_DELAY = 15; + private static final float MOVE_FORWARD_DELAY = 15; private static final float BREATH_DURATION = 4.2f; private static final int SMASH_DAMAGE = 30; private static final int CLEAVE_DAMAGE = 50; @@ -51,9 +47,6 @@ public class DemonBossTask extends DefaultTask implements PriorityTask { // Private variables private static final Logger logger = LoggerFactory.getLogger(DemonBossTask.class); private Vector2 currentPos; - private final PhysicsEngine physics; - private final GameTime gameTime; - private Vector2 jumpPos; private MovementTask jumpTask; private DemonState state = DemonState.IDLE; private DemonState prevState; @@ -80,14 +73,6 @@ private enum DemonState { TRANSFORM, IDLE, CAST, CLEAVE, DEATH, BREATH, SMASH, TAKE_HIT, WALK } - /** - * The demon boss task constructor. Initialises the physics and time. - */ - public DemonBossTask() { - physics = ServiceLocator.getPhysicsService().getPhysics(); - gameTime = ServiceLocator.getTimeSource(); - } - /** * Starts transform animation, triggers idle animation which starts * sequence, and dynamically shifts the demons boundary to the left. @@ -188,10 +173,8 @@ public void update() { } } case TRANSFORM -> { - if (health <= 0) { - if (animation.isFinished()) { - changeState(DemonState.DEATH); - } + if (health <= 0 && animation.isFinished()) { + changeState(DemonState.DEATH); } } case TAKE_HIT -> { @@ -200,6 +183,7 @@ public void update() { halfHealthFlag = true; } } + case DEATH, WALK -> {} } } @@ -309,6 +293,7 @@ public void run() { */ private Vector2 getJumpPos() { // check if boundary has shifted causing demon to be out of bounds + Vector2 jumpPos; if (currentPos.x > xRightBoundary) { jumpPos = new Vector2(currentPos.x - JUMP_DISTANCE, currentPos.y); //jump back into boundary return jumpPos; @@ -318,6 +303,7 @@ private Vector2 getJumpPos() { if (currentPos.dst(ServiceLocator.getEntityService().getClosestEntityOfLayer( demon, PhysicsLayer.HUMANS).getPosition()) < 2f) { jumpPos = new Vector2(currentPos.x + JUMP_DISTANCE, currentPos.y); + //TODO: Check whether jumpPos needs to be returned } float randomAngle = MathUtils.random(0, 2 * MathUtils.PI); diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/FinalBossMovementTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/FinalBossMovementTask.java index 34ebf7bae..fdd6e6aeb 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/FinalBossMovementTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/FinalBossMovementTask.java @@ -79,7 +79,7 @@ public void update() { if (towerAhead()) { Entity newProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.TOWER, new Vector2(0,currentPos.y + 0.75f), new Vector2(2f,2f), ProjectileEffects.BURN, false); newProjectile.scaleHeight(-0.4f); - newProjectile.setPosition((float) (currentPos.x), (float) (currentPos.y+0.75f)); + newProjectile.setPosition(currentPos.x, currentPos.y + 0.75f); ServiceLocator.getEntityService().register(newProjectile); } startWaiting(); diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/IceBabyTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/IceBabyTask.java index f89f12ed0..80e703ebf 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/IceBabyTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/IceBabyTask.java @@ -10,12 +10,10 @@ import com.csse3200.game.components.tasks.MovementTask; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.NPCFactory; -import com.csse3200.game.physics.PhysicsEngine; import com.csse3200.game.physics.PhysicsLayer; import com.csse3200.game.physics.components.HitboxComponent; import com.csse3200.game.physics.components.PhysicsMovementComponent; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +22,7 @@ public class IceBabyTask extends DefaultTask implements PriorityTask { /** Constant names */ private static final int PRIORITY = 3; private static final Vector2 ICEBABY_SPEED = new Vector2(1f, 1f); - private static final int MOVE_FORWARD_DELAY = 30; + private static final float MOVE_FORWARD_DELAY = 30; private static final int SMASH_RADIUS = 3; private static final int SMASH_DAMAGE = 30; private static final int ATK3_DAMAGE = 50; @@ -34,8 +32,6 @@ public class IceBabyTask extends DefaultTask implements PriorityTask { private static final int Y_BOT_BOUNDARY = 1; private static final Logger logger = LoggerFactory.getLogger(IceBabyTask.class); /** Variable names */ - private PhysicsEngine physics; - private GameTime gameTime; private STATE prevState; private AnimationRenderComponent animation; private Entity iceBaby; @@ -44,7 +40,6 @@ public class IceBabyTask extends DefaultTask implements PriorityTask { private MovementTask walkTask; private static int xRightBoundary = 17; private static int xLeftBoundary = 12; - private boolean aoe = true; private boolean startFlag = false; private boolean isWalking; /** Animation constants */ @@ -62,14 +57,6 @@ private enum STATE { } private STATE iceBabyState = STATE.IDLE; - /** - * Constructor for IceBabyTask - */ - public IceBabyTask() { - physics = ServiceLocator.getPhysicsService().getPhysics(); - gameTime = ServiceLocator.getTimeSource(); - } - //ice baby should be able to poop out little mobs - spawn new //ice baby can also do aoe attack based on the animation //ice baby does punches to towers once it is close @@ -141,7 +128,7 @@ public void update() { } case ATK1, ATK2 -> { if (animation.isFinished()) { - ATK3(); + atk3(); } } case ATK3 -> { @@ -149,6 +136,7 @@ public void update() { changeState(STATE.IDLE); } } + case DEATH, INTRO, STAGGER, TAKEHIT -> {} } } @@ -253,7 +241,7 @@ private boolean walkComplete() { /** * Changes the state of the animation and deals damage to nearby humans */ - private void ATK3() { + private void atk3() { changeState(STATE.ATK3); animate(); Entity target = ServiceLocator.getEntityService().getClosestEntityOfLayer(iceBaby, @@ -309,16 +297,11 @@ private Array getNearbyHumans(int radius) { for (int i = 0; i < nearbyEntities.size; i++) { Entity targetEntity = nearbyEntities.get(i); HitboxComponent targetHitbox = targetEntity.getComponent(HitboxComponent.class); - if (targetHitbox == null) { + // check target hitbox and layer + if (targetHitbox == null || (!PhysicsLayer.contains(PhysicsLayer.HUMANS, targetHitbox. + getLayer()))) { break; } - - // check target layer - if (!PhysicsLayer.contains(PhysicsLayer.HUMANS, targetHitbox. - getLayer())) { - break; - } - nearbyHumans.add(targetEntity); } return nearbyHumans; diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/MobBossDeathTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/MobBossDeathTask.java index 3d02358f2..719c2436a 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/MobBossDeathTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/MobBossDeathTask.java @@ -6,12 +6,8 @@ import com.csse3200.game.components.CombatStatsComponent; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.DropFactory; -import com.csse3200.game.physics.PhysicsEngine; -import com.csse3200.game.physics.raycast.RaycastHit; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; -//import com.csse3200.game.rendering.DebugRenderer; - /** * Task that prints a message to the terminal whenever it is called. @@ -21,10 +17,8 @@ public class MobBossDeathTask extends DefaultTask implements PriorityTask { private final int priority; private Vector2 bossPosition = new Vector2(10f,10f); - private final PhysicsEngine physics; private GameTime timeSource; private long endTime; - private final RaycastHit hit = new RaycastHit(); private int bossHealth; @@ -33,9 +27,6 @@ public class MobBossDeathTask extends DefaultTask implements PriorityTask { */ public MobBossDeathTask(int priority) { this.priority = priority; - - physics = ServiceLocator.getPhysicsService().getPhysics(); - timeSource = ServiceLocator.getTimeSource(); } @@ -70,11 +61,6 @@ public void updateMobBossState() { } - @Override - public void stop() { - super.stop(); - } - @Override public int getPriority() { if (status == Status.ACTIVE) { @@ -98,11 +84,7 @@ private int getInactivePriority() { return -1; } private boolean bossIsDead(int bosshealth) { - - if (bosshealth <= 0) { - return true; - } - return false; + return bosshealth <= 0; } private void killboss() { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTask.java index ee06a9d44..bf5e6c30c 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTask.java @@ -10,11 +10,9 @@ import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.MobBossFactory; import com.csse3200.game.entities.factories.ProjectileFactory; -import com.csse3200.game.physics.PhysicsEngine; import com.csse3200.game.physics.PhysicsLayer; import com.csse3200.game.physics.components.PhysicsMovementComponent; import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,7 +26,6 @@ public class PatrickTask extends DefaultTask implements PriorityTask { // Constants private static final int PRIORITY = 3; private static final Vector2 PATRICK_SPEED = new Vector2(1f, 1f); - private static final float MAX_RADIUS = 20f; private static final int ATTACK_DAMAGE = 100; private static final float RANGE_MIN_X = 10f; private static final float RANGE_MAX_X = 18f; @@ -38,9 +35,6 @@ public class PatrickTask extends DefaultTask implements PriorityTask { // Private variables private static final Logger logger = LoggerFactory.getLogger(PatrickTask.class); - private Vector2 currentPos; - private PhysicsEngine physics; - private GameTime gameTime; private PatrickState state = PatrickState.IDLE; private PatrickState prevState; private AnimationRenderComponent animation; @@ -61,14 +55,6 @@ private enum PatrickState { IDLE, WALK, ATTACK, HURT, DEATH, SPELL, APPEAR } - /** - * Constructor for PatrickTask - */ - public PatrickTask() { - physics = ServiceLocator.getPhysicsService().getPhysics(); - gameTime = ServiceLocator.getTimeSource(); - } - /** * What is called when the patrick task is assigned */ @@ -77,7 +63,6 @@ public void start() { super.start(); patrick = owner.getEntity(); animation = owner.getEntity().getComponent(AnimationRenderComponent.class); // get animation - currentPos = owner.getEntity().getPosition(); // get current position patrick.getComponent(PhysicsMovementComponent.class).setSpeed(PATRICK_SPEED); // set speed // give game time to load @@ -101,10 +86,7 @@ public void update() { // give game time to load if (!startFlag) { return; - } - - // update teleport task while teleporting - if (teleportFlag) { + } else if (teleportFlag) { // update teleport task while teleporting teleportTask.update(); if (teleportTask.getStatus().equals(Status.FINISHED)) { teleportFlag = false; @@ -151,15 +133,12 @@ public void run() { }, 1f); changeState(PatrickState.ATTACK); meleeFlag = false; + } else if (rangeFlag && shotsFired > 2) { + rangeFlag = false; + meleeAttack(); + shotsFired = 0; // reset shots fired } else if (rangeFlag) { - // shoot 3 projectiles - if (shotsFired > 2) { - rangeFlag = false; - meleeAttack(); - shotsFired = 0; // reset shots fired - } else { - changeState(PatrickState.IDLE); - } + changeState(PatrickState.IDLE); } } case IDLE -> { @@ -174,6 +153,7 @@ public void run() { rangeFlag = true; } } + case WALK, HURT, DEATH, SPELL -> {} } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTeleportTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTeleportTask.java index 621b0bf9d..fbb2a0c23 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTeleportTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/PatrickTeleportTask.java @@ -4,20 +4,18 @@ import com.badlogic.gdx.utils.Timer; import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.components.CombatStatsComponent; -import com.csse3200.game.components.tasks.MovementTask; import com.csse3200.game.entities.Entity; import com.csse3200.game.rendering.AnimationRenderComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PatrickTeleportTask extends DefaultTask { - private static final Logger logger = LoggerFactory.getLogger(MovementTask.class); + private static final Logger logger = LoggerFactory.getLogger(PatrickTeleportTask.class); private Entity patrick; private final Vector2 location; private PatrickState state = PatrickState.IDLE; private PatrickState prevState; private AnimationRenderComponent animation; - private Status status = Status.INACTIVE; private CombatStatsComponent combatStats; private int health; private enum PatrickState { @@ -32,6 +30,7 @@ public PatrickTeleportTask(Entity patrick, Vector2 location) { @Override public void start() { super.start(); + status = Status.INACTIVE; animation = owner.getEntity().getComponent(AnimationRenderComponent.class); combatStats = owner.getEntity().getComponent(CombatStatsComponent.class); health = combatStats.getHealth(); @@ -70,6 +69,7 @@ public void update() { status = Status.FINISHED; } } + case IDLE -> {} } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/RangeBossTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/RangeBossTask.java index ec7486a8e..1cd260d3d 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/RangeBossTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/RangeBossTask.java @@ -69,10 +69,9 @@ public void start() { } public void switchMobBossBallState() { - switch (bossBallState) { - case START: - owner.getEntity().getEvents().trigger(FINAL); - bossBallState = STATE.FINAL; + if (bossBallState == STATE.START) { + owner.getEntity().getEvents().trigger(FINAL); + bossBallState = STATE.FINAL; } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/SlimeyBoyTask.java b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/SlimeyBoyTask.java index bef8386d8..fe8cefae4 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/bosstask/SlimeyBoyTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/bosstask/SlimeyBoyTask.java @@ -101,6 +101,7 @@ public void update() { slimey.getEvents().trigger("slimey_splat_sound"); slimey.setFlagForDelete(true); } + case IDLE, PROJECTILE_EXPLOSION, PROJECTILE_IDLE -> {} } } @@ -171,10 +172,7 @@ private boolean targetFound() { */ private void applyAoeDamage(Array targets, int damage) { for (int i = 0; i < targets.size; i++) { - Entity targetEntity = targets.get(i); - - CombatStatsComponent targetCombatStats = targetEntity. - getComponent(CombatStatsComponent.class); + CombatStatsComponent targetCombatStats = targets.get(i).getComponent(CombatStatsComponent.class); if (targetCombatStats != null) { targetCombatStats.hit(damage); } diff --git a/source/core/src/main/com/csse3200/game/entities/Entity.java b/source/core/src/main/com/csse3200/game/entities/Entity.java index 4373da4a9..c0bfb1acc 100644 --- a/source/core/src/main/com/csse3200/game/entities/Entity.java +++ b/source/core/src/main/com/csse3200/game/entities/Entity.java @@ -208,10 +208,10 @@ public Entity addComponent(Component component) { public void removeComponent(Class componentClass) { ComponentType componentType = ComponentType.getFrom(componentClass); - int id = componentType.getId(); + int componentID = componentType.getId(); - if (components.containsKey(id)) { - Component removedComponent = components.remove(id); + if (components.containsKey(componentID)) { + Component removedComponent = components.remove(componentID); removedComponent.dispose(); } } @@ -311,7 +311,7 @@ public void setFlagForDelete(boolean condition) { @Override public boolean equals(Object obj) { - return (obj instanceof Entity && ((Entity) obj).getId() == this.getId()); + return (obj instanceof Entity entity && entity.getId() == this.getId()); } @Override diff --git a/source/core/src/main/com/csse3200/game/entities/EntityService.java b/source/core/src/main/com/csse3200/game/entities/EntityService.java index a5e6c4d6f..35e7a9ee5 100644 --- a/source/core/src/main/com/csse3200/game/entities/EntityService.java +++ b/source/core/src/main/com/csse3200/game/entities/EntityService.java @@ -1,19 +1,10 @@ package com.csse3200.game.entities; -import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; -import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.utils.Array; -import com.csse3200.game.areas.terrain.TerrainComponent; -import com.csse3200.game.areas.terrain.TerrainFactory; -import com.csse3200.game.components.npc.DropComponent; -import com.csse3200.game.input.DropInputComponent; import com.csse3200.game.physics.PhysicsLayer; import com.csse3200.game.physics.components.HitboxComponent; -import com.csse3200.game.rendering.RenderService; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -107,7 +98,7 @@ public Array getEntities() { * @return An array containing entities within the given radius. */ public Array getNearbyEntities(Entity source, float radius) { - Array nearbyEntities = new Array(); + Array nearbyEntities = new Array<>(); Array allEntities = ServiceLocator.getEntityService().getEntities(); for (int i = 0; i < allEntities.size; i++) { Entity otherEntity = allEntities.get(i); @@ -133,7 +124,7 @@ public Array getNearbyEntities(Entity source, float radius) { * @return An array containing entities within the given radius. */ public Array getEntitiesInLayer(Entity source, float radius, short layer) { - Array entities = new Array(); + Array entitiesInLayer = new Array<>(); Array allEntities = getNearbyEntities(source, radius); for (int i = 0; i < allEntities.size; i++) { @@ -141,15 +132,12 @@ public Array getEntitiesInLayer(Entity source, float radius, short layer // check targets layer HitboxComponent targetHitbox = targetEntity.getComponent(HitboxComponent.class); - if (targetHitbox == null) { - continue; - } - if (!PhysicsLayer.contains(layer, targetHitbox.getLayer())) { + if (targetHitbox == null || (!PhysicsLayer.contains(layer, targetHitbox.getLayer()))) { continue; } - entities.add(targetEntity); + entitiesInLayer.add(targetEntity); } - return entities; + return entitiesInLayer; } /** @@ -217,11 +205,11 @@ private boolean entityContainsPosition(Entity entity, float x, float y) { /** * Determine whether there are any entities within the given tile position (x and y range). Checks for out of bounds * click location - * @param x_coord the top right x coordinate of the tile - * @param y_coord the top right y coordinate of the tile + * @param xCoord the top right x coordinate of the tile + * @param yCoord the top right y coordinate of the tile * @return true if the tile is occupied, false otherwise */ - public boolean entitiesInTile(int x_coord, int y_coord) { + public boolean entitiesInTile(int xCoord, int yCoord) { TiledMapTileLayer mp; try { mp = (TiledMapTileLayer)ServiceLocator.getMapService().getComponent().getMap().getLayers().get(0); @@ -229,8 +217,8 @@ public boolean entitiesInTile(int x_coord, int y_coord) { // MapService is not running - consider this occupied (invalid tile) return true; } - if (mp.getCell(x_coord, y_coord) != null) { - Entity entity = checkEntityAtPosition(x_coord, y_coord); + if (mp.getCell(xCoord, yCoord) != null) { + Entity entity = checkEntityAtPosition(xCoord, yCoord); return entity != null; } return true; diff --git a/source/core/src/main/com/csse3200/game/entities/Melee.java b/source/core/src/main/com/csse3200/game/entities/Melee.java index 520aebf09..76289481f 100644 --- a/source/core/src/main/com/csse3200/game/entities/Melee.java +++ b/source/core/src/main/com/csse3200/game/entities/Melee.java @@ -21,10 +21,10 @@ public class Melee implements Weapon { private final int cooldown; - public Melee(int damage, int attackRange, String Element, int castTime, int cooldown) { + public Melee(int damage, int attackRange, String element, int castTime, int cooldown) { this.damage = damage; this.attackRange = attackRange; - this.element = Element; + this.element = element; this.castTime = castTime; this.cooldown = cooldown; } diff --git a/source/core/src/main/com/csse3200/game/entities/PredefinedWeapons.java b/source/core/src/main/com/csse3200/game/entities/PredefinedWeapons.java index 8e20a6781..53e7e1af7 100644 --- a/source/core/src/main/com/csse3200/game/entities/PredefinedWeapons.java +++ b/source/core/src/main/com/csse3200/game/entities/PredefinedWeapons.java @@ -1,17 +1,21 @@ package com.csse3200.game.entities; import com.csse3200.game.entities.configs.ProjectileConfig; -import com.csse3200.game.files.FileLoader; public class PredefinedWeapons { + + private PredefinedWeapons() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + // Melee attacks - public static Melee sword = new Melee(10, 4, "fire", 1, 1); - public static Melee punch = new Melee(3, 1, "air", 1, 1); - public static Melee axe = new Melee(9, 3, "fire", 1, 1); - public static Melee kick = new Melee(2, 1, "earth", 1, 1); + public static final Melee SWORD = new Melee(10, 4, "fire", 1, 1); + public static final Melee PUNCH = new Melee(3, 1, "air", 1, 1); + public static final Melee AXE = new Melee(9, 3, "fire", 1, 1); + public static final Melee KICK = new Melee(2, 1, "earth", 1, 1); //TODO import defined projectiles for mobs - public static ProjectileConfig fireBall = new ProjectileConfig(); - public static ProjectileConfig frostBall = new ProjectileConfig(); + public static final ProjectileConfig FIREBALL = new ProjectileConfig(); + public static final ProjectileConfig FROSTBALL = new ProjectileConfig(); } diff --git a/source/core/src/main/com/csse3200/game/entities/configs/BaseEnemyConfig.java b/source/core/src/main/com/csse3200/game/entities/configs/BaseEnemyConfig.java index 1af74ddb7..e1fdf0aeb 100644 --- a/source/core/src/main/com/csse3200/game/entities/configs/BaseEnemyConfig.java +++ b/source/core/src/main/com/csse3200/game/entities/configs/BaseEnemyConfig.java @@ -34,16 +34,16 @@ public class BaseEnemyConfig extends BaseEntityConfig { private final int id; //TODO: change to item class - private final ArrayList drops; - private ArrayList closeRangeAbilities; - private ArrayList longRangeAbilities; + private final List drops; + private List closeRangeAbilities; + private List longRangeAbilities; /** * Creates a new enemy config with default values. */ - public BaseEnemyConfig(ArrayList drops, - ArrayList closeRangeAbilities, - ArrayList longRangeAbilities) { + public BaseEnemyConfig(List drops, + List closeRangeAbilities, + List longRangeAbilities) { this.speed = 1; this.drops = drops; this.fullHeath = this.health; @@ -62,8 +62,8 @@ public BaseEnemyConfig(ArrayList drops, * @param drops the drops of the enemy * @param baseAttack the base damage to the target */ - public BaseEnemyConfig(int speed, int health, ArrayList drops, - ArrayList closeRangeAbilities, ArrayList longRangeAbilities, int baseAttack) { + public BaseEnemyConfig(int speed, int health, List drops, + List closeRangeAbilities, List longRangeAbilities, int baseAttack) { this.speed = speed; this.health = health; this.fullHeath = health; @@ -97,13 +97,13 @@ public String getDrops() { } /*** return the close range (Melee) attacks of the enemy */ - public ArrayList getCloseRangeAbilities() { + public List getCloseRangeAbilities() { return this.closeRangeAbilities; } /** return the long range (Projectile) attacks of the enemy */ //TODO change to projectile - public ArrayList getLongRangeAbilities() { + public List getLongRangeAbilities() { return this.longRangeAbilities; } diff --git a/source/core/src/main/com/csse3200/game/entities/configs/MobBossConfigs.java b/source/core/src/main/com/csse3200/game/entities/configs/MobBossConfigs.java index 54bd8201f..1ae0fc4af 100644 --- a/source/core/src/main/com/csse3200/game/entities/configs/MobBossConfigs.java +++ b/source/core/src/main/com/csse3200/game/entities/configs/MobBossConfigs.java @@ -1,7 +1,7 @@ package com.csse3200.game.entities.configs; /** - * Defines the properties stored in ghost king config files to be loaded by the NPC Factory. + * Defines the properties stored in mob boss config files to be loaded by the Mob Boss Factory. */ public class MobBossConfigs extends BaseEntityConfig { public int baseAttack = 0; diff --git a/source/core/src/main/com/csse3200/game/entities/configs/NPCConfigs.java b/source/core/src/main/com/csse3200/game/entities/configs/NPCConfigs.java index 8faed4421..19914f13c 100644 --- a/source/core/src/main/com/csse3200/game/entities/configs/NPCConfigs.java +++ b/source/core/src/main/com/csse3200/game/entities/configs/NPCConfigs.java @@ -1,10 +1,6 @@ package com.csse3200.game.entities.configs; -import com.csse3200.game.entities.Melee; -import com.csse3200.game.entities.Weapon; - import java.util.ArrayList; -import java.util.Currency; /** * Defines all NPC configs to be loaded by the NPC Factory. @@ -12,15 +8,14 @@ public class NPCConfigs { public BaseEntityConfig ghost = new BaseEntityConfig(); public BaseEntityConfig fireBall = new ProjectileConfig(); - // public GhostKingConfig ghostKing = new GhostKingConfig(); public BaseEntityConfig projectile = new ProjectileConfig(); public GhostKingConfig ghostKing = new GhostKingConfig(); public BaseEnemyConfig xenoGrunt = new BaseEnemyConfig( 10, 100, - new ArrayList(), - new ArrayList(), - new ArrayList(), + new ArrayList<>(), + new ArrayList<>(), + new ArrayList<>(), 10); public MobBossConfigs mobBoss = new MobBossConfigs(); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java index e9feaf2aa..593c12de4 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.csse3200.game.ai.tasks.AITaskComponent; import com.csse3200.game.components.CombatStatsComponent; +import com.csse3200.game.components.EffectComponent; import com.csse3200.game.components.TouchAttackComponent; import com.csse3200.game.components.npc.EngineerMenuComponent; import com.csse3200.game.components.player.HumanAnimationController; @@ -107,6 +108,7 @@ public static Entity createBaseHumanNPC() { .addComponent(new PhysicsComponent()) .addComponent(new PhysicsMovementComponent()) .addComponent(new ColliderComponent()) + .addComponent(new EffectComponent(false)) .addComponent(new HitboxComponent().setLayer(PhysicsLayer.ENGINEER)) .addComponent(new TouchAttackComponent(PhysicsLayer.NPC, 1.5f)); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/MobBossFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/MobBossFactory.java index 1e16adaa4..f42babb8a 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/MobBossFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/MobBossFactory.java @@ -216,16 +216,15 @@ public static Entity createIceBoss(int health) { * @return a base mob boss entity */ public static Entity createBaseBoss() { - Entity boss = new Entity() + return new Entity() .addComponent(new PhysicsComponent()) // .addComponent(new ColliderComponent()) + .addComponent(new EffectComponent(false)) .addComponent(new PhysicsMovementComponent()) .addComponent(new HitboxComponent().setLayer(PhysicsLayer.NPC)) .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS, 1.5f)); // PhysicsUtils.setScaledCollider(boss, 0.9f, 0.4f); - - return boss; } /** diff --git a/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java index 72f464de3..1ceb66b31 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java @@ -5,27 +5,15 @@ import com.badlogic.gdx.math.Vector2; import com.csse3200.game.ai.tasks.AITaskComponent; import com.csse3200.game.components.CombatStatsComponent; +import com.csse3200.game.components.EffectComponent; import com.csse3200.game.components.TouchAttackComponent; -import com.csse3200.game.components.npc.ArcaneArcherAnimationController; -import com.csse3200.game.components.npc.CoatAnimationController; -import com.csse3200.game.components.npc.DeflectingComponent; -import com.csse3200.game.components.npc.DodgingComponent; -import com.csse3200.game.components.npc.DragonKnightAnimationController; -import com.csse3200.game.components.npc.FireWormAnimationController; -import com.csse3200.game.components.npc.GhostAnimationController; -import com.csse3200.game.components.npc.NightBorneAnimationController; -import com.csse3200.game.components.npc.SkeletonAnimationController; -import com.csse3200.game.components.npc.SplitMoblings; -import com.csse3200.game.components.npc.WaterQueenAnimationController; -import com.csse3200.game.components.npc.WaterSlimeAnimationController; -import com.csse3200.game.components.npc.WizardAnimationController; -import com.csse3200.game.components.npc.XenoAnimationController; +import com.csse3200.game.components.npc.*; import com.csse3200.game.components.tasks.MobDodgeTask; import com.csse3200.game.components.tasks.MobMeleeAttackTask; import com.csse3200.game.components.tasks.MobRangedAttackTask; -import com.csse3200.game.components.tasks.MobTask.MobTask; -import com.csse3200.game.components.tasks.MobTask.MobType; import com.csse3200.game.components.tasks.MobWanderTask; +import com.csse3200.game.components.tasks.mobtask.MobTask; +import com.csse3200.game.components.tasks.mobtask.MobType; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.Melee; import com.csse3200.game.entities.PredefinedWeapons; @@ -57,6 +45,7 @@ public class NPCFactory { private static final NPCConfigs configs = FileLoader.readClass(NPCConfigs.class, "configs/NPCs.json"); + private static final String DEFAULT = "default"; /** * Creates a ghost entity. @@ -126,7 +115,7 @@ public static Entity createSkeleton(int health) { animator.addAnimation("skeleton_walk", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("skeleton_attack", 0.1f); animator.addAnimation("skeleton_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.SKELETON)); @@ -158,7 +147,7 @@ public static Entity createWizard(int health) { animator.addAnimation("wizard_run", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("wizard_attack", 0.1f); animator.addAnimation("wizard_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.WIZARD)); @@ -188,7 +177,7 @@ public static Entity createWaterQueen(int health) { animator.addAnimation("water_queen_walk", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("water_queen_attack", 0.1f); animator.addAnimation("water_queen_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.WATER_QUEEN)); @@ -219,7 +208,7 @@ public static Entity createBaseWaterSlime(int health) { animator.addAnimation("water_slime_walk", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("water_slime_attack", 0.1f); animator.addAnimation("water_slime_death", 0.2f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.WATER_SLIME)); @@ -250,7 +239,7 @@ public static Entity createFireWorm(int health) { animator.addAnimation("fire_worm_walk", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("fire_worm_attack", 0.1f); animator.addAnimation("fire_worm_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.FIRE_WORM)); @@ -281,7 +270,7 @@ public static Entity createDragonKnight(int health) { animator.addAnimation("dragon_knight_run", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("dragon_knight_attack", 0.1f); animator.addAnimation("dragon_knight_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.DRAGON_KNIGHT)); @@ -308,7 +297,7 @@ public static Entity createCoat(int health) { animator.addAnimation("coat_run", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("coat_attack", 0.1f); animator.addAnimation("coat_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.COAT)); @@ -335,7 +324,7 @@ public static Entity createNightBorne(int health) { animator.addAnimation("night_borne_run", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("night_borne_attack", 0.1f); animator.addAnimation("night_borne_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.NIGHT_BORNE)); @@ -352,6 +341,87 @@ public static Entity createNightBorne(int health) { return coat; } + public static Entity createRocky(int health) { + Entity coat = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/rocky.atlas", TextureAtlas.class)); + animator.addAnimation("rocky_move", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("rocky_attack", 0.1f); + animator.addAnimation("night_borne_death", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.NIGHT_BORNE)); + + coat + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new RockyAnimationController()) + .addComponent(aiTaskComponent); + + coat.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); + coat.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return coat; + } + + public static Entity createNecromancer(int health) { + Entity coat = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/necromancer.atlas", TextureAtlas.class)); + animator.addAnimation("necromancer_walk", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("necromancer_attack", 0.1f); + animator.addAnimation("necromancer_death", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.NECROMANCER)); + + coat + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new NecromancerAnimationController()) + .addComponent(aiTaskComponent); + + coat.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); + coat.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return coat; + } + + public static Entity createFirewizard(int health) { + Entity Firewizard = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/firewizard.atlas", TextureAtlas.class)); + animator.addAnimation("firewizard_move", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("firewizard_attack", 0.1f); + animator.addAnimation("firewizard_death", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.FIREWIZARD)); + + Firewizard + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new FirewizardAnimationController()) + .addComponent(aiTaskComponent); + + Firewizard.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); + Firewizard.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return Firewizard; + } + public static Entity createArcaneArcher(int health) { Entity coat = createBaseNPC(); ArrayList drops = new ArrayList<>(); @@ -363,7 +433,7 @@ public static Entity createArcaneArcher(int health) { animator.addAnimation("arcane_archer_attack", 0.1f); animator.addAnimation("arcane_archer_death", 0.1f); animator.addAnimation("arcane_archer_dodge", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.ARCANE_ARCHER)); @@ -390,7 +460,7 @@ public static Entity createGregRangeMob(int health) { animator.addAnimation("fire_worm_walk", 0.1f, Animation.PlayMode.LOOP); animator.addAnimation("fire_worm_attack", 0.1f); animator.addAnimation("fire_worm_death", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); AITaskComponent aiTaskComponent = new AITaskComponent() .addTask(new MobTask(MobType.FIRE_WORM)); @@ -416,9 +486,9 @@ public static Entity createGregRangeMob(int health) { public static Entity createXenoGrunt(int health) { Entity xenoGrunt = createMeleeBaseNPC(); BaseEnemyConfig config = configs.xenoGrunt; - ArrayList melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick)); + ArrayList melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.SWORD, PredefinedWeapons.KICK)); // tester projectiles - ArrayList projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall)); + ArrayList projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.FIREBALL, PredefinedWeapons.FROSTBALL)); ArrayList drops = new ArrayList<>(); AnimationRenderComponent animator = @@ -430,7 +500,7 @@ public static Entity createXenoGrunt(int health) { animator.addAnimation("xeno_melee_1", 0.1f); animator.addAnimation("xeno_melee_2", 0.1f); animator.addAnimation("xeno_die", 0.1f); - animator.addAnimation("default", 0.1f); + animator.addAnimation(DEFAULT, 0.1f); xenoGrunt .addComponent(new CombatStatsComponent(health, config.baseAttack, drops, melee, projectiles)) // .addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles)) @@ -449,6 +519,7 @@ public static Entity createBaseNPC() { .addComponent(new PhysicsComponent()) .addComponent(new PhysicsMovementComponent()) .addComponent(new ColliderComponent()) + .addComponent(new EffectComponent(true)) .addComponent(new HitboxComponent().setLayer(PhysicsLayer.NPC)) .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS)); PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f); @@ -463,8 +534,8 @@ public static Entity createBaseNPC() { public static Entity createMeleeBaseNPC() { AITaskComponent aiComponent = new AITaskComponent() - .addTask(new MobWanderTask(new Vector2(2f, 2f), 2f)) - .addTask(new MobMeleeAttackTask(2, 2f)); + .addTask(new MobWanderTask(2f)) + .addTask(new MobMeleeAttackTask(2)); // .addTask(new MobAttackTask(2, 2f)); // .addTask(new MeleeMobTask(new Vector2(2f, 2f), 2f)); @@ -488,9 +559,9 @@ public static Entity createMeleeBaseNPC() { public static Entity createRangedBaseNPC() { AITaskComponent aiComponent = new AITaskComponent() - .addTask(new MobWanderTask(new Vector2(2f, 2f), 2f)) + .addTask(new MobWanderTask(2f)) // .addTask(new MobAttackTask(2, 2f)); - .addTask(new MobRangedAttackTask(2, 2f)); + .addTask(new MobRangedAttackTask(2)); // .addTask(new MeleeMobTask(new Vector2(2f, 2f), 2f)); // .addTask(new MobAttackTask(2, 40)); @@ -515,7 +586,7 @@ public static Entity createSplittingXenoGrunt(int health) { Entity splitXenoGrunt = createXenoGrunt(health) // add the scaling yourself. can also scale the X and Y component, // leading to some very interesting mob designs. - .addComponent(new SplitMoblings(7, 0.5f)) + .addComponent(new SplitMoblings(MobType.WATER_SLIME, 7, 0.5f)) .addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f)); // * TEMPORARY TESTING FOR PROJECTILE DODGING @@ -527,43 +598,46 @@ public static Entity createSplittingXenoGrunt(int health) { /** * Create Splitting water slime * - * @require Entity to have a "splitDeath" - * @return + * @require - Entity to have a "splitDeath" + * @return Splitting water slime */ public static Entity createSplittingWaterSlime(int health) { - Entity splitWaterSlime = createBaseWaterSlime(health) + return createBaseWaterSlime(health).addComponent(new SplitMoblings(MobType.WATER_SLIME, 7, 0.5f)); + } - .addComponent(new SplitMoblings(7, 0.5f)); - - return splitWaterSlime; + /** + * Create Splitting water slime + * + * @require Entity to have a "splitDeath" + * @return Splitting Rocky + */ + public static Entity createSplittingRocky(int health) { + return createRocky(health).addComponent(new SplitMoblings(MobType.ROCKY, 7, 0.5f)); } /** * Create Splitting night borne * * @require Entity to have a "splitDeath" - * @return + * @return Splitting Night Borne */ public static Entity createSplittingNightBorne(int health) { - Entity splitWaterSlime = createNightBorne(health) - - .addComponent(new SplitMoblings(7, 0.5f)); - - return splitWaterSlime; + return createNightBorne(health).addComponent(new SplitMoblings(MobType.NIGHT_BORNE, 7, 0.5f)); } /** * Create a dodging Dragon Knight * - * @return + * @return Dodging dragon knight */ public static Entity createDodgingDragonKnight(int health) { Entity dodgeKnight = createDragonKnight(health); dodgeKnight.addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f)); // dodgeKnight.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector2(2f, 2f), 2f, 5)); - dodgeKnight.getComponent(AITaskComponent.class). - addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5)); + // dodgeKnight.getComponent(AITaskComponent.class). + // addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5)); + dodgeKnight.getComponent(AITaskComponent.class).getTask(MobTask.class).setDodge(true); PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f); dodgeKnight.setScale(0.3f, 0.7f); @@ -573,15 +647,16 @@ public static Entity createDodgingDragonKnight(int health) { /** * Create a dodging Arcane Archer * - * @return + * @return Dodging arcane */ public static Entity createDodgingArcaneArcher(int health) { Entity dodgeKnight = createArcaneArcher(health); dodgeKnight.addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f)); // dodgeKnight.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector2(2f, 2f), 2f, 5)); - dodgeKnight.getComponent(AITaskComponent.class). - addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5)); + // dodgeKnight.getComponent(AITaskComponent.class). + // addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5)); + dodgeKnight.getComponent(AITaskComponent.class).getTask(MobTask.class).setDodge(true); PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f); dodgeKnight.setScale(0.3f, 0.7f); @@ -593,14 +668,20 @@ public static Entity createDodgingArcaneArcher(int health) { // deflectXenoGrunt.addComponent(new DeflectingComponent( /** * Creates a wizard that can deflect bullets - * @return + * @return Deflecting wizard */ public static Entity createDeflectWizard(int health) { - Entity deflectWizard = createWizard(health); - deflectWizard.addComponent(new DeflectingComponent( + return createWizard(health).addComponent(new DeflectingComponent( PhysicsLayer.PROJECTILE, PhysicsLayer.TOWER, 10)); + } - return deflectWizard; + /** + * Creates a wizard that can deflect bullets + * @return Deflecting firewizard + */ + public static Entity createDeflectFireWizard(int health) { + return createFirewizard(health).addComponent(new DeflectingComponent( + PhysicsLayer.PROJECTILE, PhysicsLayer.TOWER, 10)); } } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java index d07b91497..f6cce1e6f 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java @@ -2,6 +2,8 @@ import com.csse3200.game.ai.tasks.AITaskComponent; import com.csse3200.game.components.CombatStatsComponent; +import com.csse3200.game.components.EffectComponent; +import com.csse3200.game.components.EffectsComponent; import com.csse3200.game.components.TouchAttackComponent; import com.csse3200.game.components.player.InventoryComponent; import com.csse3200.game.components.player.PlayerActions; @@ -47,6 +49,7 @@ public static Entity createPlayer() { .addComponent(new CombatStatsComponent(1000, 0)) .addComponent(new InventoryComponent(stats.gold)) .addComponent(inputComponent) + .addComponent(new EffectComponent(false)) .addComponent(new PlayerStatsDisplay()); PhysicsUtils.setScaledCollider(player, 0.6f, 0.3f); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index 81ff0012f..b98c5bde0 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -2,6 +2,8 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Filter; +import com.csse3200.game.components.EffectComponent; +import com.csse3200.game.components.EffectsComponent; import com.csse3200.game.components.tasks.DroidCombatTask; import com.csse3200.game.components.tasks.TNTTowerCombatTask; import com.csse3200.game.components.tasks.*; @@ -452,6 +454,7 @@ public static Entity createBaseTower() { Entity tower = new Entity() .addComponent(new ColliderComponent()) + .addComponent(new EffectComponent(false)) .addComponent(new HitboxComponent().setLayer(PhysicsLayer.TOWER)) // TODO: we might have to change the names of the layers .addComponent(new PhysicsComponent().setBodyType(BodyType.StaticBody)) .addComponent(new TowerUpgraderComponent()); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/WaveFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/WaveFactory.java index a064173e0..c0526e42b 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/WaveFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/WaveFactory.java @@ -36,38 +36,38 @@ public class WaveFactory { private static final ArrayList> lvl1Structure = new ArrayList<>(Arrays.asList( new ArrayList<>(Arrays.asList("Coat" )), new ArrayList<>(Arrays.asList("Coat", "WaterQueen" - )), new ArrayList<>(Arrays.asList("WaterQueen", "SplittingWaterSlime" - )), new ArrayList<>(Arrays.asList("Coat", "WaterQueen", "SplittingWaterSlime" + )), new ArrayList<>(Arrays.asList("WaterQueen", "WaterQueen" + )), new ArrayList<>(Arrays.asList("Coat", "WaterQueen", "Coat" )) )); private static final ArrayList> lvl2Structure = new ArrayList<>(Arrays.asList( new ArrayList<>(Arrays.asList("Skeleton" + )), new ArrayList<>(Arrays.asList("Skeleton", "SplittingNightBorne" + )), new ArrayList<>(Arrays.asList("Skeleton", "Wizard" )), new ArrayList<>(Arrays.asList("Skeleton", "ArcaneArcher" - )), new ArrayList<>(Arrays.asList("Skeleton", "DeflectWizard" - )), new ArrayList<>(Arrays.asList("Skeleton", "NightBorne" - )), new ArrayList<>(Arrays.asList("DeflectWizard", "NightBorne" - )), new ArrayList<>(Arrays.asList("NightBorne", "Skeleton" - )), new ArrayList<>(Arrays.asList("DeflectWizard", "NightBorne" - )), new ArrayList<>(Arrays.asList("ArcaneArcher", "NightBorne", "DeflectWizard" - )), new ArrayList<>(Arrays.asList("Skeleton", "ArcaneArcher", "DeflectWizard", "NightBorne" + )), new ArrayList<>(Arrays.asList("Wizard", "SplittingNightBorne" + )), new ArrayList<>(Arrays.asList("SplittingNightBorne", "Skeleton" + )), new ArrayList<>(Arrays.asList("Wizard", "SplittingNightBorne" + )), new ArrayList<>(Arrays.asList("ArcaneArcher", "SplittingNightBorne", "Wizard" + )), new ArrayList<>(Arrays.asList("Skeleton", "ArcaneArcher", "Wizard", "SplittingNightBorne" )) )); private static final ArrayList> lvl3Structure = new ArrayList<>(Arrays.asList( - new ArrayList<>(Arrays.asList("Coat" - )), new ArrayList<>(Arrays.asList("Coat", "DodgingDragon" - )), new ArrayList<>(Arrays.asList("Coat", "FireWorm" - )), new ArrayList<>(Arrays.asList("Coat", "Coat" - )), new ArrayList<>(Arrays.asList("Coat", "FireWorm" + new ArrayList<>(Arrays.asList("Necromancer" + )), new ArrayList<>(Arrays.asList("Necromancer", "DodgingDragon" + )), new ArrayList<>(Arrays.asList("Necromancer", "FireWorm" + )), new ArrayList<>(Arrays.asList("Necromancer", "FireWorm" + )), new ArrayList<>(Arrays.asList("SplittingRocky", "FireWorm" )), new ArrayList<>(Arrays.asList("DodgingDragon", "FireWorm" - )), new ArrayList<>(Arrays.asList("DodgingDragon", "Coat" - )), new ArrayList<>(Arrays.asList("FireWorm", "Coat" - )), new ArrayList<>(Arrays.asList("Coat", "Coat" - )), new ArrayList<>(Arrays.asList("DodgingDragon", "Coat", "Coat" - )), new ArrayList<>(Arrays.asList("FireWorm", "Coat", "DodgingDragon" - )), new ArrayList<>(Arrays.asList("FireWorm", "Coat", "Coat" - )), new ArrayList<>(Arrays.asList("Coat", "Coat", "Coat", "DodgingDragon", "FireWorm" + )), new ArrayList<>(Arrays.asList("DodgingDragon", "Necromancer" + )), new ArrayList<>(Arrays.asList("FireWorm", "Necromancer" + )), new ArrayList<>(Arrays.asList("DeflectFireWiza","SplittingRocky", "Necromancer" + )), new ArrayList<>(Arrays.asList("DodgingDragon", "DeflectFireWizard", "SplittingRocky", "Necromancer" + )), new ArrayList<>(Arrays.asList("FireWorm", "DeflectWizard", "DodgingDragon" + )), new ArrayList<>(Arrays.asList("FireWorm", "DeflectWizard", "Necromancer" + )), new ArrayList<>(Arrays.asList("Necromancer", "DeflectFireWizard", "SplittingRocky", "DodgingDragon", "FireWorm" )) )); @@ -153,7 +153,7 @@ public static LevelWaves createLevel(int chosenLevel) { minMobs = 8; break; default: - boss = BOSS_2; + boss = BOSS_1; bossHealth = LVL1_BOSS_BASE_HEALTH; possibleMobs = lvl1Structure; minMobs = 5; diff --git a/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java b/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java index 7f7d9cd00..e21cec99c 100644 --- a/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java +++ b/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java @@ -212,7 +212,6 @@ public void render(float delta) { ServiceLocator.getWaveService().getDisplay().updateTimerButton(); ServiceLocator.getWaveService().getDisplay().updateMobCount(); - ServiceLocator.getWaveService().getDisplay().updateLevelProgressBar(); renderer.render(); // Check if the game has ended @@ -297,7 +296,7 @@ private void createUI() { .addComponent(new MainGameActions(this.game)) .addComponent(ServiceLocator.getWaveService().getDisplay()) //.addComponent(new MainGameWinDisplay()) <- needs to be uncommented when team 3 have implemented the ui - .addComponent(new MainGameDisplay(this.game)) + .addComponent(new MainGameDisplay(this.game, selectedLevel)) .addComponent(new Terminal()) .addComponent(buildHandler) .addComponent(inputComponent) diff --git a/source/core/src/main/com/csse3200/game/services/GameTime.java b/source/core/src/main/com/csse3200/game/services/GameTime.java index fce525778..8ac6f9d5a 100644 --- a/source/core/src/main/com/csse3200/game/services/GameTime.java +++ b/source/core/src/main/com/csse3200/game/services/GameTime.java @@ -7,10 +7,9 @@ /** Controls the game time */ public class GameTime { - private static Logger logger = LoggerFactory.getLogger(GameTime.class); + private static final Logger logger = LoggerFactory.getLogger(GameTime.class); private final long startTime; private float timeScale = 1f; - private boolean paused = false; public GameTime() { diff --git a/source/core/src/main/com/csse3200/game/services/WaveService.java b/source/core/src/main/com/csse3200/game/services/WaveService.java index a32f6c0f2..5b95d3766 100644 --- a/source/core/src/main/com/csse3200/game/services/WaveService.java +++ b/source/core/src/main/com/csse3200/game/services/WaveService.java @@ -20,6 +20,8 @@ public class WaveService { private int spawnDelay; private boolean skipDelay = false; + private boolean gamePaused = false; + private long pauseBeginTime = 0; private int levelEnemyCount = 0; private int remainingLevelEnemyCount = 0; @@ -166,6 +168,27 @@ public boolean shouldSkip() { return this.skipDelay; } + /** + * Return whether the game is currently paused or not. + * @return the gamePaused variable. + */ + public boolean getGamePaused() {return this.gamePaused;} + + /** + * Toggles whether the game is paused or not, to keep track of how long the game is paused. + * When unpaused, offsets the NextWaveTime by however long the game has been paused. + */ + public void toggleGamePause() { + if (gamePaused) { + long pauseDuration = ServiceLocator.getTimeSource().getTime() - pauseBeginTime; + long updatedNextWaveTime = getNextWaveTime() + pauseDuration; + setNextWaveTime(updatedNextWaveTime); + } else { + pauseBeginTime = ServiceLocator.getTimeSource().getTime(); + } + gamePaused = !gamePaused; + } + /** * retrieve the number of enemies in the level * */ diff --git a/source/core/src/test/com/csse3200/game/components/DeflectingComponentTest.java b/source/core/src/test/com/csse3200/game/components/DeflectingComponentTest.java index 735af2f17..ae532d91c 100644 --- a/source/core/src/test/com/csse3200/game/components/DeflectingComponentTest.java +++ b/source/core/src/test/com/csse3200/game/components/DeflectingComponentTest.java @@ -35,7 +35,7 @@ import com.csse3200.game.services.ServiceLocator; @ExtendWith(GameExtension.class) -public class DeflectingComponentTest { +class DeflectingComponentTest { Entity baseMob; private static final int DEFAULT_ATTACK = 10; private static final int DEFAULT_DEFENSE = 10; @@ -73,13 +73,13 @@ public void setUp() { } @Test - public void shouldNotBeNull() { + void shouldNotBeNull() { assertNotNull("Deflecting component does not exist", baseMob.getComponent(DeflectingComponent.class)); } @Test - public void shouldNotBeDisposed() { + void shouldNotBeDisposed() { Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); triggerCollisionStart(baseMob, projectile); @@ -91,7 +91,7 @@ public void shouldNotBeDisposed() { } @Test - public void shouldBeDisposedWhenDisabled() { + void shouldBeDisposedWhenDisabled() { Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); baseMob.getComponent(DeflectingComponent.class).setEnabled(false); @@ -104,7 +104,7 @@ public void shouldBeDisposedWhenDisabled() { } @Test - public void shouldInvokeDeflectProjEvent() { + void shouldInvokeDeflectProjEvent() { EventListener2 deflectProj = mock(EventListener2.class); Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); @@ -119,7 +119,7 @@ public void shouldInvokeDeflectProjEvent() { } @Test - public void shouldInvokeXAmtTimes() { + void shouldInvokeXAmtTimes() { EventListener2 deflectProj = mock(EventListener2.class); Entity mob = createDeflectMob(3, VALID_POSITION_Y, VALID_POSITION_X); Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); @@ -155,7 +155,7 @@ public void shouldInvokeXAmtTimes() { } @Test - public void shouldInvokeAtMostOnce() { + void shouldInvokeAtMostOnce() { EventListener2 deflectProj = mock(EventListener2.class); Entity mob = createDeflectMob(1, VALID_POSITION_Y, VALID_POSITION_X); Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); @@ -177,7 +177,7 @@ public void shouldInvokeAtMostOnce() { } @Test - public void shouldReverseProjScaleX() { + void shouldReverseProjScaleX() { Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); float initialX = projectile.getScale().x; @@ -191,7 +191,7 @@ public void shouldReverseProjScaleX() { } @Test - public void shouldRemainSameHealth() { + void shouldRemainSameHealth() { Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); int health = baseMob.getComponent(CombatStatsComponent.class) .getHealth(); @@ -205,7 +205,7 @@ public void shouldRemainSameHealth() { } @Test - public void shouldNotChangeHealthWhenDisabled() { + void shouldNotChangeHealthWhenDisabled() { Entity projectile = createProjectile(VALID_POSITION_X, VALID_POSITION_Y); baseMob.getComponent(CombatStatsComponent.class).setHealth(100); int health = baseMob.getComponent(CombatStatsComponent.class).getHealth(); diff --git a/source/core/src/test/com/csse3200/game/components/DodgingComponentTest.java b/source/core/src/test/com/csse3200/game/components/DodgingComponentTest.java index 603b66e33..05369c3a5 100644 --- a/source/core/src/test/com/csse3200/game/components/DodgingComponentTest.java +++ b/source/core/src/test/com/csse3200/game/components/DodgingComponentTest.java @@ -14,8 +14,8 @@ import com.csse3200.game.components.npc.DodgingComponent; import com.csse3200.game.components.tasks.MobDodgeTask; import com.csse3200.game.components.tasks.MobWanderTask; -import com.csse3200.game.components.tasks.MobTask.MobTask; -import com.csse3200.game.components.tasks.MobTask.MobType; +import com.csse3200.game.components.tasks.mobtask.MobTask; +import com.csse3200.game.components.tasks.mobtask.MobType; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.EntityService; import com.csse3200.game.entities.factories.NPCFactory; @@ -32,7 +32,7 @@ import com.csse3200.game.services.ServiceLocator; @ExtendWith(GameExtension.class) -public class DodgingComponentTest { +class DodgingComponentTest { Entity baseMob, baseProjectile; private static final float VALID_POSITION_Y = 4; private static final float VALID_POSITION_X = 7; @@ -60,23 +60,24 @@ public void setUp() { DEFAULT_RANGE_DETECTION, 1.75f); // task = new MobDodgeTask(new Vector2(2f, 2f), 2f, 5); - task = new MobDodgeTask(MobType.DRAGON_KNIGHT, 5); + // task = new MobDodgeTask(MobType.DRAGON_KNIGHT, 5); + task = new MobTask(MobType.DRAGON_KNIGHT, true); } @Test - public void shouldNotBeNullComponent() { + void shouldNotBeNullComponent() { assertNotNull("Dodging combat component should not be null", baseMob.getComponent(DodgingComponent.class)); } @Test - public void shouldNotBeNullTask() { + void shouldNotBeNullTask() { assertNotNull("Mob dodging tasks should not be null", baseMob.getComponent(AITaskComponent.class)); } @Test - public void shouldInvokeDodgeEvent() { + void shouldInvokeDodgeEvent() { EventListener1 dodgeProj = mock(EventListener1.class); baseMob.getComponent(AITaskComponent.class).addTask(task); baseMob.getEvents().addListener(DodgingComponent.DODGE_EVENT, dodgeProj); diff --git a/source/core/src/test/com/csse3200/game/components/RicochetComponentTest.java b/source/core/src/test/com/csse3200/game/components/RicochetComponentTest.java index 00a16daa3..49d1295ca 100644 --- a/source/core/src/test/com/csse3200/game/components/RicochetComponentTest.java +++ b/source/core/src/test/com/csse3200/game/components/RicochetComponentTest.java @@ -26,7 +26,7 @@ import com.csse3200.game.services.ServiceLocator; @ExtendWith(GameExtension.class) -public class RicochetComponentTest { +class RicochetComponentTest { Entity projectile; Entity mob; @@ -60,18 +60,18 @@ public void setUp() { } @Test - public void shouldNotBeNull() { + void shouldNotBeNull() { assertNotNull(projectile, "Ricochet projectile does not exist"); } @Test - public void shouldHaveRicochetComponent() { + void shouldHaveRicochetComponent() { assertNotNull(projectile.getComponent(RicochetComponent.class), "Projectile does not contain RicochetComponent"); } @Test - public void shouldDisposeAferCollision() { + void shouldDisposeAferCollision() { int currentEntities = ServiceLocator.getEntityService().getEntities().size; triggerCollisionEnd(projectile, mob); @@ -88,7 +88,7 @@ public void shouldDisposeAferCollision() { // @Ignore @Test - public void shouldSpawnAnotherProjWithinMapBounds() { + void shouldSpawnAnotherProjWithinMapBounds() { projectile.setPosition(3, 3); int currentEntities = ServiceLocator.getEntityService().getEntities().size; @@ -102,7 +102,7 @@ public void shouldSpawnAnotherProjWithinMapBounds() { } @Test - public void shouldNotSpawnAnotherProjOutOfMapBounds() { + void shouldNotSpawnAnotherProjOutOfMapBounds() { projectile.setPosition(-1, -1); int currentEntities = ServiceLocator.getEntityService().getEntities().size; @@ -117,7 +117,7 @@ public void shouldNotSpawnAnotherProjOutOfMapBounds() { } @Test - public void testWithinRangeSpawnedProjectile() { + void testWithinRangeSpawnedProjectile() { projectile.setPosition(3, 3); mob.setPosition(3, 3); @@ -133,7 +133,7 @@ public void testWithinRangeSpawnedProjectile() { } @Test - public void testNotWithinRangeShouldNotSpawnProjectile() { + void testNotWithinRangeShouldNotSpawnProjectile() { projectile.setPosition(3, 3); mob.setPosition(3, 3); triggerCollisionEnd(projectile, mob); @@ -146,7 +146,7 @@ public void testNotWithinRangeShouldNotSpawnProjectile() { } @Test - public void shouldNotSpawnAnotherProjWithMaxBounceCount() { + void shouldNotSpawnAnotherProjWithMaxBounceCount() { Entity newProjectile = createProjectile(PhysicsLayer.NPC, 3); ServiceLocator.getEntityService().register(newProjectile); int currentEntities = ServiceLocator.getEntityService().getEntities().size; diff --git a/source/core/src/test/com/csse3200/game/components/SplitFireworksComponentTest.java b/source/core/src/test/com/csse3200/game/components/SplitFireworksComponentTest.java index 55e5decc2..06425c8d0 100644 --- a/source/core/src/test/com/csse3200/game/components/SplitFireworksComponentTest.java +++ b/source/core/src/test/com/csse3200/game/components/SplitFireworksComponentTest.java @@ -27,7 +27,7 @@ import com.csse3200.game.services.ServiceLocator; @ExtendWith(GameExtension.class) -public class SplitFireworksComponentTest { +class SplitFireworksComponentTest { Entity projectile; Entity mob; static double OFFSET_X = 1.75; @@ -63,18 +63,18 @@ public void setUp() { } @Test - public void shouldNotBeNull() { + void shouldNotBeNull() { assertNotNull(projectile, "Ricochet projectile does not exist"); } @Test - public void shouldHaveSplitFireworksComponent() { + void shouldHaveSplitFireworksComponent() { assertNotNull(projectile.getComponent(SplitFireworksComponent.class), "Projectile does not contain SplitFireworksComponent"); } @Test - public void shouldDisposeAferCollision() { + void shouldDisposeAferCollision() { triggerCollisionEnd(projectile, mob); assertTrue("original projectile entity flag should be true after collision", @@ -98,7 +98,7 @@ void shouldSpawnCorrectNumberOfProjs() { } @Test - public void shouldSpawnMultProjWithinMapBounds() { + void shouldSpawnMultProjWithinMapBounds() { projectile.setPosition(3, 3); mob.setPosition(3, 3); @@ -114,7 +114,7 @@ public void shouldSpawnMultProjWithinMapBounds() { } @Test - public void shouldNotSpawnMultProjOutOfMapBounds() { + void shouldNotSpawnMultProjOutOfMapBounds() { projectile.setPosition(22, 22); mob.setPosition(22, 22); @@ -130,7 +130,7 @@ public void shouldNotSpawnMultProjOutOfMapBounds() { } @Test - public void testWithinRangeSpawnedProjectiles() { + void testWithinRangeSpawnedProjectiles() { projectile.setPosition(3, 3); mob.setPosition(3, 3); @@ -144,7 +144,7 @@ public void testWithinRangeSpawnedProjectiles() { } @Test - public void testTooCloseRangeSpawnedProjectiles() { + void testTooCloseRangeSpawnedProjectiles() { projectile.setPosition(3, 3); mob.setPosition(3, 3); @@ -159,7 +159,7 @@ public void testTooCloseRangeSpawnedProjectiles() { } @Test - public void shouldSpawnAtSpecifiedLocation() { + void shouldSpawnAtSpecifiedLocation() { projectile.setPosition(3, 3); mob.setPosition(3, 3); float currPosition = projectile.getPosition().x; diff --git a/source/core/src/test/com/csse3200/game/components/SplitMoblingsTest.java b/source/core/src/test/com/csse3200/game/components/SplitMoblingsTest.java index ba3da58ad..a28f836a1 100644 --- a/source/core/src/test/com/csse3200/game/components/SplitMoblingsTest.java +++ b/source/core/src/test/com/csse3200/game/components/SplitMoblingsTest.java @@ -19,6 +19,7 @@ import com.badlogic.gdx.math.Vector2; import com.csse3200.game.components.npc.SplitMoblings; +import com.csse3200.game.components.tasks.mobtask.MobType; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.EntityService; import com.csse3200.game.entities.factories.NPCFactory; @@ -36,7 +37,7 @@ import com.csse3200.game.services.WaveService; @ExtendWith(GameExtension.class) -public class SplitMoblingsTest { +class SplitMoblingsTest { private static final int BASE_Y_COORD = 3; private static final int BASE_AMOUNT = 5; private final String[] atlas = { @@ -72,14 +73,14 @@ public void setUp() { } @Test - public void shouldNotBeNull() { + void shouldNotBeNull() { Entity mob = createSplitMob(5); assertNotNull("Mobling components does not exists", mob.getComponent(SplitMoblings.class)); } @Test - public void shouldHaveAsset() { + void shouldHaveAsset() { Entity projectile = createDummyProjectile(); baseMob.setPosition(SplitMoblings.MIN_X_BOUNDS + 2, SplitMoblings.MIN_Y_BOUNDS + 2); @@ -96,7 +97,7 @@ public void shouldHaveAsset() { } @Test - public void shouldBeDisposedAfterDeath() { + void shouldBeDisposedAfterDeath() { Entity projectile = createDummyProjectile(); projectile.getComponent(CombatStatsComponent.class).setBaseAttack(20); @@ -118,7 +119,7 @@ public void shouldBeDisposedAfterDeath() { } @Test - public void shouldInvokeDieStartEventAfterDeath() { + void shouldInvokeDieStartEventAfterDeath() { EventListener0 dieStart = mock(EventListener0.class); baseMob.getComponent(CombatStatsComponent.class).setHealth(0); @@ -134,7 +135,7 @@ public void shouldInvokeDieStartEventAfterDeath() { } @Test - public void shouldNotInvokeDieStartEventNoDeath() { + void shouldNotInvokeDieStartEventNoDeath() { EventListener0 dieStart = mock(EventListener0.class); assertFalse("mob is dead when health is not 0", @@ -146,7 +147,7 @@ public void shouldNotInvokeDieStartEventNoDeath() { } @Test - public void shouldSplitCorrectAmount() { + void shouldSplitCorrectAmount() { Entity projectile = createDummyProjectile(); int allEntities = ServiceLocator.getEntityService().getEntities().size; @@ -168,7 +169,7 @@ public void shouldSplitCorrectAmount() { } @Test - public void shouldNotSplitCorrectAmountOutOfBounds() { + void shouldNotSplitCorrectAmountOutOfBounds() { Entity projectile = createDummyProjectile(); int allEntities = ServiceLocator.getEntityService().getEntities().size; @@ -190,7 +191,7 @@ public void shouldNotSplitCorrectAmountOutOfBounds() { } @Test - public void shouldSpawnWithinRangeAmountOne() { + void shouldSpawnWithinRangeAmountOne() { Entity mob = createSplitMob(1); Entity projectile = createDummyProjectile(); @@ -212,7 +213,7 @@ public void shouldSpawnWithinRangeAmountOne() { } @Test - public void shouldSpawnWithinRangeMultipleAmount() { + void shouldSpawnWithinRangeMultipleAmount() { Entity projectile = createDummyProjectile(); Entity mobThree = createSplitMob(3); Entity mobSeven = createSplitMob(7); @@ -250,7 +251,7 @@ public void shouldSpawnWithinRangeMultipleAmount() { } @Test - public void shouldScaleBasedOnParamsSingleAmt() { + void shouldScaleBasedOnParamsSingleAmt() { float scale = 1.5f; Entity mob = createSplitMob(1, scale); Entity projectile = createDummyProjectile(); @@ -276,7 +277,7 @@ public void shouldScaleBasedOnParamsSingleAmt() { } @Test - public void shouldScaleXAndYbasedOnParamsMultiAmt() { + void shouldScaleXAndYbasedOnParamsMultiAmt() { float scaleX = 0.5f; float scaleY = 1.75f; Entity mob = createSplitMob(5, scaleX, scaleY); @@ -309,17 +310,18 @@ public void shouldScaleXAndYbasedOnParamsMultiAmt() { } } + // For now water slimes will be moblings spawned Entity createSplitMob(int amount) { Entity mob = NPCFactory.createBaseWaterSlime(10); mob.addComponent(new CombatStatsComponent(10, 10)); - mob.addComponent(new SplitMoblings(amount)); + mob.addComponent(new SplitMoblings(MobType.WATER_SLIME, amount)); ServiceLocator.getEntityService().register(mob); return mob; } Entity createSplitMob(int amount, float scale) { Entity mob = NPCFactory.createBaseWaterSlime(10); - mob.addComponent(new SplitMoblings(amount, scale)); + mob.addComponent(new SplitMoblings(MobType.WATER_SLIME, amount, scale)); mob.addComponent(new CombatStatsComponent(10, 10)); ServiceLocator.getEntityService().register(mob); return mob; @@ -327,7 +329,7 @@ Entity createSplitMob(int amount, float scale) { Entity createSplitMob(int amount, float scaleX, float scaleY) { Entity mob = NPCFactory.createBaseWaterSlime(10); - mob.addComponent(new SplitMoblings(amount, scaleX, scaleY)); + mob.addComponent(new SplitMoblings(MobType.WATER_SLIME, amount, scaleX, scaleY)); mob.addComponent(new CombatStatsComponent(10, 10)); ServiceLocator.getEntityService().register(mob); return mob; diff --git a/source/core/src/test/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponentTest.java b/source/core/src/test/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponentTest.java index 65cf8cb8b..f097b5bb3 100644 --- a/source/core/src/test/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponentTest.java +++ b/source/core/src/test/com/csse3200/game/components/pausemenu/PauseMenuTimeStopComponentTest.java @@ -3,7 +3,9 @@ import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.EntityService; import com.csse3200.game.extensions.GameExtension; +import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.services.WaveService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -17,6 +19,10 @@ public class PauseMenuTimeStopComponentTest { void beforeEach() { EntityService entityService = new EntityService(); ServiceLocator.registerEntityService(entityService); + WaveService waveService = new WaveService(); + ServiceLocator.registerWaveService(waveService); + GameTime gameTime = new GameTime(); + ServiceLocator.registerTimeSource(gameTime); entity = mock(Entity.class); when(entity.getId()).thenReturn(-1); //Ensure it does not coincide with the pause menu's ID entityService.register(entity); diff --git a/source/core/src/test/com/csse3200/game/components/tasks/MobAttackTaskTest.java b/source/core/src/test/com/csse3200/game/components/tasks/MobAttackTaskTest.java index e30c0e30d..243c1101f 100644 --- a/source/core/src/test/com/csse3200/game/components/tasks/MobAttackTaskTest.java +++ b/source/core/src/test/com/csse3200/game/components/tasks/MobAttackTaskTest.java @@ -12,6 +12,8 @@ class MobAttackTaskTest { @Mock GameTime gameTime; + //TODO: Add some tests to this class. + // @BeforeEach // void beforeEach() { // ServiceLocator.registerTimeSource(gameTime); diff --git a/source/core/src/test/com/csse3200/game/components/tasks/MobWanderTaskTest.java b/source/core/src/test/com/csse3200/game/components/tasks/MobWanderTaskTest.java index 56a4d8bed..102bd2673 100644 --- a/source/core/src/test/com/csse3200/game/components/tasks/MobWanderTaskTest.java +++ b/source/core/src/test/com/csse3200/game/components/tasks/MobWanderTaskTest.java @@ -18,6 +18,7 @@ class MobWanderTaskTest { void beforeEach() { ServiceLocator.registerTimeSource(gameTime); } + //TODO: Add some tests to this class. // @Test // void shouldTriggerEvent() { diff --git a/source/core/src/test/com/csse3200/game/components/xenos/XenoAnimationControllerTest.java b/source/core/src/test/com/csse3200/game/components/xenos/XenoAnimationControllerTest.java index 278e08ee7..aa0249b30 100644 --- a/source/core/src/test/com/csse3200/game/components/xenos/XenoAnimationControllerTest.java +++ b/source/core/src/test/com/csse3200/game/components/xenos/XenoAnimationControllerTest.java @@ -21,7 +21,7 @@ @ExtendWith(GameExtension.class) -public class XenoAnimationControllerTest { +class XenoAnimationControllerTest { private Entity xenoGrunt; private final String[] atlas = {"images/mobs/xenoGrunt.atlas"}; @@ -42,26 +42,27 @@ public void setUp() { } @Test - public void testAnimateWander() { + void testAnimateWander() { xenoGrunt.getEvents().trigger("wanderStart"); assertEquals("xeno_run", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); } @Test - public void testAnimateHurt() { + void testAnimateHurt() { xenoGrunt.getEvents().trigger("runHurt"); assertEquals("xeno_hurt", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); } @Test - public void testAnimateMelee1() { + void testAnimateMelee1() { + //TODO: Add at least one assertion to this test case. xenoGrunt.getEvents().trigger("meleeStart"); assert(Objects.equals(xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation(), "xeno_melee_1") || Objects.equals(xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation(), "xeno_melee_2")); } @Test - public void testAnimateDie() { + void testAnimateDie() { xenoGrunt.getEvents().trigger("dieStart"); assertEquals("xeno_die", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); } diff --git a/source/core/src/test/com/csse3200/game/entities/EnemyTest.java b/source/core/src/test/com/csse3200/game/entities/EnemyTest.java index d79eb4987..ea11925a8 100644 --- a/source/core/src/test/com/csse3200/game/entities/EnemyTest.java +++ b/source/core/src/test/com/csse3200/game/entities/EnemyTest.java @@ -13,7 +13,7 @@ @ExtendWith(GameExtension.class) -public class EnemyTest { +class EnemyTest { private ArrayList drops = new ArrayList<>(); // private ArrayList drops = new ArrayList<>(Arrays.asList(1,2)); diff --git a/source/core/src/test/com/csse3200/game/entities/factories/MobBossFactoryTest.java b/source/core/src/test/com/csse3200/game/entities/factories/MobBossFactoryTest.java index 6d2cdb538..8dcc791f2 100644 --- a/source/core/src/test/com/csse3200/game/entities/factories/MobBossFactoryTest.java +++ b/source/core/src/test/com/csse3200/game/entities/factories/MobBossFactoryTest.java @@ -12,7 +12,6 @@ import com.csse3200.game.entities.Entity; import com.csse3200.game.extensions.GameExtension; import com.csse3200.game.physics.PhysicsService; -import com.csse3200.game.physics.components.ColliderComponent; import com.csse3200.game.physics.components.HitboxComponent; import com.csse3200.game.physics.components.PhysicsComponent; import com.csse3200.game.physics.components.PhysicsMovementComponent; @@ -137,7 +136,7 @@ public void setUp() { } @Test - public void testCreateMobBossNotNull() { + void testCreateMobBossNotNull() { assertNotNull(baseBoss, "Base Boss should not be null."); assertNotNull(demon, "Demon Boss should not be null."); assertNotNull(slimeyBoy, "Slimey Boy should not be null."); @@ -147,7 +146,7 @@ public void testCreateMobBossNotNull() { } @Test - public void testMobBossPhysicsComponent() { + void testMobBossPhysicsComponent() { assertNotNull(baseBoss.getComponent(PhysicsComponent.class), "Base Boss does not have physics component."); assertNotNull(demon.getComponent(PhysicsComponent.class), @@ -163,7 +162,7 @@ public void testMobBossPhysicsComponent() { } // @Test -// public void testMobBossColliderComponent() { +// void testMobBossColliderComponent() { // assertNotNull(baseBoss.getComponent(ColliderComponent.class), // "Base Boss does not have collider component."); // assertNotNull(demon.getComponent(ColliderComponent.class), @@ -179,7 +178,7 @@ public void testMobBossPhysicsComponent() { // } @Test - public void testMobBossPhysicsMovementComponent() { + void testMobBossPhysicsMovementComponent() { assertNotNull(baseBoss.getComponent(PhysicsMovementComponent.class), "Base Boss does not have physics movement component."); assertNotNull(demon.getComponent(PhysicsMovementComponent.class), @@ -195,7 +194,7 @@ public void testMobBossPhysicsMovementComponent() { } @Test - public void testMobBossHitboxComponent() { + void testMobBossHitboxComponent() { assertNotNull(baseBoss.getComponent(HitboxComponent.class), "Base Boss does not have hitbox component."); assertNotNull(demon.getComponent(HitboxComponent.class), @@ -210,7 +209,7 @@ public void testMobBossHitboxComponent() { "Ice Baby Boss does not have hitbox component."); } @Test - public void testMobBossTouchAttackComponent() { + void testMobBossTouchAttackComponent() { assertNotNull(baseBoss.getComponent(TouchAttackComponent.class), "Base Boss does not have touch attack component."); assertNotNull(demon.getComponent(TouchAttackComponent.class), @@ -226,7 +225,7 @@ public void testMobBossTouchAttackComponent() { } @Test - public void testMobBossCombatStats(){ + void testMobBossCombatStats(){ assertEquals(80, demon.getComponent(CombatStatsComponent.class).getHealth(), "Demon Boss health should be 5000."); assertEquals(0, demon.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -250,7 +249,7 @@ public void testMobBossCombatStats(){ } @Test - public void testMobBossAnimationRenderComponent() { + void testMobBossAnimationRenderComponent() { assertNotNull(demon.getComponent(AnimationRenderComponent.class), "Demon Boss does not have an animation render component."); assertNotNull(slimeyBoy.getComponent(AnimationRenderComponent.class), @@ -264,7 +263,7 @@ public void testMobBossAnimationRenderComponent() { } @Test - public void testMobBossAnimationController() { + void testMobBossAnimationController() { assertNotNull(demon.getComponent(DemonAnimationController.class), "Demon Boss does not have an animation controller."); assertNotNull(slimeyBoy.getComponent(DemonAnimationController.class), diff --git a/source/core/src/test/com/csse3200/game/entities/factories/NPCFactoryTest.java b/source/core/src/test/com/csse3200/game/entities/factories/NPCFactoryTest.java index 3023a55db..cbb0090d7 100644 --- a/source/core/src/test/com/csse3200/game/entities/factories/NPCFactoryTest.java +++ b/source/core/src/test/com/csse3200/game/entities/factories/NPCFactoryTest.java @@ -33,7 +33,7 @@ import static org.mockito.Mockito.when; @ExtendWith(GameExtension.class) -public class NPCFactoryTest { +class NPCFactoryTest { private Entity rangedBaseNpc; private Entity meleeBaseNpc; @@ -75,7 +75,10 @@ public class NPCFactoryTest { "sounds/mobs/waterQueenSpell.mp3", "sounds/mobs/boneBreak.mp3", "sounds/mobs/fireWormRoar.mp3", - "sounds/mobs/wizardSpell.mp3" + "sounds/mobs/wizardSpell.mp3", + "sounds/mobs/archerArrow.mp3", + "sounds/mobs/coatAttack.mp3", + "sounds/mobs/skeletonHit.mp3" }; @@ -116,81 +119,81 @@ public void setUp() { } @Test - public void testCreateRangedBaseNpcNotNull() { + void testCreateRangedBaseNpcNotNull() { assertNotNull(rangedBaseNpc, "base Ranged NPC should not be null"); } @Test - public void testCreateRangedBaseNpcHasColliderComponent() { + void testCreateRangedBaseNpcHasColliderComponent() { assertNotNull(rangedBaseNpc.getComponent(ColliderComponent.class), "Fire Worm should have ColliderComponent"); } @Test - public void testCreateRangedBaseNpcHasHitboxComponent() { + void testCreateRangedBaseNpcHasHitboxComponent() { assertNotNull(rangedBaseNpc.getComponent(HitboxComponent.class), "Fire Worm should have HitboxComponent"); } @Test - public void testCreateRangedBaseNpcHasPhysicsComponent() { + void testCreateRangedBaseNpcHasPhysicsComponent() { assertNotNull(rangedBaseNpc.getComponent(PhysicsComponent.class), "Fire Worm should have PhysicsComponent"); } @Test - public void testCreateRangedBaseNpcHasPhysicsMovementComponent() { + void testCreateRangedBaseNpcHasPhysicsMovementComponent() { assertNotNull(rangedBaseNpc.getComponent(PhysicsMovementComponent.class), "Fire Worm should have PhysicsMovementComponent"); } @Test - public void testCreateRangedBaseNpcHasAIComponent() { + void testCreateRangedBaseNpcHasAIComponent() { assertNotNull(rangedBaseNpc.getComponent(AITaskComponent.class), "Fire Worm should have PhysicsMovementComponent"); } @Test - public void testCreateMeleeBaseNpcNotNull() { + void testCreateMeleeBaseNpcNotNull() { assertNotNull(meleeBaseNpc, "base Ranged NPC should not be null"); } @Test - public void testCreateMeleeBaseNpcHasColliderComponent() { + void testCreateMeleeBaseNpcHasColliderComponent() { assertNotNull(meleeBaseNpc.getComponent(ColliderComponent.class), "Fire Worm should have ColliderComponent"); } @Test - public void testCreateMeleeBaseNpcHasHitboxComponent() { + void testCreateMeleeBaseNpcHasHitboxComponent() { assertNotNull(meleeBaseNpc.getComponent(HitboxComponent.class), "Fire Worm should have HitboxComponent"); } @Test - public void testCreateMeleeBaseNpcHasPhysicsComponent() { + void testCreateMeleeBaseNpcHasPhysicsComponent() { assertNotNull(meleeBaseNpc.getComponent(PhysicsComponent.class), "Fire Worm should have PhysicsComponent"); } @Test - public void testCreateMeleeBaseNpcHasPhysicsMovementComponent() { + void testCreateMeleeBaseNpcHasPhysicsMovementComponent() { assertNotNull(meleeBaseNpc.getComponent(PhysicsMovementComponent.class), "Fire Worm should have PhysicsMovementComponent"); } @Test - public void testCreateMeleeBaseNpcHasAIComponent() { + void testCreateMeleeBaseNpcHasAIComponent() { assertNotNull(rangedBaseNpc.getComponent(AITaskComponent.class), "Fire Worm should have PhysicsMovementComponent"); } @Test - public void testCreateWaterSlime() { + void testCreateWaterSlime() { assertNotNull(waterSlime, "Water Slime should not be null"); } @Test - public void testWaterSlimeCombatStatsComponent() { + void testWaterSlimeCombatStatsComponent() { assertEquals(60, waterSlime.getComponent(CombatStatsComponent.class).getHealth(), "Health should be 100"); assertEquals(0, waterSlime.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -198,36 +201,36 @@ public void testWaterSlimeCombatStatsComponent() { } @Test - public void waterSlimeHasAnimationComponent() { + void waterSlimeHasAnimationComponent() { assertNotNull(waterSlime.getComponent(AnimationRenderComponent.class), "Water Slime should have AnimationRenderComponent"); } @Test - public void testCreateWaterSlimeHasAnimationController() { + void testCreateWaterSlimeHasAnimationController() { assertNotNull(waterSlime.getComponent(WaterSlimeAnimationController.class), "Water Slime should have an Animation Controller"); } @Test - public void testSplitWaterSlime() { + void testSplitWaterSlime() { assertNotNull(splitWaterSlime, "Water Slime should not be Null"); } @Test - public void testSplitWaterSlimeHasSplittingComponent() { + void testSplitWaterSlimeHasSplittingComponent() { Entity splitWaterSlime = NPCFactory.createSplittingWaterSlime(60); assertNotNull(splitWaterSlime.getComponent(SplitMoblings.class), "Split water slimes should have a splitting component"); } @Test - public void testCreateWaterQueenNotNull() { + void testCreateWaterQueenNotNull() { assertNotNull(waterQueen, "Water Queen should not be null"); } @Test - public void testWaterQueenCombatStatsComponent() { + void testWaterQueenCombatStatsComponent() { assertEquals(60, waterQueen.getComponent(CombatStatsComponent.class).getHealth(), "Health should be 100"); assertEquals(0, waterQueen.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -235,24 +238,24 @@ public void testWaterQueenCombatStatsComponent() { } @Test - public void waterQueenHasAnimationComponent() { + void waterQueenHasAnimationComponent() { assertNotNull(waterQueen.getComponent(AnimationRenderComponent.class), "Water Queen should have AnimationRenderComponent"); } @Test - public void testCreateWaterQueenHasAnimationController() { + void testCreateWaterQueenHasAnimationController() { assertNotNull(waterQueen.getComponent(WaterQueenAnimationController.class), "Water Queen should have an Animation controller"); } @Test - public void testCreateFireWormNotNull() { + void testCreateFireWormNotNull() { assertNotNull(fireWorm, "Fire Worm should not be null"); } @Test - public void testFireWormCombatStatsComponent() { + void testFireWormCombatStatsComponent() { assertEquals(60, fireWorm.getComponent(CombatStatsComponent.class).getHealth(), "Health should be 100"); assertEquals(0, fireWorm.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -260,23 +263,23 @@ public void testFireWormCombatStatsComponent() { } @Test - public void fireWormHasAnimationComponent() { + void fireWormHasAnimationComponent() { assertNotNull(fireWorm.getComponent(AnimationRenderComponent.class), "Fire Worm should have AnimationRenderComponent"); } @Test - public void fireWormHasAnimationController() { + void fireWormHasAnimationController() { assertNotNull(fireWorm.getComponent(FireWormAnimationController.class), "Fire Worm should have AnimationRenderComponent"); } @Test - public void testCreateDragonKnightNotNull() { + void testCreateDragonKnightNotNull() { assertNotNull(dragonKnight, "Dragon Knight should not be null"); } @Test - public void testDragonKnightCombatStatsComponent() { + void testDragonKnightCombatStatsComponent() { assertEquals(60, dragonKnight.getComponent(CombatStatsComponent.class).getHealth(), "Health should be 100"); assertEquals(0, dragonKnight.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -284,30 +287,30 @@ public void testDragonKnightCombatStatsComponent() { } @Test - public void dragonKnightHasAnimationComponent() { + void dragonKnightHasAnimationComponent() { assertNotNull(dragonKnight.getComponent(AnimationRenderComponent.class), "Dragon Knight should have AnimationRenderComponent"); } @Test - public void dragonKnightHasAnimationController() { + void dragonKnightHasAnimationController() { assertNotNull(dragonKnight.getComponent(DragonKnightAnimationController.class), "Dragon Knight should have Animation Controller"); } @Test - public void dodgingDragonKnightHasDodgingComponent() { + void dodgingDragonKnightHasDodgingComponent() { assertNotNull(dodgingDragonKnight.getComponent(DodgingComponent.class), "Dragon Knight should have AnimationRenderComponent"); } @Test - public void testCreateWizardNotNull() { + void testCreateWizardNotNull() { assertNotNull(wizard, "Wizard should not be null"); } @Test - public void testWizardCombatStatsComponent() { + void testWizardCombatStatsComponent() { assertEquals(60, wizard.getComponent(CombatStatsComponent.class).getHealth(), "Health should be 100"); assertEquals(0, wizard.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -315,30 +318,30 @@ public void testWizardCombatStatsComponent() { } @Test - public void wizardHasAnimationComponent() { + void wizardHasAnimationComponent() { assertNotNull(wizard.getComponent(AnimationRenderComponent.class), "Wizard should have AnimationRenderComponent"); } @Test - public void wizardHasAnimationController() { + void wizardHasAnimationController() { assertNotNull(wizard.getComponent(WizardAnimationController.class), "Wizard should have Animation Controller"); } @Test - public void dodgingWizardHasDeflectingComponent() { + void dodgingWizardHasDeflectingComponent() { assertNotNull(deflectWizard.getComponent(DeflectingComponent.class), "Deflecting Wizard should have Deflecting component"); } @Test - public void testCreateSkeletonNotNull() { + void testCreateSkeletonNotNull() { assertNotNull(skeleton, "skeleton should not be null"); } @Test - public void testSkeletonCombatStatsComponent() { + void testSkeletonCombatStatsComponent() { assertEquals(60, skeleton.getComponent(CombatStatsComponent.class).getHealth(), "Health should be 100"); assertEquals(0, skeleton.getComponent(CombatStatsComponent.class).getBaseAttack(), @@ -346,13 +349,13 @@ public void testSkeletonCombatStatsComponent() { } @Test - public void skeletonHasAnimationComponent() { + void skeletonHasAnimationComponent() { assertNotNull(skeleton.getComponent(AnimationRenderComponent.class), "skeleton should have AnimationRenderComponent"); } @Test - public void skeletonHasAnimationController() { + void skeletonHasAnimationController() { assertNotNull(skeleton.getComponent(SkeletonAnimationController.class), "skeleton should have an Animation Controller"); } diff --git a/source/core/src/test/com/csse3200/game/entities/factories/PauseMenuFactoryTest.java b/source/core/src/test/com/csse3200/game/entities/factories/PauseMenuFactoryTest.java index e62fe61cc..1feb7101f 100644 --- a/source/core/src/test/com/csse3200/game/entities/factories/PauseMenuFactoryTest.java +++ b/source/core/src/test/com/csse3200/game/entities/factories/PauseMenuFactoryTest.java @@ -7,8 +7,10 @@ import com.csse3200.game.entities.EntityService; import com.csse3200.game.extensions.GameExtension; import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ResourceService; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.services.WaveService; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import static org.junit.jupiter.api.Assertions.*; @@ -27,6 +29,10 @@ public class PauseMenuFactoryTest { void beforeEach() { EntityService entityService = new EntityService(); ServiceLocator.registerEntityService(entityService); + WaveService waveService = new WaveService(); + ServiceLocator.registerWaveService(waveService); + GameTime gameTime = new GameTime(); + ServiceLocator.registerTimeSource(gameTime); RenderService renderService = mock(RenderService.class); when(renderService.getStage()).thenReturn(mock(Stage.class)); ServiceLocator.registerRenderService(renderService); diff --git a/source/core/src/test/com/csse3200/game/entities/factories/ProjectileFactoryTest.java b/source/core/src/test/com/csse3200/game/entities/factories/ProjectileFactoryTest.java index 74d0c4836..d8b8a371c 100644 --- a/source/core/src/test/com/csse3200/game/entities/factories/ProjectileFactoryTest.java +++ b/source/core/src/test/com/csse3200/game/entities/factories/ProjectileFactoryTest.java @@ -63,34 +63,34 @@ public void setUp() { } @Test - public void createBaseProjectile() { + void createBaseProjectile() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile); } @Test - public void testBaseProjectileColliderComponent() { + void testBaseProjectileColliderComponent() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile.getComponent(ColliderComponent.class), "Projectile does not have a ColliderComponent"); } @Test - public void testBaseProjectileTouchAttackComponent() { + void testBaseProjectileTouchAttackComponent() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile.getComponent(TouchAttackComponent.class), "Projectile does not have a TouchAttackComponent"); } @Test - public void testBaseProjectileDeleteOnMapEdgeComponent() { + void testBaseProjectileDeleteOnMapEdgeComponent() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile.getComponent(DeleteOnMapEdgeComponent.class), "Projectile does not have a DeleteOnMapEdgeComponent"); } @Test - public void testBaseProjectileSpeed() { + void testBaseProjectileSpeed() { Vector2 testSpeed = new Vector2(1f, 1f); Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), testSpeed); assertEquals(testSpeed, projectile.getComponent(PhysicsMovementComponent.class).getSpeed(), @@ -98,114 +98,114 @@ public void testBaseProjectileSpeed() { } @Test - public void testBaseProjectileHitbox() { + void testBaseProjectileHitbox() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile.getComponent(HitboxComponent.class), "Projectile does not contain Hotbox component"); } @Test - public void testBaseProjectilePhysics() { + void testBaseProjectilePhysics() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile.getComponent(PhysicsComponent.class), "Projectile does not have Physics component"); } @Test - public void testBaseProjectilePhysicsMovement() { + void testBaseProjectilePhysicsMovement() { Entity projectile = ProjectileFactory.createBaseProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(projectile.getComponent(PhysicsMovementComponent.class), "Projectile does not have PhysicsMovement component"); } @Test - public void testFireBallProjectileCreation() { + void testFireBallProjectileCreation() { Entity fireBall = ProjectileFactory.createFireBall(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(fireBall); } @Test - public void testFireBallAnimationRenderComponent() { + void testFireBallAnimationRenderComponent() { Entity fireBall = ProjectileFactory.createFireBall(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(fireBall.getComponent(AnimationRenderComponent.class), "Fire Ball does not have an AnimationRenderComponent"); } @Test - public void testFireBallAnimationController() { + void testFireBallAnimationController() { Entity fireBall = ProjectileFactory.createFireBall(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(fireBall.getComponent(ProjectileAnimationController.class), "Fire Ball does not have an Animation Controller"); } @Test - public void createMobBallProjectile() { + void createMobBallProjectile() { Entity mobBallProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(mobBallProjectile, "Mob King Ball is Null"); } @Test - public void testMobBallProjectileAnimationRenderComponent() { + void testMobBallProjectileAnimationRenderComponent() { Entity mobBallProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(mobBallProjectile.getComponent(AnimationRenderComponent.class), "Mob Ball Projectile does not have an AnimationRenderComponent"); } // @Test -// public void testMobBallProjectileAnimationController() { +// void testMobBallProjectileAnimationController() { // Entity mobBallProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); // assertNotNull(mobBallProjectile.getComponent(MobProjectileAnimationController.class), // "Mob Ball Projectile does not have an AnimationController"); // } @Test - public void testMobBossBallCreation() { + void testMobBossBallCreation() { Entity mobBossBall = ProjectileFactory.createMobBossBall(PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(mobBossBall, "Mob King Ball is null"); } @Test - public void testMobBossBallAnimationRenderComponent() { + void testMobBossBallAnimationRenderComponent() { Entity mobBossBall = ProjectileFactory.createMobBossBall(PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(mobBossBall.getComponent(AnimationRenderComponent.class), "Mob King Ball does not have AnimationRenderComponent"); } @Test - public void testMobBossBallAnimationController() { + void testMobBossBallAnimationController() { Entity mobBossBall = ProjectileFactory.createMobBossBall(PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(mobBossBall.getComponent(MobBossProjectAnimController.class), "Mob King Ball does not have Animation Controller"); } @Test - public void testEngineerBulletCreation() { + void testEngineerBulletCreation() { Entity engineerBullet = ProjectileFactory.createEngineerBullet(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(engineerBullet, "engineerBullet is null"); } @Test - public void testEngineerBulletAnimationRenderComponent() { + void testEngineerBulletAnimationRenderComponent() { Entity engineerBulllet = ProjectileFactory.createEngineerBullet(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(engineerBulllet.getComponent(AnimationRenderComponent.class), "Engineer Bullet does not have AnimationRenderComponent"); } @Test - public void testEngineerAnimationController() { + void testEngineerAnimationController() { Entity engineerBullet = ProjectileFactory.createEngineerBullet(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(engineerBullet.getComponent(EngineerBulletsAnimationController.class), "Engineer Bullet does not have Animation Controller"); } @Test - public void testStunProjectileCreation() { + void testStunProjectileCreation() { Entity stunProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(2,2), ProjectileEffects.STUN, false); assertNotNull(stunProjectile, "stunProjectile is null"); } @Test - public void testStunProjectileAnimationRenderComponent() { + void testStunProjectileAnimationRenderComponent() { Entity stunProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(0.1f,01f), new Vector2(2,2), ProjectileEffects.STUN, false); assertNotNull(stunProjectile.getComponent(AnimationRenderComponent.class), @@ -213,7 +213,7 @@ public void testStunProjectileAnimationRenderComponent() { } @Test - public void testStunProjectileAnimationController() { + void testStunProjectileAnimationController() { Entity stunProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f) , new Vector2(2,2), ProjectileEffects.STUN, false); assertNotNull(stunProjectile.getComponent(StunEffectProjectileAnimationController.class), @@ -221,21 +221,21 @@ public void testStunProjectileAnimationController() { } @Test - public void testBurnProjectileCreation() { + void testBurnProjectileCreation() { Entity burnProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(2,2), ProjectileEffects.BURN, false); assertNotNull(burnProjectile, "burnProjectile is null"); } @Test - public void testBurnProjectileAnimationRenderComponent() { + void testBurnProjectileAnimationRenderComponent() { Entity burnProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(0.1f,01f), new Vector2(2,2), ProjectileEffects.BURN, false); assertNotNull(burnProjectile.getComponent(AnimationRenderComponent.class), "Burn Projectile does not have AnimationRenderComponent"); } @Test - public void testBurnProjectileAnimationController() { + void testBurnProjectileAnimationController() { Entity burnProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f) , new Vector2(2,2), ProjectileEffects.BURN, false); assertNotNull(burnProjectile.getComponent(BurnEffectProjectileAnimationController.class), @@ -243,21 +243,21 @@ public void testBurnProjectileAnimationController() { } @Test - public void testSlowProjectileCreation() { + void testSlowProjectileCreation() { Entity slowProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(0.1f, 0.1f), new Vector2(2,2), ProjectileEffects.SLOW, false); assertNotNull(slowProjectile, "slowProjectile is null"); } @Test - public void testSlowProjectileAnimationRenderComponent() { + void testSlowProjectileAnimationRenderComponent() { Entity slowProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(0.1f,01f), new Vector2(2,2), ProjectileEffects.SLOW, false); assertNotNull(slowProjectile.getComponent(AnimationRenderComponent.class), "Slow Projectile does not have AnimationRenderComponent"); } @Test - public void testSlowProjectileAnimationController() { + void testSlowProjectileAnimationController() { Entity slowProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f) , new Vector2(2,2), ProjectileEffects.SLOW, false); assertNotNull(slowProjectile.getComponent(SnowBallProjectileAnimationController.class), @@ -265,21 +265,21 @@ public void testSlowProjectileAnimationController() { } @Test - public void testFireworkProjectileCreation() { + void testFireworkProjectileCreation() { Entity fireworkProjectile = ProjectileFactory.createFireworks( PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(fireworkProjectile, "fireworkProjectile is null"); } @Test - public void testFireworkProjectileAnimationRenderComponent() { + void testFireworkProjectileAnimationRenderComponent() { Entity fireworkProjectile = ProjectileFactory.createFireworks( PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(fireworkProjectile.getComponent(AnimationRenderComponent.class), "Fire Projectile does not have AnimationRenderComponent"); } @Test - public void testFireworkProjectileAnimationController() { + void testFireworkProjectileAnimationController() { Entity fireworkProjectile = ProjectileFactory.createFireworks( PhysicsLayer.TOWER, new Vector2(0.1f, 0.1f), new Vector2(1f, 1f)); assertNotNull(fireworkProjectile.getComponent(FireworkAnimationController.class),