/* * 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.campaign; import java.awt.Color; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import com.t3.MD5Key; import com.t3.client.AppPreferences; import com.t3.client.ui.token.BarTokenOverlay; import com.t3.client.ui.token.BooleanTokenOverlay; import com.t3.client.ui.token.ColorDotTokenOverlay; import com.t3.client.ui.token.DiamondTokenOverlay; import com.t3.client.ui.token.ImageTokenOverlay; import com.t3.client.ui.token.MultipleImageBarTokenOverlay; import com.t3.client.ui.token.OTokenOverlay; import com.t3.client.ui.token.ShadedTokenOverlay; import com.t3.client.ui.token.SingleImageBarTokenOverlay; import com.t3.client.ui.token.TriangleTokenOverlay; import com.t3.client.ui.token.TwoImageBarTokenOverlay; import com.t3.client.ui.token.TwoToneBarTokenOverlay; import com.t3.client.ui.token.XTokenOverlay; import com.t3.client.ui.token.YieldTokenOverlay; import com.t3.guid.GUID; import com.t3.model.LightSource; import com.t3.model.LookupTable; import com.t3.model.ShapeType; import com.t3.model.SightType; import com.t3.util.math.CappedInteger; import com.t3.xstreamversioned.version.SerializationVersion; @SerializationVersion(0) public class CampaignProperties { public static final String DEFAULT_TOKEN_PROPERTY_TYPE = "Basic"; //FIXME make this a 2d HashMap private Map<String, List<TokenProperty>> tokenTypeMap; private List<String> remoteRepositoryList; private Map<String, Map<GUID, LightSource>> lightSourcesMap; private Map<String, LookupTable> lookupTableMap; private Map<String, SightType> sightTypeMap; private String defaultSightType; private Map<String, BooleanTokenOverlay> tokenStates; private Map<String, BarTokenOverlay> tokenBars; private Map<String, String> characterSheets; /** Flag indicating that owners have special permissions */ private boolean initiativeOwnerPermissions = AppPreferences.getInitOwnerPermissions(); /** Flag indicating that owners can only move tokens when they have initiative */ private boolean initiativeMovementLock = AppPreferences.getInitLockMovement(); public CampaignProperties() { init(); } public CampaignProperties(CampaignProperties properties) { tokenTypeMap = new HashMap<String, List<TokenProperty>>(); for (Entry<String, List<TokenProperty>> entry : properties.tokenTypeMap.entrySet()) { List<TokenProperty> typeList = new ArrayList<TokenProperty>(); typeList.addAll(properties.tokenTypeMap.get(entry.getKey())); tokenTypeMap.put(entry.getKey(), typeList); } remoteRepositoryList = new ArrayList<String>(properties.remoteRepositoryList); lookupTableMap = new HashMap<String, LookupTable>(); if (properties.lookupTableMap != null) { lookupTableMap.putAll(properties.lookupTableMap); } defaultSightType = properties.defaultSightType; sightTypeMap = new HashMap<String, SightType>(); if (properties.sightTypeMap != null) { sightTypeMap.putAll(properties.sightTypeMap); } // TODO: This doesn't feel right, should we deep copy, or does this do that automatically ? lightSourcesMap = new TreeMap<String, Map<GUID, LightSource>>(properties.lightSourcesMap); tokenStates = new LinkedHashMap<String, BooleanTokenOverlay>(); if (properties.tokenStates == null || properties.tokenStates.isEmpty()) { properties.initTokenStatesMap(); } for (BooleanTokenOverlay overlay : properties.tokenStates.values()) { overlay = (BooleanTokenOverlay) overlay.clone(); tokenStates.put(overlay.getName(), overlay); } // endfor tokenBars = new LinkedHashMap<String, BarTokenOverlay>(); if (properties.tokenBars == null || properties.tokenBars.isEmpty()) { properties.initTokenBarsMap(); } for (BarTokenOverlay overlay : properties.tokenBars.values()) { overlay = (BarTokenOverlay) overlay.clone(); tokenBars.put(overlay.getName(), overlay); } // endfor initiativeOwnerPermissions = properties.initiativeOwnerPermissions; initiativeMovementLock = properties.initiativeMovementLock; characterSheets = new HashMap<String, String>(); if (properties.characterSheets == null || properties.characterSheets.isEmpty()) { properties.initCharacterSheetsMap(); } for (String type : properties.characterSheets.keySet()) { characterSheets.put(type, properties.characterSheets.get(type)); } } public void mergeInto(CampaignProperties properties) { if (tokenTypeMap != null) { // This will replace any dups properties.tokenTypeMap.putAll(tokenTypeMap); } if (remoteRepositoryList != null) { // Need to cull out dups for (String repo : properties.remoteRepositoryList) { if (!remoteRepositoryList.contains(repo)) { remoteRepositoryList.add(repo); } } } if (lightSourcesMap != null) { properties.lightSourcesMap.putAll(lightSourcesMap); } if (lookupTableMap != null) { properties.lookupTableMap.putAll(lookupTableMap); } if (sightTypeMap != null) { properties.sightTypeMap.putAll(sightTypeMap); } if (tokenStates != null) { properties.tokenStates.putAll(tokenStates); } if (tokenBars != null) { properties.tokenBars.putAll(tokenBars); } } public Map<String, List<TokenProperty>> getTokenTypeMap() { if (tokenTypeMap == null) { initTokenTypeMap(); } return tokenTypeMap; } public Map<String, SightType> getSightTypeMap() { if (sightTypeMap == null) { initSightTypeMap(); } return sightTypeMap; } public void setSightTypeMap(Map<String, SightType> map) { if (map != null) { sightTypeMap = map; } } // TODO: This is for conversion from 1.3b19-1.3b20 public void setTokenTypeMap(Map<String, List<TokenProperty>> map) { tokenTypeMap = map; } public List<TokenProperty> getTokenPropertyList(String tokenType) { return getTokenTypeMap().get(tokenType); } public List<String> getRemoteRepositoryList() { if (remoteRepositoryList == null) { initRemoteRepositoryList(); } return remoteRepositoryList; } public void setRemoteRepositoryList(List<String> list) { remoteRepositoryList = list; } public Map<String, Map<GUID, LightSource>> getLightSourcesMap() { if (lightSourcesMap == null) { initLightSourcesMap(); } return lightSourcesMap; } public void setLightSourcesMap(Map<String, Map<GUID, LightSource>> map) { lightSourcesMap = map; } public Map<String, LookupTable> getLookupTableMap() { if (lookupTableMap == null) { initLookupTableMap(); } return lookupTableMap; } // TODO: This is for conversion from 1.3b19-1.3b20 public void setLookupTableMap(Map<String, LookupTable> map) { lookupTableMap = map; } public Map<String, BooleanTokenOverlay> getTokenStatesMap() { if (tokenStates == null) { initTokenStatesMap(); } return tokenStates; } public void setTokenStatesMap(Map<String, BooleanTokenOverlay> map) { tokenStates = map; } public Map<String, BarTokenOverlay> getTokenBarsMap() { if (tokenBars == null) { initTokenBarsMap(); } return tokenBars; } public void setTokenBarsMap(Map<String, BarTokenOverlay> map) { tokenBars = map; } private void init() { initLookupTableMap(); initLightSourcesMap(); initRemoteRepositoryList(); initTokenTypeMap(); initSightTypeMap(); initTokenStatesMap(); initTokenBarsMap(); initCharacterSheetsMap(); } private void initLookupTableMap() { if (lookupTableMap != null) { return; } lookupTableMap = new HashMap<String, LookupTable>(); } private void initLightSourcesMap() { if (lightSourcesMap != null) { return; } lightSourcesMap = new TreeMap<String, Map<GUID, LightSource>>(); Map<String, List<LightSource>> map = LightSource.getDefaultLightSources(); for (String key : map.keySet()) { Map<GUID, LightSource> lightSourceMap = new LinkedHashMap<GUID, LightSource>(); for (LightSource source : map.get(key)) { lightSourceMap.put(source.getId(), source); } lightSourcesMap.put(key, lightSourceMap); } } private void initRemoteRepositoryList() { if (remoteRepositoryList != null) { return; } remoteRepositoryList = new ArrayList<String>(); } public String getDefaultSightType() { return defaultSightType; } // @formatter:off private static final Object[][] starter = new Object[][] { // Sight Type Name Dist Mult Arc LtSrc Shape { "Normal", 0.0, 1.0, 0, null, null }, { "Lowlight", 0.0, 2.0, 0, null, null }, { "Square Vision", 0.0, 1.0, 0, null, ShapeType.SQUARE }, { "Normal Vision - Short Range", 12.5, 1.0, 0, null, ShapeType.CIRCLE }, { "Conic Vision", 0.0, 1.0, 120, null, ShapeType.CONE }, { "Darkvision", 62.5, 1.0, 0, null, null }, }; // @formatter:on private void initSightTypeMap() { sightTypeMap = new HashMap<String, SightType>(); for (Object[] row : starter) { SightType st = new SightType((String) row[0], (Double) row[2], (LightSource) row[4], (ShapeType) row[5], (Integer) row[3]); st.setDistance(((Double) row[1]).floatValue()); sightTypeMap.put((String) row[0], st); } SightType dv = sightTypeMap.get("Darkvision"); dv.setPersonalLightSource(LightSource.getDefaultLightSources().get("Generic").get(5)); // sightTypeMap.put("Darkvision & Lowlight", new SightType("Darkvision", 2, // LightSource.getDefaultLightSources().get("Generic").get(4))); defaultSightType = (String) starter[0][0]; } private void initTokenTypeMap() { if (tokenTypeMap != null) { return; } tokenTypeMap = new HashMap<String, List<TokenProperty>>(); List<TokenProperty> list = new ArrayList<TokenProperty>(12); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Strength", "Str")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Dexterity", "Dex")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Constitution", "Con")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Intelligence", "Int")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Wisdom", "Wis")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Charisma", "Char")); TokenProperty tp = new TokenProperty(TokenPropertyType.CAPPED,"HP", true, true, false); tp.setDefaultValue(new CappedInteger(10, 0, 10)); list.add(tp); list.add(new TokenProperty(TokenPropertyType.INTEGER,"AC", true, true, false)); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Defense", "Def")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Movement", "Mov")); list.add(new TokenProperty(TokenPropertyType.INTEGER,"Elevation", "Elv", true, false, false)); list.add(new TokenProperty(TokenPropertyType.TEXT,"Description", "Des")); tp=new TokenProperty(TokenPropertyType.BOOLEAN,"Female","fem"); tp.setDefaultValue(Boolean.FALSE); list.add(tp); tokenTypeMap.put(DEFAULT_TOKEN_PROPERTY_TYPE, list); } private void initTokenStatesMap() { tokenStates = new LinkedHashMap<String, BooleanTokenOverlay>(); tokenStates.put("Dead", (new XTokenOverlay("Dead", Color.RED, 5))); tokenStates.put("Disabled", (new XTokenOverlay("Disabled", Color.GRAY, 5))); tokenStates.put("Hidden", (new ShadedTokenOverlay("Hidden", Color.BLACK))); tokenStates.put("Prone", (new OTokenOverlay("Prone", Color.BLUE, 5))); tokenStates.put("Incapacitated", (new OTokenOverlay("Incapacitated", Color.RED, 5))); tokenStates.put("Other", (new ColorDotTokenOverlay("Other", Color.RED, null))); tokenStates.put("Other2", (new DiamondTokenOverlay("Other2", Color.RED, 5))); tokenStates.put("Other3", (new YieldTokenOverlay("Other3", Color.YELLOW, 5))); tokenStates.put("Other4", (new TriangleTokenOverlay("Other4", Color.MAGENTA, 5))); } private void initTokenBarsMap() { tokenBars = new LinkedHashMap<String, BarTokenOverlay>(); tokenBars.put("Health", new TwoToneBarTokenOverlay("Health", new Color(0x20b420), Color.BLACK, 6)); } private void initCharacterSheetsMap() { characterSheets = new HashMap<String, String>(); characterSheets.put("Basic", "com/t3/client/ui/forms/basicCharacterSheet.xml"); } public Set<MD5Key> getAllImageAssets() { Set<MD5Key> set = new HashSet<MD5Key>(); // Start with the table images for (LookupTable table : getLookupTableMap().values()) { set.addAll(table.getAllAssetIds()); } // States have images as well for (BooleanTokenOverlay overlay : getTokenStatesMap().values()) { if (overlay instanceof ImageTokenOverlay) set.add(((ImageTokenOverlay) overlay).getAssetId()); } // Bars for (BarTokenOverlay overlay : getTokenBarsMap().values()) { if (overlay instanceof SingleImageBarTokenOverlay) { set.add(((SingleImageBarTokenOverlay) overlay).getAssetId()); } else if (overlay instanceof TwoImageBarTokenOverlay) { set.add(((TwoImageBarTokenOverlay) overlay).getTopAssetId()); set.add(((TwoImageBarTokenOverlay) overlay).getBottomAssetId()); } else if (overlay instanceof MultipleImageBarTokenOverlay) { set.addAll(Arrays.asList(((MultipleImageBarTokenOverlay) overlay).getAssetIds())); } } return set; } /** @return Getter for initiativeOwnerPermissions */ public boolean isInitiativeOwnerPermissions() { return initiativeOwnerPermissions; } /** * @param initiativeOwnerPermissions * Setter for initiativeOwnerPermissions */ public void setInitiativeOwnerPermissions(boolean initiativeOwnerPermissions) { this.initiativeOwnerPermissions = initiativeOwnerPermissions; } /** @return Getter for initiativeMovementLock */ public boolean isInitiativeMovementLock() { return initiativeMovementLock; } /** * @param initiativeOwnerPermissions * Setter for initiativeMovementLock */ public void setInitiativeMovementLock(boolean initiativeMovementLock) { this.initiativeMovementLock = initiativeMovementLock; } /** * Getter for characterSheets. Only called by {@link Campaign#getCharacterSheets()} and that function is never used * elsewhere within TabletopTool. Yet. ;-) */ public Map<String, String> getCharacterSheets() { if (characterSheets == null) initCharacterSheetsMap(); return characterSheets; } /** * @param characterSheets * Setter for characterSheets */ public void setCharacterSheets(Map<String, String> characterSheets) { this.characterSheets = characterSheets; } }