diff --git a/examples/config.yml b/examples/config.yml index 7d985f7..d2d8c12 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -139,18 +139,18 @@ shapes: creatures: SpecialBat: spawn: Bat - sound: ambience_cave + sound: ambient_cave SpecialCow: spawn: Cow - sound: ambience_cave + sound: ambient_cave lightning: min: 1 despawns: false SpecialVillager: spawn: Villager - sound: ambience_cave + sound: ambient_cave lightning: min: 1 despawns: false @@ -176,7 +176,7 @@ creatures: boots: item: leather_boots rgb: [255,0,0] - + BlueSkeleton: spawn: Skeleton lightning: @@ -210,7 +210,7 @@ creatures: boots: item: leather_boots rgb: [255,0,0] - + BlueBabyZombieVillager: spawn: BabyZombieVillager despawns: false @@ -226,7 +226,7 @@ creatures: boots: item: leather_boots rgb: [0,0,255] - + RedBabyZombie: spawn: BabyZombie despawns: false @@ -242,7 +242,7 @@ creatures: boots: item: leather_boots rgb: [255,0,0] - + BlueBabyZombie: spawn: BabyZombie despawns: false @@ -294,12 +294,12 @@ creatures: BabyWolf: despawns: false spawn: Wolf - baby: true - agelocked: true - + baby: true + agelocked: true + ToughWitherSkeleton: spawn: WitherSkeleton - sound: wither_spawn + sound: entity_wither_spawn lightning: min: 1 despawns: false @@ -335,7 +335,7 @@ creatures: ToughSkeleton: spawn: Skeleton - sound: wither_spawn + sound: entity_wither_spawn lightning: min: 1 despawns: false @@ -357,7 +357,7 @@ creatures: ToughPigZombie: spawn: PigZombie - sound: wither_spawn + sound: entity_wither_spawn lightning: min: 1 despawns: false @@ -380,7 +380,7 @@ creatures: defaultname: Minion keephelmet: true spawn: Skeleton - sound: ambience_cave + sound: ambient_cave helmet: item: melon_block weapon: @@ -391,7 +391,7 @@ creatures: defaultname: Henchman keephelmet: true spawn: Skeleton - sound: ambience_cave + sound: ambient_cave helmet: item: melon_block chestplate: @@ -409,14 +409,14 @@ creatures: FlyingPig: spawn: Pig mount: InvisibleBat - sound: pig_death + sound: entity_pig_death FlyingSquid: spawn: Squid mount: InvisibleBat - sound: swim + sound: entity_generic_swim air: 72000 - + FlyingSaddledPig: spawn: SaddledPig mount: InvisibleBat @@ -438,7 +438,7 @@ creatures: potions: - type: invisibility ambient: false - + FlyingSkull: spawn: Skeleton despawns: false @@ -447,7 +447,7 @@ creatures: potions: - type: invisibility - type: fire_resistance - helmet: + helmet: item: skull_item dropchance: 0.0 weapon: @@ -467,7 +467,7 @@ creatures: lightning: min: 4 max: 7 - sound: wither_spawn + sound: entity_wither_spawn helmet: item: skull_item lore: @@ -480,13 +480,19 @@ creatures: enchantments: - type: protection_environmental level: 4 - leggings: + leggings: item: diamond_leggings damage: 3 dropchance: 0.0 enchantments: - type: protection_environmental level: 4 + boots: + item: diamond_boots + dropchance: 0.0 + enchantments: + - type: protection_environmental + level: 4 weapon: item: diamond_sword name: Whittlebone @@ -500,7 +506,7 @@ creatures: level: 5 - type: fire_aspect level: 2 - boots: + shield: # item: tripwire_hook # name: The Key of Notch # lore: @@ -547,6 +553,12 @@ creatures: - type: protection_environmental level: 4 boots: + item: diamond_boots + dropchance: 0.0 + enchantments: + - type: protection_environmental + level: 4 + shield: item: written_book lore: - "&4&oA mysterious tome of great power." @@ -653,14 +665,14 @@ creatures: - weight: 0.5 spawn: Bat - + players: Notch: spawn: Notch shapes: - diamond_t_ns - diamond_t_ew - + jeb_: shapes: - diamond_t_ns diff --git a/plugin.yml b/plugin.yml index 931da5c..1e15352 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,14 +1,16 @@ -name: Doppelganger +name: ${project.name} main: io.github.totemo.doppelganger.Doppelganger version: ${project.version} description: ${project.description} author: totemo -website: http://github.com/totemo/Doppelganger +website: ${project.url} + commands: doppel: description: Describes, finds, spawns and kills doppelgangers. See /doppel help. usage: /doppel [help|info|coords|kill|spawn|maintain] permission: doppelganger.help + permissions: doppelganger.*: description: Permission to use doppelganger commands. diff --git a/pom.xml b/pom.xml index c943cc3..8aa76dd 100644 --- a/pom.xml +++ b/pom.xml @@ -3,52 +3,29 @@ 4.0.0 io.github.totemo Doppelganger - 0.9.2 + 0.10.0 jar Doppelganger + Provides custom, summonable mobs that are reminiscent of the built-in golem types. + https://github.com/totemo/Doppelganger UTF-8 - - - - - - - - - - - - - - - - - bukkit-plugins - http://repo.bukkit.org/content/groups/public/ - - org.bukkit bukkit - 1.5.2-R0.1 + 1.9-R0.1-SNAPSHOT - bukkit-repo - - true - - - true - - http://repo.bukkit.org/content/groups/public/ + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public + clean package ${basedir}/src @@ -62,7 +39,6 @@ - clean package diff --git a/src/io/github/totemo/doppelganger/CreatureFactory.java b/src/io/github/totemo/doppelganger/CreatureFactory.java index 2517100..1deb8de 100644 --- a/src/io/github/totemo/doppelganger/CreatureFactory.java +++ b/src/io/github/totemo/doppelganger/CreatureFactory.java @@ -17,7 +17,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; -// -------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- /** * Manages known creature types and creates them on demand. */ @@ -26,7 +26,7 @@ public class CreatureFactory // -------------------------------------------------------------------------- /** * Return the type name of the specified LivingEntity. - * + * * @return the type name of the specified LivingEntity. */ public static String getLivingEntityType(LivingEntity living) @@ -38,7 +38,7 @@ public static String getLivingEntityType(LivingEntity living) // -------------------------------------------------------------------------- /** * Load the creature shapes and types from the configuration file. - * + * * @param root the root of the configuration hierarchy. * @param logger the Logger. */ @@ -171,7 +171,7 @@ else if (isValidCreatureType(type.getCreatureType())) /** * Print a human-readable list of the configured shapes, creature types and * player-name-specific creatures to the command sender. - * + * * @param sender the agent requesting the listing. */ public void listConfiguration(CommandSender sender) @@ -214,7 +214,7 @@ public void listConfiguration(CommandSender sender) /** * Return the {@link CreatureShape} with the specified name in the * configuration, or null if not found. - * + * * @param name the case insensitive shape name. * @return the {@link CreatureShape} with the specified name in the * configuration, or null if not found. @@ -228,10 +228,10 @@ public CreatureShape getCreatureShape(String name) /** * Return the {@link CreatureShape} representing the shape used to summon a * creature by placing the specified item. - * + * * The placed item must be named (by an anvil) and the shape and type of the * blocks around it must match one of those specified in the configuration. - * + * * @param loc the location where the triggering item is placed. * @param placedItem the item to be tested as a trigger of creature summoning. * @return the {@link CreatureShape} of the creature that would be created, or @@ -243,7 +243,7 @@ public CreatureShape getCreatureShape(Location loc, ItemStack placedItem) // named blocks? for (CreatureShape shape : _shapes.values()) { - if (shape.isComplete(loc, placedItem.getTypeId())) + if (shape.isComplete(loc, placedItem.getType())) { return shape; } @@ -255,12 +255,12 @@ public CreatureShape getCreatureShape(Location loc, ItemStack placedItem) /** * Return the CreatureType identified by the specified name, or null if not * found. - * + * * Note that default Minecraft creatures, or the custom creatures defined by * the PredefinedCreature enum will not have a corresponding CreatureType * instance. The purpose of the CreatureType instance is to apply overrides to * the defaults. - * + * * @param name the case-insensitive creature type name. * @return the CreatureType identified by the specified name, or null if not * found. @@ -274,7 +274,7 @@ public CreatureType getCreatureType(String name) /** * Return the specific creature type that will be spawned when the named * player is summoned. - * + * * @param playerName the name of the player whose custom creature type name * will be returned. * @return the specific creature type that will be spawned when the named @@ -288,7 +288,7 @@ public String getPlayerCreature(String playerName) // -------------------------------------------------------------------------- /** * Return the specific shapes that can summon the specified player. - * + * * @param playerName the name of the player for whom summoning shapes will be * returned. * @return the specific shapes that can summon the specified player; or null @@ -304,7 +304,7 @@ public ArrayList getPlayerShapes(String playerName) * Return true if the specified name signifies a vanilla Minecraft creature * (as in known to EntityType) or one of the custom values defined by * PredefinedCreature. - * + * * @param name the case-insensitive creature type. * @return true if the creature type is "vanilla", as opposed to defined in * the Doppelganger configuration file. @@ -319,7 +319,7 @@ public static boolean isVanillaCreatureType(String name) /** * Return true if the specified creature is a valid EntityType value or a * supported custom creature name. - * + * * @param creatureType the case-insensitive custom or vanilla creature type. * @return true if the specified living entity is a valid EntityType value or * a supported custom creature name. @@ -341,16 +341,16 @@ public boolean isValidCreatureType(String creatureType) // -------------------------------------------------------------------------- /** * Spawn a living entity of the specified type. - * + * * This method originally returned a Creature, but Bats are Ambient mobs. The * next common base class is LivingEntity. - * + * * If the creature type has a mask, then the creature will wear that player's * head, irrespective of the creature's name. If a name is not specified, then * the default name from the configuration will be used. If the original name * specified is non-empty, or a valid default is provided, the name plate will * be displayed. - * + * * @param creatureType the EntityType.getName() value specifying the creature * type; case-insensitive, or PredefinedCreature.name(). Null or the * empty string will result in no spawned creature. @@ -450,10 +450,10 @@ protected LivingEntity spawnCreature(String creatureType, Location loc, String n // -------------------------------------------------------------------------- /** * Ensure that the doppelganger is wearing the specified player's head. - * + * * If the creature was configured to be wearing a skull as a helmet, customise * that skull item so that settings from the configuration are retained. - * + * * @param doppelganger the creature. * @param name the name of the player whose head will be worn. */ @@ -476,7 +476,7 @@ protected static void setPlayerHead(LivingEntity doppelganger, String name) // -------------------------------------------------------------------------- /** * Map from lower case shape name to {@link CreatureShape} instance. - * + * * Use a LinkedHashMap to preserve the ordering defined in the configuration * file. That way earlier entries have precedence over later ones. */ diff --git a/src/io/github/totemo/doppelganger/CreatureShape.java b/src/io/github/totemo/doppelganger/CreatureShape.java index d188633..d5ddc98 100644 --- a/src/io/github/totemo/doppelganger/CreatureShape.java +++ b/src/io/github/totemo/doppelganger/CreatureShape.java @@ -25,9 +25,9 @@ public class CreatureShape // -------------------------------------------------------------------------- /** * Load this CreatureShape from the specified section. - * + * * The expected format is: - * + * *
    *    head: pumpkin
    *    body:
