/******************************************************************************* * Copyright (c) 2015, 2016 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.common.buildings; import java.util.EnumSet; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import jsettlers.common.buildings.jobs.IBuildingJob; import jsettlers.common.buildings.loader.BuildingFile; import jsettlers.common.buildings.stacks.ConstructionStack; import jsettlers.common.buildings.stacks.RelativeStack; import jsettlers.common.images.ImageLink; import jsettlers.common.landscape.ELandscapeType; import jsettlers.common.movable.EMovableType; import jsettlers.common.position.RelativePoint; /** * This interface defines the main building type. * * @author Michael Zangl * @author Andreas Eberle */ public enum EBuildingType { STONECUTTER, FORESTER, LUMBERJACK, SAWMILL, COALMINE, IRONMINE, GOLDMINE, GOLDMELT, IRONMELT, TOOLSMITH, WEAPONSMITH, FARM, PIG_FARM, /** * Needs to implement {@link IBuilding.IMill} */ MILL, WATERWORKS, SLAUGHTERHOUSE, BAKER, FISHER, WINEGROWER, CHARCOAL_BURNER, DONKEY_FARM, SMALL_LIVINGHOUSE, MEDIUM_LIVINGHOUSE, BIG_LIVINGHOUSE, LOOKOUT_TOWER, TOWER, BIG_TOWER, CASTLE, HOSPITAL, BARRACK, DOCKYARD, HARBOR, STOCK, TEMPLE, BIG_TEMPLE, MARKET_PLACE; /** * A copy of {@link #values()}. Do not modify this array. This is intended for quicker access to this value. */ public static final EBuildingType[] VALUES = EBuildingType.values(); /** * The number of buildings in the {@link #VALUES} array. */ public static final int NUMBER_OF_BUILDINGS = VALUES.length; private static final EnumSet<EBuildingType> MILITARY_BUILDINGS = EnumSet.of(TOWER, BIG_TOWER, CASTLE); private static final EnumSet<EBuildingType> MINE_BUILDINGS = EnumSet.of(GOLDMINE, IRONMINE, COALMINE); /** * The ordinal of this type. Yields more performance than using {@link #ordinal()} */ public final int ordinal; private final IBuildingJob startJob; private final EMovableType workerType; private final RelativePoint doorTile; private final RelativePoint[] blockedTiles; private final short workRadius; private final boolean mine; private final ConstructionStack[] constructionStacks; private final RelativeStack[] requestStacks; private final RelativeStack[] offerStacks; private final RelativePoint workCenter; private final RelativePoint flag; private final RelativeBricklayer[] bricklayers; private final byte numberOfConstructionMaterials; private final ImageLink guiImage; private final ImageLink[] images; private final ImageLink[] buildImages; private final RelativePoint[] protectedTiles; private final RelativePoint[] buildMarks; private final EnumSet<ELandscapeType> groundTypes; private final short viewDistance; private final OccupierPlace[] occupierPlaces; private final BuildingAreaBitSet buildingAreaBitSet; /** * Constructs an enum object. */ EBuildingType() { this.ordinal = ordinal(); BuildingFile file = new BuildingFile(this.toString()); startJob = file.getStartJob(); workerType = file.getWorkerType(); doorTile = file.getDoor(); blockedTiles = file.getBlockedTiles(); protectedTiles = file.getProtectedTiles(); constructionStacks = file.getConstructionRequiredStacks(); requestStacks = file.getRequestStacks(); offerStacks = file.getOfferStacks(); workRadius = file.getWorkradius(); workCenter = file.getWorkcenter(); mine = file.isMine(); flag = file.getFlag(); bricklayers = file.getBricklayers(); occupierPlaces = file.getOccupyerPlaces(); guiImage = file.getGuiImage(); images = file.getImages(); buildImages = file.getBuildImages(); buildMarks = file.getBuildmarks(); groundTypes = EnumSet.copyOf(file.getGroundtypes()); viewDistance = file.getViewdistance(); this.numberOfConstructionMaterials = calculateNumberOfConstructionMaterials(); this.buildingAreaBitSet = new BuildingAreaBitSet(getBuildingArea()); if (mine) { this.buildingAreaBitSet.setCenter((short) 1, (short) 1); } } private byte calculateNumberOfConstructionMaterials() { byte sum = 0; for (ConstructionStack stack : getConstructionStacks()) { sum += stack.requiredForBuild(); } return sum; } public RelativePoint[] getBuildingArea() { return protectedTiles; } /** * Gets the job a worker for this building should start with. * * @return That {@link IBuildingJob} */ public final IBuildingJob getStartJob() { return startJob; } /** * Gets the type of worker required for the building. * * @return The worker or <code>null</code> if no worker is required. */ public final EMovableType getWorkerType() { return workerType; } /** * Gets the position of the door for this building. * * @return The door. */ public final RelativePoint getDoorTile() { return doorTile; } /** * Gets a list of blocked positions. * * @return The list of blocked positions. */ public final RelativePoint[] getBlockedTiles() { return blockedTiles; } /** * Gets the tiles that are protected by this building. On thse tiles, no other buildings may be build. * * @return The tiles as array. */ public final RelativePoint[] getProtectedTiles() { return protectedTiles; } /** * Gets the images needed to display this building. They are rendered in the order provided. * * @return The images */ public final ImageLink[] getImages() { return images; } /** * Gets the images needed to display this building while it si build. They are rendered in the order provided. * * @return The images */ public final ImageLink[] getBuildImages() { return buildImages; } /** * Gets the gui image that is displayed in the building selection dialog. * * @return The image. It may be <code>null</code> */ public final ImageLink getGuiImage() { return guiImage; } /** * Gets the working radius of the building. If it is 0, the building does not support a working radius. * * @return The radius. */ public final short getWorkRadius() { return workRadius; } /** * Gets the default work center for the building type. * * @return The default work center position. */ public final RelativePoint getDefaultWorkcenter() { return workCenter; } /** * Gets the position of the flag for this building. The flag type is determined by the building itself. * * @return The flag position. */ public final RelativePoint getFlag() { return flag; } /** * Gets the positions where the bricklayers should stand to build the house. * * @return The positions. * @see RelativeBricklayer */ public final RelativeBricklayer[] getBricklayers() { return bricklayers; } /** * Gets the positions of the build marks (sticks) for this building. * * @return The positions of the marks. */ public final RelativePoint[] getBuildMarks() { return buildMarks; } /** * Gets the ground types this building can be placed on. * * @return The ground types. */ public final Set<ELandscapeType> getGroundTypes() { return groundTypes; } /** * Gets the distance the FOW should be set to visible around this building. * * @return The view distance. */ public final short getViewDistance() { return viewDistance; } /** * Gets the places where occupiers can be in this building. * * @return The places. * @see OccupierPlace */ public final OccupierPlace[] getOccupierPlaces() { return occupierPlaces; } /** * Queries a building job with the given name that needs to be accessible from the start job. * * @param jobname * The name of the job. * @return The job if found. * @throws IllegalArgumentException * If the name was not found. */ public final IBuildingJob getJobByName(String jobname) { HashSet<String> visited = new HashSet<String>(); ConcurrentLinkedQueue<IBuildingJob> queue = new ConcurrentLinkedQueue<IBuildingJob>(); queue.add(startJob); while (!queue.isEmpty()) { IBuildingJob job = queue.poll(); if (visited.contains(job.getName())) { continue; } if (job.getName().equals(jobname)) { return job; } visited.add(job.getName()); queue.add(job.getNextFailJob()); queue.add(job.getNextSucessJob()); } throw new IllegalArgumentException("This building has no job with name " + jobname); } /** * Gets the area for this building. * * @return The building area. */ public final BuildingAreaBitSet getBuildingAreaBitSet() { return buildingAreaBitSet; } /** * Gets the materials required to build this building and where to place them. * * @return The array of material stacks. */ public ConstructionStack[] getConstructionStacks() { return constructionStacks; } /** * Get the amount of material required to build this house. Usually the number of stone + planks. * * @return The number of materials required to construct the building. */ public final byte getNumberOfConstructionMaterials() { return numberOfConstructionMaterials; } /** * Gets the request stacks required to operate this building. * * @return The request stacks. */ public RelativeStack[] getRequestStacks() { return requestStacks; } /** * Gets the positions where the building should offer materials. * * @return The offer positions. */ public RelativeStack[] getOfferStacks() { return offerStacks; } /** * Checks if this building is a mine. * * @return <code>true</code> iff this building is a mine. */ public boolean isMine() { return mine; } public boolean needsFlattenedGround() { return !mine; } /** * Checks if this building is a military building. * * @return <code>true</code> iff this is a military building. */ public boolean isMilitaryBuilding() { return MILITARY_BUILDINGS.contains(this); } /** * Gets an collection of all military buildings. * * @return The buildings. */ public static EnumSet<EBuildingType> getMilitaryBuildings() { return MILITARY_BUILDINGS; } public Set<ELandscapeType> getRequiredGroundTypeAt(int relativeX, int relativeY) { if (relativeX == 0 && relativeY == 0 && mine) { // if it is a mine and we are in the center return ELandscapeType.MOUNTAIN_TYPES; } else { return groundTypes; } } }