Exemple #1
0
  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;
  }