diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..b30eb7c29 Binary files /dev/null and b/.DS_Store differ diff --git a/source/core/assets/images/mobs/arcane_archer.atlas b/source/core/assets/images/mobs/arcane_archer.atlas index 5acf48d80..b43656e7f 100644 --- a/source/core/assets/images/mobs/arcane_archer.atlas +++ b/source/core/assets/images/mobs/arcane_archer.atlas @@ -1,223 +1,223 @@ - -arcane_archer.png -size: 512, 256 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -arcane_archer_attack - rotate: false - xy: 290, 2 - size: 65, 44 - orig: 65, 44 - offset: 0, 0 - index: -1 -arcane_archer_attack - rotate: false - xy: 362, 140 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_attack - rotate: false - xy: 146, 94 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_attack - rotate: false - xy: 74, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_attack - rotate: false - xy: 362, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_attack - rotate: false - xy: 218, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_attack - rotate: false - xy: 362, 94 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 2, 2 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 2, 140 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 146, 48 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 74, 94 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 434, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 218, 140 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 2, 94 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_death - rotate: false - xy: 146, 2 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 434, 140 - size: 69, 44 - orig: 69, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 290, 140 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 146, 140 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 290, 48 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 74, 2 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 146, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_dodge - rotate: false - xy: 290, 94 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 74, 48 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 2, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 218, 94 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 2, 48 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 218, 2 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 290, 186 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 74, 140 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -arcane_archer_run - rotate: false - xy: 218, 48 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 218, 48 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 + +arcane_archer.png +size: 512, 256 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +arcane_archer_attack + rotate: false + xy: 290, 2 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +arcane_archer_attack + rotate: false + xy: 362, 140 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_attack + rotate: false + xy: 146, 94 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_attack + rotate: false + xy: 74, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_attack + rotate: false + xy: 362, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_attack + rotate: false + xy: 218, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_attack + rotate: false + xy: 362, 94 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 2, 2 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 2, 140 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 146, 48 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 74, 94 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 434, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 218, 140 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 2, 94 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_death + rotate: false + xy: 146, 2 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 434, 140 + size: 69, 44 + orig: 69, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 290, 140 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 146, 140 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 290, 48 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 74, 2 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 146, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_dodge + rotate: false + xy: 290, 94 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 74, 48 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 2, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 218, 94 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 2, 48 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 218, 2 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 290, 186 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 74, 140 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +arcane_archer_run + rotate: false + xy: 218, 48 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 218, 48 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/mobs/coat.atlas b/source/core/assets/images/mobs/coat.atlas index f98ef17d8..ae65fd9ac 100644 --- a/source/core/assets/images/mobs/coat.atlas +++ b/source/core/assets/images/mobs/coat.atlas @@ -1,167 +1,167 @@ - -coat.png -size: 1024, 64 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -coat_attack - rotate: false - xy: 498, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 98, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 218, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 2, 25 - size: 54, 37 - orig: 54, 37 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 378, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 138, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 618, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 258, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 698, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_attack - rotate: false - xy: 418, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_death - rotate: false - xy: 578, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_death - rotate: false - xy: 298, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_death - rotate: false - xy: 738, 32 - size: 33, 30 - orig: 33, 30 - offset: 0, 0 - index: -1 -coat_death - rotate: false - xy: 773, 36 - size: 31, 26 - orig: 31, 26 - offset: 0, 0 - index: -1 -coat_death - rotate: false - xy: 2, 2 - size: 30, 21 - orig: 30, 21 - offset: 0, 0 - index: -1 -coat_death - rotate: false - xy: 806, 44 - size: 25, 18 - orig: 25, 18 - offset: 0, 0 - index: -1 -coat_run - rotate: false - xy: 458, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_run - rotate: false - xy: 178, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_run - rotate: false - xy: 658, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_run - rotate: false - xy: 338, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_run - rotate: false - xy: 58, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -coat_run - rotate: false - xy: 538, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 538, 24 - size: 38, 38 - orig: 38, 38 - offset: 0, 0 - index: -1 + +coat.png +size: 1024, 64 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +coat_attack + rotate: false + xy: 498, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 98, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 218, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 2, 25 + size: 54, 37 + orig: 54, 37 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 378, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 138, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 618, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 258, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 698, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_attack + rotate: false + xy: 418, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_death + rotate: false + xy: 578, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_death + rotate: false + xy: 298, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_death + rotate: false + xy: 738, 32 + size: 33, 30 + orig: 33, 30 + offset: 0, 0 + index: -1 +coat_death + rotate: false + xy: 773, 36 + size: 31, 26 + orig: 31, 26 + offset: 0, 0 + index: -1 +coat_death + rotate: false + xy: 2, 2 + size: 30, 21 + orig: 30, 21 + offset: 0, 0 + index: -1 +coat_death + rotate: false + xy: 806, 44 + size: 25, 18 + orig: 25, 18 + offset: 0, 0 + index: -1 +coat_run + rotate: false + xy: 458, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_run + rotate: false + xy: 178, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_run + rotate: false + xy: 658, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_run + rotate: false + xy: 338, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_run + rotate: false + xy: 58, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +coat_run + rotate: false + xy: 538, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 538, 24 + size: 38, 38 + orig: 38, 38 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/mobs/dragon_knight.atlas b/source/core/assets/images/mobs/dragon_knight.atlas index 59a0335b8..4d698370a 100644 --- a/source/core/assets/images/mobs/dragon_knight.atlas +++ b/source/core/assets/images/mobs/dragon_knight.atlas @@ -25,6 +25,13 @@ dragon_knight_attack orig: 99, 99 offset: 0, 0 index: -1 +dragon_knight_freeze + rotate: false + xy: 407, 2 + size: 99, 99 + orig: 99, 99 + offset: 0, 0 + index: -1 dragon_knight_attack rotate: false xy: 2, 308 diff --git a/source/core/assets/images/mobs/dragon_knight.png b/source/core/assets/images/mobs/dragon_knight.png index 85bcd9340..2a18fb0c0 100644 Binary files a/source/core/assets/images/mobs/dragon_knight.png and b/source/core/assets/images/mobs/dragon_knight.png differ diff --git a/source/core/assets/images/mobs/fire_worm.atlas b/source/core/assets/images/mobs/fire_worm.atlas index d647dd3a1..4014b6279 100644 --- a/source/core/assets/images/mobs/fire_worm.atlas +++ b/source/core/assets/images/mobs/fire_worm.atlas @@ -130,6 +130,13 @@ fire_worm_death orig: 75, 75 offset: 0, 0 index: -1 +fire_worm_freeze + rotate: false + xy: 770, 2 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 fire_worm_death rotate: false xy: 2, 156 diff --git a/source/core/assets/images/mobs/fire_worm.png b/source/core/assets/images/mobs/fire_worm.png index 9311b527a..ab3cf4698 100644 Binary files a/source/core/assets/images/mobs/fire_worm.png and b/source/core/assets/images/mobs/fire_worm.png differ diff --git a/source/core/assets/images/mobs/fire_worm_attack.atlas b/source/core/assets/images/mobs/fire_worm_attack.atlas index c8d2e2d1f..fcb3d0597 100644 --- a/source/core/assets/images/mobs/fire_worm_attack.atlas +++ b/source/core/assets/images/mobs/fire_worm_attack.atlas @@ -1,118 +1,118 @@ - -fire_worm_attack.png -size: 256, 512 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -fire_worm_attack1 - rotate: false - xy: 2, 156 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack10 - rotate: false - xy: 2, 79 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack11 - rotate: false - xy: 79, 387 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack12 - rotate: false - xy: 79, 79 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack13 - rotate: false - xy: 79, 233 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack14 - rotate: false - xy: 2, 387 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack15 - rotate: false - xy: 156, 233 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack16 - rotate: false - xy: 79, 310 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack2 - rotate: false - xy: 79, 2 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack3 - rotate: false - xy: 79, 156 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack4 - rotate: false - xy: 2, 233 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack5 - rotate: false - xy: 156, 156 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack6 - rotate: false - xy: 156, 310 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack7 - rotate: false - xy: 2, 310 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack8 - rotate: false - xy: 2, 2 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 -fire_worm_attack9 - rotate: false - xy: 156, 387 - size: 75, 75 - orig: 75, 75 - offset: 0, 0 - index: -1 + +fire_worm_attack.png +size: 256, 512 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +fire_worm_attack1 + rotate: false + xy: 2, 156 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack10 + rotate: false + xy: 2, 79 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack11 + rotate: false + xy: 79, 387 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack12 + rotate: false + xy: 79, 79 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack13 + rotate: false + xy: 79, 233 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack14 + rotate: false + xy: 2, 387 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack15 + rotate: false + xy: 156, 233 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack16 + rotate: false + xy: 79, 310 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack2 + rotate: false + xy: 79, 2 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack3 + rotate: false + xy: 79, 156 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack4 + rotate: false + xy: 2, 233 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack5 + rotate: false + xy: 156, 156 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack6 + rotate: false + xy: 156, 310 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack7 + rotate: false + xy: 2, 310 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack8 + rotate: false + xy: 2, 2 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 +fire_worm_attack9 + rotate: false + xy: 156, 387 + size: 75, 75 + orig: 75, 75 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/mobs/fire_worm_walk b/source/core/assets/images/mobs/fire_worm_walk index 0cb3f5ec3..bea8b8b25 100644 --- a/source/core/assets/images/mobs/fire_worm_walk +++ b/source/core/assets/images/mobs/fire_worm_walk @@ -1,69 +1,69 @@ - -fire_worm_walk.png -size: 1024, 128 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -fire_worm_walk1 - rotate: false - xy: 646, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk2 - rotate: false - xy: 278, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk3 - rotate: false - xy: 2, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk4 - rotate: false - xy: 462, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk5 - rotate: false - xy: 186, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk6 - rotate: false - xy: 738, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk7 - rotate: false - xy: 370, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk8 - rotate: false - xy: 94, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 -fire_worm_walk9 - rotate: false - xy: 554, 2 - size: 90, 90 - orig: 90, 90 - offset: 0, 0 - index: -1 + +fire_worm_walk.png +size: 1024, 128 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +fire_worm_walk1 + rotate: false + xy: 646, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk2 + rotate: false + xy: 278, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk3 + rotate: false + xy: 2, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk4 + rotate: false + xy: 462, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk5 + rotate: false + xy: 186, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk6 + rotate: false + xy: 738, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk7 + rotate: false + xy: 370, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk8 + rotate: false + xy: 94, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 +fire_worm_walk9 + rotate: false + xy: 554, 2 + size: 90, 90 + orig: 90, 90 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/mobs/firewizard.atlas b/source/core/assets/images/mobs/firewizard.atlas deleted file mode 100644 index dacee9afe..000000000 --- a/source/core/assets/images/mobs/firewizard.atlas +++ /dev/null @@ -1,160 +0,0 @@ - -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 deleted file mode 100644 index d612b5352..000000000 Binary files a/source/core/assets/images/mobs/firewizard.png and /dev/null differ diff --git a/source/core/assets/images/mobs/necromancer.atlas b/source/core/assets/images/mobs/necromancer.atlas deleted file mode 100644 index b83e6c86f..000000000 --- a/source/core/assets/images/mobs/necromancer.atlas +++ /dev/null @@ -1,167 +0,0 @@ - -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 deleted file mode 100644 index c86c5cc2c..000000000 Binary files a/source/core/assets/images/mobs/necromancer.png and /dev/null differ diff --git a/source/core/assets/images/mobs/night_borne.atlas b/source/core/assets/images/mobs/night_borne.atlas index bc5f17c49..e01ece4c4 100644 --- a/source/core/assets/images/mobs/night_borne.atlas +++ b/source/core/assets/images/mobs/night_borne.atlas @@ -1,251 +1,251 @@ - -night_borne.png -size: 2048, 128 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -night_borne_attack - rotate: false - xy: 84, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 2, 54 - size: 80, 61 - orig: 80, 61 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 1232, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 740, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 822, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 330, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 1068, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 658, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 166, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 904, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 412, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_attack - rotate: false - xy: 1150, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 1232, 19 - size: 70, 44 - orig: 70, 44 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 904, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 904, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 412, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 740, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 248, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 986, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 576, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 84, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 822, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 330, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 1068, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 576, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 576, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 166, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_death - rotate: false - xy: 494, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_run - rotate: false - xy: 1150, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_run - rotate: false - xy: 658, 13 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_run - rotate: false - xy: 248, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_run - rotate: false - xy: 986, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_run - rotate: false - xy: 494, 65 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -night_borne_run - rotate: false - xy: 2, 2 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 2, 2 - size: 80, 50 - orig: 80, 50 - offset: 0, 0 - index: -1 + +night_borne.png +size: 2048, 128 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +night_borne_attack + rotate: false + xy: 84, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 2, 54 + size: 80, 61 + orig: 80, 61 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 1232, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 740, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 822, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 330, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 1068, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 658, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 166, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 904, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 412, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_attack + rotate: false + xy: 1150, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 1232, 19 + size: 70, 44 + orig: 70, 44 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 904, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 904, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 412, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 740, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 248, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 986, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 576, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 84, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 822, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 330, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 1068, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 576, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 576, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 166, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_death + rotate: false + xy: 494, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_run + rotate: false + xy: 1150, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_run + rotate: false + xy: 658, 13 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_run + rotate: false + xy: 248, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_run + rotate: false + xy: 986, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_run + rotate: false + xy: 494, 65 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +night_borne_run + rotate: false + xy: 2, 2 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 2, 2 + size: 80, 50 + orig: 80, 50 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/mobs/rangeBossRight.atlas b/source/core/assets/images/mobs/rangeBossRight.atlas index e96a1893f..7403df738 100644 --- a/source/core/assets/images/mobs/rangeBossRight.atlas +++ b/source/core/assets/images/mobs/rangeBossRight.atlas @@ -1,54 +1,54 @@ -rangeBossRight.png -size: 243, 62 -format: RGBA8888 -filter: Linear,Linear -repeat: none -Walk - rotate: false - xy: 205, 0 - size: 38, 61 - orig: 96, 114 - offset: 15, 30 - index: -1 -Walk - rotate: false - xy: 123, 0 - size: 35, 62 - orig: 96, 114 - offset: 15, 30 - index: -1 -Walk - rotate: false - xy: 0, 0 - size: 43, 62 - orig: 96, 114 - offset: 10, 30 - index: -1 -Walk - rotate: false - xy: 158, 0 - size: 47, 61 - orig: 96, 114 - offset: 8, 30 - index: -1 -Walk - rotate: false - xy: 43, 0 - size: 43, 62 - orig: 96, 114 - offset: 10, 30 - index: -1 -Walk - rotate: false - xy: 86, 0 - size: 37, 62 - orig: 96, 114 - offset: 15, 30 - index: -1 -default - rotate: false - xy: 86, 0 - size: 37, 62 - orig: 96, 114 - offset: 15, 30 - index: -1 +rangeBossRight.png +size: 243, 62 +format: RGBA8888 +filter: Linear,Linear +repeat: none +Walk + rotate: false + xy: 205, 0 + size: 38, 61 + orig: 96, 114 + offset: 15, 30 + index: -1 +Walk + rotate: false + xy: 123, 0 + size: 35, 62 + orig: 96, 114 + offset: 15, 30 + index: -1 +Walk + rotate: false + xy: 0, 0 + size: 43, 62 + orig: 96, 114 + offset: 10, 30 + index: -1 +Walk + rotate: false + xy: 158, 0 + size: 47, 61 + orig: 96, 114 + offset: 8, 30 + index: -1 +Walk + rotate: false + xy: 43, 0 + size: 43, 62 + orig: 96, 114 + offset: 10, 30 + index: -1 +Walk + rotate: false + xy: 86, 0 + size: 37, 62 + orig: 96, 114 + offset: 15, 30 + index: -1 +default + rotate: false + xy: 86, 0 + size: 37, 62 + orig: 96, 114 + offset: 15, 30 + index: -1 diff --git a/source/core/assets/images/mobs/robot.atlas b/source/core/assets/images/mobs/robot.atlas index 843e14ce1..9021ebcc7 100644 --- a/source/core/assets/images/mobs/robot.atlas +++ b/source/core/assets/images/mobs/robot.atlas @@ -1,56 +1,56 @@ -robot.png -size: 1024, 256 -format: RGBA8888 -filter: Linear,Linear -repeat: none -Walk - rotate: false - xy: 334, 34 - size: 30, 74 - orig: 30, 74 - offset: 46, -54 - index: -1 -Walk - rotate: false - xy: 632, 34 - size: 30, 73 - orig: 30, 73 - offset: 46, -55 - index: -1 -Walk - rotate: false - xy: 781, 34 - size: 32, 72 - orig: 32, 72 - offset: 46, -56 - index: -1 -Walk - rotate: false - xy: 483, 34 - size: 30, 73 - orig: 30, 73 - offset: 46, -55 - index: -1 -Walk - rotate: false - xy: 185, 34 - size: 30, 74 - orig: 30, 74 - offset: 46, -54 - index: -1 -Walk - rotate: false - xy: 34, 34 - size: 32, 75 - orig: 32, 75 - offset: 46, -53 - index: -1 -default - rotate: false - xy: 34, 34 - size: 32, 75 - orig: 32, 75 - offset: 46, -53 - index: -1 - - +robot.png +size: 1024, 256 +format: RGBA8888 +filter: Linear,Linear +repeat: none +Walk + rotate: false + xy: 334, 34 + size: 30, 74 + orig: 30, 74 + offset: 46, -54 + index: -1 +Walk + rotate: false + xy: 632, 34 + size: 30, 73 + orig: 30, 73 + offset: 46, -55 + index: -1 +Walk + rotate: false + xy: 781, 34 + size: 32, 72 + orig: 32, 72 + offset: 46, -56 + index: -1 +Walk + rotate: false + xy: 483, 34 + size: 30, 73 + orig: 30, 73 + offset: 46, -55 + index: -1 +Walk + rotate: false + xy: 185, 34 + size: 30, 74 + orig: 30, 74 + offset: 46, -54 + index: -1 +Walk + rotate: false + xy: 34, 34 + size: 32, 75 + orig: 32, 75 + offset: 46, -53 + index: -1 +default + rotate: false + xy: 34, 34 + size: 32, 75 + orig: 32, 75 + offset: 46, -53 + index: -1 + + diff --git a/source/core/assets/images/mobs/rocky.atlas b/source/core/assets/images/mobs/rocky.atlas deleted file mode 100644 index c29e734ba..000000000 --- a/source/core/assets/images/mobs/rocky.atlas +++ /dev/null @@ -1,174 +0,0 @@ - -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 deleted file mode 100644 index 86375354a..000000000 Binary files a/source/core/assets/images/mobs/rocky.png and /dev/null differ diff --git a/source/core/assets/images/mobs/skeleton.atlas b/source/core/assets/images/mobs/skeleton.atlas index f0117d879..75c312c80 100644 --- a/source/core/assets/images/mobs/skeleton.atlas +++ b/source/core/assets/images/mobs/skeleton.atlas @@ -46,6 +46,13 @@ skeleton_attack orig: 62, 48 offset: 0, 0 index: -1 +skeleton_freeze + rotate: false + xy: 1152, 2 + size: 62, 48 + orig: 62, 48 + offset: 0, 0 + index: -1 skeleton_attack rotate: false xy: 642, 2 diff --git a/source/core/assets/images/mobs/skeleton.png b/source/core/assets/images/mobs/skeleton.png index cbcbd1ed1..dd724a4bb 100644 Binary files a/source/core/assets/images/mobs/skeleton.png and b/source/core/assets/images/mobs/skeleton.png differ diff --git a/source/core/assets/images/mobs/water_queen.atlas b/source/core/assets/images/mobs/water_queen.atlas index f3d5ea8fc..03e97ae14 100644 --- a/source/core/assets/images/mobs/water_queen.atlas +++ b/source/core/assets/images/mobs/water_queen.atlas @@ -151,6 +151,13 @@ water_queen_walk orig: 90, 60 offset: 0, 0 index: -1 +water_queen_freeze + rotate: false + xy: 1104, 2 + size: 90, 60 + orig: 90, 60 + offset: 0, 0 + index: -1 water_queen_walk rotate: false xy: 554, 2 diff --git a/source/core/assets/images/mobs/water_queen.png b/source/core/assets/images/mobs/water_queen.png index bbed31311..bf4ae7659 100644 Binary files a/source/core/assets/images/mobs/water_queen.png and b/source/core/assets/images/mobs/water_queen.png differ diff --git a/source/core/assets/images/mobs/water_slime.atlas b/source/core/assets/images/mobs/water_slime.atlas index 767f1cd29..dec3cd62d 100644 --- a/source/core/assets/images/mobs/water_slime.atlas +++ b/source/core/assets/images/mobs/water_slime.atlas @@ -53,6 +53,13 @@ water_slime_death orig: 32, 25 offset: 0, 0 index: -1 +water_slime_freeze + rotate: false + xy: 442, 2 + size: 32, 25 + orig: 32, 25 + offset: 0, 0 + index: -1 water_slime_death rotate: false xy: 240, 2 diff --git a/source/core/assets/images/mobs/water_slime.png b/source/core/assets/images/mobs/water_slime.png index 66b1b071f..eff01c635 100644 Binary files a/source/core/assets/images/mobs/water_slime.png and b/source/core/assets/images/mobs/water_slime.png differ diff --git a/source/core/assets/images/mobs/wizard.atlas b/source/core/assets/images/mobs/wizard.atlas index f9a87a81f..74cccd6e8 100644 --- a/source/core/assets/images/mobs/wizard.atlas +++ b/source/core/assets/images/mobs/wizard.atlas @@ -102,6 +102,13 @@ wizard_death orig: 110, 90 offset: 0, 0 index: -1 +wizard_freeze + rotate: false + xy: 1250, 94 + size: 110, 90 + orig: 110, 90 + offset: 0, 0 + index: -1 wizard_death rotate: false xy: 804, 2 diff --git a/source/core/assets/images/mobs/wizard.png b/source/core/assets/images/mobs/wizard.png index bcb6208b0..e948ce12e 100644 Binary files a/source/core/assets/images/mobs/wizard.png and b/source/core/assets/images/mobs/wizard.png differ diff --git a/source/core/assets/images/mobs/xeno-Grunt.png b/source/core/assets/images/mobs/xeno-Grunt.png index 543bae78e..ec430c93e 100644 Binary files a/source/core/assets/images/mobs/xeno-Grunt.png and b/source/core/assets/images/mobs/xeno-Grunt.png differ diff --git a/source/core/assets/images/mobs/xenoGrunt.atlas b/source/core/assets/images/mobs/xenoGrunt.atlas index c57686a05..8a1f824e7 100644 --- a/source/core/assets/images/mobs/xenoGrunt.atlas +++ b/source/core/assets/images/mobs/xenoGrunt.atlas @@ -59,6 +59,13 @@ xeno_run orig: 200, 200 offset: 0, 0 index: 7 +xeno_freeze + rotate: false + xy: 1600, 0 + size: 200, 200 + orig: 200, 200 + offset: 0, 0 + index: -1 xeno_hurt rotate: false xy: 0, 200 diff --git a/source/core/assets/images/projectiles/arrow.atlas b/source/core/assets/images/projectiles/arrow.atlas new file mode 100644 index 000000000..1a1eaef13 --- /dev/null +++ b/source/core/assets/images/projectiles/arrow.atlas @@ -0,0 +1,54 @@ +arrow.png +size: 390, 44 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +arrow + rotate: false + xy: 65, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +arrow + rotate: false + xy: 130, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +arrow + rotate: false + xy: 195, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +arrow + rotate: false + xy: 260, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +arrow + rotate: false + xy: 325, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +arrow + rotate: false + xy: 0, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 0, 0 + size: 65, 44 + orig: 65, 44 + offset: 0, 0 + index: -1 \ No newline at end of file diff --git a/source/core/assets/images/projectiles/arrow.png b/source/core/assets/images/projectiles/arrow.png new file mode 100644 index 000000000..2db4cccc1 Binary files /dev/null and b/source/core/assets/images/projectiles/arrow.png differ diff --git a/source/core/assets/images/projectiles/attack_projectile.atlas b/source/core/assets/images/projectiles/attack_projectile.atlas index 19ed43f53..95f152253 100644 --- a/source/core/assets/images/projectiles/attack_projectile.atlas +++ b/source/core/assets/images/projectiles/attack_projectile.atlas @@ -1,33 +1,33 @@ -attack_projectile.png -size: 420, 93 -format: RGBA8888 -filter: Linear,Linear -repeat: none -P - rotate: false - xy: 0, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -P - rotate: false - xy: 140, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -p - rotate: false - xy: 280, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 280, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 +attack_projectile.png +size: 420, 93 +format: RGBA8888 +filter: Linear,Linear +repeat: none +P + rotate: false + xy: 0, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +P + rotate: false + xy: 140, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +p + rotate: false + xy: 280, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 280, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/basic_projectile.atlas b/source/core/assets/images/projectiles/basic_projectile.atlas index 9d295b888..80a571deb 100644 --- a/source/core/assets/images/projectiles/basic_projectile.atlas +++ b/source/core/assets/images/projectiles/basic_projectile.atlas @@ -1,41 +1,55 @@ basic_projectile.png -size: 256, 32 +size: 260, 32 format: RGBA8888 filter: Nearest, Nearest repeat: none +projectile + rotate: false + xy: 78, 2 + size: 36, 19 + orig: 36, 19 + offset: 0, 0 + index: -1 projectileFinal rotate: false xy: 2, 2 size: 36, 19 orig: 36, 19 offset: 0, 0 - index: 2 + index: -1 projectile rotate: false - xy: 40, 2 + xy: 116, 2 size: 36, 19 orig: 36, 19 offset: 0, 0 - index: 4 + index: -1 projectile rotate: false - xy: 78, 2 + xy: 40, 2 size: 36, 19 orig: 36, 19 offset: 0, 0 - index: 1 -projectile + index: -1 +projectileCollide rotate: false - xy: 116, 2 + xy: 152, 2 size: 36, 19 orig: 36, 19 offset: 0, 0 - index: 3 -default + index: -1 +projectileCollide rotate: false - xy: 116, 2 + xy: 188, 2 + size: 36, 19 + orig: 36, 19 + offset: 0, 0 + index: -1 +projectileCollide + rotate: false + xy: 224, 2 size: 36, 19 orig: 36, 19 offset: 0, 0 - index: 3 + index: -1 diff --git a/source/core/assets/images/projectiles/basic_projectile.png b/source/core/assets/images/projectiles/basic_projectile.png index 5fa3bb42c..e551f311b 100644 Binary files a/source/core/assets/images/projectiles/basic_projectile.png and b/source/core/assets/images/projectiles/basic_projectile.png differ diff --git a/source/core/assets/images/projectiles/bossProjectile.atlas b/source/core/assets/images/projectiles/bossProjectile.atlas index 35cdc850e..06d22f3b7 100644 --- a/source/core/assets/images/projectiles/bossProjectile.atlas +++ b/source/core/assets/images/projectiles/bossProjectile.atlas @@ -1,103 +1,103 @@ -bossProjectile.png -size: 980, 186 -format: RGBA8888 -filter: Linear,Linear -repeat: none -rotate - rotate: false - xy: 0, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 140, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 280, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 420, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 560, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 700, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 840, 0 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 0, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 140, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 280, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 420, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 560, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 700, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 700, 93 - size: 140, 93 - orig: 140, 93 - offset: 0, 0 - index: -1 +bossProjectile.png +size: 980, 186 +format: RGBA8888 +filter: Linear,Linear +repeat: none +rotate + rotate: false + xy: 0, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 140, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 280, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 420, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 560, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 700, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 840, 0 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 0, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 140, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 280, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 420, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 560, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 700, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 700, 93 + size: 140, 93 + orig: 140, 93 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/burn_effect.atlas b/source/core/assets/images/projectiles/burn_effect.atlas index 140875f0f..28e780b93 100644 --- a/source/core/assets/images/projectiles/burn_effect.atlas +++ b/source/core/assets/images/projectiles/burn_effect.atlas @@ -1,55 +1,55 @@ - -burn_effect.png -size: 256, 64 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -projectile - rotate: false - xy: 78, 2 - size: 36, 31 - orig: 36, 31 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 2, 2 - size: 36, 31 - orig: 36, 31 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 154, 2 - size: 35, 31 - orig: 35, 31 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 40, 2 - size: 36, 31 - orig: 36, 31 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 116, 2 - size: 36, 31 - orig: 36, 31 - offset: 0, 0 - index: -1 -projectileFinal - rotate: false - xy: 191, 2 - size: 31, 31 - orig: 31, 31 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 78, 2 - size: 36, 31 - orig: 36, 31 - offset: 0, 0 + +burn_effect.png +size: 256, 64 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +projectile + rotate: false + xy: 78, 2 + size: 36, 31 + orig: 36, 31 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 2, 2 + size: 36, 31 + orig: 36, 31 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 154, 2 + size: 35, 31 + orig: 35, 31 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 40, 2 + size: 36, 31 + orig: 36, 31 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 116, 2 + size: 36, 31 + orig: 36, 31 + offset: 0, 0 + index: -1 +projectileFinal + rotate: false + xy: 191, 2 + size: 31, 31 + orig: 31, 31 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 78, 2 + size: 36, 31 + orig: 36, 31 + offset: 0, 0 index: -1 \ No newline at end of file diff --git a/source/core/assets/images/projectiles/engineer_projectile.atlas b/source/core/assets/images/projectiles/engineer_projectile.atlas index 9790d718e..e1510d801 100644 --- a/source/core/assets/images/projectiles/engineer_projectile.atlas +++ b/source/core/assets/images/projectiles/engineer_projectile.atlas @@ -1,6 +1,6 @@ engineer_projectile.png -size: 128, 32 +size: 148, 32 format: RGBA8888 filter: Nearest, Nearest repeat: none @@ -32,4 +32,24 @@ bullet orig: 20, 19 offset: 0, 0 index: -1 - +bulletCollide + rotate: false + xy: 87, 2 + size: 20, 19 + orig: 20, 19 + offset: 0, 0 + index: -1 +bulletCollide + rotate: false + xy: 107, 2 + size: 20, 19 + orig: 20, 19 + offset: 0, 0 + index: -1 +bulletCollide + rotate: false + xy: 127, 2 + size: 20, 19 + orig: 20, 19 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/engineer_projectile.png b/source/core/assets/images/projectiles/engineer_projectile.png index a98ae11e2..991bba172 100644 Binary files a/source/core/assets/images/projectiles/engineer_projectile.png and b/source/core/assets/images/projectiles/engineer_projectile.png differ diff --git a/source/core/assets/images/projectiles/firework_anim.atlas b/source/core/assets/images/projectiles/firework_anim.atlas index 45f2d54c9..912c8027a 100644 --- a/source/core/assets/images/projectiles/firework_anim.atlas +++ b/source/core/assets/images/projectiles/firework_anim.atlas @@ -1,41 +1,41 @@ - -firework_anim.png -size: 128, 32 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -projectile - rotate: false - xy: 23, 2 - size: 19, 16 - orig: 19, 16 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 65, 2 - size: 19, 16 - orig: 19, 16 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 44, 2 - size: 19, 16 - orig: 19, 16 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 2, 2 - size: 19, 16 - orig: 19, 16 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 23, 2 - size: 19, 16 - orig: 19, 16 - offset: 0, 0 - index: -1 + +firework_anim.png +size: 128, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +projectile + rotate: false + xy: 23, 2 + size: 19, 16 + orig: 19, 16 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 65, 2 + size: 19, 16 + orig: 19, 16 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 44, 2 + size: 19, 16 + orig: 19, 16 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 2, 2 + size: 19, 16 + orig: 19, 16 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 23, 2 + size: 19, 16 + orig: 19, 16 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/mobBoss_projectile.atlas b/source/core/assets/images/projectiles/mobBoss_projectile.atlas index e0ddcbdd0..94ebaf787 100644 --- a/source/core/assets/images/projectiles/mobBoss_projectile.atlas +++ b/source/core/assets/images/projectiles/mobBoss_projectile.atlas @@ -1,62 +1,62 @@ - -mobBoss_projectile.png -size: 256, 32 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -mob_boss - rotate: false - xy: 142, 2 - size: 26, 19 - orig: 26, 19 - offset: 0, 0 - index: -1 -mob_boss - rotate: false - xy: 198, 3 - size: 24, 18 - orig: 24, 18 - offset: 0, 0 - index: -1 -mob_boss - rotate: false - xy: 170, 2 - size: 26, 19 - orig: 26, 19 - offset: 0, 0 - index: -1 -mob_boss - rotate: false - xy: 37, 2 - size: 33, 19 - orig: 33, 19 - offset: 0, 0 - index: -1 -mob_boss - rotate: false - xy: 107, 2 - size: 33, 19 - orig: 33, 19 - offset: 0, 0 - index: -1 -mob_boss - rotate: false - xy: 72, 2 - size: 33, 19 - orig: 33, 19 - offset: 0, 0 - index: -1 -mob_bossFinal - rotate: false - xy: 2, 2 - size: 33, 19 - orig: 33, 19 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 142, 2 - size: 26, 19 - orig: 26, 19 - offset: 0, 0 - index: -1 + +mobBoss_projectile.png +size: 256, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +mob_boss + rotate: false + xy: 142, 2 + size: 26, 19 + orig: 26, 19 + offset: 0, 0 + index: -1 +mob_boss + rotate: false + xy: 198, 3 + size: 24, 18 + orig: 24, 18 + offset: 0, 0 + index: -1 +mob_boss + rotate: false + xy: 170, 2 + size: 26, 19 + orig: 26, 19 + offset: 0, 0 + index: -1 +mob_boss + rotate: false + xy: 37, 2 + size: 33, 19 + orig: 33, 19 + offset: 0, 0 + index: -1 +mob_boss + rotate: false + xy: 107, 2 + size: 33, 19 + orig: 33, 19 + offset: 0, 0 + index: -1 +mob_boss + rotate: false + xy: 72, 2 + size: 33, 19 + orig: 33, 19 + offset: 0, 0 + index: -1 +mob_bossFinal + rotate: false + xy: 2, 2 + size: 33, 19 + orig: 33, 19 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 142, 2 + size: 26, 19 + orig: 26, 19 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/mobProjectile.atlas b/source/core/assets/images/projectiles/mobProjectile.atlas index 5dabfa025..7975b1d41 100644 --- a/source/core/assets/images/projectiles/mobProjectile.atlas +++ b/source/core/assets/images/projectiles/mobProjectile.atlas @@ -1,41 +1,41 @@ - -mobProjectile.png -size: 128, 32 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -rotate - rotate: false - xy: 80, 2 - size: 24, 23 - orig: 24, 23 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 28, 2 - size: 24, 23 - orig: 24, 23 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 28, 2 - size: 24, 23 - orig: 24, 23 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 2, 2 - size: 24, 23 - orig: 24, 23 - offset: 0, 0 - index: -1 -rotate - rotate: false - xy: 54, 2 - size: 24, 23 - orig: 24, 23 - offset: 0, 0 - index: -1 + +mobProjectile.png +size: 128, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +rotate + rotate: false + xy: 80, 2 + size: 24, 23 + orig: 24, 23 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 28, 2 + size: 24, 23 + orig: 24, 23 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 28, 2 + size: 24, 23 + orig: 24, 23 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 2, 2 + size: 24, 23 + orig: 24, 23 + offset: 0, 0 + index: -1 +rotate + rotate: false + xy: 54, 2 + size: 24, 23 + orig: 24, 23 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/oldstun_effect.atlas b/source/core/assets/images/projectiles/oldstun_effect.atlas index a50132d0b..d14093ee3 100644 --- a/source/core/assets/images/projectiles/oldstun_effect.atlas +++ b/source/core/assets/images/projectiles/oldstun_effect.atlas @@ -1,41 +1,41 @@ - -stun_effect.png -size: 256, 32 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -projectile - rotate: false - xy: 86, 3 - size: 41, 27 - orig: 41, 27 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 2, 2 - size: 40, 28 - orig: 40, 28 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 129, 2 - size: 40, 28 - orig: 40, 28 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 44, 2 - size: 40, 28 - orig: 40, 28 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 86, 3 - size: 41, 27 - orig: 41, 27 - offset: 0, 0 + +stun_effect.png +size: 256, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +projectile + rotate: false + xy: 86, 3 + size: 41, 27 + orig: 41, 27 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 2, 2 + size: 40, 28 + orig: 40, 28 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 129, 2 + size: 40, 28 + orig: 40, 28 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 44, 2 + size: 40, 28 + orig: 40, 28 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 86, 3 + size: 41, 27 + orig: 41, 27 + offset: 0, 0 index: -1 \ No newline at end of file diff --git a/source/core/assets/images/projectiles/pierce_anim.atlas b/source/core/assets/images/projectiles/pierce_anim.atlas index 0dea23b97..d6e37446a 100644 --- a/source/core/assets/images/projectiles/pierce_anim.atlas +++ b/source/core/assets/images/projectiles/pierce_anim.atlas @@ -1,42 +1,42 @@ - -pierce_anim.png -size: 256, 32 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -projectile - rotate: false - xy: 2, 2 - size: 35, 26 - orig: 35, 26 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 76, 2 - size: 35, 26 - orig: 35, 26 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 39, 2 - size: 35, 26 - orig: 35, 26 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 113, 2 - size: 35, 26 - orig: 35, 26 - offset: 0, 0 - index: -1 -default -projectile - rotate: false - xy: 2, 2 - size: 35, 26 - orig: 35, 26 - offset: 0, 0 + +pierce_anim.png +size: 256, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +projectile + rotate: false + xy: 2, 2 + size: 35, 26 + orig: 35, 26 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 76, 2 + size: 35, 26 + orig: 35, 26 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 39, 2 + size: 35, 26 + orig: 35, 26 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 113, 2 + size: 35, 26 + orig: 35, 26 + offset: 0, 0 + index: -1 +default +projectile + rotate: false + xy: 2, 2 + size: 35, 26 + orig: 35, 26 + offset: 0, 0 index: -1 \ No newline at end of file diff --git a/source/core/assets/images/projectiles/projectile_explosion.atlas b/source/core/assets/images/projectiles/projectile_explosion.atlas index d285fa835..3b16a2fc6 100644 --- a/source/core/assets/images/projectiles/projectile_explosion.atlas +++ b/source/core/assets/images/projectiles/projectile_explosion.atlas @@ -1,97 +1,97 @@ - -projectile_explosion.png -size: 2048, 256 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -explosion - rotate: false - xy: 1042, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 782, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 262, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosionFinal - rotate: false - xy: 1302, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 392, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 1432, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 652, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 132, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 1172, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 522, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 2, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -explosion - rotate: false - xy: 912, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -default - rotate: false - xy: 1042, 2 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 + +projectile_explosion.png +size: 2048, 256 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +explosion + rotate: false + xy: 1042, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 782, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 262, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosionFinal + rotate: false + xy: 1302, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 392, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 1432, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 652, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 132, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 1172, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 522, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 2, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +explosion + rotate: false + xy: 912, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +default + rotate: false + xy: 1042, 2 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/snow_ball.atlas b/source/core/assets/images/projectiles/snow_ball.atlas index 20e4eb554..21712ba2b 100644 --- a/source/core/assets/images/projectiles/snow_ball.atlas +++ b/source/core/assets/images/projectiles/snow_ball.atlas @@ -1,48 +1,48 @@ - -snow_ball.png -size: 128, 32 -format: RGBA8888 -filter: Nearest, Nearest -repeat: none -projectile - rotate: false - xy: 20, 2 - size: 16, 19 - orig: 16, 19 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 56, 2 - size: 16, 19 - orig: 16, 19 - offset: 0, 0 - index: -1 -projectile - rotate: false - xy: 38, 2 - size: 16, 19 - orig: 16, 19 - offset: 0, 0 - index: -1 -projectileFinal - rotate: false - xy: 2, 2 - size: 16, 19 - orig: 16, 19 - offset: 0, 0 - index: -1 -collision - rotate: false - xy: 92, 3 - size: 16, 18 - orig: 16, 18 - offset: 0, 0 - index: -1 -collision - rotate: false - xy: 74, 3 - size: 16, 18 - orig: 16, 18 - offset: 0, 0 - index: -1 + +snow_ball.png +size: 128, 32 +format: RGBA8888 +filter: Nearest, Nearest +repeat: none +projectile + rotate: false + xy: 20, 2 + size: 16, 19 + orig: 16, 19 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 56, 2 + size: 16, 19 + orig: 16, 19 + offset: 0, 0 + index: -1 +projectile + rotate: false + xy: 38, 2 + size: 16, 19 + orig: 16, 19 + offset: 0, 0 + index: -1 +projectileFinal + rotate: false + xy: 2, 2 + size: 16, 19 + orig: 16, 19 + offset: 0, 0 + index: -1 +collision + rotate: false + xy: 92, 3 + size: 16, 18 + orig: 16, 18 + offset: 0, 0 + index: -1 +collision + rotate: false + xy: 74, 3 + size: 16, 18 + orig: 16, 18 + offset: 0, 0 + index: -1 diff --git a/source/core/assets/images/projectiles/stun_effect.atlas b/source/core/assets/images/projectiles/stun_effect.atlas index 6aa98a315..8406d5748 100644 --- a/source/core/assets/images/projectiles/stun_effect.atlas +++ b/source/core/assets/images/projectiles/stun_effect.atlas @@ -1,6 +1,6 @@ stun_effect.png -size: 128, 32 +size: 152, 32 format: RGBA8888 filter: Nearest, Nearest repeat: none @@ -32,6 +32,27 @@ projectile orig: 17, 19 offset: 0, 0 index: -1 +stun + rotate: false + xy: 87, 2 + size: 21, 19 + orig: 21, 19 + offset: 0, 0 + index: -1 +stun + rotate: false + xy: 109, 2 + size: 21, 19 + orig: 21, 19 + offset: 0, 0 + index: -1 +stun + rotate: false + xy: 131, 2 + size: 21, 19 + orig: 21, 19 + offset: 0, 0 + index: -1 default rotate: false xy: 2, 2 diff --git a/source/core/assets/images/projectiles/stun_effect.png b/source/core/assets/images/projectiles/stun_effect.png index cd862a426..f2b3deddb 100644 Binary files a/source/core/assets/images/projectiles/stun_effect.png and b/source/core/assets/images/projectiles/stun_effect.png differ diff --git a/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java b/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java index 93798e8d4..175345a38 100644 --- a/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java +++ b/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java @@ -21,6 +21,8 @@ public class AITaskComponent extends Component implements TaskRunner { private final List priorityTasks = new ArrayList<>(2); private final List priorityTasksToBeRestored = new ArrayList<>(2); private PriorityTask currentTask; + + public boolean freezed = false; /** * Add a priority task to the list of tasks. This task will be run only when it has the highest * priority, and can be stopped to run a higher priority task. @@ -65,10 +67,11 @@ public void update() { return; } - if (desiredtask != currentTask) { + if (desiredtask != currentTask && !freezed) { changeTask(desiredtask); } - currentTask.update(); + if(currentTask!=null) + currentTask.update(); } @Override diff --git a/source/core/src/main/com/csse3200/game/components/Component.java b/source/core/src/main/com/csse3200/game/components/Component.java index babc6f291..e589d2ece 100644 --- a/source/core/src/main/com/csse3200/game/components/Component.java +++ b/source/core/src/main/com/csse3200/game/components/Component.java @@ -1,102 +1,102 @@ -package com.csse3200.game.components; - -import com.csse3200.game.entities.Entity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Core component class from which all components inherit. Contains logic for creating, updating, - * and disposing. Components can be attached to an entity to give it specific behaviour. It is - * unlikely that changes will need to be made here. - */ -public class Component { - private static final Logger logger = LoggerFactory.getLogger(Component.class); - protected Entity entity; - protected boolean enabled = true; - - /** - * Called when the entity is created and registered. Initial logic such as calls to GetComponent - * should be made here, not in the constructor which is called before an entity is finished. - */ - public void create() { - // No action by default. - } - - /** - * Early update called once per frame of the game, before update(). Use this only for logic that - * must run before other updates, such as physics. Not called if component is disabled. - */ - public void earlyUpdate() { - // No action by default. - } - - /** - * Called once per frame of the game, and should be used for most component logic. Not called if - * component is disabled. - */ - public void update() { - // No action by default. - } - - /** Called when the component is disposed. Dispose of any internal resources here. */ - public void dispose() { - // No action by default. - } - - /** - * Set the entity to which this component belongs. This is called by the Entity, and should not be - * set manually. - * - * @param entity The entity to which the component is attached. - */ - public void setEntity(Entity entity) { - logger.debug("Attaching {} to {}", this, entity); - this.entity = entity; - } - - /** - * Get the entity to which this component belongs. - * @return entity - */ - public Entity getEntity() { - return entity; - } - - /** - * Enable or disable the component. While disabled, a component does not run update() or - * earlyUpdate(). Other events inside the component may still fire. The component can still be - * disposed while disabled. - * - * @param enabled Should component be enabled - */ - public void setEnabled(boolean enabled) { - logger.debug("Setting enabled={} on {}", enabled, this); - this.enabled = enabled; - } - - /** Used to trigger the component to update itself. This should not need to be called manually. */ - public final void triggerUpdate() { - if (enabled) { - update(); - } - } - - /** - * Used to trigger the component to early-update itself. This should not need to be called - * manually. - */ - public final void triggerEarlyUpdate() { - if (enabled) { - earlyUpdate(); - } - } - - @Override - public String toString() { - String className = this.getClass().getSimpleName(); - if (entity == null) { - return className; - } - return entity + "." + className; - } -} +package com.csse3200.game.components; + +import com.csse3200.game.entities.Entity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Core component class from which all components inherit. Contains logic for creating, updating, + * and disposing. Components can be attached to an entity to give it specific behaviour. It is + * unlikely that changes will need to be made here. + */ +public class Component { + private static final Logger logger = LoggerFactory.getLogger(Component.class); + protected Entity entity; + public boolean enabled = true; + + /** + * Called when the entity is created and registered. Initial logic such as calls to GetComponent + * should be made here, not in the constructor which is called before an entity is finished. + */ + public void create() { + // No action by default. + } + + /** + * Early update called once per frame of the game, before update(). Use this only for logic that + * must run before other updates, such as physics. Not called if component is disabled. + */ + public void earlyUpdate() { + // No action by default. + } + + /** + * Called once per frame of the game, and should be used for most component logic. Not called if + * component is disabled. + */ + public void update() { + // No action by default. + } + + /** Called when the component is disposed. Dispose of any internal resources here. */ + public void dispose() { + // No action by default. + } + + /** + * Set the entity to which this component belongs. This is called by the Entity, and should not be + * set manually. + * + * @param entity The entity to which the component is attached. + */ + public void setEntity(Entity entity) { + logger.debug("Attaching {} to {}", this, entity); + this.entity = entity; + } + + /** + * Get the entity to which this component belongs. + * @return entity + */ + public Entity getEntity() { + return entity; + } + + /** + * Enable or disable the component. While disabled, a component does not run update() or + * earlyUpdate(). Other events inside the component may still fire. The component can still be + * disposed while disabled. + * + * @param enabled Should component be enabled + */ + public void setEnabled(boolean enabled) { + logger.debug("Setting enabled={} on {}", enabled, this); + this.enabled = enabled; + } + + /** Used to trigger the component to update itself. This should not need to be called manually. */ + public final void triggerUpdate() { + if (enabled) { + update(); + } + } + + /** + * Used to trigger the component to early-update itself. This should not need to be called + * manually. + */ + public final void triggerEarlyUpdate() { + if (enabled) { + earlyUpdate(); + } + } + + @Override + public String toString() { + String className = this.getClass().getSimpleName(); + if (entity == null) { + return className; + } + return entity + "." + className; + } +} 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 2ff88df7e..b55a6e80a 100644 --- a/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java +++ b/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java @@ -1,183 +1,299 @@ -package com.csse3200.game.components; - -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.physics.box2d.Body; -import com.badlogic.gdx.physics.box2d.Fixture; -import com.csse3200.game.components.npc.DeflectingComponent; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.Weapon; -import com.csse3200.game.physics.BodyUserData; -import com.csse3200.game.physics.PhysicsLayer; -import com.csse3200.game.physics.components.HitboxComponent; -import com.csse3200.game.physics.components.PhysicsComponent; - -/** - * When this entity touches a valid enemy's hitbox, deal damage to them and - * apply a knockback. - * Has an optional disposeOnHit property that disposes projectile upon - * collision. - * - *

- * Requires CombatStatsComponent, HitboxComponent on this entity. - * - *

- * Damage is only applied if target entity has a CombatStatsComponent. Knockback - * is only applied - * if target entity has a PhysicsComponent. - */ -public class TouchAttackComponent extends Component { - private short targetLayer; - private float knockbackForce = 0f; - private boolean disposeOnHit = false; - private CombatStatsComponent combatStats; - private HitboxComponent hitboxComponent; - - /** - * Create a component which attacks entities on collision, without knockback. - * - * @param targetLayer The physics layer of the target's collider. - */ - public TouchAttackComponent(short targetLayer) { - this.targetLayer = targetLayer; - } - - /** - * Create a component which attacks entities on collision, with knockback. - * - * @param targetLayer The physics layer of the target's collider. - * @param knockback The magnitude of the knockback applied to the entity. - */ - public TouchAttackComponent(short targetLayer, float knockback) { - this.targetLayer = targetLayer; - this.knockbackForce = knockback; - } - - /** - * Create a component which attacks entities on collision, with knockback and - * self-dispose. - * - * @param targetLayer The physics layer of the target's collider. - * @param knockback The magnitude of the knockback applied to the entity. - * @param disposeOnHit Whether this entity should be disposed on hit. - */ - public TouchAttackComponent(short targetLayer, float knockback, boolean disposeOnHit) { - this.targetLayer = targetLayer; - this.knockbackForce = knockback; - this.disposeOnHit = disposeOnHit; - } - - @Override - public void create() { - entity.getEvents().addListener("collisionStart", this::onCollisionStart); - entity.getEvents().addListener("collisionEnd", this::onCollisionEnd); - combatStats = entity.getComponent(CombatStatsComponent.class); - hitboxComponent = entity.getComponent(HitboxComponent.class); - } - - public void onCollisionStart(Fixture me, Fixture other) { - if (hitboxComponent.getFixture() != me) { - // Not triggered by hitbox, ignore - return; - } - - if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { - // Doesn't match our target layer, ignore - return; - } - - // Try to attack target. - Entity target = ((BodyUserData) other.getBody().getUserData()).entity; - - // If enemy has deflecting component, don't delete it. - Component deflectComponent = target.getComponent(DeflectingComponent.class); - if (deflectComponent != null && deflectComponent.enabled) - return; - - CombatStatsComponent targetStats = target.getComponent(CombatStatsComponent.class); - if (targetStats != null) { - // If entity has abilities, pick one at random and apply it else use baseAttack - // damage - if (combatStats.getWeapon(target) != null) { - targetStats.hit(combatStats.getWeapon(target).getDamage()); - } else { - targetStats.hit(combatStats.getBaseAttack()); - } - } - // Apply knockback - PhysicsComponent physicsComponent = target.getComponent(PhysicsComponent.class); - if (physicsComponent != null && knockbackForce > 0f) { - Body targetBody = physicsComponent.getBody(); - Vector2 direction = target.getCenterPosition().sub(entity.getCenterPosition()); - Vector2 impulse = direction.setLength(knockbackForce); - targetBody.applyLinearImpulse(impulse, targetBody.getWorldCenter(), true); - } - - if (disposeOnHit) { - Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; - projectile.setFlagForDelete(true); - } - } - - public void setDisposeOnHit(boolean disposeOnHit) { - this.disposeOnHit = disposeOnHit; - } - - public void setKnockBack(float knockback) { - this.knockbackForce = knockback; - } - - private void onCollisionEnd(Fixture me, Fixture other) { - // Nothing to do on collision end - if (hitboxComponent.getFixture() != me) { - // Not triggered by hitbox, ignore - return; - } - - if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { - // Doesn't match our target layer, ignore - return; - } - - Entity otherEntity = ((BodyUserData) other.getBody().getUserData()).entity; - - // If enemy has enabled deflection component, don't dispose it. - if (otherEntity.getComponent(DeflectingComponent.class) != null) - return; - - if (disposeOnHit) { - Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; - projectile.setFlagForDelete(true); - } - } - - /** - * Choose the weapon to use against the given fixture. - * - * If the fixture has been removed (died) return null, else return the weapon to use. - * */ - public Weapon chooseWeapon(Fixture other) { - if (other == null) { - return null; - } - BodyUserData data = ((BodyUserData) other.getBody().getUserData()); - if (data == null) { - return null; - } - Entity target = data.entity; - Weapon weapon = null; - if (target.getComponent(CombatStatsComponent.class) != null) { - weapon = combatStats.getWeapon(target); - } - return weapon; - } - - /** - * Sets the target layer of this component, changing which entity to "attack" - * and/or apply knockback to. - * - * @param targetLayer - */ - public void setTargetLayer(short targetLayer) { - this.targetLayer = targetLayer; - } -} +package com.csse3200.game.components; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.components.npc.DeflectingComponent; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.Weapon; +import com.csse3200.game.physics.BodyUserData; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; +import com.csse3200.game.physics.components.PhysicsComponent; +import com.csse3200.game.components.projectile.EngineerBulletsAnimationController; +import com.csse3200.game.components.projectile.ProjectileAnimationController; +import com.csse3200.game.components.projectile.SnowBallProjectileAnimationController; +import com.csse3200.game.components.projectile.StunEffectProjectileAnimationController; +import com.csse3200.game.components.projectile.BurnEffectProjectileAnimationController; +import com.csse3200.game.physics.components.PhysicsMovementComponent; +import java.util.Timer; +import java.util.TimerTask; +import com.csse3200.game.components.npc.XenoAnimationController; +import com.csse3200.game.components.npc.DragonKnightAnimationController; +import com.csse3200.game.components.npc.FireWormAnimationController; +import com.csse3200.game.components.npc.SkeletonAnimationController; +import com.csse3200.game.components.npc.WizardAnimationController; +import com.csse3200.game.components.npc.WaterQueenAnimationController; +import com.csse3200.game.components.npc.WaterSlimeAnimationController; +import com.csse3200.game.ai.tasks.AITaskComponent; + +/** + * When this entity touches a valid enemy's hitbox, deal damage to them and + * apply a knockback. + * Has an optional disposeOnHit property that disposes projectile upon + * collision. + * + *

+ * Requires CombatStatsComponent, HitboxComponent on this entity. + * + *

+ * Damage is only applied if target entity has a CombatStatsComponent. Knockback + * is only applied + * if target entity has a PhysicsComponent. + */ +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; + + /** + * Create a component which attacks entities on collision, without knockback. + * + * @param targetLayer The physics layer of the target's collider. + */ + public TouchAttackComponent(short targetLayer) { + this.targetLayer = targetLayer; + } + + /** + * Create a component which attacks entities on collision, with knockback. + * + * @param targetLayer The physics layer of the target's collider. + * @param knockback The magnitude of the knockback applied to the entity. + */ + public TouchAttackComponent(short targetLayer, float knockback) { + this.targetLayer = targetLayer; + this.knockbackForce = knockback; + } + + /** + * Create a component which attacks entities on collision, with knockback and + * self-dispose. + * + * @param targetLayer The physics layer of the target's collider. + * @param knockback The magnitude of the knockback applied to the entity. + * @param disposeOnHit Whether this entity should be disposed on hit. + */ + public TouchAttackComponent(short targetLayer, float knockback, boolean disposeOnHit) { + this.targetLayer = targetLayer; + this.knockbackForce = knockback; + this.disposeOnHit = disposeOnHit; + } + + @Override + public void create() { + entity.getEvents().addListener("collisionStart", this::onCollisionStart); + entity.getEvents().addListener("collisionEnd", this::onCollisionEnd); + combatStats = entity.getComponent(CombatStatsComponent.class); + hitboxComponent = entity.getComponent(HitboxComponent.class); + } + + public void onCollisionStart(Fixture me, Fixture other) { + if (me==null || hitboxComponent==null || hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + if(other!=null) + { + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + Component deflectComponent = ((BodyUserData) other.getBody().getUserData()).entity.getComponent(DeflectingComponent.class); + if (deflectComponent != null && deflectComponent.enabled) + return; + }else + return; + // Try to attack target. + Entity target = ((BodyUserData) other.getBody().getUserData()).entity; + + EngineerBulletsAnimationController engineerBulletsAnimationController; + ProjectileAnimationController projectileAnimationController; + SnowBallProjectileAnimationController snowBallProjectileAnimationController; + StunEffectProjectileAnimationController stunEffectProjectileAnimationController; + BurnEffectProjectileAnimationController burnEffectProjectileAnimationController; + if((engineerBulletsAnimationController=entity.getComponent(EngineerBulletsAnimationController.class)) != null) + { + setDisposeOnHit(false); + entity.getComponent(PhysicsMovementComponent.class).setSpeed(new Vector2(0, 0)); + new Timer().schedule(new TimerTask() { + public void run() { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + }, 300/*START_SPEED*frames*1000ms*/); + }else + if((projectileAnimationController=entity.getComponent(ProjectileAnimationController.class)) != null) + { + setDisposeOnHit(false); + entity.getComponent(PhysicsMovementComponent.class).setSpeed(new Vector2(0, 0)); + new Timer().schedule(new TimerTask() { + public void run() { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + }, 300/*START_SPEED*frames*1000ms*/); + }else + if((burnEffectProjectileAnimationController=entity.getComponent(BurnEffectProjectileAnimationController.class)) != null) + { + setDisposeOnHit(false); + entity.getComponent(PhysicsMovementComponent.class).setSpeed(new Vector2(0, 0)); + new Timer().schedule(new TimerTask() { + public void run() { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + }, 800/*START_SPEED*frames*1000ms*/); + }else + if((snowBallProjectileAnimationController=entity.getComponent(SnowBallProjectileAnimationController.class)) != null) + { + setDisposeOnHit(false); + entity.getComponent(PhysicsMovementComponent.class).setSpeed(new Vector2(0, 0)); + new Timer().schedule(new TimerTask() { + public void run() { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + }, 200/*START_SPEED*frames*1000ms*/); + + AITaskComponent aiTaskComponent; + if((aiTaskComponent=target.getComponent(AITaskComponent.class))!=null) + { + aiTaskComponent.freezed = true; + PhysicsMovementComponent physicsMovementComponent; + if((physicsMovementComponent=target.getComponent(PhysicsMovementComponent.class))!=null) + physicsMovementComponent.setMoving(false); + new Timer().schedule(new TimerTask() { + public void run() { + aiTaskComponent.freezed = false; + PhysicsMovementComponent physicsMovementComponent; + if((physicsMovementComponent=target.getComponent(PhysicsMovementComponent.class))!=null) + physicsMovementComponent.setMoving(true); + target.getEvents().trigger("wanderStart"); + } + }, 5000); + } + target.getEvents().trigger("freeze"); + /*else + if(aiTaskComponent!=null) + aiTaskComponent.freezed = false;*/ + }else + if((stunEffectProjectileAnimationController=entity.getComponent(StunEffectProjectileAnimationController.class)) != null) + { + setDisposeOnHit(false); + entity.getComponent(PhysicsMovementComponent.class).setSpeed(new Vector2(0, 0)); + new Timer().schedule(new TimerTask() { + public void run() { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + }, 900/*START_SPEED*frames*1000ms*/); + + AITaskComponent aiTaskComponent; + if((aiTaskComponent=target.getComponent(AITaskComponent.class))!=null) + { + aiTaskComponent.freezed = true; + PhysicsMovementComponent physicsMovementComponent; + if((physicsMovementComponent=target.getComponent(PhysicsMovementComponent.class))!=null) + physicsMovementComponent.setMoving(false); + new Timer().schedule(new TimerTask() { + public void run() { + aiTaskComponent.freezed = false; + PhysicsMovementComponent physicsMovementComponent; + if((physicsMovementComponent=target.getComponent(PhysicsMovementComponent.class))!=null) + physicsMovementComponent.setMoving(true); + } + }, 1000); + } + } + CombatStatsComponent targetStats = target.getComponent(CombatStatsComponent.class); + if (targetStats != null) { + // If entity has abilities, pick one at random and apply it else use baseAttack + // damage + if (combatStats.getWeapon(target) != null) { + targetStats.hit(combatStats.getWeapon(target).getDamage()); + } else { + targetStats.hit(combatStats.getBaseAttack()); + } + } + // Apply knockback + PhysicsComponent physicsComponent = target.getComponent(PhysicsComponent.class); + if (physicsComponent != null && knockbackForce > 0f) { + Body targetBody = physicsComponent.getBody(); + Vector2 direction = target.getCenterPosition().sub(entity.getCenterPosition()); + Vector2 impulse = direction.setLength(knockbackForce); + targetBody.applyLinearImpulse(impulse, targetBody.getWorldCenter(), true); + } + + if (disposeOnHit) { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + } + + public void setDisposeOnHit(boolean disposeOnHit) { + this.disposeOnHit = disposeOnHit; + } + + public void setKnockBack(float knockback) { + this.knockbackForce = knockback; + } + + private void onCollisionEnd(Fixture me, Fixture other) { + // Nothing to do on collision end + if (hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + + Entity otherEntity = ((BodyUserData) other.getBody().getUserData()).entity; + + // If enemy has enabled deflection component, don't dispose it. + if (otherEntity.getComponent(DeflectingComponent.class) != null) + return; + + if (disposeOnHit) { + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + projectile.setFlagForDelete(true); + } + } + + /** + * Choose the weapon to use against the given fixture. + * + * If the fixture has been removed (died) return null, else return the weapon to use. + * */ + public Weapon chooseWeapon(Fixture other) { + if (other == null) { + return null; + } + BodyUserData data = ((BodyUserData) other.getBody().getUserData()); + if (data == null) { + return null; + } + Entity target = data.entity; + Weapon weapon = null; + if (target.getComponent(CombatStatsComponent.class) != null) { + weapon = combatStats.getWeapon(target); + } + return weapon; + } + + /** + * Sets the target layer of this component, changing which entity to "attack" + * and/or apply knockback to. + * + * @param targetLayer + */ + public void setTargetLayer(short targetLayer) { + this.targetLayer = targetLayer; + } +} 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 6d9d54215..dab866862 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,7 +1,9 @@ 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; /** @@ -23,6 +25,11 @@ public void create() { entity.getEvents().addListener("mob_walk", this::animateWalk); entity.getEvents().addListener("mob_attack", this::animateAttack); entity.getEvents().addListener("mob_death", this::animateDeath); + + entity.getEvents().addListener("wanderStart", this::animateWalk); + entity.getEvents().addListener("shootStart", this::animateAttack); + entity.getEvents().addListener("dieStart", this::animateDeath); + entity.getEvents().addListener("freeze", this::animateFreeze); } void animateWalk() { @@ -37,6 +44,9 @@ void animateDeath() { animator.startAnimation("dragon_knight_death"); } - + void animateFreeze() + { + animator.startAnimation("dragon_knight_freeze"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/npc/FireWormAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/FireWormAnimationController.java index 141d43d69..02998db7f 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/FireWormAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/FireWormAnimationController.java @@ -29,7 +29,11 @@ public void create() { entity.getEvents().addListener("mob_walk", this::animateWalk); entity.getEvents().addListener("mob_attack", this::animateAttack); entity.getEvents().addListener("mob_death", this::animateDeath); - entity.getEvents().addListener("default", this::stopAnimation); + + entity.getEvents().addListener("wanderStart", this::animateWalk); + entity.getEvents().addListener("shootStart", this::animateAttack); + entity.getEvents().addListener("dieStart", this::animateDeath); + entity.getEvents().addListener("freeze", this::animateFreeze); } void animateWalk() { @@ -50,6 +54,9 @@ void stopAnimation() { animator.startAnimation("default"); } - + void animateFreeze() + { + animator.startAnimation("fire_worm_freeze"); + } } 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 d5ea57bfa..bafa8d36a 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,17 +23,14 @@ 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(); 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); + entity.getEvents().addListener("wanderStart", this::animateWalk); + entity.getEvents().addListener("shootStart", this::animateAttack); + entity.getEvents().addListener("dieStart", this::animateDeath); + entity.getEvents().addListener("freeze", this::animateFreeze); } void animateWalk() { @@ -42,8 +39,6 @@ void animateWalk() { void animateAttack() { animator.startAnimation("skeleton_attack"); - attackSound.setVolume(1000, 0); - attackSound.play(); } void animateDeath() { @@ -51,5 +46,10 @@ void animateDeath() { deathSound.setVolume(1000, 5.5f); deathSound.play(); } + + void animateFreeze() + { + animator.startAnimation("skeleton_freeze"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/npc/WaterQueenAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/WaterQueenAnimationController.java index 0b8a00b75..82209c68b 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/WaterQueenAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/WaterQueenAnimationController.java @@ -26,9 +26,10 @@ public class WaterQueenAnimationController extends Component { 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); + entity.getEvents().addListener("wanderStart", this::animateWalk); + entity.getEvents().addListener("shootStart", this::animateAttack); + entity.getEvents().addListener("dieStart", this::animateDeath); + entity.getEvents().addListener("freeze", this::animateFreeze); } void animateWalk() { @@ -44,5 +45,9 @@ void animateAttack() { void animateDeath() { animator.startAnimation("water_queen_death"); } + + void animateFreeze() { + animator.startAnimation("water_queen_freeze"); + } } 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 6909dad10..b0e14ba49 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,7 +1,9 @@ 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; /** @@ -20,9 +22,10 @@ public class WaterSlimeAnimationController extends Component { 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); + entity.getEvents().addListener("wanderStart", this::animateWalk); + entity.getEvents().addListener("shootStart", this::animateAttack); + entity.getEvents().addListener("dieStart", this::animateDeath); + entity.getEvents().addListener("freeze", this::animateFreeze); } void animateWalk() { @@ -36,6 +39,10 @@ void animateAttack() { void animateDeath() { animator.startAnimation("water_slime_death"); } + + void animateFreeze() { + animator.startAnimation("water_slime_freeze"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/npc/WizardAnimationController.java b/source/core/src/main/com/csse3200/game/components/npc/WizardAnimationController.java index c8c8e7073..68ac160fe 100644 --- a/source/core/src/main/com/csse3200/game/components/npc/WizardAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/npc/WizardAnimationController.java @@ -32,6 +32,10 @@ public void create() { entity.getEvents().addListener("mob_attack", this::animateAttack); entity.getEvents().addListener("mob_death", this::animateDeath); + entity.getEvents().addListener("wanderStart", this::animateWalk); + entity.getEvents().addListener("shootStart", this::animateAttack); + entity.getEvents().addListener("dieStart", this::animateDeath); + entity.getEvents().addListener("freeze", this::animateFreeze); } @@ -48,5 +52,10 @@ void animateAttack() { void animateDeath() { animator.startAnimation("wizard_death"); } + + void animateFreeze() + { + animator.startAnimation("wizard_freeze"); + } } 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 d07dc4683..f8a4abf3c 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,7 +1,9 @@ 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; /** @@ -26,6 +28,7 @@ public void create() { entity.getEvents().addListener("shootStart", this::animateShoot); entity.getEvents().addListener("dieStart", this::animateDie); entity.getEvents().addListener("stop", this::stopAnimation); + entity.getEvents().addListener("freeze", this::animateFreeze); } void animateRun() { @@ -56,4 +59,9 @@ void animateDie() { void stopAnimation() { animator.startAnimation("default"); } + + void animateFreeze() + { + animator.startAnimation("xeno_freeze"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/projectile/BurnEffectProjectileAnimationController.java b/source/core/src/main/com/csse3200/game/components/projectile/BurnEffectProjectileAnimationController.java index 847f77027..01e052cc6 100644 --- a/source/core/src/main/com/csse3200/game/components/projectile/BurnEffectProjectileAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/projectile/BurnEffectProjectileAnimationController.java @@ -2,6 +2,9 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; public class BurnEffectProjectileAnimationController extends Component { /** Event name constants */ @@ -12,7 +15,14 @@ public class BurnEffectProjectileAnimationController extends Component { private static final String START_ANIM = "projectile"; private static final String FINAL_ANIM = "projectileFinal"; AnimationRenderComponent animator; - + + private HitboxComponent hitboxComponent; + short targetLayer; + + public BurnEffectProjectileAnimationController(short targetLayer) + { + this.targetLayer = targetLayer; + } @Override public void create() { @@ -21,6 +31,7 @@ public void create() { entity.getEvents().addListener(START, this::animateStart); entity.getEvents().addListener(FINAL, this::animateFinal); + hitboxComponent = entity.getComponent(HitboxComponent.class); } void animateStart() { @@ -28,6 +39,18 @@ void animateStart() { } void animateFinal() { - animator.startAnimation(FINAL_ANIM); + } + + public void animateCollide(Fixture me, Fixture other) { + if (hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + + animator.startAnimation("explosion"); } } diff --git a/source/core/src/main/com/csse3200/game/components/projectile/EngineerBulletsAnimationController.java b/source/core/src/main/com/csse3200/game/components/projectile/EngineerBulletsAnimationController.java index a9dc1a63f..d68d4d79f 100644 --- a/source/core/src/main/com/csse3200/game/components/projectile/EngineerBulletsAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/projectile/EngineerBulletsAnimationController.java @@ -3,11 +3,24 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.ServiceLocator; //used for sound +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; +import com.csse3200.game.physics.BodyUserData; +import com.csse3200.game.components.npc.DeflectingComponent; public class EngineerBulletsAnimationController extends Component{ /** Event name constants */ AnimationRenderComponent animator; + + private HitboxComponent hitboxComponent; + short targetLayer; + + public EngineerBulletsAnimationController(short targetLayer) + { + this.targetLayer = targetLayer; + } @Override public void create() { @@ -15,7 +28,8 @@ public void create() { animator = this.entity.getComponent(AnimationRenderComponent.class); entity.getEvents().addListener("startProjectile", this::animateStart); entity.getEvents().addListener("startProjectileFinal", this::animateFinal); - + entity.getEvents().addListener("collisionStart", this::animateCollide); + hitboxComponent = entity.getComponent(HitboxComponent.class); } void animateStart() { @@ -25,5 +39,27 @@ void animateStart() { void animateFinal() { animator.startAnimation("bulletFinal"); } + + void animateCollide(Fixture me, Fixture other){ + if(me!=null) + { + if (hitboxComponent==null || hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + }else + { + animator.startAnimation("bulletCollide"); + return; + } + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + Component deflectComponent = ((BodyUserData) other.getBody().getUserData()).entity.getComponent(DeflectingComponent.class); + if (deflectComponent != null && deflectComponent.enabled) + return; + animator.startAnimation("bulletCollide"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/projectile/PierceArrowAnimationController.java b/source/core/src/main/com/csse3200/game/components/projectile/PierceArrowAnimationController.java new file mode 100644 index 000000000..89bd71d32 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/projectile/PierceArrowAnimationController.java @@ -0,0 +1,25 @@ +package com.csse3200.game.components.projectile; + +import com.csse3200.game.components.Component; +import com.csse3200.game.rendering.AnimationRenderComponent; + +public class PierceArrowAnimationController extends Component { + /** Event name constants */ + private static final String START = "startProjectile"; + /** Animation name constants */ + private static final String START_ANIM = "arrow"; + AnimationRenderComponent animator; + + + @Override + public void create() { + super.create(); + animator = this.entity.getComponent(AnimationRenderComponent.class); + entity.getEvents().addListener(START, this::animateStart); + + } + + void animateStart() { + animator.startAnimation(START_ANIM); + } +} diff --git a/source/core/src/main/com/csse3200/game/components/projectile/ProjectileAnimationController.java b/source/core/src/main/com/csse3200/game/components/projectile/ProjectileAnimationController.java index 9610554c9..2b0a18608 100644 --- a/source/core/src/main/com/csse3200/game/components/projectile/ProjectileAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/projectile/ProjectileAnimationController.java @@ -2,6 +2,9 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; public class ProjectileAnimationController extends Component{ /** Event name constants */ @@ -12,7 +15,14 @@ public class ProjectileAnimationController extends Component{ private static final String START_ANIM = "projectile"; private static final String FINAL_ANIM = "projectileFinal"; AnimationRenderComponent animator; - + + private HitboxComponent hitboxComponent; + short targetLayer; + + public ProjectileAnimationController(short targetLayer) + { + this.targetLayer = targetLayer; + } @Override public void create() { @@ -20,7 +30,8 @@ public void create() { animator = this.entity.getComponent(AnimationRenderComponent.class); entity.getEvents().addListener(START, this::animateStart); entity.getEvents().addListener(FINAL, this::animateFinal); - + entity.getEvents().addListener("collisionStart", this::animateCollide); + hitboxComponent = entity.getComponent(HitboxComponent.class); } void animateStart() { @@ -30,4 +41,17 @@ void animateStart() { void animateFinal() { animator.startAnimation(FINAL_ANIM); } + + void animateCollide(Fixture me, Fixture other) { + if (hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + + animator.startAnimation("projectileCollide"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/projectile/SnowBallProjectileAnimationController.java b/source/core/src/main/com/csse3200/game/components/projectile/SnowBallProjectileAnimationController.java index adb1f2869..d80b5b209 100644 --- a/source/core/src/main/com/csse3200/game/components/projectile/SnowBallProjectileAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/projectile/SnowBallProjectileAnimationController.java @@ -2,6 +2,9 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; public class SnowBallProjectileAnimationController extends Component{ private static final String START = "startProjectile"; @@ -11,6 +14,14 @@ public class SnowBallProjectileAnimationController extends Component{ private static final String START_ANIM = "projectile"; private static final String FINAL_ANIM = "projectileFinal"; AnimationRenderComponent animator; + + private HitboxComponent hitboxComponent; + short targetLayer; + + public SnowBallProjectileAnimationController(short targetLayer) + { + this.targetLayer = targetLayer; + } @Override public void create() { @@ -18,7 +29,9 @@ public void create() { animator = this.entity.getComponent(AnimationRenderComponent.class); entity.getEvents().addListener(START, this::animateStart); entity.getEvents().addListener(FINAL, this::animateFinal); + entity.getEvents().addListener("collisionStart", this::animateCollide); + hitboxComponent = entity.getComponent(HitboxComponent.class); } void animateStart() { @@ -28,4 +41,17 @@ void animateStart() { void animateFinal() { animator.startAnimation(FINAL_ANIM); } + + void animateCollide(Fixture me, Fixture other) { + if (hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + + animator.startAnimation("collision"); + } } diff --git a/source/core/src/main/com/csse3200/game/components/projectile/StunEffectProjectileAnimationController.java b/source/core/src/main/com/csse3200/game/components/projectile/StunEffectProjectileAnimationController.java index 94899ff17..507a689d4 100644 --- a/source/core/src/main/com/csse3200/game/components/projectile/StunEffectProjectileAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/projectile/StunEffectProjectileAnimationController.java @@ -2,6 +2,9 @@ import com.csse3200.game.components.Component; import com.csse3200.game.rendering.AnimationRenderComponent; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; public class StunEffectProjectileAnimationController extends Component { /** Event name constants */ @@ -11,17 +14,39 @@ public class StunEffectProjectileAnimationController extends Component { private static final String START_ANIM = "projectile"; AnimationRenderComponent animator; + private HitboxComponent hitboxComponent; + short targetLayer; + + public StunEffectProjectileAnimationController(short targetLayer) + { + this.targetLayer = targetLayer; + } @Override public void create() { super.create(); animator = this.entity.getComponent(AnimationRenderComponent.class); entity.getEvents().addListener(START, this::animateStart); + entity.getEvents().addListener("collisionStart", this::animateCollide); + hitboxComponent = entity.getComponent(HitboxComponent.class); } void animateStart() { animator.startAnimation(START_ANIM); } - + + void animateCollide(Fixture me, Fixture other) + { + if (hitboxComponent.getFixture() != me) { + // Not triggered by hitbox, ignore + return; + } + if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) { + // Doesn't match our target layer, ignore + return; + } + + animator.startAnimation("stun"); + } } 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 39215cb9e..152d27693 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 @@ -16,13 +16,15 @@ import com.csse3200.game.physics.raycast.RaycastHit; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.npc.XenoAnimationController; /** * Task that allows mobs to shoot projectiles or melee attack towers */ 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_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String STOW = "wanderStart"; @@ -33,13 +35,15 @@ 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 static final long DELAY = 1000; // delay between shots + private final long delay = 1000; // delay between shots private long startTime; private enum STATE { @@ -50,9 +54,11 @@ 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) { + public MobAttackTask(int priority, float maxRange) { this.priority = priority; + this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -66,9 +72,11 @@ public MobAttackTask(int priority) { public void start() { super.start(); startTime = timeSource.getTime(); - Vector2 mobPosition = owner.getEntity().getCenterPosition(); + this.mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); - long endTime = timeSource.getTime() + (INTERVAL * 500); + //owner.getEntity().getEvents().trigger(IDLE); + endTime = timeSource.getTime() + (INTERVAL * 500); +// owner.getEntity().getEvents().trigger("shootStart"); } /** @@ -77,11 +85,14 @@ public void start() { */ @Override public void update() { - updateMobState(); - - if (mobState == STATE.STOW) { - status = Status.FINISHED; - } + if(!owner.getEntity().getComponent(AITaskComponent.class).freezed) + { + updateMobState(); + + if (mobState == STATE.STOW) { + status = Status.FINISHED; + } + } } /** @@ -116,21 +127,25 @@ 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(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (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 -> { @@ -165,20 +180,41 @@ public void stop() { */ @Override public int getPriority() { - if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { + 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) { 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_LAYER, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); } /** @@ -189,10 +225,11 @@ private boolean isTargetVisible() { * the function will return null. If it returns null when the mob is in state FIRING or DEPLOY, it will not fire * and will STOW. * - * @return the Weapon (Melee or Projectile) the mob will use to attack the target. null if immune target or no target + * returns the Weapon (Melee or Projectile) the mob will use to attack the target. null if immune target or no target * */ private Weapon meleeOrProjectile() { - +// Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f); +// Fixture hitraycast = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); setTarget(); TouchAttackComponent comp = owner.getEntity().getComponent(TouchAttackComponent.class); Weapon chosenWeapon = null; @@ -205,6 +242,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_LAYER); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); } } 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 a437fbdbf..5cc8a44d1 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,9 +1,11 @@ package com.csse3200.game.components.tasks; -import com.csse3200.game.components.tasks.MobTask.MobTask; -import com.csse3200.game.components.tasks.MobTask.MobType; +import com.badlogic.gdx.math.Vector2; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.npc.XenoAnimationController; +import com.csse3200.game.components.tasks.MobTask.*; /** * This task runs the AI that adds a dodge mechanic/functionality for the mobs @@ -23,15 +25,17 @@ public class MobDodgeTask extends MobTask { private long endTime; // Helps task wait between each interval. - private static final int DELAY_INTERVAL = 500; + private final int DELAY_INTERVAL = 500; /** * Initialises a mob dodge task with a specified wander range, wait time, and * priority level. * - * @param mobType Distance in X and Y the entity can move from its position - * when start() is called. - * @param priority Priority level compared to other added tasks. + * @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. + * @param priority Priority level compared to other added tasks. */ public MobDodgeTask(MobType mobType, int priority) { super(mobType); @@ -59,13 +63,15 @@ public void start() { @Override public void update() { super.update(); - if (timeSource.getTime() >= endTime) { - owner.getEntity().getEvents().trigger("dodgeIncomingEntity", - owner.getEntity().getCenterPosition()); - + if(!owner.getEntity().getComponent(AITaskComponent.class).freezed) + { + if (timeSource.getTime() >= endTime) { + owner.getEntity().getEvents().trigger("dodgeIncomingEntity", + owner.getEntity().getCenterPosition()); - endTime = timeSource.getTime() + DELAY_INTERVAL; // update time - } + endTime = timeSource.getTime() + DELAY_INTERVAL; // update time + } + } } /** 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 b76de16a4..336b75f4b 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 @@ -16,13 +16,15 @@ import com.csse3200.game.physics.raycast.RaycastHit; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.npc.XenoAnimationController; /** * Task that allows mobs to shoot projectiles or melee attack towers */ 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_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String STOW = "wanderStart"; @@ -33,13 +35,15 @@ 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 static final long DELAY = 1000; // delay between shots + private final long delay = 1000; // delay between shots private long startTime; private enum STATE { @@ -52,8 +56,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 MobMeleeAttackTask(int priority) { + public MobMeleeAttackTask(int priority, float maxRange) { this.priority = priority; + this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -67,11 +72,11 @@ public MobMeleeAttackTask(int priority) { public void start() { super.start(); startTime = timeSource.getTime(); - Vector2 mobPosition = owner.getEntity().getCenterPosition(); + this.mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); -// owner.getEntity().getEvents().trigger(FIRING); +// owner.getEntity().getEvents().trigger("shootStart"); } /** @@ -80,11 +85,14 @@ public void start() { */ @Override public void update() { - updateMobState(); - - if (mobState == STATE.STOW) { - status = Status.FINISHED; - } + + if(!owner.getEntity().getComponent(AITaskComponent.class).freezed) + { + updateMobState(); + if (mobState == STATE.STOW) { + status = Status.FINISHED; + } + } } /** @@ -92,62 +100,64 @@ public void update() { * triggers the appropriate events corresponding to the STATE enum. */ public void updateMobState() { - switch (mobState) { - - case IDLE -> { - if (isTargetVisible()) { - // targets detected in idle mode - start deployment - owner.getEntity().getEvents().trigger(DEPLOY); - mobState = STATE.DEPLOY; - } - } - - case DEPLOY -> { - // currently deploying, - if (isTargetVisible() || this.meleeOrProjectile() != null) { - owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(false); - this.owner.getEntity().getEvents().trigger(FIRING); - mobState = STATE.FIRING; - } else { - this.owner.getEntity().getEvents().trigger(STOW); - mobState = STATE.STOW; - } - } - - case FIRING -> { - // targets gone or cannot be attacked - stop firing - 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 { - 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; - } - owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(true); - } - - case STOW -> { - // currently stowing - if (isTargetVisible()) { - owner.getEntity().getEvents().trigger(DEPLOY); - mobState = STATE.DEPLOY; - } else { - owner.getEntity().getEvents().trigger(IDLE); - mobState = STATE.IDLE; - } - } - } + switch (mobState) { + case IDLE -> { + if (isTargetVisible()) { + // targets detected in idle mode - start deployment + owner.getEntity().getEvents().trigger(DEPLOY); + mobState = STATE.DEPLOY; + } + } + + case DEPLOY -> { + // currently deploying, + if (isTargetVisible() || this.meleeOrProjectile() != null) { + owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(false); + this.owner.getEntity().getEvents().trigger(FIRING); + mobState = STATE.FIRING; + } else { + this.owner.getEntity().getEvents().trigger(STOW); + mobState = STATE.STOW; + } + } + + case FIRING -> { + // targets gone or cannot be attacked - stop firing + 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("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); + + // 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 -> { + // currently stowing + if (isTargetVisible()) { + owner.getEntity().getEvents().trigger(DEPLOY); + mobState = STATE.DEPLOY; + } else { + owner.getEntity().getEvents().trigger(IDLE); + mobState = STATE.IDLE; + } + } + } } /** @@ -169,7 +179,29 @@ public void stop() { */ @Override public int getPriority() { - if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { + 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) { return priority; } return -1; @@ -181,7 +213,7 @@ public int getPriority() { */ 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_LAYER, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); } /** @@ -209,6 +241,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_LAYER); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); } } 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 021419a05..35eb230fc 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 @@ -16,13 +16,17 @@ import com.csse3200.game.physics.raycast.RaycastHit; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; - +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.npc.FireWormAnimationController; +import com.csse3200.game.components.npc.WizardAnimationController; +import com.csse3200.game.components.npc.WaterQueenAnimationController; +import com.csse3200.game.components.ProjectileEffects; /** * Task that allows mobs to shoot projectiles or melee attack towers */ 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_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String STOW = "wanderStart"; @@ -33,13 +37,15 @@ 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 static final long DELAY = 1000; // delay between shots + private final long delay = 1000; // delay between shots private long startTime; private enum STATE { @@ -50,9 +56,11 @@ 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) { + public MobRangedAttackTask(int priority, float maxRange) { this.priority = priority; + this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -66,7 +74,7 @@ public MobRangedAttackTask(int priority) { public void start() { super.start(); startTime = timeSource.getTime(); - Vector2 mobPosition = owner.getEntity().getCenterPosition(); + this.mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); @@ -79,11 +87,14 @@ public void start() { */ @Override public void update() { - updateMobState(); + if(!owner.getEntity().getComponent(AITaskComponent.class).freezed) + { + updateMobState(); - if (mobState == STATE.STOW) { - status = Status.FINISHED; - } + if (mobState == STATE.STOW) { + status = Status.FINISHED; + } + } } /** @@ -118,28 +129,43 @@ 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(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(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); - newProjectile.setScale(-1f, 1f); - ServiceLocator.getEntityService().register(newProjectile); + Entity newProjectile = (owner.getEntity().getComponent(FireWormAnimationController.class)!=null)? + ProjectileFactory.createEffectProjectile(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f), ProjectileEffects.BURN, false) + : ((owner.getEntity().getComponent(WaterQueenAnimationController.class)!=null)? + ProjectileFactory.createComboSnowBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f), false) + : ((owner.getEntity().getComponent(WizardAnimationController.class)!=null)? + ProjectileFactory.createEffectProjectile(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f), ProjectileEffects.STUN, false) + : 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); + Entity newProjectile1 = (owner.getEntity().getComponent(FireWormAnimationController.class)!=null)? + ProjectileFactory.createPierceFireBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)) + : ((owner.getEntity().getComponent(WaterQueenAnimationController.class)!=null)? + ProjectileFactory.createFireworks(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)) + : ((owner.getEntity().getComponent(WizardAnimationController.class)!=null)? + ProjectileFactory.createRicochetFireball(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f), 3) + : ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f)))); + newProjectile1.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); + newProjectile1.setScale(-1f, 1f); + ServiceLocator.getEntityService().register(newProjectile1); + ServiceLocator.getEntityService().register(newProjectile); + + if (this.meleeOrProjectile() instanceof Melee) { + TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class); + HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class); + attackComp.onCollisionStart(hitboxComp.getFixture(), target); // 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); + } else { + // 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 -> { @@ -174,7 +200,29 @@ public void stop() { */ @Override public int getPriority() { - if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) { + 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) { return priority; } return -1; @@ -186,7 +234,7 @@ public int getPriority() { */ 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_LAYER, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); } /** @@ -214,6 +262,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_LAYER); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); } } 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 2453c4941..e44abeea2 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 @@ -12,13 +12,15 @@ import com.csse3200.game.physics.raycast.RaycastHit; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.npc.XenoAnimationController; /** * Task that allows mobs to shoot projectiles or melee attack towers */ 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_LAYER = PhysicsLayer.HUMANS; // mobs detecting for towers + private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers // ^ fix this private static final String WALKING = "wanderStart"; @@ -29,13 +31,15 @@ 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 static final long DELAY = 1000; // delay between shots + private final long delay = 1000; // delay between shots private long startTime; private enum STATE { @@ -46,9 +50,11 @@ 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) { + public MobShootTask(int priority, float maxRange) { this.priority = priority; + this.maxRange = maxRange; startTime = 0; physics = ServiceLocator.getPhysicsService().getPhysics(); @@ -62,7 +68,7 @@ public MobShootTask(int priority) { public void start() { super.start(); startTime = timeSource.getTime(); - Vector2 mobPosition = owner.getEntity().getCenterPosition(); + this.mobPosition = owner.getEntity().getCenterPosition(); this.maxRangePosition.set(0, mobPosition.y); //owner.getEntity().getEvents().trigger(IDLE); endTime = timeSource.getTime() + (INTERVAL * 500); @@ -75,11 +81,14 @@ public void start() { */ @Override public void update() { - updateMobState(); - - if (mobState == STATE.WALKING) { - status = Status.FINISHED; - } + if(!owner.getEntity().getComponent(AITaskComponent.class).freezed) + { + updateMobState(); + + if (mobState == STATE.WALKING) { + status = Status.FINISHED; + } + } } /** @@ -99,7 +108,7 @@ public void updateMobState() { case DEPLOY -> { // currently deploying, - if (isTargetVisible()) { + if (isTargetVisible() != false) { owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(false); this.owner.getEntity().getEvents().trigger(FIRING); mobState = STATE.FIRING; @@ -111,13 +120,13 @@ public void updateMobState() { case FIRING -> { // targets gone or cannot be attacked - stop firing - if (isTargetVisible()) { + if (!isTargetVisible() == false) { 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(owner.getEntity().getPosition().x, owner.getEntity().getPosition().y); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); newProjectile.setScale(-1f, 1f); ServiceLocator.getEntityService().register(newProjectile); @@ -163,7 +172,29 @@ public void stop() { */ @Override public int getPriority() { - if ((startTime + DELAY) < timeSource.getTime() && isTargetVisible()) { + 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) { return priority; } return -1; @@ -175,7 +206,7 @@ public int getPriority() { */ 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_LAYER, hit); + return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit); } /** @@ -203,6 +234,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_LAYER); + target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET); } } 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 08aa0b627..0a208914d 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,271 +1,325 @@ -package com.csse3200.game.components.tasks.MobTask; - -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Timer; -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.components.tasks.MovementTask; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.factories.ProjectileFactory; -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 com.csse3200.game.components.tasks.MobTask.MobType; - -/** - * The AI Task for all general mobs. This task handles the sequencing for melee - * and ranged mobs as well as animations for all mobs. Its sequence is based on - * whether the mob is a melee or ranged mob which dictates its attack method. - */ -public class MobTask extends DefaultTask implements PriorityTask { - - // Constants - private static final int PRIORITY = 3; - private static final Vector2 MELEE_MOB_SPEED = new Vector2(0.7f,0.7f); - private static final Vector2 MELEE_RANGE_SPEED = new Vector2(0.5f,0.5f); - private static final int MELEE_DAMAGE = 10; - private static final long MELEE_ATTACK_SPEED = 2000; - private static final long RANGE_ATTACK_SPEED = 5000; - private static final float MELEE_ATTACK_RANGE = 0.2f; - - // Private variables - private final MobType mobType; - private State state = State.DEFAULT; - private Entity mob; - private AnimationRenderComponent animation; - private MovementTask movementTask; - private Entity target; - private GameTime gameTime; - private long lastTimeAttacked; - private long dodgeEndTime; - - // Flags - boolean melee; - boolean runFlag = false; - boolean meleeFlag = false; - boolean targetInRange = false; - boolean rangeAttackFlag = false; - boolean meleeAttackFlag = false; - boolean deathFlag = false; - boolean canDodge = false; - - // Enums - private enum State { - RUN, ATTACK, DEATH, DEFAULT - } - - /** - * constructor for the mob - * @param mobType type of mob it is - */ - public MobTask(MobType mobType) { - this.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 - */ - @Override - public void start() { - super.start(); - mob = owner.getEntity(); - animation = mob.getComponent(AnimationRenderComponent.class); - mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_MOB_SPEED); - melee = mobType.isMelee(); - - movementTask = new MovementTask(new Vector2(0f, mob.getPosition().y)); - movementTask.create(owner); - movementTask.start(); - runFlag = true; - changeState(State.RUN); - lastTimeAttacked = gameTime.getTime(); - dodgeEndTime = gameTime.getTime(); - - if (melee) { - mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_MOB_SPEED); - } else { - mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_RANGE_SPEED); - } - } - - /** - * handles the sequencing of melee and range mobs and detects death state - */ - @Override - public void update() { - - // death check - if (mob.getComponent(CombatStatsComponent.class).getHealth() <= 0 && !deathFlag) { - changeState(State.DEATH); - animate(); - movementTask.stop(); - deathFlag = true; - } else if (deathFlag && animation.isFinished()) { - ServiceLocator.getWaveService().updateEnemyCount(); - 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) { - movementTask.start(); - animate(); - runFlag = false; - } - 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 && meleeAttackFlag) { - movementTask.stop(); - animate(); - meleeAttack(); - meleeAttackFlag = false; - } else if (!melee && rangeAttackFlag) { - movementTask.stop(); - animate(); - rangeAttack(); - rangeAttackFlag = false; - } - if (animation.isFinished()) { - movementTask.start(); - changeState(State.RUN); - runFlag = true; - } - } - } - } - - /** - * handles animation for all states and all possible mobs - */ - private void animate() { - switch (state) { - case RUN -> owner.getEntity().getEvents().trigger("mob_walk"); - case ATTACK -> owner.getEntity().getEvents().trigger("mob_attack"); - case DEATH -> { - owner.getEntity().getEvents().trigger("mob_death"); - owner.getEntity().getEvents().trigger("splitDeath"); - } - case DEFAULT -> owner.getEntity().getEvents().trigger("mob_default"); - } - } - - /** - * Changes the state of the mob. - * - * @param state state to change current state to - */ - private void changeState(State state) { - this.state = state; - } - - /** - * detects if there's an enemy within range of 1 to the left of it - * @return if there's an enemy in front of the mob or not - */ - private boolean enemyDetected() { - // if there's an entity within x of - 1 of mob - Entity targetInFront = ServiceLocator.getEntityService().getEntityAtPosition( - mob.getPosition().x - MELEE_ATTACK_RANGE, mob.getPosition().y); - if (targetInFront == null) { - return false; - } - - // layer checking - HitboxComponent targetHitbox = targetInFront.getComponent(HitboxComponent.class); - if (targetHitbox == null) { - return false; - } - if (PhysicsLayer.contains(PhysicsLayer.HUMANS, targetHitbox.getLayer())) { - this.target = targetInFront; - return true; - } - return false; - } - - /** - * hits the target directly in front of it - */ - private void meleeAttack() { - // toggle melee flag off - meleeFlag = false; - - // check if target is null or not in range - if (target == null) { - return; - } - CombatStatsComponent targetCombatStats = target.getComponent(CombatStatsComponent.class); - targetCombatStats.hit(MELEE_DAMAGE); - Timer.schedule(new Timer.Task() { - @Override - public void run() { - if (!targetInRange) { - return; // stop if target in range - } - meleeFlag = true; // toggle melee flag off - } - }, MELEE_ATTACK_SPEED); - } - - /** - * Shoots a fireball projectile and updates lastTimeAttacked - */ - private void rangeAttack() { - Vector2 destination = new Vector2(0, mob.getPosition().y); - Entity projectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.HUMANS, destination, - new Vector2(2, 2), ProjectileEffects.FIREBALL, false); - projectile.setPosition(mob.getPosition()); - projectile.setScale(-1f, 1f); - ServiceLocator.getEntityService().register(projectile); - lastTimeAttacked = gameTime.getTime(); - } - - /** - * @return priority of task - */ - @Override - 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; - } -} +package com.csse3200.game.components.tasks.MobTask; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Timer; +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.components.tasks.MovementTask; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.factories.ProjectileFactory; +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 com.csse3200.game.components.npc.ArcaneArcherAnimationController; + +/** + * The AI Task for all general mobs. This task handles the sequencing for melee + * and ranged mobs as well as animations for all mobs. Its sequence is based on + * whether the mob is a melee or ranged mob which dictates its attack method. + */ +public class MobTask extends DefaultTask implements PriorityTask { + + // Constants + private static final int PRIORITY = 3; + private static final Vector2 MELEE_MOB_SPEED = new Vector2(0.7f,0.7f); + private static final Vector2 MELEE_RANGE_SPEED = new Vector2(0.5f,0.5f); + private static final int MELEE_DAMAGE = 10; + private static final long MELEE_ATTACK_SPEED = 2000; + private static final long RANGE_ATTACK_SPEED = 5000; + private static final float MELEE_ATTACK_RANGE = 0.2f; + + // 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; + + // Flags + boolean melee; + boolean runFlag = false; + boolean meleeFlag = false; + boolean targetInRange = false; + boolean rangeAttackFlag = false; + boolean meleeAttackFlag = false; + boolean deathFlag = false; + + // Enums + private enum State { + RUN, ATTACK, DEATH, DEFAULT + } + + /** + * constructor for the mob + * @param mobType type of mob it is + */ + public MobTask(MobType mobType) { + this.mobType = mobType; + gameTime = ServiceLocator.getTimeSource(); + } + + /** + * starts general mob sequence, starts its movement task and initialises + * some of its variables + */ + @Override + public void start() { + super.start(); + mob = owner.getEntity(); + animation = mob.getComponent(AnimationRenderComponent.class); + mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_MOB_SPEED); + melee = mobType.isMelee(); + + movementTask = new MovementTask(new Vector2(0f, mob.getPosition().y)); + movementTask.create(owner); + movementTask.start(); + runFlag = true; + changeState(State.RUN); + lastTimeAttacked = gameTime.getTime(); + + if (melee) { + mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_MOB_SPEED); + } else { + mob.getComponent(PhysicsMovementComponent.class).setSpeed(MELEE_RANGE_SPEED); + } + } + + /** + * handles the sequencing of melee and range mobs and detects death state + */ + @Override + public void update() { + + // death check + if (mob.getComponent(CombatStatsComponent.class).getHealth() <= 0 && !deathFlag) { + changeState(State.DEATH); + animate(); + movementTask.stop(); + deathFlag = true; + } else if (deathFlag && animation.isFinished()) { + mob.setFlagForDelete(true); + } + + switch (state) { + case RUN -> { + if (runFlag) { + movementTask.start(); + 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; + } + } + } + case ATTACK -> { + if (melee) { + if (meleeAttackFlag) { + movementTask.stop(); + animate(); + meleeAttack(); + meleeAttackFlag = false; + } + if (animation.isFinished()) { + movementTask.start(); + changeState(State.RUN); + runFlag = true; + } + } + if (!melee) { + if (rangeAttackFlag) { + movementTask.stop(); + animate(); + rangeAttack(); + rangeAttackFlag = false; + } + if (animation.isFinished()) { + movementTask.start(); + changeState(State.RUN); + runFlag = true; + } + } + } + } + } + + /** + * handles animation for all states and all possible mobs + */ + private void animate() { + switch (state) { + case RUN -> owner.getEntity().getEvents().trigger("mob_walk"); + case ATTACK -> owner.getEntity().getEvents().trigger("mob_attack"); + case DEATH -> { + owner.getEntity().getEvents().trigger("mob_death"); + owner.getEntity().getEvents().trigger("splitDeath"); + } + case DEFAULT -> owner.getEntity().getEvents().trigger("mob_default"); + } + // switch (mobType) { + // case SKELETON -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("skeleton_walk"); + // case ATTACK -> owner.getEntity().getEvents().trigger("skeleton_attack"); + // case DEATH -> owner.getEntity().getEvents().trigger("skeleton_death"); + // case DEFAULT -> owner.getEntity().getEvents().trigger("skeleton_default"); + // } + // } + // case WIZARD -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("wizard_run"); + // case ATTACK -> owner.getEntity().getEvents().trigger("wizard_attack"); + // case DEATH -> owner.getEntity().getEvents().trigger("wizard_death"); + // case DEFAULT -> owner.getEntity().getEvents().trigger("default"); + // } + // } + // case WATER_QUEEN -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("water_queen_walk"); + // case ATTACK -> owner.getEntity().getEvents().trigger("water_queen_attack"); + // case DEATH -> owner.getEntity().getEvents().trigger("water_queen_death"); + // case DEFAULT -> owner.getEntity().getEvents().trigger("default"); + // } + // } + // case WATER_SLIME -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("water_slime_walk"); + // case ATTACK -> owner.getEntity().getEvents().trigger("water_slime_attack"); + // case DEATH -> { + // owner.getEntity().getEvents().trigger("water_slime_death"); + // owner.getEntity().getEvents().trigger("splitDeath"); + // } + // case DEFAULT -> owner.getEntity().getEvents().trigger("default"); + // } + // } + // case FIRE_WORM -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("fire_worm_walk"); + // case ATTACK -> owner.getEntity().getEvents().trigger("fire_worm_attack"); + // case DEATH -> owner.getEntity().getEvents().trigger("fire_worm_death"); + // case DEFAULT -> owner.getEntity().getEvents().trigger("default"); + // } + // } + // case DRAGON_KNIGHT -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("dragon_knight_run"); + // case ATTACK -> owner.getEntity().getEvents().trigger("dragon_knight_attack"); + // case DEATH -> owner.getEntity().getEvents().trigger("dragon_knight_death"); + // case DEFAULT -> owner.getEntity().getEvents().trigger("default"); + // } + // } + // case COAT -> { + // switch (state) { + // case RUN -> owner.getEntity().getEvents().trigger("coat_run"); + // case ATTACK -> owner.getEntity().getEvents().trigger("coat_attack"); + // case DEATH -> owner.getEntity().getEvents().trigger("coat_death"); + // case DEFAULT -> owner.getEntity().getEvents().trigger("default"); + // } + // } + // } + } + + /** + * changes state of the mob + * @param state state to change current state to + */ + private void changeState(State state) { + prevState = this.state; + this.state = state; + } + + /** + * detects if there's an enemy within range of 1 to the left of it + * @return if there's an enemy in front of the mob or not + */ + private boolean enemyDetected() { + // if there's an entity within x of - 1 of mob + Entity target = ServiceLocator.getEntityService().getEntityAtPosition( + mob.getPosition().x - MELEE_ATTACK_RANGE, mob.getPosition().y); + if (target == null) { + return false; + } + + // layer checking + HitboxComponent targetHitbox = target.getComponent(HitboxComponent.class); + if (targetHitbox == null) { + return false; + } + if (PhysicsLayer.contains(PhysicsLayer.HUMANS, targetHitbox.getLayer())) { + this.target = target; + return true; + } + return false; + } + + /** + * hits the target directly in front of it + */ + private void meleeAttack() { + // toggle melee flag off + meleeFlag = false; + + // check if target is null or not in range + if (target == null) { + return; + } + CombatStatsComponent targetCombatStats = target.getComponent(CombatStatsComponent.class); + targetCombatStats.hit(MELEE_DAMAGE); + Timer.schedule(new Timer.Task() { + @Override + public void run() { + if (!targetInRange) { + return; // stop if target in range + } + meleeFlag = true; // toggle melee flag off + } + }, MELEE_ATTACK_SPEED); + if(owner.getEntity().getComponent(ArcaneArcherAnimationController.class)!=null) + { + Entity newProjectile = ProjectileFactory.createPierceArrow(PhysicsLayer.HUMANS, new Vector2(-100, owner.getEntity().getPosition().y), new Vector2(2f,2f)); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y)); + newProjectile.setScale(1.3f, 1.3f); + ServiceLocator.getEntityService().register(newProjectile); + lastTimeAttacked = gameTime.getTime(); + } + } + + /** + * Shoots a fireball projectile and updates lastTimeAttacked + */ + private void rangeAttack() { + Vector2 destination = new Vector2(0, mob.getPosition().y); + Entity projectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.HUMANS, destination, + new Vector2(2, 2), ProjectileEffects.FIREBALL, false); + projectile.setPosition(mob.getPosition()); + projectile.setScale(-1f, 1f); + ServiceLocator.getEntityService().register(projectile); + lastTimeAttacked = gameTime.getTime(); + } + + /** + * @return priority of task + */ + @Override + public int getPriority() { + return PRIORITY; + } +} 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 335b2a7e7..92ea1027f 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,25 +1,26 @@ -package com.csse3200.game.components.tasks.MobTask; - -public enum MobType { - SKELETON(true), - WIZARD(false), - WATER_QUEEN(false), - WATER_SLIME(true), - FIRE_WORM(false), - DRAGON_KNIGHT(true), - COAT(true), - NIGHT_BORNE(true), - ARCANE_ARCHER(false), - ROCKY(true), - NECROMANCER(true), - FIREWIZARD(true); - private boolean isMelee; - - MobType(boolean melee) { - this.isMelee = melee; - } - - public boolean isMelee() { - return isMelee; - } -} +package com.csse3200.game.components.tasks.MobTask; + +public enum MobType { + SKELETON(true), + WIZARD(false), + WATER_QUEEN(false), + WATER_SLIME(true), + FIRE_WORM(false), + DRAGON_KNIGHT(true), + COAT(true), + NIGHT_BORNE(true), + ARCANE_ARCHER(true), + ROCKY(true), + NECROMANCER(true), + FIREWIZARD(true), + XENO(true); + private boolean isMelee; + + MobType(boolean melee) { + this.isMelee = melee; + } + + public boolean isMelee() { + return isMelee; + } +} 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 e652ea84e..cafc083ed 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 @@ -11,6 +11,8 @@ import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.npc.WizardAnimationController; /** * Wander around by moving a random position within a range of the starting position. Wait a little @@ -19,17 +21,22 @@ 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(float waitTime) { + public MobWanderTask(Vector2 wanderRange, float waitTime) { + this.wanderRange = wanderRange; this.waitTime = waitTime; } @@ -52,50 +59,50 @@ public void start() { movementTask.start(); currentTask = movementTask; - - // this.owner.getEntity().getEvents().trigger("wanderStart"); } @Override public void update() { - - // Update the position of the mob - 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 && Boolean.TRUE.equals(owner.getEntity().getComponent(CombatStatsComponent.class).isDead())) { - this.owner.getEntity().getEvents().trigger("dieStart"); - currentTask.stop(); - isDead = true; - ServiceLocator.getWaveService().updateEnemyCount(); - } - - // Check if the mob has finished death animation - 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); - ServiceLocator.getEntityService().register(scrap); - - // Delete the mob and update count for number of mobs remaining in the wave - owner.getEntity().setFlagForDelete(true); - - } - // If not dead, do normal things... - else if (!isDead) { - - if (currentTask.getStatus() != Status.ACTIVE) { - if (currentTask == movementTask) { - startWaiting(); - } else { - startMoving(); - } - } - currentTask.update(); - } + if(!owner.getEntity().getComponent(AITaskComponent.class).freezed) + { + // Update the position of the mob + 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()) { + this.owner.getEntity().getEvents().trigger("dieStart"); + currentTask.stop(); + isDead = true; + ServiceLocator.getWaveService().updateEnemyCount(); + } + + // Check if the mob has finished death animation + 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); + ServiceLocator.getEntityService().register(scrap); + + // Delete the mob and update count for number of mobs remaining in the wave + owner.getEntity().setFlagForDelete(true); + + } + // If not dead, do normal things... + else if (!isDead) { + + if (currentTask.getStatus() != Status.ACTIVE) { + if (currentTask == movementTask) { + startWaiting(); + } else { + startMoving(); + } + } + currentTask.update(); + } + } } private void startWaiting() { 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 53e7e1af7..2f0c8d7b5 100644 --- a/source/core/src/main/com/csse3200/game/entities/PredefinedWeapons.java +++ b/source/core/src/main/com/csse3200/game/entities/PredefinedWeapons.java @@ -13,9 +13,15 @@ private PredefinedWeapons() { 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); + 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 final ProjectileConfig FIREBALL = new ProjectileConfig(); public static final 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/factories/NPCFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java index e8038c978..a31a49fe0 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 @@ -1,668 +1,702 @@ -package com.csse3200.game.entities.factories; - -import com.badlogic.gdx.graphics.g2d.Animation; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -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.*; -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.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; -import com.csse3200.game.entities.configs.*; -import com.csse3200.game.files.FileLoader; -import com.csse3200.game.physics.PhysicsLayer; -import com.csse3200.game.physics.PhysicsUtils; -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; -import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.rendering.TextureRenderComponent; -import com.csse3200.game.services.ServiceLocator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Currency; - -/** - * Factory to create non-playable character (NPC) entities with predefined components. - * - *

Each NPC entity type should have a creation method that returns a corresponding entity. - * Predefined entity properties can be loaded from configs stored as json files which are defined in - * "NPCConfigs". - * - *

If needed, this factory can be separated into more specific factories for entities with - * similar characteristics. - */ -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. - * - * @return entity - */ - public static Entity createGhost() { - Entity ghost = createMeleeBaseNPC(); - BaseEntityConfig config = configs.ghost; - /** - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/ghost.atlas", TextureAtlas.class)); - animator.addAnimation("angry_float", 0.1f, Animation.PlayMode.LOOP); - animator.addAnimation("float", 0.1f, Animation.PlayMode.LOOP); - **/ - ghost - .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) - .addComponent(new TextureRenderComponent("images/mobs/satyr.png")); - - ghost.getComponent(TextureRenderComponent.class).scaleEntity(); - - return ghost; - } - - /** - * Creates a ghost king entity. - * - * @return entity - */ - public static Entity createGhostKing() { - Entity ghostKing = createMeleeBaseNPC(); - GhostKingConfig config = configs.ghostKing; - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/ghostKing.atlas", TextureAtlas.class)); - animator.addAnimation("float", 0.2f, Animation.PlayMode.LOOP); - animator.addAnimation("angry_float", 0.2f, Animation.PlayMode.LOOP); - - ghostKing - .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) - .addComponent(animator) - .addComponent(new GhostAnimationController()); - - ghostKing.getComponent(AnimationRenderComponent.class).scaleEntity(); - return ghostKing; - } - - /** - * Creates a fire worm entity. - * - * @return entity - */ - public static Entity createSkeleton(int health) { - Entity skeleton = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/skeleton.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.SKELETON)); - - skeleton - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new SkeletonAnimationController()) - .addComponent(aiTaskComponent); - - skeleton.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); - skeleton.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return skeleton; - } - - /** - * Creates a wizard entity. - * - * @return entity - */ - public static Entity createWizard(int health) { - Entity wizard = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/wizard.atlas", TextureAtlas.class)); - 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); - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.WIZARD)); - - wizard - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new WizardAnimationController()) - .addComponent(aiTaskComponent); - - wizard.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); - wizard.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return wizard; - } - /** - * Creates a water queen entity. - * - * @return entity - */ - public static Entity createWaterQueen(int health) { - Entity waterQueen = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/water_queen.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.WATER_QUEEN)); - - waterQueen - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new WaterQueenAnimationController()) - .addComponent(aiTaskComponent); - - waterQueen.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); - waterQueen.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return waterQueen; - } - /** - * Creates a water slime entity. - * - * @return entity - */ - public static Entity createBaseWaterSlime(int health) { - Entity waterSlime = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/water_slime.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.WATER_SLIME)); - - waterSlime - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new WaterSlimeAnimationController()) - .addComponent(aiTaskComponent); - - waterSlime.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); - waterSlime.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return waterSlime; - } - /** - * Creates a fire worm entity. - * - * @return entity - */ - public static Entity createFireWorm(int health) { - Entity fireWorm = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/fire_worm.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.FIRE_WORM)); - - fireWorm - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new FireWormAnimationController()) - .addComponent(aiTaskComponent); - - fireWorm.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); - fireWorm.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return fireWorm; - } - /** - * Creates a dragon Knight entity - * - * @return entity - */ - public static Entity createDragonKnight(int health) { - Entity dragonKnight = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/dragon_knight.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.DRAGON_KNIGHT)); - - dragonKnight - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new DragonKnightAnimationController()) - .addComponent(aiTaskComponent); - - dragonKnight.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); - dragonKnight.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return dragonKnight; - } - - public static Entity createCoat(int health) { - Entity coat = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/coat.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.COAT)); - - coat - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new CoatAnimationController()) - .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 createNightBorne(int health) { - Entity coat = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/night_borne.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.NIGHT_BORNE)); - - coat - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new NightBorneAnimationController()) - .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 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<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/arcane_archer.atlas", TextureAtlas.class)); - animator.addAnimation("arcane_archer_run", 0.1f, Animation.PlayMode.LOOP); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.ARCANE_ARCHER)); - - coat - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new ArcaneArcherAnimationController()) - .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 createGregRangeMob(int health) { - Entity fireWorm = createBaseNPC(); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/fire_worm.atlas", TextureAtlas.class)); - 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); - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new MobTask(MobType.FIRE_WORM)); - - fireWorm - .addComponent(new CombatStatsComponent(health, 0, drops)) - .addComponent(animator) - .addComponent(new FireWormAnimationController()) - .addComponent(aiTaskComponent); - - fireWorm.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); - fireWorm.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return fireWorm; - } - - - /** - * Creates a xeno grunt entity. - * - * @return entity - */ - public static Entity createXenoGrunt(int health) { - Entity xenoGrunt = createMeleeBaseNPC(); - BaseEnemyConfig config = configs.xenoGrunt; - ArrayList melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.SWORD, PredefinedWeapons.KICK)); - // tester projectiles - ArrayList projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.FIREBALL, PredefinedWeapons.FROSTBALL)); - ArrayList drops = new ArrayList<>(); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService().getAsset("images/mobs/xenoGrunt.atlas", TextureAtlas.class)); - animator.addAnimation("xeno_run", 0.1f, Animation.PlayMode.LOOP); - animator.addAnimation("xeno_hurt", 0.1f, Animation.PlayMode.LOOP); - animator.addAnimation("xeno_shoot", 0.1f); - 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); - xenoGrunt - .addComponent(new CombatStatsComponent(health, config.baseAttack, drops, melee, projectiles)) - .addComponent(animator) - .addComponent(new XenoAnimationController()); - - xenoGrunt.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); - xenoGrunt.getComponent(AnimationRenderComponent.class).scaleEntity(); - - return xenoGrunt; - } - - public static Entity createBaseNPC() { - Entity npc = - new Entity() - .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); - return npc; - } - - /** - * Creates a generic NPC to be used as a base entity by more specific NPC creation methods. - * - * @return entity - */ - public static Entity createMeleeBaseNPC() { - AITaskComponent aiComponent = - new AITaskComponent() - .addTask(new MobWanderTask(2f)) - .addTask(new MobMeleeAttackTask(2)); - - Entity npc = - new Entity() - .addComponent(new PhysicsComponent()) - .addComponent(new PhysicsMovementComponent()) - .addComponent(new ColliderComponent()) - .addComponent(new HitboxComponent().setLayer(PhysicsLayer.XENO)) - .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS)) - .addComponent(aiComponent); - PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f); - return npc; - } - /** - * Creates a generic NPC to be used as a base entity by more specific NPC creation methods. - * - * @return entity - */ - public static Entity createRangedBaseNPC() { - AITaskComponent aiComponent = - new AITaskComponent() - .addTask(new MobWanderTask(2f)) - .addTask(new MobRangedAttackTask(2)); - - Entity npc = - new Entity() - .addComponent(new PhysicsComponent()) - .addComponent(new PhysicsMovementComponent()) - .addComponent(new ColliderComponent()) - .addComponent(new HitboxComponent().setLayer(PhysicsLayer.XENO)) - .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS)) - .addComponent(aiComponent); - PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f); - return npc; - } - - private NPCFactory() { - throw new IllegalStateException("Instantiating static util class"); - } - - // * COW'S TESTING ARENA DONT TOUCH - 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(MobType.WATER_SLIME, 7, 0.5f)) - .addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f)); - - // * TEMPORARY TESTING FOR PROJECTILE DODGING - splitXenoGrunt.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5)); - // splitXenoGrunt.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector2(2f, 2f), 2f, 5)); - return splitXenoGrunt; - } - - /** - * Create Splitting water slime - * - * @require - Entity to have a "splitDeath" - * @return Splitting water slime - */ - public static Entity createSplittingWaterSlime(int health) { - return createBaseWaterSlime(health).addComponent(new SplitMoblings(MobType.WATER_SLIME, 7, 0.5f)); - } - - /** - * 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 Splitting Night Borne - */ - public static Entity createSplittingNightBorne(int health) { - return createNightBorne(health).addComponent(new SplitMoblings(MobType.NIGHT_BORNE, 7, 0.5f)); - } - - /** - * Create a dodging Dragon Knight - * - * @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).getTask(MobTask.class).setDodge(true); - PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f); - dodgeKnight.setScale(0.3f, 0.7f); - - return dodgeKnight; - } - - /** - * Create a dodging Arcane Archer - * - * @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).getTask(MobTask.class).setDodge(true); - PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f); - dodgeKnight.setScale(0.3f, 0.7f); - - return dodgeKnight; - } - - /** - * Creates a wizard that can deflect bullets - * @return Deflecting wizard - */ - public static Entity createDeflectWizard(int health) { - return createWizard(health).addComponent(new DeflectingComponent( - PhysicsLayer.PROJECTILE, PhysicsLayer.TOWER, 10)); - } - - /** - * 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)); - } -} - - +package com.csse3200.game.entities.factories; + +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.math.Vector2; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.CombatStatsComponent; +import com.csse3200.game.components.TouchAttackComponent; +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.entities.Entity; +import com.csse3200.game.entities.Melee; +import com.csse3200.game.entities.PredefinedWeapons; +import com.csse3200.game.entities.configs.*; +import com.csse3200.game.files.FileLoader; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.PhysicsUtils; +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; +import com.csse3200.game.rendering.AnimationRenderComponent; +import com.csse3200.game.rendering.TextureRenderComponent; +import com.csse3200.game.services.ServiceLocator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Currency; + +/** + * Factory to create non-playable character (NPC) entities with predefined components. + * + *

Each NPC entity type should have a creation method that returns a corresponding entity. + * Predefined entity properties can be loaded from configs stored as json files which are defined in + * "NPCConfigs". + * + *

If needed, this factory can be separated into more specific factories for entities with + * similar characteristics. + */ +public class NPCFactory { + private static final String DEFAULT = "default"; + private static final NPCConfigs configs = + FileLoader.readClass(NPCConfigs.class, "configs/NPCs.json"); + + /** + * Creates a ghost entity. + * + * @return entity + */ + public static Entity createGhost() { + Entity ghost = createMeleeBaseNPC(); + BaseEntityConfig config = configs.ghost; + /** + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/ghost.atlas", TextureAtlas.class)); + animator.addAnimation("angry_float", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("float", 0.1f, Animation.PlayMode.LOOP); + **/ + ghost + .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) + // .addComponent(animator) + .addComponent(new TextureRenderComponent("images/mobs/satyr.png")); + // .addComponent(new GhostAnimationController()); + + ghost.getComponent(TextureRenderComponent.class).scaleEntity(); + + return ghost; + } + + /** + * Creates a ghost king entity. + * + * @return entity + */ + public static Entity createGhostKing() { + Entity ghostKing = createMeleeBaseNPC(); + GhostKingConfig config = configs.ghostKing; + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/ghostKing.atlas", TextureAtlas.class)); + animator.addAnimation("float", 0.2f, Animation.PlayMode.LOOP); + animator.addAnimation("angry_float", 0.2f, Animation.PlayMode.LOOP); + + ghostKing + .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) + .addComponent(animator) + .addComponent(new GhostAnimationController()); + + ghostKing.getComponent(AnimationRenderComponent.class).scaleEntity(); + return ghostKing; + } + + /** + * Creates a fire worm entity. + * + * @return entity + */ +// public static Entity createSkeleton(int health) { +// Entity skeleton = createBaseNPC(int health); + public static Entity createSkeleton(int health) { + Entity skeleton = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/skeleton.atlas", TextureAtlas.class)); + animator.addAnimation("skeleton_walk", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("skeleton_attack", 0.1f); + animator.addAnimation("skeleton_death", 0.1f); + animator.addAnimation("skeleton_freeze", 0.1f); + animator.addAnimation("default", 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.SKELETON)); + + skeleton + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new SkeletonAnimationController()) + .addComponent(aiTaskComponent); + + skeleton.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); + skeleton.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return skeleton; + } + + /** + * Creates a wizard entity. + * + * @return entity + */ + public static Entity createWizard(int health) { + Entity wizard = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/wizard.atlas", TextureAtlas.class)); + animator.addAnimation("wizard_run", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("wizard_attack", 0.1f); + animator.addAnimation("wizard_death", 0.1f); + animator.addAnimation("wizard_freeze", 0.1f); + animator.addAnimation("default", 0.1f); + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.WIZARD)); + + wizard + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new WizardAnimationController()) + .addComponent(aiTaskComponent); + + wizard.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); + wizard.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return wizard; + } + /** + * Creates a water queen entity. + * + * @return entity + */ + public static Entity createWaterQueen(int health) { + Entity waterQueen = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/water_queen.atlas", TextureAtlas.class)); + 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("water_queen_freeze", 0.1f); + animator.addAnimation("default", 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.WATER_QUEEN)); + + waterQueen + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new WaterQueenAnimationController()) + .addComponent(aiTaskComponent); + + waterQueen.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); + waterQueen.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return waterQueen; + } + /** + * Creates a water slime entity. + * + * @return entity + */ + public static Entity createBaseWaterSlime(int health) { + Entity waterSlime = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/water_slime.atlas", TextureAtlas.class)); + 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("water_slime_freeze", 0.2f); + animator.addAnimation("default", 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.WATER_SLIME)); + + waterSlime + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new WaterSlimeAnimationController()) + .addComponent(aiTaskComponent); + + waterSlime.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); + waterSlime.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return waterSlime; + } + /** + * Creates a fire worm entity. + * + * @return entity + */ + public static Entity createFireWorm(int health) { + Entity fireWorm = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/fire_worm.atlas", TextureAtlas.class)); + 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("fire_worm_freeze", 0.1f); + animator.addAnimation("default", 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.FIRE_WORM)); + + fireWorm + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new FireWormAnimationController()) + .addComponent(aiTaskComponent); + + fireWorm.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); + fireWorm.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return fireWorm; + } + /** + * Creates a dragon Knight entity + * + * @return entity + */ + public static Entity createDragonKnight(int health) { + Entity dragonKnight = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/dragon_knight.atlas", TextureAtlas.class)); + 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("dragon_knight_freeze", 0.1f); + animator.addAnimation("default", 0.1f); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.DRAGON_KNIGHT)); + + dragonKnight + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new DragonKnightAnimationController()) + .addComponent(aiTaskComponent); + + dragonKnight.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); + dragonKnight.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return dragonKnight; + } + + public static Entity createCoat(int health) { + Entity coat = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/coat.atlas", TextureAtlas.class)); + 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); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.COAT)); + + coat + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new CoatAnimationController()) + .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 createNightBorne(int health) { + Entity coat = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/night_borne.atlas", TextureAtlas.class)); + 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); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.NIGHT_BORNE)); + + coat + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new NightBorneAnimationController()) + .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 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<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/arcane_archer.atlas", TextureAtlas.class)); + animator.addAnimation("arcane_archer_run", 0.1f, Animation.PlayMode.LOOP); + 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); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.ARCANE_ARCHER)); + + coat + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new ArcaneArcherAnimationController()) + .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 createGregRangeMob(int health) { + Entity fireWorm = createBaseNPC(); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/fire_worm.atlas", TextureAtlas.class)); + 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); + + AITaskComponent aiTaskComponent = new AITaskComponent() + .addTask(new MobTask(MobType.FIRE_WORM)); + + fireWorm + .addComponent(new CombatStatsComponent(health, 0, drops)) + .addComponent(animator) + .addComponent(new FireWormAnimationController()) + .addComponent(aiTaskComponent); + + fireWorm.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.CENTER); + fireWorm.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return fireWorm; + } + + + /** + * Creates a xeno grunt entity. + * + * @return entity + */ + public static Entity createXenoGrunt(int health) { + Entity xenoGrunt = createMeleeBaseNPC(); + BaseEnemyConfig config = configs.xenoGrunt; + ArrayList melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick)); + // tester projectiles + ArrayList projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall)); + ArrayList drops = new ArrayList<>(); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService().getAsset("images/mobs/xenoGrunt.atlas", TextureAtlas.class)); + animator.addAnimation("xeno_run", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("xeno_hurt", 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("xeno_shoot", 0.1f); + animator.addAnimation("xeno_melee_1", 0.1f); + animator.addAnimation("xeno_melee_2", 0.1f); + animator.addAnimation("xeno_die", 0.1f); + animator.addAnimation("xeno_freeze", 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)) + .addComponent(animator) + .addComponent(new XenoAnimationController()); + + xenoGrunt.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM); + xenoGrunt.getComponent(AnimationRenderComponent.class).scaleEntity(); + + return xenoGrunt; + } + + public static Entity createBaseNPC() { + Entity npc = + new Entity() + .addComponent(new PhysicsComponent()) + .addComponent(new PhysicsMovementComponent()) + .addComponent(new ColliderComponent()) + .addComponent(new HitboxComponent().setLayer(PhysicsLayer.NPC)) + .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS)); + PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f); + return npc; + } + + /** + * Creates a generic NPC to be used as a base entity by more specific NPC creation methods. + * + * @return entity + */ + public static Entity createMeleeBaseNPC() { + AITaskComponent aiComponent = + new AITaskComponent() + .addTask(new MobWanderTask(new Vector2(2f, 2f), 2f)) + .addTask(new MobMeleeAttackTask(2, 2f)); + // .addTask(new MobAttackTask(2, 2f)); + // .addTask(new MeleeMobTask(new Vector2(2f, 2f), 2f)); + + // .addTask(new MobAttackTask(2, 40)); + Entity npc = + new Entity() + .addComponent(new PhysicsComponent()) + .addComponent(new PhysicsMovementComponent()) + .addComponent(new ColliderComponent()) + .addComponent(new HitboxComponent().setLayer(PhysicsLayer.XENO)) + .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS)) + .addComponent(aiComponent); + PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f); + return npc; + } + /** + * Creates a generic NPC to be used as a base entity by more specific NPC creation methods. + * + * @return entity + */ + public static Entity createRangedBaseNPC() { + AITaskComponent aiComponent = + new AITaskComponent() + .addTask(new MobWanderTask(new Vector2(2f, 2f), 2f)) + // .addTask(new MobAttackTask(2, 2f)); + .addTask(new MobRangedAttackTask(2, 2f)); + // .addTask(new MeleeMobTask(new Vector2(2f, 2f), 2f)); + + // .addTask(new MobAttackTask(2, 40)); + Entity npc = + new Entity() + .addComponent(new PhysicsComponent()) + .addComponent(new PhysicsMovementComponent()) + .addComponent(new ColliderComponent()) + .addComponent(new HitboxComponent().setLayer(PhysicsLayer.XENO)) + .addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS)) + .addComponent(aiComponent); + PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f); + return npc; + } + + private NPCFactory() { + throw new IllegalStateException("Instantiating static util class"); + } + + // * COW'S TESTING ARENA DONT TOUCH + 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(MobType.XENO, 7, 0.5f)) + .addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f)); + + // * TEMPORARY TESTING FOR PROJECTILE DODGING + splitXenoGrunt.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5)); + // splitXenoGrunt.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector2(2f, 2f), 2f, 5)); + return splitXenoGrunt; + } + + /** + * Create Splitting water slime + * + * @require Entity to have a "splitDeath" + * @return + */ + public static Entity createSplittingWaterSlime(int health) { + Entity splitWaterSlime = createBaseWaterSlime(health) + + .addComponent(new SplitMoblings(MobType.WATER_SLIME, 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 + */ + public static Entity createSplittingNightBorne(int health) { + Entity splitWaterSlime = createNightBorne(health) + + .addComponent(new SplitMoblings(MobType.NIGHT_BORNE, 7, 0.5f)); + + return splitWaterSlime; + } + + /** + * Create a dodging Dragon Knight + * + * @return + */ + 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)); + PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f); + dodgeKnight.setScale(0.3f, 0.7f); + + return dodgeKnight; + } + + /** + * Create a dodging Arcane Archer + * + * @return + */ + 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)); + PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f); + dodgeKnight.setScale(0.3f, 0.7f); + + return dodgeKnight; + } + +// public static Entity createDeflectXenoGrunt(int health) { +// Entity deflectXenoGrunt = createXenoGrunt(health); +// deflectXenoGrunt.addComponent(new DeflectingComponent( + /** + * Creates a wizard that can deflect bullets + * @return + */ + public static Entity createDeflectWizard(int health) { + Entity deflectWizard = createWizard(health); + deflectWizard.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/ProjectileFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java index ce160b65b..95c1d7ec8 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java @@ -1,373 +1,419 @@ -package com.csse3200.game.entities.factories; - -import com.badlogic.gdx.graphics.g2d.Animation; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.csse3200.game.components.*; -import com.csse3200.game.components.MobProjectileAnimationController; -import com.csse3200.game.components.tasks.TrajectTask; -import com.csse3200.game.ai.tasks.AITaskComponent; -import com.csse3200.game.components.projectile.*; -import com.csse3200.game.entities.configs.BaseEntityConfig; -import com.csse3200.game.entities.configs.NPCConfigs; -import com.csse3200.game.files.FileLoader; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.services.ServiceLocator; -import com.csse3200.game.physics.PhysicsLayer; -import com.csse3200.game.physics.PhysicsUtils; -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; -import com.badlogic.gdx.math.Vector2; - -/** - * Responsible for creating projectiles within the game. - */ -public class ProjectileFactory { - /** - * Animation constants - */ - private static final String BASE_PROJECTILE_ATLAS = "images/projectiles/basic_projectile.atlas"; - private static final String START_ANIM = "projectile"; - private static final String FINAL_ANIM = "projectileFinal"; - private static final float START_SPEED = 0.1f; - private static final float FINAL_SPEED = 0.1f; - - private static final NPCConfigs configs = - FileLoader.readClass(NPCConfigs.class, "configs/NPCs.json"); - - /** - * Creates a single-targeting projectile with specified effect - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @param effect Specified effect from the ProjectileEffects enums - * @return Returns a new single-target projectile entity - */ - public static Entity createEffectProjectile(short targetLayer, Vector2 destination, Vector2 speed, ProjectileEffects effect, boolean aoe) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - switch (effect) { - case FIREBALL -> { - projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.FIREBALL, aoe)); - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset(BASE_PROJECTILE_ATLAS, TextureAtlas.class)); - animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); - animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); - - projectile - .addComponent(animator) - .addComponent(new ProjectileAnimationController()); - } - case BURN -> { - projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.BURN, aoe)); - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/burn_effect.atlas", TextureAtlas.class)); - animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); - animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); - - projectile - .addComponent(animator) - .addComponent(new BurnEffectProjectileAnimationController()); - } - case SLOW -> { - projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.SLOW, aoe)); - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/snow_ball.atlas", TextureAtlas.class)); - animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); - animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); - - projectile - .addComponent(animator) - .addComponent(new SnowBallProjectileAnimationController()); - // * TEMPORARY - // .addComponent(new DeleteOnMapEdgeComponent()); - // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); - - return projectile; - } - case STUN -> { - projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.STUN, aoe)); - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/stun_effect.atlas", TextureAtlas.class)); - animator.addAnimation(START_ANIM, 0.1f, Animation.PlayMode.LOOP); - - projectile - .addComponent(animator) - .addComponent(new StunEffectProjectileAnimationController()); - } - } - return projectile; - } - - /** - * Create a pierce fireball. - * Pierce fireball is basically a fireball that does damage but won't self destruct on hit. - */ - public static Entity createPierceFireBall(short targetLayer, Vector2 destination, Vector2 speed) { - Entity fireBall = createPierceBallAnim(targetLayer, destination, speed); - fireBall.getComponent(TouchAttackComponent.class).setDisposeOnHit(false); - fireBall.getComponent(TouchAttackComponent.class).setKnockBack(0f); - - return fireBall; - } - - /** - * Create a ricochet fireball. - * Ricochet fireball bounces off specified targets while applying intended effects i.e. damage - */ - public static Entity createRicochetFireball(short targetLayer, Vector2 destination, Vector2 speed, int bounceCount) { - Entity fireBall = createFireBall(targetLayer, destination, speed); - fireBall - .addComponent(new RicochetComponent(targetLayer, bounceCount)); - - setColliderSize(fireBall, (float) 0.1, (float) 0.1); - - return fireBall; - } - - public static Entity createSplitFireWorksFireball(short targetLayer, Vector2 destination, Vector2 speed, int amount) { - Entity fireBall = createFireBall(targetLayer, destination, speed); - fireBall - .addComponent(new SplitFireworksComponent(targetLayer, amount)); - - return fireBall; - } - - /** - * Creates a fireball Entity. - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @return Returns a new fireball projectile entity. - */ - public static Entity createFireBall(short targetLayer, Vector2 destination, Vector2 speed) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset(BASE_PROJECTILE_ATLAS, TextureAtlas.class)); - animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); - animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); - - projectile - .addComponent(animator) - .addComponent(new ProjectileAnimationController()); - // * TEMPORARY - // .addComponent(new DeleteOnMapEdgeComponent()); - // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); - - return projectile; - } - - /** - * Creates new animation and fireballs for SplitFireworkComponent. - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @return Returns a new fireball projectile entity. - */ - public static Entity createFireworks(short targetLayer, Vector2 destination, Vector2 speed) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/firework_anim.atlas", TextureAtlas.class)); - animator.addAnimation(START_ANIM, 0.2f, Animation.PlayMode.LOOP); - projectile - .addComponent(animator) - .addComponent(new FireworkAnimationController()); - - return projectile; - } - - public static Entity createPierceBallAnim(short targetLayer, Vector2 destination, Vector2 speed) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/pierce_anim.atlas", TextureAtlas.class)); - animator.addAnimation(START_ANIM, 0.05f, Animation.PlayMode.LOOP); - projectile - .addComponent(animator) - .addComponent(new PierceProjectileAnimationController()); - - return projectile; - } - - - /** - * Creates a engineer bullet - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @return Returns a new fireball projectile entity. - */ - public static Entity createEngineerBullet(short targetLayer, Vector2 destination, Vector2 speed) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/engineer_projectile.atlas", TextureAtlas.class)); - animator.addAnimation("bullet", START_SPEED, Animation.PlayMode.NORMAL); - animator.addAnimation("bulletFinal", FINAL_SPEED, Animation.PlayMode.NORMAL); - - projectile - .addComponent(animator) - .addComponent(new EngineerBulletsAnimationController()); - // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); - - return projectile; - } - - /** - * Creates a projectile specifically for mobs to shoot - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @return Returns a new fireball projectile entity. - */ - public static Entity createMobBall(short targetLayer, Vector2 destination, Vector2 speed) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/mobProjectile.atlas", TextureAtlas.class)); - - animator.addAnimation("rotate", 0.15f, Animation.PlayMode.LOOP); - - projectile - .addComponent(animator) - .addComponent(new MobProjectileAnimationController()); - // * TEMPORARY - // .addComponent(new DeleteOnMapEdgeComponent()); - - projectile - .getComponent(AnimationRenderComponent.class).scaleEntity(); - - - - return projectile; - } - public static Entity createBossBall(short targetLayer, Vector2 destination, Vector2 speed) { // function added by team 7 for Boss projectile - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/bossProjectile.atlas", TextureAtlas.class)); - - animator.addAnimation("rotate", 0.15f, Animation.PlayMode.LOOP); - - projectile - .addComponent(animator) - .addComponent(new BossProjectileAnimationController()); - - projectile - .getComponent(AnimationRenderComponent.class).scaleEntity(); - projectile.setScale(2,2); - - return projectile; - } - - /** - * Creates a projectile to be used by the MobBoss - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @return Returns a new fireball projectile entity. - */ - public static Entity createMobBossBall(short targetLayer, Vector2 destination, Vector2 speed) { - Entity projectile = createBaseProjectile(targetLayer, destination, speed); - - AnimationRenderComponent animator = - new AnimationRenderComponent( - ServiceLocator.getResourceService() - .getAsset("images/projectiles/mobBoss_projectile.atlas", TextureAtlas.class)); - animator.addAnimation("mob_boss", 0.17f, Animation.PlayMode.NORMAL); - animator.addAnimation("mob_bossFinal", 0.17f, Animation.PlayMode.NORMAL); - - - projectile - .addComponent(animator) - .addComponent(new MobBossProjectAnimController()); - - projectile - .getComponent(AnimationRenderComponent.class).scaleEntity(); - - return projectile; - } - - /** - * Creates a generic projectile entity that can be used for multiple types of * projectiles. - * - * @param targetLayer The enemy layer that the projectile collides with. - * @param destination The destination the projectile heads towards. - * @param speed The speed of the projectile. - * @return Returns a generic projectile entity. - */ - public static Entity createBaseProjectile(short targetLayer, Vector2 - destination, Vector2 speed) { - BaseEntityConfig config = configs.fireBall; - - AITaskComponent aiComponent = - new AITaskComponent() - .addTask(new TrajectTask(destination)); - - Entity projectile = new Entity() - .addComponent(new PhysicsComponent()) - .addComponent(new PhysicsMovementComponent()) - .addComponent(new HitboxComponent().setLayer(PhysicsLayer.PROJECTILE)) - .addComponent(aiComponent) - .addComponent(new ColliderComponent().setSensor(true)) - // This is the component that allows the projectile to damage a - // specified target. - // Original knockback value: 1.5f - .addComponent(new TouchAttackComponent(targetLayer, 1.5f, true)) - .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) - // *TEMPORARY - .addComponent(new DeleteOnMapEdgeComponent()); - - projectile - .getComponent(PhysicsMovementComponent.class).setSpeed(speed); - - return projectile; - } - - /** - * Sets the projectile collider so that the collider size can be altered for flexibility. - * @param projectile Projectile's size collider to be scaled upon. - * @param x Horizontal scaling of the collider in respect ot the size of the entity - * @param y Veritcal scaling of the collider in respect to the size of the entity - */ - public static void setColliderSize(Entity projectile, float x, float y) { - PhysicsUtils.setScaledCollider(projectile, x, y); - } - - /** - * Prevents the creation of a Projectile Factory entity being created - */ - private ProjectileFactory() { - throw new IllegalStateException("Instantiating static util class"); - } -} +package com.csse3200.game.entities.factories; + +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.csse3200.game.components.*; +import com.csse3200.game.components.MobProjectileAnimationController; +import com.csse3200.game.components.tasks.TrajectTask; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.components.projectile.*; +import com.csse3200.game.entities.configs.BaseEntityConfig; +import com.csse3200.game.entities.configs.NPCConfigs; +import com.csse3200.game.files.FileLoader; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.rendering.AnimationRenderComponent; +import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.PhysicsUtils; +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; +import com.badlogic.gdx.math.Vector2; + +/** + * Responsible for creating projectiles within the game. + */ +public class ProjectileFactory { + /** + * Animation constants + */ + private static final String BASE_PROJECTILE_ATLAS = "images/projectiles/basic_projectile.atlas"; + private static final String START_ANIM = "projectile"; + private static final String FINAL_ANIM = "projectileFinal"; + private static final float START_SPEED = 0.1f; + private static final float FINAL_SPEED = 0.1f; + + private static final NPCConfigs configs = + FileLoader.readClass(NPCConfigs.class, "configs/NPCs.json"); + + /** + * Creates a single-targeting projectile with specified effect + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @param effect Specified effect from the ProjectileEffects enums + * @return Returns a new single-target projectile entity + */ + public static Entity createEffectProjectile(short targetLayer, Vector2 destination, Vector2 speed, ProjectileEffects effect, boolean aoe) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + switch (effect) { + case FIREBALL -> { + projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.FIREBALL, aoe)); + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset(BASE_PROJECTILE_ATLAS, TextureAtlas.class)); + animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("projectileCollide", START_SPEED, Animation.PlayMode.NORMAL); + + projectile + .addComponent(animator) + .addComponent(new ProjectileAnimationController(targetLayer)); + } + case BURN -> { + projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.BURN, aoe)); + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/burn_effect.atlas", TextureAtlas.class)); + animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("explosion", 0.1f, Animation.PlayMode.NORMAL); + + projectile + .addComponent(animator) + .addComponent(new BurnEffectProjectileAnimationController(targetLayer)); + } + case SLOW -> { + projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.SLOW, aoe)); + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/snow_ball.atlas", TextureAtlas.class)); + animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("collision", START_SPEED, Animation.PlayMode.NORMAL); + + projectile + .addComponent(animator) + .addComponent(new SnowBallProjectileAnimationController(targetLayer)); + // * TEMPORARY + // .addComponent(new DeleteOnMapEdgeComponent()); + // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); + + return projectile; + } + case STUN -> { + projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.STUN, aoe)); + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/stun_effect.atlas", TextureAtlas.class)); + animator.addAnimation(START_ANIM, 0.1f, Animation.PlayMode.LOOP); + animator.addAnimation("stun", 0.3f, Animation.PlayMode.LOOP); + + projectile + .addComponent(animator) + .addComponent(new StunEffectProjectileAnimationController(targetLayer)); + } + } + return projectile; + } + + public static Entity createComboSnowBall(short targetLayer, Vector2 destination, Vector2 speed, boolean aoe) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + projectile.addComponent(new EffectsComponent(targetLayer, 3, ProjectileEffects.SLOW, aoe)); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/mobBoss_projectile.atlas", TextureAtlas.class), + ServiceLocator.getResourceService() + .getAsset("images/projectiles/snow_ball.atlas", TextureAtlas.class)); + animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("collision", START_SPEED, Animation.PlayMode.NORMAL); + + projectile + .addComponent(animator) + .addComponent(new SnowBallProjectileAnimationController(targetLayer)); + // * TEMPORARY + // .addComponent(new DeleteOnMapEdgeComponent()); + // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); + + return projectile; + } + + /** + * Create a pierce fireball. + * Pierce fireball is basically a fireball that does damage but won't self destruct on hit. + */ + public static Entity createPierceFireBall(short targetLayer, Vector2 destination, Vector2 speed) { + Entity fireBall = createPierceBallAnim(targetLayer, destination, speed); + fireBall.getComponent(TouchAttackComponent.class).setDisposeOnHit(false); + fireBall.getComponent(TouchAttackComponent.class).setKnockBack(0f); + + return fireBall; + } + + public static Entity createPierceArrow(short targetLayer, Vector2 destination, Vector2 speed) { + Entity arrow = createBaseProjectile(targetLayer, destination, speed); + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/arrow.atlas", TextureAtlas.class)); + animator.addAnimation("arrow", 0.1f, Animation.PlayMode.LOOP); + arrow + .addComponent(animator) + .addComponent(new PierceArrowAnimationController()); + arrow.getComponent(TouchAttackComponent.class).setDisposeOnHit(false); + arrow.getComponent(TouchAttackComponent.class).setKnockBack(0f); + + return arrow; + } + + /** + * Create a ricochet fireball. + * Ricochet fireball bounces off specified targets while applying intended effects i.e. damage + */ + public static Entity createRicochetFireball(short targetLayer, Vector2 destination, Vector2 speed, int bounceCount) { + Entity fireBall = createFireBall(targetLayer, destination, speed); + fireBall + .addComponent(new RicochetComponent(targetLayer, bounceCount)); + + setColliderSize(fireBall, (float) 0.1, (float) 0.1); + + return fireBall; + } + + public static Entity createSplitFireWorksFireball(short targetLayer, Vector2 destination, Vector2 speed, int amount) { + Entity fireBall = createFireBall(targetLayer, destination, speed); + fireBall + .addComponent(new SplitFireworksComponent(targetLayer, amount)); + + return fireBall; + } + + /** + * Creates a fireball Entity. + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @return Returns a new fireball projectile entity. + */ + public static Entity createFireBall(short targetLayer, Vector2 destination, Vector2 speed) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset(BASE_PROJECTILE_ATLAS, TextureAtlas.class)); + animator.addAnimation(START_ANIM, START_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation(FINAL_ANIM, FINAL_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("projectileCollide", START_SPEED, Animation.PlayMode.NORMAL); + + projectile + .addComponent(animator) + .addComponent(new ProjectileAnimationController(targetLayer)); + // * TEMPORARY + // .addComponent(new DeleteOnMapEdgeComponent()); + // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); + + return projectile; + } + + /** + * Creates new animation and fireballs for SplitFireworkComponent. + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @return Returns a new fireball projectile entity. + */ + public static Entity createFireworks(short targetLayer, Vector2 destination, Vector2 speed) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/firework_anim.atlas", TextureAtlas.class)); + animator.addAnimation(START_ANIM, 0.2f, Animation.PlayMode.LOOP); + projectile + .addComponent(animator) + .addComponent(new FireworkAnimationController()); + + return projectile; + } + + public static Entity createPierceBallAnim(short targetLayer, Vector2 destination, Vector2 speed) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/pierce_anim.atlas", TextureAtlas.class)); + animator.addAnimation(START_ANIM, 0.05f, Animation.PlayMode.LOOP); + projectile + .addComponent(animator) + .addComponent(new PierceProjectileAnimationController()); + + return projectile; + } + + + /** + * Creates a engineer bullet + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @return Returns a new fireball projectile entity. + */ + public static Entity createEngineerBullet(short targetLayer, Vector2 destination, Vector2 speed) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/engineer_projectile.atlas", TextureAtlas.class)); + animator.addAnimation("bullet", START_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("bulletFinal", FINAL_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation("bulletCollide", START_SPEED, Animation.PlayMode.NORMAL); + + projectile + .addComponent(animator) + .addComponent(new EngineerBulletsAnimationController(targetLayer)); + // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); + + return projectile; + } + + /** + * Creates a projectile specifically for mobs to shoot + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @return Returns a new fireball projectile entity. + */ + public static Entity createMobBall(short targetLayer, Vector2 destination, Vector2 speed) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/mobProjectile.atlas", TextureAtlas.class)); + + animator.addAnimation("rotate", 0.15f, Animation.PlayMode.LOOP); + + projectile + .addComponent(animator) + .addComponent(new MobProjectileAnimationController()); + // * TEMPORARY + // .addComponent(new DeleteOnMapEdgeComponent()); + + projectile + .getComponent(AnimationRenderComponent.class).scaleEntity(); + + + + return projectile; + } + public static Entity createBossBall(short targetLayer, Vector2 destination, Vector2 speed) { // function added by team 7 for Boss projectile + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/bossProjectile.atlas", TextureAtlas.class)); + + animator.addAnimation("rotate", 0.15f, Animation.PlayMode.LOOP); + + projectile + .addComponent(animator) + .addComponent(new BossProjectileAnimationController()); + + projectile + .getComponent(AnimationRenderComponent.class).scaleEntity(); + projectile.setScale(2,2); + + return projectile; + } + + /** + * Creates a projectile to be used by the MobBoss + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @return Returns a new fireball projectile entity. + */ + public static Entity createMobBossBall(short targetLayer, Vector2 destination, Vector2 speed) { + Entity projectile = createBaseProjectile(targetLayer, destination, speed); + + AnimationRenderComponent animator = + new AnimationRenderComponent( + ServiceLocator.getResourceService() + .getAsset("images/projectiles/mobBoss_projectile.atlas", TextureAtlas.class)); + animator.addAnimation("mob_boss", 0.17f, Animation.PlayMode.NORMAL); + animator.addAnimation("mob_bossFinal", 0.17f, Animation.PlayMode.NORMAL); + + + projectile + .addComponent(animator) + .addComponent(new MobBossProjectAnimController()); + + projectile + .getComponent(AnimationRenderComponent.class).scaleEntity(); + + return projectile; + } + + /** + * Creates a generic projectile entity that can be used for multiple types of * projectiles. + * + * @param targetLayer The enemy layer that the projectile collides with. + * @param destination The destination the projectile heads towards. + * @param speed The speed of the projectile. + * @return Returns a generic projectile entity. + */ + public static Entity createBaseProjectile(short targetLayer, Vector2 + destination, Vector2 speed) { + BaseEntityConfig config = configs.fireBall; + + AITaskComponent aiComponent = + new AITaskComponent() + .addTask(new TrajectTask(destination)); + + Entity projectile = new Entity() + .addComponent(new PhysicsComponent()) + .addComponent(new PhysicsMovementComponent()) + .addComponent(new HitboxComponent().setLayer(PhysicsLayer.PROJECTILE)) + .addComponent(aiComponent) + .addComponent(new ColliderComponent().setSensor(true)) + // This is the component that allows the projectile to damage a + // specified target. + // Original knockback value: 1.5f + .addComponent(new TouchAttackComponent(targetLayer, 1.5f, true)) + .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) + // *TEMPORARY + .addComponent(new DeleteOnMapEdgeComponent()); + + projectile + .getComponent(PhysicsMovementComponent.class).setSpeed(speed); + + return projectile; + } + + /** + * Sets the projectile collider so that the collider size can be altered for flexibility. + * @param projectile Projectile's size collider to be scaled upon. + * @param x Horizontal scaling of the collider in respect ot the size of the entity + * @param y Veritcal scaling of the collider in respect to the size of the entity + */ + public static void setColliderSize(Entity projectile, float x, float y) { + PhysicsUtils.setScaledCollider(projectile, x, y); + } + + /** + * Prevents the creation of a Projectile Factory entity being created + */ + private ProjectileFactory() { + throw new IllegalStateException("Instantiating static util class"); + } +} diff --git a/source/core/src/test/com/csse3200/game/components/archer/ArcherAnimationControllerTest.java b/source/core/src/test/com/csse3200/game/components/archer/ArcherAnimationControllerTest.java new file mode 100644 index 000000000..4bf447bc1 --- /dev/null +++ b/source/core/src/test/com/csse3200/game/components/archer/ArcherAnimationControllerTest.java @@ -0,0 +1,67 @@ +package com.csse3200.game.components.archer; + + +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.factories.NPCFactory; +import com.csse3200.game.extensions.GameExtension; +import com.csse3200.game.physics.PhysicsService; +import com.csse3200.game.rendering.AnimationRenderComponent; +import com.csse3200.game.rendering.DebugRenderer; +import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.services.ResourceService; +import com.csse3200.game.services.ServiceLocator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + + +@ExtendWith(GameExtension.class) +public class ArcherAnimationControllerTest { + + private Entity arcaneArcher; + private final String[] atlas = {"images/mobs/arcane_archer.atlas"}; + + @BeforeEach + public void setUp() { + ServiceLocator.registerPhysicsService(new PhysicsService()); + RenderService render = new RenderService(); + render.setDebug(mock(DebugRenderer.class)); + ServiceLocator.registerRenderService(render); + ResourceService resourceService = new ResourceService(); + ServiceLocator.registerResourceService(resourceService); + resourceService.loadTextureAtlases(atlas); + resourceService.loadAll(); + + arcaneArcher = NPCFactory.createDodgingArcaneArcher(60); // Replace with actual Droid Tower creation logic + arcaneArcher.create(); + } + + @Test + public void testAnimateWander() { + arcaneArcher.getEvents().trigger("mob_walk"); + assertEquals("arcane_archer_run", arcaneArcher.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateAttack() { + arcaneArcher.getEvents().trigger("mob_attack"); + assertEquals("arcane_archer_attack", arcaneArcher.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateDeath() { + arcaneArcher.getEvents().trigger("mob_death"); + assertEquals("arcane_archer_death", arcaneArcher.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateDodge() { + arcaneArcher.getEvents().trigger("mob_dodge"); + assertEquals("arcane_archer_dodge", arcaneArcher.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } +} diff --git a/source/core/src/test/com/csse3200/game/components/projectile/EngineerBulletsAnimationControllerTest.java b/source/core/src/test/com/csse3200/game/components/projectile/EngineerBulletsAnimationControllerTest.java new file mode 100644 index 000000000..5c2e79976 --- /dev/null +++ b/source/core/src/test/com/csse3200/game/components/projectile/EngineerBulletsAnimationControllerTest.java @@ -0,0 +1,67 @@ +package com.csse3200.game.components.projectile; + +import com.badlogic.gdx.math.Vector2; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.factories.ProjectileFactory; +import com.csse3200.game.extensions.GameExtension; +import com.csse3200.game.physics.PhysicsService; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.rendering.AnimationRenderComponent; +import com.csse3200.game.rendering.DebugRenderer; +import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.services.ResourceService; +import com.csse3200.game.services.ServiceLocator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import com.badlogic.gdx.physics.box2d.Fixture; + +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + + +@ExtendWith(GameExtension.class) +public class EngineerBulletsAnimationControllerTest { + + private Entity engineerBullet; + private final String[] atlas = {"images/projectiles/engineer_projectile.atlas"}; + + @BeforeEach + public void setUp() { + ServiceLocator.registerPhysicsService(new PhysicsService()); + RenderService render = new RenderService(); + render.setDebug(mock(DebugRenderer.class)); + ServiceLocator.registerRenderService(render); + ResourceService resourceService = new ResourceService(); + ServiceLocator.registerResourceService(resourceService); + resourceService.loadTextureAtlases(atlas); + resourceService.loadAll(); + + engineerBullet = ProjectileFactory.createEngineerBullet(PhysicsLayer.NPC, + new Vector2(100, 0), + new Vector2(4f, 4f)); + engineerBullet.setScale(0.8f, 0.8f); + engineerBullet.setPosition(0, 0); + engineerBullet.create(); + } + + @Test + public void testAnimateStart() { + engineerBullet.getEvents().trigger("startProjectile"); + assertEquals("bullet", engineerBullet.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateFinal() { + engineerBullet.getEvents().trigger("startProjectileFinal"); + assertEquals("bulletFinal", engineerBullet.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateCollide() { + engineerBullet.getEvents().trigger("collisionStart", null, null); + assertEquals("bulletCollide", engineerBullet.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } +} 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 aa0249b30..0d5361e75 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 @@ -1,70 +1,75 @@ -package com.csse3200.game.components.xenos; - - -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.factories.NPCFactory; -import com.csse3200.game.extensions.GameExtension; -import com.csse3200.game.physics.PhysicsService; -import com.csse3200.game.rendering.AnimationRenderComponent; -import com.csse3200.game.rendering.DebugRenderer; -import com.csse3200.game.rendering.RenderService; -import com.csse3200.game.services.ResourceService; -import com.csse3200.game.services.ServiceLocator; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import java.util.Objects; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; - - -@ExtendWith(GameExtension.class) -class XenoAnimationControllerTest { - - private Entity xenoGrunt; - private final String[] atlas = {"images/mobs/xenoGrunt.atlas"}; - - @BeforeEach - public void setUp() { - ServiceLocator.registerPhysicsService(new PhysicsService()); - RenderService render = new RenderService(); - render.setDebug(mock(DebugRenderer.class)); - ServiceLocator.registerRenderService(render); - ResourceService resourceService = new ResourceService(); - ServiceLocator.registerResourceService(resourceService); - resourceService.loadTextureAtlases(atlas); - resourceService.loadAll(); - - xenoGrunt = NPCFactory.createXenoGrunt(60); // Replace with actual Droid Tower creation logic - xenoGrunt.create(); - } - - @Test - void testAnimateWander() { - xenoGrunt.getEvents().trigger("wanderStart"); - assertEquals("xeno_run", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); - } - - @Test - void testAnimateHurt() { - xenoGrunt.getEvents().trigger("runHurt"); - assertEquals("xeno_hurt", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); - } - - @Test - 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 - void testAnimateDie() { - xenoGrunt.getEvents().trigger("dieStart"); - assertEquals("xeno_die", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); - } - -} +package com.csse3200.game.components.xenos; + + +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.factories.NPCFactory; +import com.csse3200.game.extensions.GameExtension; +import com.csse3200.game.physics.PhysicsService; +import com.csse3200.game.rendering.AnimationRenderComponent; +import com.csse3200.game.rendering.DebugRenderer; +import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.services.ResourceService; +import com.csse3200.game.services.ServiceLocator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + + +@ExtendWith(GameExtension.class) +public class XenoAnimationControllerTest { + + private Entity xenoGrunt; + private final String[] atlas = {"images/mobs/xenoGrunt.atlas"}; + + @BeforeEach + public void setUp() { + ServiceLocator.registerPhysicsService(new PhysicsService()); + RenderService render = new RenderService(); + render.setDebug(mock(DebugRenderer.class)); + ServiceLocator.registerRenderService(render); + ResourceService resourceService = new ResourceService(); + ServiceLocator.registerResourceService(resourceService); + resourceService.loadTextureAtlases(atlas); + resourceService.loadAll(); + + xenoGrunt = NPCFactory.createXenoGrunt(60); // Replace with actual Droid Tower creation logic + xenoGrunt.create(); + } + + @Test + public void testAnimateWander() { + xenoGrunt.getEvents().trigger("wanderStart"); + assertEquals("xeno_run", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateHurt() { + xenoGrunt.getEvents().trigger("runHurt"); + assertEquals("xeno_hurt", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateMelee1() { + 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() { + xenoGrunt.getEvents().trigger("dieStart"); + assertEquals("xeno_die", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + + @Test + public void testAnimateFreeze() { + xenoGrunt.getEvents().trigger("freeze"); + assertEquals("xeno_freeze", xenoGrunt.getComponent(AnimationRenderComponent.class).getCurrentAnimation()); + } + +}