All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.rpgframework.genericrpg.items.CarriedItem Maven / Gradle / Ivy

package de.rpgframework.genericrpg.items;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;

import org.prelle.simplepersist.AttribConvert;
import org.prelle.simplepersist.Attribute;
import org.prelle.simplepersist.Element;
import org.prelle.simplepersist.ElementList;
import org.prelle.simplepersist.Root;

import de.rpgframework.genericrpg.chargen.OperationResult;
import de.rpgframework.genericrpg.data.ComplexDataItemValue;
import de.rpgframework.genericrpg.data.Decision;
import de.rpgframework.genericrpg.data.IReferenceResolver;
import de.rpgframework.genericrpg.data.Lifeform;
import de.rpgframework.genericrpg.modification.Modification;
import de.rpgframework.genericrpg.modification.Modification.Origin;
import de.rpgframework.genericrpg.modification.ValueModification;
import de.rpgframework.genericrpg.persist.IntegerArrayConverter;
import de.rpgframework.genericrpg.requirements.Requirement;

/**
 * @author prelle
 *
 */
@Root(name="item")
public class CarriedItem extends ComplexDataItemValue implements IReferenceResolver {

	final static Logger logger = System.getLogger(CarriedItem.class.getPackageName());

	@Attribute(name="variant", required = false)
	private String variantRef;
	/** How is the item associated with the character */
	@Attribute(required = false)
	private CarryMode mode = CarryMode.CARRIED;
	@Element
	private String description;
	@Attribute(required = false)
	private int count;
	@Attribute
	private Hook slot;

	// ToDo: Ausrüstungssets
    @ElementList(type = String.class, entry = "set")
	private List equipmentSets;
	@Element
	private String notes;
	@Element
	private byte[] image;
	@Element
	private Boolean primary;
	@Element(name="mode")
	protected String activeMode;
	@Attribute(name="changes")
	@AttribConvert(value=IntegerArrayConverter.class)
	protected int[] modificationSlotChanges;

    private transient PieceOfGearVariant variant;
    private transient List allowedHooks;
	/** Calculated item attributes */
	private transient Map> attributes;

	protected transient List requirements;
	/** User added accessories */
	@ElementList(entry="item",type=CarriedItem.class)
	private List> accessories;
	@ElementList(entry="enhancement",type=ItemEnhancementValue.class)
	private List enhancements;

	protected transient Lifeform user;
	protected transient boolean isInitialized=false;

	protected transient Map> slots;
	protected transient List autoEnhancements;
	protected transient List> alternates;
	/** Item needs recalculation */
	protected transient boolean dirty = true;
	protected transient CarriedItem parent;
	private transient OperationResult> lastRecalculateResult;

	//-------------------------------------------------------------------
	public CarriedItem() {
		attributes   = new HashMap>();
		requirements = new ArrayList<>();
		decisions    = new ArrayList<>();
		accessories  = new ArrayList<>();
		enhancements  = new ArrayList<>();
		autoEnhancements= new ArrayList();
		alternates    = new ArrayList<>();
		allowedHooks  = new ArrayList<>();
		isInitialized = true;

		slots = new HashMap<>();
		this.uuid = UUID.randomUUID();
	}

	//-------------------------------------------------------------------
	public CarriedItem(CarriedItem toCopy) {
		super(toCopy.getResolved());
		attributes   = deepCopy(toCopy.attributes);
		requirements = new ArrayList<>();
		decisions    = new ArrayList<>(toCopy.decisions);
		accessories  = new ArrayList<>();
		enhancements  = new ArrayList<>();
		autoEnhancements= new ArrayList();
		alternates    = new ArrayList<>();
		allowedHooks  = new ArrayList<>();
		isInitialized = true;

		slots = new HashMap<>();
		this.uuid = UUID.randomUUID();
	}

	//-------------------------------------------------------------------
	public static Map> deepCopy(Map> old) {
		HashMap> copy = new HashMap<>();
		for (Map.Entry> entry : old.entrySet()) {
			copy.put(entry.getKey(), (ItemAttributeValue) entry.getValue().clone());
		}
		return copy;
	}

