Android Open Source - Gloomy-Dungeons-3D Game






From Project

Back to project page Gloomy-Dungeons-3D.

License

The source code is released under:

MIT License

If you think the Android project Gloomy-Dungeons-3D 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 zame.game.engine;
//w  w w. j av a 2 s .c o  m
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Debug;
import android.os.Environment;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.microedition.khronos.opengles.GL10;
import zame.game.Common;
import zame.game.Config;
import zame.game.GameActivity;
import zame.game.MenuActivity;
import zame.game.R;
import zame.game.Renderer;
import zame.game.SoundManager;
import zame.game.ZameApplication;
import zame.game.ZameGame;

public class Game extends ZameGame
{
  private static final float WALK_WALL_DIST = 0.2f;
  private static final int LOAD_LEVEL_NORMAL = 1;
  private static final int LOAD_LEVEL_NEXT = 2;
  public static final int LOAD_LEVEL_RELOAD = 3;

  public static final String INSTANT_NAME = "instant";
  public static final String AUTOSAVE_NAME = "autosave";
  private static boolean pathsInitialized = false;

  // paths initialized in MenuActivity (which started first)
  // TODO: initialize paths in some common place, and re-initialize in necessary
  // but I'm think this is already fixed. anyway, check it.
  public static String SAVES_FOLDER;
  public static String SAVES_ROOT;
  public static String INSTANT_PATH;
  public static String AUTOSAVE_PATH;

  private boolean showFps = false;
  private int actionsMask = 0;
  private int processedMask = 0;
  private boolean hasMoved = false;
  private long prevMovedTime = 0;
  private String unprocessedGameCode = "";

  private static long nextLevelTime;
  private static long killedTime;
  private static float killedAngle;
  private static float killedHeroAngle;
  private static boolean isGameOverFlag;
  private static boolean playStartLevelSound;
  private static boolean skipEndLevelActivityOnce;
  public static boolean renderBlackScreen;
  public static String savedGameParam = INSTANT_NAME;

  public static int endlTotalKills;
  public static int endlTotalItems;
  public static int endlTotalSecrets;

  private static int heroCellX = 0;
  private static int heroCellY = 0;

  public Game(Resources res, AssetManager assets)
  {
    super(res, assets);
    setUpdateInterval(25);  // updates per second - 40
    initialize();
  }

  public void initialize()
  {
    nextLevelTime = 0;
    killedTime = 0;
    isGameOverFlag = false;
    playStartLevelSound = false;
    skipEndLevelActivityOnce = false;
    renderBlackScreen = false;

    Labels.init();
    Common.init();
    Overlay.init();
    State.init();
    Level.init();
    LevelRenderer.init();
    Weapons.init();

    if (savedGameParam.equals("") || !loadGameState(savedGameParam)) {
      loadLevel(LOAD_LEVEL_NORMAL);
    }

    savedGameParam = INSTANT_NAME;
  }

  private static String getInternalStoragePath(Context appContext)
  {
    String result = "";

    if (appContext == null) {
      Log.e(Common.LOG_KEY, "Game.getInternalStoragePath : appContext == null");
    } else if (appContext.getFilesDir() == null) {
      Log.e(Common.LOG_KEY, "Game.getInternalStoragePath : appContext.getFilesDir() == null");
    } else {
      try {
        result = appContext.getFilesDir().getCanonicalPath();
      } catch (IOException ex) {
        Log.e(Common.LOG_KEY, "Can't open internal storage", ex);
      }
    }

    if (result.equals("") && appContext != null) {
      Toast.makeText(ZameApplication.self, "Critical error!\nCan't open internal storage.", Toast.LENGTH_LONG).show();
    }

    return result;
  }

  public static String getExternalStoragePath()
  {
    try {
      if (Environment.getExternalStorageDirectory() == null) {
        // mystical error? return default value
        return "/sdcard";
      } else {
        return Environment.getExternalStorageDirectory().getCanonicalPath();
      }
    } catch (IOException ex) {
      // sdcard missing or mounted. it is not essential for the game, so let's assume it is sdcard
      return "/sdcard";
    }
  }

  public static void initPaths(Context appContext)
  {
    if (pathsInitialized) {
      return;
    }

        String internalStoragePath = getInternalStoragePath(appContext);
    String externalStoragePath = GameHelper.initPaths(appContext);

    String noMediaPath = String.format(Locale.US, "%1$s%2$s.nomedia", externalStoragePath, File.separator);

    if (!(new File(noMediaPath)).exists())
    {
      try
      {
        FileOutputStream out = new FileOutputStream(noMediaPath);
        out.close();
      }
      catch (FileNotFoundException ex) {}
      catch (SecurityException ex) {}
      catch (IOException ex) {}
    }

    SAVES_FOLDER = externalStoragePath;
    SAVES_ROOT = externalStoragePath + File.separator;
    INSTANT_PATH = String.format(Locale.US, "%1$s%2$s%3$s.save", internalStoragePath, File.separator, INSTANT_NAME);
    AUTOSAVE_PATH = String.format(Locale.US, "%1$s%2$s%3$s.save", internalStoragePath, File.separator, AUTOSAVE_NAME);

    pathsInitialized = true;
  }

  public void setGameCode(String code)
  {
    synchronized (lockUpdate) {
      unprocessedGameCode = code;
    }
  }

