Android Open Source - DivisionByZero Tower






From Project

Back to project page DivisionByZero.

License

The source code is released under:

Apache License

If you think the Android project DivisionByZero listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.ggstudios.divisionbyzero;
/*from  ww w  . ja  v  a 2s .  c om*/
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;

import android.graphics.Rect;
import android.opengl.GLES20;

import com.ggstudios.divisionbyzero.FontManager.TextureRegion;
import com.ggstudios.divisionbyzero.TowerLibrary.TowerEvoTree;
import com.ggstudios.utils.BufferUtils;
import com.ggstudios.utils.DebugLog;

import static fix.android.opengl.GLES20.glVertexAttribPointer;

public class Tower extends PictureBox implements Updatable{
  private static final String TAG = "Tower";

  private static final int TEXTURE_ATLAS_WIDTH = 512;
  private static final int TEXTURE_ATLAS_HEIGHT = 512;
  private static final int TEXTURE_ATLAS_TILE_WIDTH = 64;
  private static final int TEXTURE_ATLAS_TILE_HEIGHT = 64;

  private static final float COOLOFF_TIME = 0.2f;

  TowerEvoTree evoTree;
  
  int level;
  private int towerType;
  private int cost;

  private int nextCost;
  private int totalCost = 0;

  private float attackSpeed;
  private float coolDown = 0.0f;

  private float rangeSquared;
  private float range;

  private int resellPrice;

  private boolean destroyed = false;
  private boolean enabled = true;

  private int totalDmgDealt = 0;

  private TextureRegion tr;

  int tileX, tileY;

  private static interface Special {
    void updateSpecial(float delta);
    void drawSpecial(float offX, float offY);
  }
  
  public static interface OnTowerChangeListener {
    void onDamageDealtChange(int totalDmgDealt);
    void onStatChange();
  }

  private OnTowerChangeListener towerChangeListener;
  private Special special;

  public void writeToStream(DataOutputStream stream) throws IOException { 
    stream.writeInt(evoTree.typeId);
    stream.writeInt(level);
    stream.writeInt(totalDmgDealt);
    stream.writeFloat(coolDown);
  }
  
  public Tower(int tileX, int tileY, DataInputStream stream) throws IOException {
    this(tileX, tileY, stream.readInt(), stream.readInt());
    
    totalDmgDealt = stream.readInt();
    coolDown = stream.readFloat();
  }
  
  public Tower(int tileX, int tileY, int type, int level) {
    this(tileX, tileY, TowerLibrary.getEvolutionTree(type), level);
  }
  
  public Tower(int tileX, int tileY, TowerEvoTree evoTree, int level) {
    super(0, 0);

    this.evoTree = evoTree;
    this.level = level;
    this.tileX = tileX;
    this.tileY = tileY;

    tr = new TextureRegion(TEXTURE_ATLAS_WIDTH, TEXTURE_ATLAS_HEIGHT, TEXTURE_ATLAS_TILE_WIDTH, TEXTURE_ATLAS_TILE_HEIGHT);

    refreshTowerInfo(false);
  }

  private void refreshTowerInfo(boolean textureChanged) {
    this.cost = evoTree.cost[level];
    this.towerType = evoTree.typeId;
    setTexture(evoTree.resId[level]);
    this.attackSpeed = evoTree.as[level];

    totalCost += cost;

    if(evoTree.resell != null && evoTree.resell.length > level) {
      resellPrice = evoTree.resell[level];
    } else {
      resellPrice = totalCost >> 1;
    }

    if(evoTree.maxLevel == level + 1) {
      nextCost = -1;
    } else {
      nextCost = evoTree.cost[level + 1];
    }

    setRange(evoTree.range[level] * Core.MAP_SDP);

    if(evoTree.hasSpecial[level]) {
      switch(towerType) {
      case TowerLibrary.TYPE_DYNAMIC:
        special = DYNAMIC_SPECIAL;
        break;
      case TowerLibrary.TYPE_BOSS:
        special = BOSS_SPECIAL;
        break;
      case TowerLibrary.TYPE_CLUSTER:
        special = CLUSTER_SPECIAL;
        break;
      case TowerLibrary.TYPE_BOX:
        special = BOX_SPECIAL;
        break;
      case TowerLibrary.TYPE_NORMAL:
        special = NORMAL_SPECIAL;
        break;
      case TowerLibrary.TYPE_DESIRE:
        special = DESIRE_SPECIAL;
        break;
      case TowerLibrary.TYPE_BRUTAL:
      case TowerLibrary.TYPE_DESOLATOR:
        special = BRUTAL_SPECIAL;  // set target to only ghosts...
        break;
      default:
        break;
      }
    }

    tr.setRegion(evoTree.taTileX[level] * TEXTURE_ATLAS_TILE_WIDTH, 
        evoTree.taTileY[level] * TEXTURE_ATLAS_TILE_HEIGHT);

    if(textureChanged)
      Core.game.towerManager.invalidate();
    
    if(towerChangeListener != null)
      towerChangeListener.onStatChange();
  }