	//-------------------------------------------------------------------
	/**
	 * Use the item in NORMAL usage
	 */
	public CarriedItem(T item, PieceOfGearVariant variant, CarryMode mode) {
		super(item);
		this.mode = mode;
		if (variant!=null) {
			this.variant = variant;
			this.variantRef = variant.getId();
		}

		uuid = UUID.randomUUID();
		attributes = new HashMap>();
		requirements = new ArrayList<>();
		decisions = new ArrayList<>();
		accessories  = new ArrayList<>();
		setResolved(item, variant);
		enhancements  = new ArrayList<>();
		autoEnhancements= new ArrayList();
		alternates    = new ArrayList<>();
		allowedHooks  = new ArrayList<>();
		isInitialized = true;

		slots = new HashMap<>();
	}

	//-------------------------------------------------------------------
	public String toString() {
		return "CarriedItem("+getKey()+")";
	}

	//-------------------------------------------------------------------
	public String getNameWithoutRating(Locale loc) {
		// User defined name gets precedence
		if (customName!=null) return customName;
		// Lookup real items name
		if (resolved==null)
			return ref;
		//String decString = decisions.isEmpty()?"":getDecisionString(loc);
		String baseName = resolved.getName(loc);//+" "+decString;

		if (variant!=null) {
			// If the variant is optional, add the variants name in brackets
			if (!resolved.requiresVariant()) {
				return baseName+" ("+variant.getName(loc)+")";
			}
			// Otherwise use full name
			return variant.getName(loc);
		}
		return baseName;
	}

	//-------------------------------------------------------------------
	@Override
	public String getNameWithoutRating() {
		return getNameWithoutRating(Locale.getDefault());
	}

	//-------------------------------------------------------------------
	/**
	 * @see de.rpgframework.genericrpg.data.ComplexDataItemValue#getNameWithRating(java.util.Locale)
	 */
	@Override
	public String getNameWithRating(Locale loc) {
		String baseName = getNameWithoutRating(loc);
		if (getDecision(UUID.fromString("c2d17c87-1cfe-4355-9877-a20fe09c170d"))!=null) {
			return baseName + " "+ getDecision(UUID.fromString("c2d17c87-1cfe-4355-9877-a20fe09c170d")).getValueAsInt();
		}
		if (value==0) return baseName;
		return baseName+" "+value;
	}

	//-------------------------------------------------------------------
	public String getNameWithCount(Locale loc) {
		if (count>1)
			return getNameWithRating(loc)+" ("+count+"x)";
		return getNameWithRating(loc);
	}

	//-------------------------------------------------------------------
	public String getTemplateID() {
		return getKey();
	}

	//-------------------------------------------------------------------
	public void setResolved(T template, PieceOfGearVariant variant) {
		this.resolved = template;
		this.variant  = variant;
		if (variant!=null) {
			this.variantRef = variant.getId();
		}
		if (isInitialized) {
			refresh();
		}
	}

	//-------------------------------------------------------------------
	private void refresh() {
		logger.log(Level.TRACE, "START: refresh() "+uuid+"  "+ref);
		try {
			attributes.clear();
			requirements.clear();
			allowedHooks.clear();
			GearTool.recalculate("", this.getResolved().getReferenceType(), user, this);
		} finally {
			logger.log(Level.TRACE, "STOP : refresh() "+uuid+"  "+ref);
		}
	}

	//-------------------------------------------------------------------
	public Collection> getAttributes() {
		return attributes.values();
	}

	//-------------------------------------------------------------------
	public Collection getAttributeKeys() {
		return attributes.keySet();
	}