  public void processGameCode(String codes)
  {
    String[] codeList = codes.toLowerCase().split(" ");

    for (String code : codeList)
    {
      if (code.length() < 2) {
        continue;
      }

      if (code.equals("gmfa"))
      {
        State.heroHasWeapon[Weapons.WEAPON_PISTOL] = true;
        State.heroHasWeapon[Weapons.WEAPON_SHOTGUN] = true;
        State.heroHasWeapon[Weapons.WEAPON_CHAINGUN] = true;
        State.heroHasWeapon[Weapons.WEAPON_DBLSHOTGUN] = true;
        State.heroHasWeapon[Weapons.WEAPON_DBLCHAINGUN] = true;
        State.heroHasWeapon[Weapons.WEAPON_CHAINSAW] = true;

        State.heroAmmo[Weapons.AMMO_PISTOL] = Weapons.MAX_PISTOL_AMMO;
        State.heroAmmo[Weapons.AMMO_SHOTGUN] = Weapons.MAX_SHOTGUN_AMMO;
      }
      else if (code.equals("gmfh"))
      {
        State.heroHealth = 100;
        State.heroArmor = 200;
      }
      else if (code.equals("gmak"))
      {
        State.heroKeysMask = 7;
      }
      else if (code.equals("tmnl"))
      {
        skipEndLevelActivityOnce = true;
        loadLevel(LOAD_LEVEL_NEXT);
      }
      else if (code.equals("tfps"))
      {
        showFps = !showFps;
      }
      else if (code.equals("tmon"))
      {
        LevelRenderer.showMonstersOnMap = !LevelRenderer.showMonstersOnMap;
      }
      else if (code.equals("gmgm"))
      {
        State.godMode = !State.godMode;
      }
      else if (
        code.length() == 4 &&
        code.charAt(0) == 't' &&
        code.charAt(1) == 'l' &&
        (code.charAt(2) >= '0' && code.charAt(2) <= '9') &&
        (code.charAt(3) >= '0' && code.charAt(3) <= '9')
      ) {
        int newLevelNum = (code.charAt(2) - '0') * 10 + (code.charAt(3) - '0');

        if (Level.exists(newLevelNum)) {
          State.levelNum = newLevelNum;
          loadLevel(LOAD_LEVEL_RELOAD);
        }
      }
      else if (code.equals("iddqd"))
      {
        State.godMode = false;
        State.heroHealth = 1;
        State.heroArmor = 0;
      }
    }
  }

  @Override
  public void saveState()
  {
    saveGameState(INSTANT_NAME);
  }

  public static void loadLevel(int loadLevelType)
  {
    if (loadLevelType == LOAD_LEVEL_NEXT) {
      if (!Level.exists(State.levelNum + 1)) {
        return;
      }

      State.levelNum++;
    }

    killedTime = 0;
    nextLevelTime = 0;
    renderBlackScreen = true;
    playStartLevelSound = true;

    Level.load(State.levelNum);
    saveGameState(AUTOSAVE_NAME);

    if (loadLevelType == LOAD_LEVEL_NEXT && !skipEndLevelActivityOnce) {
      GameActivity.changeView(R.layout.end_level);
    } else {
      GameActivity.changeView(R.layout.pre_level);
    }
  }

  private void showGameOverScreen()
  {
    renderBlackScreen = true;
    SoundManager.setPlaylist(SoundManager.LIST_GAMEOVER);
    GameActivity.changeView(R.layout.game_over);
    ZameApplication.trackPageView("/game/game-over");
  }

  private void showEndLevelScreen()
  {
    endlTotalKills = (State.totalMonsters == 0 ? 100 : (State.killedMonsters * 100 / State.totalMonsters));
    endlTotalItems = (State.totalItems == 0 ? 100 : (State.pickedItems * 100 / State.totalItems));
    endlTotalSecrets = (State.totalSecrets == 0 ? 100 : (State.foundSecrets * 100 / State.totalSecrets));

    loadLevel(LOAD_LEVEL_NEXT);
    skipEndLevelActivityOnce = false;
  }

  public static void nextLevel(boolean isTutorial)
  {
    skipEndLevelActivityOnce = isTutorial;
    nextLevelTime = elapsedTime;

    SoundManager.playSound(SoundManager.SOUND_LEVEL_END);

    if (!isTutorial) {
      SoundManager.setPlaylist(SoundManager.LIST_ENDL);
    }
  }

  public void toggleAutoMap()
  {
    State.showAutoMap = !State.showAutoMap;
  }

  @Override
  protected boolean keyUp(int keyCode)
  {
    return Controls.keyUp(keyCode);
  }

  @Override
  protected boolean keyDown(int keyCode)
  {
    return Controls.keyDown(keyCode);
  }

  @Override
  protected void touchEvent(MotionEvent event)
  {
    Controls.touchEvent(event);
  }

  @Override
  protected void trackballEvent(MotionEvent event)
  {
    Controls.trackballEvent(event);
  }

  protected void updateControls()
  {
    actionsMask = Controls.getActionsMask();

    if (actionsMask != 0) {
      // if any button pressed, reset "justLoaded" flag
      MenuActivity.justLoaded = false;
    }

    if (Controls.currentVariant.slidable && (Math.abs(Controls.rotatedAngle) >= 0.1f))
    {
      State.setHeroA(State.heroA + Controls.rotatedAngle);
      Controls.rotatedAngle /= 2.0f;

      if (Math.abs(Controls.rotatedAngle) < 0.1f) {
        Controls.rotatedAngle = 0.0f;
      }

      // if hero rotated, reset "justLoaded" flag
      MenuActivity.justLoaded = false;
    }
  }