  public void build(float w, float h) {
    this.w = w;
    this.h = h;

    generateBuffer();
  }

  private void setRange(float range) {
    this.range = range;
    this.rangeSquared = range * range;
  }

  @Override
  public void draw(float offX, float offY) {
    super.draw(offX, offY);

    if(special != null)
      special.drawSpecial(offX, offY);
  }

  public void drawSpecial(float offX, float offY) {
    if(special != null)
      special.drawSpecial(offX, offY);
  }

  public void drawSprite(float[] vertexBuffer, int offset, float offX, float offY)  {
    final float x1 = x + offX;
    final float y1 = y + offY;
    final float x2 = x1 + w;
    final float y2 = y1 + h;

    vertexBuffer[offset++] = x1;               // Add X for Vertex 0
    vertexBuffer[offset++] = y1;               // Add Y for Vertex 0
    vertexBuffer[offset++] = tr.u1;        // Add U for Vertex 0
    vertexBuffer[offset++] = tr.v1;        // Add V for Vertex 0

    vertexBuffer[offset++] = x2;               // Add X for Vertex 1
    vertexBuffer[offset++] = y1;               // Add Y for Vertex 1
    vertexBuffer[offset++] = tr.u2;        // Add U for Vertex 1
    vertexBuffer[offset++] = tr.v1;        // Add V for Vertex 1

    vertexBuffer[offset++] = x2;               // Add X for Vertex 2
    vertexBuffer[offset++] = y2;               // Add Y for Vertex 2
    vertexBuffer[offset++] = tr.u2;        // Add U for Vertex 2
    vertexBuffer[offset++] = tr.v2;        // Add V for Vertex 2

    vertexBuffer[offset++] = x1;               // Add X for Vertex 3
    vertexBuffer[offset++] = y2;               // Add Y for Vertex 3
    vertexBuffer[offset++] = tr.u1;        // Add U for Vertex 3
    vertexBuffer[offset++] = tr.v2;        // Add V for Vertex 3
  }

  private Sprite getTarget() {
    List<Sprite> list = Core.game.spriteMgr.getRawList();
    final int len = Core.game.spriteMgr.size();
    for(int i = 0; i < len; i++) {
      Sprite sprite = list.get(i);
      
      if(!sprite.isTargetable()) continue;

      final float sX = sprite.x, sY = sprite.y;
      final float u = (sX - x)*(sX - x);
      final float v = (sY - y)*(sY - y);

      if(rangeSquared > u + v){
        return sprite;
      }
    }
    return null;
  }

  private Sprite getGhostTarget() {
    List<Sprite> list = Core.game.spriteMgr.getRawList();
    final int len = Core.game.spriteMgr.size();
    for(int i = 0; i < len; i++) {
      Sprite sprite = list.get(i);

      if(!sprite.isGhost() || !sprite.isTargetable()) continue;

      final float sX = sprite.x, sY = sprite.y;
      final float u = (sX - x)*(sX - x);
      final float v = (sY - y)*(sY - y);

      if(rangeSquared > u + v){
        return sprite;
      }
    }
    return null;
  }