@@ -39,12 +39,12 @@ public class CreatureShape
    *    - weight: 1.0
    *      spawn: ToughWitherSkeleton
    * 
- * + * * Note that the "body" can be omitted, in which case placing a named head * block will summon a creature. Also, the "summon" can be omitted, in which * case nothing will be summoned by default. This may still be useful if * specific player names override what is summoned. - * + * * @param section the configuration section to load. * @param logger logs messages. * @return a new CreatureShape instance, or null on error. @@ -142,7 +142,7 @@ public static CreatureShape loadFromSection(ConfigurationSection section, Logger // -------------------------------------------------------------------------- /** * Constructor. - * + * * @param name the name of this shape in the configuration. * @param triggerMaterial the Material of the final placed block that triggers * creature spawning. @@ -152,14 +152,14 @@ public static CreatureShape loadFromSection(ConfigurationSection section, Logger public CreatureShape(String name, Material triggerMaterial, boolean enabled) { _name = name; - _triggerMaterialId = triggerMaterial.getId(); + _triggerMaterial = triggerMaterial; _enabled = enabled; } // -------------------------------------------------------------------------- /** * Return the name of this shape in the configuration. - * + * * @return the name of this shape in the configuration. */ public String getName() @@ -169,19 +169,19 @@ public String getName() // -------------------------------------------------------------------------- /** - * Return the Material ID of the trigger. - * - * @return the Material ID of the trigger. + * Return the Material of the trigger. + * + * @return the Material of the trigger. */ - public int getTriggerMaterialId() + public Material getTriggerMaterial() { - return _triggerMaterialId; + return _triggerMaterial; } // -------------------------------------------------------------------------- /** * Return true if building this shape will summon a doppelganger. - * + * * @return true if building this shape will summon a doppelganger. */ public boolean isEnabled() @@ -193,10 +193,10 @@ public boolean isEnabled() /** * Signify that the {@link CreatureType} signified by its name can be summoned * by this shape, with the specified weighted probability. - * + * * The chance of a specific {@link CreatureType} being spawned is its weight * divided by the sum of the weights of all registered types for this shape. - * + * * @param type the name of the {@link CreatureType}. * @param weight the probability weight. */ @@ -208,10 +208,10 @@ public void addCreatureType(String type, double weight) // -------------------------------------------------------------------------- /** * Return the name of the spawned CreatureType. - * + * * If more than one {@link CreatureType} is associated with this shape, a type * will be selected at random according to weighted probability. - * + * * @return the type name of the spawned CreatureType. */ public String chooseCreatureType() @@ -222,13 +222,13 @@ public String chooseCreatureType() // -------------------------------------------------------------------------- /** * Define the Material its position relative to the trigger block. - * + * * @param material the Material of the pre-placed creature block. * @param offset the position of that relative to the final trigger block. */ public void addCreatureBlock(Material material, Vector offset) { - _materialIds.add(material.getId()); + _materials.add(material); _offsets.add(offset); if (offset.getBlockY() < _groundOffset) { @@ -240,31 +240,31 @@ public void addCreatureBlock(Material material, Vector offset) /** * Return true if this shape is enabled and placing an item of the specified * type at the specified Location would result in this creature shape. - * + * * @param loc the location where the trigger block would be placed. - * @param placedItemId the ID of the placed block. + * @param placedMaterial the Material of the placed block. * @return true if placing the specified block at the specified location would * result in a complete creature shape. */ - public boolean isComplete(Location loc, int placedItemId) + public boolean isComplete(Location loc, Material placedMaterial) { - return isEnabled() && _triggerMaterialId == placedItemId && isCreatureShape(loc); + return isEnabled() && _triggerMaterial == placedMaterial && isCreatureShape(loc); } // -------------------------------------------------------------------------- /** * Return true if placing the trigger block at the specified Location would * result in a complete creature shape. - * + * * @param loc the location where the trigger block would be placed. * @return true if placing the trigger block at the specified location would * result in a complete creature shape. */ public boolean isCreatureShape(Location loc) { - for (int i = 0; i < _materialIds.size(); ++i) + for (int i = 0; i < _materials.size(); ++i) { - if (getCreatureBlock(loc, i).getTypeId() != _materialIds.get(i)) + if (getCreatureBlock(loc, i).getType() != _materials.get(i)) { return false; } @@ -276,21 +276,21 @@ public boolean isCreatureShape(Location loc) /** * Set all of the blocks of the creature shape at the specified location to * air. - * + * * @param loc the location where the trigger block would be placed. */ public void vaporise(Location loc) { for (int i = 0; i < _offsets.size(); ++i) { - getCreatureBlock(loc, i).setTypeId(0); + getCreatureBlock(loc, i).setType(Material.AIR); } } // -------------------------------------------------------------------------- /** * Return the offset in Y coordinate of the lowest blocks in the shape. - * + * * @return the offset in Y coordinate of the lowest blocks in the shape. */ public int getGroundOffset() @@ -301,23 +301,22 @@ public int getGroundOffset() // -------------------------------------------------------------------------- /** * Print a description of this shape to the command sender. - * + * * @param sender the entity requesting the description. */ public void describe(CommandSender sender) { sender.sendMessage(ChatColor.GOLD + "Shape " + getName() + ":"); sender.sendMessage(ChatColor.GOLD + " Enabled: " + ChatColor.YELLOW + isEnabled()); - sender.sendMessage(ChatColor.GOLD + " Head material: " + ChatColor.YELLOW - + Material.getMaterial(getTriggerMaterialId()).toString()); + sender.sendMessage(ChatColor.GOLD + " Head material: " + ChatColor.YELLOW + getTriggerMaterial()); sender.sendMessage(ChatColor.GOLD + " Y offset to ground: " + ChatColor.YELLOW + getGroundOffset()); - if (_materialIds.size() != 0) + if (_materials.size() != 0) { sender.sendMessage(ChatColor.GOLD + " Body: "); - for (int i = 0; i < _materialIds.size(); ++i) + for (int i = 0; i < _materials.size(); ++i) { sender.sendMessage(String.format("%s (%d) %s at (%d, %d, %d)", - ChatColor.YELLOW, i + 1, Material.getMaterial(_materialIds.get(i)).toString(), + ChatColor.YELLOW, i + 1, _materials.get(i).toString(), _offsets.get(i).getBlockX(), _offsets.get(i).getBlockY(), _offsets.get(i).getBlockZ())); } } @@ -358,11 +357,11 @@ public void describe(CommandSender sender) * Check that there is 1 block wide border of air around the bounding box of * the creature shape in all horizontal directions (but not above or below the * bounding box). - * + * * The purpose of this is to prevent the use of Doppelganger spawning as a way * to grief a pre-existing structure that was not built for the purpose of * spawning a Doppelganger. - * + * * @param loc the Location of the final head block. * @return true if the required border is present around the shape. */ @@ -374,7 +373,7 @@ public boolean hasBorder(Location loc) int x = loc.getBlockX() + offset.getBlockX(); int y = loc.getBlockY() + offset.getBlockY(); int z = loc.getBlockZ() + offset.getBlockZ(); - if (loc.getWorld().getBlockTypeIdAt(x, y, z) != 0) + if (loc.getWorld().getBlockAt(x, y, z).getType() != Material.AIR) { return false; } @@ -386,7 +385,7 @@ public boolean hasBorder(Location loc) /** * Return the Block with the specified index comprising the creature shape, * relative to the location of the trigger block. - * + * * @param loc the Location of the trigger block. * @param index the 0-based index of the block in the shape; 0 is first one * added. @@ -457,10 +456,10 @@ protected void computeBorder() /** * Return true if the specified (x,y,z) offset from the head location is a * body block. - * + * * This method is only called from computeBorder(), which happens only while * the shape is being loaded. - * + * * @return true if the specified (x,y,z) offset from the head location is a * body block. */ @@ -486,17 +485,17 @@ protected boolean hasBodyOffset(int x, int y, int z) // -------------------------------------------------------------------------- /** * Dump internal state to the specified Logger for debugging. - * + * * @param logger the Logger. */ protected void dump(Logger logger) { - logger.info("Trigger: " + Material.getMaterial(_triggerMaterialId).name()); + logger.info("Trigger: " + _triggerMaterial.name()); logger.info("Ground offset: " + _groundOffset); logger.info("Blocks:"); - for (int i = 0; i < _materialIds.size(); ++i) + for (int i = 0; i < _materials.size(); ++i) { - String material = Material.getMaterial(_materialIds.get(i)).name(); + String material = _materials.get(i).name(); String offset = _offsets.get(i).toString(); logger.info(i + ": " + material + " at " + offset); } @@ -513,10 +512,10 @@ protected void dump(Logger logger) protected String _name; /** - * The material of the placed, named block that triggers a search for a + * The Material of the placed, named block that triggers a search for a * creature shape. */ - protected int _triggerMaterialId; + protected Material _triggerMaterial; /** * True if building this shape will summon a doppelganger. @@ -529,9 +528,9 @@ protected void dump(Logger logger) protected int _groundOffset; /** - * Expected Material ID at corresponding offset from trigger block. + * Expected Material at corresponding offset from trigger block. */ - protected ArrayList _materialIds = new ArrayList(); + protected ArrayList _materials = new ArrayList(); /** * Offset relative to trigger block to look for corresponding _materials diff --git a/src/io/github/totemo/doppelganger/CreatureType.java b/src/io/github/totemo/doppelganger/CreatureType.java index c6d92e4..f623042 100644 --- a/src/io/github/totemo/doppelganger/CreatureType.java +++ b/src/io/github/totemo/doppelganger/CreatureType.java @@ -35,9 +35,9 @@ public class CreatureType // -------------------------------------------------------------------------- /** * Load this CreatureType from the specified section. - * + * * The expected format is: - * + * *
    * spawn: WitherSkeleton
    * despawns: false
@@ -50,7 +50,7 @@ public class CreatureType
    * potions:
    * - type: invisibility
    * 
- * + * * @param name the name of the creature to load. * @param section the configuration section to load. * @param logger logs messages. @@ -91,7 +91,7 @@ public static CreatureType loadFromSection(ConfigurationSection section, Logger } if (section.isSet("health")) { - type._health = Math.max(1, section.getInt("health", 20)); + type._health = (double) Math.max(1, section.getInt("health", 20)); } if (section.isSet("air")) { @@ -140,6 +140,7 @@ public static CreatureType loadFromSection(ConfigurationSection section, Logger type._leggings = loadItem(section.getConfigurationSection("leggings"), logger); type._boots = loadItem(section.getConfigurationSection("boots"), logger); type._weapon = loadItem(section.getConfigurationSection("weapon"), logger); + type._shield = loadItem(section.getConfigurationSection("shield"), logger); if (section.isSet("helmet.dropchance")) { type._helmetDropChance = section.getDouble("helmet.dropchance"); @@ -160,6 +161,10 @@ public static CreatureType loadFromSection(ConfigurationSection section, Logger { type._weaponDropChance = section.getDouble("weapon.dropchance"); } + if (section.isSet("shield.dropchance")) + { + type._shieldDropChance = section.getDouble("shield.dropchance"); + } // Escorts. if (section.isConfigurationSection("escorts")) @@ -173,7 +178,7 @@ public static CreatureType loadFromSection(ConfigurationSection section, Logger // -------------------------------------------------------------------------- /** * Constructor. - * + * * @param name a unique identifier for this type. * @param creatureType the type of creature to spawn. */ @@ -186,7 +191,7 @@ public CreatureType(String name, String creatureType) // -------------------------------------------------------------------------- /** * Return the unique identifier of this creature. - * + * * @return the unique identifier of this creature. */ public String getName() @@ -198,7 +203,7 @@ public String getName() /** * Return the name of the CreatureType instance upon which this instance is * based. - * + * * @return the name of the CreatureType instance upon which this instance is * based. */ @@ -210,7 +215,7 @@ public String getCreatureType() // -------------------------------------------------------------------------- /** * Return the type of creature that this creature is riding. - * + * * @return the type of creature that this creature is riding. If not set in * the configuration, it will be null. If null or set to the empty * string, nothing will be ridden. @@ -224,7 +229,7 @@ public String getMount() /** * Return the name of the player whose head this creature should always wear, * irrespective of the player name it was summoned with. - * + * * @return the name of the player whose head this creature should always wear, * irrespective of the player name it was summoned with, or null if * not set. @@ -239,7 +244,7 @@ public String getMask() * Return the default name tag to give this creature if no name is specified * when it spawns - either because it was spawned anonymous by command, or * because it was spawned as an escort mob. - * + * * @return the default name of this creature if not specified. */ public String getDefaultName() @@ -252,10 +257,10 @@ public String getDefaultName() * Return true if the creature should keep wearing whatever helmet it was * configured with rather than wearing the player head corresponding to its * name or mask. - * + * * If this is false (the default), a name or mask will force the creature to * wear that player's head. - * + * * @return the default name of this creature if not specified. */ public boolean getKeepHelmet() @@ -267,7 +272,7 @@ public boolean getKeepHelmet() // -------------------------------------------------------------------------- /** * Do sound and damage-free lighting strike effects. - * + * * @param plugin the originating Plugin. * @param loc the Location where the creature will spawn. */ @@ -293,7 +298,7 @@ public void doSpawnEffects(Plugin plugin, Location loc) // -------------------------------------------------------------------------- /** * Spawn escorts of this creature, if they have been defined. - * + * * @param plugin the Doppelganger plugin. * @param centre the Location where the creature will spawn and the centre of * the circle within which escorts can spawn. @@ -320,7 +325,7 @@ public void run() /** * Apply the custom attributes embodied by this type to the specified * creature. - * + * * @param entity the creature to customise. */ public void customise(LivingEntity entity) @@ -394,18 +399,26 @@ public void customise(LivingEntity entity) } if (_weapon != null) { - entity.getEquipment().setItemInHand(_weapon); + entity.getEquipment().setItemInMainHand(_weapon); } if (_weaponDropChance != null) { - entity.getEquipment().setItemInHandDropChance(_weaponDropChance.floatValue()); + entity.getEquipment().setItemInMainHandDropChance(_weaponDropChance.floatValue()); + } + if (_shield != null) + { + entity.getEquipment().setItemInOffHand(_shield); + } + if (_shieldDropChance != null) + { + entity.getEquipment().setItemInOffHandDropChance(_shieldDropChance.floatValue()); } } // customise // -------------------------------------------------------------------------- /** * Print a description of this CreatureType to the command sender. - * + * * @param sender the entity requesting the description. */ public void describe(CommandSender sender) @@ -480,6 +493,7 @@ public void describe(CommandSender sender) describeItem(sender, " Leggings: ", _leggings, _leggingsDropChance); describeItem(sender, " Boots: ", _boots, _bootsDropChance); describeItem(sender, " Weapon: ", _weapon, _weaponDropChance); + describeItem(sender, " Shield: ", _shield, _shieldDropChance); if (_maxEscorts > 0) { sender.sendMessage(String.format( @@ -502,9 +516,9 @@ public void describe(CommandSender sender) /** * Send a human-readable description of the specified item to the command * sender. - * + * * This method is called by describe(). - * + * * @param sender the actor issuing the command and receiving output. * @param heading the heading of the description. * @param item the (assumed non-null) item to describe. @@ -577,7 +591,7 @@ protected static void describeItem(CommandSender sender, String heading, ItemSta /** * Load the potion effects defined in the "potions" section of this * CreatureType's configuration - * + * * @param potions the "potions" ConfigurationSection. * @param logger logs messages. */ @@ -627,7 +641,7 @@ protected void loadPotions(List> potions, Logger logger) /** * Load an item (armour or weapon, with optional enchants) and return it as an * ItemStack. - * + * * @param section the configuration section to load from. * @param logger logs messages. */ @@ -750,7 +764,7 @@ else if (isLeatherArmour(material)) /** * Return true if the specified Material is one of the four leather armour * items. - * + * * @param material the item material. * @return true if the specified Material is one of the four leather armour * items. @@ -766,7 +780,7 @@ protected static boolean isLeatherArmour(Material material) // -------------------------------------------------------------------------- /** * Log a warning message if the value is not in the range [min,max]. - * + * * @param logger the logger. * @param name the name used to describe the value in the message. * @param value the value. @@ -787,7 +801,7 @@ protected static boolean checkInteger(Logger logger, String name, int value, int // -------------------------------------------------------------------------- /** * Load the description of the escort mobs from the configuration. - * + * * @param escorts the "escorts" section of the current creature, if such a * section exists. * @param logger used to log messages. @@ -831,7 +845,7 @@ protected void loadEscorts(ConfigurationSection escorts, Logger logger) /** * Schedule a random, damage-free lighting strike effect around the specified * Location. - * + * * @param plugin the originating Plugin. * @param centre the centre of the random coordinate range. * @param minRange the minimum distance of the strike from centre on the X-Z @@ -859,7 +873,7 @@ public void run() /** * Select a random location at the same altitude as the centre, between * minRange and maxRange blocks distant in the X-Z plane. - * + * * @param centre the average location returned. * @param minRange minimum distance from centre in blocks. * @param maxRange maximum distance from centre in blocks. @@ -880,9 +894,9 @@ protected static Location randomLocation(Location centre, double minRange, doubl /** * Translate colour and formatting codes preceded by ampersand and replace * C-style backslash escape sequences for \n with that characters. - * + * * The game currently doesn't understand \t (tabs), so they are not supported. - * + * * @param text the text to translate; can be null. * @return the translated text. If the text parameter was null, return null. */ @@ -928,10 +942,10 @@ protected static String translate(String text) * Instead it will keep whatever helmet it was configured with. If false (the * default if omitted), the creature will wear a player's head if given a * name. - * + * * The "keephelmet:" configuration setting takes precedence over the "mask:" * setting when both are specified. - * + * * Store a Boolean rather than boolean, so we can keep track of whether a * value was explicitly specified in the configuration, for describe(). */ @@ -950,7 +964,7 @@ protected static String translate(String text) /** * Maximum health in half-hearts. Null if not set in the configuration. */ - protected Integer _health; + protected Double _health; /** * The lung capacity of the creature in ticks. Null if not set in the @@ -1026,10 +1040,15 @@ protected static String translate(String text) protected ItemStack _boots; /** - * Item in hand. Null if not set in the configuration. + * Item in the main hand. Null if not set in the configuration. */ protected ItemStack _weapon; + /** + * Item in the off hand. Null if not set in the configuration. + */ + protected ItemStack _shield; + /** * Chance of dropping helmet, [0.0, 1.0]. Null if not set in the * configuration. @@ -1054,11 +1073,17 @@ protected static String translate(String text) protected Double _bootsDropChance; /** - * Chance of dropping item in hand, [0.0, 1.0]. Null if not set in the - * configuration. + * Chance of dropping the item in the main hand, [0.0, 1.0]. Null if not set + * in the configuration. */ protected Double _weaponDropChance; + /** + * Chance of dropping the item in the off hand, [0.0, 1.0]. Null if not set + * in the configuration. + */ + protected Double _shieldDropChance; + /** * Minimum number of escort creatures. */ diff --git a/src/io/github/totemo/doppelganger/Doppelganger.java b/src/io/github/totemo/doppelganger/Doppelganger.java index dd1ed9b..a4162b3 100644 --- a/src/io/github/totemo/doppelganger/Doppelganger.java +++ b/src/io/github/totemo/doppelganger/Doppelganger.java @@ -31,7 +31,7 @@ public class Doppelganger extends JavaPlugin implements Listener // -------------------------------------------------------------------------- /** * Return the configuration. - * + * * @return the configuration. */ public Configuration getConfiguration() @@ -42,7 +42,7 @@ public Configuration getConfiguration() // -------------------------------------------------------------------------- /** * Return the {@link CreatureFactory}. - * + * * @return the {@link CreatureFactory}. */ public CreatureFactory getCreatureFactory() @@ -73,10 +73,10 @@ public void onEnable() // -------------------------------------------------------------------------- /** * Event handler for placing blocks.message - * + * * Checks that a named item is stacked on a configured shape made of blocks of * the requisite material. - * + * * @param event the event. */ @EventHandler(ignoreCancelled = true) @@ -112,7 +112,7 @@ public void onBlockPlace(BlockPlaceEvent event) CreatureShape shape = null; for (CreatureShape tryShape : shapes) { - if (tryShape.isComplete(loc, placedItem.getTypeId())) + if (tryShape.isComplete(loc, placedItem.getType())) { if (tryShape.hasBorder(loc)) { @@ -139,7 +139,7 @@ public void onBlockPlace(BlockPlaceEvent event) { // Generic case where the doppelganger name doesn't matter. // Check whether there is a complete creature under the trigger block. - CreatureShape shape = _creatureFactory.getCreatureShape(loc, event.getPlayer().getItemInHand()); + CreatureShape shape = _creatureFactory.getCreatureShape(loc, event.getPlayer().getEquipment().getItemInMainHand()); if (shape != null) { if (shape.hasBorder(loc)) @@ -174,11 +174,11 @@ public void onBlockPlace(BlockPlaceEvent event) * Vanilla Minecraft doesn't always drop equipment when the drop chance is 1.0 * (or more). Try to work around that by moving the equipment into the drops * if it is not already there. - * + * * In Bukkit versions prior to 1.7.9, the equipment was not part of the drops * list in the EntityDeathEvent. Bukkit fixed that issue with the API, but had * to retain vanilla's handling of drop probabilities, which is still faulty. - * + * * This handler will process any entity death, but naturally spawned monsters * probably won't have a (near) 1.0 drop chance for the their equipment, and * in any case the relocation of the equipment to drops should be benign. @@ -235,11 +235,11 @@ public void onEntityDeath(EntityDeathEvent event) if (equipment.getItemInHandDropChance() > NEAR_UNITY) { forcedDrops = true; - ItemStack itemInHand = equipment.getItemInHand(); + ItemStack itemInHand = equipment.getItemInMainHand(); if (itemInHand != null && !drops.contains(itemInHand)) { drops.add(itemInHand); - equipment.setItemInHand(null); + equipment.setItemInMainHand(null); } } } @@ -267,7 +267,7 @@ public void onEntityDeath(EntityDeathEvent event) // -------------------------------------------------------------------------- /** * Spawn a doppelganger of the specified type and name. - * + * * @param creatureType the type of creature to spawn. * @param name the name to show on the name tag. This is also the name of the * player whose head will be worn, unless the creature type includes @@ -288,7 +288,7 @@ public LivingEntity spawnDoppelganger(String creatureType, String name, Location /** * Cancel the original block placement, vaporise the golem blocks and spawn a * named LivingEntity of the specified type. - * + * * @param doppelgangerName the name of spawned creature. * @param creatureType the name of the type of creature to spawn. * @param shape the shape of the golem blocks. @@ -312,11 +312,11 @@ protected void doDoppelganger(String doppelgangerName, String creatureType, Crea if (placedItem.getAmount() > 1) { placedItem.setAmount(placedItem.getAmount() - 1); - event.getPlayer().setItemInHand(placedItem); + event.getPlayer().getEquipment().setItemInMainHand(placedItem); } else { - event.getPlayer().setItemInHand(null); + event.getPlayer().getEquipment().setItemInMainHand(null); } // Vaporise the shape blocks.