  public static void hitHero(int amt, int soundIdx, Monster mon)
  {
    if (killedTime > 0) {
      return;
    }

    if (State.levelNum > Level.FIRST_REAL_LEVEL) {
      amt += (State.levelNum - Level.FIRST_REAL_LEVEL) / 5;
    }

    SoundManager.playSound(soundIdx);
    Overlay.showOverlay(Overlay.BLOOD);

    if (!State.godMode)
    {
      if (State.heroArmor > 0) {
        State.heroArmor = Math.max(0, State.heroArmor - Math.max(1, amt * 3 / 4));
        State.heroHealth -= Math.max(1, amt / 4);
      } else {
        State.heroHealth -= amt;
      }
    }

    if (State.heroHealth <= 0)
    {
      State.heroHealth = 0;
      killedTime = elapsedTime;

      float dx = mon.x - State.heroX;
      float dy = mon.y - State.heroY;
      killedAngle = PortalTracer.getAngle(dx, dy) * Common.RAD2G_F;
      killedHeroAngle = ((Math.abs(360.0f + State.heroA - killedAngle) < Math.abs(State.heroA - killedAngle)) ? (360.0f + State.heroA) : State.heroA);

      SoundManager.playSound(SoundManager.SOUND_DETH_HERO);
    }
  }

  private boolean processUse()
  {
    if ((LevelRenderer.currVis == null) || (LevelRenderer.currVis.dist > 1.8)) {
      return false;
    }

    if (LevelRenderer.currVis.obj instanceof Door)
    {
      Door door = (Door)LevelRenderer.currVis.obj;

      if (door.sticked)
      {
        if (door.requiredKey == 0)
        {
          Overlay.showLabel(Labels.LABEL_CANT_OPEN);
          SoundManager.playSound(SoundManager.SOUND_NOWAY);

          if (door.mark != null) {
            processOneMark(100 + door.mark.id);
          }

          return true;
        }

        if ((State.heroKeysMask & door.requiredKey) == 0)
        {
          if (door.requiredKey == 4 ) {
            Overlay.showLabel(Labels.LABEL_NEED_GREEN_KEY);
          } else if (door.requiredKey == 2) {
            Overlay.showLabel(Labels.LABEL_NEED_RED_KEY);
          } else {
            Overlay.showLabel(Labels.LABEL_NEED_BLUE_KEY);
          }

          if (door.mark != null) {
            processOneMark(100 + door.mark.id);
          }

          SoundManager.playSound(SoundManager.SOUND_NOWAY);
          return true;
        }

        door.sticked = false;
      }

      if (door.open())
      {
        State.passableMap[door.y][door.x] |= Level.PASSABLE_IS_DOOR_OPENED_BY_HERO;

        if (door.mark != null) {
          processOneMark(door.mark.id);
        }

        return true;
      }
      else
      {
        return false;
      }
    }
    else if (LevelRenderer.currVis.obj instanceof Mark)
    {
      processOneMark(((Mark)LevelRenderer.currVis.obj).id);
      return true;
    }

    return false;
  }

  private boolean checkMonsterVisibilityAndHit(Monster mon, int hits)
  {
    float dx = mon.x - State.heroX;
    float dy = mon.y - State.heroY;
    float dist = (float)Math.sqrt(dx*dx + dy*dy);

    float shootXMain = State.heroX + Common.heroCs * dist;
    float shootYMain = State.heroY - Common.heroSn * dist;

    float xoff = Common.heroSn * 0.2f;
    float yoff = Common.heroCs * 0.2f;

    if (
      Common.traceLine(State.heroX + xoff, State.heroY + yoff, shootXMain + xoff, shootYMain + yoff, Level.PASSABLE_MASK_SHOOT_W) ||
      Common.traceLine(State.heroX, State.heroY, shootXMain, shootYMain, Level.PASSABLE_MASK_SHOOT_W) ||
      Common.traceLine(State.heroX - xoff, State.heroY - yoff, shootXMain - xoff, shootYMain - yoff, Level.PASSABLE_MASK_SHOOT_W)
    ) {
      mon.hit(Common.getRealHits(hits, dist), Weapons.WEAPONS[State.heroWeapon].hitTimeout);
      return true;
    }

    return false;
  }

  private void processShoot()
  {
    // just for case
    if (Weapons.hasNoAmmo(State.heroWeapon)) {
      Weapons.selectBestWeapon();
    }

    boolean hit = false;

    if ((LevelRenderer.currVis != null) && (LevelRenderer.currVis.obj instanceof Monster))
    {
      if ((!Weapons.currentParams.isNear) || (LevelRenderer.currVis.dist <= 1.4))
      {
        Monster mon = (Monster)LevelRenderer.currVis.obj;

        if (checkMonsterVisibilityAndHit(mon, Weapons.currentParams.hits)) {
          hit = true;
        }
      }
    }

    if (Weapons.currentCycle[Weapons.shootCycle] > -1000) {
      SoundManager.playSound((Weapons.currentParams.noHitSoundIdx != 0 && !hit) ? Weapons.currentParams.noHitSoundIdx : Weapons.currentParams.soundIdx);
    }

    if (Weapons.currentParams.ammoIdx >= 0)
    {
      State.heroAmmo[Weapons.currentParams.ammoIdx] -= Weapons.currentParams.needAmmo;

      if (State.heroAmmo[Weapons.currentParams.ammoIdx] < Weapons.currentParams.needAmmo)
      {
        if (State.heroAmmo[Weapons.currentParams.ammoIdx] < 0) {
          State.heroAmmo[Weapons.currentParams.ammoIdx] = 0;
        }

        Weapons.selectBestWeapon();
      }
    }
  }

  protected void updateOpenedDoors()
  {
    for (int i = 0; i < State.doorsCount; i++) {
      State.doors[i].tryClose();
    }
  }

  protected void updateMonsters()
  {
    for (int i = 0; i < State.monstersCount; i++) {
      State.monsters[i].update();
    }

    for (int i = 0; i < State.monstersCount;)
    {
      if (State.monsters[i].removeTimeout <= 0) {
        State.monsters[i].remove();
      } else {
        i++;
      }
    }
  }