	//-------------------------------------------------------------------
	public  ItemAttributeNumericalValue getAsValue(A attrib) {
		if (attributes.get(attrib)==null)
			return null;
		if (attributes.get(attrib) instanceof ItemAttributeNumericalValue)
			return (ItemAttributeNumericalValue) attributes.get(attrib);
		throw new ClassCastException("getAsValue() is the wrong method for "+attributes.get(attrib).getClass().getSimpleName()+"="+attributes.get(attrib));
	}

	//-------------------------------------------------------------------
	public  boolean isFloat(A attrib) {
		if (attributes.get(attrib)==null)
			return false;
		return (attributes.get(attrib) instanceof ItemAttributeFloatValue);
	}

	//-------------------------------------------------------------------
	public  ItemAttributeFloatValue getAsFloat(A attrib) {
		if (attributes.get(attrib)==null)
			return null;
		if (attributes.get(attrib) instanceof ItemAttributeFloatValue)
			return (ItemAttributeFloatValue) attributes.get(attrib);
		throw new ClassCastException("getAsFloat() is the wrong method for "+attributes.get(attrib).getClass().getSimpleName()+"="+attributes.get(attrib));
	}

	//-------------------------------------------------------------------
	public  ItemAttributeObjectValue getAsObject(A attrib) {
		return (ItemAttributeObjectValue) attributes.get(attrib);
	}

	//-------------------------------------------------------------------
	public void setDecisions(List val) {
		this.decisions = val;
//		refresh();
	}

	//-------------------------------------------------------------------
	/**
	 * @return the uuid
	 */
	public UUID getUuid() {
		return uuid;
	}

	//-------------------------------------------------------------------
	public void setAttribute(IItemAttribute attrib, ItemAttributeValue val) {
		//if (logger.isLoggable(Level.DEBUG)) logger.log(Level.DEBUG, "SetAttribute("+attrib+", "+val);
		attributes.put(attrib, val);
		if (attrib.name().equals("PRICE") && val instanceof ItemAttributeObjectValue)
			throw new IllegalArgumentException("Should not be an object");
//		if (attrib.name().equals("DAMAGE") && !val.getClass().getSimpleName().equals("Damage"))
//			throw new IllegalArgumentException("Should be a Damage object");
	}

	//-------------------------------------------------------------------
	public ItemAttributeValue getAttributeRaw(IItemAttribute key) {
		return attributes.get(key);
	}

	//-------------------------------------------------------------------
	public String dump() {
		StringBuffer buf = new StringBuffer(uuid+"");
		for (ItemAttributeValue attr : attributes.values()) {
			buf.append("\n  "+attr.getModifyable()+" : "+attr+" = "+attr.getClass());
		}
		buf.append("\nSlots\n");
		for (AAvailableSlot slot : this.slots.values()) {
			buf.append(String.format(" %20s  \t%s\n", slot.getHook(), slot));
		}
		return buf.toString();
	}

	//-------------------------------------------------------------------
	/**
	 * @return the variantRef
	 */
	public String getVariantID() {
		return variantRef;
	}

	//-------------------------------------------------------------------
	/**
	 * @return the variant
	 */
	public PieceOfGearVariant getVariant() {
		return variant;
	}

	//-------------------------------------------------------------------
	/**
	 * @param variant the variant to set
	 */
	public void setVariant(PieceOfGearVariant variant) {
		this.variant = variant;
	}

	//-------------------------------------------------------------------
	public void addRequirement(Requirement req) {
		requirements.add(req);
	}

	//-------------------------------------------------------------------
	public List getRequirements() {
		return new ArrayList(requirements);
	}

	//-------------------------------------------------------------------
	/**
	 * @return the count
	 */
	public int getCount() {
		if (count==0) return 1;
		return count;
	}

	//-------------------------------------------------------------------
	/**
	 * @param count the count to set
	 */
	public void setCount(int count) {
		this.count = count;
	}

	//-------------------------------------------------------------------
	/**
	 * @return the user
	 */
	public Lifeform getUser() {
		return user;
	}

	//-------------------------------------------------------------------
	/**
	 * @param user the user to set
	 */
	public void setUser(Lifeform user) {
		this.user = user;
	}