  @Override
  public boolean update(float dt) {
    if(!enabled) return true;
    if(special != null) {
      special.updateSpecial(dt);
    } else if(coolDown <= 0) {
      Sprite target = getTarget();

      if(target != null) {
        // fire
        Bullet b = Core.game.obtainBullet();
        b.parent = this;
        switch(towerType) {
        case TowerLibrary.TYPE_HEAVY:
          b.setTexture(R.drawable.bullet_heavy);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_AOE, evoTree.aoe[level] * Core.MAP_SDP);
          break;
        case TowerLibrary.TYPE_FLAKE:
          b.setTexture(R.drawable.demo_flake_shot);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_COMPLEX_AOE_FROST,
              evoTree.aoe[level] * Core.MAP_SDP, /* Slow percentage */ ((int[])evoTree.extra)[level]);
          b.setState(Sprite.STATE_SLOW);
          b.setDuration(SLOW_TIME);
          break;
        case TowerLibrary.TYPE_DEMO:
          b.setTexture(R.drawable.demo_shot);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_COMPLEX_AOE_STUN,
              evoTree.aoe[level] * Core.MAP_SDP);
          b.setState(Sprite.STATE_STUN);
          b.setDuration(/* stun time */ ((float[])evoTree.extra)[level]);
          break;
        case TowerLibrary.TYPE_NULL:
          b.setTexture(R.drawable.bullet);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_SEEKING, 
              /* dmg multiplier */((float[])evoTree.extra)[level]);
          b.setState(Sprite.STATE_DECAY);
          break;
        default:
          b.setTexture(R.drawable.bullet);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_NORMAL);
          break;
        }


        Core.gu.addGameUpdatable(b);
        b.isVisible = true;

        coolDown = attackSpeed;
      } else {
        coolDown = COOLOFF_TIME;
      }
    }

    coolDown -= dt;
    return !destroyed;
  }

  public int getUpgradeCost() {
    return nextCost;
  }

  public void upgrade() {
    if(evoTree.maxLevel == level + 1) {
      DebugLog.e(TAG, "Attempting to upgrade tower over bounds");
    } else {
      level++;
    }

    refreshTowerInfo(true);
  }

  public void upgrade(int selection) {
    if(evoTree.maxLevel <= level + 1) {
      selection++;
    }
    if(selection == 0) {
      upgrade();
      return;
    }
    evoTree = evoTree.typeUpgrade[level + 1][selection - 1];
    level = 0;

    refreshTowerInfo(true);
  }

  public boolean isMaxLevel() {
    return evoTree.maxLevel == level + 1;
  }
  
  public void setTowerChangeListener(OnTowerChangeListener listener) {
    towerChangeListener = listener;
  }

  public int getSellPrice() {
    return resellPrice;
  }

  public void destroy() {
    destroyed = true;
  }

  public float getRange() {
    return range;
  }
  
  /**
   * Gets the tower range in grid units.
   * @return Tower range in grid units.
   */
  public float getGridRange() {
    return range/Core.MAP_SDP;
  }

  public boolean hasTypeUpgrade() {
    return evoTree.typeUpgrade != null && evoTree.typeUpgrade.length > level + 1 && evoTree.typeUpgrade[level + 1] != null;
  }

  public int getDamage() {
    return evoTree.dmg[level];
  }

  public int getCost() {
    return cost;
  }

  private static int scopeTexture;
  private static int bulletTexture;
  private static int handle;

  private static int boxBurnTextureHandle;
  private static int boxBurnVertexHandle;

  private static int normalPulseTextureHandle;
  private static int normalPulseVertexHandle;

  private static int desireLaserTextureHandle;
  private static int desireLaserTextureHandle2;
  private static int desireLaserVertexHandle;

  private static final float SCOPE_LENGTH = 1f;

  public static final float SLOW_TIME = 4f;
  
  private static float scopeLength;

  public static void init() {
    {
      scopeLength = Core.SDP * SCOPE_LENGTH;

      final float h = Core.SDP / 16f;

      final float arr[] = {
          0, -h,
          scopeLength, -h,
          0, h,
          scopeLength, h
      };

      scopeTexture = Core.tm.get(R.drawable.sniper_asset);
      bulletTexture = Core.tm.get(R.drawable.bullet);
      handle = BufferUtils.copyToBuffer(arr);
    }

    {
      // box stuff...
      final float off = -(Core.MAP_SDP * 0.1f);
      final float size = (Core.MAP_SDP * 1.1f);

      final float arr[] = {
          off, off,
          size, off,
          off, size,
          size, size
      };

      boxBurnTextureHandle = Core.tm.get(R.drawable.box_burn);
      boxBurnVertexHandle = BufferUtils.copyToBuffer(arr);
    }

    {
      final float range = Core.MAP_SDP * 2.0f;

      // normal stuff...
      final float arr[] = {
          -range, -range,   //Vertex 0
          range,   -range,   //v1
          -range, range,     //v2
          range,   range,     //v3
      };

      normalPulseTextureHandle = Core.tm.get(R.drawable.normal_pulse);
      normalPulseVertexHandle = BufferUtils.copyToBuffer(arr);
    }

    {
      final float size = Core.MAP_SDP * 1f;
      final float h = size / 2f;

      final float arr[] = {
          -h, 0,
          h, 0,
          -h, -size,
          h, -size
      };

      desireLaserTextureHandle = Core.tm.get(R.drawable.lazer_background);
      desireLaserTextureHandle2 = Core.tm.get(R.drawable.lazer_overlay);
      desireLaserVertexHandle = BufferUtils.copyToBuffer(arr);
    }
  }

  private final Special DYNAMIC_SPECIAL = new Special() {
    // imitate sniper effect...
    static final float FADE_TIME = 0.5f;
    float fadeCounter = 0.0f;

    boolean showEff;
    float angle;
    Sprite target = null;

    float targetDistance = 0f;

    @Override
    public void updateSpecial(float delta) {
      final float cd = coolDown;
      if(target != null) {
        if(target.isAlive())
          angle = Utils.fastatan2(x - target.x, y - target.y);
        else target = null;
      } else if(cd <= 1) {
        target = getTarget();
        if(target != null) {
          angle = Utils.fastatan2(x - target.x, y - target.y);
          showEff = true;
        }
      } else {
        showEff = false;
      }

      if(cd <= 0) {
        coolDown = attackSpeed;

        if(target != null) {
          fadeCounter = FADE_TIME;
          target.hitBy(Tower.this);
          targetDistance = (float) (Math.sqrt((target.x - x) * (target.x - x) + (target.y - y) * (target.y - y)) / scopeLength);
        }

        target = null;
        showEff = false;
      }

      if(fadeCounter > 0f) {
        fadeCounter -= delta;
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) {
      final float finalX = x + offX;
      final float finalY = y + offY;

      if(showEff){
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, scopeTexture);

        Utils.resetMatrix();
        Utils.rotate(Utils.PI/2.0f + angle);
        Utils.translateAndCommit(finalX, finalY);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, handle);
        glVertexAttribPointer(Core.A_POSITION_HANDLE, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
      }

      if(fadeCounter > 0f) {
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, bulletTexture);

        Utils.resetMatrix();
        Utils.scaleW(targetDistance);
        Utils.rotate(Utils.PI/2.0f + angle);
        Utils.translateAndCommit(finalX, finalY);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f,( fadeCounter/FADE_TIME));
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, handle);
        glVertexAttribPointer(Core.A_POSITION_HANDLE, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, 1.0f);
      }
    }

  };

  private final Special BOSS_SPECIAL = new Special() {

    int positionIndex = 0;
    float[] position = {
        -0.5f, -0.5f,
        0.5f, -0.5f,
        -0.5f, 0f,
        0.5f, 0f,
        -0.5f, 0.5f,
        0.5f, 0.5f
    };

    static final int MAX_POSITION = 6;

    @Override
    public void updateSpecial(float delta) {
      if(coolDown <= 0) {
        Sprite target = getTarget();

        if(target != null) {
          // fire
          Bullet b = Core.game.obtainBullet();
          b.setTexture(R.drawable.bullet);
          b.setup(x + position[positionIndex<<1] * w, y + position[(positionIndex<<1) + 1] * h, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.SDP, Bullet.TYPE_NORMAL);
          b.parent = Tower.this;

          Core.gu.addGameUpdatable(b);
          b.isVisible = true;

          coolDown = attackSpeed;

          positionIndex++;
          if(positionIndex == MAX_POSITION) {
            positionIndex = 0;
          }
        }
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) { }

  };

  private final Special CLUSTER_SPECIAL = new Special() {
    private static final float BURST_SPEED = 0.2f;

    private int burstLeft = 0;
    private float burstCd = BURST_SPEED;

    private boolean startBurst = false;

    @Override
    public void updateSpecial(float delta) {
      if(coolDown <= 0) {
        burstLeft = (Integer) evoTree.extra;

        Sprite target = getTarget();

        if(target != null) {
          Bullet b = Core.game.obtainBullet();

          b.parent = Tower.this;

          b.setTexture(R.drawable.bullet_heavy);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.SDP, Bullet.TYPE_AOE_SEEKING, evoTree.aoe[level] * Core.MAP_SDP);

          Core.gu.addGameUpdatable(b);
          b.isVisible = true;

          coolDown = attackSpeed;
          burstLeft--;

          startBurst = true;
        }
      }

      if(startBurst) {
        burstCd -= delta;
      }

      if(burstCd <= 0f) {
        Sprite target = getTarget();

        if(target != null) {
          Bullet b = Core.game.obtainBullet();

          b.parent = Tower.this;

          b.setTexture(R.drawable.bullet_heavy);

          b.setup(x, y, target, evoTree.dmg[level], 
              evoTree.bs[level] * Core.SDP, Bullet.TYPE_AOE_SEEKING, evoTree.aoe[level] * Core.MAP_SDP);

          Core.gu.addGameUpdatable(b);
          b.isVisible = true;

          burstCd = BURST_SPEED;
          burstLeft--;

          if(burstLeft == 0) {
            startBurst = false;
          }
        }
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) {
    }

  };

  private final Special BOX_SPECIAL = new Special() {
    private static final float BURN_DURATION = 2f;

    private Rect rect = new Rect();
    private float effectTimeLeft = 0f; 
    private float burnCd = 0f; 

    private static final float TRANSPARENCY_MAX = 0.7f, TRANSPARENCY_MIN = 0.3f;
    private float transparency = TRANSPARENCY_MIN;
    private boolean fading = false;

    @Override
    public void updateSpecial(float delta) {
      if(coolDown <= 0) {
        Sprite target = getTarget();

        if(target != null) {
          final float l = (int)(target.x / Core.MAP_SDP) * Core.MAP_SDP;
          final float t = (int)(target.y / Core.MAP_SDP) * Core.MAP_SDP;

          rect.left = (int) l;
          rect.top = (int) t;
          rect.bottom = (int) (rect.top + Core.MAP_SDP);
          rect.right = (int) (rect.left + Core.MAP_SDP);

          effectTimeLeft = BURN_DURATION;

          coolDown = attackSpeed;

          transparency = 0f;
          burnCd = 0f;
        }
      }

      if(effectTimeLeft > 0) {
        effectTimeLeft -= delta;
        if(burnCd > 0)
          burnCd -= delta;

        if(burnCd <= 0) {
          burnCd = (Float) evoTree.extra;

          List<Sprite> list = Core.game.spriteMgr.getRawList();
          final int len = Core.game.spriteMgr.size();
          for(int i = 0; i < len; i++) {
            Sprite sprite = list.get(i);
            if(!sprite.isTargetable()) continue;

            if(rect.contains((int)sprite.x, (int)sprite.y)) {
              sprite.hitBy(Tower.this);
            }
          }
        }

        if(fading) {
          transparency -= delta / 2f;
          if(transparency <= TRANSPARENCY_MIN) {
            transparency = TRANSPARENCY_MIN;
            fading = false;
          }
        } else {
          transparency += delta / 2f;
          if(transparency >= TRANSPARENCY_MAX) {
            transparency = TRANSPARENCY_MAX;
            fading = true;
          }
        }
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) {
      final float finalX = rect.left + offX;
      final float finalY = rect.top + offY;

      if(effectTimeLeft > 0) {
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, boxBurnTextureHandle);

        Utils.resetMatrix();
        Utils.translateAndCommit(finalX, finalY);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, boxBurnVertexHandle);
        glVertexAttribPointer(Core.A_POSITION_HANDLE, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, transparency);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, 1.0f);
      }
    }

  };

  private final Special NORMAL_SPECIAL = new Special() {
    private static final float FADE_DURATION = 0.4f;  // in seconds
    private static final float EFFECT_DURATION = 0.4f;  // in seconds

    private static final float TOTAL_EFFECT_DURATION = FADE_DURATION + EFFECT_DURATION;

    private boolean showEffect = false;
    private float effectTimeLeft = 0f;
    private float transparency = 1f;
    private float scale = 0f;

    private boolean scaling = false;

    @Override
    public void updateSpecial(float delta) {
      if(showEffect) {
        effectTimeLeft -= delta;

        if(effectTimeLeft <= 0)
          showEffect = false;
        else if (effectTimeLeft > FADE_DURATION) {
          scaling = true;

          scale = (TOTAL_EFFECT_DURATION - effectTimeLeft) / EFFECT_DURATION;
          scale *= scale;
        } else {
          if(scaling) {
            scaling = false;

            List<Sprite> list = Core.game.spriteMgr.getRawList();
            final int len = Core.game.spriteMgr.size();
            for(int i = 0; i < len; i++) {
              Sprite sprite = list.get(i);
              
              if(!sprite.isTargetable()) continue;

              final float s_x = sprite.x, s_y = sprite.y;
              final float u = (s_x - x)*(s_x - x);
              final float v = (s_y - y)*(s_y - y);

              if(rangeSquared > u + v){
                sprite.hitBy(Tower.this);
              }
            }
          }

          scale = 1f;
          transparency = effectTimeLeft / FADE_DURATION;
        }
      }

      if(coolDown <= 0) {
        boolean hitSomething = false;

        List<Sprite> list = Core.game.spriteMgr.getRawList();
        final int len = Core.game.spriteMgr.size();
        for(int i = 0; i < len; i++) {
          Sprite sprite = list.get(i);

          final float s_x = sprite.x, s_y = sprite.y;
          final float u = (s_x - x)*(s_x - x);
          final float v = (s_y - y)*(s_y - y);

          if(rangeSquared > u + v){
            hitSomething = true;
            break;
          }
        }

        if(hitSomething) {
          effectTimeLeft = TOTAL_EFFECT_DURATION;
          coolDown = attackSpeed;
          transparency = 1f;
          scale = 0f;

          showEffect = true;
        }
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) {
      if(showEffect){
        final float finalX = x + offX;
        final float finalY = y + offY;

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, normalPulseTextureHandle);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, normalPulseVertexHandle);

        Utils.resetMatrix();
        Utils.scale(scale);
        Utils.translateAndCommit(finalX, finalY);

        glVertexAttribPointer(Core.A_POSITION_HANDLE, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, transparency);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, 1.0f);
      }
    }

  };

  private final Special DESIRE_SPECIAL = new Special() {
    private static final float FADE_TIME = 0.8f;

    private float effectTimeLeft = 0f;

    private float angle;

    private float len;

    @Override
    public void updateSpecial(float delta) {
      if(coolDown <= 0) {
        Sprite target = getTarget();

        if(target != null) {
          // there was a sprite in range...

          angle = (float) Utils.fastatan2(x - target.x, y - target.y);

          //calc who was hit
          float dX = target.x - x; 
          float dY = target.y - y;

          final float multiplier = Math.abs(Core.game.map.getWidth() / dX);

          dX *= multiplier;
          dY *= multiplier;

          final float a = dX*dX + dY*dY;

          len = (float) (Math.sqrt(a) / Core.MAP_SDP);

          List<Sprite> list = Core.game.spriteMgr.getRawList();
          final int len = Core.game.spriteMgr.size();
          for(int i = 0; i < len; i++) {
            Sprite sprite = list.get(i);

            if(!sprite.isTargetable()) continue;

            float fX = x - sprite.x;
            float fY = y - sprite.y;

            float b = 2*(fX*dX + fY*dY);
            float c = (fX*fX + fY*fY) - sprite.h * sprite.h;

            float discriminant = b*b-4*a*c;

            if( discriminant >= 0 ) {
              discriminant = (float) Math.sqrt( discriminant );
              float t1 = (-b + discriminant)/(2*a);

              if( t1 >= 0 && t1 <= 1 ) {
                sprite.hitBy(Tower.this);
              }
            }
          }

          coolDown = attackSpeed;

          effectTimeLeft = FADE_TIME;
        }
      }

      if (effectTimeLeft > 0) {
        effectTimeLeft -= delta;
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) {
      if(effectTimeLeft > 0){
        final float interpolatedTime = (effectTimeLeft / FADE_TIME);
        final float transparency = -1f * interpolatedTime *(interpolatedTime-2);

        final float finalX = x + offX;
        final float finalY = y + offY;

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, desireLaserTextureHandle);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, desireLaserVertexHandle);

        Utils.resetMatrix();
        Utils.scaleH(len);
        Utils.rotate(angle);
        Utils.translateAndCommit(finalX, finalY);

        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE);

        glVertexAttribPointer(Core.A_POSITION_HANDLE, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 0.0f, 0.0f, transparency);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, transparency);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, desireLaserTextureHandle2);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        GLES20.glUniform4f(Core.U_TEX_COLOR_HANDLE, 1.0f, 1.0f, 1.0f, 1.0f);

        Core.gr.resetBlendFunc();
      }
    }

  };

  private final Special BRUTAL_SPECIAL = new Special() {

    @Override
    public void updateSpecial(float delta) {
      if(coolDown <= 0) {
        Sprite target = getGhostTarget();

        if(target != null) {
          // fire
          Bullet b = Core.game.obtainBullet();
          b.parent = Tower.this;

          if (towerType == TowerLibrary.TYPE_BRUTAL) {  
            b.setTexture(R.drawable.bullet);

            b.setup(x, y, target, evoTree.dmg[level], 
                evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_GHOST);
          } else {
            b.setTexture(R.drawable.bullet);

            b.setup(x, y, target, evoTree.dmg[level], 
                evoTree.bs[level] * Core.MAP_SDP, Bullet.TYPE_GHOST_AOE,
                evoTree.aoe[level] * Core.MAP_SDP);
          }


          Core.gu.addGameUpdatable(b);
          b.isVisible = true;

          coolDown = attackSpeed;
        } else {
          coolDown = COOLOFF_TIME;
        }
      }
    }

    @Override
    public void drawSpecial(float offX, float offY) {}

  };

  public void updateDamageDealt(int dmg) {
    totalDmgDealt += dmg;
    
    if(towerChangeListener != null) {
      towerChangeListener.onDamageDealtChange(totalDmgDealt);
    }
  }

  public int getTotalDmgDealt() {
    return totalDmgDealt;
  }

  public String getName() {
    return evoTree.name[level];
  }

  public float getAttackSpeed() {
    return attackSpeed;
  }

  public int getTowerType() {
    return evoTree.typeId;
  }

  public int getLevel() {
    return level;
  }
  
  public String getDescription() {
    return evoTree.getDescription();
  }
  
  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }
}