  protected void updateHeroPosition(float dx, float dy, float accel)
  {
    Level.quickReturnFromFillInitialInWall = false;

    float acc = accel;
    float prevX = State.heroX;

    while (Math.abs(acc) >= 0.02f)
    {
      float add = acc * dx;

      while (Math.abs(add) > 0.1f)
      {
        Level.fillInitialInWallMap(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO);
        State.heroX += (add > 0 ? 0.1f : -0.1f);

        if (!Level.isPassable(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO))
        {
          add = 0;
          break;
        }

        add += (add > 0 ? -0.1f : 0.1f);
      }

      if (Math.abs(add) > 0.02f)
      {
        Level.fillInitialInWallMap(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO);
        State.heroX += add;

        if (Level.isPassable(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO)) {
          break;
        }
      }

      State.heroX = prevX;
      acc += (acc > 0 ? -0.01f : 0.01f);
    }

    acc = accel;
    float prevY = State.heroY;

    while (Math.abs(acc) >= 0.02f)
    {
      float add = acc * dy;

      while (Math.abs(add) > 0.1f)
      {
        Level.fillInitialInWallMap(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO);
        State.heroY += (add > 0 ? 0.1f : -0.1f);

        if (!Level.isPassable(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO))
        {
          add = 0;
          break;
        }

        add += (add > 0 ? -0.1f : 0.1f);
      }

      if (Math.abs(add) > 0.02f)
      {
        Level.fillInitialInWallMap(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO);
        State.heroY += add;

        if (Level.isPassable(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_MASK_HERO)) {
          break;
        }
      }

      State.heroY = prevY;
      acc += (acc > 0 ? -0.01f : 0.01f);
    }

    hasMoved |= ((State.heroX != prevX) || (State.heroY != prevY));
  }

  protected void setNewControlsType(int controlsType)
  {
    Config.controlsType = controlsType;
    Controls.fillMap();

    SoundManager.playSound(SoundManager.SOUND_SWITCH);
    Overlay.showOverlay(Overlay.MARK);
  }

  protected void update()
  {
    if (!unprocessedGameCode.equals("")) {
      processGameCode(unprocessedGameCode);
      unprocessedGameCode = "";
    }

    if (renderBlackScreen || createdTexturesCount < totalTexturesCount) {
      return;
    }

    if (playStartLevelSound) {
      SoundManager.playSound(SoundManager.SOUND_LEVEL_START);
      playStartLevelSound = false;
    }

    // Debug.startMethodTracing("GloomyDungeons.update");

    hasMoved = false;

    updateOpenedDoors();
    updateMonsters();

    if ((nextLevelTime > 0) || (killedTime > 0)) {
      if (Weapons.shootCycle > 0) {
        Weapons.shootCycle = (Weapons.shootCycle + 1) % Weapons.currentCycle.length;
      }

      return;
    }

    if (((actionsMask & (~processedMask) & Controls.ACTION) != 0) || (Weapons.currentCycle[Weapons.shootCycle] < 0)) {
      LevelRenderer.sortVisibleObjects();
    }

    if ((Weapons.currentCycle[Weapons.shootCycle] < 0) && (Weapons.changeWeaponDir == 0)) {
      processShoot();
    }

    if (Weapons.shootCycle > 0) {
      Weapons.shootCycle = (Weapons.shootCycle + 1) % Weapons.currentCycle.length;

      if (Weapons.shootCycle == 0) {
        processedMask &= ~Controls.ACTION;
      }
    }

    if ((actionsMask & Controls.NEXT_WEAPON) != 0) {
      if (Weapons.shootCycle==0 && ((processedMask & Controls.NEXT_WEAPON) == 0) && Weapons.changeWeaponDir==0) {
        Weapons.nextWeapon();
        processedMask |= Controls.NEXT_WEAPON;
      }
    } else {
      processedMask &= ~Controls.NEXT_WEAPON;
    }

    if ((actionsMask & Controls.ACTION) != 0) {
      if ((processedMask & Controls.ACTION) == 0) {
        if (!processUse()) {
          if (Weapons.shootCycle == 0) {
            Weapons.shootCycle++;
          }
        }

        processedMask |= Controls.ACTION;
      }
    } else {
      processedMask &= ~Controls.ACTION;
    }

    if ((actionsMask & Controls.TOGGLE_MAP) != 0) {
      if ((processedMask & Controls.TOGGLE_MAP) == 0) {
        toggleAutoMap();
        processedMask |= Controls.TOGGLE_MAP;
      }
    } else {
      processedMask &= ~Controls.TOGGLE_MAP;
    }

    Controls.updateAccelerations(actionsMask);
    Level.clearPassable(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_IS_HERO);

    if (Math.abs(Controls.accelerometerX) >= 0.1f) {
      if (Config.invertRotation) {
        State.setHeroA(State.heroA + Controls.accelerometerX * Config.accelerometerAcceleration);
      } else {
        State.setHeroA(State.heroA - Controls.accelerometerX * Config.accelerometerAcceleration);
      }

      // if hero has moved or rotated, reset "justLoaded" flag
      MenuActivity.justLoaded = false;
    }

    float joyY = Controls.joyY - Controls.padY * Config.padYAccel;
    float joyX = Controls.joyX + Controls.padX * Config.padXAccel;

    if (Math.abs(joyY) >= 0.05f)
    {
      updateHeroPosition(Common.heroCs, -Common.heroSn, joyY / 7.0f);

      // if hero has moved, reset "justLoaded" flag
      MenuActivity.justLoaded = false;
    }

    if (Math.abs(joyX) >= 0.01f)
    {
      // WAS: if ((Controls.joyButtonsMask & Controls.STRAFE_MODE) != 0) {
      if ((actionsMask & Controls.STRAFE_MODE) != 0) {
        updateHeroPosition(Common.heroSn, Common.heroCs, joyX / 9.0f);
        hasMoved = true;
      } else {
        State.setHeroA(State.heroA - joyX * 3.0f);
      }

      // if hero has moved or rotated, reset "justLoaded" flag
      MenuActivity.justLoaded = false;
    }

    if (Controls.ACCELERATIONS[Controls.ACCELERATION_MOVE].active()) {
      updateHeroPosition(Common.heroCs, -Common.heroSn, Controls.ACCELERATIONS[Controls.ACCELERATION_MOVE].value / Config.moveSpeed);
    }

    if (Controls.ACCELERATIONS[Controls.ACCELERATION_STRAFE].active()) {
      updateHeroPosition(Common.heroSn, Common.heroCs, Controls.ACCELERATIONS[Controls.ACCELERATION_STRAFE].value / Config.strafeSpeed);
    }

    Level.setPassable(State.heroX, State.heroY, WALK_WALL_DIST, Level.PASSABLE_IS_HERO);

    if (Controls.ACCELERATIONS[Controls.ACCELERATION_ROTATE].active()) {
      State.setHeroA(State.heroA - (Controls.ACCELERATIONS[Controls.ACCELERATION_ROTATE].value * Config.rotateSpeed));
    }

    if (((int)State.heroX != heroCellX) || ((int)State.heroY != heroCellY))
    {
      heroCellX = (int)State.heroX;
      heroCellY = (int)State.heroY;

      processMarks();
      pickObjects();
    }

    // Debug.stopMethodTracing();
  }

  private void processOneMark(int markId)
  {
    if (Level.executeActions(markId)) {
      // if this is *not* end level switch, play sound
      if (nextLevelTime == 0) {
        SoundManager.playSound(SoundManager.SOUND_SWITCH);
        Overlay.showOverlay(Overlay.MARK);
      }
    }
  }

  protected void processMarks()
  {
    if (
      (Level.marksMap[(int)State.heroY][(int)State.heroX] != null) &&
      (Level.doorsMap[(int)State.heroY][(int)State.heroX] == null)
    ) {
      processOneMark(Level.marksMap[(int)State.heroY][(int)State.heroX].id);
    }
  }

  protected void pickObjects()
  {
    if ((State.passableMap[(int)State.heroY][(int)State.heroX] & Level.PASSABLE_IS_OBJECT) == 0) {
      return;
    }

    // decide shall we pick object or not

    switch (State.objectsMap[(int)State.heroY][(int)State.heroX])
    {
      case TextureLoader.OBJ_ARMOR_GREEN:
      case TextureLoader.OBJ_ARMOR_RED:
        if (State.heroArmor >= 200) {
          return;
        }
        break;

      case TextureLoader.OBJ_STIM:
      case TextureLoader.OBJ_MEDI:
        if (State.heroHealth >= 100) {
          return;
        }
        break;

      case TextureLoader.OBJ_CLIP:
      case TextureLoader.OBJ_AMMO:
        if (State.heroAmmo[Weapons.AMMO_PISTOL] >= Weapons.MAX_PISTOL_AMMO) {
          return;
        }
        break;

      case TextureLoader.OBJ_SHELL:
      case TextureLoader.OBJ_SBOX:
        if (State.heroAmmo[Weapons.AMMO_SHOTGUN] >= Weapons.MAX_SHOTGUN_AMMO) {
          return;
        }
        break;

      case TextureLoader.OBJ_BPACK:
        if (
          State.heroHealth >= 100
          && State.heroAmmo[Weapons.AMMO_PISTOL] >= Weapons.MAX_PISTOL_AMMO
          && State.heroAmmo[Weapons.AMMO_SHOTGUN] >= Weapons.MAX_SHOTGUN_AMMO
        ) {
          return;
        }
        break;

      case TextureLoader.OBJ_SHOTGUN:
        if (State.heroHasWeapon[Weapons.WEAPON_SHOTGUN] && State.heroAmmo[Weapons.AMMO_SHOTGUN]>=Weapons.MAX_SHOTGUN_AMMO) {
          return;
        }
        break;

      case TextureLoader.OBJ_CHAINGUN:
        if (State.heroHasWeapon[Weapons.WEAPON_CHAINGUN] && State.heroAmmo[Weapons.AMMO_PISTOL]>=Weapons.MAX_PISTOL_AMMO) {
          return;
        }
        break;

      case TextureLoader.OBJ_DBLSHOTGUN:
        if (State.heroHasWeapon[Weapons.WEAPON_DBLSHOTGUN] && State.heroAmmo[Weapons.AMMO_SHOTGUN]>=Weapons.MAX_SHOTGUN_AMMO) {
          return;
        }
        break;
    }

    // play sounds

    switch (State.objectsMap[(int)State.heroY][(int)State.heroX])
    {
      case TextureLoader.OBJ_CLIP:
      case TextureLoader.OBJ_AMMO:
      case TextureLoader.OBJ_SHELL:
      case TextureLoader.OBJ_SBOX:
        SoundManager.playSound(SoundManager.SOUND_PICK_AMMO);
        break;

      case TextureLoader.OBJ_BPACK:
      case TextureLoader.OBJ_SHOTGUN:
      case TextureLoader.OBJ_CHAINGUN:
      case TextureLoader.OBJ_DBLSHOTGUN:
        SoundManager.playSound(SoundManager.SOUND_PICK_WEAPON);
        break;

      default:
        SoundManager.playSound(SoundManager.SOUND_PICK_ITEM);
        break;
    }

    // add healh/armor/wepons/bullets

    int bestWeapon = Weapons.getBestWeapon();

    switch (State.objectsMap[(int)State.heroY][(int)State.heroX])
    {
      case TextureLoader.OBJ_ARMOR_GREEN:
        State.heroArmor = Math.min(State.heroArmor + 100, 200);
        break;

      case TextureLoader.OBJ_ARMOR_RED:
        State.heroArmor = Math.min(State.heroArmor + 200, 200);
        break;

      case TextureLoader.OBJ_KEY_BLUE:
        State.heroKeysMask |= 1;
        break;

      case TextureLoader.OBJ_KEY_RED:
        State.heroKeysMask |= 2;
        break;

      case TextureLoader.OBJ_KEY_GREEN:
        State.heroKeysMask |= 4;
        break;

      case TextureLoader.OBJ_STIM:
        State.heroHealth = Math.min(State.heroHealth + 10, 100);
        break;

      case TextureLoader.OBJ_MEDI:
        State.heroHealth = Math.min(State.heroHealth + 50, 100);
        break;

      case TextureLoader.OBJ_CLIP:
        State.heroAmmo[Weapons.AMMO_PISTOL] = Math.min(State.heroAmmo[Weapons.AMMO_PISTOL] + 5, Weapons.MAX_PISTOL_AMMO);
        if (bestWeapon < Weapons.WEAPON_PISTOL) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_AMMO:
        State.heroAmmo[Weapons.AMMO_PISTOL] = Math.min(State.heroAmmo[Weapons.AMMO_PISTOL] + 20, Weapons.MAX_PISTOL_AMMO);
        if (bestWeapon < Weapons.WEAPON_PISTOL) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_SHELL:
        State.heroAmmo[Weapons.AMMO_SHOTGUN] = Math.min(State.heroAmmo[Weapons.AMMO_SHOTGUN] + 5, Weapons.MAX_SHOTGUN_AMMO);
        if (bestWeapon < Weapons.WEAPON_SHOTGUN && State.heroHasWeapon[Weapons.WEAPON_SHOTGUN]) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_SBOX:
        State.heroAmmo[Weapons.AMMO_SHOTGUN] = Math.min(State.heroAmmo[Weapons.AMMO_SHOTGUN] + 15, Weapons.MAX_SHOTGUN_AMMO);
        if (bestWeapon < Weapons.WEAPON_SHOTGUN && State.heroHasWeapon[Weapons.WEAPON_SHOTGUN]) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_BPACK:
        State.heroHealth = Math.min(State.heroHealth + 10, 100);
        State.heroAmmo[Weapons.AMMO_PISTOL] = Math.min(State.heroAmmo[Weapons.AMMO_PISTOL] + 5, Weapons.MAX_PISTOL_AMMO);
        State.heroAmmo[Weapons.AMMO_SHOTGUN] = Math.min(State.heroAmmo[Weapons.AMMO_SHOTGUN] + 5, Weapons.MAX_SHOTGUN_AMMO);
        // do not check shotgun existing (than, if it didn't exists, pistol will be selected)
        if (bestWeapon < Weapons.WEAPON_SHOTGUN) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_SHOTGUN:
        State.heroHasWeapon[Weapons.WEAPON_SHOTGUN] = true;
        State.heroAmmo[Weapons.AMMO_SHOTGUN] = Math.min(State.heroAmmo[Weapons.AMMO_SHOTGUN] + 3, Weapons.MAX_SHOTGUN_AMMO);
        if (bestWeapon < Weapons.WEAPON_SHOTGUN) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_CHAINGUN:
        State.heroHasWeapon[Weapons.WEAPON_CHAINGUN] = true;
        State.heroAmmo[Weapons.AMMO_PISTOL] = Math.min(State.heroAmmo[Weapons.AMMO_PISTOL] + 20, Weapons.MAX_PISTOL_AMMO);
        if (bestWeapon < Weapons.WEAPON_CHAINGUN) { Weapons.selectBestWeapon(); }
        break;

      case TextureLoader.OBJ_DBLSHOTGUN:
        State.heroHasWeapon[Weapons.WEAPON_DBLSHOTGUN] = true;
        State.heroAmmo[Weapons.AMMO_SHOTGUN] = Math.min(State.heroAmmo[Weapons.AMMO_SHOTGUN] + 6, Weapons.MAX_SHOTGUN_AMMO);
        if (bestWeapon < Weapons.WEAPON_DBLSHOTGUN) { Weapons.selectBestWeapon(); }
        break;
    }

    // don't count objects leaved by monsters
    if ((State.passableMap[(int)State.heroY][(int)State.heroX] & Level.PASSABLE_IS_OBJECT_ORIG) != 0) {
      State.pickedItems++;
    }

    // remove picked objects from map
    State.objectsMap[(int)State.heroY][(int)State.heroX] = 0;
    State.passableMap[(int)State.heroY][(int)State.heroX] &= ~Level.PASSABLE_MASK_OBJECT;

    Overlay.showOverlay(Overlay.ITEM);
  }

  private int createdTexturesCount = 0;
  private int totalTexturesCount = 0;

  @Override
  protected void surfaceCreated(GL10 gl)
  {
    createdTexturesCount = 0;
    totalTexturesCount = TextureLoader.TEXTURES_TO_LOAD.length + 1;
  }

  @Override
  protected void surfaceSizeChanged(GL10 gl)
  {
    Common.ratio = (float)width / (float)height;
    Labels.surfaceSizeChanged(width);
    LevelRenderer.surfaceSizeChanged(gl);
  }

  private static final int FPS_AVG_LEN = 2;

  private int mFrames = 0;
  private long mPrevRenderTime = 0;
  private int[] fpsList = new int[FPS_AVG_LEN];
  private int currFpsPtr = 0;

  private int getAvgFps()
  {
    mFrames++;

    long time = System.currentTimeMillis();
    long diff = time - mPrevRenderTime;

    if (diff > 1000)
    {
      int seconds = (int)(diff / 1000L);
      mPrevRenderTime += (long)seconds * 1000L;

      fpsList[currFpsPtr] = mFrames / seconds;
      currFpsPtr = (currFpsPtr + 1) % FPS_AVG_LEN;

      mFrames = 0;
    }

    int sum = 0;

    for (int v : fpsList) {
      sum += v;
    }

    return (sum / FPS_AVG_LEN);
  }

  protected void drawFps(GL10 gl)
  {
    int fps = getAvgFps();
    gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

    int xpos = (int)(0.02f * (float)Game.width / Common.ratio);
    int ypos = (int)((float)Game.height * Controls.currentVariant.debugLineBaseY);

    Labels.maker.beginDrawing(gl, width, height);
    Labels.maker.draw(gl, xpos, ypos, Labels.map[Labels.LABEL_FPS]);
    Labels.maker.endDrawing(gl);

    Labels.numeric.setValue(fps);
    Labels.numeric.draw(gl, xpos + Labels.maker.getWidth(Labels.map[Labels.LABEL_FPS]) + 5, ypos, width, height);
  }

  private static void renderEndLevelLayer(GL10 gl, float dt)
  {
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPushMatrix();
    Renderer.loadIdentityAndOrthof(gl, 0.0f, 1.0f, 0.0f, 1.0f, 0f, 1.0f);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    Renderer.init();

    Renderer.a2 = Math.min(1.0f, dt) * 0.9f;
    Renderer.a3 = Renderer.a2;

    Renderer.a1 = Math.min(1.0f, dt * 0.5f) * 0.9f;
    Renderer.a4 = Renderer.a1;

    Renderer.setQuadRGB(0.0f, 0.0f, 0.0f);
    Renderer.setQuadOrthoCoords(0.0f, 0.0f, 1.0f, 1.0f);
    Renderer.drawQuad();

    gl.glShadeModel(GL10.GL_SMOOTH);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    Renderer.flush(gl, false);

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPopMatrix();
  }

  private static void renderGammaLayer(GL10 gl)
  {
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPushMatrix();
    Renderer.loadIdentityAndOrthof(gl, 0.0f, 1.0f, 0.0f, 1.0f, 0f, 1.0f);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    Renderer.init();

    Renderer.setQuadRGBA(1.0f, 1.0f, 1.0f, Config.gamma);
    Renderer.setQuadOrthoCoords(0.0f, 0.0f, 1.0f, 1.0f);
    Renderer.drawQuad();

    gl.glShadeModel(GL10.GL_FLAT);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
    Renderer.flush(gl, false);
    gl.glDisable(GL10.GL_BLEND);

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPopMatrix();
  }

  protected void drawCrosshair(GL10 gl)
  {
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPushMatrix();
    Renderer.loadIdentityAndOrthof(gl, -Common.ratio, Common.ratio, -1.0f, 1.0f, 0f, 1.0f);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    Renderer.init();

    Renderer.setLineRGBA(1.0f, 1.0f, 1.0f, 1.0f);

    Renderer.drawLine(0.0f, 0.03f, 0.0f, 0.08f);
    Renderer.drawLine(0.0f, -0.03f, 0.0f, -0.08f);
    Renderer.drawLine(0.03f, 0.0f, 0.08f, 0.0f);
    Renderer.drawLine(-0.03f, 0.0f, -0.08f, 0.0f);

    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    Renderer.flush(gl, false);
    gl.glDisable(GL10.GL_BLEND);

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPopMatrix();
  }