	//-------------------------------------------------------------------
	public void addAccessory(CarriedItem val, Hook slot) {
		if (getSlot(slot)==null)
			throw new NullPointerException("No slot "+slot+" in item "+getKey());
		if (val.getUuid()!=null) {
			for (CarriedItem already : accessories) {
				if (val.getUuid().equals(already.getUuid()))
					throw new RuntimeException("Already added");
			}
		}
		logger.log(Level.INFO, "Add accessory ''{0}'' to slot {1}", val.getKey(), slot);
		val.setUsedSlot(slot);
		val.parent = this;
		accessories.add(val);
		getSlot(slot).addEmbeddedItem(val);
	}

	//-------------------------------------------------------------------
	public boolean removeAccessory(CarriedItem val, Hook slot) {
		boolean notFound = true;
		if (val.getUuid()!=null) {
			for (CarriedItem already : accessories) {
				if (val.getUuid().equals(already.getUuid()) || val==already)
					notFound = false;
			}
		}
		if (notFound) {
			for (CarriedItem already : accessories) {
				if (val==already)
					notFound = false;
			}
		}
		if (notFound) {
			logger.log(Level.ERROR, "{0}: No item Removed {1} with UUID {3} in {2}", getKey(), val, slot, val.getUuid());
			return false;
		}
		val.setUsedSlot(null);
		val.parent = null;
		accessories.remove(val);
		slots.get(slot).removeEmbeddedItem(val);
		logger.log(Level.DEBUG, "{0}: Removed {1} from {2}", getKey(), val, slot);
		return true;
	}

	//-------------------------------------------------------------------
	public List> getAccessories() {
		return accessories;
	}

	//-------------------------------------------------------------------
	public List> getAccessory(String id, String variant) {
		List> ret = new ArrayList<>();
		for (CarriedItem tmp : getEffectiveAccessories()) {
			if (!tmp.getKey().equals(id))
				continue;
			if (variant!=null && !variant.equals(tmp.getVariantID()))
				continue;
			ret.add(tmp);
		}
//		for (AAvailableSlot slot : getSlots()) {
//			for (CarriedItem tmp : slot.getAllEmbeddedItems()) {
//				if (!tmp.getKey().equals(id))
//					continue;
//				if (variant!=null && !variant.equals(tmp.getVariantID()))
//					continue;
//				ret.add(tmp);
//			}
//		}
		return ret;
	}

	//-------------------------------------------------------------------
	public Collection> getEffectiveAccessories() {
		List> ret = new ArrayList>();
		for (CarriedItem tmp : accessories) {
			ret.add(tmp);
			ret.addAll(tmp.getEffectiveAccessories());
		}
		return ret;
	}

	//-------------------------------------------------------------------
	/**
	 * @see de.rpgframework.genericrpg.data.ComplexDataItemValue#reset()
	 */
	@Override
	public void reset() {
		super.reset();
		clearModificationsFromCharacter();
		clearOutgoingModifications();
		autoEnhancements.clear();
		slots.clear();
		// Remove auto-added accessories
		for (CarriedItem tmp : new ArrayList(accessories)) {
			if ("DEFAULT".equals(tmp.getInjectedBy())) {
				accessories.remove(tmp);
			}
		}
		// Remove all modifications from item attributes
		for (ItemAttributeValue attr : attributes.values()) {
			attr.clearIncomingModifications();
		}

		clearIncomingModifications();
		// Remove dynamic flags
		autoFlags.clear();
	}

	//-------------------------------------------------------------------
	public > A getSlot(Hook slot) {
		return (A) slots.get(slot);
	}

	//-------------------------------------------------------------------
	public Collection> getSlots() {
		return slots.values();
	}

	//-------------------------------------------------------------------
	public void addSlot(AAvailableSlot slot) {
//		logger.log(Level.ERROR, "#######ADD SLOT "+slot);
//		try {
//			throw new Exception("Trace");
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		System.exit(1);
		if (slots.containsKey(slot.getHook()))
			throw new IllegalStateException("Hook "+slot+" already exists");
		slots.put(slot.getHook(), slot);
	}

