Package forestry.apiculture.genetics

Source Code of forestry.apiculture.genetics.Bee

/*******************************************************************************
* Copyright (c) 2011-2014 SirSengir.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Various Contributors including, but not limited to:
* SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges
******************************************************************************/
package forestry.apiculture.genetics;

import forestry.api.apiculture.EnumBeeChromosome;
import forestry.api.apiculture.IAlleleBeeEffect;
import forestry.api.apiculture.IAlleleBeeSpecies;
import forestry.api.apiculture.IApiaristTracker;
import forestry.api.apiculture.IBee;
import forestry.api.apiculture.IBeeGenome;
import forestry.api.apiculture.IBeeHousing;
import forestry.api.apiculture.IBeeMutation;
import forestry.api.apiculture.IBeekeepingMode;
import forestry.api.core.EnumHumidity;
import forestry.api.core.EnumTemperature;
import forestry.api.genetics.AlleleManager;
import forestry.api.genetics.IAllele;
import forestry.api.genetics.IAlleleTolerance;
import forestry.api.genetics.IChromosome;
import forestry.api.genetics.IEffectData;
import forestry.api.genetics.IFlowerProvider;
import forestry.api.genetics.IGenome;
import forestry.api.genetics.IIndividual;
import forestry.api.genetics.IPollinatable;
import forestry.core.EnumErrorCode;
import forestry.core.config.Defaults;
import forestry.core.genetics.Chromosome;
import forestry.core.genetics.GenericRatings;
import forestry.core.genetics.IndividualLiving;
import forestry.core.proxy.Proxies;
import forestry.core.utils.StackUtils;
import forestry.core.utils.StringUtil;
import forestry.core.utils.Utils;
import forestry.core.utils.Vect;
import forestry.plugins.PluginApiculture;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.common.BiomeDictionary;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Bee extends IndividualLiving implements IBee {

  public IBeeGenome genome;
  public IBeeGenome mate;

  /* CONSTRUCTOR */
  public Bee(NBTTagCompound nbttagcompound) {
    readFromNBT(nbttagcompound);
  }

  public Bee(World world, IBeeGenome genome, IBee mate) {
    this(world, genome);
    this.mate = mate.getGenome();
    this.isIrregularMating = mate.isNatural() != this.isNatural;
  }

  public Bee(IBeeGenome genome, IBee mate) {
    this(genome);
    this.mate = mate.getGenome();
    this.isIrregularMating = mate.isNatural() != this.isNatural;
  }

  public Bee(World world, IBeeGenome genome) {
    this(world, genome, true, 0);
  }

  public Bee(IBeeGenome genome) {
    this(genome, true, 0);
  }

  public Bee(World world, IBeeGenome genome, boolean isNatural, int generation) {
    super(genome.getLifespan(), isNatural, generation);
    this.genome = genome;
  }

  public Bee(IBeeGenome genome, boolean isNatural, int generation) {
    super(genome.getLifespan(), isNatural, generation);
    this.genome = genome;
  }

  /* SAVING & LOADING */
  @Override
  public void readFromNBT(NBTTagCompound nbttagcompound) {

    if (nbttagcompound == null) {
      this.genome = PluginApiculture.beeInterface.templateAsGenome(BeeTemplates.getForestTemplate());
      return;
    }

    super.readFromNBT(nbttagcompound);

    if (nbttagcompound.hasKey("Genome"))
      genome = new BeeGenome(nbttagcompound.getCompoundTag("Genome"));
    else
      genome = PluginApiculture.beeInterface.templateAsGenome(BeeTemplates.getForestTemplate());
    if (nbttagcompound.hasKey("Mate"))
      mate = new BeeGenome(nbttagcompound.getCompoundTag("Mate"));

  }

  @Override
  public void mate(IIndividual individual) {
    if(!(individual instanceof IBee))
      return;

    IBee drone = (IBee)individual;
    mate = drone.getGenome();
    this.isIrregularMating = drone.isNatural() != this.isNatural;
  }

  /* EFFECTS */
  @Override
  public IEffectData[] doEffect(IEffectData[] storedData, IBeeHousing housing) {
    IAlleleBeeEffect effect = genome.getEffect();

    if (effect == null)
      return null;

    storedData[0] = doEffect(effect, storedData[0], housing);

    // Return here if the primary can already not be combined
    if (!effect.isCombinable())
      return storedData;

    IAlleleBeeEffect secondary = (IAlleleBeeEffect) genome.getInactiveAllele(EnumBeeChromosome.EFFECT.ordinal());
    if (!secondary.isCombinable())
      return storedData;

    storedData[1] = doEffect(secondary, storedData[1], housing);

    return storedData;
  }

  private IEffectData doEffect(IAlleleBeeEffect effect, IEffectData storedData, IBeeHousing housing) {
    storedData = effect.validateStorage(storedData);
    return effect.doEffect(genome, storedData, housing);
  }

  @Override
  public IEffectData[] doFX(IEffectData[] storedData, IBeeHousing housing) {
    IAlleleBeeEffect effect = genome.getEffect();

    if (effect == null)
      return null;

    storedData[0] = doFX(effect, storedData[0], housing);

    // Return here if the primary can already not be combined
    if (!effect.isCombinable())
      return storedData;

    IAlleleBeeEffect secondary = (IAlleleBeeEffect) genome.getInactiveAllele(EnumBeeChromosome.EFFECT.ordinal());
    if (!secondary.isCombinable())
      return storedData;

    storedData[1] = doFX(secondary, storedData[1], housing);

    return storedData;
  }

  private IEffectData doFX(IAlleleBeeEffect effect, IEffectData storedData, IBeeHousing housing) {
    return effect.doFX(genome, storedData, housing);
  }

  // / INFORMATION
  @Override
  public IBeeGenome getGenome() {
    return genome;
  }

  @Override
  public IBeeGenome getMate() {
    return mate;
  }

  @Override
  public IBee copy() {
    NBTTagCompound nbttagcompound = new NBTTagCompound();
    this.writeToNBT(nbttagcompound);
    return new Bee(nbttagcompound);

  }

  @Override
  public boolean canSpawn() {
    return mate != null;
  }

  @Override
  public int isWorking(IBeeHousing housing) {

    World world = housing.getWorld();
    // / Rain needs tolerant flyers
    if (world.isRaining() && !genome.getTolerantFlyer() && housing.getHumidity() != EnumHumidity.ARID && !housing.isSealed())
      return EnumErrorCode.ISRAINING.ordinal();

    // / Night or darkness requires nocturnal species
    if(world.isDaytime()) {
      if(!canWorkDuringDay())
        return EnumErrorCode.NOTNIGHT.ordinal();
    } else if (!canWorkAtNight() && !housing.isSelfLighted())
      return EnumErrorCode.NOTDAY.ordinal();

    if (world.getBlockLightValue(housing.getXCoord(), housing.getYCoord() + 2, housing.getZCoord()) > Defaults.APIARY_MIN_LEVEL_LIGHT) {
      if(!canWorkDuringDay())
        return EnumErrorCode.NOTGLOOMY.ordinal();
    } else if(!canWorkAtNight() && !housing.isSelfLighted())
      return EnumErrorCode.NOTLUCID.ordinal();

    // / No sky, except if in hell
    BiomeGenBase biome = BiomeGenBase.getBiome(housing.getBiomeId());
    if(biome == null)
      return EnumErrorCode.NOSKY.ordinal();
    if (!BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.NETHER) && !world.canBlockSeeTheSky(housing.getXCoord(), housing.getYCoord() + 3, housing.getZCoord())
        && !genome.getCaveDwelling() && !housing.isSunlightSimulated())
      return EnumErrorCode.NOSKY.ordinal();

    // / And finally climate check
    if (!checkSuitableClimate(housing.getTemperature(), housing.getHumidity()))
      return EnumErrorCode.INVALIDBIOME.ordinal();

    return EnumErrorCode.OK.ordinal();
  }

  private boolean canWorkAtNight() {
    return genome.getPrimary().isNocturnal() || genome.getNocturnal();
  }

  private boolean canWorkDuringDay() {
    return !genome.getPrimary().isNocturnal() || genome.getNocturnal();
  }

  private boolean checkBiomeHazard(BiomeGenBase biome) {

    EnumTemperature temperature = EnumTemperature.getFromValue(biome.temperature);
    EnumHumidity humidity = EnumHumidity.getFromValue(biome.rainfall);
    return AlleleManager.climateHelper.isWithinLimits(temperature, humidity,
        genome.getPrimary().getTemperature(), genome.getToleranceTemp(),
        genome.getPrimary().getHumidity(), genome.getToleranceHumid());
  }

  private boolean checkSuitableClimate(EnumTemperature temperature, EnumHumidity humidity) {

    return AlleleManager.climateHelper.isWithinLimits(temperature, humidity,
        genome.getPrimary().getTemperature(), genome.getToleranceTemp(),
        genome.getPrimary().getHumidity(), genome.getToleranceHumid());
  }

  @Override
  public boolean hasFlower(IBeeHousing housing) {

    IFlowerProvider provider = genome.getFlowerProvider();

    Vect coords = new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord());
    Vect posCurrent = new Vect(0, 0, 0);
    int[] areaAr = genome.getTerritory();
    Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f));

    if (area.x < 1)
      area.x = 1;
    if (area.y < 1)
      area.y = 1;
    if (area.z < 1)
      area.z = 1;

    Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2));

    boolean hasFlower = false;

    while (advancePosition(posCurrent, area)) {

      Vect posBlock = posCurrent.add(coords);
      posBlock = posBlock.add(offset);

      if (provider.isAcceptedFlower(housing.getWorld(), this, posBlock.x, posBlock.y, posBlock.z)) {
        hasFlower = true;
        break;
      }

    }

    return hasFlower;
  }

  private boolean advancePosition(Vect posCurrent, Vect area) {
    // Increment z first until end reached
    if (posCurrent.z < area.z - 1)
      posCurrent.z++;
    else {
      posCurrent.z = 0;

      if (posCurrent.x < area.x - 1)
        posCurrent.x++;
      else {
        posCurrent.x = 0;

        if (posCurrent.y < area.y - 1)
          posCurrent.y++;
        else
          return false;
      }
    }

    return true;
  }

  @Override
  public ArrayList<Integer> getSuitableBiomeIds() {
    ArrayList<Integer> suitableBiomes = new ArrayList<Integer>();
    for (BiomeGenBase biome : BiomeGenBase.getBiomeGenArray())
      if (checkBiomeHazard(biome))
        suitableBiomes.add(biome.biomeID);

    return suitableBiomes;
  }

  @Override
  public void addTooltip(List<String> list) {

    // No info 4 u!
    if (!isAnalyzed) {
      list.add("<" + StringUtil.localize("gui.unknown") + ">");
      return;
    }

    // You analyzed it? Juicy tooltip coming up!
    IAlleleBeeSpecies primary = genome.getPrimary();
    IAlleleBeeSpecies secondary = genome.getSecondary();
    if (!isPureBred(EnumBeeChromosome.SPECIES.ordinal()))
      list.add("\u00A79" + StringUtil.localize("bees.hybrid").replaceAll("%PRIMARY",primary.getName()).replaceAll("%SECONDARY",secondary.getName()));

    IAllele speed = genome.getActiveAllele(EnumBeeChromosome.SPEED.ordinal());
    String customWorker = "tooltip.worker." + speed.getUnlocalizedName().replaceFirst("gui.", "");
    if (StringUtil.canTranslate(customWorker))
      list.add(StringUtil.localize(customWorker));
    else
      list.add(speed.getName() + " " + StringUtil.localize("gui.worker"));

    list.add(genome.getActiveAllele(EnumBeeChromosome.LIFESPAN.ordinal()).getName() + " " + StringUtil.localize("gui.life"));

    IAlleleTolerance tempTolerance = (IAlleleTolerance)getGenome().getActiveAllele(EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal());
    list.add("\u00A7aT: " + AlleleManager.climateHelper.toDisplay(genome.getPrimary().getTemperature()) + " / " + tempTolerance.getName());

    IAlleleTolerance humidTolerance = (IAlleleTolerance)getGenome().getActiveAllele(EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal());
    list.add("\u00A7aH: " + AlleleManager.climateHelper.toDisplay(genome.getPrimary().getHumidity()) + " / " + humidTolerance.getName());

    list.add(genome.getFlowerProvider().getDescription());
    if (genome.getNocturnal())
      list.add("\u00A7c" + GenericRatings.rateActivityTime(genome.getNocturnal(), false));
  }

  @Override
  public void age(World world, float housingLifespanModifier) {
    IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(world);
    float finalModifier = housingLifespanModifier * mode.getLifespanModifier(genome, mate, housingLifespanModifier);

    super.age(world, finalModifier);
  }

  // / PRODUCTION
  @Override
  public ItemStack[] getProduceList() {
    ArrayList<ItemStack> products = new ArrayList<ItemStack>();

    IAlleleBeeSpecies primary = genome.getPrimary();
    IAlleleBeeSpecies secondary = genome.getSecondary();

    products.addAll(primary.getProducts().keySet());

    Set<ItemStack> secondaryProducts = secondary.getProducts().keySet();
    // Remove duplicates
    for (ItemStack second : secondaryProducts) {
      boolean skip = false;

      for (ItemStack compare : products)
        if (second.isItemEqual(compare)) {
          skip = true;
          break;
        }

      if (!skip)
        products.add(second);

    }

    return products.toArray(new ItemStack[0]);
  }

  @Override
  public ItemStack[] getSpecialtyList() {
    return genome.getPrimary().getSpecialty().keySet().toArray(new ItemStack[0]);
  }

  @Override
  public ItemStack[] produceStacks(IBeeHousing housing) {
    if (!hasFlower(housing))
      return null;

    if (housing == null) {
      Proxies.log.warning("Failed to produce in an apiary because the beehousing was null.");
      return null;
    }
    IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(housing.getWorld());
    if (mode == null) {
      Proxies.log.warning("Failed to produce in an apiary because the beekeeping mode was null.");
      return null;
    }

    ArrayList<ItemStack> products = new ArrayList<ItemStack>();

    IAlleleBeeSpecies primary = genome.getPrimary();
    IAlleleBeeSpecies secondary = genome.getSecondary();

    // All work and no play makes queen a dull girl.
    if(mode.isOverworked(this, housing))
      setIsNatural(false);

    // Bee genetic speed * beehousing * beekeeping mode
    float speed = genome.getSpeed() * housing.getProductionModifier(genome, 1f) * mode.getProductionModifier(genome, 1f);

    // / Primary Products
    for (Map.Entry<ItemStack, Integer> entry : primary.getProducts().entrySet())
      if (housing.getWorld().rand.nextInt(100) < entry.getValue() * speed)
        products.add(entry.getKey().copy());
    // / Secondary Products
    for (Map.Entry<ItemStack, Integer> entry : secondary.getProducts().entrySet())
      if (housing.getWorld().rand.nextInt(100) < Math.round(entry.getValue() / 2) * speed)
        products.add(entry.getKey().copy());

    // We are done if the we are not jubilant.
    if (!primary.isJubilant(genome, housing) || !secondary.isJubilant(genome, housing))
      return products.toArray(StackUtils.EMPTY_STACK_ARRAY);

    // / Specialty products
    for (Map.Entry<ItemStack, Integer> entry : primary.getSpecialty().entrySet())
      if (housing.getWorld().rand.nextInt(100) < entry.getValue() * speed)
        products.add(entry.getKey().copy());

    return genome.getFlowerProvider().affectProducts(housing.getWorld(), this, housing.getXCoord(), housing.getYCoord(), housing.getZCoord(),
        products.toArray(StackUtils.EMPTY_STACK_ARRAY));
  }

  /* REPRODUCTION */
  @Override
  public IBee spawnPrincess(IBeeHousing housing) {

    // We need a mated queen to produce offspring.
    if (mate == null)
      return null;

    // Fatigued queens do not produce princesses.
    if (PluginApiculture.beeInterface.getBeekeepingMode(housing.getWorld()).isFatigued(this, housing))
      return null;

    return createOffspring(housing, getGeneration() + 1);
  }

  @Override
  public IBee[] spawnDrones(IBeeHousing housing) {

    World world = housing.getWorld();

    // We need a mated queen to produce offspring.
    if (mate == null)
      return null;

    ArrayList<IBee> bees = new ArrayList<IBee>();

    int toCreate = PluginApiculture.beeInterface.getBeekeepingMode(world).getFinalFertility(this, world, housing.getXCoord(), housing.getYCoord(),
        housing.getZCoord());

    if (toCreate <= 0)
      toCreate = 1;

    for (int i = 0; i < toCreate; i++) {
      IBee offspring = createOffspring(housing, -1);
      if (offspring != null) {
        offspring.setIsNatural(true);
        bees.add(offspring);
      }
    }

    if (bees.size() > 0)
      return bees.toArray(new IBee[0]);
    else
      return null;
  }

  private IBee createOffspring(IBeeHousing housing, int generation) {

    World world = housing.getWorld();

    IChromosome[] chromosomes = new IChromosome[genome.getChromosomes().length];
    IChromosome[] parent1 = genome.getChromosomes();
    IChromosome[] parent2 = mate.getChromosomes();

    // Check for mutation. Replace one of the parents with the mutation
    // template if mutation occured.
    IChromosome[] mutated1 = mutateSpecies(housing, genome, mate);
    if (mutated1 != null)
      parent1 = mutated1;
    IChromosome[] mutated2 = mutateSpecies(housing, mate, genome);
    if (mutated2 != null)
      parent2 = mutated2;

    for (int i = 0; i < parent1.length; i++)
      if (parent1[i] != null && parent2[i] != null)
        chromosomes[i] = Chromosome.inheritChromosome(world.rand, parent1[i], parent2[i]);

    IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(world);
    IBee offspring = new Bee(world, new BeeGenome(chromosomes), mode.isNaturalOffspring(this), generation);

    /* Disabling the mutation rate nerf
    // All mutation and no play makes queen a dull girl.
    if(mode.isDegenerating(this, offspring, housing))
      offspring.setIsNatural(false);*/

    return offspring;
  }

  private IChromosome[] mutateSpecies(IBeeHousing housing, IGenome genomeOne, IGenome genomeTwo) {

    World world = housing.getWorld();

    IChromosome[] parent1 = genomeOne.getChromosomes();
    IChromosome[] parent2 = genomeTwo.getChromosomes();

    IGenome genome0;
    IGenome genome1;
    IAllele allele0;
    IAllele allele1;

    if (world.rand.nextBoolean()) {
      allele0 = parent1[EnumBeeChromosome.SPECIES.ordinal()].getPrimaryAllele();
      allele1 = parent2[EnumBeeChromosome.SPECIES.ordinal()].getSecondaryAllele();

      genome0 = genomeOne;
      genome1 = genomeTwo;
    } else {
      allele0 = parent2[EnumBeeChromosome.SPECIES.ordinal()].getPrimaryAllele();
      allele1 = parent1[EnumBeeChromosome.SPECIES.ordinal()].getSecondaryAllele();

      genome0 = genomeTwo;
      genome1 = genomeOne;
    }

    for (IBeeMutation mutation : PluginApiculture.beeInterface.getMutations(true)) {
      float chance = 0;

      if ((chance = mutation.getChance(housing, allele0, allele1, genome0, genome1)) > 0)
        if (world.rand.nextFloat()*100 < chance) {
          IApiaristTracker breedingTracker = PluginApiculture.beeInterface.getBreedingTracker(world, housing.getOwnerName());
          breedingTracker.registerMutation(mutation);
          return PluginApiculture.beeInterface.templateAsChromosomes(mutation.getTemplate());
        }
    }

    return null;
  }

  /* FLOWERS */
  @Override
  public IIndividual retrievePollen(IBeeHousing housing) {

    int chance = (int) (genome.getFlowering() * housing.getFloweringModifier(getGenome(), 1f));

    // Correct speed
    if (housing.getWorld().rand.nextInt(100) >= chance)
      return null;

    int[] areaAr = genome.getTerritory();
    Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)).multiply(3.0f);
    Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2));

    if (area.x < 1)
      area.x = 1;
    if (area.y < 1)
      area.y = 1;
    if (area.z < 1)
      area.z = 1;

    // We have up to ten attempts
    for (int i = 0; i < 20; i++) {

      Vect randomPos = new Vect(housing.getWorld().rand.nextInt(area.x), housing.getWorld().rand.nextInt(area.y), housing.getWorld().rand.nextInt(area.z));

      Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord()));
      posBlock = posBlock.add(offset);

      TileEntity tile = housing.getWorld().getTileEntity(posBlock.x, posBlock.y, posBlock.z);
      if (!(tile instanceof IPollinatable)) {
        if (housing.getWorld().isAirBlock(posBlock.x, posBlock.y, posBlock.z))
          continue;

        // Test for ersatz genomes
        for (Map.Entry<ItemStack, IIndividual> entry : AlleleManager.ersatzSpecimen.entrySet()) {
          if (!StackUtils.equals(housing.getWorld().getBlock(posBlock.x, posBlock.y, posBlock.z), entry.getKey()))
            continue;
          if (entry.getKey().getItemDamage() != housing.getWorld().getBlockMetadata(posBlock.x, posBlock.y, posBlock.z))
            continue;

          // We matched, return ersatz genome
          return entry.getValue().copy();
        }

        continue;
      }

      IPollinatable pitcher = (IPollinatable) tile;
      if (!genome.getFlowerProvider().isAcceptedPollinatable(housing.getWorld(), pitcher))
        continue;

      IIndividual pollen = pitcher.getPollen();

      if (pollen != null)
        return pollen;
    }

    return null;
  }

  @Override
  public boolean pollinateRandom(IBeeHousing housing, IIndividual pollen) {

    int chance = (int) (genome.getFlowering() * housing.getFloweringModifier(getGenome(), 1f));

    // Correct speed
    if (housing.getWorld().rand.nextInt(100) >= chance)
      return false;

    int[] areaAr = genome.getTerritory();
    Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)).multiply(3.0f);
    Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 4), -Math.round(area.z / 2));

    if (area.x < 1)
      area.x = 1;
    if (area.y < 1)
      area.y = 1;
    if (area.z < 1)
      area.z = 1;

    // We have up to ten attempts
    for (int i = 0; i < 30; i++) {

      Vect randomPos = new Vect(housing.getWorld().rand.nextInt(area.x), housing.getWorld().rand.nextInt(area.y), housing.getWorld().rand.nextInt(area.z));

      Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord()));
      posBlock = posBlock.add(offset);

      IPollinatable receiver = Utils.getOrCreatePollinatable(housing.getOwnerName(), housing.getWorld(), posBlock.x, posBlock.y, posBlock.z);
      if(receiver == null)
        continue;

      if (!genome.getFlowerProvider().isAcceptedPollinatable(housing.getWorld(), receiver))
        continue;
      if (!receiver.canMateWith(pollen))
        continue;

      receiver.mateWith(pollen);
      return true;
    }

    return false;
  }

  @Override
  public void plantFlowerRandom(IBeeHousing housing) {

    int chance = (int) (genome.getFlowering() * housing.getFloweringModifier(getGenome(), 1f));

    // Correct speed
    if (housing.getWorld().rand.nextInt(100) >= chance)
      return;

    // Gather required info
    IFlowerProvider provider = genome.getFlowerProvider();
    int[] areaAr = genome.getTerritory();
    Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)).multiply(3.0f);
    Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 4), -Math.round(area.z / 2));

    if (area.x < 1)
      area.x = 1;
    if (area.y < 1)
      area.y = 1;
    if (area.z < 1)
      area.z = 1;

    // We have up to ten attempts
    for (int i = 0; i < 10; i++) {

      Vect randomPos = new Vect(housing.getWorld().rand.nextInt(area.x), housing.getWorld().rand.nextInt(area.y), housing.getWorld().rand.nextInt(area.z));

      Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord()));
      posBlock = posBlock.add(offset);

      if (provider.growFlower(housing.getWorld(), this, posBlock.x, posBlock.y, posBlock.z))
        break;
    }
  }
}
TOP

Related Classes of forestry.apiculture.genetics.Bee

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.