001package squidpony.squidgrid.gui.gdx;
002
003import com.badlogic.gdx.graphics.g2d.Batch;
004import com.badlogic.gdx.graphics.g2d.TextureRegion;
005import com.badlogic.gdx.scenes.scene2d.Group;
006import com.badlogic.gdx.graphics.Color;
007import squidpony.squidgrid.Direction;
008
009import java.util.ArrayList;
010import java.util.LinkedHashSet;
011
012/**
013 * A helper class to make using multiple SquidPanels easier.
014 * There is some useful documentation in this class' getPalette method (honestly, I don't know where else to put
015 * documentation specifically about this class' default palette)..
016 * Created by Tommy Ettinger on 7/6/2015.
017 */
018public class SquidLayers extends Group {
019    protected int width;
020    protected int height;
021    protected int cellWidth;
022    protected int cellHeight;
023    protected SquidPanel backgroundPanel, lightnessPanel, foregroundPanel;
024    protected int[][] bgIndices;
025    protected int[][] lightnesses;
026    protected ArrayList<SquidPanel> extraPanels;
027    protected TextCellFactory textFactory;
028    protected ArrayList<Color> palette, lightingPalette;
029    protected boolean[][] values;
030    protected float animationDuration;
031
032    public static final char EMPTY_CELL = '\0';
033    /**
034     * The pixel width of the entire map.
035     *
036     * @return
037     */
038    @Override
039    public float getWidth() {
040        return width * cellWidth;
041    }
042
043    /**
044     * The pixel height of the entire map.
045     *
046     * @return
047     */
048    @Override
049    public float getHeight() {
050        return height * cellHeight;
051    }
052
053    /**
054     * Width of the map in grid cells.
055     *
056     * @return
057     */
058    public int getGridWidth() {
059        return width;
060    }
061
062    /**
063     * Height of the map in grid cells.
064     *
065     * @return
066     */
067    public int getGridHeight() {
068        return height;
069    }
070
071    /**
072     * Width of one cell in pixels.
073     *
074     * @return
075     */
076    public int getCellWidth() {
077        return cellWidth;
078    }
079
080    /**
081     * Height of one cell in pixels.
082     *
083     * @return
084     */
085    public int getCellHeight() {
086        return cellHeight;
087    }
088
089    public float getAnimationDuration() {
090        return animationDuration;
091    }
092
093    public void setAnimationDuration(float animationDuration) {
094        this.animationDuration = animationDuration;
095    }
096
097    public TextCellFactory getTextFactory() {
098        return textFactory;
099    }
100
101    /**
102     * Gets the current palette used when no other is specified.
103     *
104     * The palette can be customized with SquidLayers.alterPalette() and SquidLayers.extendPalette() .
105     * 
106     * The default palette has colors at these elements:
107     * <ul>
108     * <li>0: Black, also used for backgrounds if not specified</li>
109     * <li>1: Off-white, used as the default foreground at times</li>
110     * <li>2: Dark gray for walls</li>
111     * <li>3: Silver gray for floors</li>
112     * <li>4: Rust brown for doors</li>
113     * <li>5: Gray-blue for water</li>
114     * <li>6: Bright orange for traps</li>
115     * <li>7: White</li>
116     * <li>8: Light gray</li>
117     * <li>9: Dark gray</li>
118     * <li>10: Light red</li>
119     * <li>11: Medium red</li>
120     * <li>12: Dark red</li>
121     * <li>13: Light orange</li>
122     * <li>14: Medium orange</li>
123     * <li>15: Dark orange</li>
124     * <li>16: Light yellow</li>
125     * <li>17: Medium yellow</li>
126     * <li>18: Dark yellow</li>
127     * <li>19: Light green</li>
128     * <li>20: Medium green</li>
129     * <li>21: Dark green</li>
130     * <li>22: Light blue-green</li>
131     * <li>23: Medium blue-green</li>
132     * <li>24: Dark blue-green</li>
133     * <li>25: Light blue</li>
134     * <li>26: Medium blue</li>
135     * <li>27: Dark blue</li>
136     * <li>28: Light purple</li>
137     * <li>29: Medium purple</li>
138     * <li>30: Dark purple</li>
139     * <li>31: Light pink</li>
140     * <li>32: Medium pink</li>
141     * <li>33: Dark pink</li>
142     * <li>34: Light gray-brown</li>
143     * <li>35: Medium gray-brown</li>
144     * <li>36: Dark gray-brown</li>
145     * <li>37: Light brown</li>
146     * <li>38: Medium brown</li>
147     * <li>39: Dark brown</li>
148     * </ul>
149     *
150     * @return the current Color ArrayList used as a default palette.
151     */
152    public ArrayList<Color> getPalette() {
153        return palette;
154    }
155
156    /**
157     * Get the lightness modifiers used for background cells as an int[][], with elements between 0 and 511, 256 as the
158     * unmodified lightness level, lower numbers meaning darker, and higher meaning lighter.
159     *
160     * @return
161     */
162    public int[][] getLightnesses() {
163        return lightnesses;
164    }
165
166    /**
167     * Get all the background color indices at once, which are probably indexed into the default palette. See the
168     * documentation for the getPalette() method in this class for more information.
169     *
170     * @return
171     */
172    public int[][] getBgIndices() {
173        return bgIndices;
174    }
175
176    /**
177     * Sets the lightness modifiers used for background cells with the int[][] passed as lightnesses. This 2D array
178     * should have elements between 0 to 511, with 256 as the unmodified lightness level, lower numbers meaning darker,
179     * and higher meaning lighter. Elements less than 0 or higher than 511 will probably cause array out-of-bounds
180     * exceptions to be thrown when this renders, so just don't do that. This doesn't validate because maps can get
181     * large, validating many cells could be expensive, and this might be called often if it's being called at all.
182     *
183     * @param lightnesses 2D array, width and height should match this class' gridWidth and gridHeight. elements must
184     *                    be between 0 and 511.
185     */
186    public void setLightnesses(int[][] lightnesses) {
187        this.lightnesses = lightnesses;
188    }
189
190    /**
191     * Set all of the background colors at once, using indexes into what is probably the default palette unless
192     * otherwise specified in the call to put(). If you want subtle variations on a color, don't add a new entry to
193     * the default palette every time if you can set the lightness differently for things with that color. Indices
194     * should correspond to the numbers in getPalette()'s documentation, or higher if you extended it.
195     *
196     * @param bgIndices 2D array, width and height should match this class' gridWidth and gridHeight.
197     */
198    public void setBgIndices(int[][] bgIndices) {
199        this.bgIndices = bgIndices;
200    }
201
202    /**
203     * Create a new SquidLayers widget with the default <b>square</b> font, 40 cells wide and high, with a size of
204     * 12x12 pixels for each cell.
205     */
206    public SquidLayers() {
207        this(40, 40);
208    }
209
210    /**
211     * Create a new SquidLayers widget with the default <b>square</b> font, the given number of cells for gridWidth
212     * and gridHeight, and 12x12 pixels for each cell.
213     *
214     * @param gridWidth  in grid cells
215     * @param gridHeight in grid cells
216     */
217    public SquidLayers(int gridWidth, int gridHeight) {
218        super();
219        initPalettes();
220        width = gridWidth;
221        height = gridHeight;
222
223        cellWidth = 12;
224        cellHeight = 12;
225
226        bgIndices = new int[width][height];
227        lightnesses = new int[width][height];
228        values = new boolean[width][height];
229
230        for (int x = 0; x < width; x++) {
231            for (int y = 0; y < height; y++) {
232                lightnesses[x][y] = 256;
233            }
234        }
235
236        textFactory = new TextCellFactory().defaultSquareFont().width(12).height(12).initBySize();
237
238        backgroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
239        lightnessPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
240        foregroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
241        animationDuration = foregroundPanel.DEFAULT_ANIMATION_DURATION;
242
243        extraPanels = new ArrayList<SquidPanel>();
244
245        super.addActorAt(0, backgroundPanel);
246        super.addActorAt(1, lightnessPanel);
247        super.addActorAt(2, foregroundPanel);
248
249        this.setSize(backgroundPanel.getWidth(), backgroundPanel.getHeight());
250    }
251
252    /**
253     * Create a new SquidLayers widget with a default font (it will be square if cellWidth and cellHeight are equal, or
254     * narrow otherwise), the given number of cells for gridWidth
255     * and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
256     *
257     * @param gridWidth  in grid cells
258     * @param gridHeight in grid cells
259     * @param cellWidth  in pixels
260     * @param cellHeight in pixels
261     */
262    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight) {
263        super();
264        initPalettes();
265        width = gridWidth;
266        height = gridHeight;
267
268        this.cellWidth = cellWidth;
269        this.cellHeight = cellHeight;
270
271        bgIndices = new int[width][height];
272        lightnesses = new int[width][height];
273        values = new boolean[width][height];
274        for (int x = 0; x < width; x++) {
275            for (int y = 0; y < height; y++) {
276                lightnesses[x][y] = 256;
277            }
278        }
279
280        textFactory = new TextCellFactory();
281        if (cellHeight == cellWidth) {
282            textFactory = textFactory.defaultSquareFont();
283        } else {
284            textFactory = textFactory.defaultNarrowFont();
285        }
286        textFactory = textFactory.width(cellWidth).height(cellHeight).initBySize();
287        backgroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
288        lightnessPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
289        foregroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
290        animationDuration = foregroundPanel.DEFAULT_ANIMATION_DURATION;
291
292        extraPanels = new ArrayList<SquidPanel>();
293
294        super.addActorAt(0, backgroundPanel);
295        super.addActorAt(1, lightnessPanel);
296        super.addActorAt(2, foregroundPanel);
297
298        this.setSize(backgroundPanel.getWidth(), backgroundPanel.getHeight());
299    }
300
301    /**
302     * Create a new SquidLayers widget with the given path to a Font file, the given number of cells for gridWidth
303     * and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
304     *
305     * @param gridWidth  in grid cells
306     * @param gridHeight in grid cells
307     * @param cellWidth  in pixels
308     * @param cellHeight in pixels
309     * @param fontpath   A Font that should have been assigned a size before being passed here.
310     */
311    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, String fontpath) {
312        super();
313        initPalettes();
314
315        width = gridWidth;
316        height = gridHeight;
317
318        this.cellWidth = cellWidth;
319        this.cellHeight = cellHeight;
320
321        bgIndices = new int[width][height];
322        lightnesses = new int[width][height];
323        values = new boolean[width][height];
324        for (int x = 0; x < width; x++) {
325            for (int y = 0; y < height; y++) {
326                lightnesses[x][y] = 256;
327            }
328        }
329
330        textFactory = new TextCellFactory().font(fontpath).width(cellWidth).height(cellHeight).initBySize();
331
332        backgroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
333        lightnessPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
334        foregroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory);
335        animationDuration = foregroundPanel.DEFAULT_ANIMATION_DURATION;
336
337        extraPanels = new ArrayList<SquidPanel>();
338
339        super.addActorAt(0, backgroundPanel);
340        super.addActorAt(1, lightnessPanel);
341        super.addActorAt(2, foregroundPanel);
342
343        this.setSize(backgroundPanel.getWidth(), backgroundPanel.getHeight());
344    }
345
346    private void initPalettes() {
347        palette = new ArrayList<Color>(256);
348        palette.add(SColor.DARK_SLATE_GRAY);
349        palette.add(SColor.CREAM);
350        palette.add(SColor.FLATTERY_BROWN);
351        palette.add(SColor.SILVER_GREY);
352        palette.add(SColor.RUST);
353        palette.add(SColor.WATER);
354        palette.add(SColor.INTERNATIONAL_ORANGE);
355
356        palette.add(SColor.WHITE);
357        palette.add(SColor.LIGHT_GRAY);
358        palette.add(SColor.DARK_GRAY);
359
360        palette.add(SColor.RED_INCENSE);
361        palette.add(SColor.RED);
362        palette.add(SColor.COCHINEAL_RED);
363
364        palette.add(SColor.PEACH_ORANGE);
365        palette.add(SColor.ORANGE_PEEL);
366        palette.add(SColor.TANGERINE);
367
368        palette.add(SColor.LEMON_CHIFFON);
369        palette.add(SColor.CORN);
370        palette.add(SColor.GOLDEN_YELLOW);
371
372        palette.add(SColor.TEA_GREEN);
373        palette.add(SColor.LIME_GREEN);
374        palette.add(SColor.GREEN_BAMBOO);
375
376        palette.add(SColor.BABY_BLUE);
377        palette.add(SColor.CYAN);
378        palette.add(SColor.BLUE_GREEN);
379
380        palette.add(SColor.COLUMBIA_BLUE);
381        palette.add(SColor.ROYAL_BLUE);
382        palette.add(SColor.PERSIAN_BLUE);
383
384        palette.add(SColor.LAVENDER_BLUE);
385        palette.add(SColor.THIN_VIOLET);
386        palette.add(SColor.DARK_VIOLET);
387
388        palette.add(SColor.CARNATION_PINK);
389        palette.add(SColor.HOT_MAGENTA);
390        palette.add(SColor.LIGHT_MAROON);
391
392        palette.add(SColor.TAN);
393        palette.add(SColor.DARK_TAN);
394        palette.add(SColor.PALE_BROWN);
395
396        palette.add(SColor.STEAMED_CHESTNUT);
397        palette.add(SColor.DARK_CHESTNUT);
398        palette.add(SColor.SAPPANWOOD_INCENSE);
399
400        lightingPalette = new ArrayList<Color>(512);
401        for (int i = 0; i < 512; i++) {
402            lightingPalette.add(Color.CLEAR);
403        }
404        for (int i = 1; i < 256; i++) {
405            lightingPalette.set(256 + i, new Color(1.0f, 0xFD / 255f, 0xD8 / 255f, i / 255f));
406            lightingPalette.set(256 - i, new Color(0, 0, 0, i / 255f));
407        }
408
409    }
410
411    /**
412     * Add an extra layer on top of the foreground layer. Use putInto methods to specify the layer when adding a char (0
413     * is background, 1 is lightness modifiers, 2 is foreground, and the first call to this method creates layer 3).
414     *
415     * @return
416     */
417    public SquidLayers addExtraLayer() {
418        SquidPanel sp = new SquidPanel(width, height, textFactory);
419        super.addActor(sp);
420        extraPanels.add(sp);
421        return this;
422    }
423
424    /**
425     * Adds a color to the end of the default palette, then returns that palette.
426     * 
427     * The default palette's entries can be seen in the documentation for SquidLayers.getPalette() .
428     *
429     * @param color
430     * @return
431     */
432    public ArrayList<Color> extendPalette(Color color) {
433        palette.add(color);
434        return palette;
435    }
436
437    /**
438     * Changes a color at the specified index in the default palette, then returns that palette.
439     * 
440     * If the index is greater than or equal to the number of colors in the palette, does nothing.
441     * 
442     * The default palette's entries can be seen in the documentation for SquidLayers.getPalette() .
443     *
444     * @param index must be at least 0 and less than the length of palette (starts at length 40).
445     * @param color
446     * @return
447     */
448    public ArrayList<Color> alterPalette(int index, Color color) {
449        if (index >= 0 && index < palette.size())
450            palette.set(index, color);
451
452        return palette;
453    }
454
455    /**
456     * Place a char c into the foreground at position x, y, with the default color.
457     *
458     * @param x in grid cells.
459     * @param y in grid cells.
460     * @param c a character to be drawn in the foreground
461     */
462    public SquidLayers put(int x, int y, char c) {
463        foregroundPanel.put(x, y, c);
464        values[x][y] = true;
465        return this;
466    }
467
468    /**
469     * Place a char c into the foreground, with a foreground color specified by an index into the default palette.
470     *
471     * @param x               in grid cells.
472     * @param y               in grid cells.
473     * @param c               a character to be drawn in the foreground
474     * @param foregroundIndex int index into the default palette for the char being drawn
475     */
476    public SquidLayers put(int x, int y, char c, int foregroundIndex) {
477        foregroundPanel.put(x, y, c, foregroundIndex, palette);
478        values[x][y] = true;
479        return this;
480    }
481
482    /**
483     * Place a char c into the foreground, with a foreground color specified by an index into the default palette.
484     *
485     * @param x               in grid cells.
486     * @param y               in grid cells.
487     * @param c               a character to be drawn in the foreground
488     * @param foreground    Color for the char being drawn
489     */
490    public SquidLayers put(int x, int y, char c, Color foreground) {
491        foregroundPanel.put(x, y, c, foreground);
492        values[x][y] = true;
493        return this;
494    }
495
496    /**
497     * Place a char c into the foreground, with a foreground color specified by an index into the default palette, and a
498     * background color specified in the same way.
499     *
500     * @param x               in grid cells.
501     * @param y               in grid cells.
502     * @param c               a character to be drawn in the foreground
503     * @param foregroundIndex int index into the default palette for the char being drawn
504     * @param backgroundIndex int index into the default palette for the background
505     */
506    public SquidLayers put(int x, int y, char c, int foregroundIndex, int backgroundIndex) {
507        foregroundPanel.put(x, y, c, foregroundIndex, palette);
508        backgroundPanel.put(x, y, backgroundIndex, palette);
509        values[x][y] = true;
510        return this;
511    }
512    /**
513     * Place a char c into the foreground, with a foreground color specified by an index into the default palette, and a
514     * background color specified in the same way.
515     *
516     * @param x               in grid cells.
517     * @param y               in grid cells.
518     * @param c               a character to be drawn in the foreground
519     * @param foreground    Color for the char being drawn
520     * @param background    Color for the background
521     */
522    public SquidLayers put(int x, int y, char c, Color foreground, Color background) {
523        foregroundPanel.put(x, y, c, foreground);
524        backgroundPanel.put(x, y, background);
525        values[x][y] = true;
526        return this;
527    }
528
529    /**
530     * Place a char c into the foreground, with a foreground color specified by an index into the default palette, a
531     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
532     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
533     *
534     * @param x                   in grid cells.
535     * @param y                   in grid cells.
536     * @param c                   a character to be drawn in the foreground
537     * @param foregroundIndex     int index into the default palette for the char being drawn
538     * @param backgroundIndex     int index into the default palette for the background
539     * @param backgroundLightness int between -255 and 255 , lower numbers are darker, higher lighter.
540     */
541    public SquidLayers put(int x, int y, char c, int foregroundIndex, int backgroundIndex, int backgroundLightness) {
542        backgroundLightness = clamp(backgroundLightness, -255, 255);
543        foregroundPanel.put(x, y, c, foregroundIndex, palette);
544        values[x][y] = true;
545        lightnesses[x][y] = 256 + backgroundLightness;
546
547        lightnessPanel.put(x, y, 256 + backgroundLightness, lightingPalette);
548        backgroundPanel.put(x, y, backgroundIndex, palette);
549        return this;
550    }
551    /**
552     * Place a char c into the foreground, with a foreground color specified by an index into alternatePalette, a
553     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
554     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
555     *
556     * @param x                   in grid cells.
557     * @param y                   in grid cells.
558     * @param c                   a character to be drawn in the foreground
559     * @param alternatePalette    an alternate Color ArrayList for both foreground and background
560     * @param foregroundIndex     int index into alternatePalette for the char being drawn
561     * @param backgroundIndex     int index into alternatePalette for the background
562     * @param backgroundLightness int between -255 and 255 , lower numbers are darker, higher lighter.
563     */
564    public SquidLayers put(int x, int y, char c, ArrayList<Color> alternatePalette, int foregroundIndex, int backgroundIndex, int backgroundLightness) {
565        backgroundLightness = clamp(backgroundLightness, -255, 255);
566        foregroundPanel.put(x, y, c, foregroundIndex, alternatePalette);
567        values[x][y] = true;
568        lightnesses[x][y] = 256 + backgroundLightness;
569
570        lightnessPanel.put(x, y, 256 + backgroundLightness, lightingPalette);
571        backgroundPanel.put(x, y, backgroundIndex, alternatePalette);
572        return this;
573    }
574
575    /**
576     * Place a char c into the foreground, with a foreground and background libGDX Color and a lightness variation for
577     * the background (0 is no change, 100 is very bright, -100 is very dark, anything past -150 or 150 will make the
578     * background almost fully black or white).
579     *
580     * @param x                   in grid cells.
581     * @param y                   in grid cells.
582     * @param c                   a character to be drawn in the foreground
583     * @param foreground            Color for the char being drawn
584     * @param background            Color for the background
585     * @param backgroundLightness int between -255 and 255 , lower numbers are darker, higher lighter.
586     */
587    public SquidLayers put(int x, int y, char c, Color foreground, Color background, int backgroundLightness) {
588        backgroundLightness = clamp(backgroundLightness, -255, 255);
589        foregroundPanel.put(x, y, c, foreground);
590        values[x][y] = true;
591        lightnesses[x][y] = 256 + backgroundLightness;
592
593        lightnessPanel.put(x, y, 256 + backgroundLightness, lightingPalette);
594        backgroundPanel.put(x, y, background);
595        return this;
596    }
597
598    /**
599     * Place a char c into the foreground, with a foreground color specified by an index into alternatePalette, a
600     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
601     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
602     *
603     * @param x                   in grid cells.
604     * @param y                   in grid cells.
605     * @param c                   a character to be drawn in the foreground
606     * @param foregroundIndex     int index into alternatePalette for the char being drawn
607     * @param fgPalette           an alternate Color ArrayList for the foreground; can be null to use the default.
608     * @param backgroundIndex     int index into alternatePalette for the background
609     * @param bgPalette           an alternate Color ArrayList for the background; can be null to use the default.
610     * @param backgroundLightness int between -255 and 255 , lower numbers are darker, higher lighter.
611     */
612    public SquidLayers put(int x, int y, char c, int foregroundIndex, ArrayList<Color> fgPalette, int backgroundIndex, ArrayList<Color> bgPalette, int backgroundLightness) {
613        backgroundLightness = clamp(backgroundLightness, -255, 255);
614        if (fgPalette == null) fgPalette = palette;
615        if (bgPalette == null) bgPalette = palette;
616        foregroundPanel.put(x, y, c, foregroundIndex, fgPalette);
617        values[x][y] = true;
618        lightnesses[x][y] = 256 + backgroundLightness;
619
620        lightnessPanel.put(x, y, 256 + backgroundLightness, lightingPalette);
621        backgroundPanel.put(x, y, backgroundIndex, bgPalette);
622        return this;
623    }
624
625
626    public SquidLayers put(int x, int y, char[][] c) {
627        foregroundPanel.put(x, y, c);
628        for (int i = x; i < c.length && i < width; i++) {
629            for (int j = y; j < c[i].length && j < height; j++) {
630                values[i][j] = true;
631            }
632        }
633        return this;
634    }
635
636    public SquidLayers put(int x, int y, char[][] c, int[][] foregroundIndex) {
637        foregroundPanel.put(x, y, c, foregroundIndex, palette);
638        for (int i = x; i < c.length && i < width; i++) {
639            for (int j = y; j < c[i].length && j < height; j++) {
640                values[i][j] = true;
641            }
642        }
643        return this;
644    }
645
646    public SquidLayers put(int x, int y, char c[][], int[][] foregroundIndex, int[][] backgroundIndex) {
647        foregroundPanel.put(x, y, c, foregroundIndex, palette);
648        for (int i = x; i < c.length && i < width; i++) {
649            for (int j = y; j < c[i].length && j < height; j++) {
650                values[i][j] = true;
651            }
652        }
653        backgroundPanel.put(x, y, backgroundIndex, palette);
654        return this;
655    }
656
657    /**
658     * Place a char[][] c into the foreground, with a foreground color specified by an index into alternatePalette, a
659     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
660     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
661     *
662     * @param x                   in grid cells.
663     * @param y                   in grid cells.
664     * @param c                   char[][] to be drawn in the foreground starting from x, y
665     * @param foregroundIndex     int[][] of indices into the default palette for the char being drawn
666     * @param backgroundIndex     int[][] of indices into the default palette for the background
667     * @param backgroundLightness int[][] with elements between -255 and 255 , lower darker, higher lighter.
668     */
669    public SquidLayers put(int x, int y, char[][] c, int[][] foregroundIndex, int[][] backgroundIndex, int[][] backgroundLightness) {
670        foregroundPanel.put(x, y, c, foregroundIndex, palette);
671        for (int i = x; i < width && i < backgroundLightness.length; i++) {
672            for (int j = y; j < height && j < backgroundLightness[i].length; j++) {
673                lightnesses[i][j] = 256 + clamp(backgroundLightness[i][j], -255, 255);
674                values[i][j] = true;
675            }
676        }
677        lightnessPanel.put(0, 0, lightnesses, lightingPalette);
678        backgroundPanel.put(x, y, backgroundIndex, palette);
679        return this;
680    }
681
682    /**
683     * Place a char c into the foreground, with a foreground color specified by an index into alternatePalette, a
684     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
685     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
686     *
687     * @param x                   in grid cells.
688     * @param y                   in grid cells.
689     * @param c                   char[][] to be drawn in the foreground starting from x, y
690     * @param alternatePalette    an alternate Color ArrayList for both foreground and background
691     * @param foregroundIndex     int[][] of indices into alternatePalette for the char being drawn
692     * @param backgroundIndex     int[][] of indices into alternatePalette for the background
693     * @param backgroundLightness int[][] with elements between -255 and 255 , lower darker, higher lighter.
694     */
695    public SquidLayers put(int x, int y, char[][] c, ArrayList<Color> alternatePalette, int[][] foregroundIndex, int[][] backgroundIndex, int[][] backgroundLightness) {
696
697        if (alternatePalette == null) alternatePalette = palette;
698        foregroundPanel.put(x, y, c, foregroundIndex, alternatePalette);
699        for (int i = x; i < width && i < backgroundLightness.length; i++) {
700            for (int j = y; j < height && j < backgroundLightness[i].length; j++) {
701                lightnesses[i][j] = 256 + clamp(backgroundLightness[i][j], -255, 255);
702                values[i][j] = true;
703            }
704        }
705        lightnessPanel.put(0, 0, lightnesses, lightingPalette);
706        backgroundPanel.put(x, y, backgroundIndex, alternatePalette);
707        return this;
708    }
709    /**
710     * Place a char c into the foreground, with a foreground color specified by an index into alternatePalette, a
711     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
712     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
713     *
714     * @param x                   in grid cells.
715     * @param y                   in grid cells.
716     * @param c                   char[][] to be drawn in the foreground starting from x, y
717     * @param foregrounds     int[][] of indices into alternatePalette for the char being drawn
718     * @param backgrounds     int[][] of indices into alternatePalette for the background
719     * @param backgroundLightness int[][] with elements between -255 and 255 , lower darker, higher lighter.
720     */
721    public SquidLayers put(int x, int y, char[][] c, Color[][] foregrounds, Color[][] backgrounds, int[][] backgroundLightness) {
722
723        foregroundPanel.put(x, y, c, foregrounds);
724        for (int i = x; i < width && i < backgroundLightness.length; i++) {
725            for (int j = y; j < height && j < backgroundLightness[i].length; j++) {
726                lightnesses[i][j] = 256 + clamp(backgroundLightness[i][j], -255, 255);
727                values[i][j] = true;
728            }
729        }
730        lightnessPanel.put(0, 0, lightnesses, lightingPalette);
731        backgroundPanel.put(x, y, backgrounds);
732        return this;
733    }
734
735    /**
736     * Place a char c into the foreground, with a foreground color specified by an index into alternatePalette, a
737     * background color specified in the same way, and a lightness variation for the background (0 is no change, 100 is
738     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
739     *
740     * @param x                   in grid cells.
741     * @param y                   in grid cells.
742     * @param c                   char[][] to be drawn in the foreground starting from x, y
743     * @param foregroundIndex     int[][] of indices into fgPalette for the char being drawn
744     * @param fgPalette           an alternate Color ArrayList for the foreground; can be null to use the default.
745     * @param backgroundIndex     int[][] of indices into bgPalette for the background
746     * @param bgPalette           an alternate Color ArrayList for the background; can be null to use the default.
747     * @param backgroundLightness int[][] with elements between -255 and 255 , lower darker, higher lighter.
748     */
749    public SquidLayers put(int x, int y, char[][] c, int[][] foregroundIndex, ArrayList<Color> fgPalette, int[][] backgroundIndex, ArrayList<Color> bgPalette, int[][] backgroundLightness) {
750        if (fgPalette == null) fgPalette = palette;
751        if (bgPalette == null) bgPalette = palette;
752        foregroundPanel.put(x, y, c, foregroundIndex, fgPalette);
753        for (int i = x; i < width && i < backgroundLightness.length; i++) {
754            for (int j = y; j < height && j < backgroundLightness[i].length; j++) {
755                lightnesses[i][j] = 256 + clamp(backgroundLightness[i][j], -255, 255);
756                values[i][j] = true;
757            }
758        }
759        lightnessPanel.put(0, 0, lightnesses, lightingPalette);
760        backgroundPanel.put(x, y, backgroundIndex, bgPalette);
761        return this;
762    }
763
764    /**
765     * Place a char c[][] into the specified layer, with a color specified by an index into alternatePalette.
766     *
767     * @param layer 0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
768     * @param x     in grid cells.
769     * @param y     in grid cells.
770     * @param c     char[][] to be drawn in the foreground starting from x, y
771     */
772    public SquidLayers putInto(int layer, int x, int y, char c) {
773        SquidPanel p = backgroundPanel;
774        switch (layer) {
775            case 0:
776                break;
777            case 1:
778                p = lightnessPanel;
779                break;
780            case 2:
781                p = foregroundPanel;
782                break;
783            default:
784                p = extraPanels.get(layer - 3);
785        }
786        p.put(x, y, c);
787        values[x][y] = true;
788        return this;
789    }
790
791    /**
792     * Place a char c[][] into the specified layer, with a color specified by an index into the default palette.
793     *
794     * @param layer      0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
795     * @param x          in grid cells.
796     * @param y          in grid cells.
797     * @param c          char[][] to be drawn in the foreground starting from x, y
798     * @param colorIndex int[][] of indices into alternatePalette for the char being drawn
799     */
800    public SquidLayers putInto(int layer, int x, int y, char c, int colorIndex) {
801        SquidPanel p = backgroundPanel;
802        switch (layer) {
803            case 0:
804                break;
805            case 1:
806                p = lightnessPanel;
807                break;
808            case 2:
809                p = foregroundPanel;
810                break;
811            default:
812                p = extraPanels.get(layer - 3);
813        }
814        p.put(x, y, c, colorIndex, palette);
815        values[x][y] = true;
816        return this;
817    }
818
819    /**
820     * Place a char c[][] into the specified layer, with a color specified by an index into alternatePalette.
821     *
822     * @param layer            0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
823     * @param x                in grid cells.
824     * @param y                in grid cells.
825     * @param c                char[][] to be drawn in the foreground starting from x, y
826     * @param alternatePalette an alternate Color ArrayList for both foreground and background
827     * @param colorIndex       int[][] of indices into alternatePalette for the char being drawn
828     */
829    public SquidLayers putInto(int layer, int x, int y, char c, ArrayList<Color> alternatePalette, int colorIndex) {
830        SquidPanel p = backgroundPanel;
831        switch (layer) {
832            case 0:
833                break;
834            case 1:
835                p = lightnessPanel;
836                break;
837            case 2:
838                p = foregroundPanel;
839                break;
840            default:
841                p = extraPanels.get(layer - 3);
842        }
843        if (alternatePalette == null) alternatePalette = palette;
844        p.put(x, y, c, colorIndex, alternatePalette);
845        values[x][y] = true;
846        return this;
847    }
848
849    /**
850     * Place a char c[][] into the specified layer, with a color specified by an index into alternatePalette.
851     *
852     * @param layer 0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
853     * @param x     in grid cells.
854     * @param y     in grid cells.
855     * @param c     char[][] to be drawn in the foreground starting from x, y
856     */
857    public SquidLayers putInto(int layer, int x, int y, char[][] c) {
858        SquidPanel p = backgroundPanel;
859        switch (layer) {
860            case 0:
861                break;
862            case 1:
863                p = lightnessPanel;
864                break;
865            case 2:
866                p = foregroundPanel;
867                break;
868            default:
869                p = extraPanels.get(layer - 3);
870        }
871        p.put(x, y, c);
872        for (int i = x; i < c.length && i < width; i++) {
873            for (int j = y; j < c[i].length && j < height; j++) {
874                values[i][j] = true;
875            }
876        }
877        return this;
878    }
879
880    /**
881     * Place a char c[][] into the specified layer, with a color specified by an index into the default palette.
882     *
883     * @param layer      0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
884     * @param x          in grid cells.
885     * @param y          in grid cells.
886     * @param c          char[][] to be drawn in the foreground starting from x, y
887     * @param colorIndex int[][] of indices into alternatePalette for the char being drawn
888     */
889    public SquidLayers putInto(int layer, int x, int y, char[][] c, int[][] colorIndex) {
890        SquidPanel p = backgroundPanel;
891        switch (layer) {
892            case 0:
893                break;
894            case 1:
895                p = lightnessPanel;
896                break;
897            case 2:
898                p = foregroundPanel;
899                break;
900            default:
901                p = extraPanels.get(layer - 3);
902        }
903        p.put(x, y, c, colorIndex, palette);
904        for (int i = x; i < c.length && i < width; i++) {
905            for (int j = y; j < c[i].length && j < height; j++) {
906                values[i][j] = true;
907            }
908        }
909        return this;
910    }
911
912    /**
913     * Place a char c[][] into the specified layer, with a color specified by an index into alternatePalette.
914     *
915     * @param layer            0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
916     * @param x                in grid cells.
917     * @param y                in grid cells.
918     * @param c                char[][] to be drawn in the foreground starting from x, y
919     * @param alternatePalette an alternate Color ArrayList for both foreground and background
920     * @param colorIndex       int[][] of indices into alternatePalette for the char being drawn
921     */
922    public SquidLayers putInto(int layer, int x, int y, char[][] c, ArrayList<Color> alternatePalette, int[][] colorIndex) {
923        SquidPanel p = backgroundPanel;
924        switch (layer) {
925            case 0:
926                break;
927            case 1:
928                p = lightnessPanel;
929                break;
930            case 2:
931                p = foregroundPanel;
932                break;
933            default:
934                p = extraPanels.get(layer - 3);
935        }
936        if (alternatePalette == null) alternatePalette = palette;
937        p.put(x, y, c, colorIndex, alternatePalette);
938        for (int i = x; i < c.length && i < width; i++) {
939            for (int j = y; j < c[i].length && j < height; j++) {
940                values[i][j] = true;
941            }
942        }
943        return this;
944    }
945
946    /**
947     * Place a char c[][] into the specified layer, with a color specified by an index into alternatePalette.
948     *
949     * @param layer            0 for background, 1 for lightness, 2 for foreground, 3 or higher for extra layers added on.
950     * @param x                in grid cells.
951     * @param y                in grid cells.
952     * @param c                char[][] to be drawn in the foreground starting from x, y
953     * @param colors          int[][] of indices into alternatePalette for the char being drawn
954     */
955    public SquidLayers putInto(int layer, int x, int y, char[][] c, Color[][] colors) {
956        SquidPanel p = backgroundPanel;
957        switch (layer) {
958            case 0:
959                break;
960            case 1:
961                p = lightnessPanel;
962                break;
963            case 2:
964                p = foregroundPanel;
965                break;
966            default:
967                p = extraPanels.get(layer - 3);
968        }
969        p.put(x, y, c, colors);
970        for (int i = x; i < c.length && i < width; i++) {
971            for (int j = y; j < c[i].length && j < height; j++) {
972                values[i][j] = true;
973            }
974        }
975        return this;
976    }
977
978    /**
979     * Put a string at the given x, y position, using the default color.
980     *
981     * @param x in grid cells.
982     * @param y in grid cells.
983     * @param s the string to print
984     * @return this, for chaining
985     */
986    public SquidLayers putString(int x, int y, String s) {
987        foregroundPanel.put(x, y, s);
988        return this;
989    }
990
991    /**
992     * Put a string at the given x, y position, with the given index for foreground color that gets looked up in the
993     * default palette.
994     *
995     * @param x               in grid cells.
996     * @param y               in grid cells.
997     * @param s               the string to print
998     * @param foregroundIndex
999     * @return this, for chaining
1000     */
1001    public SquidLayers putString(int x, int y, String s, int foregroundIndex) {
1002        foregroundPanel.put(x, y, s, palette.get(foregroundIndex));
1003        return this;
1004    }
1005
1006    /**
1007     * Put a string at the given x, y position, with the given indices for foreground and background color that look up
1008     * their index in the default palette.
1009     *
1010     * @param x               in grid cells.
1011     * @param y               in grid cells.
1012     * @param s               the string to print
1013     * @param foregroundIndex
1014     * @param backgroundIndex
1015     * @return this, for chaining
1016     */
1017    public SquidLayers putString(int x, int y, String s, int foregroundIndex, int backgroundIndex) {
1018        foregroundPanel.put(x, y, s, palette.get(foregroundIndex));
1019        for (int i = x; i < s.length() && i < width; i++) {
1020            backgroundPanel.put(i, y, palette.get(backgroundIndex));
1021        }
1022        return this;
1023    }
1024
1025    /**
1026     * Put a string at the given x, y position, with the given indices for foreground and background color that look up
1027     * their index in alternatePalette.
1028     *
1029     * @param x                in grid cells.
1030     * @param y                in grid cells.
1031     * @param s                the string to print
1032     * @param alternatePalette
1033     * @param foregroundIndex
1034     * @param backgroundIndex
1035     * @return this, for chaining
1036     */
1037    public SquidLayers putString(int x, int y, String s, ArrayList<Color> alternatePalette, int foregroundIndex, int backgroundIndex) {
1038        foregroundPanel.put(x, y, s, alternatePalette.get(foregroundIndex));
1039        for (int i = x; i < s.length() && i < width; i++) {
1040            backgroundPanel.put(i, y, alternatePalette.get(backgroundIndex));
1041        }
1042        return this;
1043    }
1044    /**
1045     * Put a string at the given x, y position, with the given indices for foreground and background color that look up
1046     * their index in alternatePalette.
1047     *
1048     * @param x                in grid cells.
1049     * @param y                in grid cells.
1050     * @param s                the string to print
1051     * @param foreground      the Color of the string's chars
1052     * @param background      the Color of the background of the string
1053     * @return this, for chaining
1054     */
1055    public SquidLayers putString(int x, int y, String s, Color foreground, Color background) {
1056        foregroundPanel.put(x, y, s, foreground);
1057        for (int i = x; i < s.length() && i < width; i++) {
1058            backgroundPanel.put(i, y, background);
1059        }
1060        return this;
1061    }
1062
1063    /**
1064     * A utility method that draws a 1-cell-wide black box around the text you request (as s) and replaces the contents
1065     * of anything that was below or adjacent to the string's new position. Useful for message boxes.
1066     *
1067     * @param x in grid cells.
1068     * @param y in grid cells.
1069     * @param s the string to print inside the box
1070     * @return this, for chaining
1071     */
1072    public SquidLayers putBoxedString(int x, int y, String s) {
1073        if (y > 0 && y + 1 < height && x > 0 && x + 1 < width) {
1074            for (int j = y - 1; j < y + 2 && j < height; j++) {
1075                for (int i = x - 1; i < s.length() + x + 2 && i < width; i++) {
1076                    foregroundPanel.put(i, j, ' ');
1077                    backgroundPanel.put(i, j, palette.get(9));
1078                    lightnesses[i][j] = -255;
1079                    lightnessPanel.put(i, j, 1, lightingPalette);
1080                }
1081            }
1082        }
1083        foregroundPanel.put(x, y, s, palette.get(1));
1084
1085        return this;
1086    }
1087
1088    /**
1089     * Change the lightness for the background of the cell at x, y (0 is no change, 100 is
1090     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
1091     *
1092     * @param x                   in grid cells.
1093     * @param y                   in grid cells.
1094     * @param lightness int between -255 and 255 , lower numbers are darker, higher lighter.
1095     */
1096    public SquidLayers highlight(int x, int y, int lightness) {
1097        lightness = clamp(lightness, -255, 255);
1098        lightnesses[x][y] = 256 + lightness;
1099
1100        lightnessPanel.put(x, y, 256 + lightness, lightingPalette);
1101        return this;
1102    }
1103    /**
1104     * Change the lightness for the background of the cell at x, y (0 is no change, 100 is
1105     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
1106     *
1107     * @param x                   in grid cells.
1108     * @param y                   in grid cells.
1109     * @param lightness int[][] with elements between -255 and 255 , lower numbers are darker, higher lighter.
1110     */
1111    public SquidLayers highlight(int x, int y, int[][] lightness) {
1112        for (int i = 0; i < lightness.length && x + i < width; i++) {
1113            for (int j = 0; j < lightness[i].length && y + j < height; j++) {
1114                lightness[i][j] = 256 + clamp(lightness[i][j], -255, 255);
1115                lightnesses[x+i][y+j] = lightness[i][j];
1116            }
1117        }
1118        lightnessPanel.put(x, y, lightness, lightingPalette);
1119        return this;
1120    }
1121    /**
1122     * Very basic check to see if something was rendered at the x,y cell requested. (usually this only checks the
1123     * foreground) If blank, false, otherwise true.
1124     *
1125     * @param x in grid cells.
1126     * @param y in grid cells.
1127     * @return
1128     */
1129    public boolean hasValue(int x, int y) {
1130        return values[x][y];
1131    }
1132
1133    /**
1134     * Clear one cell at position x, y of  its foreground contents.
1135     * 
1136     * You may be looking for the erase() method, which erases all panels and all cells.
1137     *
1138     * @param x in grid cells
1139     * @param y in grid cells
1140     * @return
1141     */
1142    public SquidLayers clear(int x, int y) {
1143        foregroundPanel.clear(x, y);
1144        values[x][y] = false;
1145        return this;
1146    }
1147
1148    /**
1149     * Erase everything visible in all cells or all layers.  This can be expensive to do in a traditional game loop,
1150     * since Swing is not meant for that at all.
1151     *
1152     * @return this, for chaining
1153     */
1154    public SquidLayers erase() {
1155        foregroundPanel.erase();
1156        lightnessPanel.erase();
1157        backgroundPanel.erase();
1158        for (SquidPanel sp : extraPanels) {
1159            sp.erase();
1160        }
1161        for (int i = 0; i < width; i++) {
1162            for (int j = 0; j < height; j++) {
1163                values[i][j] = false;
1164            }
1165        }
1166        return this;
1167    }
1168
1169    public SquidLayers bump(int x, int y, int layer, Direction dir, float duration) {
1170        SquidPanel p = foregroundPanel;
1171        switch (layer) {
1172            case 0:
1173                p = backgroundPanel;
1174                break;
1175            case 1:
1176                p = lightnessPanel;
1177                break;
1178            case 2:
1179                break;
1180            default:
1181                p = extraPanels.get(layer - 3);
1182        }
1183        if (duration < 0)
1184            duration = animationDuration;
1185        p.bump(x, y, dir, duration);
1186        return this;
1187    }
1188    public SquidLayers bump(AnimatedEntity ae, int layer, Direction dir, float duration) {
1189        SquidPanel p = foregroundPanel;
1190        switch (layer) {
1191            case 0:
1192                p = backgroundPanel;
1193                break;
1194            case 1:
1195                p = lightnessPanel;
1196                break;
1197            case 2:
1198                break;
1199            default:
1200                p = extraPanels.get(layer - 3);
1201        }
1202        if (duration < 0)
1203            duration = animationDuration;
1204        p.bump(ae, dir, duration);
1205        return this;
1206    }
1207
1208    public SquidLayers bump(int x, int y, Direction dir) {
1209        return bump(x, y, 2, dir, -1);
1210    }
1211    public SquidLayers bump(AnimatedEntity ae, Direction dir) {
1212        return bump(ae, 2, dir, -1);
1213    }
1214
1215    public SquidLayers slide(AnimatedEntity ae, int endX, int endY, int layer, float duration) {
1216        SquidPanel p = foregroundPanel;
1217        switch (layer) {
1218            case 0:
1219                p = backgroundPanel;
1220                break;
1221            case 1:
1222                p = lightnessPanel;
1223                break;
1224            case 2:
1225                break;
1226            default:
1227                p = extraPanels.get(layer - 3);
1228        }
1229        if (duration < 0)
1230            duration = animationDuration;
1231        p.slide(ae, endX, endY, duration);
1232        return this;
1233    }
1234    public SquidLayers slide(int x, int y, int endX, int endY, int layer, float duration) {
1235        SquidPanel p = foregroundPanel;
1236        switch (layer) {
1237            case 0:
1238                p = backgroundPanel;
1239                break;
1240            case 1:
1241                p = lightnessPanel;
1242                break;
1243            case 2:
1244                break;
1245            default:
1246                p = extraPanels.get(layer - 3);
1247        }
1248        if (duration < 0)
1249            duration = animationDuration;
1250        p.slide(x, y, endX, endY, duration);
1251        return this;
1252    }
1253
1254    public SquidLayers slide(int x, int y, int endX, int endY) {
1255        return slide(x, y, endX, endY, 2, -1);
1256    }
1257    public SquidLayers slide(AnimatedEntity ae, int endX, int endY) {
1258        return slide(ae, endX, endY, 2, -1);
1259    }
1260
1261    public SquidLayers wiggle(int x, int y, int layer, float duration) {
1262        SquidPanel p = foregroundPanel;
1263        switch (layer) {
1264            case 0:
1265                p = backgroundPanel;
1266                break;
1267            case 1:
1268                p = lightnessPanel;
1269                break;
1270            case 2:
1271                break;
1272            default:
1273                p = extraPanels.get(layer - 3);
1274        }
1275        if (duration < 0)
1276            duration = animationDuration;
1277        p.wiggle(x, y, duration);
1278        return this;
1279    }
1280    public SquidLayers wiggle(AnimatedEntity ae, int layer, float duration) {
1281        SquidPanel p = foregroundPanel;
1282        switch (layer) {
1283            case 0:
1284                p = backgroundPanel;
1285                break;
1286            case 1:
1287                p = lightnessPanel;
1288                break;
1289            case 2:
1290                break;
1291            default:
1292                p = extraPanels.get(layer - 3);
1293        }
1294        if (duration < 0)
1295            duration = animationDuration;
1296        p.wiggle(ae, duration);
1297        return this;
1298    }
1299
1300    public SquidLayers wiggle(int x, int y) {
1301        return wiggle(x, y, 2, -1);
1302    }
1303    public SquidLayers wiggle(AnimatedEntity ae) {
1304        return wiggle(ae, 2, -1);
1305    }
1306    public SquidLayers tint(int x, int y, Color color, int layer, float duration) {
1307        SquidPanel p = foregroundPanel;
1308        switch (layer) {
1309            case 0:
1310                p = backgroundPanel;
1311                break;
1312            case 1:
1313                p = lightnessPanel;
1314                break;
1315            case 2:
1316                break;
1317            default:
1318                p = extraPanels.get(layer - 3);
1319        }
1320        if (duration < 0)
1321            duration = animationDuration;
1322        p.tint(x, y, color, duration);
1323        return this;
1324    }
1325    public SquidLayers tint(AnimatedEntity ae, Color color, int layer, float duration) {
1326        SquidPanel p = foregroundPanel;
1327        switch (layer) {
1328            case 0:
1329                p = backgroundPanel;
1330                break;
1331            case 1:
1332                p = lightnessPanel;
1333                break;
1334            case 2:
1335                break;
1336            default:
1337                p = extraPanels.get(layer - 3);
1338        }
1339        if (duration < 0)
1340            duration = animationDuration;
1341        p.tint(ae, color, duration);
1342        return this;
1343    }
1344
1345    public SquidLayers tint(int x, int y, Color color) {
1346        return tint(x, y, color, 2, -1);
1347    }
1348    public SquidLayers tint(AnimatedEntity ae, Color color) {
1349        return tint(ae, color, 2, -1);
1350    }
1351
1352    public boolean hasActiveAnimations() {
1353        if (foregroundPanel.hasActiveAnimations())
1354            return true;
1355        if (backgroundPanel.hasActiveAnimations())
1356            return true;
1357        if (lightnessPanel.hasActiveAnimations())
1358            return true;
1359        for (SquidPanel panel : extraPanels) {
1360            if (panel.hasActiveAnimations())
1361                return true;
1362        }
1363        return false;
1364    }
1365
1366    public AnimatedEntity animateActor(int x, int y, char c, Color color, int layer) {
1367        SquidPanel p = foregroundPanel;
1368        switch (layer) {
1369            case 0:
1370                p = backgroundPanel;
1371                break;
1372            case 1:
1373                p = lightnessPanel;
1374                break;
1375            case 2:
1376                break;
1377            default:
1378                p = extraPanels.get(layer - 3);
1379        }
1380        return p.animateActor(x, y, c, color);
1381    }
1382
1383    public AnimatedEntity animateActor(int x, int y, char c, Color color) {
1384        return foregroundPanel.animateActor(x, y, c, color);
1385    }
1386    public AnimatedEntity animateActor(int x, int y, char c, Color color, boolean doubleWidth) {
1387        return foregroundPanel.animateActor(x, y, doubleWidth, c, color);
1388    }
1389
1390    public AnimatedEntity animateActor(int x, int y, char c, int index, ArrayList<Color> palette, int layer) {
1391        return animateActor(x, y, c, palette.get(index), layer);
1392    }
1393    public AnimatedEntity animateActor(int x, int y, char c, int index, ArrayList<Color> palette) {
1394        return animateActor(x, y, c, palette.get(index));
1395    }
1396
1397    public AnimatedEntity animateActor(int x, int y, char c, int index, int layer) {
1398        return animateActor(x, y, c, palette.get(index), layer);
1399    }
1400    public AnimatedEntity animateActor(int x, int y, char c, int index) {
1401        return animateActor(x, y, c, palette.get(index));
1402    }
1403    public AnimatedEntity animateActor(int x, int y, char c, int index, boolean doubleWidth) {
1404        return animateActor(x, y, c, palette.get(index), doubleWidth);
1405    }
1406
1407    public AnimatedEntity animateActor(int x, int y, String s, Color color, int layer) {
1408        SquidPanel p = foregroundPanel;
1409        switch (layer) {
1410            case 0:
1411                p = backgroundPanel;
1412                break;
1413            case 1:
1414                p = lightnessPanel;
1415                break;
1416            case 2:
1417                break;
1418            default:
1419                p = extraPanels.get(layer - 3);
1420        }
1421        return p.animateActor(x, y, s, color);
1422    }
1423    public AnimatedEntity animateActor(int x, int y, String s, Color color, int layer, boolean doubleWidth) {
1424        SquidPanel p = foregroundPanel;
1425        switch (layer) {
1426            case 0:
1427                p = backgroundPanel;
1428                break;
1429            case 1:
1430                p = lightnessPanel;
1431                break;
1432            case 2:
1433                break;
1434            default:
1435                p = extraPanels.get(layer - 3);
1436        }
1437        return p.animateActor(x, y, doubleWidth, s, color);
1438    }
1439    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, int layer) {
1440        SquidPanel p = foregroundPanel;
1441        switch (layer) {
1442            case 0:
1443                p = backgroundPanel;
1444                break;
1445            case 1:
1446                p = lightnessPanel;
1447                break;
1448            case 2:
1449                break;
1450            default:
1451                p = extraPanels.get(layer - 3);
1452        }
1453        return p.animateActor(x, y, tr, color);
1454    }
1455    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, int layer, boolean doubleWidth, boolean stretch) {
1456        SquidPanel p = foregroundPanel;
1457        switch (layer) {
1458            case 0:
1459                p = backgroundPanel;
1460                break;
1461            case 1:
1462                p = lightnessPanel;
1463                break;
1464            case 2:
1465                break;
1466            default:
1467                p = extraPanels.get(layer - 3);
1468        }
1469        return p.animateActor(x, y, doubleWidth, stretch, tr, color);
1470    }
1471
1472    public AnimatedEntity animateActor(int x, int y, String s, Color color) {
1473        return foregroundPanel.animateActor(x, y, s, color);
1474    }
1475    public AnimatedEntity animateActor(int x, int y, String s, Color color, boolean doubleWidth) {
1476        return foregroundPanel.animateActor(x, y, doubleWidth, s, color);
1477    }
1478
1479    public AnimatedEntity animateActor(int x, int y, String s, int index, ArrayList<Color> palette, int layer) {
1480        return animateActor(x, y, s, palette.get(index), layer);
1481    }
1482    public AnimatedEntity animateActor(int x, int y, String s, int index, ArrayList<Color> palette) {
1483        return animateActor(x, y, s, palette.get(index));
1484    }
1485
1486    public AnimatedEntity animateActor(int x, int y, String s, int index, int layer) {
1487        return animateActor(x, y, s, palette.get(index), layer);
1488    }
1489    public AnimatedEntity animateActor(int x, int y, String s, int index) {
1490        return animateActor(x, y, s, palette.get(index));
1491    }
1492    public AnimatedEntity animateActor(int x, int y, String s, int index, boolean doubleWidth) {
1493        return animateActor(x, y, s, palette.get(index), doubleWidth);
1494    }
1495
1496    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color) {
1497        return foregroundPanel.animateActor(x, y, tr, color);
1498    }
1499    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, boolean doubleWidth) {
1500        return foregroundPanel.animateActor(x, y, doubleWidth, tr, color);
1501    }
1502    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, boolean doubleWidth, boolean stretch) {
1503        return foregroundPanel.animateActor(x, y, doubleWidth, stretch, tr, color);
1504    }
1505
1506    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, ArrayList<Color> palette, int layer) {
1507        return animateActor(x, y, tr, palette.get(index), layer);
1508    }
1509    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, ArrayList<Color> palette, int layer, boolean doubleWidth) {
1510        return animateActor(x, y, tr, palette.get(index), layer, doubleWidth, true);
1511    }
1512    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, ArrayList<Color> palette, int layer, boolean doubleWidth, boolean stretch) {
1513        return animateActor(x, y, tr, palette.get(index), layer, doubleWidth, stretch);
1514    }
1515    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, ArrayList<Color> palette) {
1516        return animateActor(x, y, tr, palette.get(index));
1517    }
1518    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, int layer) {
1519        return animateActor(x, y, tr, palette.get(index), layer);
1520    }
1521    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index) {
1522        return animateActor(x, y, tr, palette.get(index));
1523    }
1524    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, boolean doubleWidth) {
1525        return animateActor(x, y, tr, palette.get(index), doubleWidth);
1526    }
1527    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, int index, boolean doubleWidth, boolean stretch) {
1528        return animateActor(x, y, tr, palette.get(index), doubleWidth, stretch);
1529    }
1530    public AnimatedEntity animateActor(int x, int y, TextureRegion tr) {
1531        return animateActor(x, y, tr, Color.WHITE);
1532    }
1533    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, boolean doubleWidth) {
1534        return animateActor(x, y, tr, Color.WHITE, doubleWidth);
1535    }
1536    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, boolean doubleWidth, boolean stretch) {
1537        return animateActor(x, y, tr, Color.WHITE, doubleWidth, stretch);
1538    }
1539
1540    public LinkedHashSet<AnimatedEntity> getAnimatedEntities(int layer) {
1541        SquidPanel p = foregroundPanel;
1542        switch (layer) {
1543            case 0:
1544                p = backgroundPanel;
1545                break;
1546            case 1:
1547                p = lightnessPanel;
1548                break;
1549            case 2:
1550                break;
1551            default:
1552                p = extraPanels.get(layer - 3);
1553        }
1554        return p.getAnimatedEntities();
1555    }
1556
1557    public LinkedHashSet<AnimatedEntity> getAnimatedEntities() {
1558        return foregroundPanel.getAnimatedEntities();
1559    }
1560
1561    public AnimatedEntity getAnimatedEntityByCell(int x, int y, int layer) {
1562        SquidPanel p = foregroundPanel;
1563        switch (layer) {
1564            case 0:
1565                p = backgroundPanel;
1566                break;
1567            case 1:
1568                p = lightnessPanel;
1569                break;
1570            case 2:
1571                break;
1572            default:
1573                p = extraPanels.get(layer - 3);
1574        }
1575        return p.getAnimatedEntityByCell(x, y);
1576    }
1577
1578    public AnimatedEntity getAnimatedEntityByCell(int x, int y) {
1579        return foregroundPanel.getAnimatedEntityByCell(x, y);
1580    }
1581
1582    @Override
1583    public void draw(Batch batch, float parentAlpha) {
1584        super.draw(batch, parentAlpha);
1585    }
1586
1587    public void drawActor(Batch batch, float parentAlpha, AnimatedEntity ae, int layer)
1588    {
1589        SquidPanel p = foregroundPanel;
1590        switch (layer) {
1591            case 0:
1592                p = backgroundPanel;
1593                break;
1594            case 1:
1595                p = lightnessPanel;
1596                break;
1597            case 2:
1598                break;
1599            default:
1600                p = extraPanels.get(layer - 3);
1601        }
1602        p.drawActor(batch, parentAlpha, ae);
1603    }
1604    public void drawActor(Batch batch, float parentAlpha, AnimatedEntity ae)
1605    {
1606        foregroundPanel.drawActor(batch, parentAlpha, ae);
1607    }
1608
1609
1610    private int clamp(int x, int min, int max)
1611    {
1612        return Math.min(Math.max(min, x), max);
1613    }
1614
1615}