	//-------------------------------------------------------------------
	public void removeSlot(Hook hook) {
		slots.remove(hook);
	}

	//-------------------------------------------------------------------
	/**
	 * @return the slot
	 */
	public Hook getUsedSlot() {
		return slot;
	}

	//-------------------------------------------------------------------
	/**
	 * @param slot the slot to set
	 */
	public void setUsedSlot(Hook slot) {
		this.slot = slot;
	}

	//-------------------------------------------------------------------
	/**
	 * @return the mode
	 */
	public CarryMode getCarryMode() {
		return mode;
	}

	//-------------------------------------------------------------------
	/**
	 * @param mode the mode to set
	 */
	public void setCarryMode(CarryMode mode) {
		this.mode = mode;
	}

	//-------------------------------------------------------------------
	/**
	 * @return the notes
	 */
	public String getNotes() {
		return notes;
	}

	//-------------------------------------------------------------------
	/**
	 * @param notes the notes to set
	 */
	public void setNotes(String notes) {
		this.notes = notes;
	}

	//-------------------------------------------------------------------
	public byte[] getImage() {
		return image;
	}

	//-------------------------------------------------------------------
	public void setImage(byte[] image) {
		this.image = image;
	}

	//-------------------------------------------------------------------
	public boolean hasAttribute(IItemAttribute key) {
		return attributes.containsKey(key);
	}

	//-------------------------------------------------------------------
	/**
	 * @return the dirty
	 */
	public boolean isDirty() {
		return dirty;
	}

	//-------------------------------------------------------------------
	/**
	 * @param dirty the dirty to set
	 */
	public void setDirty(boolean dirty) {
		this.dirty = dirty;
	}

	//-------------------------------------------------------------------
	public CarriedItem getEmbeddedItem(String id) {
		for (CarriedItem tmp : getEffectiveAccessories()) {
			if (tmp.getKey().equals(id))
				return tmp;
		}
		return null;
	}

	//-------------------------------------------------------------------
	public List getOperationModes(boolean recursive) {
		List options = new ArrayList<>();
		@SuppressWarnings("unchecked")
		List modes = getResolved().getOperationModes();
		if (!modes.isEmpty()) {
			OperationModeOption option = new OperationModeOption(this, modes) ;
			options.add( option);
		}

		// Recurse accessories
		if (recursive) {
			for (CarriedItem acc : getAccessories()) {
				options.addAll(acc.getOperationModes(true));
			}
		}
		return new ArrayList(options);
	}

	//-------------------------------------------------------------------
	public List getActiveOperationModes(boolean recursive) {
		List ret = new ArrayList<>();
		if (mode!=null) {
			List modes = getResolved().getOperationModes();
			for (OperationMode tmp : modes) {
				if (tmp.id.equals(activeMode)) {
					ret.add(tmp);
				}
			}
		}

		// Recurse accessories
		if (recursive) {
			for (CarriedItem acc : getAccessories()) {
				ret.addAll(acc.getActiveOperationModes(true));
			}
		}
		return ret;
	}

	//-------------------------------------------------------------------
	public void setMode(OperationMode mode, boolean active) {
		if (!active) {
			if (mode.getId().equals(activeMode)) {
				activeMode = null;
				dirty = true;
			}
			return;
		}

		List modes = getResolved().getOperationModes();
		for (OperationMode tmp : modes) {
			if (tmp==mode) {
				activeMode = mode.id;
				dirty = true;
				break;
			}
		}
	}

	//-------------------------------------------------------------------
	public void addAutoEnhancement(ItemEnhancementValue value) {
		autoEnhancements.add(value);
	}

	//-------------------------------------------------------------------
	public  List> getEnhancements() {
		List> ret = new ArrayList<>();
		autoEnhancements.forEach(e -> ret.add(e));
		enhancements.forEach(e -> ret.add(e));
		return ret;
	}