Java Source Code List

com.ggstudios.divisionbyzero.ActivityAbout.java
com.ggstudios.divisionbyzero.ActivityLevelSelection.java
com.ggstudios.divisionbyzero.ActivityMainMenu.java
com.ggstudios.divisionbyzero.ActivitySettings.java
com.ggstudios.divisionbyzero.ActivitySplashScreen.java
com.ggstudios.divisionbyzero.ApplicationMain.java
com.ggstudios.divisionbyzero.BaseActivity.java
com.ggstudios.divisionbyzero.BaseDialog.java
com.ggstudios.divisionbyzero.BulletManager.java
com.ggstudios.divisionbyzero.Bullet.java
com.ggstudios.divisionbyzero.Button.java
com.ggstudios.divisionbyzero.Circle.java
com.ggstudios.divisionbyzero.ClickableCollection.java
com.ggstudios.divisionbyzero.Clickable.java
com.ggstudios.divisionbyzero.ConfirmDialog.java
com.ggstudios.divisionbyzero.Core.java
com.ggstudios.divisionbyzero.CustomGLSurfaceView.java
com.ggstudios.divisionbyzero.DialogManager.java
com.ggstudios.divisionbyzero.DrawableCollection.java
com.ggstudios.divisionbyzero.DrawableString.java
com.ggstudios.divisionbyzero.Drawable.java
com.ggstudios.divisionbyzero.EndDialog.java
com.ggstudios.divisionbyzero.Event.java
com.ggstudios.divisionbyzero.ExplosionGenerator.java
com.ggstudios.divisionbyzero.ExtrasManager.java
com.ggstudios.divisionbyzero.FontManager.java
com.ggstudios.divisionbyzero.GameRenderer.java
com.ggstudios.divisionbyzero.GameUpdater.java
com.ggstudios.divisionbyzero.Game.java
com.ggstudios.divisionbyzero.Grid.java
com.ggstudios.divisionbyzero.Hud.java
com.ggstudios.divisionbyzero.InGameMenu.java
com.ggstudios.divisionbyzero.InfoDialog.java
com.ggstudios.divisionbyzero.Label.java
com.ggstudios.divisionbyzero.LevelManager.java
com.ggstudios.divisionbyzero.LevelMap.java
com.ggstudios.divisionbyzero.LineGuide.java
com.ggstudios.divisionbyzero.MainActivity.java
com.ggstudios.divisionbyzero.Map.java
com.ggstudios.divisionbyzero.MessageDialog.java
com.ggstudios.divisionbyzero.ParticleEngine.java
com.ggstudios.divisionbyzero.PathFinder.java
com.ggstudios.divisionbyzero.PauseMenu.java
com.ggstudios.divisionbyzero.PictureBox.java
com.ggstudios.divisionbyzero.Player.java
com.ggstudios.divisionbyzero.PopupMenu.java
com.ggstudios.divisionbyzero.Rectangle.java
com.ggstudios.divisionbyzero.Shader.java
com.ggstudios.divisionbyzero.SpawnManager.java
com.ggstudios.divisionbyzero.SpriteAnimation.java
com.ggstudios.divisionbyzero.SpriteManager.java
com.ggstudios.divisionbyzero.Sprite.java
com.ggstudios.divisionbyzero.Statbar.java
com.ggstudios.divisionbyzero.StateManager.java
com.ggstudios.divisionbyzero.TargetRectangle.java
com.ggstudios.divisionbyzero.TextureManager.java
com.ggstudios.divisionbyzero.TowerInfoDialog.java
com.ggstudios.divisionbyzero.TowerLibrary.java
com.ggstudios.divisionbyzero.TowerManager.java
com.ggstudios.divisionbyzero.TowerMenu.java
com.ggstudios.divisionbyzero.Tower.java
com.ggstudios.divisionbyzero.UpdatableCollection.java
com.ggstudios.divisionbyzero.Updatable.java
com.ggstudios.divisionbyzero.UpgradeDialog.java
com.ggstudios.divisionbyzero.Utils.java
com.ggstudios.divisionbyzero.VBO.java
com.ggstudios.divisionbyzero.WaveControlDialog.java
com.ggstudios.divisionbyzero.WaveControlHud.java
com.ggstudios.divisionbyzero.ZoomControl.java
com.ggstudios.utils.BitmapUtils.java
com.ggstudios.utils.BufferUtils.java
com.ggstudios.utils.DebugLog.java
com.ggstudios.utils.ShaderUtils.java
com.ggstudios.widget.LevelMapBackground.java
fix.android.opengl.GLES20.java