<commit_before>/*
 * Copyright 2018 MovingBlocks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.destinationsol.game.particle;

import com.badlogic.gdx.graphics.g2d.ParticleEmitter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.utils.JsonValue;
import com.google.common.base.Preconditions;
import org.destinationsol.common.NotNull;
import org.destinationsol.common.SolMath;
import org.destinationsol.common.SolRandom;
import org.destinationsol.game.GameColors;
import org.destinationsol.game.GameDrawer;
import org.destinationsol.game.SolGame;
import org.destinationsol.game.SolObject;
import org.destinationsol.game.drawables.Drawable;
import org.destinationsol.game.drawables.DrawableLevel;
import org.destinationsol.game.planet.Planet;
import org.destinationsol.game.ship.SolShip;
import org.destinationsol.game.sound.OggSoundSet;

import java.util.ArrayList;
import java.util.List;

public class DSParticleEmitter {

    private static final float JUMP_SPEED_THRESHOLD = 0.9f;
    private static final float JUMP_SIZE_THRESHOLD = 0.7f;
    private static final float MAX_BOUNDINGBOX_RECALC_AWAIT = .5f;
    private static final float MAX_TIME_BETWEEN_POSITION_CHANGE = .25f;

    private Vector2 position;
    private String trigger;
    private float angleOffset;
    private boolean hasLight;
    private EffectConfig config;
    private List<String> workSounds;
    private OggSoundSet workSoundSet;

    private List<Drawable> drawables;
    private ParticleEmitter particleEmitter;
    private DrawableLevel drawableLevel;
    private Vector2 relativePosition, originalRelativePosition;
    private float relativeAngle, areaSize, timeSinceLastPositionChange, boundingBoxRecalcAwait;
    private ParticleEmitter.ScaledNumericValue originalSpeedAngle, originalRotation;
    private boolean inheritsSpeed, working, floatedUp;
    private BoundingBox boundingBox;
    private LightSource light;
    private SolGame game;

    public DSParticleEmitter(@NotNull Vector2 position, @NotNull String trigger, float angleOffset, boolean hasLight,
                             JsonValue effectConfigNode, List<String> sounds) {
        Preconditions.checkNotNull(position, "position cannot be null");
        this.position = new Vector2(position);
        this.trigger = Preconditions.checkNotNull(trigger, "trigger cannot be null");
        this.angleOffset = angleOffset;
        this.hasLight = hasLight;
        this.config = EffectConfig.load(effectConfigNode, new EffectTypes(), new GameColors());
        this.workSounds = sounds;

        workSoundSet = null;
        drawables = null;
        particleEmitter = null;
        drawableLevel = null;
        relativePosition = null;
        originalRelativePosition = null;
        relativeAngle = 0f;
        game = null;
    }

    public DSParticleEmitter(SolGame game, DSParticleEmitter particleEmitter, SolShip ship) {
        this.angleOffset = particleEmitter.getAngleOffset();
        this.hasLight = particleEmitter.getHasLight();
        this.trigger = particleEmitter.getTrigger();
        this.position = particleEmitter.getPosition();
        this.config = particleEmitter.getEffectConfig();
        if (!particleEmitter.getWorkSounds().isEmpty()) {
            this.workSoundSet = new OggSoundSet(game.getSoundManager(), particleEmitter.getWorkSounds());
        }
        else {
            this.workSoundSet = null;
        }
        Vector2 shipPos = ship.getPosition();
        Vector2 shipSpeed = ship.getSpeed();

        initialiseEmitter(config, -1, DrawableLevel.PART_BG_0, position, true, game, shipPos, shipSpeed,
                angleOffset, hasLight);
    }

    public DSParticleEmitter(EffectConfig config, float size, DrawableLevel drawableLevel, Vector2 relativePosition,
                             boolean inheritsSpeed, SolGame game, Vector2 basePosition, Vector2 baseSpeed,
                             float relativeAngle) {
        initialiseEmitter(config, size, drawableLevel, relativePosition, inheritsSpeed, game, basePosition, baseSpeed,
                relativeAngle, false);
    }

    private void initialiseEmitter(EffectConfig config, float size, DrawableLevel drawableLevel,
                                   Vector2 relativePosition, boolean inheritsSpeed, SolGame game, Vector2 basePosition,
                                   Vector2 baseSpeed, float relativeAngle, boolean hasLight) {

        drawables = new ArrayList<>();
        ParticleEmitterDrawable drawable = new ParticleEmitterDrawable();
        drawables.add(drawable);

        this.config = config;
        this.particleEmitter = config.emitter.newEmitter();
        this.drawableLevel = drawableLevel;
        this.relativePosition = new Vector2(relativePosition);
        this.originalRelativePosition = new Vector2(this.relativePosition);
        this.position = new Vector2();
        this.relativeAngle = relativeAngle;
        this.game = game;

        light = new LightSource(config.size * 2.5f, true, 0.7f, relativePosition, config.tint);
        if (hasLight) {
            light.collectDras(drawables);
        }

        if (size <= 0) {
            size = config.size;
        }

        // has area
        if (particleEmitter.getSpawnShape().getShape() != ParticleEmitter.SpawnShape.point) {
            multiplyValue(particleEmitter.getEmission(), size * size);
            multiplyValue(particleEmitter.getSpawnWidth(), size);
            multiplyValue(particleEmitter.getSpawnHeight(), size);
            areaSize = 0;
        }
        // moves fast
        else if (JUMP_SPEED_THRESHOLD < particleEmitter.getVelocity().getHighMax()) {
            multiplyValue(particleEmitter.getEmission(), size * size);
            ParticleEmitter.ScaledNumericValue velocity = particleEmitter.getVelocity();
            velocity.setHigh(velocity.getHighMin() * size, velocity.getHighMax() * size);
            areaSize = 0;
        }
        // large scale
        else if (JUMP_SIZE_THRESHOLD < particleEmitter.getScale().getHighMax()) {
            ParticleEmitter.ScaledNumericValue scale = particleEmitter.getScale();
            scale.setHigh(scale.getHighMin() * size, scale.getHighMax() * size);
            areaSize = 0;
        }
        else {
            areaSize = size;
        }

        particleEmitter.setSprite(new Sprite(config.tex));
        float[] tint = particleEmitter.getTint().getColors();
        tint[0] = config.tint.r;
        tint[1] = config.tint.g;
        tint[2] = config.tint.b;

        originalSpeedAngle = new ParticleEmitter.ScaledNumericValue();
        originalRotation = new ParticleEmitter.ScaledNumericValue();
        transferAngle(particleEmitter.getAngle(), originalSpeedAngle, 0f);
        transferAngle(particleEmitter.getRotation(), originalRotation, 0f);

        this.inheritsSpeed = inheritsSpeed;
        updateSpeed(game, baseSpeed, basePosition);

        if (config.emitter.continuous) {
            // making it continuous after setting initial speed
            particleEmitter.setContinuous(true);
            // this is needed because making effect continuous starts it
            particleEmitter.allowCompletion();
            // ... and still initial speed is not applied : (
        } else {
            particleEmitter.start();
        }
        boundingBox = particleEmitter.getBoundingBox();
    }

    private void multiplyValue(ParticleEmitter.ScaledNumericValue value, float multiplier) {
        value.setHigh(value.getHighMin() * multiplier, value.getHighMax() * multiplier);
        value.setLow(value.getLowMin() * multiplier, value.getLowMax() * multiplier);
    }

    private static void transferAngle(ParticleEmitter.ScaledNumericValue from, ParticleEmitter.ScaledNumericValue to,
                                      float diff) {
        if (!to.isRelative()) {
            to.setHigh(from.getHighMin() + diff, from.getHighMax() + diff);<commit_msg>Fix some checkstyle issues in DSParticleEmitter<commit_after>/*
 * Copyright 2018 MovingBlocks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.destinationsol.game.particle;

import com.badlogic.gdx.graphics.g2d.ParticleEmitter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.utils.JsonValue;
import com.google.common.base.Preconditions;
import org.destinationsol.common.NotNull;
import org.destinationsol.common.SolMath;
import org.destinationsol.common.SolRandom;
import org.destinationsol.game.GameColors;
import org.destinationsol.game.GameDrawer;
import org.destinationsol.game.SolGame;
import org.destinationsol.game.SolObject;
import org.destinationsol.game.drawables.Drawable;
import org.destinationsol.game.drawables.DrawableLevel;
import org.destinationsol.game.planet.Planet;
import org.destinationsol.game.ship.SolShip;
import org.destinationsol.game.sound.OggSoundSet;

import java.util.ArrayList;
import java.util.List;

public class DSParticleEmitter {

    private static final float JUMP_SPEED_THRESHOLD = 0.9f;
    private static final float JUMP_SIZE_THRESHOLD = 0.7f;
    private static final float MAX_BOUNDINGBOX_RECALC_AWAIT = .5f;
    private static final float MAX_TIME_BETWEEN_POSITION_CHANGE = .25f;

    private Vector2 position;
    private String trigger;
    private float angleOffset;
    private boolean hasLight;
    private EffectConfig config;
    private List<String> workSounds;
    private OggSoundSet workSoundSet;

    private List<Drawable> drawables;
    private ParticleEmitter particleEmitter;
    private DrawableLevel drawableLevel;
    private Vector2 relativePosition;
    private Vector2 originalRelativePosition;
    private float relativeAngle;
    private float areaSize;
    private float timeSinceLastPositionChange;
    private float boundingBoxRecalcAwait;
    private ParticleEmitter.ScaledNumericValue originalSpeedAngle;
    private ParticleEmitter.ScaledNumericValue originalRotation;
    private boolean inheritsSpeed;
    private boolean working;
    private boolean floatedUp;
    private BoundingBox boundingBox;
    private LightSource light;
    private SolGame game;

    public DSParticleEmitter(@NotNull Vector2 position, @NotNull String trigger, float angleOffset, boolean hasLight, JsonValue effectConfigNode, List<String> sounds) {
        Preconditions.checkNotNull(position, "position cannot be null");
        this.position = new Vector2(position);
        this.trigger = Preconditions.checkNotNull(trigger, "trigger cannot be null");
        this.angleOffset = angleOffset;
        this.hasLight = hasLight;
        this.config = EffectConfig.load(effectConfigNode, new EffectTypes(), new GameColors());
        this.workSounds = sounds;

        workSoundSet = null;
        drawables = null;
        particleEmitter = null;
        drawableLevel = null;
        relativePosition = null;
        originalRelativePosition = null;
        relativeAngle = 0f;
        game = null;
    }

    public DSParticleEmitter(SolGame game, DSParticleEmitter particleEmitter, SolShip ship) {
        this.angleOffset = particleEmitter.getAngleOffset();
        this.hasLight = particleEmitter.getHasLight();
        this.trigger = particleEmitter.getTrigger();
        this.position = particleEmitter.getPosition();
        this.config = particleEmitter.getEffectConfig();
        if (!particleEmitter.getWorkSounds().isEmpty()) {
            this.workSoundSet = new OggSoundSet(game.getSoundManager(), particleEmitter.getWorkSounds());
        } else {
            this.workSoundSet = null;
        }
        Vector2 shipPos = ship.getPosition();
        Vector2 shipSpeed = ship.getSpeed();

        initialiseEmitter(config, -1, DrawableLevel.PART_BG_0, position, true, game, shipPos, shipSpeed, angleOffset, hasLight);
    }

    public DSParticleEmitter(EffectConfig config, float size, DrawableLevel drawableLevel, Vector2 relativePosition,
                             boolean inheritsSpeed, SolGame game, Vector2 basePosition, Vector2 baseSpeed,
                             float relativeAngle) {
        initialiseEmitter(config, size, drawableLevel, relativePosition, inheritsSpeed, game, basePosition, baseSpeed,
                relativeAngle, false);
    }

    private void initialiseEmitter(EffectConfig config, float size, DrawableLevel drawableLevel, Vector2 relativePosition, boolean inheritsSpeed,
                                   SolGame game, Vector2 basePosition, Vector2 baseSpeed, float relativeAngle, boolean hasLight) {

        drawables = new ArrayList<>();
        ParticleEmitterDrawable drawable = new ParticleEmitterDrawable();
        drawables.add(drawable);

        this.config = config;
        this.particleEmitter = config.emitter.newEmitter();
        this.drawableLevel = drawableLevel;
        this.relativePosition = new Vector2(relativePosition);
        this.originalRelativePosition = new Vector2(this.relativePosition);
        this.position = new Vector2();
        this.relativeAngle = relativeAngle;
        this.game = game;

        light = new LightSource(config.size * 2.5f, true, 0.7f, relativePosition, config.tint);
        if (hasLight) {
            light.collectDras(drawables);
        }

        if (size <= 0) {
            size = config.size;
        }

        if (particleEmitter.getSpawnShape().getShape() != ParticleEmitter.SpawnShape.point) { // has area
            multiplyValue(particleEmitter.getEmission(), size * size);
            multiplyValue(particleEmitter.getSpawnWidth(), size);
            multiplyValue(particleEmitter.getSpawnHeight(), size);
            areaSize = 0;
        } else if (JUMP_SPEED_THRESHOLD < particleEmitter.getVelocity().getHighMax()) { // moves fast
            multiplyValue(particleEmitter.getEmission(), size * size);
            ParticleEmitter.ScaledNumericValue velocity = particleEmitter.getVelocity();
            velocity.setHigh(velocity.getHighMin() * size, velocity.getHighMax() * size);
            areaSize = 0;
        } else if (JUMP_SIZE_THRESHOLD < particleEmitter.getScale().getHighMax()) { // large scale
            ParticleEmitter.ScaledNumericValue scale = particleEmitter.getScale();
            scale.setHigh(scale.getHighMin() * size, scale.getHighMax() * size);
            areaSize = 0;
        } else {
            areaSize = size;
        }

        particleEmitter.setSprite(new Sprite(config.tex));
        float[] tint = particleEmitter.getTint().getColors();
        tint[0] = config.tint.r;
        tint[1] = config.tint.g;
        tint[2] = config.tint.b;

        originalSpeedAngle = new ParticleEmitter.ScaledNumericValue();
        originalRotation = new ParticleEmitter.ScaledNumericValue();
        transferAngle(particleEmitter.getAngle(), originalSpeedAngle, 0f);
        transferAngle(particleEmitter.getRotation(), originalRotation, 0f);

        this.inheritsSpeed = inheritsSpeed;
        updateSpeed(game, baseSpeed, basePosition);

        if (config.emitter.continuous) {
            // making it continuous after setting initial speed
            particleEmitter.setContinuous(true);
            // this is needed because making effect continuous starts it
            particleEmitter.allowCompletion();
            // ... and still initial speed is not applied : (
        } else {
            particleEmitter.start();
        }
        boundingBox = particleEmitter.getBoundingBox();
    }

    private void multiplyValue(ParticleEmitter.ScaledNumericValue value, float multiplier) {
        value.setHigh(value.getHighMin() * multiplier, value.getHighMax() * multiplier);
        value.setLow(value.getLowMin() * multiplier, value.getLowMax() * multiplier);
    }

    private static void transferAngle(ParticleEmitter.ScaledNumericValue from, ParticleEmitter.ScaledNumericValue to, float diff) {
        if (!to.isRelative()) {
            to.setHigh(from.getHighMin() + diff, from.getHighMax() + diff);
{'fraction_non_alphanumeric': 0.08700930797248077, 'fraction_numerical': 0.005954789847950511, 'mean_word_length': 3.1491964499880067, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3636001', 'n_tokens_mistral': 4689, 'n_tokens_neox': 4643, 'n_words': 1110}