/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.common.graphics; import illarion.common.util.FastMath; import org.jetbrains.annotations.Contract; import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collection; /** * The item info class stores some general information about the items that are shared by all instances of the same * item type and by some instances of different item types in case its possible. * <p/> * The class stores final values and does not support to change the values once its created. * * @author Nop * @author Martin Karing <nitram@illarion.org> */ public final class ItemInfo { /** * Facing value for accepting the light from all sides. */ public static final int FACE_ALL = 0; /** * Facing value for accepting the light from south and blocking it from all other sides. */ public static final int FACE_S = 3; /** * Facing value for accepting the light from west and from south and blocking it from all other sides. */ public static final int FACE_SW = 2; /** * Facing value for accepting the light from west and blocking it from all other sides. */ public static final int FACE_W = 1; /** * The special item value in case the book is a container. */ private static final int BOOK = 2; /** * The buffer storage that is used to save the created item info instances to compare them during the loading * time so a minimal amount of instances is created. */ @Nonnull private static final Collection<ItemInfo> BUFFER = new ArrayList<>(); /** * The special item value in case the item is a container. */ private static final int CONTAINER = 1; /** * The special item value in case the Jesus item is a container. */ private static final int JESUS = 3; /** * The value the variance is divided with to get the actual modification value on the scale of the item. */ private static final float VARIANCE_MOD = 100.f; /** * The facing of the item so the direction this item accepts light from. Possible values are {@link #FACE_ALL}, * {@link #FACE_W}, {@link #FACE_SW} and {@link #FACE_S}. */ private final int face; /** * The checking flag if this item uses variances by {@link #variance}. So this flag in general is {@code true} in * case the {@link #variance} value is greater then {@code 0.f}. */ private final boolean hasVariance; /** * The surface level of the item, so the offset from the origin of the item upwards where the next item is placed * on top of the item. */ private final int level; /** * The encoded value of the light source this item emits. */ private final int light; /** * The movable flag, so in case this item can be moved by the player this is set to {@code true}. */ private final boolean movable; /** * The flag if the pathfinder can step in this item or not. In case this is set to {@code false} the pathfinder * has to move around this item. */ private final boolean obstacle; /** * The opacity of the item in percent, so the value how much the item blocks the line of sight of the player. */ private final int opacity; /** * The special item flag that determines if this item is a normal item or a {@link #CONTAINER}, * a {@link #BOOK} or a {@link #JESUS} item. */ private final int special; /** * The variance of the size of this item. In case this is set to a value greater then 0.f this item is scaled. */ private final float variance; /** * Create a new instance of a ItemInfo object. * * @param facing The facing flag that contains the information from what direction the item accepts light. The * possible values are {@link #FACE_ALL}, {@link #FACE_SW}, {@link #FACE_S}, {@link #FACE_W}. * @param itemMovable the movable flag that stores if the item can be moved or not * @param specialFlag the special flag that indicates of the item is a normal item or a container, a book or a * Jesus item. * @param itemObstacle the obstacle flag determines if the characters can walk over this item or not, more * exactly it blocks the way for the automated pathfinder * @param varianceRange the variance of the item in since, if this variable stores a value larger then 0 the item * is scaled up and down by the percent value handed over in this variable * @param itemOpacity the opacity of this object so the value in percent this item blocks the line of sight * @param surfaceLevel the offset of the surface level of the item relative to the origin of the item, this is * used to add a additional offset to the item in case there are additional items upon this * item, so it looks like the other line lies on this item * @param lightSource the encoded value of the light of this item, any value greater then 0 causes this item to * be a light source emitting constantly light on the map */ private ItemInfo(int facing, boolean itemMovable, int specialFlag, boolean itemObstacle, float varianceRange, int itemOpacity, int surfaceLevel, int lightSource) { face = facing; movable = itemMovable; special = specialFlag; obstacle = itemObstacle; level = surfaceLevel; if (varianceRange > 0.f) { hasVariance = true; variance = varianceRange; } else { hasVariance = false; variance = 0.f; } opacity = itemOpacity; light = lightSource; } /** * Create a new instance of a ItemInfo object. This instance also checks if there is already a object of this * kind with exactly the same values as the new one that is going to be created and returns this one rather then * a new one. * * @param facing The facing flag that contains the information from what direction the item accepts light. The * possible values are {@link #FACE_ALL}, {@link #FACE_SW}, {@link #FACE_S}, {@link #FACE_W}. * @param movable the movable flag that stores if the item can be moved or not * @param special the special flag that indicates of the item is a normal item or a container, a book or a Jesus * item. * @param obstacle the obstacle flag determines if the characters can walk over this item or not, more exactly it * blocks the way for the automated pathfinder * @param variance the variance of the item in since, if this variable stores a value larger then 0 the item is * scaled up and down by the percent value handed over in this variable * @param opacity the opacity of this object so the value in percent this item blocks the line of sight * @param level the offset of the surface level of the item relative to the origin of the item, this is used to * add a additional offset to the item in case there are additional items upon this item, so it * looks like the other line lies on this item * @param lightSource the encoded value of the light of this item, any value greater then 0 causes this item to * be a light source emitting constantly light on the map * @return the ItemInfo object, either a newly created one, or one that was loaded from the buffer */ @Nonnull public static ItemInfo create(int facing, boolean movable, int special, boolean obstacle, int variance, int opacity, int level, int lightSource) { float prepVariance = variance / VARIANCE_MOD; for (ItemInfo testItemInfo : BUFFER) { if (testItemInfo.face != facing) { continue; } if (testItemInfo.movable != movable) { continue; } if (testItemInfo.special != special) { continue; } if (testItemInfo.obstacle != obstacle) { continue; } if (!FastMath.equals(testItemInfo.variance, prepVariance, FastMath.FLT_EPSILON)) { continue; } if (testItemInfo.opacity != opacity) { continue; } if (testItemInfo.level != level) { continue; } if (testItemInfo.light != lightSource) { continue; } return testItemInfo; } ItemInfo retInfo = new ItemInfo(facing, movable, special, obstacle, prepVariance, opacity, level, lightSource); BUFFER.add(retInfo); return retInfo; } /** * Get the facing of the item. So the direction the item accepts light from. * * @return the facing of the item * @see #FACE_ALL * @see #FACE_S * @see #FACE_SW * @see #FACE_W */ @Contract(pure = true) public int getFace() { return face; } /** * Get the surface level of the item. So the offset how much a item that lies on this item has to move up to * appear to lie on this item. * * @return the amount of pixels the next item offset has to move up */ @Contract(pure = true) public int getLevel() { return level; } /** * The value of the light source. * * @return the encodes parameters of the light source of this item */ @Contract(pure = true) public int getLight() { return light; } /** * Get the opacity if the item so the value how the item blocks the line of sight. * * @return the percent value how much of the line of sight is blocked by * this item */ @Contract(pure = true) public int getOpacity() { return opacity; } /** * Get the variances of this item. * * @return the modification value of the default scaling to decrease or increase the default scaling by */ @Contract(pure = true) public float getVariance() { return variance; } /** * Check if this item uses scale variances. * * @return {@code true} in case the item is able to use scale variances */ @Contract(pure = true) public boolean hasVariance() { return hasVariance; } /** * Check if the item is a book. * * @return {@code true} in case the item is a book */ @Contract(pure = true) public boolean isBook() { return special == BOOK; } /** * Check if the item is a container. * * @return {@code true} in case the item is a container */ @Contract(pure = true) public boolean isContainer() { return special == CONTAINER; } /** * Check if the item is a Jesus item. * * @return {@code true} in case the item is a Jesus item */ @Contract(pure = true) public boolean isJesus() { return special == JESUS; } /** * Check if this item is a source of light. * * @return {@code true} in case the item is a source of light */ @Contract(pure = true) public boolean isLight() { return light > 0; } /** * Check if the item is movable by the player. * * @return {@code true} in case the player can move the item around */ @Contract(pure = true) public boolean isMovable() { return movable; } /** * Check if the item is obstacle. * * @return {@code true} if the item is obstacle and the pathfinder has * to search a way around it */ @Contract(pure = true) public boolean isObstacle() { return obstacle; } }