package net.torocraft.toroquest.civilization.quests; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.Set; import java.util.UUID; import javax.annotation.Nullable; import com.google.common.base.Predicate; import net.minecraft.block.BlockColored; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.Enchantment; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.EnumDyeColor; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.torocraft.toroquest.block.BlockToroSpawner; import net.torocraft.toroquest.block.TileEntityToroSpawner; import net.torocraft.toroquest.civilization.Province; import net.torocraft.toroquest.civilization.player.PlayerCivilizationCapabilityImpl; import net.torocraft.toroquest.civilization.quests.util.Quest; import net.torocraft.toroquest.civilization.quests.util.QuestData; import net.torocraft.toroquest.civilization.quests.util.Quests; public class QuestEnemyEncampment extends QuestBase implements Quest { public static int ID; public static QuestEnemyEncampment INSTANCE; private final static int hutHalfWidth = 6; // TODO make dynamic and save in quest data private final static int mobCount = 30; public static void init(int id) { INSTANCE = new QuestEnemyEncampment(); Quests.registerQuest(id, INSTANCE); MinecraftForge.EVENT_BUS.register(INSTANCE); ID = id; } @Override public List<ItemStack> complete(QuestData data, List<ItemStack> in) { if (getKills(data) < 1) { data.getPlayer().sendMessage(new TextComponentTranslation("quests.enemey_encampment.wasnt_you")); return null; } int count = countEntities(data); if (count > 0) { if (count == 1) { data.getPlayer().sendMessage(new TextComponentTranslation("quests.enemey_encampment.one_left")); } else { data.getPlayer().sendMessage(new TextComponentTranslation("quests.enemey_encampment.some_left", count)); } return null; } data.setCompleted(true); in.addAll(getRewardItems(data)); if (getKills(data) == mobCount) { addGoldenSword(data, in); } return in; } protected void addGoldenSword(QuestData data, List<ItemStack> in) { ItemStack sword = new ItemStack(Items.GOLDEN_SWORD); sword.addEnchantment(Enchantment.getEnchantmentByID(16), 5); sword.addEnchantment(Enchantment.getEnchantmentByID(21), 3); Province inProvince = PlayerCivilizationCapabilityImpl.get(data.getPlayer()).getInCivilization(); if (inProvince.id.equals(data.getProvinceId())) { // TODO lang sword.setStackDisplayName("Golden Sword of " + inProvince.name); } in.add(sword); } private int countEntities(final QuestData data) { Predicate<Entity> filter = new Predicate<Entity>() { public boolean apply(@Nullable Entity entity) { return entity.getTags().contains("encampment_quest") && entity.getTags().contains(data.getQuestId().toString()); } }; return data.getPlayer().world.getEntitiesWithinAABB(EntityMob.class, new AxisAlignedBB(getSpawnPosition(data)).expand(80, 40, 80), filter).size(); } @Override public List<ItemStack> reject(QuestData data, List<ItemStack> in) { return in; } @Override public List<ItemStack> accept(QuestData data, List<ItemStack> in) { spawn(data); return in; } private void spawn(QuestData data) { BlockPos pos = searchForSuitableLocation(data); setSpawnPosition(data, pos); buildHut(data, pos); addToroSpawner(data, data.getPlayer().getEntityWorld(), getSpawnPosition(data), getEnemyType(data)); } private BlockPos searchForSuitableLocation(QuestData data) { // TODO support underground and under water positions Random rand = data.getPlayer().getEntityWorld().rand; BlockPos pos = null; for (int i = 0; i < 100; i++) { pos = randomLocation(data, rand, false); if (pos != null) { break; } } if (pos == null) { return randomLocation(data, rand, true); } return pos; } private BlockPos randomLocation(QuestData data, Random rand, boolean force) { int distance = rand.nextInt(300) + 500; int directionDegrees = rand.nextInt(360); int z = distance * (int) Math.round(Math.sin(Math.toRadians(directionDegrees))); int x = distance * (int) Math.round(Math.cos(Math.toRadians(directionDegrees))); BlockPos pos = findSurface(data, x + (int) data.getPlayer().posX, z + (int) data.getPlayer().posZ, force); if (pos == null) { return null; } if (data.getPlayer().world.isAnyPlayerWithinRangeAt((double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), 60d)) { return null; } try { pos = new BlockPos(pos.getX(), getLocalMinimum(data, pos), pos.getZ()); } catch (NotLevelEnoughException e) { if (force) { return pos; } return null; } return pos; } private int getLocalMinimum(QuestData data, BlockPos pos) throws NotLevelEnoughException { int w = hutHalfWidth; int max = 0, min = 1000; int y; for (int x = -w; x <= w; x++) { for (int z = -w; z <= w; z++) { y = findSurface(data, pos.getX() + x, pos.getZ() + z, true).getY(); max = Math.max(y, max); min = Math.min(y, min); } } if (max - min > 5) { throw new NotLevelEnoughException("Offest " + (max - min)); } return min; } private static class NotLevelEnoughException extends Exception { public NotLevelEnoughException(String message) { super(message); } } private BlockPos findSurface(QuestData data, int x, int z, boolean force) { World world = data.getPlayer().getEntityWorld(); BlockPos pos = new BlockPos(x, world.getActualHeight(), z); IBlockState blockState; while (pos.getY() > 0) { blockState = world.getBlockState(pos); if (!force && isLiquid(blockState)) { return null; } if (isGroundBlock(blockState)) { break; } pos = pos.down(); } return pos.up(); } private void buildHut(QuestData data, BlockPos pos) { World world = data.getPlayer().getEntityWorld(); if (pos == null) { return; } int w = hutHalfWidth; BlockPos pointer; IBlockState block; for (int x = -w; x <= w; x++) { for (int y = 0; y <= w; y++) { for (int z = -w; z <= w; z++) { pointer = pos.add(x, y, z); block = world.getBlockState(pointer); if (cantBuildOver(block)) { continue; } if (y + Math.abs(z) == w) { if (x % 2 == 0) { world.setBlockState(pointer, Blocks.WOOL.getDefaultState().withProperty(BlockColored.COLOR, EnumDyeColor.RED)); } else { world.setBlockState(pointer, Blocks.WOOL.getDefaultState().withProperty(BlockColored.COLOR, EnumDyeColor.BLACK)); } } else if (z == 0 && (x == w || x == -w)) { world.setBlockState(pointer, Blocks.DARK_OAK_FENCE.getDefaultState()); } } } } } private void addToroSpawner(QuestData data, World world, BlockPos blockpos, List<String> entities) { world.setBlockState(blockpos, BlockToroSpawner.INSTANCE.getDefaultState()); TileEntity tileentity = world.getTileEntity(blockpos); if (tileentity instanceof TileEntityToroSpawner) { TileEntityToroSpawner spawner = (TileEntityToroSpawner) tileentity; spawner.setTriggerDistance(80); spawner.setEntityIds(entities); spawner.setSpawnRadius(4); spawner.setHelmet(new ItemStack(Items.DIAMOND_HELMET)); spawner.setBoots(new ItemStack(Items.DIAMOND_BOOTS)); spawner.setLeggings(new ItemStack(Items.DIAMOND_LEGGINGS)); spawner.setChestplate(new ItemStack(Items.DIAMOND_CHESTPLATE)); spawner.addEntityTag(data.getQuestId().toString()); spawner.addEntityTag("encampment_quest"); } else { System.out.println("tile entity is missing"); } } @Override public String getTitle(QuestData data) { if (data == null) { return ""; } return "quests.enemey_encampment.title"; } @Override public String getDescription(QuestData data) { if (data == null) { return ""; } StringBuilder s = new StringBuilder(); s.append("quests.enemey_encampment.description"); s.append("|").append(getEnemyNames(data)); if (getSpawnPosition(data) != null) { s.append("|").append(getDirections(getProvincePosition(getQuestProvince(data)), getSpawnPosition(data))); } else { s.append("|").append(" "); } s.append("|").append(listItems(getRewardItems(data))); s.append("|").append(getRewardRep(data)); return s.toString(); } private String getEnemyNames(QuestData data) { String name = getEnemyType(data).get(0); try { Entity entity = TileEntityToroSpawner.getEntityForId(data.getPlayer().world, name); return entity.getName(); } catch (Exception e) { System.out.println("failed to get name of entity [" + name + "] : " + e.getMessage()); return "unknown enemy"; } } @Override public QuestData generateQuestFor(EntityPlayer player, Province province) { Random rand = player.getEntityWorld().rand; QuestData data = new QuestData(); data.setCiv(province.civilization); data.setPlayer(player); data.setProvinceId(province.id); data.setQuestId(UUID.randomUUID()); data.setQuestType(ID); data.setCompleted(false); chooseEnemyType(data); setRewardRep(data, 50); List<ItemStack> reward = new ArrayList<ItemStack>(1); reward.add(new ItemStack(Items.EMERALD, 10)); setRewardItems(data, reward); return data; } private void chooseEnemyType(QuestData data) { // TODO add variety // TODO set amount List<String> enemies = new ArrayList<String>(); for (int i = 0; i < mobCount; i++) { enemies.add("minecraft:stray"); } setEnemyType(data, enemies); } private BlockPos getSpawnPosition(QuestData data) { NBTTagCompound c = getCustomNbtTag(data); if (c.getInteger("locationFound") != 1) { return null; } return new BlockPos(c.getInteger("pos_x"), c.getInteger("pos_y"), c.getInteger("pos_z")); } private void setSpawnPosition(QuestData data, BlockPos pos) { NBTTagCompound c = getCustomNbtTag(data); c.setInteger("pos_x", pos.getX()); c.setInteger("pos_y", pos.getY()); c.setInteger("pos_z", pos.getZ()); c.setInteger("locationFound", 1); } private List<String> getEnemyType(QuestData data) { List<String> enemies = new ArrayList<String>(); NBTTagCompound c = getCustomNbtTag(data); try { NBTTagList list = (NBTTagList) c.getTag("enemies"); for (int i = 0; i < list.tagCount(); i++) { enemies.add(list.getStringTagAt(i)); } return enemies; } catch (Exception e) { System.out.println("Failed to load enemy types: " + e.getMessage()); return getDefaultEnemies(data); } } private List<String> getDefaultEnemies(QuestData data) { List<String> zombies = new ArrayList<String>(); for (int i = 0; i < 69; i++) { zombies.add("zombie"); } return zombies; } private void setEnemyType(QuestData data, List<String> enemies) { NBTTagCompound c = getCustomNbtTag(data); NBTTagList list = new NBTTagList(); for (String enemy : enemies) { list.appendTag(new NBTTagString(enemy)); } c.setTag("enemies", list); } public static Integer getKills(QuestData data) { return coalesce(i(data.getiData().get("kills")), 0); } private static Integer coalesce(Integer i, int j) { if (i == null) { return j; } return i; } public static void incrementKills(QuestData data) { data.getiData().put("kills", getKills(data) + 1); } @SubscribeEvent public void checkkills(LivingDeathEvent event) { EntityPlayer player = null; EntityLivingBase victum = (EntityLivingBase) event.getEntity(); DamageSource source = event.getSource(); if (!victum.getTags().contains("encampment_quest")) { return; } if (source.getTrueSource() instanceof EntityPlayer) { player = (EntityPlayer) source.getTrueSource(); } else { return; } Set<QuestData> quests = PlayerCivilizationCapabilityImpl.get(player).getCurrentQuests(); for (QuestData data : quests) { if (ID == data.getQuestType() && victum.getTags().contains(data.getQuestId().toString())) { incrementKills(data); return; } } } }