001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.graphics.Color; 004import com.badlogic.gdx.math.Interpolation; 005import com.badlogic.gdx.scenes.scene2d.Action; 006import com.badlogic.gdx.scenes.scene2d.actions.Actions; 007import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction; 008import squidpony.ArrayTools; 009import squidpony.squidgrid.FOV; 010import squidpony.squidgrid.Radius; 011import squidpony.squidmath.Bresenham; 012import squidpony.squidmath.Coord; 013import squidpony.squidmath.DiverRNG; 014import squidpony.squidmath.GreasedRegion; 015import squidpony.squidmath.NumberTools; 016import squidpony.squidmath.SeededNoise; 017 018import java.util.Arrays; 019import java.util.List; 020 021/** 022 * Various special effects that can be applied to a {@link SquidPanel} or {@link SparseLayers} as an 023 * {@link com.badlogic.gdx.scenes.scene2d.Action}. The PanelEffect class is abstract and has implementations as static 024 * inner classes, such as {@link ExplosionEffect}. Each PanelEffect specifically affects one {@link IPackedColorPanel} 025 * (an interface that both SquidPanel and SparseLayers implement), which can be a layer in a SquidLayers object or a 026 * SquidPanel/SparseLayers on its own. By adding the PanelEffect to any actor using 027 * {@link com.badlogic.gdx.scenes.scene2d.Actor#addAction(Action)} when the Actor has its act() method called after the 028 * normal map parts of the panel have been placed, the PanelEffect will advance and change what chars/colors are in 029 * the panel as specified in its implementation of the {@link #update(float)} method. Typically the Actor you add this 030 * to is the SquidPanel or SparseLayers this affects, but it could also be a SquidLayers. Most PanelEffect 031 * implementations should allow most configuration to be set in their constructors. 032 * <br> 033 * Created by Tommy Ettinger on 5/24/2017. 034 */ 035public abstract class PanelEffect extends TemporalAction{ 036 public IPackedColorPanel target; 037 public GreasedRegion validCells; 038 039 protected PanelEffect(IPackedColorPanel targeting) 040 { 041 target = targeting; 042 validCells = new GreasedRegion(targeting.gridWidth(), targeting.gridHeight()).allOn(); 043 } 044 protected PanelEffect(IPackedColorPanel targeting, float duration) 045 { 046 target = targeting; 047 setDuration(duration); 048 validCells = new GreasedRegion(targeting.gridWidth(), targeting.gridHeight()).allOn(); 049 } 050 protected PanelEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid) 051 { 052 target = targeting; 053 setDuration(duration); 054 validCells = valid; 055 } 056 public static class ExplosionEffect extends PanelEffect 057 { 058 /** 059 * Normally you should set this in the constructor, and not change it later. 060 */ 061 public Coord center; 062 /** 063 * Normally you should set this in the constructor, and not change it later. 064 */ 065 public int radius = 2; 066 /** 067 * The default explosion colors are normal for (non-chemical, non-electrical) fire and smoke, going from orange 068 * at the start to yellow, very light yellow, and then back to a different orange before going to smoke and 069 * fading out to translucent and then transparent by the end. 070 * <br> 071 * If you want to change the colors the explosion uses, you can either pass a List of Color (or SColor or other 072 * subclasses) to the constructor or change this array directly. The float items assigned to this should be the 073 * result of calling {@link Color#toFloatBits()} or possibly the result of mixing multiple existing floats with 074 * {@link SColor#lerpFloatColors(float, float, float)}; other floats that can be directly used by libGDX, that 075 * is, packed as ABGR floats (usually the docs will call this a packed float), can also be used. 076 */ 077 public float[] colors = { 078 SColor.floatGet(0xFF4F00FF), // SColor.INTERNATIONAL_ORANGE 079 SColor.floatGet(0xFFB94EFF), // SColor.FLORAL_LEAF 080 SColor.floatGet(0xFDE910FF), // SColor.LEMON 081 SColor.floatGet(0xFFFACDFF), // SColor.LEMON_CHIFFON 082 SColor.floatGet(0xFF6600EE), // SColor.SAFETY_ORANGE 083 SColor.floatGet(0x595652DD), // SColor.DB_SOOT 084 SColor.floatGet(0x59565299) // SColor.DB_SOOT 085 }; 086 /** 087 * The internal representation of how affected each cell is by the explosion, based on proximity to center. 088 */ 089 public double[][] lightMap; 090 /** 091 * The raw list of Coords that might be affected by the explosion; may include some cells that aren't going to 092 * show as exploding (it usually has some false positives), but shouldn't exclude any cells that should show as 093 * such (no false negatives). You can edit this if you need to, but it isn't recommended. 094 */ 095 public List<Coord> affected; 096 /** 097 * Constructs an ExplosionEffect with explicit settings for some fields. The valid cells this can affect will be 098 * the full expanse of the IPackedColorPanel. The duration will be 1 second. 099 * @param targeting the IPackedColorPanel to affect 100 * @param center the center of the explosion 101 * @param radius the radius of the explosion, in cells 102 */ 103 104 public ExplosionEffect(IPackedColorPanel targeting, Coord center, int radius) 105 { 106 this(targeting, 1f, center, radius); 107 } 108 /** 109 * Constructs an ExplosionEffect with explicit settings for some fields. The valid cells this can affect will be 110 * the full expanse of the IPackedColorPanel. 111 * @param targeting the IPackedColorPanel to affect 112 * @param duration the duration of this PanelEffect in seconds, as a float 113 * @param center the center of the explosion 114 * @param radius the radius of the explosion, in cells 115 */ 116 public ExplosionEffect(IPackedColorPanel targeting, float duration, Coord center, int radius) 117 { 118 super(targeting, duration); 119 this.center = center; 120 this.radius = radius; 121 double[][] resMap = new double[validCells.width][validCells.height]; 122 lightMap = new double[validCells.width][validCells.height]; 123 FOV.reuseFOV(resMap, lightMap, center.x, center.y, radius + 0.5); 124 affected = Radius.inCircle(center.x, center.y, radius, false, validCells.width, validCells.height); 125 } 126 /** 127 * Constructs an ExplosionEffect with explicit settings for most fields. 128 * @param targeting the IPackedColorPanel to affect 129 * @param duration the duration of this PanelEffect in seconds, as a float 130 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 131 * @param center the center of the explosion 132 * @param radius the radius of the explosion, in cells 133 */ 134 public ExplosionEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius) 135 { 136 super(targeting, duration, valid); 137 this.center = center; 138 this.radius = radius; 139 double[][] resMap = ArrayTools.fill(1.0, validCells.width, validCells.height); 140 validCells.writeDoublesInto(resMap, 0.0); 141 lightMap = new double[validCells.width][validCells.height]; 142 FOV.reuseFOV(resMap, lightMap, center.x, center.y, radius + 0.5); 143 validCells.not().writeDoublesInto(lightMap, 0.0); 144 validCells.not(); 145 affected = Radius.inCircle(center.x, center.y, radius, false, validCells.width, validCells.height); 146 } 147 148 /** 149 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 150 * objects that it will use to color the explosion instead of using fiery/smoke colors. 151 * @param targeting the IPackedColorPanel to affect 152 * @param duration the duration of this PanelEffect in seconds, as a float 153 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 154 * @param center the center of the explosion 155 * @param radius the radius of the explosion, in cells 156 * @param coloring a List of Color or subclasses thereof that will replace the default fire/smoke colors here 157 */ 158 public ExplosionEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, List<? extends Color> coloring) 159 { 160 this(targeting, duration, valid, center, radius); 161 if(colors.length != coloring.size()) 162 colors = new float[coloring.size()]; 163 for (int i = 0; i < colors.length; i++) { 164 colors[i] = coloring.get(i).toFloatBits(); 165 } 166 } 167 168 /** 169 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 170 * objects that it will use to color the explosion instead of using fiery/smoke colors. 171 * @param targeting the IPackedColorPanel to affect 172 * @param duration the duration of this PanelEffect in seconds, as a float 173 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 174 * @param center the center of the explosion 175 * @param radius the radius of the explosion, in cells 176 * @param coloring an array of colors as packed floats that will replace the default fire/smoke colors here 177 */ 178 public ExplosionEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, float[] coloring) 179 { 180 this(targeting, duration, valid, center, radius); 181 if(coloring == null) return; 182 if(colors.length != coloring.length) 183 colors = new float[coloring.length]; 184 System.arraycopy(coloring, 0, colors, 0, coloring.length); 185 } 186 /** 187 * Constructs an ExplosionEffect with explicit settings for most fields; this constructor allows the case where 188 * an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} (in degrees) 189 * and will cover an amount of the circular area (in degrees) equal to {@code span}. 190 * @param targeting the IPackedColorPanel to affect 191 * @param duration the duration of this PanelEffect in seconds, as a float 192 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 193 * @param center the center of the explosion 194 * @param radius the radius of the explosion, in cells 195 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 196 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 197 */ 198 public ExplosionEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span) 199 { 200 super(targeting, duration, valid); 201 this.center = center; 202 this.radius = radius; 203 double[][] resMap = ArrayTools.fill(1.0, validCells.width, validCells.height); 204 validCells.writeDoublesInto(resMap, 0.0); 205 lightMap = new double[validCells.width][validCells.height]; 206 FOV.reuseFOV(resMap, lightMap, center.x, center.y, radius + 0.5, Radius.CIRCLE, angle, span); 207 validCells.not().writeDoublesInto(lightMap, 0.0); 208 validCells.not(); 209 affected = Radius.inCircle(center.x, center.y, radius, false, validCells.width, validCells.height); 210 } 211 212 /** 213 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 214 * objects that it will use to color the explosion instead of using fiery/smoke colors; this constructor allows 215 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 216 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 217 * @param targeting the IPackedColorPanel to affect 218 * @param duration the duration of this PanelEffect in seconds, as a float 219 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 220 * @param center the center of the explosion 221 * @param radius the radius of the explosion, in cells 222 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 223 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 224 * @param coloring a List of Color or subclasses thereof that will replace the default fire/smoke colors here 225 */ 226 public ExplosionEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, List<? extends Color> coloring) 227 { 228 this(targeting, duration, valid, center, radius, angle, span); 229 if(colors.length != coloring.size()) 230 colors = new float[coloring.size()]; 231 for (int i = 0; i < colors.length; i++) { 232 colors[i] = coloring.get(i).toFloatBits(); 233 } 234 } 235 236 /** 237 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 238 * objects that it will use to color the explosion instead of using fiery/smoke colors; this constructor allows 239 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 240 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 241 * @param targeting the IPackedColorPanel to affect 242 * @param duration the duration of this PanelEffect in seconds, as a float 243 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 244 * @param center the center of the explosion 245 * @param radius the radius of the explosion, in cells 246 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 247 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 248 * @param coloring an array of colors as packed floats that will replace the default fire/smoke colors here 249 */ 250 public ExplosionEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, float[] coloring) 251 { 252 this(targeting, duration, valid, center, radius, angle, span); 253 if(coloring == null) return; 254 if(colors.length != coloring.length) 255 colors = new float[coloring.length]; 256 System.arraycopy(coloring, 0, colors, 0, coloring.length); 257 } 258 /** 259 * Called each frame. 260 * 261 * @param percent The percentage of completion for this action, growing from 0 to 1 over the duration. If 262 * {@link #setReverse(boolean) reversed}, this will shrink from 1 to 0. 263 */ 264 @Override 265 protected void update(float percent) { 266 int len = affected.size(); 267 Coord c; 268 float f, color, light; 269 int idx, seed = System.identityHashCode(this); 270 for (int i = 0; i < len; i++) { 271 c = affected.get(i); 272 if((light = (float) lightMap[c.x][c.y]) <= 0.0)// || 0.6 * (lightMap[c.x][c.y] + percent) < 0.25) 273 continue; 274 f = (float)SeededNoise.noise(c.x * 1.5, c.y * 1.5, percent * 5, seed) 275 * 0.17f + percent * 1.2f; 276 if(f < 0f || 0.5 * light + f < 0.4) 277 continue; 278 idx = (int) (f * colors.length); 279 if(idx >= colors.length - 1) 280 color = SColor.lerpFloatColors(colors[colors.length-1], NumberTools.setSelectedByte(colors[colors.length-1], 3, (byte)0), (Math.min(0.99f, f) * colors.length) % 1f); 281 else 282 color = SColor.lerpFloatColors(colors[idx], colors[idx+1], (f * colors.length) % 1f); 283 target.blend(c.x, c.y, color, SColor.alphaOfFloatF(color) * light * 0.25f + 0.75f); 284 } 285 } 286 /** 287 * Sets the colors this ExplosionEffect uses to go from through various shades of gray-purple before fading. 288 * Meant for electrical bursts, this will affect character foregrounds in a GibberishEffect. This should look 289 * like sparks in GibberishEffect if the chars in {@link GibberishEffect#choices} are selected in a way that 290 * fits that theme. 291 */ 292 public ExplosionEffect useElectricColors() 293 { 294 colors[0] = SColor.floatGet(0xCCCCFFEE); // SColor.PERIWINKLE 295 colors[1] = SColor.floatGet(0xBF00FFFF); // SColor.ELECTRIC_PURPLE 296 colors[2] = SColor.floatGet(0xCC99CCFF); // SColor.MEDIUM_LAVENDER_MAGENTA 297 colors[3] = SColor.floatGet(0xC8A2C8EE); // SColor.LILAC 298 colors[4] = SColor.floatGet(0xBF00FFDD); // SColor.ELECTRIC_PURPLE 299 colors[5] = SColor.floatGet(0x6022EEBB); // SColor.ELECTRIC_INDIGO 300 colors[6] = SColor.floatGet(0x4B008277); // SColor.INDIGO 301 return this; 302 } 303 304 /** 305 * Sets the colors this ExplosionEffect uses to go from orange, to yellow, to orange, to dark gray, then fade. 306 * Meant for fiery explosions with smoke, this will affect character foregrounds in a GibberishEffect. 307 * This may look more like a fiery blast if used with an ExplosionEffect than a GibberishEffect. 308 */ 309 public ExplosionEffect useFieryColors() 310 { 311 colors[0] = SColor.floatGet(0xFF4F00FF); // SColor.INTERNATIONAL_ORANGE 312 colors[1] = SColor.floatGet(0xFFB94EFF); // SColor.FLORAL_LEAF 313 colors[2] = SColor.floatGet(0xFDE910FF); // SColor.LEMON 314 colors[3] = SColor.floatGet(0xFFFACDFF); // SColor.LEMON_CHIFFON 315 colors[4] = SColor.floatGet(0xFF6600EE); // SColor.SAFETY_ORANGE 316 colors[5] = SColor.floatGet(0x595652DD); // SColor.DB_SOOT 317 colors[6] = SColor.floatGet(0x59565299); // SColor.DB_SOOT 318 return this; 319 } 320 321 } 322 public static class GibberishEffect extends ExplosionEffect 323 { 324 /** 325 * This char array contains all characters that can be used in the foreground of this effect. You can assign 326 * another char array, such as if you take {@link squidpony.StringKit#PUNCTUATION} and call 327 * {@link String#toCharArray()} on it, to this at any time between calls to {@link #update(float)} (which is 328 * usually called indirectly via Stage's {@link com.badlogic.gdx.scenes.scene2d.Stage#act()} method if this has 329 * been added to an Actor on that Stage). These chars are pseudo-randomly selected approximately once every 330 * eighth of a second, and may change sooner if the effect expands more quickly than that. 331 */ 332 public char[] choices = "`~!@#$%^&*()-_=+\\|][}{'\";:/?.>,<".toCharArray(); 333 334 public GibberishEffect(IPackedColorPanel targeting, Coord center, int radius) 335 { 336 super(targeting, 1f, center, radius); 337 useElectricColors(); 338 } 339 /** 340 * Constructs an ExplosionEffect with explicit settings for some fields. The valid cells this can affect will be 341 * the full expanse of the IPackedColorPanel. 342 * @param targeting the IPackedColorPanel to affect 343 * @param duration the duration of this PanelEffect in seconds, as a float 344 * @param center the center of the explosion 345 * @param radius the radius of the explosion, in cells 346 */ 347 public GibberishEffect(IPackedColorPanel targeting, float duration, Coord center, int radius) { 348 super(targeting, duration, center, radius); 349 useElectricColors(); 350 } 351 /** 352 * Constructs an ExplosionEffect with explicit settings for some fields. The valid cells this can affect will be 353 * the full expanse of the IPackedColorPanel. 354 * @param targeting the IPackedColorPanel to affect 355 * @param duration the duration of this PanelEffect in seconds, as a float 356 * @param center the center of the explosion 357 * @param radius the radius of the explosion, in cells 358 */ 359 public GibberishEffect(IPackedColorPanel targeting, float duration, Coord center, int radius, char[] choices) { 360 super(targeting, duration, center, radius); 361 this.choices = choices; 362 useElectricColors(); 363 } 364 /** 365 * Constructs an ExplosionEffect with explicit settings for most fields. 366 * @param targeting the IPackedColorPanel to affect 367 * @param duration the duration of this PanelEffect in seconds, as a float 368 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 369 * @param center the center of the explosion 370 * @param radius the radius of the explosion, in cells 371 */ 372 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius) 373 { 374 super(targeting, duration, valid, center, radius); 375 useElectricColors(); 376 } 377 /** 378 * Constructs an ExplosionEffect with explicit settings for most fields. 379 * @param targeting the IPackedColorPanel to affect 380 * @param duration the duration of this PanelEffect in seconds, as a float 381 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 382 * @param center the center of the explosion 383 * @param radius the radius of the explosion, in cells 384 */ 385 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, char[] choices) 386 { 387 super(targeting, duration, valid, center, radius); 388 this.choices = choices; 389 useElectricColors(); 390 } 391 392 /** 393 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 394 * objects that it will use to color the explosion instead of using purple spark colors. 395 * @param targeting the IPackedColorPanel to affect 396 * @param duration the duration of this PanelEffect in seconds, as a float 397 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 398 * @param center the center of the explosion 399 * @param radius the radius of the explosion, in cells 400 * @param coloring a List of Color or subclasses thereof that will replace the default purple spark colors here 401 */ 402 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, List<? extends Color> coloring) 403 { 404 super(targeting, duration, valid, center, radius, coloring); 405 } 406 /** 407 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 408 * objects that it will use to color the explosion instead of using purple spark colors. 409 * @param targeting the IPackedColorPanel to affect 410 * @param duration the duration of this PanelEffect in seconds, as a float 411 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 412 * @param center the center of the explosion 413 * @param radius the radius of the explosion, in cells 414 * @param coloring a List of Color or subclasses thereof that will replace the default purple spark colors here 415 */ 416 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, List<? extends Color> coloring, char[] choices) 417 { 418 super(targeting, duration, valid, center, radius, coloring); 419 this.choices = choices; 420 } 421 422 /** 423 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 424 * objects that it will use to color the explosion instead of using purple spark colors. 425 * @param targeting the IPackedColorPanel to affect 426 * @param duration the duration of this PanelEffect in seconds, as a float 427 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 428 * @param center the center of the explosion 429 * @param radius the radius of the explosion, in cells 430 * @param coloring an array of colors as packed floats that will replace the default purple spark colors here 431 */ 432 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, float[] coloring) 433 { 434 super(targeting, duration, valid, center, radius, coloring); 435 } 436 /** 437 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 438 * objects that it will use to color the explosion instead of using purple spark colors. 439 * @param targeting the IPackedColorPanel to affect 440 * @param duration the duration of this PanelEffect in seconds, as a float 441 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 442 * @param center the center of the explosion 443 * @param radius the radius of the explosion, in cells 444 * @param coloring an array of colors as packed floats that will replace the default purple spark colors here 445 */ 446 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, float[] coloring, char[] choices) 447 { 448 super(targeting, duration, valid, center, radius, coloring); 449 this.choices = choices; 450 } 451 /** 452 * Constructs an ExplosionEffect with explicit settings for most fields; this constructor allows 453 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 454 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 455 * @param targeting the IPackedColorPanel to affect 456 * @param duration the duration of this PanelEffect in seconds, as a float 457 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 458 * @param center the center of the explosion 459 * @param radius the radius of the explosion, in cells 460 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 461 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 462 */ 463 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, char[] choices) 464 { 465 super(targeting, duration, valid, center, radius, angle, span); 466 this.choices = choices; 467 useElectricColors(); 468 } 469 470 /** 471 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 472 * objects that it will use to color the explosion instead of using purple spark colors; this constructor allows 473 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 474 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 475 * @param targeting the IPackedColorPanel to affect 476 * @param duration the duration of this PanelEffect in seconds, as a float 477 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 478 * @param center the center of the explosion 479 * @param radius the radius of the explosion, in cells 480 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 481 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 482 * @param coloring a List of Color or subclasses thereof that will replace the default purple spark colors here 483 */ 484 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, List<? extends Color> coloring) 485 { 486 super(targeting, duration, valid, center, radius, angle, span, coloring); 487 } 488 /** 489 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 490 * objects that it will use to color the explosion instead of using purple spark colors; this constructor allows 491 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 492 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 493 * @param targeting the IPackedColorPanel to affect 494 * @param duration the duration of this PanelEffect in seconds, as a float 495 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 496 * @param center the center of the explosion 497 * @param radius the radius of the explosion, in cells 498 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 499 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 500 * @param coloring a List of Color or subclasses thereof that will replace the default purple spark colors here 501 */ 502 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, List<? extends Color> coloring, char[] choices) 503 { 504 super(targeting, duration, valid, center, radius, angle, span, coloring); 505 this.choices = choices; 506 } 507 508 /** 509 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 510 * objects that it will use to color the explosion instead of using purple spark colors; this constructor allows 511 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 512 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 513 * @param targeting the IPackedColorPanel to affect 514 * @param duration the duration of this PanelEffect in seconds, as a float 515 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 516 * @param center the center of the explosion 517 * @param radius the radius of the explosion, in cells 518 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 519 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 520 * @param coloring an array of colors as packed floats that will replace the default purple spark colors here 521 */ 522 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, float[] coloring) 523 { 524 super(targeting, duration, valid, center, radius, angle, span, coloring); 525 } 526 /** 527 * Constructs an ExplosionEffect with explicit settings for most fields but also an alternate group of Color 528 * objects that it will use to color the explosion instead of using purple spark colors; this constructor allows 529 * the case where an explosion is directed in a cone or sector shape. It will center the sector on {@code angle} 530 * (in degrees) and will cover an amount of the circular area (in degrees) equal to {@code span}. 531 * @param targeting the IPackedColorPanel to affect 532 * @param duration the duration of this PanelEffect in seconds, as a float 533 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 534 * @param center the center of the explosion 535 * @param radius the radius of the explosion, in cells 536 * @param angle the angle, in degrees, that will be the center of the sector-shaped effect 537 * @param span the span, in degrees, of the full arc at the end of the sector-shaped effect 538 * @param coloring an array of colors as packed floats that will replace the default purple spark colors here 539 */ 540 public GibberishEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, float[] coloring, char[] choices) 541 { 542 super(targeting, duration, valid, center, radius, angle, span, coloring); 543 this.choices = choices; 544 } 545 /** 546 * Called each frame. 547 * 548 * @param percent The percentage of completion for this action, growing from 0 to 1 over the duration. If 549 * {@link #setReverse(boolean) reversed}, this will shrink from 1 to 0. 550 */ 551 @Override 552 protected void update(float percent) { 553 int len = affected.size(); 554 Coord c; 555 float f, color; 556 int idx, seed = System.identityHashCode(this), clen = choices.length; 557 final long tick = DiverRNG.determine((System.currentTimeMillis() >>> 7) * seed); 558 for (int i = 0; i < len; i++) { 559 c = affected.get(i); 560 if(lightMap[c.x][c.y] <= 0.0)// || 0.6 * (lightMap[c.x][c.y] + percent) < 0.25) 561 continue; 562 f = (float)SeededNoise.noise(c.x * 1.5, c.y * 1.5, percent * 5, seed) 563 * 0.17f + percent * 1.2f; 564 if(f < 0f || 0.5 * lightMap[c.x][c.y] + f < 0.4) 565 continue; 566 idx = (int) (f * colors.length); 567 if(idx >= colors.length - 1) 568 color = SColor.lerpFloatColors(colors[colors.length-1], NumberTools.setSelectedByte(colors[colors.length-1], 3, (byte)0), (Math.min(0.99f, f) * colors.length) % 1f); 569 else 570 color = SColor.lerpFloatColors(colors[idx], colors[idx+1], (f * colors.length) % 1f); 571 target.put(c.x, c.y, choices[DiverRNG.determineBounded(tick + i, clen)], color); 572 } 573 } 574 575 } 576 public static class PulseEffect extends ExplosionEffect 577 { 578 public PulseEffect(IPackedColorPanel targeting, Coord center, int radius) { 579 super(targeting, center, radius); 580 } 581 582 public PulseEffect(IPackedColorPanel targeting, float duration, Coord center, int radius) { 583 super(targeting, duration, center, radius); 584 } 585 586 public PulseEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius) { 587 super(targeting, duration, valid, center, radius); 588 } 589 590 public PulseEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, List<? extends Color> coloring) { 591 super(targeting, duration, valid, center, radius, coloring); 592 } 593 594 public PulseEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, float[] coloring) { 595 super(targeting, duration, valid, center, radius, coloring); 596 } 597 598 public PulseEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span) { 599 super(targeting, duration, valid, center, radius, angle, span); 600 } 601 602 public PulseEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, List<? extends Color> coloring) { 603 super(targeting, duration, valid, center, radius, angle, span, coloring); 604 } 605 606 public PulseEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord center, int radius, double angle, double span, float[] coloring) { 607 super(targeting, duration, valid, center, radius, angle, span, coloring); 608 } 609 @Override 610 protected void update(float percent) { 611 int len = affected.size(); 612 Coord c; 613 float f, light; 614 int seed = System.identityHashCode(this); 615 for (int i = 0; i < len; i++) { 616 c = affected.get(i); 617 if((light = (float) lightMap[c.x][c.y]) <= 0f)// || 0.6 * (lightMap[c.x][c.y] + percent) < 0.25) 618 continue; 619 f = (float)SeededNoise.noise(c.x * 0.3, c.y * 0.3, percent * 1.3, seed) 620 * 0.498f + 0.4999f; 621 target.blend(c.x, c.y, 622 SColor.lerpFloatColors(colors[(int) (f * colors.length)], 623 colors[((int) (f * colors.length) + 1) % colors.length], 624 (f * colors.length) % 1f), NumberTools.swayTight(percent * 2f) * light); 625 } 626 } 627 } 628 public static class ProjectileEffect extends PanelEffect 629 { 630 /** 631 * Normally you should set this in the constructor, and not change it later. 632 */ 633 public Coord startPoint; 634 /** 635 * Normally you should set this in the constructor, and not change it later. 636 */ 637 public Coord endPoint; 638 639 /** 640 * The char to show at each stage of the projectile's path; defaults to a Unicode bullet symbol, '·'. 641 */ 642 public char shown = '·'; 643 /** 644 * The color used for the projectile as a packed float; defaults to white. 645 */ 646 public float color = SColor.FLOAT_WHITE; 647 /** 648 * The raw list of Coords that might be affected by the projectile, or are on its (potential) path. You can edit 649 * this if you need to, but it isn't recommended; because it is an array you would need to assign a new Coord 650 * array if the length changes. 651 */ 652 public Coord[] affected; 653 /** 654 * Constructs a ProjectileEffect with explicit settings for some fields. The valid cells this can affect will be 655 * the full expanse of the IPackedColorPanel. The duration will be 1 second. 656 * @param targeting the IPackedColorPanel to affect 657 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 658 * @param endPoint the point to try to hit with the projectile; this should always succeed with no obstructions 659 */ 660 public ProjectileEffect(IPackedColorPanel targeting, Coord startPoint, Coord endPoint) 661 { 662 this(targeting, 1f, startPoint, endPoint); 663 } 664 /** 665 * Constructs a ProjectileEffect with explicit settings for some fields. The valid cells this can affect will be 666 * the full expanse of the IPackedColorPanel. 667 * @param targeting the IPackedColorPanel to affect 668 * @param duration the duration of this PanelEffect in seconds, as a float 669 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 670 * @param endPoint the point to try to hit with the projectile; this should always succeed with no obstructions 671 */ 672 public ProjectileEffect(IPackedColorPanel targeting, float duration, Coord startPoint, Coord endPoint) 673 { 674 super(targeting, duration); 675 this.startPoint = startPoint; 676 this.endPoint = endPoint; 677 affected = Bresenham.line2D_(startPoint.x, startPoint.y, endPoint.x, endPoint.y); 678 } 679 /** 680 * Constructs a ProjectileEffect with explicit settings for most fields. 681 * @param targeting the IPackedColorPanel to affect 682 * @param duration the duration of this PanelEffect in seconds, as a float 683 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 684 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 685 * @param endPoint the point to try to hit with the projectile; this may not be reached if the path crosses a cell not in valid 686 */ 687 public ProjectileEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord startPoint, Coord endPoint) 688 { 689 super(targeting, duration, valid); 690 this.startPoint = startPoint; 691 this.endPoint = endPoint; 692 affected = Bresenham.line2D_(startPoint.x, startPoint.y, endPoint.x, endPoint.y); 693 for (int i = 0; i < affected.length; i++) { 694 if(!validCells.contains(affected[i])) 695 affected[i] = null; 696 } 697 } 698 699 /** 700 * Constructs a ProjectileEffect with explicit settings for most fields but also an alternate Color 701 * object for the projectile instead of the default white color. 702 * @param targeting the IPackedColorPanel to affect 703 * @param duration the duration of this PanelEffect in seconds, as a float 704 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 705 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 706 * @param endPoint the point to try to hit with the projectile; this may not be reached if the path crosses a cell not in valid 707 * @param shown the char to show at each step of the projectile's path as it advances 708 * @param coloring a Color or subclass thereof that will replace the default white color here 709 */ 710 public ProjectileEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord startPoint, Coord endPoint, char shown, Color coloring) 711 { 712 this(targeting, duration, valid, startPoint, endPoint); 713 this.shown = shown; 714 if(coloring != null) 715 color = coloring.toFloatBits(); 716 } 717 718 /** 719 * Constructs a ProjectileEffect with explicit settings for most fields but also an alternate Color 720 * object for the projectile instead of the default white color. 721 * @param targeting the IPackedColorPanel to affect 722 * @param duration the duration of this PanelEffect in seconds, as a float 723 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 724 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 725 * @param endPoint the point to try to hit with the projectile; this may not be reached if the path crosses a cell not in valid 726 * @param shown the char to show at each step of the projectile's path as it advances 727 * @param coloring an array of colors as packed floats that will replace the default white color here 728 */ 729 public ProjectileEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord startPoint, Coord endPoint, char shown, float coloring) 730 { 731 this(targeting, duration, valid, startPoint, endPoint); 732 this.shown = shown; 733 color = coloring; 734 } 735 736 /** 737 * Makes this ProjectileEffect take an "arc-like" path toward the target, where it is fast at the 738 * beginning and end of its motion and is reaching the height of its arc at the center. 739 */ 740 public void useArcPathInterpolation() 741 { 742 setInterpolation(fastInSlowMidFastOut); 743 } 744 745 /** 746 * Makes this ProjectileEffect take a direct path to the target, traveling at uniform speed throughout its path. 747 */ 748 public void useStraightPathInterpolation() 749 { 750 setInterpolation(Interpolation.linear); 751 } 752 /** 753 * Called each frame. 754 * 755 * @param percent The percentage of completion for this action, growing from 0 to 1 over the duration. If 756 * {@link #setReverse(boolean) reversed}, this will shrink from 1 to 0. 757 */ 758 @Override 759 protected void update(float percent) { 760 int len = affected.length, index = (int)((len - 1) * percent); 761 if(index < 0 || index >= len) return; 762 Coord c = affected[index]; 763 if(c != null) 764 { 765 target.put(c.x, c.y, shown, color); 766 } 767 else { 768 for (int i = index + 1; i < len; i++) { 769 affected[i] = null; 770 } 771 } 772 } 773 } 774 775 /** 776 * Almost exactly lke {@link ProjectileEffect}, but its duration specifies the amount of time to spend crossing each 777 * cell (in seconds), not the duration of the entire effect. For ranged weapons like arrows, a fixed duration for 778 * the effect (as in ProjectileEffect) would mean an arrow shot at a close-by target travels slowly and an arrow 779 * shot at a far-away target travels very quickly; this class avoids that issue. Note that the time spent by the 780 * whole effect will vary based on the Chebyshev distance between the start and end points. The speed the projectile 781 * travels at is also dependent on the size and aspect ratio of cells it travels over. 782 */ 783 public static class SteadyProjectileEffect extends ProjectileEffect 784 { 785 786 /** 787 * Constructs a SteadyProjectileEffect with explicit settings for some fields. The valid cells this can affect will be 788 * the full expanse of the IPackedColorPanel. The duration will be 0.05 seconds per cell crossed. 789 * 790 * @param targeting the IPackedColorPanel to affect 791 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 792 * @param endPoint the point to try to hit with the projectile; this should always succeed with no obstructions 793 */ 794 public SteadyProjectileEffect(IPackedColorPanel targeting, Coord startPoint, Coord endPoint) { 795 this(targeting, 0.05f, startPoint, endPoint); 796 } 797 798 /** 799 * Constructs a SteadyProjectileEffect with explicit settings for some fields. The valid cells this can affect will be 800 * the full expanse of the IPackedColorPanel. 801 * 802 * @param targeting the IPackedColorPanel to affect 803 * @param duration the time the projectile will take to cross one cell, in seconds as a float 804 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 805 * @param endPoint the point to try to hit with the projectile; this should always succeed with no obstructions 806 */ 807 public SteadyProjectileEffect(IPackedColorPanel targeting, float duration, Coord startPoint, Coord endPoint) { 808 super(targeting, (float) Radius.SQUARE.radius(startPoint, endPoint) * duration, startPoint, endPoint); 809 } 810 811 /** 812 * Constructs a SteadyProjectileEffect with explicit settings for most fields. 813 * 814 * @param targeting the IPackedColorPanel to affect 815 * @param duration the duration of this PanelEffect in seconds, as a float 816 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 817 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 818 * @param endPoint the point to try to hit with the projectile; this may not be reached if the path crosses a cell not in valid 819 */ 820 public SteadyProjectileEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord startPoint, Coord endPoint) { 821 super(targeting, (float) Radius.SQUARE.radius(startPoint, endPoint) * duration, valid, startPoint, endPoint); 822 } 823 824 /** 825 * Constructs a SteadyProjectileEffect with explicit settings for most fields but also an alternate Color 826 * object for the projectile instead of the default white color. 827 * 828 * @param targeting the IPackedColorPanel to affect 829 * @param duration the time the projectile will take to cross one cell, in seconds as a float 830 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 831 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 832 * @param endPoint the point to try to hit with the projectile; this may not be reached if the path crosses a cell not in valid 833 * @param shown the char to show at each step of the projectile's path as it advances 834 * @param coloring a Color or subclass thereof that will replace the default white color here 835 */ 836 public SteadyProjectileEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord startPoint, Coord endPoint, char shown, Color coloring) { 837 super(targeting, (float) Radius.SQUARE.radius(startPoint, endPoint) * duration, valid, startPoint, endPoint, shown, coloring); 838 } 839 840 /** 841 * Constructs a SteadyProjectileEffect with explicit settings for most fields but also an alternate Color 842 * object for the projectile instead of the default white color. 843 * 844 * @param targeting the IPackedColorPanel to affect 845 * @param duration the time the projectile will take to cross one cell, in seconds as a float 846 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 847 * @param startPoint the starting point of the projectile; may be best if it is adjacent to whatever fires it 848 * @param endPoint the point to try to hit with the projectile; this may not be reached if the path crosses a cell not in valid 849 * @param shown the char to show at each step of the projectile's path as it advances 850 * @param coloring an array of colors as packed floats that will replace the default white color here 851 */ 852 public SteadyProjectileEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord startPoint, Coord endPoint, char shown, float coloring) { 853 super(targeting, (float) Radius.SQUARE.radius(startPoint, endPoint) * duration, valid, startPoint, endPoint, shown, coloring); 854 } 855 } 856 857 public static class GlowBallEffect extends PanelEffect 858 { 859 /** 860 * This will change over the course of the effect's duration, and includes 16 overlapping faint glowing areas. 861 */ 862 public Coord[] centers = new Coord[16]; 863 864 /** 865 * Where the glow effect should travel towards as a whole. 866 */ 867 public Coord end; 868 /** 869 * Normally you should set this in the constructor, and not change it later. 870 */ 871 public int radius = 3; 872 /** 873 * The default glow ball color is medium-light blue. 874 */ 875 public float color = SColor.CW_AZURE.toFloatBits(); 876 /** 877 * The internal representation of how affected each cell is by the glow, based on proximity to center. 878 * This always has 16 light maps, but many will be identical and only calculated once. 879 */ 880 public double[][][] lightMaps = new double[16][][]; 881 private double[][] resMap; 882 /** 883 * The raw list of Coords that might be affected by the glow; may include some cells that aren't going to 884 * show as glowing (it usually has some false positives), but shouldn't exclude any cells that should show as 885 * such (no false negatives). You can edit this if you need to, but it isn't recommended. 886 */ 887 public List<Coord> affected; 888 /** 889 * Constructs a GlowBallEffect with explicit settings for some fields. The valid cells this can affect will be 890 * the full expanse of the IPackedColorPanel. The duration will be 1 second. 891 * @param targeting the IPackedColorPanel to affect 892 * @param start the starting point for the glow ball(s) 893 * @param end the ending point for the glow ball(s) 894 * @param radius the radius of the explosion, in cells 895 */ 896 897 public GlowBallEffect(IPackedColorPanel targeting, Coord start, Coord end, int radius) 898 { 899 this(targeting, 1f, start, end, radius); 900 } 901 /** 902 * Constructs a GlowBallEffect with explicit settings for some fields. The valid cells this can affect will be 903 * the full expanse of the IPackedColorPanel. 904 * @param targeting the IPackedColorPanel to affect 905 * @param duration the duration of this PanelEffect in seconds, as a float 906 * @param start the starting point for the glow ball(s) 907 * @param end the ending point for the glow ball(s) 908 * @param radius the radius of the explosion, in cells 909 */ 910 public GlowBallEffect(IPackedColorPanel targeting, float duration, Coord start, Coord end, int radius) 911 { 912 super(targeting, duration); 913 Arrays.fill(centers, start); 914 this.end = end; 915 this.radius = radius; 916 resMap = new double[validCells.width][validCells.height]; 917 lightMaps[0] = new double[validCells.width][validCells.height]; 918 FOV.reuseFOV(resMap, lightMaps[0], start.x, start.y, radius + 0.5); 919 for (int i = 1; i < 16; i++) { 920 lightMaps[i] = lightMaps[0]; 921 } 922 affected = Radius.inCircle(start.x, start.y, radius, false, validCells.width, validCells.height); 923 } 924 /** 925 * Constructs a GlowBallEffect with explicit settings for some fields. The valid cells this can affect will be 926 * the full expanse of the IPackedColorPanel. 927 * @param targeting the IPackedColorPanel to affect 928 * @param duration the duration of this PanelEffect in seconds, as a float 929 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 930 * @param start the starting point for the glow ball(s) 931 * @param end the ending point for the glow ball(s) 932 * @param radius the radius of the explosion, in cells 933 */ 934 public GlowBallEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord start, Coord end, int radius) 935 { 936 super(targeting, duration, valid); 937 Arrays.fill(centers, start); 938 this.end = end; 939 this.radius = radius; 940 941 resMap = ArrayTools.fill(1.0, validCells.width, validCells.height); 942 validCells.writeDoublesInto(resMap, 0.0); 943 lightMaps[0] = new double[validCells.width][validCells.height]; 944 FOV.reuseFOV(resMap, lightMaps[0], start.x, start.y, radius + 0.5); 945 validCells.not().writeDoublesInto(lightMaps[0], 0.0); 946 validCells.not(); 947 for (int i = 1; i < 16; i++) { 948 lightMaps[i] = lightMaps[0]; 949 } 950 affected = Radius.inCircle(start.x, start.y, radius, false, validCells.width, validCells.height); 951 } 952 953 /** 954 * Constructs a GlowBallEffect with explicit settings for some fields. The valid cells this can affect will be 955 * the full expanse of the IPackedColorPanel. 956 * @param targeting the IPackedColorPanel to affect 957 * @param duration the duration of this PanelEffect in seconds, as a float 958 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 959 * @param start the starting point for the glow ball(s) 960 * @param end the ending point for the glow ball(s) 961 * @param radius the radius of the explosion, in cells 962 */ 963 public GlowBallEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord start, Coord end, int radius, Color coloring) 964 { 965 this(targeting, duration, valid, start, end, radius, coloring.toFloatBits()); 966 } 967 968 /** 969 * Constructs a GlowBallEffect with explicit settings for some fields. The valid cells this can affect will be 970 * the full expanse of the IPackedColorPanel. 971 * @param targeting the IPackedColorPanel to affect 972 * @param duration the duration of this PanelEffect in seconds, as a float 973 * @param valid the valid cells that can be changed by this PanelEffect, as a GreasedRegion 974 * @param start the starting point for the glow ball(s) 975 * @param end the ending point for the glow ball(s) 976 * @param radius the radius of the explosion, in cells 977 */ 978 public GlowBallEffect(IPackedColorPanel targeting, float duration, GreasedRegion valid, Coord start, Coord end, int radius, float coloring) 979 { 980 this(targeting, duration, valid, start, end, radius); 981 color = coloring; 982 } 983 private static float adjust(final float x, final int amt) { return ((x * (16 + amt)) + ((16 - amt) * x * x * (3f - 2f * x))) * 0.03125f; } 984 /** 985 * Called each frame. 986 * 987 * @param percent The percentage of completion for this action, growing from 0 to 1 over the duration. If 988 * {@link #setReverse(boolean) reversed}, this will shrink from 1 to 0. 989 */ 990 @Override 991 protected void update(float percent) { 992 affected.clear(); 993 Radius.inCircle(centers[0].x, centers[0].y, radius, false, validCells.width, validCells.height, affected); 994 int len = affected.size(); 995 Coord c; 996 float f, light; 997 Coord prev = centers[0]; 998 for (int i = 0; i < 16; i++) { 999 centers[i] = centers[i].interpolate(end, adjust(percent, i)); 1000 } 1001 validCells.not(); 1002 if(!prev.equals(centers[0])) 1003 { 1004 FOV.reuseFOV(resMap, lightMaps[0], centers[0].x, centers[0].y, radius + 0.5); 1005 validCells.writeDoublesInto(lightMaps[0], 0.0); 1006 } 1007 for (int i = 1; i < 16; i++) { 1008 if(!centers[i-1].equals(centers[i])) 1009 { 1010 FOV.reuseFOV(resMap, lightMaps[i], centers[i].x, centers[i].y, radius + 0.5); 1011 validCells.writeDoublesInto(lightMaps[i], 0.0); 1012 } 1013 else 1014 { 1015 lightMaps[i] = lightMaps[i-1]; 1016 } 1017 } 1018 validCells.not(); 1019 for (int i = 0; i < len; i++) { 1020 c = affected.get(i); 1021 for (int j = 0; j < 16; j++) { 1022 if ((light = (float) lightMaps[j][c.x][c.y]) <= 0f) 1023 continue; 1024 target.blend(c.x, c.y, color, light * 0.0625f); 1025 } 1026 } 1027 } 1028 } 1029 1030 1031 public static Interpolation fastInSlowMidFastOut = new Interpolation() { 1032 private final float value = 2, power = 3; 1033 @Override 1034 public float apply(float a) { 1035 if (a <= 0.5f) return (1 - ((float)Math.pow(value, -power * (a * 2)) - 0.125f) * 1.1428572f) * 0.5f; 1036 return (1 + (float) Math.pow(value, power * (a * 2 - 2)) - 0.25f) * 0.5714286f; 1037 } 1038 }; 1039 1040 /** 1041 * Convenience method to make a ProjectileEffect or SteadyProjectileEffect take an "arc-like" path toward the 1042 * target, where it is fast at the beginning and end of its motion and is reaching the height of its arc at the 1043 * center, before triggering another Action when the projectile stops (often this might be an 1044 * {@link PanelEffect.ExplosionEffect}, but could be any scene2d Action). 1045 * @param projectile a {@link PanelEffect.ProjectileEffect} (or a subclass of it) to run as the first step 1046 * @param result an {@link Action} to run after the ProjectileEffect completes 1047 * @return an Action that can be added to a scene2d Actor, such as a SquidLayers or SparseLayers 1048 */ 1049 public static Action makeGrenadeEffect(ProjectileEffect projectile, Action result) 1050 { 1051 projectile.useArcPathInterpolation(); 1052 return Actions.sequence(projectile, result); 1053 } 1054}