  protected void drawPreloader(GL10 gl)
  {
    if (totalTexturesCount <= 0) {
      return;
    }

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPushMatrix();
    Renderer.loadIdentityAndOrthof(gl, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    Renderer.init();

    Renderer.setQuadRGBA(0.4f, 0.4f, 0.4f, 1.0f);
    Renderer.setQuadOrthoCoords(0.1f, 0.475f, 0.9f, 0.525f);
    Renderer.drawQuad();

    Renderer.setQuadRGB(0.8f, 0.8f, 0.8f);
    Renderer.x3 = (float)(createdTexturesCount + 1) / (float)totalTexturesCount * 0.8f + 0.1f;
    Renderer.x4 = Renderer.x3;
    Renderer.drawQuad();

    gl.glShadeModel(GL10.GL_FLAT);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glDisable(GL10.GL_BLEND);
    Renderer.flush(gl, false);

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glPopMatrix();
  }

  protected void render(GL10 gl)
  {
    // Debug.startMethodTracing("GloomyDungeons.render");

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

    if (renderBlackScreen) {
      return;
    }

    if (createdTexturesCount < totalTexturesCount) {
      drawPreloader(gl);

      if (createdTexturesCount == 0) {
        Labels.createLabels(gl);
        gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
      } else {
        TextureLoader.loadTexture(gl, createdTexturesCount - 1);
      }

      createdTexturesCount++;
      return;
    }

    long walkTime = 0;

    if (hasMoved) {
      if (prevMovedTime != 0) {
        walkTime = elapsedTime - prevMovedTime;
      } else {
        prevMovedTime = elapsedTime;
      }
    } else {
      prevMovedTime = 0;
    }

    float yoff = LevelRenderer.HALF_WALL / 8.0f + (float)Math.sin((double)walkTime / 100.0) * LevelRenderer.HALF_WALL / 16.0f;

    if (killedTime > 0) {
      yoff -= Math.min(1.0f, (float)(elapsedTime - killedTime) / 500.0f) * LevelRenderer.HALF_WALL / 2.0f;
      State.setHeroA(killedHeroAngle + (killedAngle - killedHeroAngle) * Math.min(1.0f, (float)(elapsedTime - killedTime) / 1000.0f));
    }

    LevelRenderer.render(gl, elapsedTime, -yoff);

    if (Config.showCrosshair) {
      drawCrosshair(gl);
    }

    Weapons.render(gl, walkTime);

    if (State.showAutoMap) {
      LevelRenderer.renderAutoMap(gl);
    }

    Overlay.render(gl);
    Stats.render(gl);
    Controls.render(gl, elapsedTime);

    if (nextLevelTime > 0) {
      renderEndLevelLayer(gl, (float)(elapsedTime - nextLevelTime) / 500.0f);
    }

    if (Config.gamma > 0.01f) {
      renderGammaLayer(gl);
    }

    if (showFps) {
      drawFps(gl);
    }

    if (nextLevelTime > 0) {
      if (elapsedTime - nextLevelTime > 1000) {
        if (isGameOverFlag) {
          showGameOverScreen();
        } else {
          showEndLevelScreen();
        }
      }
    } else if ((killedTime > 0) && (elapsedTime - killedTime > 3500)) {
      isGameOverFlag = true;
      nextLevelTime = elapsedTime;
    }

    // Debug.stopMethodTracing();
  }

  public static void safeRename(String tmpName, String fileName)
  {
    String oldName = fileName + ".old";

    if ((new File(oldName)).exists()) {
      (new File(oldName)).delete();
    }

    if ((new File(fileName)).exists()) {
      (new File(fileName)).renameTo(new File(oldName));
    }

    (new File(tmpName)).renameTo(new File(fileName));

    if ((new File(oldName)).exists()) {
      (new File(oldName)).delete();
    }
  }

  public static boolean saveGameState(String name)
  {
    initPaths(ZameApplication.self);

    String saveName = (
      name.equals(INSTANT_NAME) ? INSTANT_PATH : (
        name.equals(AUTOSAVE_NAME) ? AUTOSAVE_PATH :
        (SAVES_ROOT + name + ".save")
      )
    );

    String tmpName = saveName + ".tmp";
    boolean success = true;

    try
    {
      FileOutputStream fo = new FileOutputStream(tmpName, false);
      ObjectOutputStream os = new ObjectOutputStream(fo);

      State.writeTo(os);

      os.flush();
      fo.close();

      safeRename(tmpName, saveName);
    }
    catch (Exception ex)
    {
      Log.e(Common.LOG_KEY, "Exception", ex);
      success = false;
    }

    if (!success) {
      try {
        Toast.makeText(ZameApplication.self, R.string.msg_cant_save_state, Toast.LENGTH_LONG).show();
      } catch (Exception ex) {
        // something really bad happened
      }
    }

    return success;
  }

  public static boolean loadGameState(String name)
  {
    initPaths(ZameApplication.self);

    String saveName = (
      name.equals(INSTANT_NAME) ? INSTANT_PATH : (
        name.equals(AUTOSAVE_NAME) ? AUTOSAVE_PATH :
        (SAVES_ROOT + name + ".save")
      )
    );

    boolean success = true;
    String errorMessage = ZameApplication.self.getString(R.string.msg_cant_load_state);

    try
    {
      FileInputStream fi = new FileInputStream(saveName);
      ObjectInputStream is = new ObjectInputStream(fi);

      State.readFrom(is);
    }
    catch (FileNotFoundException ex)
    {
      return false;
    }
    catch (ClassNotFoundException ex)
    {
      Log.e(Common.LOG_KEY, "Exception", ex);
      success = false;
      errorMessage = ex.toString();
    }
    catch (Exception ex)
    {
      Log.e(Common.LOG_KEY, "Exception", ex);
      success = false;
    }

    if (!success) {
      Toast.makeText(ZameApplication.self, errorMessage, Toast.LENGTH_LONG).show();
    }

    if (success && State.tmpReloadLevel) {
      State.tmpReloadLevel = false;
      loadLevel(LOAD_LEVEL_RELOAD);
    }

    return success;
  }
}




Java Source Code List

zame.game.AppConfig.java
zame.game.AppConfig.java
zame.game.Common.java
zame.game.ConfigZeemote.java
zame.game.ConfigZeemote.java
zame.game.Config.java
zame.game.GameActivityZeemoteHelper.java
zame.game.GameActivityZeemoteHelper.java
zame.game.GameActivity.java
zame.game.GamePreferencesActivity.java
zame.game.GamePreferencesActivity.java
zame.game.MenuActivityHelper.java
zame.game.MenuActivityHelper.java
zame.game.MenuActivity.java
zame.game.Renderer.java
zame.game.SoundManager.java
zame.game.ZameApplicationAnalyticsHelper.java
zame.game.ZameApplicationAnalyticsHelper.java
zame.game.ZameApplication.java
zame.game.ZameGame.java
zame.game.ZameJniRenderer.java
zame.game.engine.Action.java
zame.game.engine.AutoWall.java
zame.game.engine.Controls.java
zame.game.engine.Door.java
zame.game.engine.GameHelper.java
zame.game.engine.GameHelper.java
zame.game.engine.Game.java
zame.game.engine.Labels.java
zame.game.engine.LevelConfig.java
zame.game.engine.LevelRenderer.java
zame.game.engine.Level.java
zame.game.engine.Mark.java
zame.game.engine.Monster.java
zame.game.engine.Overlay.java
zame.game.engine.PortalTracer.java
zame.game.engine.State.java
zame.game.engine.Stats.java
zame.game.engine.TextureLoader.java
zame.game.engine.Weapons.java
zame.game.views.EndLevelView.java
zame.game.views.GameOverView.java
zame.game.views.GameView.java
zame.game.views.IZameView.java
zame.game.views.MenuViewHelper.java
zame.game.views.MenuViewHelper.java
zame.game.views.MenuView.java
zame.game.views.PreLevelView.java
zame.game.views.ZameGameView.java
zame.libs.FrameLayout.java
zame.libs.GLSurfaceView21.java
zame.libs.Grid.java
zame.libs.KeyMapPreference.java
zame.libs.LabelMaker.java
zame.libs.ListPreference.java
zame.libs.NumericSprite.java
zame.libs.SeekBarPreference.java
zame.promo.PromoView.java