From 321b25b23c2d21fd106e36b47be87167857070e7 Mon Sep 17 00:00:00 2001 From: totemo Date: Fri, 11 Mar 2016 15:33:21 +1030 Subject: [PATCH] Add predefined creature types for all professions of villagers and zombies including baby variants of each. --- .../doppelganger/IPredefinedCreature.java | 29 ++ .../doppelganger/PredefinedCreature.java | 363 +++++++++++------- 2 files changed, 249 insertions(+), 143 deletions(-) create mode 100644 src/io/github/totemo/doppelganger/IPredefinedCreature.java diff --git a/src/io/github/totemo/doppelganger/IPredefinedCreature.java b/src/io/github/totemo/doppelganger/IPredefinedCreature.java new file mode 100644 index 0000000..5355c8a --- /dev/null +++ b/src/io/github/totemo/doppelganger/IPredefinedCreature.java @@ -0,0 +1,29 @@ +package io.github.totemo.doppelganger; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +// ---------------------------------------------------------------------------- +/** + * The interface implemented by all {@link PredefinedCreature}s + */ +public interface IPredefinedCreature +{ + // -------------------------------------------------------------------------- + /** + * Return true if the specified LivingEntity is of this type. + * + * @param living the creature to examine. + * @return true if it is this type of PredefinedCreature. + */ + boolean isInstance(LivingEntity living); + + // -------------------------------------------------------------------------- + /** + * Spawn a creature of this type at the specified location. + * + * @param loc the Location. + * @return the LivingEntity. + */ + LivingEntity spawn(Location loc); +} // class IPredefinedCreature \ No newline at end of file diff --git a/src/io/github/totemo/doppelganger/PredefinedCreature.java b/src/io/github/totemo/doppelganger/PredefinedCreature.java index 27cb11a..e47df9b 100644 --- a/src/io/github/totemo/doppelganger/PredefinedCreature.java +++ b/src/io/github/totemo/doppelganger/PredefinedCreature.java @@ -1,6 +1,7 @@ package io.github.totemo.doppelganger; import java.util.HashMap; +import java.util.Random; import org.bukkit.Location; import org.bukkit.entity.Creeper; @@ -16,15 +17,15 @@ // ---------------------------------------------------------------------------- /** * Describes predefined creature types that are variations on vanilla creatures. - * + * * These creature types are not defined in the Doppelganger configuration file, * but are a well known part of the vanilla game. They are all variants of some * base LivingEntity type that must be customised by setting an attribute, * rather than instantiating a unique class. */ -public enum PredefinedCreature +public enum PredefinedCreature implements IPredefinedCreature { - WitherSkeleton + WitherSkeleton(new IPredefinedCreature() { @Override public boolean isInstance(LivingEntity living) @@ -40,9 +41,9 @@ public LivingEntity spawn(Location loc) skeleton.setSkeletonType(SkeletonType.WITHER); return skeleton; } - }, + }), - SaddledPig + SaddledPig(new IPredefinedCreature() { @Override public boolean isInstance(LivingEntity living) @@ -57,244 +58,320 @@ public LivingEntity spawn(Location loc) pig.setSaddle(true); return pig; } - }, + }), - ZombieVillager + BabyPigZombie(new IPredefinedCreature() { @Override public boolean isInstance(LivingEntity living) { - return living instanceof Zombie && ((Zombie) living).isVillager(); + return living instanceof PigZombie && ((PigZombie) living).isBaby(); } @Override public LivingEntity spawn(Location loc) { - Zombie zombie = loc.getWorld().spawn(loc, Zombie.class); - zombie.setVillager(true); + PigZombie zombie = loc.getWorld().spawn(loc, PigZombie.class); + zombie.setBaby(true); return zombie; } - }, + }), - BabyZombieVillager + ChargedCreeper(new IPredefinedCreature() { @Override public boolean isInstance(LivingEntity living) { - return living instanceof Zombie && - ((Zombie) living).isVillager() && - ((Zombie) living).isBaby(); + return living instanceof Creeper && ((Creeper) living).isPowered(); } @Override public LivingEntity spawn(Location loc) { - Zombie zombie = loc.getWorld().spawn(loc, Zombie.class); - zombie.setVillager(true); - // Note: Zombie interface does not extend Ageable. - zombie.setBaby(true); - return zombie; + Creeper creeper = loc.getWorld().spawn(loc, Creeper.class); + creeper.setPowered(true); + return creeper; } - }, - - BabyZombie + }), + + Blacksmith(new PredefinedVillager(false, Profession.BLACKSMITH)), + BabyBlacksmith(new PredefinedVillager(true, Profession.BLACKSMITH)), + ZombieBlacksmith(new PredefinedZombie(false, Profession.BLACKSMITH)), + BabyZombieBlacksmith(new PredefinedZombie(true, Profession.BLACKSMITH)), + Butcher(new PredefinedVillager(false, Profession.BUTCHER)), + BabyButcher(new PredefinedVillager(true, Profession.BUTCHER)), + ZombieButcher(new PredefinedZombie(false, Profession.BUTCHER)), + BabyZombieButcher(new PredefinedZombie(true, Profession.BUTCHER)), + Farmer(new PredefinedVillager(false, Profession.FARMER)), + BabyFarmer(new PredefinedVillager(true, Profession.FARMER)), + ZombieFarmer(new PredefinedZombie(false, Profession.FARMER)), + BabyZombieFarmer(new PredefinedZombie(true, Profession.FARMER)), + Librarian(new PredefinedVillager(false, Profession.LIBRARIAN)), + BabyLibrarian(new PredefinedVillager(true, Profession.LIBRARIAN)), + ZombieLibrarian(new PredefinedZombie(false, Profession.LIBRARIAN)), + BabyZombieLibrarian(new PredefinedZombie(true, Profession.LIBRARIAN)), + Priest(new PredefinedVillager(false, Profession.PRIEST)), + BabyPriest(new PredefinedVillager(true, Profession.PRIEST)), + ZombiePriest(new PredefinedZombie(false, Profession.PRIEST)), + BabyZombiePriest(new PredefinedZombie(true, Profession.PRIEST)), + + BabyVillager(new PredefinedVillager(true, null)), + BabyZombie(new PredefinedZombie(true, null)), + + ZombieVillager(new IPredefinedCreature() { @Override public boolean isInstance(LivingEntity living) { - return living instanceof Zombie && - !((Zombie) living).isVillager() && - ((Zombie) living).isBaby(); + return living instanceof Zombie && ((Zombie) living).isVillager(); } @Override public LivingEntity spawn(Location loc) { Zombie zombie = loc.getWorld().spawn(loc, Zombie.class); - zombie.setBaby(true); + zombie.setVillagerProfession(getRandomVillagerProfession()); return zombie; } - }, + }), - BabyPigZombie + BabyZombieVillager(new IPredefinedCreature() { @Override public boolean isInstance(LivingEntity living) { - return living instanceof PigZombie && ((PigZombie) living).isBaby(); + return living instanceof Zombie && + ((Zombie) living).isVillager() && + ((Zombie) living).isBaby(); } @Override public LivingEntity spawn(Location loc) { - PigZombie zombie = loc.getWorld().spawn(loc, PigZombie.class); + Zombie zombie = loc.getWorld().spawn(loc, Zombie.class); zombie.setBaby(true); + zombie.setVillagerProfession(getRandomVillagerProfession()); return zombie; } - }, + }); - ChargedCreeper + // -------------------------------------------------------------------------- + /** + * Look up the PredefinedCreature enum value by name. + * + * @param name the case insensitive name. + * @return the PredefinedCreature value, or null if not found. + */ + public static PredefinedCreature fromName(String name) { - @Override - public boolean isInstance(LivingEntity living) - { - return living instanceof Creeper && ((Creeper) living).isPowered(); - } + return BY_NAME.get(name.toLowerCase()); + } - @Override - public LivingEntity spawn(Location loc) + // -------------------------------------------------------------------------- + /** + * If the LivingEntity is an instance of a PredefinedCreature, return that + * enum value; otherwise, return null. + * + * @param living the LivingEntity to look up. + * @return the corresponding PredefinedCreature, or null if not found. + */ + public static PredefinedCreature fromLivingEntity(LivingEntity living) + { + for (PredefinedCreature creature : values()) + { + if (creature.isInstance(living)) { - Creeper creeper = loc.getWorld().spawn(loc, Creeper.class); - creeper.setPowered(true); - return creeper; + return creature; } - }, + } + return null; + } - Blacksmith + // -------------------------------------------------------------------------- + /** + * Return a random villager profession. + * + * @return a random villager profession. + */ + public static Villager.Profession getRandomVillagerProfession() { - @Override - public boolean isInstance(LivingEntity living) - { - return living instanceof Villager && - ((Villager) living).getProfession() == Profession.BLACKSMITH; - } + Villager.Profession[] professions = Villager.Profession.values(); + return professions[_random.nextInt(professions.length)]; + } - @Override - public LivingEntity spawn(Location loc) - { - Villager villager = loc.getWorld().spawn(loc, Villager.class); - villager.setProfession(Profession.BLACKSMITH); - return villager; - } - }, + // -------------------------------------------------------------------------- - Butcher + private PredefinedCreature(IPredefinedCreature implementation) { - @Override - public boolean isInstance(LivingEntity living) - { - return living instanceof Villager && - ((Villager) living).getProfession() == Profession.BUTCHER; - } + _implementation = implementation; + } - @Override - public LivingEntity spawn(Location loc) - { - Villager villager = loc.getWorld().spawn(loc, Villager.class); - villager.setProfession(Profession.BUTCHER); - return villager; - } - }, + // -------------------------------------------------------------------------- + /** + * @see io.github.totemo.doppelganger.IPredefinedCreature#isInstance(org.bukkit.entity.LivingEntity) + */ + @Override + public boolean isInstance(LivingEntity living) + { + return _implementation.isInstance(living); + } - Farmer + // -------------------------------------------------------------------------- + /** + * @see io.github.totemo.doppelganger.IPredefinedCreature#spawn(org.bukkit.Location) + */ + @Override + public LivingEntity spawn(Location loc) { - @Override - public boolean isInstance(LivingEntity living) - { - return living instanceof Villager && - ((Villager) living).getProfession() == Profession.FARMER; - } + return _implementation.spawn(loc); + } - @Override - public LivingEntity spawn(Location loc) + // -------------------------------------------------------------------------- + /** + * PredefinedCreature implementation delegate for villagers with specified age + * (adult or baby) and villager profession. + * + * Bukkit Villager and Zombie interfaces don't share a common superinterface + * to control age, so this implementation must be distinct from that of + * PredefinedZombies. + */ + static final class PredefinedVillager implements IPredefinedCreature + { + /** + * Constructor. + * + * @param baby if true, the villager is a baby; otherwise it is an adult. + * @param profession the villager's profession. + */ + public PredefinedVillager(boolean baby, Profession profession) { - Villager villager = loc.getWorld().spawn(loc, Villager.class); - villager.setProfession(Profession.FARMER); - return villager; + _baby = baby; + _profession = profession; } - }, - Librarian - { + // ------------------------------------------------------------------------ + /** + * @see io.github.totemo.doppelganger.IPredefinedCreature#isInstance(org.bukkit.entity.LivingEntity) + */ @Override public boolean isInstance(LivingEntity living) { return living instanceof Villager && - ((Villager) living).getProfession() == Profession.LIBRARIAN; + ((Villager) living).isAdult() != _baby && + ((Villager) living).getProfession() == _profession; } + // ------------------------------------------------------------------------ + /** + * @see io.github.totemo.doppelganger.IPredefinedCreature#spawn(org.bukkit.Location) + */ @Override public LivingEntity spawn(Location loc) { Villager villager = loc.getWorld().spawn(loc, Villager.class); - villager.setProfession(Profession.LIBRARIAN); + if (_baby) + { + villager.setBaby(); + } + if (_profession != null) + { + villager.setProfession(_profession); + } return villager; } - }, - Priest + // ------------------------------------------------------------------------ + /** + * True if a baby. + */ + protected boolean _baby; + + /** + * Villager profession. + */ + protected Profession _profession; + }; // inner class PredefinedVillager + + // -------------------------------------------------------------------------- + /** + * PredefinedCreature implementation delegate for zombies with specified age + * (adult or baby) and villager profession. + * + * Bukkit Villager and Zombie interfaces don't share a common superinterface + * to control age, so this implementation must be distinct from that of + * PredefinedVillagers. + */ + static final class PredefinedZombie implements IPredefinedCreature { - @Override - public boolean isInstance(LivingEntity living) + /** + * Constructor. + * + * @param baby if true, the zombie villager is a baby; otherwise it is an + * adult. + * @param profession the zombie villager's profession; or null for no + * profession (a non-villager). + */ + public PredefinedZombie(boolean baby, Profession profession) { - return living instanceof Villager && - ((Villager) living).getProfession() == Profession.PRIEST; + _baby = baby; + _profession = profession; } + // ------------------------------------------------------------------------ + /** + * @see io.github.totemo.doppelganger.IPredefinedCreature#isInstance(org.bukkit.entity.LivingEntity) + */ @Override - public LivingEntity spawn(Location loc) + public boolean isInstance(LivingEntity living) { - Villager villager = loc.getWorld().spawn(loc, Villager.class); - villager.setProfession(Profession.PRIEST); - return villager; + return living instanceof Zombie && + ((Zombie) living).isBaby() == _baby && + ((Zombie) living).getVillagerProfession() == _profession; } - }; - - // -------------------------------------------------------------------------- - /** - * Look up the PredefinedCreature enum value by name. - * - * @param name the case insensitive name. - * @return the PredefinedCreature value, or null if not found. - */ - public static PredefinedCreature fromName(String name) - { - return BY_NAME.get(name.toLowerCase()); - } - // -------------------------------------------------------------------------- - /** - * If the LivingEntity is an instance of a PredefinedCreature, return that - * enum value; otherwise, return null. - * - * @param living the LivingEntity to look up. - * @return the corresponding PredefinedCreature, or null if not found. - */ - public static PredefinedCreature fromLivingEntity(LivingEntity living) - { - for (PredefinedCreature creature : values()) + // ------------------------------------------------------------------------ + /** + * @see io.github.totemo.doppelganger.IPredefinedCreature#spawn(org.bukkit.Location) + */ + @Override + public LivingEntity spawn(Location loc) { - if (creature.isInstance(living)) + Zombie zombie = loc.getWorld().spawn(loc, Zombie.class); + zombie.setBaby(_baby); + if (_profession != null) { - return creature; + zombie.setVillagerProfession(_profession); } + return zombie; } - return null; - } + + // ------------------------------------------------------------------------ + /** + * True if a baby. + */ + protected boolean _baby; + + /** + * Villager profession, or null for a generic zombie. + */ + protected Profession _profession; + }; // inner class PredefinedZombie // -------------------------------------------------------------------------- /** - * Return true if the specified LivingEntity is of this type. - * - * @param living the creature to examine. - * @return true if it is this type of PredefinedCreature. + * Map from lower case PredefinedCreature name to instance. */ - public abstract boolean isInstance(LivingEntity living); + protected static HashMap BY_NAME = new HashMap(); - // -------------------------------------------------------------------------- /** - * Spawn a creature of this type at the specified location. - * - * @param loc the Location. - * @return the LivingEntity. + * Random number generator. */ - public abstract LivingEntity spawn(Location loc); + protected static Random _random = new Random(); - // -------------------------------------------------------------------------- /** - * Map from lower case PredefinedCreature name to instance. + * PredefinedCreature enums delegate to this instance, set by the constructor. */ - protected static HashMap BY_NAME = new HashMap(); + protected final IPredefinedCreature _implementation; // -------------------------------------------------------------------------- // Initialise maps.