/* Subspace Mobile - A Android Subspace Client Copyright (C) 2012 Kingsley Masters. All Rights Reserved. kingsley dot masters at gmail dot com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.subspace.android; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import com.subspace.redemption.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.Log; public class LVL extends ZoneFile { public static short BMPHeader = 0x4D42; public static final int FLAG = 170; public static final int SAFETY = 171; public static final int GOAL = 172; // Large objects public static final int SMALL_ASTEROID1 = 216; public static final int LARGE_ASTEROID = 217; public static final int SMALL_ASTEROID2 = 218; public static final int STATION = 219; public static final int WORMHOLE = 220; public static final int FIRST_FLYUNDER = 176; public static final int LAST_FLYUNDER = 190; BitmapFactory.Options opts = new BitmapFactory.Options(); public Bitmap Tileset; public LVLTile[][] Tiles; Paint paint = new Paint(); Rect r = new Rect(); Sprite smallAsteroid1; Sprite largeAsteroid; Sprite smallAsteroid2; public LVL(Context context, String zoneName, String filename) { super(context, zoneName, filename); // prevent scaling opts.inScaled = false; smallAsteroid1 = new Sprite(BitmapFactory.decodeResource( context.getResources(), R.drawable.over1, opts), 16, 16); largeAsteroid = new Sprite(BitmapFactory.decodeResource( context.getResources(), R.drawable.over2, opts), 32, 32); smallAsteroid2 = new Sprite(BitmapFactory.decodeResource( context.getResources(), R.drawable.over3, opts), 16, 16); paint.setColor(Color.CYAN); } public synchronized int CheckSum(long key) { int savekey = (int) key; if (Tiles != null) { for (int y = savekey % 32; y < 1024; y += 32) for (int x = savekey % 31; x < 1024; x += 31) { byte tile = 0; LVLTile lvltile = Tiles[x][y]; if (lvltile != null) { tile = (byte) Tiles[x][y].Type; if ((tile >= LVLTile.TILE_START && tile <= LVLTile.TILE_END) || tile == LVLTile.SAFETY) { key += savekey ^ tile; } } } } return (int) key; } @Override public synchronized void AfterLoad(LittleEndianDataInputStream inputStream) throws IOException { Tiles = new LVLTile[1024][1024]; // process file inputStream.mark(500); short bfType = inputStream.readShort(); // == 0x4D42 ("BM") int bfSize = inputStream.readInt(); // the total size of the file, which // is // also // the offset of the tile data short bfReserved1 = inputStream.readShort();// previously reserved, but // we're going to use this // for our format short bfReserved2 = inputStream.readShort(); // this one is still // unused,should be 0 int bfOffBits = inputStream.readInt(); // the offset to the bitmap data int tileOffset = 0; Log.i(TAG, "Loading LVL"); // embedded bitmap if (bfType == 0x4D42) { Log.i(TAG, "Loading LVL tileset"); //rewind to start inputStream.reset(); //read in entire bitmap tileOffset = bfSize; byte[] bitmapBuffer = new byte[bfSize]; inputStream.readFully(bitmapBuffer); // read in Tileset = BitmapFactory.decodeByteArray(bitmapBuffer, 0, bfSize); } else { Log.i(TAG, "Using Default Tileset"); Tileset = BitmapFactory.decodeResource(context.getResources(), R.drawable.tiles, opts); } // now load tiles // might need to rethink this to improve performance Log.i(TAG, "Loading LVL Tiles"); while (true) { try { int intstruct = inputStream.readInt(); int tileType = (int) ((intstruct >> 24) & 0xFF); int y = (int) ((intstruct >> 12) & 0x03FF); // get position in // pixels int x = (int) (intstruct & 0x03FF); // get position in pixels LVLTile tile = new LVLTile((short) x, (short) y,(short) tileType); Tiles[x][y] = tile; } catch (EOFException eofE) { break; } } Log.i(TAG, "Completed loading LVL Tiles"); } public void Draw(Canvas canvas, Rect clipRectangle) { int tileOffsetLeft = EnsureWithinBounds(clipRectangle.left / 16); int tileOffsetTop = EnsureWithinBounds(clipRectangle.top / 16); int tileOffsetRight = EnsureWithinBounds(clipRectangle.right / 16); int tileOffsetBottom = EnsureWithinBounds(clipRectangle.bottom / 16); for (int i = tileOffsetLeft; i < tileOffsetRight; i++) { for (int j = tileOffsetTop; j < tileOffsetBottom; j++) { if (Tiles[i][j] != null) { int type = Tiles[i][j].Type; r.set(i * 16 - clipRectangle.left, j * 16 - clipRectangle.top, i * 16 + 16 - clipRectangle.left, j * 16 + 16 - clipRectangle.top); // this is for standard tiles if (type == SMALL_ASTEROID1) { smallAsteroid1.Draw(canvas, r, null); // render small asteroid sprite } else if (type == LARGE_ASTEROID) { r.set(i * 16 - clipRectangle.left, j * 16 - clipRectangle.top, i * 16 + 32 - clipRectangle.left, j * 16 + 32 - clipRectangle.top); largeAsteroid.Draw(canvas, r, null); } else if (type == SMALL_ASTEROID2) { smallAsteroid2.Draw(canvas, r, null); } else { canvas.drawBitmap(Tileset, GetTile(type), r, null); } } } } } private Rect GetTile(int type) { Rect result = new Rect(); type = type - 1; int tileY = (type / 19); int tileX = type - (19 * tileY); result.set(tileX * 16, tileY * 16, tileX * 16 + 16, tileY * 16 + 16); return result; } private int EnsureWithinBounds(int i) { int result = 0; if (i > 0 && i < 1024) { result = i; } return result; } }