	//-------------------------------------------------------------------
	@SuppressWarnings("unchecked")
	public  ItemEnhancementValue getEnhancement(E data) {
		for (ItemEnhancementValue val : enhancements) {
			if (val.getResolved()==data)
				return val;
		}
		return null;
	}

	//-------------------------------------------------------------------
	public boolean hasEnhancement(AItemEnhancement value) {
		return getEnhancements().stream().anyMatch(e -> e.getResolved().equals(value));
	}

	//-------------------------------------------------------------------
	public void addEnhancement(ItemEnhancementValue value) {
		enhancements.add(value);
		dirty = true;
	}

	//-------------------------------------------------------------------
	public void removeEnhancement(ItemEnhancementValue value) {
		enhancements.remove(value);
		dirty = true;
	}

	//-------------------------------------------------------------------
	public int getModificationSlotsUsed() {
		int capacityUsed = 0;
		for (ItemEnhancementValue tmp : getEnhancements()) {
			if (!tmp.isAutoAdded())
				capacityUsed+= tmp.getResolved().getSize();
		}
		return capacityUsed;
	}

	//-------------------------------------------------------------------
	public List> getAlternates() {
		return alternates;
	}

	//-------------------------------------------------------------------
	public void addAlternates(CarriedItem alt) {
		this.alternates.add(alt);
	}

	//-------------------------------------------------------------------
	public void clearAlternates() {
		this.alternates.clear();
	}

	//-------------------------------------------------------------------
	/**
	 * @see de.rpgframework.genericrpg.data.IReferenceResolver#resolveItem(java.lang.String)
	 */
	@Override
	public  T resolveItem(String key) {
		return ((IReferenceResolver)resolved).resolveItem(key);
	}

	//-------------------------------------------------------------------
	public CarriedItem getParent() {
		return parent;
	}
	public void setParent(CarriedItem parent) { this.parent = parent; }

	//-------------------------------------------------------------------
	/**
	 * @return the modificationSlotChanges
	 */
	public int[] getModificationSlotChanges() {
		return modificationSlotChanges;
	}

	//-------------------------------------------------------------------
	/**
	 * @param modificationSlotChanges the modificationSlotChanges to set
	 */
	public void setModificationSlotChanges(int[] modificationSlotChanges) {
		this.modificationSlotChanges = modificationSlotChanges;
	}

	//-------------------------------------------------------------------
	public void setLastRecalculateResult(OperationResult> unprocessed) {
		this.lastRecalculateResult = unprocessed;
	}

	//-------------------------------------------------------------------
	public OperationResult> getLastRecalculateResult() {
		return this.lastRecalculateResult;
	}

	//-------------------------------------------------------------------
	public void clearModificationsFromCharacter() {
		for (ItemAttributeValue val : attributes.values()) {
			val.removeIncomingModifications(Origin.OUTSIDE);
		}
	}

//	//-------------------------------------------------------------------
//	/**
//	 * @see de.rpgframework.genericrpg.modification.Modifyable#setIncomingModifications(java.util.List)
//	 */
//	@Override
//	public void removeIncomingModification(Modification mod) {
//		super.removeIncomingModification(mod);
//		dirty = true;
//	}

	//-------------------------------------------------------------------
	public void addModificationFromCharacter(ValueModification mod) {
		mod.setOrigin(Origin.OUTSIDE);
		ItemAttributeValue val = getAttributeRaw( (IItemAttribute)mod.getResolvedKey());
		if (val==null) {
			logger.log(Level.ERROR, "Trying to add modification to unknown attribute {0} in {1}",mod.getResolvedKey(), this.getKey());
		}
		val.addIncomingModification(mod);
	}

	//-------------------------------------------------------------------
	public List getAllowedHooks() {
		return allowedHooks;
	}

	//-------------------------------------------------------------------
	public void setAllowedHooks(Collection value) {
		allowedHooks.clear();
		allowedHooks.addAll(value);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy