1 /*************************************************************************** 2 * (C) Copyright 2003-2017 - Faiumoni e.V. * 3 *************************************************************************** 4 *************************************************************************** 5 * * 6 * This program is free software; you can redistribute it and/or modify * 7 * it under the terms of the GNU General Public License as published by * 8 * the Free Software Foundation; either version 2 of the License, or * 9 * (at your option) any later version. * 10 * * 11 ***************************************************************************/ 12 package games.stendhal.client.sprite; 13 14 import java.util.HashMap; 15 import java.util.Map; 16 17 import org.apache.log4j.Logger; 18 19 /** 20 * A tileset animation map. 21 */ 22 public class TilesetAnimationMap { 23 /** 24 * The default frame delay (in ms). 25 */ 26 static final int DEFAULT_DELAY = 500; 27 private static final Logger LOGGER = Logger.getLogger(TilesetAnimationMap.class); 28 29 /** 30 * The map of tileset animations. 31 */ 32 private Map<Integer, Mapping> animations; 33 34 /** 35 * Create a tileset animation map. 36 */ TilesetAnimationMap()37 public TilesetAnimationMap() { 38 animations = new HashMap<Integer, Mapping>(); 39 } 40 41 // 42 // TilesetAnimationMap 43 // 44 45 /** 46 * Add a mapping of a tile index to animation frame indexes. 47 * 48 * <strong>NOTE: The array of frame indexes/delays passed is not copied, and 49 * should not be altered after this is called.</strong> 50 * 51 * @param index 52 * The tile index to map. 53 * @param frameIndexes 54 * The indexes of frame tiles. 55 * @param frameDelays 56 * The frame delays (in ms). 57 */ add(final int index, final int[] frameIndexes, final int[] frameDelays)58 void add(final int index, final int[] frameIndexes, 59 final int[] frameDelays) { 60 animations.put(Integer.valueOf(index), new Mapping(frameIndexes, 61 frameDelays)); 62 } 63 64 /** 65 * Add mappings of a tile indexes to animation frame indexes. For each 66 * frame, a mapping will be created with the remaining indexes as it's 67 * frames (in order, starting with it's index). 68 * 69 * @param frameIndexes 70 * The indexes of frame tiles. 71 * @param frameDelays 72 * The frame delays (in ms). 73 * 74 * @throws IllegalArgumentException 75 * If the number of indexes and delays don't match. 76 */ add(final int[] frameIndexes, final int[] frameDelays)77 void add(final int[] frameIndexes, final int[] frameDelays) { 78 if (frameIndexes.length != frameDelays.length) { 79 throw new IllegalArgumentException( 80 "Mismatched number of frame indexes and delays"); 81 } 82 83 for (int i = 0; i < frameIndexes.length; i++) { 84 final int[] frames = new int[frameIndexes.length]; 85 final int[] delays = new int[frameIndexes.length]; 86 int tidx = i; 87 88 for (int fidx = 0; fidx < frameIndexes.length; fidx++) { 89 frames[fidx] = frameIndexes[tidx]; 90 delays[fidx] = frameDelays[tidx]; 91 92 if (++tidx >= frameIndexes.length) { 93 tidx = 0; 94 } 95 } 96 97 add(frameIndexes[i], frames, delays); 98 } 99 } 100 101 /** 102 * Get the animated sprite for an indexed tile of a tileset. 103 * 104 * @param tileset 105 * The tileset to load from. 106 * @param index 107 * The index with-in the tileset. 108 * 109 * @return A sprite, or <code>null</code> if no mapped sprite. 110 */ getSprite(final Tileset tileset, final int index)111 public Sprite getSprite(final Tileset tileset, final int index) { 112 final Mapping mapping = animations.get(Integer.valueOf(index)); 113 114 if (mapping == null) { 115 return null; 116 } 117 118 final int[] frameIndexes = mapping.getIndices(); 119 final int[] frameDelays = mapping.getDelays(); 120 121 final Sprite[] frames = new Sprite[frameIndexes.length]; 122 123 for (int i = 0; i < frameIndexes.length; i++) { 124 frames[i] = tileset.getSprite(frameIndexes[i]); 125 if (frames[i] == null) { 126 LOGGER.error("Invalid animation mapping. Tileset does not have " 127 + "tile index " + frameIndexes[i] + "."); 128 return null; 129 } 130 } 131 132 // Use the reference of the first frame as the reference for the whole 133 // group 134 Object ref = null; 135 Sprite first = frames[0]; 136 if (first != null) { 137 ref = first.getReference(); 138 } 139 return new AnimatedSprite(frames, frameDelays, true, ref); 140 } 141 142 // 143 // 144 145 /** 146 * A frame indexes/delays mapping entry for an animated tile. 147 */ 148 private static class Mapping { 149 /** 150 * The frame indexes. 151 */ 152 private int[] indices; 153 154 /** 155 * The frame delays. 156 */ 157 private int[] delays; 158 159 /** 160 * Create a new Mapping 161 * 162 * @param indices frame indices 163 * @param delays frame delays 164 */ Mapping(final int[] indices, final int[] delays)165 private Mapping(final int[] indices, final int[] delays) { 166 this.indices = indices; 167 this.delays = delays; 168 } 169 170 // 171 // Mapping 172 // 173 174 /** 175 * Get the delays. 176 * 177 * @return delays 178 */ getDelays()179 private int[] getDelays() { 180 return delays; 181 } 182 183 /** 184 * Get the indices 185 * 186 * @return delays 187 */ getIndices()188 private int[] getIndices() { 189 return indices; 190 } 191 } 192 } 193