/* * Copyright (c) 2014 tabletoptool.com team. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * rptools.com team - initial implementation * tabletoptool.com team - further development */ package com.t3.model; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import com.t3.MD5Key; import com.t3.chatparser.generated.ChatParser; import com.t3.chatparser.generated.ParseException; import com.t3.dice.expression.Expression; import com.t3.macro.MacroException; import com.t3.xstreamversioned.version.SerializationVersion; @SerializationVersion(0) public class LookupTable { private List<LookupEntry> entryList; private String name; private String defaultRoll; private MD5Key tableImage; private Boolean visible; private Boolean allowLookup; public LookupTable() { } public LookupTable(LookupTable table) { name = table.name; defaultRoll = table.defaultRoll; tableImage = table.tableImage; if (table.entryList != null) { getInternalEntryList().addAll(table.entryList); } } public void setRoll(String roll) { defaultRoll = roll; } public void clearEntries() { getInternalEntryList().clear(); } public void addEntry(int min, int max, String result, MD5Key imageId) { getInternalEntryList().add(new LookupEntry(min, max, result, imageId)); } public LookupEntry getLookup() throws MacroException { return getLookup(null); } public String getRoll() { return getDefaultRoll(); } public void setName(String name) { this.name = name; } public String getName() { return name; } public LookupEntry getLookup(String roll) throws MacroException { int tableResult = 0; // If the roll is null, we didn't get a passed in result, so roll // the table's default if (roll == null) { roll = getDefaultRoll(); try { Expression rollExpr= new ChatParser(roll).parseExpression(); roll = Float.toString(rollExpr.getResult()); } catch (ParseException e) { throw new MacroException("Could not parse dice Expression '"+roll+"'",e); } } try { // Translate the String into a Integer // Use ParseFloat to ensure the best match with // macro syntax tableResult = (int)Float.parseFloat(roll); Integer minmin = Integer.MAX_VALUE; Integer maxmax = Integer.MIN_VALUE; for (LookupEntry entry : getInternalEntryList()) { if(entry.min < minmin) { minmin = entry.min; } if(entry.max > maxmax) { maxmax = entry.max; } } if(tableResult > maxmax) { tableResult = maxmax; } if(tableResult < minmin) { tableResult = minmin; } for (LookupEntry entry : getInternalEntryList()) { if (tableResult >= entry.min && tableResult <= entry.max) { // Support for "/" commands return entry; } } } catch (NumberFormatException nfe) { throw new MacroException("Error lookup up value: " + tableResult,nfe); } throw new MacroException("Unknown table lookup: " + tableResult); } private String getDefaultRoll() { if (defaultRoll != null && defaultRoll.length() > 0) { return defaultRoll; } // Find the min and max range Integer min = null; Integer max = null; for (LookupEntry entry : getInternalEntryList()) { if (min == null || entry.min < min) { min = entry.min; } if (max == null || entry.max > max) { max = entry.max; } } return min != null ? "d" + (max - min + 1) + (min - 1 != 0 ? "+" + (min-1) : "") : ""; } private List<LookupEntry> getInternalEntryList() { if (entryList == null) { entryList = new ArrayList<LookupEntry>(); } return entryList; } public List<LookupEntry> getEntryList() { return Collections.unmodifiableList(getInternalEntryList()); } public MD5Key getTableImage() { return tableImage; } public void setTableImage(MD5Key tableImage) { this.tableImage = tableImage; } @Override public String toString() { StringBuilder builder = new StringBuilder(); for (LookupEntry entry : getInternalEntryList()) { if (entry.min == entry.max) { builder.append(entry.min); } else { builder.append(entry.min).append("-").append(entry.max); } builder.append("=").append(entry.value).append("\n"); } return builder.toString(); } @SerializationVersion(0) public static class LookupEntry { private int min; private int max; private String value; private MD5Key imageId; /** * @Deprecated here to prevent xstream from breaking b24-b25 */ private String result; public LookupEntry(int min, int max, String result, MD5Key imageId) { this.min = min; this.max = max; this.value = result; this.imageId = imageId; } public MD5Key getImageId() { return imageId; } public int getMax() { return max; } public int getMin() { return min; } public String getValue() { // Temporary fix to convert b24 to b25 if (result != null) { value = result; result = null; } return value; } } public Set<MD5Key> getAllAssetIds() { Set<MD5Key> assetSet = new HashSet<MD5Key>(); if (getTableImage() != null) { assetSet.add(getTableImage()); } for (LookupEntry entry : getEntryList()) { if (entry.getImageId() != null) { assetSet.add(entry.getImageId()); } } return assetSet; } /**Retrieves the visible flag for the LookupTable. * @return Boolean -- True indicates that the table will be * visible to players. False indicates that the table will * be hidden from players. */ public Boolean getVisible() { if(visible == null) { visible = new Boolean(true); } return visible; } /**Sets the visible flag for the LookupTable. * @param value(Boolean) -- True specifies that the table will * be visible to players. False indicates that the table will * be hidden from players. */ public void setVisible(Boolean value) { visible = value; } /**Retrieves the allowLookup flag for the LookupTable. * @return Boolean -- True indicates that players can call * for values from this table. False indicates that players * will be prevented from calling values from this table. * GM's can ALWAYS perform lookups against a table. */ public Boolean getAllowLookup() { if(allowLookup == null) { allowLookup = true; } return allowLookup; } /**Sets the allowLookup flag for the LookupTable. * @param value(Boolean) -- True indicates that players can call * for values from this table. False indicates that players * will be prevented from calling values from this table. * GM's can ALWAYS perform lookups against a table. */ public void setAllowLookup(Boolean value) { allowLookup = value; } }