protected SpellResult alterEntity(Entity entity) { EntityType entityType = entity.getType(); switch (entityType) { case PAINTING: registerModified(entity); Painting painting = (Painting) entity; Art[] artValues = Art.values(); Art oldArt = painting.getArt(); Art newArt = oldArt; int ordinal = (oldArt.ordinal() + 1); for (int i = 0; i < artValues.length; i++) { newArt = artValues[ordinal++ % artValues.length]; painting.setArt(newArt); newArt = painting.getArt(); if (oldArt != newArt) { break; } } if (oldArt == newArt) { return SpellResult.FAIL; } mage.sendDebugMessage("Altering art from " + oldArt + " to " + newArt); break; case ITEM_FRAME: ItemFrame itemFrame = (ItemFrame) entity; ItemStack frameItem = itemFrame.getItem(); if (frameItem == null || frameItem.getType() != Material.MAP) { return SpellResult.NO_TARGET; } short data = frameItem.getDurability(); data++; MapView mapView = DeprecatedUtils.getMap(data); if (mapView == null) { data = 0; mapView = DeprecatedUtils.getMap(data); if (mapView == null) { return SpellResult.NO_TARGET; } } registerModified(entity); frameItem.setDurability(data); itemFrame.setItem(frameItem); break; case HORSE: registerModified(entity); Horse horse = (Horse) entity; Color color = horse.getColor(); Color[] colorValues = Color.values(); color = colorValues[(color.ordinal() + 1) % colorValues.length]; Variant variant = horse.getVariant(); Variant[] variantValues = Variant.values(); variant = variantValues[(variant.ordinal() + 1) % variantValues.length]; Style horseStyle = horse.getStyle(); Style[] styleValues = Style.values(); horseStyle = styleValues[(horseStyle.ordinal() + 1) % styleValues.length]; horse.setStyle(horseStyle); horse.setColor(color); horse.setVariant(variant); break; case OCELOT: registerModified(entity); Ocelot ocelot = (Ocelot) entity; Type catType = ocelot.getCatType(); Type[] typeValues = Type.values(); catType = typeValues[(catType.ordinal() + 1) % typeValues.length]; ocelot.setCatType(catType); break; case VILLAGER: registerModified(entity); Villager villager = (Villager) entity; Profession profession = villager.getProfession(); Profession[] professionValues = Profession.values(); profession = professionValues[(profession.ordinal() + 1) % professionValues.length]; villager.setProfession(profession); break; case WOLF: registerModified(entity); Wolf wolf = (Wolf) entity; DyeColor wolfColor = wolf.getCollarColor(); DyeColor[] wolfColorValues = DyeColor.values(); wolfColor = wolfColorValues[(wolfColor.ordinal() + 1) % wolfColorValues.length]; wolf.setCollarColor(wolfColor); break; case SHEEP: registerModified(entity); Sheep sheep = (Sheep) entity; DyeColor dyeColor = sheep.getColor(); DyeColor[] dyeColorValues = DyeColor.values(); dyeColor = dyeColorValues[(dyeColor.ordinal() + 1) % dyeColorValues.length]; sheep.setColor(dyeColor); break; case SKELETON: registerModified(entity); Skeleton skeleton = (Skeleton) entity; SkeletonType skeletonType = skeleton.getSkeletonType(); SkeletonType[] skeletonTypeValues = SkeletonType.values(); skeletonType = skeletonTypeValues[(skeletonType.ordinal() + 1) % skeletonTypeValues.length]; skeleton.setSkeletonType(skeletonType); break; default: return SpellResult.NO_TARGET; } ; registerForUndo(); return SpellResult.CAST; }
@Override public int process(int maxBlocks) { int processedBlocks = 0; if (state == SimulationState.SCANNING_COMMAND) { // Process the casting command block first, and only if specially configured to do so. if (includeCommands && castCommandBlock != null) { // We are going to rely on the block toggling to kick this back to life when the chunk // reloads, so for now just bail and hope the timing works out. if (!castCommandBlock.getChunk().isLoaded()) { finish(); // TODO: Maybe Scatter-shot and register all 6 surrounding power blocks for reload toggle. // Can't really do it without the chunk being loaded though, so hrm. return processedBlocks; } // Check for death since activation (e.g. during delay period) if (castCommandBlock.getType() != Material.COMMAND) { die(); finish(); return processedBlocks; } // Check for power blocks for (BlockFace powerFace : POWER_FACES) { Block checkForPower = castCommandBlock.getRelative(powerFace); if (checkForPower.getType() == POWER_MATERIAL) { if (commandReload) { controller.unregisterAutomata(checkForPower); } powerSimMaterial.modify(checkForPower); commandPowered = true; } } if (!commandPowered) { die(); finish(); return processedBlocks; } // Make this a normal block so the sim will process it // this also serves to reset the command block for the next tick, if it lives. birthMaterial.modify(castCommandBlock); } processedBlocks++; state = SimulationState.SCANNING; } while (state == SimulationState.SCANNING && processedBlocks <= maxBlocks) { if (!simulateBlocks(x, y, z)) { return processedBlocks; } y++; if (y > yRadius) { y = 0; if (x < radius) { x++; } else { z--; if (z < 0) { r++; z = r; x = 0; } } } if (r > radius) { state = SimulationState.UPDATING; } } while (state == SimulationState.UPDATING && processedBlocks <= maxBlocks) { int deadIndex = updatingIndex; if (deadIndex >= 0 && deadIndex < deadBlocks.size()) { Block killBlock = deadBlocks.get(deadIndex); if (!killBlock.getChunk().isLoaded()) { killBlock.getChunk().load(); return processedBlocks; } if (birthMaterial.is(killBlock)) { registerForUndo(killBlock); killBlock.setType(deathMaterial); } else { // If this block was destroyed while we were processing, // avoid spawning a random birth block. // This tries to make it so automata don't "cheat" when // getting destroyed. A bit hacky though, I'm not about // to re-simulate... if (bornBlocks.size() > 0) { bornBlocks.remove(bornBlocks.size() - 1); } } processedBlocks++; } int bornIndex = updatingIndex - deadBlocks.size(); if (bornIndex >= 0 && bornIndex < bornBlocks.size()) { Block birthBlock = bornBlocks.get(bornIndex); if (!birthBlock.getChunk().isLoaded()) { birthBlock.getChunk().load(); return processedBlocks; } registerForUndo(birthBlock); birthMaterial.modify(birthBlock); } updatingIndex++; if (updatingIndex >= deadBlocks.size() + bornBlocks.size()) { state = SimulationState.COMMAND_SEARCH; // Wait at least a tick before re-populating the command block. return maxBlocks; } } // Each of the following states will end in this tick, to give the // MC sim time to register power updates. if (state == SimulationState.COMMAND_SEARCH) { if (includeCommands && potentialCommandBlocks.size() > 0) { switch (targetMode) { case HUNT: Collections.sort(potentialCommandBlocks); break; case FLEE: Collections.sort(potentialCommandBlocks); break; default: Collections.shuffle(potentialCommandBlocks); break; } // Find a valid block for the command powerTargetBlock = null; commandTargetBlock = null; Block backupBlock = null; while (commandTargetBlock == null && potentialCommandBlocks.size() > 0) { Block block = potentialCommandBlocks.remove(0).getBlock(); if (block != null && birthMaterial.is(block)) { // If we're powering the block, look for one with a powerable neighbor. if (!commandPowered) { commandTargetBlock = block; } else { backupBlock = block; BlockFace powerFace = findPowerLocation(block, powerSimMaterial); if (powerFace != null) { commandTargetBlock = block; } } } } // If we didn't find any powerable blocks, but we did find at least one valid sim block // just use that one. if (commandTargetBlock == null) commandTargetBlock = backupBlock; // Search for a power block if (commandTargetBlock != null) { // First try and replace a live cell BlockFace powerDirection = findPowerLocation(commandTargetBlock, powerSimMaterial); // Next try to replace a dead cell, which will affect the simulation outcome // but this is perhaps better than it dying? if (powerDirection == null) { if (DEBUG) { controller .getLogger() .info("Had to fall back to backup location, pattern may diverge"); } powerDirection = findPowerLocation(commandTargetBlock, powerSimMaterialBackup); } // If it's *still* not valid, search for something breakable. if (powerDirection == null) { for (BlockFace face : POWER_FACES) { if (blockSpell.isDestructible(commandTargetBlock.getRelative(face))) { if (DEBUG) { controller .getLogger() .info( "Had to fall back to destructible location, pattern may diverge and may destroy blocks"); } powerDirection = face; break; } } } if (powerDirection != null) { powerTargetBlock = commandTargetBlock.getRelative(powerDirection); } } } if (DEBUG) { if (commandTargetBlock != null) { controller .getLogger() .info( "MOVED: " + commandTargetBlock.getLocation().toVector().subtract(center.toVector())); } } state = SimulationState.COMMON_RESET_REDSTONE; return processedBlocks; } if (state == SimulationState.COMMON_RESET_REDSTONE) { if (includeCommands && commandTargetBlock != null) { DeprecatedUtils.setData(commandTargetBlock, (byte) 0); } if (includeCommands && powerTargetBlock != null) { DeprecatedUtils.setData(powerTargetBlock, (byte) 0); } state = SimulationState.COMMAND_UPDATE; return processedBlocks; } if (state == SimulationState.COMMAND_UPDATE) { if (includeCommands) { if (commandTargetBlock != null) { if (!commandTargetBlock.getChunk().isLoaded()) { commandTargetBlock.getChunk().load(); return processedBlocks; } commandTargetBlock.setType(Material.COMMAND); BlockState commandData = commandTargetBlock.getState(); if (castCommand != null && commandData != null && commandData instanceof CommandBlock) { CommandBlock copyCommand = (CommandBlock) commandData; copyCommand.setCommand(castCommand); copyCommand.setName(commandName); copyCommand.update(); // Also move the mage Location newLocation = commandTargetBlock.getLocation(); newLocation.setPitch(center.getPitch()); newLocation.setYaw(center.getYaw()); mage.setLocation(newLocation); } else { commandTargetBlock = null; } } else { die(); } } powerDelayTicks = POWER_DELAY_TICKS; state = SimulationState.COMMAND_POWER; return processedBlocks; } if (state == SimulationState.COMMAND_POWER) { // Continue to power the command block if (commandPowered && powerTargetBlock != null && includeCommands) { // Wait a bit before powering for redstone signals to reset if (powerDelayTicks > 0) { powerDelayTicks--; return processedBlocks; } if (powerTargetBlock != null) { powerTargetBlock.setType(POWER_MATERIAL); if (commandReload) { String automataName = commandName; if (automataName == null || automataName.length() <= 1) { automataName = controller.getMessages().get("automata.default_name"); } controller.registerAutomata(powerTargetBlock, automataName, "automata.awaken"); } } } state = SimulationState.FINISHED; return processedBlocks; } if (state == SimulationState.FINISHED) { finish(); } return processedBlocks; }