diff options
Diffstat (limited to 'src/org/happysanta/gd')
68 files changed, 12669 insertions, 0 deletions
diff --git a/src/org/happysanta/gd/API/API.java b/src/org/happysanta/gd/API/API.java new file mode 100755 index 0000000..8e1ee0d --- /dev/null +++ b/src/org/happysanta/gd/API/API.java @@ -0,0 +1,101 @@ +package org.happysanta.gd.API; + +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; + +import java.io.*; +import java.util.LinkedList; +import java.util.List; + +import static org.happysanta.gd.Helpers.getDeviceName; + +public class API { + + public static final String URL = "http://gdtr.net/api.php"; + public static final String DEBUG_URL = "http://dev.gdtr.net/api.php"; + public static final String MRG_URL = "http://gdtr.net/mrg/%d.mrg"; + public static final int VERSION = 2; + + public static Request getLevels(int offset, int limit, LevelsSortType sort, ResponseHandler handler) + throws Exception { + List<NameValuePair> params = new LinkedList<NameValuePair>(); + params.add(new BasicNameValuePair("sort", sort.toString())); + params.add(new BasicNameValuePair("offset", String.valueOf(offset))); + params.add(new BasicNameValuePair("limit", String.valueOf(limit))); + + return new Request("getLevels", params, handler); + } + + public static Request getNotifications(boolean installedFromAPK, ResponseHandler handler) { + List<NameValuePair> params = new LinkedList<NameValuePair>(); + params.add(new BasicNameValuePair("apk", String.valueOf(installedFromAPK ? 1 : 0))); + return new Request("getNotifications", params, handler); + } + + public static Request sendStats(String statsJSON, String installationID, int useCheats, ResponseHandler handler) { + List<NameValuePair> params = new LinkedList<NameValuePair>(); + params.add(new BasicNameValuePair("stats", statsJSON)); + params.add(new BasicNameValuePair("id", installationID)); + params.add(new BasicNameValuePair("use_cheats", String.valueOf(useCheats))); + return new Request("sendStats", params, handler); + } + + public static Request sendKeyboardLogs(String log, ResponseHandler handler) { + List<NameValuePair> params = new LinkedList<NameValuePair>(); + params.add(new BasicNameValuePair("log", log)); + params.add(new BasicNameValuePair("device", getDeviceName())); + return new Request("sendKeyboardLogs", params, handler, true); + } + + public static DownloadFile downloadMrg(long id, FileOutputStream output, DownloadHandler handler) { + return new DownloadFile(String.format(MRG_URL, id), output, handler); + } + + public static String getMrgURL(long id) { + return String.format(MRG_URL, id); + } + + public static enum LevelsSortType { + POPULAR("popular"), TRACKS("tracks"), RECENT("recent"), OLDEST("oldest"); + + private final String text; + + private LevelsSortType(final String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + } + + public static LevelsSortType getSortTypeById(int id) { + switch (id) { + case 0: + return LevelsSortType.POPULAR; + case 1: + return LevelsSortType.RECENT; + case 2: + return LevelsSortType.OLDEST; + case 3: + return LevelsSortType.TRACKS; + } + return null; + } + + public static int getIdBySortType(LevelsSortType type) { + switch (type) { + case POPULAR: + return 0; + case RECENT: + return 1; + case OLDEST: + return 2; + case TRACKS: + return 3; + } + return 0; + } + +} diff --git a/src/org/happysanta/gd/API/APIException.java b/src/org/happysanta/gd/API/APIException.java new file mode 100755 index 0000000..6cf2c14 --- /dev/null +++ b/src/org/happysanta/gd/API/APIException.java @@ -0,0 +1,9 @@ +package org.happysanta.gd.API; + +public class APIException extends java.lang.Exception { + + public APIException(String message) { + super(message); + } + +} diff --git a/src/org/happysanta/gd/API/DownloadFile.java b/src/org/happysanta/gd/API/DownloadFile.java new file mode 100644 index 0000000..2920c27 --- /dev/null +++ b/src/org/happysanta/gd/API/DownloadFile.java @@ -0,0 +1,144 @@ +package org.happysanta.gd.API; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.PowerManager; +import org.apache.http.HttpException; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import static org.happysanta.gd.Helpers.getGDActivity; + +public class DownloadFile { + + private String urlString; + private DownloadHandler handler; + private FileOutputStream output; + private AsyncDownloadTask task; + + public DownloadFile(String url, FileOutputStream output) { + this.urlString = url; + this.output = output; + } + + public DownloadFile(String url, FileOutputStream output, DownloadHandler handler) { + this(url, output); + this.handler = handler; + } + + public void setDownloadHandler(DownloadHandler handler) { + this.handler = handler; + } + + public void start() { + task = new AsyncDownloadTask(); + task.execute(); + } + + public void cancel() { + if (task != null) { + task.cancel(true); + task = null; + } + } + + protected class AsyncDownloadTask extends AsyncTask<Void, Integer, Throwable> { + + private PowerManager.WakeLock lock; + + @Override + protected Throwable doInBackground(Void... params) { + // OutputStream output = (FileOutputStream)params[1]; + InputStream input = null; + HttpURLConnection connection = null; + + try { + URL url = new URL(urlString); + connection = (HttpURLConnection) url.openConnection(); + connection.connect(); + + // expect HTTP 200 OK, so we don't mistakenly save error report + // instead of the file + if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { + return new HttpException("Server returned HTTP " + connection.getResponseCode() + + " " + connection.getResponseMessage()); + } + + // this will be useful to display download percentage + // might be -1: server did not report the length + int fileLength = connection.getContentLength(); + + // download the file + input = connection.getInputStream(); + + byte data[] = new byte[4096]; + long total = 0; + int count; + while ((count = input.read(data)) != -1) { + // allow canceling with back button + if (isCancelled()) { + input.close(); + return null; + } + + total += count; + + // publishing the progress.... + if (fileLength > 0) // only if total length is known + publishProgress((int) (total * 100 / fileLength)); + + output.write(data, 0, count); + } + } catch (Exception e) { + return e; + } finally { + try { + if (output != null) + output.close(); + if (input != null) + input.close(); + } catch (IOException ignored) { + } + + if (connection != null) + connection.disconnect(); + } + + return null; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + // take CPU lock to prevent CPU from going off if the user + // presses the power button during download + PowerManager pm = (PowerManager) getGDActivity().getSystemService(Context.POWER_SERVICE); + lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + getClass().getName()); + lock.acquire(); + + handler.onStart(); + } + + @Override + protected void onProgressUpdate(Integer... progress) { + super.onProgressUpdate(progress); + + handler.onProgress(progress[0]); + } + + @Override + protected void onPostExecute(Throwable error) { + lock.release(); + handler.onFinish(error); + } + + } + + +} diff --git a/src/org/happysanta/gd/API/DownloadHandler.java b/src/org/happysanta/gd/API/DownloadHandler.java new file mode 100644 index 0000000..ec43651 --- /dev/null +++ b/src/org/happysanta/gd/API/DownloadHandler.java @@ -0,0 +1,14 @@ +package org.happysanta.gd.API; + +/** + * Created by evgeny on 6/10/14. + */ +public interface DownloadHandler { + + public abstract void onStart(); + + public abstract void onFinish(Throwable error); + + public abstract void onProgress(int progress); + +}
\ No newline at end of file diff --git a/src/org/happysanta/gd/API/LevelsResponse.java b/src/org/happysanta/gd/API/LevelsResponse.java new file mode 100755 index 0000000..b62a6e6 --- /dev/null +++ b/src/org/happysanta/gd/API/LevelsResponse.java @@ -0,0 +1,64 @@ +package org.happysanta.gd.API; + +import org.happysanta.gd.Storage.Level; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Vector; + +public class LevelsResponse { + + protected Level levels[] = null; + protected int totalCount = 0; + + public LevelsResponse(Response response) { + parse(response); + } + + protected void parse(Response response) { + JSONArray json = response.getJSON(); + try { + JSONObject object = json.getJSONObject(1); + Vector<Level> levels = new Vector<>(); + totalCount = object.getInt("count"); + JSONArray items = object.getJSONArray("items"); + + try { + JSONObject item; + JSONArray tracks; + for (int i = 0; i < items.length(); i++) { + item = items.getJSONObject(i); + tracks = item.getJSONArray("tracks"); + + levels.addElement(new Level( + 0, + item.getString("name"), + item.getJSONObject("author").getString("name"), + tracks.getInt(0), + tracks.getInt(1), + tracks.getInt(2), + item.getInt("added"), + item.getInt("size"), + item.getInt("id") + )); + } + } catch (JSONException e) { + e.printStackTrace(); + } finally { + this.levels = levels.toArray(new Level[0]); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public int getTotalCount() { + return totalCount; + } + + public Level[] getLevels() { + return levels; + } + +} diff --git a/src/org/happysanta/gd/API/NotificationsResponse.java b/src/org/happysanta/gd/API/NotificationsResponse.java new file mode 100644 index 0000000..06dca09 --- /dev/null +++ b/src/org/happysanta/gd/API/NotificationsResponse.java @@ -0,0 +1,76 @@ +package org.happysanta.gd.API; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class NotificationsResponse { + + private String title; + private String message; + private String url; + private int buttonsCount = 1; + private String[] buttons = new String[2]; + private boolean empty = true; + private boolean isURL = false; + + public NotificationsResponse(Response response) { + parse(response); + } + + protected void parse(Response response) { + JSONArray json = response.getJSON(); + try { + JSONArray jsonResponse = json.getJSONArray(1); + if (jsonResponse.length() > 0) { + JSONObject notification = jsonResponse.getJSONObject(0); + title = notification.getString("title"); + message = notification.getString("message"); + buttons[0] = notification.getString("button_ok"); + if (notification.has("button_cancel")) { + buttonsCount = 2; + buttons[1] = notification.getString("button_cancel"); + } + if (notification.has("open_url")) { + url = notification.getString("open_url"); + isURL = true; + } + empty = false; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public boolean isEmpty() { + return empty; + } + + public boolean hasURL() { + return isURL; + } + + public String getURL() { + return url; + } + + public String getTitle() { + return title; + } + + public String getMessage() { + return message; + } + + public boolean hasTwoButtons() { + return buttonsCount == 2; + } + + public String getOKButton() { + return buttons[0]; + } + + public String getCancelButton() { + return buttons[1]; + } + +} diff --git a/src/org/happysanta/gd/API/Request.java b/src/org/happysanta/gd/API/Request.java new file mode 100644 index 0000000..d8bfa6e --- /dev/null +++ b/src/org/happysanta/gd/API/Request.java @@ -0,0 +1,143 @@ +package org.happysanta.gd.API; + +import android.os.AsyncTask; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Locale; + +import static org.happysanta.gd.Helpers.getAppVersion; +import static org.happysanta.gd.Helpers.logDebug; + +public class Request { + + // enum Method { GET, POST }; + + private List<NameValuePair> params; + private ResponseHandler handler; + private AsyncRequestTask task; + private String apiURL; + + public Request(String method, List<NameValuePair> params, ResponseHandler handler, boolean useDebugURL) { + construct(method, params, handler, useDebugURL ? API.DEBUG_URL : API.URL); + } + + public Request(String method, List<NameValuePair> params, ResponseHandler handler) { + construct(method, params, handler, API.URL); + } + + private void construct(String method, List<NameValuePair> params, ResponseHandler handler, String apiURL) { + this.apiURL = apiURL; + + params.add(new BasicNameValuePair("v", String.valueOf(API.VERSION))); + params.add(new BasicNameValuePair("method", method)); + params.add(new BasicNameValuePair("app_version", getAppVersion())); + params.add(new BasicNameValuePair("app_lang", Locale.getDefault().getDisplayLanguage())); + + this.params = params; + this.handler = handler; + + go(); + } + + private void go() { + task = new AsyncRequestTask(); + task.execute(apiURL); + } + + public void cancel() { + if (task != null) { + task.cancel(true); + task = null; + } + } + + private void onDone(String result) { + Response response; + logDebug("API.Request.onDone()"); + + try { + response = new Response(result); + } catch (APIException e) { + handler.onError(e); + return; + } catch (Exception e) { + // e.printStackTrace(); + handler.onError(new APIException(result == null ? "Network error" : "JSON parsing error")); + return; + // exception = new Exception(); + } + + // handler.onResponse(response); + + if (response != null) + handler.onResponse(response); + else + handler.onError(new APIException("JSON parsing error")); + } + + protected class AsyncRequestTask extends AsyncTask<String, Void, String> { + + @Override + protected String doInBackground(String... objects) { + String url = objects[0]; + + DefaultHttpClient client = new DefaultHttpClient(); + HttpPost post = new HttpPost(url); + try { + post.setEntity(new UrlEncodedFormEntity(params)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + String result = null; + InputStream is = null; + + try { + HttpResponse response = client.execute(post); + HttpEntity entity = response.getEntity(); + is = entity.getContent(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"), 8); + StringBuilder sb = new StringBuilder(); + + String line; + while ((line = reader.readLine()) != null) { + if (isCancelled()) break; + sb.append(line + "\n"); + } + result = sb.toString(); + } catch (java.lang.Exception e) { + logDebug("API request failed: " + e.getMessage()); + // e.printStackTrace(); + return null; + } finally { + try { + if (is != null) is.close(); + } catch (IOException e) { + // e.printStackTrace(); + } + } + + return result; + } + + @Override + public void onPostExecute(String result) { + onDone(result); + } + + } + +} diff --git a/src/org/happysanta/gd/API/Response.java b/src/org/happysanta/gd/API/Response.java new file mode 100644 index 0000000..827fae4 --- /dev/null +++ b/src/org/happysanta/gd/API/Response.java @@ -0,0 +1,26 @@ +package org.happysanta.gd.API; + +import org.happysanta.gd.API.*; +import org.json.JSONArray; +import org.json.JSONException; + +public class Response { + + JSONArray jsonArray; + + public Response(String result) throws JSONException, APIException { + jsonArray = new JSONArray(result); + if (!isOK()) { + throw new APIException(jsonArray.getString(1)); + } + } + + public boolean isOK() throws JSONException { + return jsonArray.getString(0).equals("ok"); + } + + public JSONArray getJSON() { + return jsonArray; + } + +} diff --git a/src/org/happysanta/gd/API/ResponseHandler.java b/src/org/happysanta/gd/API/ResponseHandler.java new file mode 100755 index 0000000..7b39c99 --- /dev/null +++ b/src/org/happysanta/gd/API/ResponseHandler.java @@ -0,0 +1,9 @@ +package org.happysanta.gd.API; + +public interface ResponseHandler { + + public void onResponse(Response response); + + public void onError(APIException error); + +} diff --git a/src/org/happysanta/gd/Callback.java b/src/org/happysanta/gd/Callback.java new file mode 100644 index 0000000..a2a2c3f --- /dev/null +++ b/src/org/happysanta/gd/Callback.java @@ -0,0 +1,7 @@ +package org.happysanta.gd; + +public interface Callback { + + public abstract void onDone(Object... objects); + +} diff --git a/src/org/happysanta/gd/Command.java b/src/org/happysanta/gd/Command.java new file mode 100755 index 0000000..821ddc9 --- /dev/null +++ b/src/org/happysanta/gd/Command.java @@ -0,0 +1,11 @@ +package org.happysanta.gd; + +public class Command { + + public String title; + + public Command(String title, int unused1, int unused2) { + this.title = title; + } + +} diff --git a/src/org/happysanta/gd/CommandListener.java b/src/org/happysanta/gd/CommandListener.java new file mode 100755 index 0000000..7af87e8 --- /dev/null +++ b/src/org/happysanta/gd/CommandListener.java @@ -0,0 +1,7 @@ +package org.happysanta.gd; + +public interface CommandListener { + + public void commandAction(Command cmd); + +} diff --git a/src/org/happysanta/gd/DoubleCallback.java b/src/org/happysanta/gd/DoubleCallback.java new file mode 100644 index 0000000..f7d6b7e --- /dev/null +++ b/src/org/happysanta/gd/DoubleCallback.java @@ -0,0 +1,7 @@ +package org.happysanta.gd; + +public interface DoubleCallback extends Callback { + + public abstract void onFail(); + +} diff --git a/src/org/happysanta/gd/FileDialog.java b/src/org/happysanta/gd/FileDialog.java new file mode 100644 index 0000000..78b0326 --- /dev/null +++ b/src/org/happysanta/gd/FileDialog.java @@ -0,0 +1,209 @@ +package org.happysanta.gd; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Environment; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static org.happysanta.gd.Helpers.logDebug; + +public class FileDialog { + private static final String PARENT_DIR = ".."; + private final String TAG = getClass().getName(); + private String[] fileList; + private File currentPath; + + public interface FileSelectedListener { + void fileSelected(File file); + } + + public interface DirectorySelectedListener { + void directorySelected(File directory); + } + + private ListenerList<FileSelectedListener> fileListenerList = new ListenerList<FileDialog.FileSelectedListener>(); + private ListenerList<DirectorySelectedListener> dirListenerList = new ListenerList<FileDialog.DirectorySelectedListener>(); + private final Activity activity; + private boolean selectDirectoryOption = false; + private String fileEndsWith; + + public FileDialog(Activity activity, File path, String fileEndsWith) { + this.activity = activity; + this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase() : fileEndsWith; + if (!path.exists()) path = Environment.getExternalStorageDirectory(); + // logDebug("FileDialog contrustor, path = " + path); + loadFileList(path); + } + + /** + * @return file dialog + */ + public Dialog createFileDialog() { + Dialog dialog = null; + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + + builder.setTitle(currentPath.getPath()); + if (selectDirectoryOption) { + builder.setPositiveButton("Select directory", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + Helpers.logDebug(currentPath.getParent()); + // Log.d(TAG, currentPath.getPath()); + fireDirectorySelectedEvent(currentPath); + } + }); + } + + builder.setItems(fileList, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String fileChosen = fileList[which]; + File chosenFile = getChosenFile(fileChosen); + if (chosenFile.isDirectory()) { + loadFileList(chosenFile); + dialog.cancel(); + dialog.dismiss(); + showDialog(); + } else fireFileSelectedEvent(chosenFile); + } + }); + + dialog = builder.show(); + return dialog; + } + + + public void addFileListener(FileSelectedListener listener) { + fileListenerList.add(listener); + } + + public void removeFileListener(FileSelectedListener listener) { + fileListenerList.remove(listener); + } + + public void setSelectDirectoryOption(boolean selectDirectoryOption) { + this.selectDirectoryOption = selectDirectoryOption; + } + + public void addDirectoryListener(DirectorySelectedListener listener) { + dirListenerList.add(listener); + } + + public void removeDirectoryListener(DirectorySelectedListener listener) { + dirListenerList.remove(listener); + } + + /** + * Show file dialog + */ + public void showDialog() { + createFileDialog().show(); + } + + private void fireFileSelectedEvent(final File file) { + fileListenerList.fireEvent(new ListenerList.FireHandler<FileSelectedListener>() { + public void fireEvent(FileSelectedListener listener) { + listener.fileSelected(file); + } + }); + } + + private void fireDirectorySelectedEvent(final File directory) { + dirListenerList.fireEvent(new ListenerList.FireHandler<DirectorySelectedListener>() { + public void fireEvent(DirectorySelectedListener listener) { + listener.directorySelected(directory); + } + }); + } + + private void loadFileList(File path) { + this.currentPath = path; + + ArrayList<String> dirs = new ArrayList<>(); + ArrayList<String> files = new ArrayList<>(); + ArrayList<String> totalList = new ArrayList<>(); + + if (path.exists()) { + if (path.getParentFile() != null) dirs.add(PARENT_DIR); + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String filename) { + File sel = new File(dir, filename); + if (!sel.canRead()) return false; + if (sel.isHidden()) return false; + if (selectDirectoryOption) return sel.isDirectory(); + else { + boolean endsWith = fileEndsWith != null ? filename.toLowerCase().endsWith(fileEndsWith) : true; + return endsWith || sel.isDirectory(); + } + } + }; + + File[] list = path.listFiles(filter); + try { + if (list != null && list.length > 0) { + for (File file : list) { + if (file.isDirectory()) + dirs.add(file.getName() + "/"); + else + files.add(file.getName()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + Comparator<String> comparator = new Comparator<String>() { + @Override + public int compare(String lhs, String rhs) { + return lhs.compareTo(rhs); + } + }; + + Collections.sort(dirs, comparator); + Collections.sort(files, comparator); + + totalList.addAll(dirs); + totalList.addAll(files); + } + + fileList = totalList.toArray(new String[]{}); + } + + private File getChosenFile(String fileChosen) { + if (fileChosen.equals(PARENT_DIR)) return currentPath.getParentFile(); + else return new File(currentPath, fileChosen); + } +} + +class ListenerList<L> { + private List<L> listenerList = new ArrayList<L>(); + + public interface FireHandler<L> { + void fireEvent(L listener); + } + + public void add(L listener) { + listenerList.add(listener); + } + + public void fireEvent(FireHandler<L> fireHandler) { + List<L> copy = new ArrayList<L>(listenerList); + for (L l : copy) { + fireHandler.fireEvent(l); + } + } + + public void remove(L listener) { + listenerList.remove(listener); + } + + public List<L> getListenerList() { + return listenerList; + } +}
\ No newline at end of file diff --git a/src/org/happysanta/gd/GDActivity.java b/src/org/happysanta/gd/GDActivity.java new file mode 100755 index 0000000..88876a6 --- /dev/null +++ b/src/org/happysanta/gd/GDActivity.java @@ -0,0 +1,1177 @@ +package org.happysanta.gd; + +import android.app.Activity; +import android.app.AlarmManager; +import android.app.AlertDialog; +import android.app.PendingIntent; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Rect; +import android.net.Uri; +import android.os.Bundle; +import android.text.Html; +import android.view.*; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import org.happysanta.gd.API.*; +import org.happysanta.gd.Game.*; +import org.happysanta.gd.Levels.Loader; +import org.happysanta.gd.Menu.Views.MenuHelmetView; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; +import org.happysanta.gd.Menu.Views.MenuTextView; +import org.happysanta.gd.Menu.Views.MenuTitleLinearLayout; +import org.happysanta.gd.Menu.Views.ObservableScrollView; +import org.happysanta.gd.Storage.LevelsManager; +import org.acra.util.Installation; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +import static org.happysanta.gd.Helpers.logDebug; + +public class GDActivity extends Activity implements Runnable { + + public static GDActivity shared = null; + public static final int MENU_TITLE_LAYOUT_TOP_PADDING = 25; + public static final int MENU_TITLE_LAYOUT_BOTTOM_PADDING = 13; + public static final int MENU_TITLE_LAYOUT_X_PADDING = 30; + public static final int MENU_TITLE_FONT_SIZE = 30; + public static final int GAME_MENU_BUTTON_LAYOUT_WIDTH = 40; + public static final int GAME_MENU_BUTTON_LAYOUT_HEIGHT = 56; + + private static final long IMAGES_DELAY = 1000L; + private static final long IMAGES_DELAY_DEBUG = 100L; + + public int m_longI = 0; + + private boolean wasPaused = false; + private boolean wasStarted = false; + private boolean wasDestroyed = false; + private boolean restartingStarted = false; + public boolean alive = false; + public boolean m_cZ = true; + private boolean menuShown = false; + public boolean fullResetting = false; + public boolean exiting = false; + + public GameView gameView = null; + // public MenuView menuView = null; + public Loader levelLoader; + public Physics physEngine; + public org.happysanta.gd.Menu.Menu menu; + public boolean m_caseZ; + public int m_nullI; + public long m_forJ; + // public long seconds; + public long startedTime = 0; + public long finishedTime = 0; + public long pausedTime = 0; + public long pausedTimeStarted = 0; + public long m_byteJ; + public boolean inited = false; + public boolean m_ifZ; + private Thread thread; + private MenuImageView menuBtn; + public MenuTitleLinearLayout titleLayout; + public ObservableScrollView scrollView; + private FrameLayout frame; + private MenuLinearLayout menuLayout; + private KeyboardController keyboardController; + private boolean isNormalAndroid = true; + private boolean buttonCoordsCalculated = false; + public TextView menuTitleTextView; + private boolean menuReady = false; + private ArrayList<Command> commands = new ArrayList<Command>(); + private MenuLinearLayout keyboardLayout; + private MenuTextView portedTextView; + private int buttonHeight = 60; + public LevelsManager levelsManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + shared = this; + + if (Helpers.isSDK10OrLower()) { + isNormalAndroid = false; + } + + final GDActivity self = this; + Request request = API.getNotifications(Global.INSTALLED_FROM_APK, new ResponseHandler() { + @Override + public void onResponse(final Response apiResponse) { + try { + final NotificationsResponse response = new NotificationsResponse(apiResponse); + if (!response.isEmpty()) { + final Runnable onOk = new Runnable() { + @Override + public void run() { + if (response.hasURL()) { + String url = response.getURL(); + try { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(browserIntent); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }; + + if (response.hasTwoButtons()) { + AlertDialog.Builder alert = new AlertDialog.Builder(self) + .setTitle(response.getTitle()) + .setMessage(response.getMessage()) + .setPositiveButton(response.getOKButton(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + onOk.run(); + } + }) + .setNegativeButton(response.getCancelButton(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + + } + }); + alert.show(); + } else { + AlertDialog alertDialog = new AlertDialog.Builder(self) + .setTitle(response.getTitle()) + .setMessage(response.getMessage()) + .setPositiveButton(response.getOKButton(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + onOk.run(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + } + }) + .create(); + alertDialog.show(); + } + } + } catch (Exception e) { + // e.printStackTrace(); + } + } + + @Override + public void onError(APIException error) { + + } + }); + + if (true) { + gameView = new GameView(this); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + + scrollView = new ObservableScrollView(this); + scrollView.setBackgroundColor(0x00ffffff); + scrollView.setFillViewport(true); + scrollView.setOnScrollListener(new ObservableScrollView.OnScrollListener() { + @Override + public void onScroll(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) { + if (isMenuShown() && menu != null && menu.currentMenu != null) { + int h = scrollView.getChildAt(0).getHeight() - scrollView.getHeight(); + double p = 100.0 * y / h; + if (p > 100f) + p = 100f; + + menu.currentMenu.onScroll(p); + } + } + }); + scrollView.setVisibility(View.GONE); + + frame = new FrameLayout(this); + frame.setBackgroundColor(0xffffffff); + + titleLayout = new MenuTitleLinearLayout(this); + titleLayout.setBackgroundColor(0x00ffffff); + titleLayout.setGravity(Gravity.TOP); + titleLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + titleLayout.setPadding(Helpers.getDp(MENU_TITLE_LAYOUT_X_PADDING), Helpers.getDp(MENU_TITLE_LAYOUT_TOP_PADDING), Helpers.getDp(MENU_TITLE_LAYOUT_X_PADDING), Helpers.getDp(MENU_TITLE_LAYOUT_BOTTOM_PADDING)); + + menuTitleTextView = new TextView(this); + menuTitleTextView.setText(getString(R.string.main)); + menuTitleTextView.setTextColor(0xff000000); + menuTitleTextView.setTypeface(Global.robotoCondensedTypeface); + menuTitleTextView.setTextSize(MENU_TITLE_FONT_SIZE); + menuTitleTextView.setLineSpacing(0f, 1.1f); + menuTitleTextView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + menuTitleTextView.setVisibility(android.view.View.GONE); + + titleLayout.addView(menuTitleTextView); + + scrollView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, 1)); + + // Keyboard + String[] buttonResources = { + "btn_br", "btn_br", "btn_b", + "btn_br", "btn_br", "btn_b", + "btn_r", "btn_r", "btn_n" + }; + if (getString(R.string.screen_type).equals("tablet")) { + buttonHeight = 85; + } else if (Global.density < 1.5) { + buttonHeight = 55; + } + + keyboardLayout = new MenuLinearLayout(this, true); + keyboardLayout.setOrientation(LinearLayout.VERTICAL); + + keyboardController = new KeyboardController(this); + + for (int i = 0; i < 3; i++) { + LinearLayout row = new LinearLayout(this); + row.setPadding(Helpers.getDp(KeyboardController.PADDING), i == 0 ? Helpers.getDp(KeyboardController.PADDING) : 0, Helpers.getDp(KeyboardController.PADDING), 0); + row.setOrientation(LinearLayout.HORIZONTAL); + row.setBackgroundColor(0xc6ffffff); + for (int j = 0; j < 3; j++) { + LinearLayout btn = new LinearLayout(this); + TextView btnText = new TextView(this); + btnText.setText(String.valueOf(i * 3 + j + 1)); + btnText.setTextColor(0xff000000); + btnText.setTextSize(17); + btn.setBackgroundResource(getResources().getIdentifier(buttonResources[i * 3 + j], "drawable", getPackageName())); + btn.addView(btnText, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + btn.setGravity(Gravity.CENTER); + btn.setWeightSum(1); + + row.addView(btn, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, Helpers.getDp(buttonHeight), 1)); + + keyboardController.addButton(btn, j, i); + } + + keyboardLayout.addView(row); + } + + keyboardLayout.setGravity(Gravity.BOTTOM); + keyboardLayout.setPadding(0, 0, 0, Helpers.getDp(KeyboardController.PADDING)); + keyboardLayout.setOnTouchListener(keyboardController); + keyboardLayout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); + + hideKeyboardLayout(); + + menuBtn = new MenuImageView(this); + menuBtn.setImageResource(R.drawable.ic_menu); + menuBtn.setScaleType(ImageView.ScaleType.CENTER); + menuBtn.setLayoutParams(new FrameLayout.LayoutParams(Helpers.getDp(GAME_MENU_BUTTON_LAYOUT_WIDTH), Helpers.getDp(GAME_MENU_BUTTON_LAYOUT_HEIGHT), Gravity.RIGHT | Gravity.TOP)); + menuBtn.setOnClickListener(new android.view.View.OnClickListener() { + @Override + public void onClick(android.view.View v) { + gameView.showMenu(); + } + }); + menuBtn.setVisibility(android.view.View.GONE); + + menuLayout = new MenuLinearLayout(this); + menuLayout.setOrientation(LinearLayout.VERTICAL); + menuLayout.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT + )); + + portedTextView = new MenuTextView(this); + portedTextView.setTypeface(Global.robotoCondensedTypeface); + portedTextView.setTextSize(15); + portedTextView.setLineSpacing(0f, 1.2f); + portedTextView.setText(Html.fromHtml(getString(R.string.ported_text))); + portedTextView.setGravity(Gravity.CENTER); + portedTextView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); + portedTextView.setPadding(0, 0, 0, Helpers.getDp(10)); + + menuLayout.addView(titleLayout); + menuLayout.addView(scrollView); + + frame.addView(menuLayout); + frame.addView(keyboardLayout); + frame.addView(menuBtn); + frame.addView(portedTextView); + + gameView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT, 1)); + frame.addView(gameView, 0); + + setContentView(frame); + + gameView._doIV(1); // flag for 1st image, as I understand.. + thread = null; + m_caseZ = false; + m_nullI = 2; + m_forJ = 0; + m_byteJ = 0; + inited = false; + m_ifZ = false; + wasDestroyed = false; + restartingStarted = false; + + frame.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + frame.getViewTreeObserver().removeOnPreDrawListener(this); + // setButtonsLayoutHeight(); + doStart(); + return true; + } + }); + + + + /* gameView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + gameView.getViewTreeObserver().removeOnPreDrawListener(this); + doStart(); + return true; + } + }); */ + + /* alive = true; + m_cZ = false; + + Thread.currentThread().setName("main_thread"); + + if (thread == null) { + thread = new Thread(this); + thread.setName("game_thread"); + } */ + + /*synchronized (thread) { + thread.start(); + try { + thread.wait(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + for (int i = 1; i <= 4; i++) { + menu.load(i); + } + + wasStarted = true;*/ + } + } + + protected void doStart() { + alive = true; + m_cZ = false; + + Thread.currentThread().setName("main_thread"); + + if (thread == null) { + thread = new Thread(this); + thread.setName("game_thread"); + thread.start(); + } + + wasStarted = true; + } + + // protected boolean viewDone = false; + + @Override + public void run() { + Helpers.logDebug("!!! run()"); + long l1; + + if (!inited) { + Helpers.logDebug("run(): initing"); + try { + // Game view + /* gameView = new GameView(shared); + gameView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT, 1)); + frame.addView(gameView, 0); */ + + /* gameView._doIV(1); + thread = null; + m_caseZ = false; + m_nullI = 2; + m_forJ = 0L; + seconds = 0L; + m_byteJ = 0L; + inited = false; + m_ifZ = false; */ + + long imageDelay = Global.DEBUG ? IMAGES_DELAY_DEBUG : IMAGES_DELAY; // delay of first image + Thread.yield(); + + /*gameView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + gameView.getViewTreeObserver().removeOnPreDrawListener(this); + viewDone = true; + logDebug("gameView is ready"); + //doStart(); + return true; + } + }); + + logDebug("before while.."); + while (!viewDone) { + // Thread.sleep(1); + } + logDebug("after while..");*/ + + // do we really need this?! + /*while (gameView == null || gameView.getParent() == null) { + try { + Thread.sleep(100); + } catch (Exception x) {} + }*/ + + MenuHelmetView.clearStaticFields(); + + levelsManager = new LevelsManager(); + try { + levelLoader = new Loader(levelsManager.getCurrentLevelsFile()); + } catch (IOException e) { + e.printStackTrace(); + // logDebug("Reset level id now"); + levelsManager.resetId(); + levelsManager.reload(); + + levelLoader = new Loader(levelsManager.getCurrentLevelsFile()); + } + + physEngine = new Physics(levelLoader); + gameView.setPhysicsEngine(physEngine); + + // logDebug(levelsManager.getLevelsStat()); + sendStats(); + + /* synchronized (Thread.currentThread()) { + Thread.currentThread().notify(); + } */ + menu = new org.happysanta.gd.Menu.Menu(); + // menu = null; + // menu.hideKeyboard(); + for (int i = 1; i <= 4; i++) { + menu.load(i); + } + + // menu = new Menu(); + // menu.hideKeyboard(); + + /*menu.load(1); + menu.load(2); + menu.load(3); + + Runnable createMenuRunnable = new Runnable() { + @Override + public void run() { + menu.load(4); + synchronized (this) { + notify(); + } + } + }; + + synchronized (createMenuRunnable) { + // logDebug("before runOnUiThread()"); + runOnUiThread(createMenuRunnable); + try { + // logDebug("before wait()"); + createMenuRunnable.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }*/ + + portedTextView.setVisibility(View.VISIBLE); + + gameView.setMenu(menu); + gameView._doIIV(-50, 150); + setMode(1); + + // Show first image + Helpers.logDebug("show first image"); + long l2; + for (; imageDelay > 0L; imageDelay -= l2) + l2 = _avJ(); + + // Show second image + portedTextView.setVisibility(View.GONE); + Helpers.logDebug("show second image"); + imageDelay = Global.DEBUG ? IMAGES_DELAY_DEBUG : IMAGES_DELAY; + gameView._doIV(2); + long l3; + for (long l4 = imageDelay; l4 > 0L; l4 -= l3) + l3 = _avJ(); + + while (m_longI < 10) + _avJ(); + + gameView._doIV(0); + Helpers.logDebug("images DONE"); + inited = true; + + } catch (Exception _ex) { + _ex.printStackTrace(); + // Log.w("GDTR", _ex); + throw new RuntimeException(_ex); + } + } + + // logDebug("inited, continue"); + + restart(false); + // logDebug("showMenu() now"); + + /*if (menu != null) */ + menu.showMenu(0); + if (/*menu != null && */menu.canStartTrack()) + restart(true); + l1 = 0L; + + // try { + Helpers.logDebug("start main loop"); + while (alive) { + /*if (!alive) { + logDebug("!alive"); + break; + }*/ + + // try { + if (physEngine._bytevI() != menu._jvI()) { + int j = gameView._intII(menu._jvI()); + physEngine._doIV(j); + menu._intIV(j); + } + + if (menuShown) { + menu.showMenu(1); + if (menu.canStartTrack()) + restart(true); + } + + for (int i1 = m_nullI; i1 > 0 && alive; i1--) { + /* if (m_ifZ) + seconds += 20L; */ + if (m_forJ == 0L) + m_forJ = System.currentTimeMillis(); + int k = 0; + if (/*physEngine != null && */(k = physEngine._dovI()) == 3 && m_byteJ == 0L) { + m_byteJ = System.currentTimeMillis() + 3000L; + gameView.showInfoMessage(getString(R.string.crashed), 3000); + //m_di.postInvalidate(); + //m_di.serviceRepaints(); + } + if (m_byteJ != 0L && m_byteJ < System.currentTimeMillis()) + restart(true); + if (k == 5) { + finishedTime = System.currentTimeMillis(); + gameView.showInfoMessage(getString(R.string.crashed), 3000); + //m_di.postInvalidate(); + //m_di.serviceRepaints(); + try { + long l2 = 1000L; + if (m_byteJ > 0L) + l2 = Math.min(m_byteJ - System.currentTimeMillis(), 1000L); + if (l2 > 0L) + Thread.sleep(l2); + } catch (InterruptedException _ex) { + } + restart(true); + } else if (k == 4) { + // logDebug("k == 4"); + m_forJ = 0; + // seconds = 0; + startedTime = 0; + finishedTime = 0; + pausedTime = 0; + } else if (k == 1 || k == 2) { + finishedTime = System.currentTimeMillis(); + // logDebug("game-run: k = " + k); + /* if (k == 2) + seconds -= 10L; */ + goalLoop(); + // menu.setLastTrackTime(seconds / 10L); + menu.setLastTrackTime((finishedTime - startedTime) / 10); + menu.showMenu(2); + + if (menu.canStartTrack()) + restart(true); + if (!alive) { + Helpers.logDebug("!alive (2)"); + break; + } + } + m_ifZ = k != 4; + if (m_ifZ && startedTime == 0) { + startedTime = System.currentTimeMillis(); + } + } + + if (!alive) { + Helpers.logDebug("!alive (3)"); + break; + } + + //try { + /*if (physEngine != null)*/ + physEngine._charvV(); + long l; + if ((l = System.currentTimeMillis()) - l1 < 30L) { + try { + synchronized (this) { + wait(Math.max(30L - (l - l1), 1L)); + } + } catch (InterruptedException interruptedexception) { + } + l1 = System.currentTimeMillis(); + } else { + l1 = l; + } + //m_di.postInvalidate(); + /*} catch (Exception exception) { + exception.printStackTrace(); + }*/ + } + // } catch (Exception e) { + // e.printStackTrace(); + //} + + Helpers.logDebug("game thread finished, destroyApp(false) next"); + + // finish(); + destroyApp(false); + // return; + } + + @Override + protected void onResume() { + Helpers.logDebug("@@@ [GDActivity \"+hashCode()+\"] onResume()"); + super.onResume(); + Helpers.logDebug("[GDActivity \"+hashCode()+\"] onResume(), inited = " + inited); + if (wasPaused && wasStarted) { + // logDebug("onResume(): wasPaused && wasResumed"); + // start(); + m_cZ = false; + wasPaused = false; + + // Menu.HelmetRotation.start(); + } + } + + @Override + protected void onPause() { + super.onPause(); + + Helpers.logDebug("@@@ [GDActivity " + hashCode() + "] onPause()"); + + wasPaused = true; + m_cZ = true; + Helpers.logDebug("inited : " + inited); + if (!menuShown && inited) + gameToMenu(); + + // menu.helmetRotationStop(); + // Menu.HelmetRotation.stop(); + // if (menu != null) + // menu.saveAll(); + // levelsManager.updateLevelSettings(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + Helpers.logDebug("@@@ [GDActivity " + hashCode() + "] onDestroy()"); + destroyApp(false); + } + + @Override + protected void onStop() { + super.onStop(); + Helpers.logDebug("@@@ [GDActivity " + hashCode() + "] onStop()"); + } + + @Override + protected void onStart() { + super.onStart(); + Helpers.logDebug("@@@ [GDActivity " + hashCode() + "] onStart()"); + } + + @Override + protected void onRestart() { + super.onRestart(); + Helpers.logDebug("@@@ [GDActivity " + hashCode() + "] onRestart()"); + } + + @Override + public void onBackPressed() { + if (gameView != null && menu != null && inited) { + if (menuShown) + menu.back(); + else + gameView.showMenu(); + } + } + + @Override + public boolean onCreateOptionsMenu(android.view.Menu menu) { + menu.clear(); + int id = 1; + for (Command cmd : commands) { + MenuItem item = menu.add(0, id, 0, cmd.title); + id++; + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + gameView.commandAction(commands.get(item.getItemId() - 1)); + return true; + } + + public void setMode(int j) { + physEngine._byteIV(j); + } + + public boolean isMenuShown() { + return menuShown; + } + + // @UiThread + public void setMenu(final LinearLayout layout) { + runOnUiThread(new Runnable() { + @Override + public void run() { + scrollView.removeAllViews(); + if (layout.getParent() != null) { + ((ViewManager) layout.getParent()).removeView(layout); + } + scrollView.addView(layout); + } + }); + } + + public void goalLoop() { + if (!alive) { + return; + } + + long l1 = 0L; + if (!physEngine.m_NZ) + gameView.showInfoMessage(getString(R.string.wheelie), 1000); + else + gameView.showInfoMessage(getString(R.string.finished1), 1000); + for (long l2 = System.currentTimeMillis() + 1000L; l2 > System.currentTimeMillis(); gameView.postInvalidate()) { + if (menuShown) { + //m_di.postInvalidate(); + return; + } + for (int j = m_nullI; j > 0; j--) + if (physEngine._dovI() == 5) + try { + long l3; + if ((l3 = l2 - System.currentTimeMillis()) > 0L) + Thread.sleep(l3); + return; + } catch (InterruptedException _ex) { + return; + } + + physEngine._charvV(); + long l; + if ((l = System.currentTimeMillis()) - l1 < 30L) { + try { + synchronized (this) { + wait(Math.max(30L - (l - l1), 1L)); + } + } catch (InterruptedException interruptedexception) { + } + l1 = System.currentTimeMillis(); + } else { + l1 = l; + } + } + } + + public void restart(boolean flag) { + // logDebug("[GDActivity] restart()"); + if (!alive) { + return; + } + + physEngine._doZV(true); + // logDebug("[GDActivity] restart(): 1"); + m_forJ = 0; + // seconds = 0; + startedTime = 0; + finishedTime = 0; + pausedTime = 0; + m_byteJ = 0; + if (flag) + gameView.showInfoMessage(levelLoader.getLevelName(menu.getSelectedLevel(), menu.getSelectedTrack()), 3000); + // logDebug("[GDActivity] restart(): 2"); + gameView._casevV(); + // logDebug("[GDActivity] restart(): 3"); + } + + public void destroyApp(final boolean restart) { + if (wasDestroyed) { + return; + } + + wasDestroyed = true; + alive = false; + + final GDActivity self = this; + + runOnUiThread(new Runnable() { + @Override + public void run() { + Helpers.logDebug("[GDActivity " + self.hashCode() + "] destroyApp()"); + inited = false; + m_caseZ = true; + + synchronized (gameView) { + destroyResources(); + + if (exiting || restart) { + finish(); + } + + if (restart) { + doRestartApp(); + } + } + } + }); + } + + private void destroyResources() { + Helpers.logDebug("[GDActivity " + hashCode() + "] destroyResources()"); + + // if (thread != null) thread.interrupt(); + if (gameView != null) gameView.destroy(); + + menuShown = false; + if (menu != null) { + if (!fullResetting) menu.saveAll(); + menu.destroy(); + } + + if (levelsManager != null) levelsManager.closeDataSource(); + } + + public int getButtonsLayoutHeight() { + return buttonHeight * 3 + KeyboardController.PADDING * 2; + } + + // @UiThread + public void hideKeyboardLayout() { + runOnUiThread(new Runnable() { + @Override + public void run() { + keyboardLayout.setVisibility(android.view.View.GONE); + + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) scrollView.getLayoutParams(); + params.setMargins(0, 0, 0, 0); + scrollView.setLayoutParams(params); + } + }); + } + + // @UiThread + public void showKeyboardLayout() { + runOnUiThread(new Runnable() { + @Override + public void run() { + keyboardLayout.setVisibility(android.view.View.VISIBLE); + + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) scrollView.getLayoutParams(); + params.setMargins(0, 0, 0, Helpers.getDp(getButtonsLayoutHeight())); + scrollView.setLayoutParams(params); + } + }); + } + + public void addCommand(Command cmd) { + if (!commands.contains(cmd)) + commands.add(cmd); + if (isNormalAndroid) + invalidateOptionsMenu(); + } + + public void removeCommand(Command cmd) { + commands.remove(cmd); + if (isNormalAndroid) + invalidateOptionsMenu(); + } + + public void gameToMenu() { + Helpers.logDebug("gameToMenu()"); + + if (gameView == null) { + Helpers.logDebug("gameToMenu(): gameView == null"); + return; + } + + pausedTimeStarted = System.currentTimeMillis(); + + gameView.removeMenuCommand(); + menuShown = true; + // menu.helmetRotationStart(); + // Menu.HelmetRotation.start(); + if (menu != null) + menu.addCommands(); + + // hideKeyboardLayout(); + if (!Settings.isKeyboardInMenuEnabled()) + hideKeyboardLayout(); + else + showKeyboardLayout(); + + gameToMenuUpdateUi(); + } + + // @UiThread + protected void gameToMenuUpdateUi() { + runOnUiThread(new Runnable() { + @Override + public void run() { + menuBtn.setVisibility(android.view.View.GONE); + menuTitleTextView.setVisibility(android.view.View.VISIBLE); + scrollView.setVisibility(android.view.View.VISIBLE); + } + }); + } + + public void menuToGame() { + Helpers.logDebug("menuToGame()"); + + if (pausedTimeStarted > 0 && startedTime > 0) { + pausedTime += (System.currentTimeMillis() - pausedTimeStarted); + pausedTimeStarted = 0; + } + + if (menu != null) menu.removeCommands(); + menuShown = false; + // menu.helmetRotationStop(); + // Menu.HelmetRotation.stop(); + if (gameView != null) gameView.addMenuCommand(); + showKeyboardLayout(); + // menu.showKeyboard(); + + menuToGameUpdateUi(); + + keyboardController.clearLogBuffer(); + } + + // @UiThread + protected void menuToGameUpdateUi() { + runOnUiThread(new Runnable() { + @Override + public void run() { + menuBtn.setVisibility(android.view.View.VISIBLE); + menuTitleTextView.setVisibility(android.view.View.GONE); + scrollView.setVisibility(android.view.View.GONE); + + // Clear menu + scrollView.removeAllViews(); + menuTitleTextView.setText(""); + menu.menuDisabled = true; + // menu.currentMenu = null; + } + }); + } + + public void scrollTextMenuUp() { + runOnUiThread(new Runnable() { + @Override + public void run() { + int y = scrollView.getScrollY(); + scrollView.scrollTo(0, y - Helpers.getDp(20)); + } + }); + } + + public void scrollTextMenuDown() { + runOnUiThread(new Runnable() { + @Override + public void run() { + int y = scrollView.getScrollY(); + scrollView.scrollTo(0, y + Helpers.getDp(20)); + } + }); + } + + public void scrollToView(final View view) { + final GDActivity gd = Helpers.getGDActivity(); + final ObservableScrollView scrollView = gd.scrollView; + + runOnUiThread(new Runnable() { + @Override + public void run() { + Rect scrollBounds = new Rect(); + scrollView.getHitRect(scrollBounds); + + if (!view.getLocalVisibleRect(scrollBounds) + || scrollBounds.height() < view.getHeight()) { + int top = view.getTop(), + height = view.getHeight(), + scrollY = scrollView.getScrollY(), + scrollHeight = scrollView.getHeight(), + y = top; + + /*logDebug("top = " + top); + logDebug("height = " + height); + logDebug("scrollY = " + scrollY); + logDebug("scrollHeight = " + scrollHeight);*/ + + if (top < scrollY) { + // scroll to y + } else if (top + height > scrollY + scrollHeight) { + y = top + height - scrollHeight; + if (y < 0) + y = 0; + } + + // logDebug("View is not visible, scroll to y = " + y); + scrollView.scrollTo(0, y); + } else { + // logDebug("View is visible"); + } + } + }); + } + + private long _avJ() { + m_longI++; + long l = System.currentTimeMillis(); + if (m_longI < 1 || m_longI > 10) { // maybe < 1 not needed? + m_longI--; + try { + Thread.sleep(100L); + } catch (InterruptedException _ex) { + } + } + return System.currentTimeMillis() - l; + } + + public void restartApp() { + if (!restartingStarted) { + destroyApp(true); + restartingStarted = true; + } + } + + private void doRestartApp() { + Intent mStartActivity = new Intent(this, GDActivity.class); + int mPendingIntentId = 123456; + PendingIntent mPendingIntent = PendingIntent.getActivity(this, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT); + AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent); + } + + private void sendStats() { + long lastTs = Settings.getLastSendStats(); + Helpers.logDebug("sendStats: lastTs = " + lastTs); + if (lastTs == 0) { + Helpers.logDebug("sendStats: set it to current ts and return"); + Settings.setLastSendStats(Helpers.getTimestamp()); + return; + } + + // if (Helpers.getTimestamp() < lastTs + 3600 * 8) { + if (Helpers.getTimestamp() < lastTs + 10) { + Helpers.logDebug("sendStats: just return"); + return; + } + + final GDActivity self = this; + Thread statsThread = new Thread() { + @Override + public void run() { + try { + HashMap<String, Double> stats = levelsManager.getLevelsStat(); + + JSONObject statsJSON = new JSONObject(stats); + String id = Installation.id(self); + int useCheats = org.happysanta.gd.Menu.Menu.isNameCheat(Settings.getName()) ? 1 : 0; + + API.sendStats(statsJSON.toString(), id, useCheats, new ResponseHandler() { + @Override + public void onResponse(Response response) { + Helpers.logDebug("send stats OK"); + Settings.setLastSendStats(Helpers.getTimestamp()); + } + + @Override + public void onError(APIException error) { + Helpers.logDebug("send stats error: " + error.getMessage()); + // logDebug(error); + // error.printStackTrace(); + } + }); + } catch (Exception e) { + Helpers.logDebug("send stats exception: " + e.getMessage()); + // e.printStackTrace(); + } + } + }; + statsThread.start(); + } + + public void sendKeyboardLogs() { + final ProgressDialog progressDialog = ProgressDialog.show(this, getString(R.string.please_wait), getString(R.string.please_wait), true); + API.sendKeyboardLogs(keyboardController.getLog(), new ResponseHandler() { + @Override + public void onResponse(Response response) { + progressDialog.dismiss(); + keyboardController.clearLogBuffer(); + Helpers.showAlert(getString(R.string.ok), "Done", null); + } + + @Override + public void onError(APIException error) { + progressDialog.dismiss(); + Helpers.showAlert(getString(R.string.error), "Unable to send logs. Maybe log is empty?", null); + } + }); + } + + private class ButtonCoords { + + public int x = 0; + public int y = 0; + public int w = 0; + public int h = 0; + + public ButtonCoords() { + } + + public boolean in(float x, float y) { + if (x < this.x || x > this.x + this.w || y < this.y || y > this.y + this.h) { + return false; + } + return true; + } + + } + +}
\ No newline at end of file diff --git a/src/org/happysanta/gd/GDApplication.java b/src/org/happysanta/gd/GDApplication.java new file mode 100644 index 0000000..120a5a7 --- /dev/null +++ b/src/org/happysanta/gd/GDApplication.java @@ -0,0 +1,24 @@ +package org.happysanta.gd; + +import android.app.Application; +import org.acra.*; +import org.acra.annotation.*; + +import static org.acra.ReportField.*; + +@ReportsCrashes( + formKey = "", + formUri = "http://gdtr.net/report.php", + customReportContent = {APP_VERSION_NAME, APP_VERSION_CODE, ANDROID_VERSION, PHONE_MODEL, PRODUCT, DISPLAY, STACK_TRACE, LOGCAT, USER_CRASH_DATE, INSTALLATION_ID, CUSTOM_DATA} +) +public class GDApplication extends Application { + + @Override + public void onCreate() { + super.onCreate(); + if (Global.ACRA_ENABLED) { + ACRA.init(this); + } + } + +}
\ No newline at end of file diff --git a/src/org/happysanta/gd/Game/Bitmap.java b/src/org/happysanta/gd/Game/Bitmap.java new file mode 100755 index 0000000..087a865 --- /dev/null +++ b/src/org/happysanta/gd/Game/Bitmap.java @@ -0,0 +1,184 @@ +package org.happysanta.gd.Game; + +import org.happysanta.gd.Global; +import org.happysanta.gd.R; + +import java.io.IOException; + +import static org.happysanta.gd.Helpers.*; + +public class Bitmap { + + public final static int HELMET = 0; + public final static int CODEBREW_LOGO = 1; + public final static int GD_LOGO = 2; + public final static int STEERING = 3; + public final static int WHEELS = 4; + public final static int ARROWS = 5; + public final static int FLAGS = 6; + public final static int LOCKS = 7; + public final static int MEDALS = 8; + public final static int LEVELS_WHEELS = 9; + public final static int FENDER = 10; + public final static int ENGINE = 11; + public final static int BIKER = 12; + + public final static int BLUEARM = 100; + public final static int BLUELEG = 101; + public final static int BLUEBODY = 102; + + public android.graphics.Bitmap bitmap; + protected static GDBitmapHolder holders[]; + protected static Bitmap empty = null; + + Bitmap(android.graphics.Bitmap b) { + bitmap = b; + } + + static { + holders = new GDBitmapHolder[]{ + // 0 + new GDBitmapHolder(Bitmap.fromDrawable(R.drawable.s_helmet)), + + // 1 + new GDBitmapHolder(Bitmap.fromDrawable(R.drawable.codebrew)), + + // 2 + new GDBitmapHolder(Bitmap.fromDrawable(R.drawable.gd)), + + // 3 + new GDBitmapHolder(Bitmap.fromDrawable(R.drawable.s_steering)), + + // 4 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.s_wheel1), + Bitmap.fromDrawable(R.drawable.s_wheel2) + }), + + // 5 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.s_arrow_up), + Bitmap.fromDrawable(R.drawable.s_arrow_down) + }), + + // 6 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.s_flag_start0), + Bitmap.fromDrawable(R.drawable.s_flag_start1), + Bitmap.fromDrawable(R.drawable.s_flag_start2), + Bitmap.fromDrawable(R.drawable.s_flag_finish0), + Bitmap.fromDrawable(R.drawable.s_flag_finish1), + Bitmap.fromDrawable(R.drawable.s_flag_finish2) + }), + + // 7 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.s_lock0), + Bitmap.fromDrawable(R.drawable.s_lock1), + Bitmap.fromDrawable(R.drawable.s_lock2) + }), + + // 8 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.s_medal_gold), + Bitmap.fromDrawable(R.drawable.s_medal_silver), + Bitmap.fromDrawable(R.drawable.s_medal_bronze) + }), + + // 9 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.levels_wheel0), + Bitmap.fromDrawable(R.drawable.levels_wheel1), + Bitmap.fromDrawable(R.drawable.levels_wheel2) + }), + + // 10 + new GDBitmapHolder(Bitmap.fromDrawable(R.drawable.s_fender)), + + // 11 + new GDBitmapHolder(Bitmap.fromDrawable(R.drawable.s_engine)), + + // 12 + new GDBitmapHolder(new Bitmap[]{ + Bitmap.fromDrawable(R.drawable.s_bluearm), + Bitmap.fromDrawable(R.drawable.s_blueleg), + Bitmap.fromDrawable(R.drawable.s_bluebody) + }) + }; + empty = new Bitmap(android.graphics.Bitmap.createBitmap(1, 1, android.graphics.Bitmap.Config.ARGB_8888)); + } + + public static Bitmap get(int index) { + if (index >= BLUEARM && index <= BLUEBODY) { + return get(BIKER, index - 100); + } + + if (holders.length >= index - 1) { + GDBitmapHolder holder = holders[index]; + + if (holder != null && !holder.isArray && holder.bitmap != null) { + return holder.bitmap; + } + } + + return empty; + } + + public static Bitmap get(int index, int arrayIndex) { + if (holders.length >= index - 1) { + GDBitmapHolder holder = holders[index]; + if (holder != null && holder.isArray && holder.bitmaps != null && holder.bitmaps.length >= arrayIndex - 1) { + return holder.bitmaps[arrayIndex]; + } + } + + return empty; + } + + public static Bitmap getEmpty() { + return empty; + } + + public static Bitmap fromDrawable(int id) { + return new Bitmap(loadBitmapFromDrawable(id)); + } + + public static Bitmap fromAsset(String s) throws IOException { + return new Bitmap(loadBitmapFromAsset(s)); + } + + public int getWidth() { + return bitmap.getWidth(); + } + + public int getHeight() { + return bitmap.getHeight(); + } + + public int getWidthDp() { + return Math.round(getWidth() / Global.density); + } + + public int getHeightDp() { + return Math.round(getHeight() / Global.density); + } + + private static class GDBitmapHolder { + + public Bitmap bitmap = null; + public Bitmap bitmaps[] = null; + public boolean isArray = false; + + GDBitmapHolder(Bitmap bitmap) { + this.bitmap = bitmap; + } + + GDBitmapHolder(Bitmap bitmaps[]) { + this.bitmaps = new Bitmap[bitmaps.length]; + System.arraycopy(bitmaps, 0, this.bitmaps, 0, bitmaps.length); + isArray = true; + } + + } + +} diff --git a/src/org/happysanta/gd/Game/FPMath.java b/src/org/happysanta/gd/Game/FPMath.java new file mode 100755 index 0000000..9ddc4ab --- /dev/null +++ b/src/org/happysanta/gd/Game/FPMath.java @@ -0,0 +1,80 @@ +package org.happysanta.gd.Game; + +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + + +public class FPMath { + + // public static final int UNSIGNED_MASK = 0x7fffffff; +// public static final int SIGN_MASK = 0x80000000; + //public static final int m_ifI; +// public static final int m_aI = 1; + public static int HALF_PI = 0x19220; // 1,57080949111162 + // public static int DOUBLE_PI = 0x6487f; // 6,283192187380789 + public static int PI = 0x3243f; // 3,141588464179446 + // public static int ONE = 0x10000; + private static int m_jI; + private static int m_kI; +// private static int SIN_TABLE[] = { +// 0, 1608, 3215, 4821, 6423, 8022, 9616, 11204, 12785, 14359, +// 15923, 17479, 19024, 20557, 22078, 23586, 25079, 26557, 28020, 29465, +// 30893, 32302, 33692, 35061, 36409, 37736, 39039, 40319, 41575, 42806, +// 44011, 45189, 46340, 47464, 48558, 49624, 50660, 51665, 52639, 53581, +// 54491, 55368, 56212, 57022, 57797, 58538, 59243, 59913, 60547, 61144, +// 61705, 62228, 62714, 63162, 63571, 63943, 64276, 64571, 64826, 65043, +// 65220, 65358, 65457, 65516 +// }; +// private static int ARCTG_TABLE[] = { +// 0, 1023, 2047, 3069, 4090, 5109, 6126, 7139, 8149, 9155, +// 10157, 11155, 12146, 13133, 14113, 15087, 16054, 17015, 17967, 18912, +// 19849, 20778, 21698, 22610, 23512, 24405, 25289, 26163, 27027, 27882, +// 28726, 29561, 30385, 31199, 32003, 32796, 33579, 34352, 35114, 35866, +// 36608, 37339, 38060, 38771, 39471, 40161, 40841, 41512, 42172, 42822, +// 43463, 44094, 44716, 45328, 45931, 46524, 47109, 47684, 48251, 48809, +// 49358, 49899, 50431, 50955 +// }; + + public FPMath() { + } + + public static int divide(int i, int j) { + int res = (int) (((long) i << 32) / (long) j >> 16); + return res; + } + + public static int sin(int i) { + float fi = i / (float) 0xFFFF; + return (int) Math.round(Math.sin(fi) * 65536); + } + + public static int _doII(int i) { + return sin(HALF_PI - i); + } + + public static int arctg(int i) { + float fi = i / (float) 0xFFFF; + return (int) Math.round(Math.atan(fi) * 65536); + } + + public static int _ifIII(int i, int j) { + if ((j >= 0 ? j : -j) < 3) + return (i <= 0 ? -1 : 1) * HALF_PI; + int k = arctg(divide(i, j)); + if (i > 0) + if (j > 0) + return k; + else + return PI + k; + if (j > 0) + return k; + else + return k - PI; + } + + static { + m_jI = 64; + m_kI = m_jI << 16; + } +} diff --git a/src/org/happysanta/gd/Game/GameView.java b/src/org/happysanta/gd/Game/GameView.java new file mode 100755 index 0000000..ad181e0 --- /dev/null +++ b/src/org/happysanta/gd/Game/GameView.java @@ -0,0 +1,968 @@ +package org.happysanta.gd.Game; + +import android.graphics.*; +import android.view.View; +import org.happysanta.gd.Command; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Menu; +import org.happysanta.gd.Menu.MenuScreen; +import org.happysanta.gd.Menu.SimpleMenuElement; + +import java.io.IOException; +import java.util.Timer; + +import static org.happysanta.gd.Helpers.*; + +public class GameView extends View { + + private static int m_VI = 0; + private static int m_vcI = 0; + private final int[] startFlagIndexes = { + 2, 0, 1, 0 + }; + private final int[] finishFlagIndexes = { + 4, 3, 5, 3 + }; + public int m_abI; + public int m_dI; + public int m_lI; + public boolean drawTimer; + public android.graphics.Bitmap m_zaBitmap[]; + public boolean m_KZ; + public long m_rJ; + Menu menu; + int m_uI; + int m_aiI; + int m_agI; + int m_gI; + private Canvas canvas; + private int m_XI; + private int m_BI; + private Physics physEngine; + private int m_TI; + private int m_QI; + private GDActivity activity; + private Paint infoFont; + private Paint timerFont; + private boolean m_ahZ; + private int m_oI; + private boolean m_AZ; + private int m_OI; + private android.graphics.Bitmap m_MBitmap; + private Canvas m_dcGraphics; + private boolean m_ecZ; + private String infoMessage; + private int gc; + private Timer timer; + private Command menuCommand; + private Paint paint = new Paint(); + private Object m_ocObject; + private byte[][] m_DaaB = { + {0, 0}, + {1, 0}, + {0, -1}, + {0, 0}, + {0, 0}, + {0, 1}, + {-1, 0} + }; + private byte[][][] m_maaaB = { + { + { + 0, 0 + }, + { + 1, -1 + }, + { + 1, 0 + }, + { + 1, 1 + }, + { + 0, -1 + }, + { + -1, 0 + }, + { + 0, 1 + }, + { + -1, -1 + }, + { + -1, 0 + }, + { + -1, 1 + } + }, { + { + 0, 0 + }, + { + 1, 0 + }, + { + 0, 0 + }, + { + 0, 0 + }, + { + -1, 0 + }, + { + 0, -1 + }, + { + 0, 1 + }, + { + 0, 0 + }, + { + 0, 0 + }, + { + 0, 0 + } + }, + { + { + 0, 0 + }, + { + 0, 0 + }, + { + 0, 0 + }, + { + 1, 0 + }, + { + 0, -1 + }, + { + 0, 1 + }, + { + -1, 0 + }, + { + 0, 0 + }, + { + 0, 0 + }, + { + 0, 0 + } + } + }; + private int inputOption; + private boolean[] m_aeaZ; + private boolean[] m_LaZ; + // private int defaultHeight; + // private int defaultWidth; + + public GameView(GDActivity micro) { + super(micro); + // clear static + m_vcI = 0; + m_VI = 0; + + canvas = null; + physEngine = null; + menu = null; + m_TI = 0; + m_QI = 0; + activity = null; + infoFont = null; + m_ahZ = false; + drawTimer = true; + m_oI = 1; + m_uI = 0; + m_zaBitmap = null; + + m_KZ = false; + m_AZ = true; + m_MBitmap = null; + m_dcGraphics = null; + m_ecZ = false; + infoMessage = null; + gc = 0; + timer = new Timer(); + m_rJ = -1L; + m_ocObject = new Object(); + m_aiI = 0; + m_agI = 0; + m_gI = -1; + inputOption = 2; + m_aeaZ = new boolean[7]; + m_LaZ = new boolean[10]; + // String s; + // String s1; + paint.setAntiAlias(true); + paint.setStrokeWidth(1); + + invalidate(); + m_KZ = false; + activity = micro; + _ifvV(); + + infoFont = new Paint(); + infoFont.setTextSize(20); + infoFont.setAntiAlias(true); + infoFont.setTypeface(Global.robotoCondensedTypeface); + + timerFont = new Paint(); + timerFont.setTextSize(18); + timerFont.setAntiAlias(true); + timerFont.setTypeface(Global.robotoCondensedTypeface); + + m_XI = 0; + m_BI = m_dI; + menuCommand = new Command("Menu", 1, 1); + } + + public void drawBitmap(Bitmap b, float x, float y) { + drawBitmap(b, x, y, canvas); + } + + public void drawBitmap(Bitmap b, float x, float y, Canvas g) { + Paint paint = null; + if (!isSDK11OrHigher()) { + paint = new Paint(); + paint.setFlags(Paint.DITHER_FLAG); + paint.setFilterBitmap(true); + } + g.drawBitmap(b.bitmap, + new Rect(0, 0, b.getWidth(), b.getHeight()), + new RectF(x, y, x + b.getWidthDp(), y + b.getHeightDp()), + paint); + } + + public static void _dovV() { + m_vcI += 655; + int j = 32768 + ((FPMath.sin(m_vcI) >= 0 ? FPMath.sin(m_vcI) : -FPMath.sin(m_vcI)) >> 1); + m_VI += (int) (6553L * (long) j >> 16); + } + + /* + TODO + суть этого метода в том, что после того, как splash-картинки проигрались, они удаляются из памяти, т.к. они больше нафиг не нужны + видимо это было критично на старых телефонах + можно и тут в принципе сделать + */ + public void _doIV(int j) { + m_oI = j; + if (j == 0) { + // Bitmap.get(Bitmap.CODEBREW_LOGO) = null; + // Bitmap.get(Bitmap.GD_LOGO) = null; + } + } + + public void _aZV(boolean flag) { + m_AZ = flag; + _ifvV(); + } + + public void _ifvV() { + m_abI = getScaledWidth(); + m_lI = m_dI = getScaledHeight(); + if (m_KZ && m_AZ) + m_dI -= 80; + //postInvalidate(); + } + + public android.graphics.Bitmap[] spritesFromBitmap(android.graphics.Bitmap bitmap, int j, int k) { + int l = bitmap.getWidth() / j; + int i1 = bitmap.getHeight() / k; + android.graphics.Bitmap aBitmap[] = new android.graphics.Bitmap[j * k]; + for (int j1 = 0; j1 < j * k; j1++) { + aBitmap[j1] = android.graphics.Bitmap.createBitmap(l, i1, android.graphics.Bitmap.Config.ARGB_8888); + new Canvas(aBitmap[j1]).drawBitmap(bitmap, -l * (j1 % j), -i1 * (j1 / j), null); + } + + return aBitmap; + } + + public int _intII(int j) { + synchronized (m_ocObject) { + try { + { + if ((j & 1) != 0) { + /* try { + if (Bitmap.get(Bitmap.FENDER) == null) { + //Bitmap.get(Bitmap.FENDER) = Bitmap.fromAsset("/fender.png"); + //Bitmap.get(Bitmap.FENDER).mulWidth = 1.0f/6.0f; + //Bitmap.get(Bitmap.FENDER).mulHeight = 1.0f/6.0; + Bitmap.get(Bitmap.FENDER) = Bitmap.fromDrawable(R.drawable.s_fender); + } + if (Bitmap.get(Bitmap.ENGINE) == null) { + //Bitmap.get(Bitmap.ENGINE) = Bitmap.fromAsset("/engine.png"); + //Bitmap.get(Bitmap.ENGINE).mulHeight = 1.0f/6.0f; + //Bitmap.get(Bitmap.ENGINE).mulWidth = 1.0f/6.0f; + Bitmap.get(Bitmap.ENGINE) = Bitmap.fromDrawable(R.drawable.s_engine); + } + } catch (Throwable _ex) { + Bitmap.get(Bitmap.FENDER) = Bitmap.get(Bitmap.ENGINE) = null; + j &= -2; + } */ + } else { + // Bitmap.get(Bitmap.ENGINE) = Bitmap.get(Bitmap.FENDER) = null; + // System.gc(); + } + if ((j & 2) != 0) { + // blueleg + /*try { + if (bikerSprites[1] == null) + bikerSprites[1] = Bitmap.fromDrawable(R.drawable.s_blueleg); + } catch (Throwable _ex) { + bikerSprites[1] = null; + bikerSprites[0] = null; + bikerSprites[2] = null; + j &= -3; + System.out.println("There may be error"); + return 0; + }*/ + + // bluearm + /*try { + bikerSprites[0] = Bitmap.fromDrawable(R.drawable.s_bluearm); + } catch (Throwable _ex) { + bikerSprites[0] = bikerSprites[1]; + } + + // bluebody + try { + bikerSprites[2] = Bitmap.fromDrawable(R.drawable.s_bluebody); + } catch (Throwable _ex) { + bikerSprites[2] = bikerSprites[1]; + }*/ + } else { + // bikerSprites[1] = bikerSprites[2] = bikerSprites[0] = null; + } + } + } catch (Exception e) { + e.printStackTrace(); + System.out.println("There may be error [1]"); + } + } + return j; + } + + public android.graphics.Bitmap[] loadSprites(String s, int j, int k) { + android.graphics.Bitmap bitmap; + try { + bitmap = loadBitmapFromAsset(s); + } catch (IOException _ex) { + android.graphics.Bitmap aBitmap[] = new android.graphics.Bitmap[j * k]; + for (int l = 0; l < j * k; l++) + aBitmap[l] = Bitmap.getEmpty().bitmap; + + return aBitmap; + } + return spritesFromBitmap(bitmap, j, k); + } + + public void _casevV() { + physEngine._nullvV(); + _avV(); + m_aiI = 0; + m_agI = 0; + } + + public void setPhysicsEngine(Physics b1) { + physEngine = b1; + physEngine._caseIV(m_abI >= m_dI ? m_dI : m_abI); + } + + public void setMenu(Menu menu) { + this.menu = menu; + } + + /* public Bitmap _aStringBitmap(String s) { + Bitmap bitmap = null; + try { + bitmap = Global.loadBitmapFromAsset(s); + } catch (IOException _ex) { + } + return bitmap; + } */ + + public void _doIIV(int j, int k) { + m_XI = j; + m_BI = k; + physEngine._ifIIV(-j, -j + m_abI); + } + + public int _charvI() { + return m_XI; + } + + private float offsetX(float j) { + return j + m_XI; + } + + private float offsetY(float j) { + return -j + m_BI - getGDActivity().getButtonsLayoutHeight() / 2; + } + + public void _newvV() { + paint.setColor(0xFFFFFFFF); + paint.setStyle(Paint.Style.FILL); + canvas.drawRect(0, m_dI, m_abI, 80, paint); + byte byte0 = 35; + int j = m_abI / 2; + int k = m_dI + 40; + // m_CGraphics.setColor(150, 0, 0); + paint.setColor(0xFF960000); + int i1; + paint.setStyle(Paint.Style.STROKE); + if (m_aiI != 0 || m_agI != 0) { + i1 = (int) (((long) (int) ((long) m_OI * 0xb40000L >> 16) << 32) / 0x3243fL >> 16) >> 16; + int l = i1 - i1 % 45; + l -= 90; + //m_CGraphics.fillArc(j - byte0, k - byte0, 2 * byte0, 2 * byte0, l - 22, 45); + canvas.drawArc(new RectF(j - byte0, k - byte0, 2 * byte0 + j - byte0, 2 * byte0 + k - byte0), l - 22, 45, true, paint); + } + //m_CGraphics.setColor(0, 0, 0); + paint.setColor(0xFF000000); + canvas.drawArc(new RectF(j - byte0, k - byte0, 2 * byte0 + j - byte0, 2 * byte0 + k - byte0), 0, 360, true, paint); + byte0 = 2; + canvas.drawArc(new RectF(j - byte0, k - byte0, 2 * byte0 + j - byte0, 2 * byte0 + k - byte0), 0, 360, true, paint); + paint.setStyle(Paint.Style.FILL); + } + + public void _aIIIV(int j, int k, int l, int i1) { + canvas.drawLine(offsetX(j), offsetY(k), offsetX(l), offsetY(i1), paint); + } + + public void drawLine(int j, int k, int l, int i1) { + canvas.drawLine(offsetX((j << 2) / (float) 0xFFFF), offsetY((k << 2) / (float) 0xFFFF), offsetX((l << 2) / (float) 0xFFFF), offsetY((i1 << 2) / (float) 0xFFFF), paint); + } + + public void _aIIIV(int j, int k, int l, int i1, int j1) { + drawBikerPart(j, k, l, i1, j1, 32768); + } + + public void drawBikerPart(int j, int k, int l, int i1, int j1, int k1) { + float l1 = offsetX((int) ((long) l * (long) k1 >> 16) + (int) ((long) j * (long) (0x10000 - k1) >> 16) >> 16); + float i2 = offsetY((int) ((long) i1 * (long) k1 >> 16) + (int) ((long) k * (long) (0x10000 - k1) >> 16) >> 16); + int j2 = FPMath._ifIII(l - j, i1 - k); + int index = 0; + switch (j1) { + case 0: // '\0' + index = _aIIII(j2, 0, 0x3243f, 16, false); + break; + + case 1: // '\001' + index = _aIIII(j2, 0, 0x3243f, 16, false); + break; + + case 2: // '\002' + index = _aIIII(j2, 0, 0x3243f, 16, false); + break; + } + float fAngleDeg = (float) (j2 / (float) 0xFFFF / Math.PI * 180) - 180; + index = 0; + + Bitmap bikerSprite = Bitmap.get(Bitmap.BIKER, j1); + if (bikerSprite != null) { + float x = l1 - bikerSprite.getWidthDp() / 2; + float y = i2 - bikerSprite.getHeightDp() / 2; + + canvas.save(); + canvas.rotate(fAngleDeg, x + bikerSprite.getWidthDp() / 2, y + bikerSprite.getHeightDp() / 2); + drawBitmap(bikerSprite, x, y); + canvas.restore(); + } + } + + // �������� ����� + public void _ifIIIV(int j, int k, int l, int i1) { + l++; + float j1 = offsetX(j - l); + float k1 = offsetY(k + l); + int l1 = l << 1; + if ((i1 = -(int) (((long) (int) ((long) i1 * 0xb40000L >> 16) << 32) / 0x3243fL >> 16)) < 0) + i1 += 360; + paint.setStyle(Paint.Style.STROKE); + canvas.drawArc(new RectF(j1, k1, j1 + l1, k1 + l1), -((i1 >> 16) + 170), -90, false, paint); + paint.setStyle(Paint.Style.FILL); + } + + // Draws red circle + public void drawLineWheel(float j, float k, int l) { + float i1 = l / 2; + float j1 = offsetX(j - i1); + float k1 = offsetY(k + i1); + + paint.setStyle(Paint.Style.STROKE); + canvas.drawArc(new RectF(j1, k1, j1 + l, k1 + l), 0, 360, true, paint); + paint.setStyle(Paint.Style.FILL); + } + + public void _forIIIV(int j, int k, int l, int i1) { + float j1 = offsetX(j); + float k1 = offsetY(k); + canvas.drawRect(j1, k1, j1 + l, k1 + i1, paint); + } + + public void drawSteering(int j, int k) { + float x = offsetX(j - Bitmap.get(Bitmap.STEERING).getWidthDp() / 2); + float y = offsetY(k + Bitmap.get(Bitmap.STEERING).getHeightDp() / 2); + + drawBitmap(Bitmap.get(Bitmap.STEERING), x, y); + } + + public void drawHelmet(float j, float k, int l) { + float fAngleDeg = (float) (l / (float) 0xFFFF / Math.PI * 180) - 90 - 10; + if (fAngleDeg >= 360) fAngleDeg -= 360; + if (fAngleDeg < 0) fAngleDeg = 360 + fAngleDeg; + if (Bitmap.get(Bitmap.HELMET) != null) { + float x = offsetX(j) - Bitmap.get(Bitmap.HELMET).getWidthDp() / 2; + float y = offsetY(k) - Bitmap.get(Bitmap.HELMET).getHeightDp() / 2; + canvas.save(); + canvas.rotate(fAngleDeg, x + Bitmap.get(Bitmap.HELMET).getWidthDp() / 2, y + Bitmap.get(Bitmap.HELMET).getHeightDp() / 2); + + drawBitmap(Bitmap.get(Bitmap.HELMET), x, y); + canvas.restore(); + } + } + + public void _ifIIIIV(int j, int k, int l, int i1, int j1, int k1) { + } + + public void drawTimer(long l) { + // logDebug("Timer: " + l); + String txt = String.format("%d:%02d:%02d", l / 6000, (l / 100) % 60, l % 100); + // logDebug("drawTimter: long = " + l + ", string = " + txt); + canvas.drawText(txt, 18, -infoFont.ascent() + 17, timerFont); + } + + public synchronized void showInfoMessage(String s, int j) { + m_ahZ = false; + gc++; + infoMessage = s; + if (timer != null) { + timer.schedule(new SimpleMenuElement(gc), j); + } + } + + public void _tryIV(int j) { + if (gc == j) + m_ahZ = true; + } + + public void drawStartFlag(int j, int k) { + if (m_VI > 0x38000) + m_VI = 0; + setColor(0, 0, 0); + _aIIIV(j, k, j, k + 32); + drawBitmap(Bitmap.get(Bitmap.FLAGS, startFlagIndexes[m_VI >> 16]), offsetX(j), offsetY(k) - 32); + } + + public void drawFinishFlag(int j, int k) { + if (m_VI > 0x38000) + m_VI = 0; + setColor(0, 0, 0); + _aIIIV(j, k, j, k + 32); + drawBitmap(Bitmap.get(Bitmap.FLAGS, finishFlagIndexes[m_VI >> 16]), offsetX(j), offsetY(k) - 32); + } + + public void drawWheel(float j, float k, int l) { + int wheel; + if (l == 1) + wheel = 0; // small + else + wheel = 1; // big + + float x = offsetX(j - Bitmap.get(Bitmap.WHEELS, wheel).getWidthDp() / 2); + float y = offsetY(k + Bitmap.get(Bitmap.WHEELS, wheel).getHeightDp() / 2); + + drawBitmap(Bitmap.get(Bitmap.WHEELS, wheel), x, y); + } + + int _aIIII(int j, int k, int l, int i1, boolean flag) { + for (j += k; j < 0; j += l) ; + for (; j >= l; j -= l) ; + if (flag) + j = l - j; + int j1; + if ((j1 = (int) ((long) (int) (((long) j << 32) / (long) l >> 16) * (long) (i1 << 16) >> 16)) >> 16 < i1 - 1) + return j1 >> 16; + else + return i1 - 1; + } + + public void drawEngine(float j, float k, int l) { + float fAngleDeg = (float) (l / (float) 0xFFFF / Math.PI * 180) - 180; + float x = offsetX(j) - Bitmap.get(Bitmap.ENGINE).getWidthDp() / 2; + float y = offsetY(k) - Bitmap.get(Bitmap.ENGINE).getHeightDp() / 2; + if (Bitmap.get(Bitmap.ENGINE) != null) { + canvas.save(); + canvas.rotate(fAngleDeg, x + Bitmap.get(Bitmap.ENGINE).getWidthDp() / 2, y + Bitmap.get(Bitmap.ENGINE).getHeightDp() / 2); + drawBitmap(Bitmap.get(Bitmap.ENGINE), x, y); + canvas.restore(); + } + } + + public void drawFender(float j, float k, int l) { + float fAngleDeg = (float) (l / (float) 0xFFFF / Math.PI * 180) - 180 + 15; + if (fAngleDeg >= 360) fAngleDeg -= 360; + if (Bitmap.get(Bitmap.FENDER) != null) { + float x = offsetX(j) - Bitmap.get(Bitmap.FENDER).getWidthDp() / 2; + float y = offsetY(k) - Bitmap.get(Bitmap.FENDER).getHeightDp() / 2; + + canvas.save(); + canvas.rotate(fAngleDeg, x + Bitmap.get(Bitmap.FENDER).getWidthDp() / 2, y + Bitmap.get(Bitmap.FENDER).getHeightDp() / 2); + drawBitmap(Bitmap.get(Bitmap.FENDER), x, y); + canvas.restore(); + } + } + + public void _tryvV() { + paint.setColor(0xFFFFFFFF); + canvas.drawRect(0, 0, m_abI, m_dI, paint); + } + + public void setColor(int r, int g, int b) { + GDActivity _tmp = activity; + if (getGDActivity().isMenuShown()) { + r += 128; + g += 128; + b += 128; + if (r > 240) + r = 240; + if (g > 240) + g = 240; + if (b > 240) + b = 240; + } + //m_CGraphics.setColor(j, k, l); + paint.setColor(0xFF000000 | (r << 16) | (g << 8) | b); + } + + // Draw boot logos and something else + public void drawGame(Canvas g) { + final GDActivity gd = getGDActivity(); + label0: + { + int j; + synchronized (m_ocObject) { + if (gd.alive && !gd.m_caseZ) + break label0; + } + return; + } + + if (m_ecZ) + canvas = m_dcGraphics; + else + canvas = g; + if (m_oI != 0) { + if (m_oI == 1) { + // Draw codebrew + paint.setColor(0xFFFFFFFF); + canvas.drawRect(0, 0, getScaledWidth(), getScaledHeight(), paint); + if (Bitmap.get(Bitmap.CODEBREW_LOGO) != null) { + drawBitmap(Bitmap.get(Bitmap.CODEBREW_LOGO), + getScaledWidth() / 2 - Bitmap.get(Bitmap.CODEBREW_LOGO).getWidthDp() / 2, + (float) (getScaledHeight() / 2 - Bitmap.get(Bitmap.CODEBREW_LOGO).getHeightDp() / 1.6)); + } + } else { + // Draw gd + paint.setColor(0xFFFFFFFF); + canvas.drawRect(0, 0, getScaledWidth(), getScaledHeight(), paint); + if (Bitmap.get(Bitmap.GD_LOGO) != null) { + drawBitmap(Bitmap.get(Bitmap.GD_LOGO), + getScaledWidth() / 2 - Bitmap.get(Bitmap.GD_LOGO).getWidthDp() / 2, + (float) (getScaledHeight() / 2 - Bitmap.get(Bitmap.GD_LOGO).getHeightDp() / 1.6)); + } + } + int j = (int) (((long) (gd.m_longI << 16) << 32) / 0xa0000L >> 16); + drawProgress(j, true); + } else { + if (m_lI != getHeight()) + _ifvV(); + physEngine._voidvV(); + _doIIV(-physEngine._elsevI() + m_TI + m_abI / 2, physEngine._ifvI() + m_QI + m_dI / 2); + physEngine._ifiV(this); + if (drawTimer) { + long time = 0, finished; + if (gd.startedTime > 0) { + if (gd.finishedTime > 0) + finished = gd.finishedTime; + else + finished = System.currentTimeMillis(); + time = (finished - gd.startedTime - gd.pausedTime) / 10; + } + drawTimer(time); + } + if (infoMessage != null) { + setColor(0, 0, 0); + infoFont.setColor(paint.getColor()); + /*if (m_dI <= 128) + canvas.drawText(infoMessage, m_abI / 2 - infoFont.measureText(infoMessage) / 2, 1, infoFont); + else*/ + + canvas.drawText(infoMessage, m_abI / 2 - infoFont.measureText(infoMessage) / 2, m_dI / 5, infoFont); + if (m_ahZ) { + m_ahZ = false; + infoMessage = null; + } + } + int j = physEngine._tryvI(); + drawProgress(j, false); + if (m_KZ && m_AZ) + _newvV(); + } + canvas = null; + if (m_ecZ) + g.drawBitmap(m_MBitmap, 0, 0, null); + } + + public void drawProgress(int j, boolean flag) { + double progr = j / (double) 0xFFFF; + + paint.setColor(0xffc4c4c4); + canvas.drawRect(0, 0, getScaledWidth(), 3, paint); + + paint.setColor(0xff29aa27); + canvas.drawRect(0, 0, Math.round(getScaledWidth() * Math.min(Math.max(progr, 0), 1)), 3, paint); + } + + private void _ifIIV(int j, int k) { + if (!getGDActivity().isMenuShown()) { + byte byte0 = 0; + byte byte1 = 0; + m_aiI = j; + m_agI = k; + int l = j << 16; + int i1 = k << 16; + int j1 = m_abI / 2 << 16; + int k1 = m_dI + 40 << 16; + if (m_KZ && m_AZ) { + int l1 = FPMath._ifIII(l - j1, i1 - k1); + for (l1 += 25735; l1 < 0; l1 += 0x6487e) ; + for (; l1 > 0x6487e; l1 -= 0x6487e) ; + m_OI = l1; + int i2; + if ((i2 = 51471) >= l1) + byte0 = -1; + else if (l1 < (int) ((long) i2 * 0x20000L >> 16)) { + byte0 = -1; + byte1 = 1; + } else if (l1 < (int) ((long) i2 * 0x30000L >> 16)) + byte1 = 1; + else if (l1 < (int) ((long) i2 * 0x40000L >> 16)) { + byte0 = 1; + byte1 = 1; + } else if (l1 < (int) ((long) i2 * 0x50000L >> 16)) + byte0 = 1; + else if (l1 < (int) ((long) i2 * 0x60000L >> 16)) { + byte0 = 1; + byte1 = -1; + } else if (l1 < (int) ((long) i2 * 0x70000L >> 16)) + byte1 = -1; + else if (l1 < (int) ((long) i2 * 0x80000L >> 16)) { + byte0 = -1; + byte1 = -1; + } + physEngine._aIIV(byte0, byte1); + } + } + } + + public void _pointerPressedIIV(int j, int k) { + if (!getGDActivity().isMenuShown()) + _ifIIV(j, k); + } + + public void _pointerReleasedIIV(int j, int k) { + if (!getGDActivity().isMenuShown()) { + m_aiI = 0; + m_agI = 0; + physEngine._nullvV(); + } + } + + public void _pointerDraggedIIV(int j, int k) { + if (!getGDActivity().isMenuShown()) + _ifIIV(j, k); + } + + public void setInputOption(int option) { + inputOption = option; + } + + private void _avV() { + for (int j = 0; j < 10; j++) + m_LaZ[j] = false; + + for (int k = 0; k < 7; k++) + m_aeaZ[k] = false; + + } + + private void _xavV() { + int j = 0; + int k = 0; + int l = inputOption; + for (int i1 = 0; i1 < 10; i1++) + if (m_LaZ[i1]) { + j += m_maaaB[l][i1][0]; + k += m_maaaB[l][i1][1]; + } + + for (int j1 = 0; j1 < 7; j1++) + if (m_aeaZ[j1]) { + j += m_DaaB[j1][0]; + k += m_DaaB[j1][1]; + } + + physEngine._aIIV(j, k); + } + + protected void processKeyPressed(int j) { + int k = getGameAction(j); + int l; + if ((l = j - 48) >= 0 && l < 10) + m_LaZ[l] = true; + else if (k >= 0 && k < 7) + m_aeaZ[k] = true; + _xavV(); + } + + protected void processKeyReleased(int j) { + int k = getGameAction(j); + int l; + if ((l = j - 48) >= 0 && l < 10) + m_LaZ[l] = false; + else if (k >= 0 && k < 7) + m_aeaZ[k] = false; + _xavV(); + } + + public void showMenu() { + if (menu != null) { + menu.m_blZ = true; + getGDActivity().gameToMenu(); + } + } + + /* protected void hideNotify() { + if (!getGDActivity().isMenuShown()) { + GDActivity.m_cZ = true; + activity.gameToMenu(); + } + } */ + + /* protected void showNotify() { + GDActivity.m_cZ = false; + } */ + + protected void keyRepeated(int j) { + if (getGDActivity().isMenuShown() && menu != null) + menu._tryIV(j); + } + + public synchronized void keyPressed(int j) { + if (getGDActivity().isMenuShown() && menu != null) + menu.keyPressed(j); + processKeyPressed(j); + } + + public synchronized void keyReleased(int j) { + processKeyReleased(j); + } + + @Override + public void onDraw(Canvas g) { + g.save(); + if (!Global.DISABLE_SCALING) + g.scale(Global.density, Global.density); + if (getGDActivity().isMenuShown() && menu != null) { + menu.draw(g); + } else { + drawGame(g); + } + g.restore(); + invalidate(); + } + + public void commandAction(Command command) { + if (getGDActivity().isMenuShown() && menu != null) { + menu.onCommand(command); + } else { + showMenu(); + } + } + + public void removeMenuCommand() { + removeCommand(menuCommand); + } + + public void addMenuCommand() { + addCommand(menuCommand); + } + + public static int getGameAction(int key) { + // logDebug("getGameAction: key = " + key); + switch (key) { + case 50: // 2 + return MenuScreen.KEY_UP; // up + case 56: // 8 + return MenuScreen.KEY_DOWN; // down + case 52: // 4 + return MenuScreen.KEY_LEFT; // left + case 54: // 6 + return MenuScreen.KEY_RIGHT; // right + case 53: // 5 + return MenuScreen.KEY_FIRE; // fire + } + return 0; + } + + public void addCommand(Command cmd) { + GDActivity.shared.addCommand(cmd); + } + + public void removeCommand(Command cmd) { + GDActivity.shared.removeCommand(cmd); + } + + public int getScaledWidth() { + float density = Global.DISABLE_SCALING ? 1 : Global.density; + return Math.round(getWidth() / density); + } + + public int getScaledHeight() { + float density = Global.DISABLE_SCALING ? 1 : Global.density; + return Math.round(getHeight() / density); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = MeasureSpec.getSize(widthMeasureSpec), height = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(width, height); + } + + public synchronized void destroy() { + if (timer != null) { + timer.cancel(); + timer.purge(); + timer = null; + } + } + +} diff --git a/src/org/happysanta/gd/Game/Physics.java b/src/org/happysanta/gd/Game/Physics.java new file mode 100755 index 0000000..d6e25b3 --- /dev/null +++ b/src/org/happysanta/gd/Game/Physics.java @@ -0,0 +1,1336 @@ +package org.happysanta.gd.Game; + +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + + +import org.happysanta.gd.Levels.Loader; +import org.happysanta.gd.Menu.SimpleMenuElement; + +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getLevelLoader; + +public class Physics { + + /*public static final int m_agI = 1; + //public static final int m_byteI; + public static final int m_ahI = 1; + public static final int m_LI = 2; + public static final int m_uI = 3; + //public static final int m_aI; + public static final int m_VI = 1; + public static final int m_BI = 2; + public static final int m_acI = 3; + public static final int m_newI = 4; + public static final int m_ZI = 5 */ + public static int m_YI; + public static int m_voidI; + public static int m_gI; + public static int m_fI; + public static int m_eI; + public static int m_aeI; + public static int m_adI; + public static int m_yI; + public static int m_qI; + public static int m_xI; + public static int m_foraI[] = { + 0x1c000, 0x10000, 32768 + }; + public static int m_PI; + public static int m_jI; + public static int m_QI; + public static int m_charI; + public static int m_abI; + public static int m_WI; + public static int m_AI; + public static int m_longI; + public static int m_hI = 0; + // private final int m_pI = 3276; + private final int m_KaaI[][] = { + { + 0x2cccc, -52428 + }, { + 0x40000, 0xfffd8000 + }, { + 0x63333, 0xffff0000 + }, { + 0x6cccc, -39321 + }, { + 0x39999, 39321 + }, { + 16384, 0xfffdcccd + }, { + 13107, 0xfffecccd + }, { + 0x46666, 0x14000 + } + }; + private final int m_ucaaI[][] = { + { + 0x2e666, 0xfffe4ccd + }, { + 0x4b333, 0xfffc6667 + }, { + 0x51999, 0xfffe4000 + }, { + 0x60000, -58982 + }, { + 0x40000, 0x18000 + }, { + 0x10000, 0xfffe199a + }, { + 13107, 0xfffecccd + }, { + 0x46666, 0x14000 + } + }; + private final int m_SaaI[][] = { + { + 0x26666, 13107 + }, { + 0x48000, -13107 + }, { + 0x59999, 0x16666 + }, { + 0x63333, 0x2e666 + }, { + 0x54ccc, 0x11999 + }, { + 39321, 0xfffe8000 + }, { + 13107, -52428 + }, { + 0x48000, 0x14000 + } + }; + private final int m_wcaaI[][] = { + { + 0x2cccc, -39321 + }, { + 0x40000, 0xfffe0000 + }, { + 0x60000, 0xffff0000 + }, { + 0x70000, -39321 + }, { + 0x48000, 6553 + }, { + 16384, 0xfffdcccd + }, { + 13107, 0xfffecccd + }, { + 0x46666, 0x14ccc + } + }; + private final int m_DaaI[][] = { + { + 0x2e666, 0xfffe999a + }, { + 0x3e666, 0xfffc6667 + }, { + 0x51999, 0xfffe4000 + }, { + 0x60000, -42598 + }, { + 0x49999, 6553 + }, { + 0x10000, 0xfffecccd + }, { + 13107, 0xfffecccd + }, { + 0x46666, 0x14ccc + } + }; + private final int m_MaaI[][] = { + { + 0x26666, 13107 + }, { + 0x48000, -13107 + }, { + 0x59999, 0x19999 + }, { + 0x63333, 0x2b333 + }, { + 0x54ccc, 0x11999 + }, { + 39321, 0xfffe8000 + }, { + 13107, -52428 + }, { + 0x46666, 0x14ccc + } + }; + public k m_Hak[]; + public boolean m_bZ; + public int m_zI; + public boolean m_elseZ; + public boolean m_UZ; + public boolean m_NZ; + SimpleMenuElement m_aaan[]; + private int m_vaI; + private int m_waI; + private int m_xaI; + private SimpleMenuElement m_ian[]; + private int m_cI; + private Loader m_lf; + private int m_EI; + private int m_CI; + private boolean m_IZ; + private boolean m_mZ; + private int m_TI; + private int m_kI; + private boolean m_vZ; + private boolean m_afZ; + private int m_tI; + private boolean m_dZ; + private boolean m_FZ; + private boolean m_XZ; + private boolean m_wZ; + private boolean m_ifZ; + private boolean m_sZ; + private boolean m_OZ; + private boolean m_rZ; + private boolean m_RZ; + private boolean m_doZ; + private int m_oI; + private int m_nI; + private int m_GI; + private int m_JaaI[][] = { + { + 45875 + }, { + 32768 + }, { + 52428 + } + }; + private final int leftWheelUpdatingFrequency = 20; + private long leftWheelLastUpdated = 0; + private int leftWheelParams[][]; + + public Physics(Loader f1) { + m_vaI = 0; + m_waI = 1; + m_xaI = -1; + m_cI = 0; + m_EI = 0; + m_CI = 0; + m_IZ = false; + m_mZ = false; + m_TI = 32768; + m_kI = 0; + m_vZ = false; + m_bZ = false; + m_afZ = false; + m_aaan = new SimpleMenuElement[6]; + for (int j = 0; j < 6; j++) + m_aaan[j] = new SimpleMenuElement(); + + m_tI = 0; + m_zI = 0; + m_elseZ = false; + m_UZ = false; + m_dZ = false; + m_FZ = false; + m_XZ = false; + m_wZ = false; + m_ifZ = false; + m_sZ = false; + m_OZ = false; + m_rZ = false; + m_RZ = false; + m_NZ = false; + m_doZ = true; + m_oI = 0; + m_nI = 0; + m_GI = 0xa0000; + m_lf = f1; + _doZV(true); + m_vZ = false; + _charvV(); + m_IZ = false; + + leftWheelParams = new int[5][4]; + } + + public static int _doIII(int j, int i1) { + int j1 = j >= 0 ? j : -j; + int k1; + int l1; + int i2; + if ((k1 = i1 >= 0 ? i1 : -i1) >= j1) { + l1 = k1; + i2 = j1; + } else { + l1 = j1; + i2 = k1; + } + return (int) (64448L * (long) l1 >> 16) + (int) (28224L * (long) i2 >> 16); + } + + public int _bytevI() { + if (m_elseZ && m_UZ) + return 3; + if (m_UZ) + return 1; + return !m_elseZ ? 0 : 2; + } + + public void _doIV(int j) { + m_elseZ = false; + m_UZ = false; + if ((j & 2) != 0) + m_elseZ = true; + if ((j & 1) != 0) + m_UZ = true; + } + + public void _byteIV(int j) { + m_zI = j; + switch (j) { + case 1: // '\001' + default: + m_YI = 1310; + break; + } + m_voidI = 0x190000; + setLeague(1); + _doZV(true); + } + + public void setLeague(int j) { + m_hI = j; + m_gI = 45875; + m_fI = 13107; + m_eI = 39321; + m_yI = 0x140000; + m_xI = 0x40000; + m_jI = 6553; + switch (j) { + case 3: // '\003' + m_aeI = 32768; + m_adI = 32768; + m_PI = 0x160000; + m_QI = 0x4b00000; + m_charI = 0x360000; + m_abI = 6553; + m_WI = 26214; + m_AI = 0x10000; + m_longI = 0x140000; + m_qI = 0x14a0000; + break; + + case 2: // '\002' + m_aeI = 32768; + m_adI = 32768; + m_PI = 0x140000; + m_QI = 0x47e0000; + m_charI = 0x350000; + m_abI = 6553; + m_WI = 26214; + m_AI = 39321; + m_longI = 0x50000; + m_qI = 0x14a0000; + break; + + case 1: // '\001' + m_aeI = 32768; + m_adI = 32768; + m_PI = 0x110000; + m_QI = 0x3e80000; + m_charI = 0x320000; + m_abI = 6553; + m_WI = 26214; + m_AI = 26214; + m_longI = 0x50000; + m_qI = 0x12c0000; + break; + + case 0: // '\0' + default: + m_aeI = 19660; + m_adI = 19660; + m_PI = 0x110000; + m_QI = 0x3200000; + m_charI = 0x320000; + m_abI = 327; + m_WI = 0; + m_AI = 32768; + m_longI = 0x50000; + m_qI = 0x12c0000; + break; + } + _doZV(true); + } + + public void _doZV(boolean flag) { + m_tI = 0; + _iIIV(m_lf._newvI(), m_lf._avI()); + m_cI = 0; + m_kI = 0; + m_IZ = false; + m_mZ = false; + m_RZ = false; + m_NZ = false; + m_vZ = false; + m_bZ = false; + m_afZ = false; + m_lf.levels._aIIV((m_Hak[2].m_ifan[5].x + 0x18000) - m_foraI[0], (m_Hak[1].m_ifan[5].x - 0x18000) + m_foraI[0]); + } + + public void _aZV(boolean flag) { + int j = (flag ? 0x10000 : 0xffff0000) << 1; + for (int i1 = 0; i1 < 6; i1++) { + for (int j1 = 0; j1 < 6; j1++) + m_Hak[i1].m_ifan[j1].y += j; + } + + } + + private void _iIIV(int j, int i1) { + if (m_Hak == null) + m_Hak = new k[6]; + if (m_ian == null) + m_ian = new SimpleMenuElement[10]; + int l1 = 0; + int i2 = 0; + int j2 = 0; + int k2 = 0; + for (int j1 = 0; j1 < 6; j1++) { + int l2 = 0; + switch (j1) { + case 0: // '\0' + i2 = 1; + l1 = 0x58000; + j2 = 0; + k2 = 0; + break; + + case 4: // '\004' + i2 = 1; + l1 = 0x38000; + j2 = 0xfffe0000; + k2 = 0x30000; + break; + + case 3: // '\003' + i2 = 1; + l1 = 0x38000; + j2 = 0x20000; + k2 = 0x30000; + break; + + case 1: // '\001' + i2 = 0; + l1 = 0x18000; + j2 = 0x38000; + k2 = 0; + break; + + case 2: // '\002' + i2 = 0; + l1 = 0x58000; + j2 = 0xfffc8000; + k2 = 0; + l2 = 21626; + break; + + case 5: // '\005' + i2 = 2; + l1 = 0x48000; + j2 = 0; + k2 = 0x50000; + break; + } + if (m_Hak[j1] == null) + m_Hak[j1] = new k(); + m_Hak[j1]._avV(); + m_Hak[j1].m_aI = m_foraI[i2]; + m_Hak[j1].m_intI = i2; + m_Hak[j1].m_forI = (int) ((long) (int) (0x1000000000000L / (long) l1 >> 16) * (long) m_yI >> 16); + m_Hak[j1].m_ifan[m_vaI].x = j + j2; + m_Hak[j1].m_ifan[m_vaI].y = i1 + k2; + m_Hak[j1].m_ifan[5].x = j + j2; + m_Hak[j1].m_ifan[5].y = i1 + k2; + m_Hak[j1].m_newI = l2; + } + + for (int k1 = 0; k1 < 10; k1++) { + if (m_ian[k1] == null) + m_ian[k1] = new SimpleMenuElement(); + m_ian[k1].init(); + m_ian[k1].x = m_qI; + m_ian[k1].m_bI = m_xI; + } + + m_ian[0].y = 0x38000; + m_ian[1].y = 0x38000; + m_ian[2].y = 0x39b05; + m_ian[3].y = 0x39b05; + m_ian[4].y = 0x40000; + m_ian[5].y = 0x35aa6; + m_ian[6].y = 0x35aa6; + m_ian[7].y = 0x2d413; + m_ian[8].y = 0x2d413; + m_ian[9].y = 0x50000; + m_ian[5].m_bI = (int) ((long) m_xI * 45875L >> 16); + m_ian[6].x = (int) (6553L * (long) m_qI >> 16); + m_ian[5].x = (int) (6553L * (long) m_qI >> 16); + m_ian[9].x = (int) (0x11999L * (long) m_qI >> 16); + m_ian[8].x = (int) (0x11999L * (long) m_qI >> 16); + m_ian[7].x = (int) (0x11999L * (long) m_qI >> 16); + } + + public void _ifIIV(int j, int i1) { + m_lf._ifIIV(j, i1); + } + + public void _nullvV() { + m_ifZ = m_sZ = m_rZ = m_OZ = false; + } + + public void _aIIV(int j, int i1) { + if (!m_vZ) { + m_ifZ = m_sZ = m_rZ = m_OZ = false; + if (j > 0) + m_ifZ = true; + else if (j < 0) + m_sZ = true; + if (i1 > 0) { + m_rZ = true; + return; + } + if (i1 < 0) + m_OZ = true; + } + } + + public synchronized void _casevV() { + _doZV(true); + m_vZ = true; + } + + public synchronized void _avV() { + m_vZ = false; + } + + public boolean _gotovZ() { + return m_vZ; + } + + private void _pvV() { + int j = m_Hak[1].m_ifan[m_vaI].x - m_Hak[2].m_ifan[m_vaI].x; + int i1 = m_Hak[1].m_ifan[m_vaI].y - m_Hak[2].m_ifan[m_vaI].y; + int j1 = _doIII(j, i1); + int _tmp = (int) (((long) j << 32) / (long) j1 >> 16); + i1 = (int) (((long) i1 << 32) / (long) j1 >> 16); + m_FZ = false; + if (i1 < 0) { + m_XZ = true; + m_wZ = false; + } else if (i1 > 0) { + m_wZ = true; + m_XZ = false; + } + boolean flag; + if ((flag = (m_Hak[2].m_ifan[m_vaI].y - m_Hak[0].m_ifan[m_vaI].y <= 0 ? -1 : 1) * (m_Hak[2].m_ifan[m_vaI].m_eI - m_Hak[0].m_ifan[m_vaI].m_eI <= 0 ? -1 : 1) > 0) && m_wZ || !flag && m_XZ) { + m_dZ = true; + return; + } else { + m_dZ = false; + return; + } + } + + private void _qvV() { + if (!m_IZ) { + int j = m_Hak[1].m_ifan[m_vaI].x - m_Hak[2].m_ifan[m_vaI].x; + int i1 = m_Hak[1].m_ifan[m_vaI].y - m_Hak[2].m_ifan[m_vaI].y; + int j1 = _doIII(j, i1); + j = (int) (((long) j << 32) / (long) j1 >> 16); + i1 = (int) (((long) i1 << 32) / (long) j1 >> 16); + if (m_dZ && m_cI >= -m_QI) + m_cI -= m_charI; + if (m_FZ) { + m_cI = 0; + m_Hak[1].m_ifan[m_vaI].m_gotoI = (int) ((long) m_Hak[1].m_ifan[m_vaI].m_gotoI * (long) (0x10000 - m_abI) >> 16); + m_Hak[2].m_ifan[m_vaI].m_gotoI = (int) ((long) m_Hak[2].m_ifan[m_vaI].m_gotoI * (long) (0x10000 - m_abI) >> 16); + if (m_Hak[1].m_ifan[m_vaI].m_gotoI < 6553) + m_Hak[1].m_ifan[m_vaI].m_gotoI = 0; + if (m_Hak[2].m_ifan[m_vaI].m_gotoI < 6553) + m_Hak[2].m_ifan[m_vaI].m_gotoI = 0; + } + m_Hak[0].m_forI = (int) (11915L * (long) m_yI >> 16); + m_Hak[0].m_forI = (int) (11915L * (long) m_yI >> 16); + m_Hak[4].m_forI = (int) (18724L * (long) m_yI >> 16); + m_Hak[3].m_forI = (int) (18724L * (long) m_yI >> 16); + m_Hak[1].m_forI = (int) (43690L * (long) m_yI >> 16); + m_Hak[2].m_forI = (int) (11915L * (long) m_yI >> 16); + m_Hak[5].m_forI = (int) (14563L * (long) m_yI >> 16); + if (m_XZ) { + m_Hak[0].m_forI = (int) (18724L * (long) m_yI >> 16); + m_Hak[4].m_forI = (int) (14563L * (long) m_yI >> 16); + m_Hak[3].m_forI = (int) (18724L * (long) m_yI >> 16); + m_Hak[1].m_forI = (int) (43690L * (long) m_yI >> 16); + m_Hak[2].m_forI = (int) (10082L * (long) m_yI >> 16); + } else if (m_wZ) { + m_Hak[0].m_forI = (int) (18724L * (long) m_yI >> 16); + m_Hak[4].m_forI = (int) (18724L * (long) m_yI >> 16); + m_Hak[3].m_forI = (int) (14563L * (long) m_yI >> 16); + m_Hak[1].m_forI = (int) (26214L * (long) m_yI >> 16); + m_Hak[2].m_forI = (int) (11915L * (long) m_yI >> 16); + } + if (m_XZ || m_wZ) { + int k1 = -i1; + int l1 = j; + if (m_XZ && m_kI > -m_longI) { + int i2 = 0x10000; + if (m_kI < 0) + i2 = (int) (((long) (m_longI - (m_kI >= 0 ? m_kI : -m_kI)) << 32) / (long) m_longI >> 16); + int k2 = (int) ((long) m_AI * (long) i2 >> 16); + int i3 = (int) ((long) k1 * (long) k2 >> 16); + int k3 = (int) ((long) l1 * (long) k2 >> 16); + int i4 = (int) ((long) j * (long) k2 >> 16); + int k4 = (int) ((long) i1 * (long) k2 >> 16); + if (m_TI > 32768) + m_TI = m_TI - 1638 >= 0 ? m_TI - 1638 : 0; + else + m_TI = m_TI - 3276 >= 0 ? m_TI - 3276 : 0; + m_Hak[4].m_ifan[m_vaI].m_eI -= i3; + m_Hak[4].m_ifan[m_vaI].m_dI -= k3; + m_Hak[3].m_ifan[m_vaI].m_eI += i3; + m_Hak[3].m_ifan[m_vaI].m_dI += k3; + m_Hak[5].m_ifan[m_vaI].m_eI -= i4; + m_Hak[5].m_ifan[m_vaI].m_dI -= k4; + } + if (m_wZ && m_kI < m_longI) { + int j2 = 0x10000; + if (m_kI > 0) + j2 = (int) (((long) (m_longI - m_kI) << 32) / (long) m_longI >> 16); + int l2 = (int) ((long) m_AI * (long) j2 >> 16); + int j3 = (int) ((long) k1 * (long) l2 >> 16); + int l3 = (int) ((long) l1 * (long) l2 >> 16); + int j4 = (int) ((long) j * (long) l2 >> 16); + int l4 = (int) ((long) i1 * (long) l2 >> 16); + if (m_TI > 32768) + m_TI = m_TI + 1638 >= 0x10000 ? 0x10000 : m_TI + 1638; + else + m_TI = m_TI + 3276 >= 0x10000 ? 0x10000 : m_TI + 3276; + m_Hak[4].m_ifan[m_vaI].m_eI += j3; + m_Hak[4].m_ifan[m_vaI].m_dI += l3; + m_Hak[3].m_ifan[m_vaI].m_eI -= j3; + m_Hak[3].m_ifan[m_vaI].m_dI -= l3; + m_Hak[5].m_ifan[m_vaI].m_eI += j4; + m_Hak[5].m_ifan[m_vaI].m_dI += l4; + } + return; + } + if (m_TI < 26214) { + m_TI += 3276; + return; + } + if (m_TI > 39321) { + m_TI -= 3276; + return; + } + m_TI = 32768; + } + } + + public synchronized int _dovI() { + m_dZ = m_ifZ; + m_FZ = m_sZ; + m_XZ = m_OZ; + m_wZ = m_rZ; + if (m_vZ) + _pvV(); + GameView._dovV(); + _qvV(); + int j; + if ((j = _uII(m_YI)) == 5 || m_mZ) + return 5; + if (m_IZ) + return 3; + if (_newvZ()) { + m_NZ = false; + return 4; + } else { + return j; + } + } + + public boolean _newvZ() { + return m_Hak[1].m_ifan[m_vaI].x < m_lf._intvI(); + } + + public boolean _longvZ() { + return m_Hak[1].m_ifan[m_waI].x > m_lf._dovI() || m_Hak[2].m_ifan[m_waI].x > m_lf._dovI(); + } + + private int _uII(int j) { + boolean flag = m_RZ; + int i1 = 0; + int j1 = j; + int j2; + do { + if (i1 >= j) + break; + _aaIV(j1 - i1); + int k1; + if (!flag && _longvZ()) + k1 = 3; + else + k1 = _baII(m_waI); + if (!flag && m_RZ) + return k1 == 3 ? 1 : 2; + if (k1 == 0) { + if (((j1 = i1 + j1 >> 1) - i1 >= 0 ? j1 - i1 : -(j1 - i1)) < 65) + return 5; + } else if (k1 == 3) { + m_RZ = true; + j1 = i1 + j1 >> 1; + } else { + int i2; + if (k1 == 1) + do { + _caIV(m_waI); + j2 = _baII(m_waI); + i2 = j2; + if (j2 == 0) + return 5; + } while (i2 != 2); + i1 = j1; + j1 = j; + m_vaI = m_vaI != 1 ? 1 : 0; + m_waI = m_waI != 1 ? 1 : 0; + } + } while (true); + int l1; + if ((l1 = (int) ((long) (m_Hak[1].m_ifan[m_vaI].x - m_Hak[2].m_ifan[m_vaI].x) * (long) (m_Hak[1].m_ifan[m_vaI].x - m_Hak[2].m_ifan[m_vaI].x) >> 16) + (int) ((long) (m_Hak[1].m_ifan[m_vaI].y - m_Hak[2].m_ifan[m_vaI].y) * (long) (m_Hak[1].m_ifan[m_vaI].y - m_Hak[2].m_ifan[m_vaI].y) >> 16)) < 0xf0000) + m_IZ = true; + if (l1 > 0x460000) + m_IZ = true; + return 0; + } + + private void _aIV(int j) { + for (int i1 = 0; i1 < 6; i1++) { + k k1; + SimpleMenuElement n1; + (n1 = (k1 = m_Hak[i1]).m_ifan[j]).m_nullI = 0; + n1.m_longI = 0; + n1.m_fI = 0; + n1.m_longI -= (int) (((long) m_voidI << 32) / (long) k1.m_forI >> 16); + } + + if (!m_IZ) { + _akkV(m_Hak[0], m_ian[1], m_Hak[2], j, 0x10000); + _akkV(m_Hak[0], m_ian[0], m_Hak[1], j, 0x10000); + _akkV(m_Hak[2], m_ian[6], m_Hak[4], j, 0x20000); + _akkV(m_Hak[1], m_ian[5], m_Hak[3], j, 0x20000); + } + _akkV(m_Hak[0], m_ian[2], m_Hak[3], j, 0x10000); + _akkV(m_Hak[0], m_ian[3], m_Hak[4], j, 0x10000); + _akkV(m_Hak[3], m_ian[4], m_Hak[4], j, 0x10000); + _akkV(m_Hak[5], m_ian[8], m_Hak[3], j, 0x10000); + _akkV(m_Hak[5], m_ian[7], m_Hak[4], j, 0x10000); + _akkV(m_Hak[5], m_ian[9], m_Hak[0], j, 0x10000); + SimpleMenuElement n2 = m_Hak[2].m_ifan[j]; + m_cI = (int) ((long) m_cI * (long) (0x10000 - m_jI) >> 16); + n2.m_fI = m_cI; + if (n2.m_gotoI > m_PI) + n2.m_gotoI = m_PI; + if (n2.m_gotoI < -m_PI) + n2.m_gotoI = -m_PI; + int j1 = 0; + int l1 = 0; + for (int i2 = 0; i2 < 6; i2++) { + j1 += m_Hak[i2].m_ifan[j].m_eI; + l1 += m_Hak[i2].m_ifan[j].m_dI; + } + + j1 = (int) (((long) j1 << 32) / 0x60000L >> 16); + l1 = (int) (((long) l1 << 32) / 0x60000L >> 16); + int j3 = 0; + for (int k3 = 0; k3 < 6; k3++) { + int j2 = m_Hak[k3].m_ifan[j].m_eI - j1; + int k2 = m_Hak[k3].m_ifan[j].m_dI - l1; + if ((j3 = _doIII(j2, k2)) > 0x1e0000) { + int l2 = (int) (((long) j2 << 32) / (long) j3 >> 16); + int i3 = (int) (((long) k2 << 32) / (long) j3 >> 16); + m_Hak[k3].m_ifan[j].m_eI -= l2; + m_Hak[k3].m_ifan[j].m_dI -= i3; + } + } + + byte byte0 = ((byte) (m_Hak[2].m_ifan[j].y - m_Hak[0].m_ifan[j].y < 0 ? -1 : 1)); + byte byte1 = ((byte) (m_Hak[2].m_ifan[j].m_eI - m_Hak[0].m_ifan[j].m_eI < 0 ? -1 : 1)); + if (byte0 * byte1 > 0) { + m_kI = j3; + return; + } else { + m_kI = -j3; + return; + } + } + + private void _akkV(k k1, SimpleMenuElement n1, k k2, int j, int i1) { + SimpleMenuElement n2 = k1.m_ifan[j]; + SimpleMenuElement n3 = k2.m_ifan[j]; + int j1 = n2.x - n3.x; + int l1 = n2.y - n3.y; + int i2; + if (((i2 = _doIII(j1, l1)) >= 0 ? i2 : -i2) >= 3) { + j1 = (int) (((long) j1 << 32) / (long) i2 >> 16); + l1 = (int) (((long) l1 << 32) / (long) i2 >> 16); + int j2 = i2 - n1.y; + int l2 = (int) ((long) j1 * (long) (int) ((long) j2 * (long) n1.x >> 16) >> 16); + int i3 = (int) ((long) l1 * (long) (int) ((long) j2 * (long) n1.x >> 16) >> 16); + int j3 = n2.m_eI - n3.m_eI; + int k3 = n2.m_dI - n3.m_dI; + int l3 = (int) ((long) ((int) ((long) j1 * (long) j3 >> 16) + (int) ((long) l1 * (long) k3 >> 16)) * (long) n1.m_bI >> 16); + l2 += (int) ((long) j1 * (long) l3 >> 16); + i3 += (int) ((long) l1 * (long) l3 >> 16); + l2 = (int) ((long) l2 * (long) i1 >> 16); + i3 = (int) ((long) i3 * (long) i1 >> 16); + n2.m_nullI -= l2; + n2.m_longI -= i3; + n3.m_nullI += l2; + n3.m_longI += i3; + } + } + + private void _aIIV(int j, int i1, int j1) { + for (int l1 = 0; l1 < 6; l1++) { + SimpleMenuElement n1 = m_Hak[l1].m_ifan[j]; + SimpleMenuElement n2; + (n2 = m_Hak[l1].m_ifan[i1]).x = (int) ((long) n1.m_eI * (long) j1 >> 16); + n2.y = (int) ((long) n1.m_dI * (long) j1 >> 16); + int k1 = (int) ((long) j1 * (long) m_Hak[l1].m_forI >> 16); + n2.m_eI = (int) ((long) n1.m_nullI * (long) k1 >> 16); + n2.m_dI = (int) ((long) n1.m_longI * (long) k1 >> 16); + } + + } + + private void _zIIV(int j, int i1, int j1) { + for (int k1 = 0; k1 < 6; k1++) { + SimpleMenuElement n1 = m_Hak[k1].m_ifan[j]; + SimpleMenuElement n2 = m_Hak[k1].m_ifan[i1]; + SimpleMenuElement n3 = m_Hak[k1].m_ifan[j1]; + n1.x = n2.x + (n3.x >> 1); + n1.y = n2.y + (n3.y >> 1); + n1.m_eI = n2.m_eI + (n3.m_eI >> 1); + n1.m_dI = n2.m_dI + (n3.m_dI >> 1); + } + + } + + private void _aaIV(int j) { + _aIV(m_vaI); + _aIIV(m_vaI, 2, j); + _zIIV(4, m_vaI, 2); + _aIV(4); + _aIIV(4, 3, j >> 1); + _zIIV(4, m_vaI, 3); + _zIIV(m_waI, m_vaI, 2); + _zIIV(m_waI, m_waI, 3); + + // wheels?!?!?!?! oh my god i found it!!!!! + for (int i1 = 1; i1 <= 2; i1++) { + SimpleMenuElement n1 = m_Hak[i1].m_ifan[m_vaI]; + SimpleMenuElement n2; + (n2 = m_Hak[i1].m_ifan[m_waI]).m_bI = n1.m_bI + (int) ((long) j * (long) n1.m_gotoI >> 16); + n2.m_gotoI = n1.m_gotoI + (int) ((long) j * (long) (int) ((long) m_Hak[i1].m_newI * (long) n1.m_fI >> 16) >> 16); + } + + } + + private int _baII(int j) { + byte byte0 = 2; + int i1; + i1 = (i1 = m_Hak[1].m_ifan[j].x >= m_Hak[2].m_ifan[j].x ? m_Hak[1].m_ifan[j].x : m_Hak[2].m_ifan[j].x) >= m_Hak[5].m_ifan[j].x ? i1 : m_Hak[5].m_ifan[j].x; + int j1; + j1 = (j1 = m_Hak[1].m_ifan[j].x >= m_Hak[2].m_ifan[j].x ? m_Hak[2].m_ifan[j].x : m_Hak[1].m_ifan[j].x) >= m_Hak[5].m_ifan[j].x ? m_Hak[5].m_ifan[j].x : j1; + m_lf._aIIV(j1 - m_foraI[0], i1 + m_foraI[0], m_Hak[5].m_ifan[j].y); + int k1 = m_Hak[1].m_ifan[j].x - m_Hak[2].m_ifan[j].x; + int l1 = m_Hak[1].m_ifan[j].y - m_Hak[2].m_ifan[j].y; + int i2 = _doIII(k1, l1); + k1 = (int) (((long) k1 << 32) / (long) i2 >> 16); + int j2 = -(int) (((long) l1 << 32) / (long) i2 >> 16); + int k2 = k1; + for (int l2 = 0; l2 < 6; l2++) { + if (l2 == 4 || l2 == 3) + continue; + SimpleMenuElement n1 = m_Hak[l2].m_ifan[j]; + if (l2 == 0) { + n1.x += (int) ((long) j2 * 0x10000L >> 16); + n1.y += (int) ((long) k2 * 0x10000L >> 16); + } + int i3 = m_lf._anvI(n1, m_Hak[l2].m_intI); + if (l2 == 0) { + n1.x -= (int) ((long) j2 * 0x10000L >> 16); + n1.y -= (int) ((long) k2 * 0x10000L >> 16); + } + m_EI = m_lf.m_eI; + m_CI = m_lf.m_dI; + if (l2 == 5 && i3 != 2) + m_mZ = true; + if (l2 == 1 && i3 != 2) + m_NZ = true; + if (i3 == 1) { + m_xaI = l2; + byte0 = 1; + continue; + } + if (i3 != 0) + continue; + m_xaI = l2; + byte0 = 0; + break; + } + + return byte0; + } + + private void _caIV(int j) { + k k1; + SimpleMenuElement n1; + (n1 = (k1 = m_Hak[m_xaI]).m_ifan[j]).x += (int) ((long) m_EI * 3276L >> 16); + n1.y += (int) ((long) m_CI * 3276L >> 16); + int i1; + int j1; + int l1; + int i2; + int j2; + if (m_FZ && (m_xaI == 2 || m_xaI == 1) && n1.m_gotoI < 6553) { + i1 = m_gI - m_WI; + j1 = 13107; + l1 = 39321; + i2 = 26214 - m_WI; + j2 = 26214 - m_WI; + } else { + i1 = m_gI; + j1 = m_fI; + l1 = m_eI; + i2 = m_aeI; + j2 = m_adI; + } + int k2 = _doIII(m_EI, m_CI); + m_EI = (int) (((long) m_EI << 32) / (long) k2 >> 16); + m_CI = (int) (((long) m_CI << 32) / (long) k2 >> 16); + int l2 = n1.m_eI; + int i3 = n1.m_dI; + int j3 = -((int) ((long) l2 * (long) m_EI >> 16) + (int) ((long) i3 * (long) m_CI >> 16)); + int k3 = -((int) ((long) l2 * (long) (-m_CI) >> 16) + (int) ((long) i3 * (long) m_EI >> 16)); + int l3 = (int) ((long) i1 * (long) n1.m_gotoI >> 16) - (int) ((long) j1 * (long) (int) (((long) k3 << 32) / (long) k1.m_aI >> 16) >> 16); + int i4 = (int) ((long) i2 * (long) k3 >> 16) - (int) ((long) l1 * (long) (int) ((long) n1.m_gotoI * (long) k1.m_aI >> 16) >> 16); + int j4 = -(int) ((long) j2 * (long) j3 >> 16); + int k4 = (int) ((long) (-i4) * (long) (-m_CI) >> 16); + int l4 = (int) ((long) (-i4) * (long) m_EI >> 16); + int i5 = (int) ((long) (-j4) * (long) m_EI >> 16); + int j5 = (int) ((long) (-j4) * (long) m_CI >> 16); + n1.m_gotoI = l3; + n1.m_eI = k4 + i5; + n1.m_dI = l4 + j5; + } + + public void _ifZV(boolean flag) { + m_doZ = flag; + } + + public void _caseIV(int j) { + m_GI = (int) (((long) (int) (0xa0000L * (long) (j << 16) >> 16) << 32) / 0x800000L >> 16); + } + + public int _elsevI() { + if (m_doZ) + m_oI = (int) (((long) m_aaan[0].m_eI << 32) / 0x180000L >> 16) + (int) ((long) m_oI * 57344L >> 16); + else + m_oI = 0; + m_oI = m_oI >= m_GI ? m_GI : m_oI; + m_oI = m_oI >= -m_GI ? m_oI : -m_GI; + return (m_aaan[0].x + m_oI << 2) >> 16; + } + + public int _ifvI() { + if (m_doZ) + m_nI = (int) (((long) m_aaan[0].m_dI << 32) / 0x180000L >> 16) + (int) ((long) m_nI * 57344L >> 16); + else + m_nI = 0; + m_nI = m_nI >= m_GI ? m_GI : m_nI; + m_nI = m_nI >= -m_GI ? m_nI : -m_GI; + return (m_aaan[0].y + m_nI << 2) >> 16; + } + + public int _tryvI() { + int j = m_aaan[1].x >= m_aaan[2].x ? m_aaan[1].x : m_aaan[2].x; + if (m_IZ) + return m_lf._aII(m_aaan[0].x); + else + return m_lf._aII(j); + } + + public void _charvV() { + synchronized (m_Hak) { + for (int j = 0; j < 6; j++) { + m_Hak[j].m_ifan[5].x = m_Hak[j].m_ifan[m_vaI].x; + m_Hak[j].m_ifan[5].y = m_Hak[j].m_ifan[m_vaI].y; + m_Hak[j].m_ifan[5].m_bI = m_Hak[j].m_ifan[m_vaI].m_bI; + } + + m_Hak[0].m_ifan[5].m_eI = m_Hak[0].m_ifan[m_vaI].m_eI; + m_Hak[0].m_ifan[5].m_dI = m_Hak[0].m_ifan[m_vaI].m_dI; + m_Hak[2].m_ifan[5].m_gotoI = m_Hak[2].m_ifan[m_vaI].m_gotoI; + } + } + + public void _voidvV() { + synchronized (m_Hak) { + for (int j = 0; j < 6; j++) { + m_aaan[j].x = m_Hak[j].m_ifan[5].x; + m_aaan[j].y = m_Hak[j].m_ifan[5].y; + m_aaan[j].m_bI = m_Hak[j].m_ifan[5].m_bI; + } + + m_aaan[0].m_eI = m_Hak[0].m_ifan[5].m_eI; + m_aaan[0].m_dI = m_Hak[0].m_ifan[5].m_dI; + m_aaan[2].m_gotoI = m_Hak[2].m_ifan[5].m_gotoI; + } + } + + private void _aiIV(GameView view, int i1, int j1) { + int k1 = FPMath._ifIII(m_aaan[0].x - m_aaan[3].x, m_aaan[0].y - m_aaan[3].y); + int l1 = FPMath._ifIII(m_aaan[0].x - m_aaan[4].x, m_aaan[0].y - m_aaan[4].y); + int engineX = (m_aaan[0].x >> 1) + (m_aaan[3].x >> 1); + int engineY = (m_aaan[0].y >> 1) + (m_aaan[3].y >> 1); + int fenderX = (m_aaan[0].x >> 1) + (m_aaan[4].x >> 1); + int fenderY = (m_aaan[0].y >> 1) + (m_aaan[4].y >> 1); + int i3 = -j1; + int j3 = i1; + engineX += (int) ((long) i3 * 0x10000L >> 16) - (int) ((long) i1 * 32768L >> 16); + engineY += (int) ((long) j3 * 0x10000L >> 16) - (int) ((long) j1 * 32768L >> 16); + fenderX += (int) ((long) i3 * 0x10000L >> 16) - (int) ((long) i1 * 0x1ccccL >> 16); + fenderY += (int) ((long) j3 * 0x10000L >> 16) - (int) ((long) j1 * 0x20000L >> 16); + view.drawFender((fenderX << 2) / (float) 0xFFFF /*>> 16*/, (fenderY << 2) / (float) 0xFFFF /*>> 16*/, l1); + view.drawEngine((engineX << 2) / (float) 0xFFFF /*>> 16*/, (engineY << 2) / (float) 0xFFFF /*>> 16*/, k1); + } + + private void _laiV(GameView view) { + view.setColor(128, 128, 128); + view.drawLine(m_aaan[3].x, m_aaan[3].y, m_aaan[1].x, m_aaan[1].y); + } + + private void _aiV(GameView gameView) { + int i1 = 1; + int j1 = 1; + switch (m_hI) { + case 2: // '\002' + case 3: // '\003' + i1 = j1 = 0; + break; + + case 1: // '\001' + i1 = 0; + break; + } + gameView.drawWheel((m_aaan[2].x << 2) / (float) 0xFFFF /*>> 16*/, (m_aaan[2].y << 2) / (float) 0xFFFF /*>> 16*/, i1); + gameView.drawWheel((m_aaan[1].x << 2) / (float) 0xFFFF /*>> 16*/, (m_aaan[1].y << 2) / (float) 0xFFFF /*>> 16*/, j1); + } + + private void _doiV(GameView gameView) { + int i1; + int j1 = (int) ((long) (i1 = m_Hak[1].m_aI) * 58982L >> 16); + int k1 = (int) ((long) i1 * 45875L >> 16); + gameView.setColor(0, 0, 0); + if (getGDActivity().isMenuShown()) { + gameView.drawLineWheel((m_aaan[1].x << 2) >> 16, (m_aaan[1].y << 2) >> 16, (i1 + i1 << 2) >> 16); + gameView.drawLineWheel((m_aaan[1].x << 2) >> 16, (m_aaan[1].y << 2) >> 16, (j1 + j1 << 2) >> 16); + gameView.drawLineWheel((m_aaan[2].x << 2) >> 16, (m_aaan[2].y << 2) >> 16, (i1 + i1 << 2) >> 16); + gameView.drawLineWheel((m_aaan[2].x << 2) >> 16, (m_aaan[2].y << 2) >> 16, (k1 + k1 << 2) >> 16); + } + + // right wheel + int l1 = j1; + int i2 = 0; + int j2; + int k2 = FPMath._doII(j2 = m_aaan[1].m_bI); + int l2 = FPMath.sin(j2); + int i3 = l1; + l1 = (int) ((long) k2 * (long) l1 >> 16) + (int) ((long) (-l2) * (long) i2 >> 16); + i2 = (int) ((long) l2 * (long) i3 >> 16) + (int) ((long) k2 * (long) i2 >> 16); + k2 = FPMath._doII(j2 = 0x141b2); + l2 = FPMath.sin(j2); + for (int k3 = 0; k3 < 5; k3++) { + gameView.drawLine(m_aaan[1].x, m_aaan[1].y, m_aaan[1].x + l1, m_aaan[1].y + i2); + i3 = l1; + l1 = (int) ((long) k2 * (long) l1 >> 16) + (int) ((long) (-l2) * (long) i2 >> 16); + i2 = (int) ((long) l2 * (long) i3 >> 16) + (int) ((long) k2 * (long) i2 >> 16); + } + + // left wheel + l1 = j1; + i2 = 0; + // k2 = FPMath._doII(j2 = m_aaan[2].m_bI); + k2 = FPMath._doII(j2 = Math.round(m_aaan[2].m_bI / 1.75f)); + l2 = FPMath.sin(j2); + i3 = l1; + l1 = (int) ((long) k2 * (long) l1 >> 16) + (int) ((long) (-l2) * (long) i2 >> 16); + i2 = (int) ((long) l2 * (long) i3 >> 16) + (int) ((long) k2 * (long) i2 >> 16); + k2 = FPMath._doII(j2 = 0x141b2); + l2 = FPMath.sin(j2); + + boolean toUpdate = true; + for (int l3 = 0; l3 < 5; l3++) { + if (toUpdate) { + // Log.d("AGDTR", "toUpdate is true"); + leftWheelParams[l3][0] = m_aaan[2].x; + leftWheelParams[l3][1] = m_aaan[2].y; + leftWheelParams[l3][2] = m_aaan[2].x + l1; + leftWheelParams[l3][3] = m_aaan[2].y + i2; + } + // gameView.drawLine(m_aaan[2].x, m_aaan[2].y, m_aaan[2].x + l1, m_aaan[2].y + i2); + gameView.drawLine(leftWheelParams[l3][0], leftWheelParams[l3][1], leftWheelParams[l3][2], leftWheelParams[l3][3]); + int j3 = l1; + l1 = (int) ((long) k2 * (long) l1 >> 16) + (int) ((long) (-l2) * (long) i2 >> 16); + i2 = (int) ((long) l2 * (long) j3 >> 16) + (int) ((long) k2 * (long) i2 >> 16); + } + // if (toUpdate) leftWheelLastUpdated = System.currentTimeMillis(); + // Log.d("AGDTR", "diff: " + (System.currentTimeMillis() - leftWheelLastUpdated)); + + if (m_hI > 0) { + gameView.setColor(255, 0, 0); + if (m_hI > 2) + gameView.setColor(100, 100, 255); + gameView.drawLineWheel((m_aaan[2].x << 2) / (float) 0xFFFF /*>> 16*/, (m_aaan[2].y << 2) / (float) 0xFFFF /*>> 16*/, 4); + gameView.drawLineWheel((m_aaan[1].x << 2) / (float) 0xFFFF /*>> 16*/, (m_aaan[1].y << 2) / (float) 0xFFFF /*>> 16*/, 4); + } + } + + private void _ifiIIV(GameView j, int i1, int j1, int k1, int l1) { + int i2 = 0; + int j2 = 0x10000; + int k2 = m_aaan[0].x; + int l2 = m_aaan[0].y; + int i3 = 0; + int j3 = 0; + int k3 = 0; + int l3 = 0; + int i4 = 0; + int j4 = 0; + int k4 = 0; + int l4 = 0; + int i5 = 0; + int j5 = 0; + int k5 = 0; + int l5 = 0; + int i6 = 0; + int j6 = 0; + int k6 = 0; + int l6 = 0; + int ai[][] = (int[][]) null; + int ai1[][] = (int[][]) null; + int ai2[][] = (int[][]) null; + if (m_elseZ) { + if (m_TI < 32768) { + ai1 = m_ucaaI; + ai2 = m_KaaI; + j2 = (int) ((long) m_TI * 0x20000L >> 16); + } else if (m_TI > 32768) { + i2 = 1; + ai1 = m_KaaI; + ai2 = m_SaaI; + j2 = (int) ((long) (m_TI - 32768) * 0x20000L >> 16); + } else { + ai = m_KaaI; + } + } else if (m_TI < 32768) { + ai1 = m_DaaI; + ai2 = m_wcaaI; + j2 = (int) ((long) m_TI * 0x20000L >> 16); + } else if (m_TI > 32768) { + i2 = 1; + ai1 = m_wcaaI; + ai2 = m_MaaI; + j2 = (int) ((long) (m_TI - 32768) * 0x20000L >> 16); + } else { + ai = m_wcaaI; + } + for (int j7 = 0; j7 < m_KaaI.length; j7++) { + int i8; + int j8; + if (ai1 != null) { + j8 = (int) ((long) ai1[j7][0] * (long) (0x10000 - j2) >> 16) + (int) ((long) ai2[j7][0] * (long) j2 >> 16); + i8 = (int) ((long) ai1[j7][1] * (long) (0x10000 - j2) >> 16) + (int) ((long) ai2[j7][1] * (long) j2 >> 16); + } else { + j8 = ai[j7][0]; + i8 = ai[j7][1]; + } + int k8 = k2 + (int) ((long) k1 * (long) j8 >> 16) + (int) ((long) i1 * (long) i8 >> 16); + int l8 = l2 + (int) ((long) l1 * (long) j8 >> 16) + (int) ((long) j1 * (long) i8 >> 16); + switch (j7) { + case 0: // '\0' + k4 = k8; + l4 = l8; + break; + + case 1: // '\001' + i5 = k8; + j5 = l8; + break; + + case 2: // '\002' + k5 = k8; + l5 = l8; + break; + + case 3: // '\003' + i6 = k8; + j6 = l8; + break; + + case 4: // '\004' + k6 = k8; + l6 = l8; + break; + + case 5: // '\005' + k3 = k8; + l3 = l8; + break; + + case 6: // '\006' + i4 = k8; + j4 = l8; + break; + + case 7: // '\007' + i3 = k8; + j3 = l8; + break; + } + } + + int i7 = (int) ((long) m_JaaI[i2][0] * (long) (0x10000 - j2) >> 16) + (int) ((long) m_JaaI[i2 + 1][0] * (long) j2 >> 16); + if (m_elseZ) { + j._aIIIV(k3 << 2, l3 << 2, k4 << 2, l4 << 2, 1); + j._aIIIV(k4 << 2, l4 << 2, i5 << 2, j5 << 2, 1); + j.drawBikerPart(i5 << 2, j5 << 2, k5 << 2, l5 << 2, 2, i7); + j._aIIIV(k5 << 2, l5 << 2, k6 << 2, l6 << 2, 0); + int k7 = FPMath._ifIII(i1, j1); + if (m_TI > 32768) + k7 += 20588; + j.drawHelmet((i6 << 2) / (float) 0xFFFF /*>> 16*/, (j6 << 2) / (float) 0xFFFF /*>> 16*/, k7); + } else { + j.setColor(0, 0, 0); + j.drawLine(k3, l3, k4, l4); + j.drawLine(k4, l4, i5, j5); + j.setColor(0, 0, 128); + j.drawLine(i5, j5, k5, l5); + j.drawLine(k5, l5, k6, l6); + j.drawLine(k6, l6, i3, j3); + int l7 = 0x10000; + j.setColor(156, 0, 0); + j.drawLineWheel((i6 << 2) >> 16, (j6 << 2) >> 16, (l7 + l7 << 2) >> 16); + } + j.setColor(0, 0, 0); + j.drawSteering((i3 << 2) >> 16, (j3 << 2) >> 16); + j.drawSteering((i4 << 2) >> 16, (j4 << 2) >> 16); + } + + private void _aiIIV(GameView j, int i1, int j1, int k1, int l1) { + int i2 = m_aaan[2].x; + int j2 = m_aaan[2].y; + int k2 = i2 + (int) ((long) k1 * (long) 32768 >> 16); + int l2 = j2 + (int) ((long) l1 * (long) 32768 >> 16); + int i3 = i2 - (int) ((long) k1 * (long) 32768 >> 16); + int j3 = j2 - (int) ((long) l1 * (long) 32768 >> 16); + int k3 = m_aaan[0].x + (int) ((long) i1 * 32768L >> 16); + int l3 = m_aaan[0].y + (int) ((long) j1 * 32768L >> 16); + int i4 = k3 - (int) ((long) i1 * 0x20000L >> 16); + int j4 = l3 - (int) ((long) j1 * 0x20000L >> 16); + int k4 = i4 + (int) ((long) k1 * 0x10000L >> 16); + int l4 = j4 + (int) ((long) l1 * 0x10000L >> 16); + int i5 = i4 + (int) ((long) i1 * 49152L >> 16) + (int) ((long) k1 * 49152L >> 16); + int j5 = j4 + (int) ((long) j1 * 49152L >> 16) + (int) ((long) l1 * 49152L >> 16); + int k5 = i4 + (int) ((long) k1 * 32768L >> 16); + int l5 = j4 + (int) ((long) l1 * 32768L >> 16); + int i6 = m_aaan[1].x; + int j6 = m_aaan[1].y; + int k6 = m_aaan[4].x - (int) ((long) i1 * 49152L >> 16); + int l6 = m_aaan[4].y - (int) ((long) j1 * 49152L >> 16); + int i7 = k6 - (int) ((long) k1 * 32768L >> 16); + int j7 = l6 - (int) ((long) l1 * 32768L >> 16); + int k7 = (k6 - (int) ((long) i1 * 0x20000L >> 16)) + (int) ((long) k1 * 16384L >> 16); + int l7 = (l6 - (int) ((long) j1 * 0x20000L >> 16)) + (int) ((long) l1 * 16384L >> 16); + int i8 = m_aaan[3].x; + int j8 = m_aaan[3].y; + int k8 = i8 + (int) ((long) k1 * 32768L >> 16); + int l8 = j8 + (int) ((long) l1 * 32768L >> 16); + int i9 = (i8 + (int) ((long) k1 * 0x1c000L >> 16)) - (int) ((long) i1 * 32768L >> 16); + int j9 = (j8 + (int) ((long) l1 * 0x1c000L >> 16)) - (int) ((long) j1 * 32768L >> 16); + j.setColor(50, 50, 50); + j.drawLineWheel((k5 << 2) >> 16, (l5 << 2) >> 16, (32768 + 32768 << 2) >> 16); + if (!m_IZ) { + j.drawLine(k2, l2, k4, l4); + j.drawLine(i3, j3, i4, j4); + } + j.drawLine(k3, l3, i4, j4); + j.drawLine(k3, l3, i8, j8); + j.drawLine(i5, j5, k8, l8); + j.drawLine(k8, l8, i9, j9); + if (!m_IZ) { + j.drawLine(i8, j8, i6, j6); + j.drawLine(i9, j9, i6, j6); + } + j.drawLine(k4, l4, i7, j7); + j.drawLine(i5, j5, k6, l6); + j.drawLine(k6, l6, k7, l7); + j.drawLine(i7, j7, k7, l7); + } + + public void _ifiV(GameView j) { + j._tryvV(); + int i1 = m_aaan[3].x - m_aaan[4].x; + int j1 = m_aaan[3].y - m_aaan[4].y; + int k1; + if ((k1 = _doIII(i1, j1)) != 0) { + i1 = (int) (((long) i1 << 32) / (long) k1 >> 16); + j1 = (int) (((long) j1 << 32) / (long) k1 >> 16); + } + int l1 = -j1; + int i2 = i1; + if (m_IZ) { + int k2 = m_aaan[4].x; + int j2; + if ((j2 = m_aaan[3].x) >= k2) { + int l2 = j2; + j2 = k2; + k2 = l2; + } + m_lf.levels._aIIV(j2, k2); + } + + Loader loader = getLevelLoader(); + if (loader != null && loader.isPerspectiveEnabled()) + m_lf._aiIV(j, m_aaan[0].x, m_aaan[0].y); + if (m_UZ) + _aiIV(j, i1, j1); + if (!getGDActivity().isMenuShown()) + _aiV(j); + _doiV(j); + if (m_UZ) + j.setColor(170, 0, 0); + else + j.setColor(50, 50, 50); + j._ifIIIV((m_aaan[1].x << 2) >> 16, (m_aaan[1].y << 2) >> 16, (m_foraI[0] << 2) >> 16, FPMath._ifIII(i1, j1)); + if (!m_IZ) + _laiV(j); + _ifiIIV(j, i1, j1, l1, i2); + if (!m_UZ) + _aiIIV(j, i1, j1, l1, i2); + m_lf._aiV(j); + } + +} diff --git a/src/org/happysanta/gd/Game/k.java b/src/org/happysanta/gd/Game/k.java new file mode 100755 index 0000000..7a45482 --- /dev/null +++ b/src/org/happysanta/gd/Game/k.java @@ -0,0 +1,34 @@ +package org.happysanta.gd.Game; + +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + + +import org.happysanta.gd.Menu.SimpleMenuElement; + +public class k { + + public boolean m_doZ; + public int m_aI; + public int m_intI; + public int m_forI; + public int m_newI; + public SimpleMenuElement m_ifan[]; + + public k() { + m_ifan = new SimpleMenuElement[6]; + for (int i = 0; i < 6; i++) + m_ifan[i] = new SimpleMenuElement(); + + _avV(); + } + + public void _avV() { + m_aI = m_forI = m_newI = 0; + m_doZ = true; + for (int i = 0; i < 6; i++) + m_ifan[i].init(); + + } +} diff --git a/src/org/happysanta/gd/Global.java b/src/org/happysanta/gd/Global.java new file mode 100755 index 0000000..3fb600b --- /dev/null +++ b/src/org/happysanta/gd/Global.java @@ -0,0 +1,21 @@ +package org.happysanta.gd; + +import android.graphics.Typeface; + +public class Global { + + public static final boolean DEBUG = false; + public static final boolean DISABLE_SCALING = false; + public static final boolean INSTALLED_FROM_APK = true; + public static final boolean ACRA_ENABLED = true; + // public static final boolean ENABLE_TOUCH_HACK_FOR_ALL = false; + + public static float density = 0; + public static Typeface robotoCondensedTypeface; + + static { + density = Helpers.getGDActivity().getResources().getDisplayMetrics().density; + robotoCondensedTypeface = Typeface.createFromAsset(Helpers.getGDActivity().getAssets(), "RobotoCondensed-Regular.ttf"); + } + +} diff --git a/src/org/happysanta/gd/Helpers.java b/src/org/happysanta/gd/Helpers.java new file mode 100755 index 0000000..667a880 --- /dev/null +++ b/src/org/happysanta/gd/Helpers.java @@ -0,0 +1,309 @@ +package org.happysanta.gd; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.util.Log; +import org.happysanta.gd.Game.GameView; +import org.happysanta.gd.Levels.Loader; +import org.happysanta.gd.Menu.Menu; +import org.happysanta.gd.Storage.LevelsManager; + +import java.io.IOException; +import java.io.InputStream; + +public class Helpers { + + private static char[] cp1251Map = new char[]{ + '\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007', + '\u0008', '\u0009', '\n', '\u000B', '\u000C', '\r', '\u000E', '\u000F', + '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017', + '\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', '\u001E', '\u001F', + '\u0020', '\u0021', '\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\'', + '\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F', + '\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', + '\u0038', '\u0039', '\u003A', '\u003B', '\u003C', '\u003D', '\u003E', '\u003F', + '\u0040', '\u0041', '\u0042', '\u0043', '\u0044', '\u0045', '\u0046', '\u0047', + '\u0048', '\u0049', '\u004A', '\u004B', '\u004C', '\u004D', '\u004E', '\u004F', + '\u0050', '\u0051', '\u0052', '\u0053', '\u0054', '\u0055', '\u0056', '\u0057', + '\u0058', '\u0059', '\u005A', '\u005B', '\\', '\u005D', '\u005E', '\u005F', + '\u0060', '\u0061', '\u0062', '\u0063', '\u0064', '\u0065', '\u0066', '\u0067', + '\u0068', '\u0069', '\u006A', '\u006B', '\u006C', '\u006D', '\u006E', '\u006F', + '\u0070', '\u0071', '\u0072', '\u0073', '\u0074', '\u0075', '\u0076', '\u0077', + '\u0078', '\u0079', '\u007A', '\u007B', '\u007C', '\u007D', '\u007E', '\u007F', + '\u0402', '\u0403', '\u201A', '\u0453', '\u201E', '\u2026', '\u2020', '\u2021', + '\u20AC', '\u2030', '\u0409', '\u2039', '\u040A', '\u040C', '\u040B', '\u040F', + '\u0452', '\u2018', '\u2019', '\u201C', '\u201D', '\u2022', '\u2013', '\u2014', + '\uFFFD', '\u2122', '\u0459', '\u203A', '\u045A', '\u045C', '\u045B', '\u045F', + '\u00A0', '\u040E', '\u045E', '\u0408', '\u00A4', '\u0490', '\u00A6', '\u00A7', + '\u0401', '\u00A9', '\u0404', '\u00AB', '\u00AC', '\u00AD', '\u00AE', '\u0407', + '\u00B0', '\u00B1', '\u0406', '\u0456', '\u0491', '\u00B5', '\u00B6', '\u00B7', + '\u0451', '\u2116', '\u0454', '\u00BB', '\u0458', '\u0405', '\u0455', '\u0457', + '\u0410', '\u0411', '\u0412', '\u0413', '\u0414', '\u0415', '\u0416', '\u0417', + '\u0418', '\u0419', '\u041A', '\u041B', '\u041C', '\u041D', '\u041E', '\u041F', + '\u0420', '\u0421', '\u0422', '\u0423', '\u0424', '\u0425', '\u0426', '\u0427', + '\u0428', '\u0429', '\u042A', '\u042B', '\u042C', '\u042D', '\u042E', '\u042F', + '\u0430', '\u0431', '\u0432', '\u0433', '\u0434', '\u0435', '\u0436', '\u0437', + '\u0438', '\u0439', '\u043A', '\u043B', '\u043C', '\u043D', '\u043E', '\u043F', + '\u0440', '\u0441', '\u0442', '\u0443', '\u0444', '\u0445', '\u0446', '\u0447', + '\u0448', '\u0449', '\u044A', '\u044B', '\u044C', '\u044D', '\u044E', '\u044F' + }; + + public static GDActivity getGDActivity() { + return GDActivity.shared; + } + + public static GameView getGDView() { + return GDActivity.shared.gameView; + } + + public static Menu getGameMenu() { + return GDActivity.shared.menu; + } + + public static Loader getLevelLoader() { + return GDActivity.shared.levelLoader; + } + + public static LevelsManager getLevelsManager() { + return GDActivity.shared.levelsManager; + } + + public static int getDp(int px) { + return Math.round(px * Global.density); + } + + public static int getDp(float px) { + return Math.round(px * Global.density); + } + + public static String getCurrentStackTrace() { + String del = "\n"; + StringBuilder sb = new StringBuilder(); + StackTraceElement[] list = Thread.currentThread().getStackTrace(); + // for (StackTraceElement e: list) { + for (int i = 0; i < list.length; i++) { + sb.append(list[i].toString() + (i < list.length - 1 ? del : "")); + } + return sb.toString(); + } + + public static Bitmap loadBitmapFromDrawable(int id) { + BitmapFactory.Options options = null; + if (!isSDK11OrHigher()) { + options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + } + return BitmapFactory.decodeResource(getGDActivity().getResources(), id); + } + + public static Bitmap loadBitmapFromAsset(String name) throws IOException { + if (name.startsWith("/")) name = name.substring(1); + Bitmap bmp = null; + InputStream s = getGDActivity().getAssets().open(name); + bmp = BitmapFactory.decodeStream(s); + s.close(); + return bmp; + } + + public static void logDebug(String s) { + Log.d("AGDTR<" + Thread.currentThread().getName() + ">", s); + } + + public static void logDebug(Object s) { + Log.d("AGDTR<" + Thread.currentThread().getName() + ">", s.toString()); + } + + public static boolean isOnline() { + ConnectivityManager cm = (ConnectivityManager) getGDActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cm.getActiveNetworkInfo(); + return netInfo != null && netInfo.isConnectedOrConnecting(); + } + + /*public static String trimLine(String s, Paint f, int w) { + // logDebug("trimLine; s = " + s + ", w = " + w + "; measure = " + f.measureText(s)); + String points = "...", result = s; + float avgWidth = f.measureText("o"), pointsWidth = f.measureText(points); + float diff; + int i = 0, + len = s.length(), + half = 0, + c = 0, + st1 = 0, + st2 = len - 1; + + if (s.equals("") || f.measureText(s) <= w) return s; + + w -= pointsWidth; + + int tmpMax = (int)Math.round(Math.floor(w / Math.round(avgWidth / 1.5)) * 2); + if (len > tmpMax) { + s = s.substring(0, tmpMax); + len = s.length(); + } + + while (true) { + i++; + // if (i >= 100) return s; + if (half == 0) { + c = Math.round(len / 2); + } else { + switch (half) { + case 1: + st2 = c; + c -= (st2 - st1) / 2; + break; + + case 2: + st1 = c; + c += (st2 - st1) / 2; + break; + } + } + + String sub = s.substring(0, c > len - 1 ? len - 1 : c); + float subWidth = f.measureText(sub); + + if (subWidth > w + avgWidth) half = 1; + else if (subWidth < w - avgWidth) half = 2; + else { + diff = subWidth - w; + + if (diff > 0) { + result = s.substring(0, c - 1); + if (!result.equals(s)) result += points; + } else { + result = s.substring(0, c + 1); + if (!result.equals(s)) result += points; + } + + return result; + } + } + + // return s; + }*/ + + public static String getString(int r) { + return GDActivity.shared.getString(r); + } + + public static String[] getStringArray(int r) { + return GDActivity.shared.getResources().getStringArray(r); + } + + public static void runOnUiThread(Runnable runnable) { + GDActivity.shared.runOnUiThread(runnable); + } + + public static long getTimestamp() { + return System.currentTimeMillis() / 1000L; + } + + public static void showAlert(String title, String message, final Runnable listener) { + Context context = getGDActivity(); + AlertDialog alertDialog = new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (listener != null) listener.run(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + if (listener != null) listener.run(); + } + }) + .create(); + alertDialog.show(); + } + + public static void showConfirm(String title, String message, final Runnable onOk, final Runnable onCancel) { + Context context = getGDActivity(); + AlertDialog.Builder alert = new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (onOk != null) onOk.run(); + } + }) + .setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (onCancel != null) onCancel.run(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + if (onCancel != null) onCancel.run(); + } + }); + alert.show(); + } + + public static boolean isSDK11OrHigher() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; + } + + public static boolean isSDK10OrLower() { + return Build.VERSION.SDK_INT <= 10; + } + + public static String getAppVersion() { + String v = "0.0"; + try { + PackageInfo pInfo = GDActivity.shared.getPackageManager().getPackageInfo(GDActivity.shared.getPackageName(), 0); + v = pInfo.versionName; + } catch (PackageManager.NameNotFoundException e) { + } + return v; + } + + public static String decodeCp1251(byte[] data) { + if (data == null) { + return ""; + } + StringBuffer sb = new StringBuffer(data.length); + for (int i = 0; i < data.length; i++) { + if (data[i] == 0) break; + sb.append(cp1251Map[data[i] & 0xFF]); + } + return sb.toString(); + } + + public static String getDeviceName() { + String manufacturer = Build.MANUFACTURER; + String model = Build.MODEL; + if (model.startsWith(manufacturer)) { + return capitalize(model); + } else { + return capitalize(manufacturer) + " " + model; + } + } + + private static String capitalize(String s) { + if (s == null || s.length() == 0) { + return ""; + } + char first = s.charAt(0); + if (Character.isUpperCase(first)) { + return s; + } else { + return Character.toUpperCase(first) + s.substring(1); + } + } + +} diff --git a/src/org/happysanta/gd/KeyboardController.java b/src/org/happysanta/gd/KeyboardController.java new file mode 100644 index 0000000..4438677 --- /dev/null +++ b/src/org/happysanta/gd/KeyboardController.java @@ -0,0 +1,303 @@ +package org.happysanta.gd; + +import android.graphics.Rect; +import android.util.Log; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; +import org.happysanta.gd.Game.GameView; + +import java.text.SimpleDateFormat; +import java.util.Calendar; + +import static org.happysanta.gd.Helpers.getDp; + +public class KeyboardController implements View.OnTouchListener { + + private static final int MAX_POINTERS = 10; + public static final int PADDING = 15; + private static final boolean DISABLE_MOVE = false; + + private static int PADDING_DP = 0; + + private GDActivity gd; + private int[] buf; + private LinearLayout[] btns; + private PointerInfo[] pointers; + private StringBuffer logBuffer; + + static { + PADDING_DP = getDp(PADDING); + } + + KeyboardController(GDActivity gd) { + this.gd = gd; + buf = new int[2]; + btns = new LinearLayout[9]; + pointers = new PointerInfo[MAX_POINTERS]; + for (int i = 0; i < MAX_POINTERS; i++) { + pointers[i] = new PointerInfo(i); + } + + logBuffer = new StringBuffer(); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + GameView gameView = gd.gameView; + + v.getLocationOnScreen(buf); + Rect rect = new Rect(buf[0], buf[1], buf[0] + v.getWidth(), buf[1] + v.getHeight()); + + rect.left += PADDING_DP; + rect.right -= PADDING_DP; + rect.top += PADDING_DP; + rect.bottom -= PADDING_DP; + + /*int actionRaw = MotionEventCompat.getAction/event.getAction(); + if (actionRaw != MotionEvent.ACTION_MOVE) { + log("EVT_RAW " + actionRaw + " " + actionToString(actionRaw)); + }*/ + + // int action = actionRaw & MotionEvent.ACTION_MASK; + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN + || action == MotionEvent.ACTION_POINTER_DOWN + || action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_POINTER_UP +// || action == MotionEvent.ACTION_CANCEL + /*|| action == MotionEvent.ACTION_POINTER_2_DOWN + || action == MotionEvent.ACTION_POINTER_3_DOWN + || action == MotionEvent.ACTION_POINTER_2_UP + || action == MotionEvent.ACTION_POINTER_3_UP*/) { + /*int index = event.getActionIndex(); + int pointerId = event.getPointerId(index);*/ + + int index = event.getActionIndex(); + int pointerId = event.getPointerId(index); +// int pointerId = event.getPointerId(index); + + if (pointerId >= MAX_POINTERS) { + return true; + } + + int x = Math.round(event.getX(index)); + int y = Math.round(event.getY(index)); + + //if (Global.DEBUG || true) { +// log("EVT [ind=" + index + ", pntId=" + pointerId + "] " + actionToString(action) + " " +// + "(x=" + x + ", y=" + y + "), " +// + "(rx=" + event.getRawX() + ", ry=" + event.getRawY() + ")" +// ); +// log("EVT DUMP " + event.toString()); +// log("RECT l="+rect.left+", r="+rect.right+", t="+rect.top+", b="+rect.bottom); + // } + + LinearLayout btn; + PointerInfo pointer = pointers[pointerId]; + + int btnIndex = whichButton(rect, x, y); + +// log("BTN index="+btnIndex, true); + + // logBuffer("x="+x+", y="+y+", btn="+btnIndex); + + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + press(v); + + pointer.setButtonIndex(btnIndex); + btn = pointer.getButton(); + + btn.setPressed(true); + gameView.keyPressed(gameKeyCode(btnIndex)); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + // case MotionEvent.ACTION_CANCEL: + btn = pointer.getButton(); + if (btn != null) { + btn.setPressed(false); + if (DISABLE_MOVE) { + btnIndex = pointer.btnIndex; + } + gameView.keyReleased(gameKeyCode(btnIndex)); + pointer.finish(); + } + break; + } + } else if (action == MotionEvent.ACTION_MOVE && !gd.isMenuShown() && !DISABLE_MOVE) { + int pointerCount = event.getPointerCount(); +// int pointerCount = event.getPointerCount(); + LinearLayout btn, oldBtn; + PointerInfo pointer; + + for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) { + int pointerId = event.getPointerId(pointerIndex); + if (pointerId >= MAX_POINTERS) continue; + + int x = Math.round(event.getX(pointerIndex)); + int y = Math.round(event.getY(pointerIndex)); + +// int x = Math.round(event.getX(pointerIndex)); +// int y = Math.round(event.getY(pointerIndex)); + int btnIndex = whichButton(rect, x, y); + + pointer = pointers[pointerId]; + if (btnIndex != pointer.btnIndex) { + oldBtn = btns[pointer.btnIndex]; + oldBtn.setPressed(false); + gameView.keyReleased(gameKeyCode(pointer.btnIndex)); + + press(v); + + pointer.setButtonIndex(btnIndex); + btn = pointer.getButton(); + btn.setPressed(true); + gameView.keyPressed(gameKeyCode(pointer.btnIndex)); + } + } + } + + return true; + } + + private synchronized void log(Object o, boolean last) { + String logStr = o.toString(); + Log.d("GD Keyboard", o.toString()); + + if (last) + Log.d("", ""); + + /*if (!gd.isMenuShown()) { + logBuffer.append("<"); + logBuffer.append(getCurrentTime()); + logBuffer.append("> "); + + logBuffer.append(logStr); + logBuffer.append("\n"); + + if (last) + logBuffer.append("\n"); + }*/ + } + + private void log(Object o) { + log(o, false); + } + + public synchronized void clearLogBuffer() { + logBuffer = null; + logBuffer = new StringBuffer(); + } + + public String getLog() { + return logBuffer.toString(); + } + + private static String getCurrentTime() { + Calendar cal = Calendar.getInstance(); + cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + return sdf.format(cal.getTime()); + } + + private static String actionToString(int action) { + switch (action) { + case MotionEvent.ACTION_DOWN: + return "ACTION_DOWN"; + case MotionEvent.ACTION_POINTER_DOWN: + return "ACTION_POINTER_DOWN"; + case MotionEvent.ACTION_POINTER_2_DOWN: + return "ACTION_POINTER_2_DOWN"; + case MotionEvent.ACTION_POINTER_2_UP: + return "ACTION_POINTER_2_UP"; + case MotionEvent.ACTION_POINTER_3_DOWN: + return "ACTION_POINTER_3_DOWN"; + case MotionEvent.ACTION_POINTER_3_UP: + return "ACTION_POINTER_3_UP"; + case MotionEvent.ACTION_UP: + return "ACTION_UP"; + case MotionEvent.ACTION_POINTER_UP: + return "ACTION_POINTER_UP"; + case MotionEvent.ACTION_MOVE: + return "ACTION_MOVE"; + } + return "?"; + } + + private static int whichButton(Rect rect, int x, int y) { + int cellW = rect.width() / 3, + cellH = rect.height() / 3; + + // logBuffer("cellW="+cellW+", cellH="+cellH); + + int posX = 0, posY = 0; + + if (x < PADDING_DP + cellW) + posX = 0; + else if (x < PADDING_DP + cellW * 2) + posX = 1; + else + posX = 2; + + if (y < PADDING_DP + cellH) + posY = 0; + else if (y < PADDING_DP + cellH * 2) + posY = 1; + else + posY = 2; + + return posY * 3 + posX; + } + + private static int gameKeyCode(int btnIndex) { + return btnIndex + 49; + } + + private static void press(View v) { + if (Settings.isVibrateOnTouchEnabled()) { + v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + + public void addButton(LinearLayout btn, int x, int y) { + btns[y * 3 + x] = btn; + } + + private class PointerInfo { + + private int id; + private int btnIndex = -1; + private boolean active = false; + + PointerInfo(int id) { + this.id = id; + } + + void finish() { + active = false; + btnIndex = -1; + } + + /*void setActive() { + active = true; + }*/ + + void setButtonIndex(int index) { + active = true; + btnIndex = index; + } + + LinearLayout getButton() { + if (!active) + return null; + return btns[btnIndex]; + } + + } + +} diff --git a/src/org/happysanta/gd/Levels/InvalidTrackException.java b/src/org/happysanta/gd/Levels/InvalidTrackException.java new file mode 100644 index 0000000..9b2b827 --- /dev/null +++ b/src/org/happysanta/gd/Levels/InvalidTrackException.java @@ -0,0 +1,12 @@ +package org.happysanta.gd.Levels; + +/** + * Created by evgeny on 6/15/14. + */ +public class InvalidTrackException extends Exception { + + public InvalidTrackException(Exception e) { + super(e); + } + +} diff --git a/src/org/happysanta/gd/Levels/Level.java b/src/org/happysanta/gd/Levels/Level.java new file mode 100755 index 0000000..78f89ac --- /dev/null +++ b/src/org/happysanta/gd/Levels/Level.java @@ -0,0 +1,245 @@ +package org.happysanta.gd.Levels; + +import org.happysanta.gd.Game.GameView; +import org.happysanta.gd.Game.Physics; + +import java.io.DataInputStream; + +import static org.happysanta.gd.Helpers.getLevelLoader; +import static org.happysanta.gd.Helpers.logDebug; + +public class Level { + + public int startX; + public int startY; + public int finishX; + public int m_gotoI; + public int m_forI; + public int finishY; + public int pointsCount; + public int m_intI; + public int points[][]; + public String levelName; + private int m_aI; + private int m_dI; + private int m_eI; + private int m_bI; + private int m_gI; + private int m_rI; + + public Level() { + m_aI = 0; + m_dI = 0; + m_eI = 0; + m_bI = 0; + m_gI = 0; + m_gotoI = 0; + m_forI = 0; + points = (int[][]) null; + levelName = "levelname"; + m_rI = 0; + clear(); + } + + public void clear() { + startX = 0; + startY = 0; + finishX = 0xc80000; + pointsCount = 0; + m_intI = 0; + } + + public int _doII(int j) { + int k = j - points[m_gotoI][0]; + int i1; + if (((i1 = points[m_forI][0] - points[m_gotoI][0]) >= 0 ? i1 : -i1) < 3 || k > i1) + return 0x10000; + else + return (int) (((long) k << 32) / (long) i1 >> 16); + } + + public void _ifIIV(int j, int k) { + m_aI = (j << 16) >> 3; + m_dI = (k << 16) >> 3; + } + + public void _aIIV(int j, int k) { + m_eI = j >> 1; + m_bI = k >> 1; + } + + public void _aIIV(int j, int k, int i1) { + m_eI = j; + m_bI = k; + m_gI = i1; + } + + public void _ifiIV(GameView view, int k, int i1) { + if (i1 <= pointsCount - 1) { + int j1 = m_gI - (points[k][1] + points[i1 + 1][1] >> 1) >= 0 ? m_gI - (points[k][1] + points[i1 + 1][1] >> 1) : 0; + if (m_gI <= points[k][1] || m_gI <= points[i1 + 1][1]) + j1 = j1 >= 0x50000 ? 0x50000 : j1; + m_rI = (int) ((long) m_rI * 49152L >> 16) + (int) ((long) j1 * 16384L >> 16); + if (m_rI <= 0x88000) { + int k1 = (int) (0x190000L * (long) m_rI >> 16) >> 16; + view.setColor(k1, k1, k1); + int l1 = points[k][0] - points[k + 1][0]; + int i2 = (int) (((long) (points[k][1] - points[k + 1][1]) << 32) / (long) l1 >> 16); + int j2 = points[k][1] - (int) ((long) points[k][0] * (long) i2 >> 16); + int k2 = (int) ((long) m_eI * (long) i2 >> 16) + j2; + l1 = points[i1][0] - points[i1 + 1][0]; + i2 = (int) (((long) (points[i1][1] - points[i1 + 1][1]) << 32) / (long) l1 >> 16); + j2 = points[i1][1] - (int) ((long) points[i1][0] * (long) i2 >> 16); + int l2 = (int) ((long) m_bI * (long) i2 >> 16) + j2; + if (k == i1) { + view._aIIIV((m_eI << 3) >> 16, (k2 + 0x10000 << 3) >> 16, (m_bI << 3) >> 16, (l2 + 0x10000 << 3) >> 16); + return; + } + view._aIIIV((m_eI << 3) >> 16, (k2 + 0x10000 << 3) >> 16, (points[k + 1][0] << 3) >> 16, (points[k + 1][1] + 0x10000 << 3) >> 16); + for (int i3 = k + 1; i3 < i1; i3++) + view._aIIIV((points[i3][0] << 3) >> 16, (points[i3][1] + 0x10000 << 3) >> 16, (points[i3 + 1][0] << 3) >> 16, (points[i3 + 1][1] + 0x10000 << 3) >> 16); + + view._aIIIV((points[i1][0] << 3) >> 16, (points[i1][1] + 0x10000 << 3) >> 16, (m_bI << 3) >> 16, (l2 + 0x10000 << 3) >> 16); + } + } + } + + public synchronized void _aiIV(GameView view, int k, int i1) { + int k2 = 0; + int l2 = 0; + int j2; + for (j2 = 0; j2 < pointsCount - 1 && points[j2][0] <= m_aI; j2++) ; + if (j2 > 0) + j2--; + int i3 = k - points[j2][0]; + int j3 = (i1 + 0x320000) - points[j2][1]; + int k3 = Physics._doIII(i3, j3); + i3 = (int) (((long) i3 << 32) / (long) (k3 >> 1 >> 1) >> 16); + j3 = (int) (((long) j3 << 32) / (long) (k3 >> 1 >> 1) >> 16); + view.setColor(0, 170, 0); + do { + if (j2 >= pointsCount - 1) + break; + int j1 = i3; + int l1 = j3; + i3 = k - points[j2 + 1][0]; + j3 = (i1 + 0x320000) - points[j2 + 1][1]; + int l3 = Physics._doIII(i3, j3); + i3 = (int) (((long) i3 << 32) / (long) (l3 >> 1 >> 1) >> 16); + j3 = (int) (((long) j3 << 32) / (long) (l3 >> 1 >> 1) >> 16); + view._aIIIV((points[j2][0] + j1 << 3) >> 16, (points[j2][1] + l1 << 3) >> 16, (points[j2 + 1][0] + i3 << 3) >> 16, (points[j2 + 1][1] + j3 << 3) >> 16); + view._aIIIV((points[j2][0] << 3) >> 16, (points[j2][1] << 3) >> 16, (points[j2][0] + j1 << 3) >> 16, (points[j2][1] + l1 << 3) >> 16); + if (j2 > 1) { + if (points[j2][0] > m_eI && k2 == 0) + k2 = j2 - 1; + if (points[j2][0] > m_bI && l2 == 0) + l2 = j2 - 1; + } + if (m_gotoI == j2) { + view.drawStartFlag((points[m_gotoI][0] + j1 << 3) >> 16, (points[m_gotoI][1] + l1 << 3) >> 16); + view.setColor(0, 170, 0); + } + if (m_forI == j2) { + view.drawFinishFlag((points[m_forI][0] + j1 << 3) >> 16, (points[m_forI][1] + l1 << 3) >> 16); + view.setColor(0, 170, 0); + } + if (points[j2][0] > m_dI) + break; + j2++; + } while (true); + int k1 = i3; + int i2 = j3; + view._aIIIV((points[pointsCount - 1][0] << 3) >> 16, (points[pointsCount - 1][1] << 3) >> 16, (points[pointsCount - 1][0] + k1 << 3) >> 16, (points[pointsCount - 1][1] + i2 << 3) >> 16); + if (getLevelLoader().isShadowsEnabled()) + _ifiIV(view, k2, l2); + } + + public synchronized void _aiV(GameView view) { + int k; + for (k = 0; k < pointsCount - 1 && points[k][0] <= m_aI; k++) ; + if (k > 0) + k--; + do { + if (k >= pointsCount - 1) + break; + view._aIIIV((points[k][0] << 3) >> 16, (points[k][1] << 3) >> 16, (points[k + 1][0] << 3) >> 16, (points[k + 1][1] << 3) >> 16); + if (m_gotoI == k) { + view.drawStartFlag((points[m_gotoI][0] << 3) >> 16, (points[m_gotoI][1] << 3) >> 16); + view.setColor(0, 255, 0); + } + if (m_forI == k) { + view.drawFinishFlag((points[m_forI][0] << 3) >> 16, (points[m_forI][1] << 3) >> 16); + view.setColor(0, 255, 0); + } + if (points[k][0] > m_dI) + break; + k++; + } while (true); + } + + public void unpackInt(int x, int y) { + addPoint((x << 16) >> 3, (y << 16) >> 3); + } + + public void addPoint(int x, int y) { + if (points == null || points.length <= pointsCount) { + int i1 = 100; + if (points != null) + i1 = i1 >= points.length + 30 ? i1 : points.length + 30; + int ai[][] = new int[i1][2]; + if (points != null) + System.arraycopy(points, 0, ai, 0, points.length); + points = ai; + } + if (pointsCount == 0 || points[pointsCount - 1][0] < x) { + points[pointsCount][0] = x; + points[pointsCount][1] = y; + pointsCount++; + } + } + + public synchronized void readTrackData(DataInputStream in) { + try { + clear(); + if (in.readByte() == 50) { + byte bytes[] = new byte[20]; + in.readFully(bytes); + } + m_forI = 0; + m_gotoI = 0; + startX = in.readInt(); + startY = in.readInt(); + finishX = in.readInt(); + finishY = in.readInt(); + short pointsCount = in.readShort(); + int firstPointX = in.readInt(); + int firstPointY = in.readInt(); + int k1 = firstPointX; + int l1 = firstPointY; + unpackInt(k1, l1); + for (int i = 1; i < pointsCount; i++) { + int x; + int y; + byte byte0; + if ((byte0 = in.readByte()) == -1) { + k1 = l1 = 0; + x = in.readInt(); + y = in.readInt(); + } else { + x = byte0; + y = in.readByte(); + } + k1 += x; + l1 += y; + unpackInt(k1, l1); + } + + /*logDebug("Points: "); + for (int[] point: points) { + logDebug("(" + ((point[0] >> 16) << 3) + ", " + ((point[1] >> 16) << 3) + ")"); + }*/ + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/src/org/happysanta/gd/Levels/LevelHeader.java b/src/org/happysanta/gd/Levels/LevelHeader.java new file mode 100644 index 0000000..68aa112 --- /dev/null +++ b/src/org/happysanta/gd/Levels/LevelHeader.java @@ -0,0 +1,53 @@ +package org.happysanta.gd.Levels; + +public class LevelHeader { + + private int pointers[][] = new int[3][]; + private String names[][] = new String[3][]; + private int counts[] = new int[3]; + + public LevelHeader() { + } + + public void setCount(int level, int count) { + if (level >= counts.length) + return; + + pointers[level] = new int[count]; + names[level] = new String[count]; + counts[level] = count; + } + + public int getCount(int level) { + if (level < counts.length) + return counts[level]; + else + return 0; + } + + public void setPointer(int level, int index, int value) { + pointers[level][index] = value; + } + + public void setName(int level, int index, String value) { + names[level][index] = value; + } + + public int[][] getPointers() { + return pointers; + } + + public String[][] getNames() { + return names; + } + + public boolean isCountsOk() { + for (int i = 0; i < counts.length; i++) { + if (counts[i] <= 0) + return false; + } + + return true; + } + +} diff --git a/src/org/happysanta/gd/Levels/Loader.java b/src/org/happysanta/gd/Levels/Loader.java new file mode 100755 index 0000000..48ef645 --- /dev/null +++ b/src/org/happysanta/gd/Levels/Loader.java @@ -0,0 +1,335 @@ +package org.happysanta.gd.Levels; + +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Game.GameView; +import org.happysanta.gd.Menu.SimpleMenuElement; +import org.happysanta.gd.Game.Physics; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import static org.happysanta.gd.Helpers.logDebug; + +public class Loader { + + //public static final int m_bI; + // public static final int m_forI = 1; + // public static final int m_intI = 2; + //public static final int m_doI; + // public static final int m_ifI = 1; + + public File levelsFile; + public Level levels; + public int m_nullI; + public int m_fI; + public String names[][]; + public int m_jI; + public int m_iI; + public int m_longI; + public int m_eI; + public int m_dI; + + private boolean perspectiveEnabled = true; + private boolean shadowsEnabled = true; + private int pointers[][] = new int[3][]; + private int m_eaI = 0; + private int m_faI = 0; + private int m_aI = 0; + private int m_kI = 0; + private int m_saaI[][]; + private int m_haI[]; + private int m_vaI[]; + private int m_daI; + + public Loader() throws IOException { + reset(); + } + + public Loader(File levelsFile) throws IOException { + if (levelsFile != null) + this.levelsFile = levelsFile; + reset(); + } + + private void reset() throws IOException { + m_saaI = null; + levels = null; + m_haI = new int[3]; + m_vaI = new int[3]; + m_nullI = 0; + m_fI = -1; + names = new String[3][]; + m_daI = 0; + for (int j = 0; j < 3; j++) { + m_haI[j] = (int) ((long) (Physics.m_foraI[j] + 19660 >> 1) * (long) (Physics.m_foraI[j] + 19660 >> 1) >> 16); + m_vaI[j] = (int) ((long) (Physics.m_foraI[j] - 19660 >> 1) * (long) (Physics.m_foraI[j] - 19660 >> 1) >> 16); + } + + // try { + readLevels(); + // } catch ( _ex) { + // _ex.printStackTrace(); + //} + _ifvV(); + } + + + public void setLevelsFile(File file) throws IOException { + levelsFile = file; + reset(); + } + + public InputStream getLevelsInputStream(String s) throws IOException { + if (levelsFile == null) + return GDActivity.shared.getAssets().open(s); + else + return new FileInputStream(levelsFile); + } + + private void readLevels() throws IOException { + //try { + InputStream in = getLevelsInputStream("levels.mrg"); + LevelHeader header = Reader.readHeader(in); + + pointers = header.getPointers(); + names = header.getNames(); + //} catch (Exception ex) { + // logDebug("Levels.Loader: error while reading mrg file"); + // ex.printStackTrace(); + //} + } + + public String getLevelName(int j, int k) { + if (j < names.length && k < names[j].length) + return names[j][k]; + else + return "---"; + } + + public void _ifvV() { + try { + _doIII(m_nullI, m_fI + 1); + } catch (InvalidTrackException e) { + e.printStackTrace(); + } + } + + public int _doIII(int j, int k) throws InvalidTrackException { + m_nullI = j; + m_fI = k; + if (m_fI >= names[m_nullI].length) + m_fI = 0; + _hIIV(m_nullI + 1, m_fI + 1); + return m_fI; + } + + private void _hIIV(int j, int k) throws InvalidTrackException { + try { + InputStream is = getLevelsInputStream("levels.mrg"); + DataInputStream dis = new DataInputStream(is); + for (int i1 = pointers[j - 1][k - 1]; i1 > 0; i1 -= dis.skipBytes(i1)) ; + if (levels == null) + levels = new Level(); + levels.readTrackData(dis); + dis.close(); + load(levels); + } catch (IOException _ex) { + _ex.printStackTrace(); + } + } + + public void _ifIV(int j) { + m_jI = levels.startX << 1; + m_iI = levels.startY << 1; + } + + public int _dovI() { + return levels.points[levels.m_forI][0] << 1; + } + + public int _intvI() { + return levels.points[levels.m_gotoI][0] << 1; + } + + public int _newvI() { + return levels.startX << 1; + } + + public int _avI() { + return levels.startY << 1; + } + + public int _aII(int j) { + return levels._doII(j >> 1); + } + + public void load(Level l1) throws InvalidTrackException { + try { + m_longI = 0x80000000; + levels = l1; + int j = levels.pointsCount; + if (m_saaI == null || m_daI < j) { + m_saaI = (int[][]) null; + // System.gc(); + m_daI = j >= 100 ? j : 100; + m_saaI = new int[m_daI][2]; + } + m_eaI = 0; + m_faI = 0; + m_aI = l1.points[m_eaI][0]; + m_kI = l1.points[m_faI][0]; + for (int k = 0; k < j; k++) { + int i1 = l1.points[(k + 1) % j][0] - l1.points[k][0]; + int j1 = l1.points[(k + 1) % j][1] - l1.points[k][1]; + if (k != 0 && k != j - 1) + m_longI = m_longI >= l1.points[k][0] ? m_longI : l1.points[k][0]; + int k1 = -j1; + int i2 = i1; + int j2 = Physics._doIII(k1, i2); + m_saaI[k][0] = (int) (((long) k1 << 32) / (long) j2 >> 16); + m_saaI[k][1] = (int) (((long) i2 << 32) / (long) j2 >> 16); + if (levels.m_gotoI == 0 && l1.points[k][0] > levels.startX) + levels.m_gotoI = k + 1; + if (levels.m_forI == 0 && l1.points[k][0] > levels.finishX) + levels.m_forI = k; + } + + m_eaI = 0; + m_faI = 0; + m_aI = 0; + m_kI = 0; + } catch (ArithmeticException e) { + throw new InvalidTrackException(e); + } + } + + public void _ifIIV(int j, int k) { + levels._ifIIV(j, k); + } + + public void _aiIV(GameView j, int k, int i1) { + if (j != null) { + j.setColor(0, 170, 0); + k >>= 1; + i1 >>= 1; + levels._aiIV(j, k, i1); + } + } + + public void _aiV(GameView j) { + j.setColor(0, 255, 0); + levels._aiV(j); + } + + public void _aIIV(int j, int k, int i1) { + levels._aIIV(j + 0x18000 >> 1, k - 0x18000 >> 1, i1 >> 1); + k >>= 1; + j >>= 1; + m_faI = m_faI >= levels.pointsCount - 1 ? levels.pointsCount - 1 : m_faI; + m_eaI = m_eaI >= 0 ? m_eaI : 0; + if (k > m_kI) + while (m_faI < levels.pointsCount - 1 && k > levels.points[++m_faI][0]) ; + else if (j < m_aI) { + while (m_eaI > 0 && j < levels.points[--m_eaI][0]) ; + } else { + while (m_eaI < levels.pointsCount && j > levels.points[++m_eaI][0]) ; + if (m_eaI > 0) + m_eaI--; + while (m_faI > 0 && k < levels.points[--m_faI][0]) ; + m_faI = m_faI + 1 >= levels.pointsCount - 1 ? levels.pointsCount - 1 : m_faI + 1; + } + m_aI = levels.points[m_eaI][0]; + m_kI = levels.points[m_faI][0]; + } + + public int _anvI(SimpleMenuElement n1, int j) { + int k3 = 0; + byte byte1 = 2; + int l3 = n1.x >> 1; + int i4 = n1.y >> 1; + if (perspectiveEnabled) + i4 -= 0x10000; + int j4 = 0; + int k4 = 0; + for (int l4 = m_eaI; l4 < m_faI; l4++) { + int k = levels.points[l4][0]; + int i1 = levels.points[l4][1]; + int j1 = levels.points[l4 + 1][0]; + int k1; + int _tmp = (k1 = levels.points[l4 + 1][1]) < i1 ? i1 : k1; + if (l3 - m_haI[j] > j1 || l3 + m_haI[j] < k) + continue; + int l1 = k - j1; + int i2 = i1 - k1; + int j2 = (int) ((long) l1 * (long) l1 >> 16) + (int) ((long) i2 * (long) i2 >> 16); + int k2 = (int) ((long) (l3 - k) * (long) (-l1) >> 16) + (int) ((long) (i4 - i1) * (long) (-i2) >> 16); + int l2; + if ((j2 >= 0 ? j2 : -j2) >= 3) + l2 = (int) (((long) k2 << 32) / (long) j2 >> 16); + else + l2 = (k2 <= 0 ? -1 : 1) * (j2 <= 0 ? -1 : 1) * 0x7fffffff; + if (l2 < 0) + l2 = 0; + if (l2 > 0x10000) + l2 = 0x10000; + int i3 = k + (int) ((long) l2 * (long) (-l1) >> 16); + int j3 = i1 + (int) ((long) l2 * (long) (-i2) >> 16); + l1 = l3 - i3; + i2 = i4 - j3; + byte byte0; + long l5; + if ((l5 = ((long) l1 * (long) l1 >> 16) + ((long) i2 * (long) i2 >> 16)) < (long) m_haI[j]) { + if (l5 >= (long) m_vaI[j]) + byte0 = 1; + else + byte0 = 0; + } else { + byte0 = 2; + } + if (byte0 == 0 && (int) ((long) m_saaI[l4][0] * (long) n1.m_eI >> 16) + (int) ((long) m_saaI[l4][1] * (long) n1.m_dI >> 16) < 0) { + m_eI = m_saaI[l4][0]; + m_dI = m_saaI[l4][1]; + return 0; + } + if (byte0 != 1 || (int) ((long) m_saaI[l4][0] * (long) n1.m_eI >> 16) + (int) ((long) m_saaI[l4][1] * (long) n1.m_dI >> 16) >= 0) + continue; + k3++; + byte1 = 1; + if (k3 == 1) { + j4 = m_saaI[l4][0]; + k4 = m_saaI[l4][1]; + } else { + j4 += m_saaI[l4][0]; + k4 += m_saaI[l4][1]; + } + } + + if (byte1 == 1) { + if ((int) ((long) j4 * (long) n1.m_eI >> 16) + (int) ((long) k4 * (long) n1.m_dI >> 16) >= 0) + return 2; + m_eI = j4; + m_dI = k4; + } + return byte1; + } + + public boolean isShadowsEnabled() { + return shadowsEnabled; + } + + public boolean isPerspectiveEnabled() { + return perspectiveEnabled; + } + + public void setPerspectiveEnabled(boolean enabled) { + perspectiveEnabled = enabled; + } + + public void setShadowsEnabled(boolean enabled) { + shadowsEnabled = enabled; + } + +} diff --git a/src/org/happysanta/gd/Levels/Reader.java b/src/org/happysanta/gd/Levels/Reader.java new file mode 100644 index 0000000..f0ce9a6 --- /dev/null +++ b/src/org/happysanta/gd/Levels/Reader.java @@ -0,0 +1,52 @@ +package org.happysanta.gd.Levels; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +import static org.happysanta.gd.Helpers.decodeCp1251; + +public class Reader { + + private static final int MAX_VALID_TRACKS = 16384; + + public static LevelHeader readHeader(InputStream in) throws IOException { + LevelHeader header = new LevelHeader(); + DataInputStream din = new DataInputStream(in); + byte buf[] = new byte[40]; + String tmp; + for (int i = 0; i < 3; i++) { + int tCount = din.readInt(); + if (tCount > MAX_VALID_TRACKS) { + din.close(); + throw new IOException("Level file is not valid"); + } + header.setCount(i, tCount); + + label0: + for (int j = 0; j < header.getCount(i); j++) { + int trackPointer = din.readInt(); + header.setPointer(i, j, trackPointer); + int nameLen = 0; + do { + if (nameLen >= 40) + continue label0; + + buf[nameLen] = din.readByte(); + if (buf[nameLen] == 0) { + // tmp = (new String(buf, 0, nameLen, "CP-1251")); + tmp = decodeCp1251(buf); + header.setName(i, j, tmp.replace('_', ' ')); + continue label0; + } + nameLen++; + } while (true); + } + + } + din.close(); + + return header; + } + +} diff --git a/src/org/happysanta/gd/Menu/ActionMenuElement.java b/src/org/happysanta/gd/Menu/ActionMenuElement.java new file mode 100755 index 0000000..fb0b706 --- /dev/null +++ b/src/org/happysanta/gd/Menu/ActionMenuElement.java @@ -0,0 +1,141 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.Menu.Views.MenuTextView; +import org.happysanta.gd.R; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; + +public class ActionMenuElement + extends ClickableMenuElement + implements MenuHandler, MenuElement { + + protected static final int DISABLED_COLOR = 0xff999999; + public static final int LOCK_IMAGE_MARGIN_RIGHT = 5; + public static final int locks[] = new int[]{ + R.drawable.s_lock0, + R.drawable.s_lock1, + R.drawable.s_lock2 + }; + + public static final int LINE_SPACING = 15; + public static final int X_OFFSET = 48; + + public static final int OK = 0; + public static final int BACK = 1; + public static final int EXIT = 2; + public static final int YES = 3; + public static final int NO = 4; + public static final int PLAY_MENU = 5; + public static final int GO_TO_MAIN = 6; + public static final int RESTART = 7; + public static final int NEXT = 8; + public static final int CONTINUE = 9; + public static final int INSTALL = 10; + public static final int LOAD = 11; + public static final int SELECT_FILE = 12; + public static final int DELETE = 13; + public static final int RESTART_WITH_NEW_LEVEL = 14; + public static final int SEND_LOGS = 15; + + protected MenuHandler handler; + protected boolean isLocked = false; + protected boolean isBlackLock = true; + protected MenuImageView lockImage = null; + + protected int actionValue = -1; + + public ActionMenuElement(String s, int value, MenuHandler handler) { + actionValue = value; + this.handler = handler; + + text = s; + + createAllViews(); + } + + @Override + protected void createAllViews() { + super.createAllViews(); + + Context context = getGDActivity(); + lockImage = new MenuImageView(context); + lockImage.setScaleType(ImageView.ScaleType.CENTER); + lockImage.setVisibility(View.GONE); + + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT); + lp.setMargins(0, 0, getDp(ActionMenuElement.LOCK_IMAGE_MARGIN_RIGHT), 0); + lockImage.setLayoutParams(lp); + + layout.addView(lockImage, 1); + } + + public ActionMenuElement(String s, MenuHandler handler/*, MenuScreen screen*/) { + this(s, -1, handler); + } + + public int getActionValue() { + return actionValue; + } + + public void setHandler(MenuHandler hander) { + this.handler = hander; + } + + public void setLock(boolean flag, boolean flag1) { + isLocked = flag; + isBlackLock = flag1; + + lockImage.setVisibility(isLocked ? View.VISIBLE : View.GONE); + lockImage.setImageResource(locks[isBlackLock ? 0 : 1]); + } + + @Override + public void setText(String s) { + text = s; + updateViewText(); + } + + @Override + public void performAction(int k) { + if (disabled || handler == null) return; + + if (k == MenuScreen.KEY_FIRE) { + handler.handleAction(this); + } + } + + @Override + protected void onHighlightChanged() { + lockImage.setImageResource(locks[isHighlighted ? 2 : (isBlackLock ? 0 : 1)]); + } + + @Override + public MenuScreen getCurrentMenu() { + return null; + } + + @Override + public void setCurrentMenu(MenuScreen e1, boolean flag) { + } + + @Override + public void handleAction(MenuElement item) { + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + + if (disabled) { + ((MenuTextView) textView).setTextColor(DISABLED_COLOR); + } else { + ((MenuTextView) textView).setTextColor(defaultColorStateList()); + } + } + +} diff --git a/src/org/happysanta/gd/Menu/BigTextMenuElement.java b/src/org/happysanta/gd/Menu/BigTextMenuElement.java new file mode 100644 index 0000000..8b30e64 --- /dev/null +++ b/src/org/happysanta/gd/Menu/BigTextMenuElement.java @@ -0,0 +1,30 @@ +package org.happysanta.gd.Menu; + +import android.text.Spanned; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.MenuTextView; + +public class BigTextMenuElement + extends TextMenuElement { + + public static final int TEXT_SIZE = 19; + + public BigTextMenuElement(String s) { + super(s); + createTextView(); + setTextParams(textView); + } + + public BigTextMenuElement(Spanned s) { + super(s); + createTextView(); + setTextParams(textView); + } + + protected static void setTextParams(MenuTextView textView) { + textView.setTextSize(TEXT_SIZE); + textView.setTypeface(Global.robotoCondensedTypeface); + textView.setLineSpacing(0f, 1.2f); + } + +} diff --git a/src/org/happysanta/gd/Menu/ClickableMenuElement.java b/src/org/happysanta/gd/Menu/ClickableMenuElement.java new file mode 100644 index 0000000..f33db34 --- /dev/null +++ b/src/org/happysanta/gd/Menu/ClickableMenuElement.java @@ -0,0 +1,196 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Rect; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.MenuHelmetView; +import org.happysanta.gd.Menu.Views.MenuTextView; +import org.happysanta.gd.R; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.logDebug; + +public class ClickableMenuElement + implements MenuElement { + + public static final int TEXT_SIZE = 20; + public static final int PADDING_TOP = 5; + protected View textView; + protected String text; + protected View.OnTouchListener onTouchListener; + protected LinearLayout layout; + protected MenuHelmetView helmet; + protected OnMenuElementHighlightListener onMenuElementHighlightListener = null; + protected boolean isHighlighted = false; + protected Thread originalThread = null; + protected boolean disabled = false; + + public ClickableMenuElement() { + } + + public ClickableMenuElement(String text) { + this.text = text; + originalThread = Thread.currentThread(); + + createAllViews(); + } + + protected boolean inViewBounds(View view, int x, int y) { + Rect rect = new Rect(); + int location[] = new int[2]; + + view.getDrawingRect(rect); + view.getLocationOnScreen(location); + rect.offset(location[0], location[1]); + + return rect.contains(x, y); + } + + protected void createAllViews() { + final ClickableMenuElement self = this; + Context context = getGDActivity(); + + layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.HORIZONTAL); + layout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + helmet = new MenuHelmetView(context); + helmet.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); + + /*if (!isSDK11OrHigher()) { + helmet.setMeasuredHeight(true); + }*/ + + onTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (disabled) return false; + + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + view.setSelected(true); + helmet.setShow(true); + + if (onMenuElementHighlightListener != null) + onMenuElementHighlightListener.onElementHighlight(self); + + setHighlighted(true); + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + view.setSelected(false); + + if (motionEvent.getAction() == MotionEvent.ACTION_UP && inViewBounds(view, (int) motionEvent.getRawX(), (int) motionEvent.getRawY())) { + performAction(MenuScreen.KEY_FIRE); + } + + setHighlighted(false); + break; + + case MotionEvent.ACTION_MOVE: + if (!inViewBounds(view, (int) motionEvent.getRawX(), (int) motionEvent.getRawY())) { + view.setSelected(false); + setHighlighted(false); + } else { + view.setSelected(true); + setHighlighted(true); + } + break; + } + return true; + } + }; + + textView = createMainView(); + + layout.addView(helmet); + layout.addView(textView); + layout.setOnTouchListener(onTouchListener); + } + + protected View createMainView() { + Context context = getGDActivity(); + MenuTextView mtv = new MenuTextView(context); + mtv.setText(getTextForView()); + mtv.setTextColor(defaultColorStateList()); + mtv.setTypeface(Global.robotoCondensedTypeface); + mtv.setTextSize(TEXT_SIZE); + mtv.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + mtv.setPadding(0, getDp(PADDING_TOP), 0, getDp(PADDING_TOP)); + + return mtv; + } + + protected ColorStateList defaultColorStateList() { + return getGDActivity().getResources().getColorStateList(R.drawable.menu_item_color); + } + + @Override + public boolean isSelectable() { + return true; + } + + @Override + public View getView() { + return layout; + } + + protected MenuTextView getMenuTextView() { + return (MenuTextView) textView; + } + + @Override + public void setText(String text) { + this.text = text; + updateViewText(); + } + + public String getText() { + return text; + } + + protected void updateViewText() { + if (textView != null && textView instanceof MenuTextView) + ((MenuTextView) textView).setTextOnUiThread(getTextForView()); + } + + protected String getTextForView() { + return text; + } + + @Override + public void performAction(int k) { + + } + + public void setOnHighlightListener(OnMenuElementHighlightListener listener) { + onMenuElementHighlightListener = listener; + } + + public void showHelmet() { + helmet.setShow(true); + } + + private void setHighlighted(boolean highlighted) { + isHighlighted = highlighted; + onHighlightChanged(); + } + + protected void onHighlightChanged() { + } + + public boolean isDisabled() { + return disabled; + } + +} diff --git a/src/org/happysanta/gd/Menu/DownloadLevelsMenuScreen.java b/src/org/happysanta/gd/Menu/DownloadLevelsMenuScreen.java new file mode 100755 index 0000000..fe072ce --- /dev/null +++ b/src/org/happysanta/gd/Menu/DownloadLevelsMenuScreen.java @@ -0,0 +1,222 @@ +package org.happysanta.gd.Menu; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.Toast; +import org.happysanta.gd.API.*; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.R; +import org.happysanta.gd.API.Response; +import org.happysanta.gd.Settings; +import org.happysanta.gd.WaitForNetworkConnection; + +import static org.happysanta.gd.Helpers.*; +import static org.happysanta.gd.Helpers.getDp; + +public class DownloadLevelsMenuScreen extends LevelsMenuScreen { + + protected final static int API_LIMIT = 100; + public static API.LevelsSortType sort; + + protected MenuImageView sortImage; + // protected API api; + protected Request request; + protected int offset = 0; + protected boolean isLoading = false; + protected boolean fullLoaded = false; + protected WaitForNetworkConnection waitForNetworkConnection = null; + protected Toast toast; + + public DownloadLevelsMenuScreen(String title, MenuScreen navTarget) { + super(title, navTarget); + + // api = new API(); + // api.setSort(sort); + + Context context = getGDActivity(); + + // Sort icon + sortImage = new MenuImageView(context); + sortImage.setImageResource(R.drawable.ic_sort); + sortImage.setAdjustViewBounds(true); + sortImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showSortDialog(); + } + }); + sortImage.setVisibility(View.GONE); + sortImage.setPadding(getDp(10), 0, 0, 0); + + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + getDp(40) + ); + params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + + sortImage.setLayoutParams(params); + } + + @Override + protected void loadLevels() { + try { + if (!checkNetwork()) + return; + + showLoading(); + isLoading = true; + request = API.getLevels(offset, API_LIMIT, sort, new ResponseHandler() { + @Override + public void onResponse(final Response response) { + final LevelsResponse levelsResponse = new LevelsResponse(response); + if (status != Statuses.NORMAL) { + clearList(); + setStatus(Statuses.NORMAL); + } + + hideLoading(); + + addElements = new AsyncAddElements() { + @Override + protected void onPostExecute(Void v) { + logDebug("offset = " + offset + ", totalCount = " + levelsResponse.getTotalCount()); + fullLoaded = offset >= levelsResponse.getTotalCount(); + if (!fullLoaded) + showLoading(); + + isLoading = false; + } + }; + addElements.execute(levelsResponse.getLevels()); + } + + @Override + public void onError(APIException error) { + showError(error.getMessage()); + isLoading = false; + } + }); + + offset += API_LIMIT; + } catch (Exception e) { + e.printStackTrace(); + showError(getString(R.string.download_error)); + + isLoading = false; + } + } + + @Override + public void reloadLevels() { + if (request != null) request.cancel(); + offset = 0; + isLoading = false; + fullLoaded = false; + + super.reloadLevels(); + } + + protected void showSortDialog() { + final CharSequence[] items = getStringArray(R.array.sort_variants); + + AlertDialog dialog = new AlertDialog.Builder(getGDActivity()) + .setTitle(getString(R.string.sort_by)) + .setSingleChoiceItems(items, API.getIdBySortType(sort), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + API.LevelsSortType newSort = API.getSortTypeById(item); + + if (newSort != sort) { + sort = newSort; + // api.setSort(newSort); + Settings.setLevelsSort(sort); + reloadLevels(); + } + + dialog.dismiss(); + } + }) + .create(); + + dialog.show(); + } + + protected boolean checkNetwork() { + if (!isOnline()) { + if (elements.isEmpty()) { + showError(getString(R.string.waiting_for_network)); + + if (waitForNetworkConnection != null) + waitForNetworkConnection.cancel(true); + + waitForNetworkConnection = new WaitForNetworkConnection(); + waitForNetworkConnection.execute(null, new Runnable() { + @Override + public void run() { + reloadLevels(); + } + }); + } else { + if (toast != null) { + toast.cancel(); + } + + toast = Toast.makeText(getGDActivity().getApplicationContext(), getString(R.string.no_internet_connection), Toast.LENGTH_SHORT); + toast.show(); + } + + return false; + } + + return true; + } + + @Override + public void onHide(MenuScreen newMenu) { + logDebug("onHide"); + super.onHide(newMenu); + + GDActivity activity = getGDActivity(); + + if (newMenu != getGameMenu().levelScreen) { + offset = 0; + isLoading = false; + fullLoaded = false; + + if (request != null) request.cancel(); + // api.cancelRequest(); + if (waitForNetworkConnection != null) + waitForNetworkConnection.cancel(true); + } + + activity.titleLayout.removeView(sortImage); + sortImage.setVisibility(View.GONE); + } + + @Override + public void onShow() { + super.onShow(); + + GDActivity activity = getGDActivity(); + + activity.titleLayout.addView(sortImage); + sortImage.setVisibility(View.VISIBLE); + } + + @Override + public void onScroll(double percent) { + if (percent >= 97 && !isLoading && !fullLoaded) { + loadLevels(); + } + } + + @Override + public void deleteElement(LevelMenuElement el) { + super.deleteElement(el); + offset--; + } + +} diff --git a/src/org/happysanta/gd/Menu/EmptyLineMenuElement.java b/src/org/happysanta/gd/Menu/EmptyLineMenuElement.java new file mode 100755 index 0000000..e0901f9 --- /dev/null +++ b/src/org/happysanta/gd/Menu/EmptyLineMenuElement.java @@ -0,0 +1,42 @@ +package org.happysanta.gd.Menu; + +import android.view.View; +import android.view.ViewGroup; +import org.happysanta.gd.Menu.Views.MenuTextView; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; + +public class EmptyLineMenuElement implements MenuElement { + + protected String text; + protected int offset; + protected MenuTextView view; + + EmptyLineMenuElement(int offset) { + this.offset = offset; + + view = new MenuTextView(getGDActivity()); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getDp(offset))); + } + + @Override + public View getView() { + return view; + } + + @Override + public boolean isSelectable() { + return false; + } + + @Override + public void setText(String s) { + text = s; + } + + @Override + public void performAction(int k) { + } + +} diff --git a/src/org/happysanta/gd/Menu/HighScoreTextMenuElement.java b/src/org/happysanta/gd/Menu/HighScoreTextMenuElement.java new file mode 100755 index 0000000..fc392df --- /dev/null +++ b/src/org/happysanta/gd/Menu/HighScoreTextMenuElement.java @@ -0,0 +1,100 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.graphics.Typeface; +import android.text.Spanned; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; +import org.happysanta.gd.R; + +import static org.happysanta.gd.Helpers.*; + +public class HighScoreTextMenuElement + extends TextMenuElement + implements MenuElement { + + protected static final int TEXT_LEFT_MARGIN = 5; + protected static final int SUBTITLE_MARGIN_BOTTOM = 8; + protected static final int SUBTITLE_TEXT_SIZE = 20; + protected static final int LAYOUT_PADDING = 3; + protected static int medals[] = new int[]{ + R.drawable.s_medal_gold, + R.drawable.s_medal_silver, + R.drawable.s_medal_bronze + }; + protected static Typeface defaultTypeface = null; + + protected boolean showMedal = false; + protected MenuLinearLayout layout; + protected MenuImageView image; + + public HighScoreTextMenuElement(String s) { + super(s); + createAllViews(); + } + + public HighScoreTextMenuElement(Spanned text) { + super(text); + createAllViews(); + } + + protected void createAllViews() { + Context context = getGDActivity(); + + layout = new MenuLinearLayout(context); + layout.setOrientation(LinearLayout.HORIZONTAL); + layout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + image = new MenuImageView(context); + image.setScaleType(ImageView.ScaleType.CENTER); + image.setVisibility(View.GONE); + + // textView was already created in super constructor + textView.setLineSpacing(0, 1); + + if (defaultTypeface == null) { + defaultTypeface = textView.getTypeface(); + } + + LinearLayout.LayoutParams textViewLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + // textViewLayoutParams.setMargins(getDp(TEXT_LEFT_MARGIN), 0, 0, 0); + textView.setLayoutParams(textViewLayoutParams); + + layout.addView(image, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); + layout.addView(textView); + } + + @Override + public View getView() { + return layout; + } + + public void setMedal(boolean showMedal, int medalIndex) { + image.setVisibility(showMedal ? View.VISIBLE : View.GONE); + image.setImageResource(medals[medalIndex]); + + LinearLayout.LayoutParams textViewLayoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams(); + textViewLayoutParams.setMargins(showMedal ? getDp(TEXT_LEFT_MARGIN) : 0, 0, 0, 0); + textView.setLayoutParams(textViewLayoutParams); + + this.showMedal = showMedal; + } + + public void setIsSubtitle(boolean is) { + textView.setTextSize(is ? SUBTITLE_TEXT_SIZE : TEXT_SIZE); + textView.setTypeface(is ? Global.robotoCondensedTypeface : defaultTypeface); + + LinearLayout.LayoutParams textViewLayoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams(); + textViewLayoutParams.setMargins(!is && showMedal ? getDp(TEXT_LEFT_MARGIN) : 0, 0, 0, is ? getDp(SUBTITLE_MARGIN_BOTTOM) : 0); + textView.setLayoutParams(textViewLayoutParams); + } + + public void setLayoutPadding(boolean use) { + layout.setPadding(0, use ? getDp(LAYOUT_PADDING) : 0, 0, use ? getDp(LAYOUT_PADDING) : 0); + } + +} diff --git a/src/org/happysanta/gd/Menu/InstalledLevelsMenuScreen.java b/src/org/happysanta/gd/Menu/InstalledLevelsMenuScreen.java new file mode 100644 index 0000000..b3adbab --- /dev/null +++ b/src/org/happysanta/gd/Menu/InstalledLevelsMenuScreen.java @@ -0,0 +1,103 @@ +package org.happysanta.gd.Menu; + +import android.os.AsyncTask; +import android.view.ViewTreeObserver; +import org.happysanta.gd.Storage.Level; +import org.happysanta.gd.Storage.LevelsManager; + +import static org.happysanta.gd.Helpers.getGDActivity; + +public class InstalledLevelsMenuScreen extends LevelsMenuScreen { + + LevelsManager levelsManager; + protected boolean isLoading = false; + AsyncLoadLevels asyncLoadLevels = null; + + public InstalledLevelsMenuScreen(String title, MenuScreen navTarget) { + super(title, navTarget); + levelsManager = getGDActivity().levelsManager; + } + + @Override + public void loadLevels() { + showLoading(); + isLoading = true; + + asyncLoadLevels = new AsyncLoadLevels() { + @Override + public void onPostExecute(Level[] levels) { + if (status != Statuses.NORMAL) { + clearList(); + setStatus(Statuses.NORMAL); + } + hideLoading(); + + addElements = new AsyncAddElements() { + @Override + protected void onPostExecute(Void v) { + isLoading = false; + if (selectedIndex != -1) { + // listLayout.requestLayout(); + // listLayout.invalidate(); + + // View someView = findViewById(R.id.someView); + final ViewTreeObserver obs = listLayout.getViewTreeObserver(); + obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + + public boolean onPreDraw() { + scrollToItem(selectedIndex); + try { + obs.removeOnPreDrawListener(this); + } catch (IllegalStateException e) { + } + + return true; + } + }); + + // scrollToItem(selectedIndex); + } + } + }; + addElements.execute(levels); + } + }; + asyncLoadLevels.execute(); + } + + @Override + public void onShow() { + super.onShow(); + } + + @Override + public void onHide(MenuScreen newMenu) { + super.onHide(newMenu); + } + + @Override + protected boolean hideDate() { + return true; + } + + @Override + public void reloadLevels() { + if (asyncLoadLevels != null) { + asyncLoadLevels.cancel(true); + asyncLoadLevels = null; + } + + isLoading = false; + super.reloadLevels(); + } + + private class AsyncLoadLevels extends AsyncTask<Void, Void, Level[]> { + + @Override + protected Level[] doInBackground(Void... params) { + return levelsManager.getAllInstalledLevels(); + } + + } + +} diff --git a/src/org/happysanta/gd/Menu/LevelMenuElement.java b/src/org/happysanta/gd/Menu/LevelMenuElement.java new file mode 100755 index 0000000..e577e94 --- /dev/null +++ b/src/org/happysanta/gd/Menu/LevelMenuElement.java @@ -0,0 +1,370 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.text.Html; +import android.text.SpannableString; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import org.happysanta.gd.Callback; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.LevelNameLeadingMarginSpan2; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; +import org.happysanta.gd.Menu.Views.MenuRelativeLayout; +import org.happysanta.gd.Menu.Views.MenuTextView; +import org.happysanta.gd.R; +import org.happysanta.gd.Storage.Level; +import org.happysanta.gd.Storage.LevelsManager; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getGameMenu; +import static org.happysanta.gd.Helpers.getLevelsManager; +import static org.happysanta.gd.Helpers.getString; +import static org.happysanta.gd.Helpers.logDebug; +import static org.happysanta.gd.Helpers.showConfirm; + +public class LevelMenuElement + extends ClickableMenuElement + implements MenuHandler { + + protected static final int PADDING_TOP = 7; + protected static final int PADDING_BOTTOM = 7; + protected static final int LEVEL_TEXT_SIZE = 16; + protected static final int NAME_SIZE = 20; + + protected static final int INSTALLED_MARGIN = 15; + protected static final int ACTIVE_MARGIN = 21; + + protected Level level; + + protected MenuTextView textView; + protected MenuLinearLayout mainLayout; + protected MenuRelativeLayout nameLayout; + protected MenuTextView tracksCountTextView; + protected MenuScreen screen; + protected MenuImageView installedIcon = null; + protected MenuImageView activeIcon = null; + protected boolean installed = false; + protected boolean active = false; + protected boolean showDate = true; + + public LevelMenuElement() { + } + + public LevelMenuElement(Level level, MenuScreen screen) { + this.level = level; + this.screen = screen; + + createAllViews(); + } + + @Override + protected View createMainView() { + Context context = getGDActivity(); + + mainLayout = new MenuLinearLayout(context); + mainLayout.setOrientation(LinearLayout.VERTICAL); + mainLayout.setPadding(0, getDp(PADDING_TOP), 0, getDp(PADDING_BOTTOM)); + + nameLayout = new MenuRelativeLayout(context); + // nameLayout.setOrientation(LinearLayout.HORIZONTAL); + + // Text + textView = new MenuTextView(context); + // textView.setText(level.getName()); + updateNameLine(); + textView.setTextColor(context.getResources().getColorStateList(R.drawable.menu_item_color)); + textView.setTypeface(Global.robotoCondensedTypeface); + textView.setTextSize(NAME_SIZE); + textView.setLineSpacing(0f, 1.1f); + textView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + textView.setPadding(0, getDp(PADDING_TOP), 0, 0); + + tracksCountTextView = new MenuTextView(context); + tracksCountTextView.setTextSize(LEVEL_TEXT_SIZE); + tracksCountTextView.setTypeface(Global.robotoCondensedTypeface); + updateLevelsLine(); + + nameLayout.addView(textView); + mainLayout.addView(nameLayout); + mainLayout.addView(tracksCountTextView); + + return mainLayout; + } + + public void updateNameLine() { + String name = level.getName() + (Global.DEBUG ? " (id" + level.getAnyId() + ")" : ""); + // if (!active) { + int margin = 0; + if (installed) + margin = INSTALLED_MARGIN; + else if (active) + margin = ACTIVE_MARGIN; + + SpannableString ss = new SpannableString(name); + ss.setSpan(new LevelNameLeadingMarginSpan2(1, installed || active ? getDp(margin) : 0), 0, ss.length(), 0); + textView.setTextOnUiThread(ss); + /*} else { + textView.setTextOnUiThread(Html.fromHtml(String.format(getString(R.string.active_name_tpl), name))); + }*/ + } + + public void updateLevelsLine() { + if (showDate) { + tracksCountTextView.setText(Html.fromHtml(String.format(getString(R.string.levels_count_tpl), + level.getCountEasy() + " - " + level.getCountMedium() + " - " + level.getCountHard(), level.getShortAddedDate()))); + } else { + tracksCountTextView.setText(level.getCountEasy() + " - " + level.getCountMedium() + " - " + level.getCountHard()); + } + } + + @Override + protected void onHighlightChanged() { + if (installed && installedIcon != null) { + installedIcon.setImageResource(isHighlighted ? R.drawable.ic_downloaded_selected : R.drawable.ic_downloaded); + } + if (active && activeIcon != null) { + activeIcon.setImageResource(isHighlighted ? R.drawable.ic_installed_selected : R.drawable.ic_installed); + } + } + + @Override + protected void createAllViews() { + super.createAllViews(); + + helmet.setMeasuredHeight(true); + + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ); + lp.setMargins(0, getDp(PADDING_TOP * 2 + 5), 0, 0); + + helmet.setLayoutParams(lp); + } + + public void setInstalled(boolean installed) { + this.installed = installed; + if (installed) { + if (installedIcon == null) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT + ); + // params.setMargins(0, getDp(PADDING_TOP * 2 + 2), getDp(7), 0); + params.setMargins(0, getDp(PADDING_TOP * 2 + 2), 0, 0); + + installedIcon = new MenuImageView(getGDActivity()); + installedIcon.setLayoutParams(params); + installedIcon.setImageResource(R.drawable.ic_downloaded); + } + + if (installedIcon.getParent() != nameLayout) { + nameLayout.addView(installedIcon); + } + } else if (!installed && installedIcon != null && installedIcon.getParent() == nameLayout) { + nameLayout.removeView(installedIcon); + } + + updateNameLine(); + } + + public void setActive(boolean active) { + this.active = active; + if (active) { + if (activeIcon == null) { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT + ); + // params.setMargins(0, getDp(PADDING_TOP * 2 + 2), getDp(7), 0); + params.setMargins(0, getDp(PADDING_TOP * 2 + 2), 0, 0); + + activeIcon = new MenuImageView(getGDActivity()); + activeIcon.setLayoutParams(params); + activeIcon.setImageResource(R.drawable.ic_installed); + } + + if (activeIcon.getParent() != nameLayout) { + nameLayout.addView(activeIcon); + } + } else if (!active && activeIcon != null && activeIcon.getParent() == nameLayout) { + nameLayout.removeView(activeIcon); + } + + updateNameLine(); + } + + public void setShowDate(boolean showDate) { + this.showDate = showDate; + updateLevelsLine(); + } + + @Override + public void performAction(int k) { + if (k == MenuScreen.KEY_FIRE) { + buildScreen(); + } + } + + protected void buildScreen() { + Menu menu = getGameMenu(); + MenuScreen screen = menu.levelScreen; + LevelsManager levelsManager = getLevelsManager(); + + screen.clear(); + // System.gc(); + + logDebug(level); + + screen.setNavTarget(this.screen); + screen.setTitle(level.getName()); + + if (!level.getAuthor().equals("")) + screen.addItem(new BigTextMenuElement(Html.fromHtml(String.format(getString(R.string.author_tpl), level.getAuthor())))); + if (level.getInstalledTs() > 0) + screen.addItem(new BigTextMenuElement(Html.fromHtml(String.format(getString(R.string.installed_tpl), level.getFullInstalledDate())))); + else if (level.getAddedTs() > 0) + screen.addItem(new BigTextMenuElement(Html.fromHtml(String.format(getString(R.string.added_tpl), level.getFullAddedDate())))); + screen.addItem(new BigTextMenuElement(Html.fromHtml(String.format(getString(R.string.tracks_tpl), level.getCountEasy() + " / " + level.getCountMedium() + " / " + level.getCountHard())))); + screen.addItem(menu.createEmptyLine(true)); + + if (!level.isInstalled()) { + ActionMenuElement installAction = menu.createAction(ActionMenuElement.INSTALL); + installAction.setText(String.format( + getString(R.string.install_kb), level.getSizeKb() + )); + installAction.setHandler(this); + + screen.addItem(installAction); + } else { + if (!level.isDefault()) { + ActionMenuElement installed = new ActionMenuElement(getString(R.string.installed), null); + installed.setDisabled(true); + screen.addItem(installed); + } + + if (level.getId() == levelsManager.getCurrentId()) { + ActionMenuElement active = new ActionMenuElement(getString(R.string.active), null); + active.setDisabled(true); + screen.addItem(active); + } else { + ActionMenuElement loadAction = menu.createAction(ActionMenuElement.LOAD); + loadAction.setHandler(this); + screen.addItem(loadAction); + } + + if (!level.isDefault() && levelsManager.getCurrentId() != level.getId()) { + ActionMenuElement deleteAction = menu.createAction(ActionMenuElement.DELETE); + deleteAction.setHandler(this); + + screen.addItem(deleteAction); + } + } + + screen.addItem(menu.createAction(ActionMenuElement.BACK)); + + if (menu.getCurrentMenu() != screen) { + menu.setCurrentMenu(screen, false); + } else { + screen.highlightElement(); + } + } + + @Override + public MenuScreen getCurrentMenu() { + return null; + } + + @Override + public void setCurrentMenu(MenuScreen e1, boolean flag) { + } + + @Override + public void handleAction(MenuElement item) { + if (item instanceof ActionMenuElement) { + final GDActivity gd = getGDActivity(); + final Menu menu = getGameMenu(); + + switch (((ActionMenuElement) item).getActionValue()) { + case ActionMenuElement.DELETE: + if (!level.isInstalled()) + break; + + showConfirm( + getString(R.string.delete_levels), + getString(R.string.delete_levels_confirmation), + new Runnable() { + @Override + public void run() { + gd.levelsManager.deleteAsync(level, new Runnable() { + @Override + public void run() { + long id = level.getId(); + + MenuScreen target = menu.getCurrentMenu().getNavTarget(); + if (target instanceof InstalledLevelsMenuScreen) { + InstalledLevelsMenuScreen installedScreen = (InstalledLevelsMenuScreen) target; + LevelMenuElement el = installedScreen.getElementByLevelId(id, 0); + if (el != null) + installedScreen.deleteElement(el); + level.setId(0); + menu.back(); + } else if (target instanceof DownloadLevelsMenuScreen) { + DownloadLevelsMenuScreen downloadScreen = (DownloadLevelsMenuScreen) target; + LevelMenuElement el = downloadScreen.getElementByLevelId(id, 0); + if (el != null) + el.setInstalled(false); + + level.setId(0); + buildScreen(); + } + } + }); + } + }, + null + ); + break; + + case ActionMenuElement.INSTALL: + gd.levelsManager.downloadLevel(level, new Callback() { + @Override + public void onDone(Object... objects) { + long id = (long) objects[0]; + level.setId(id); + + MenuScreen target = menu.getCurrentMenu().getNavTarget(); + if (target instanceof DownloadLevelsMenuScreen) { + DownloadLevelsMenuScreen downloadScreen = (DownloadLevelsMenuScreen) target; + LevelMenuElement el = downloadScreen.getElementByLevelId(id, 0); + if (el != null) + el.setInstalled(true); + } + + buildScreen(); + } + }); + break; + + case ActionMenuElement.LOAD: + gd.levelsManager.load(level); + // buildScreen(); + break; + } + } + } + + @Override + public String toString() { + return level.toString(); + } + +}
\ No newline at end of file diff --git a/src/org/happysanta/gd/Menu/LevelsAdapter.java b/src/org/happysanta/gd/Menu/LevelsAdapter.java new file mode 100644 index 0000000..9f7ddc9 --- /dev/null +++ b/src/org/happysanta/gd/Menu/LevelsAdapter.java @@ -0,0 +1,53 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; +import org.happysanta.gd.Global; +import org.happysanta.gd.R; +import org.happysanta.gd.Storage.Level; + +import java.util.ArrayList; + +import static org.happysanta.gd.Helpers.getString; + +public class LevelsAdapter extends ArrayAdapter<Level> { + + private ArrayList<Level> levels; + + public LevelsAdapter(Context context, ArrayList<Level> levels) { + super(context, R.layout.levels_list_item, levels); + this.levels = levels; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + if (v == null) { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = inflater.inflate(R.layout.levels_list_item, null); + } + + Level level = levels.get(position); + if (level != null) { + TextView name = (TextView) v.findViewById(R.id.level_name); + TextView count = (TextView) v.findViewById(R.id.level_count); + + name.setTypeface(Global.robotoCondensedTypeface); + count.setTypeface(Global.robotoCondensedTypeface); + + name.setText(level.getName()); + count.setText(Html.fromHtml(String.format(getString(R.string.levels_count_tpl), + level.getCountEasy() + " - " + level.getCountMedium() + " - " + level.getCountHard(), level.getShortAddedDate()))); + } + + return v; + } + +} + + diff --git a/src/org/happysanta/gd/Menu/LevelsCountTextMenuElement.java b/src/org/happysanta/gd/Menu/LevelsCountTextMenuElement.java new file mode 100644 index 0000000..7ead337 --- /dev/null +++ b/src/org/happysanta/gd/Menu/LevelsCountTextMenuElement.java @@ -0,0 +1,86 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.view.View; +import android.widget.LinearLayout; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; +import org.happysanta.gd.Menu.Views.MenuTextView; +import org.happysanta.gd.R; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; + +public class LevelsCountTextMenuElement + extends BigTextMenuElement { + + protected static final int PADDING_LEFT = 4; + protected static final int PADDING_RIGHT = 8; + protected static final int MARGIN_RIGHT = 3; + + protected int tracks[]; + + protected MenuLinearLayout layout; + protected MenuImageView tracksImages[]; + protected MenuTextView tracksTexts[]; + + public LevelsCountTextMenuElement(String s, int easy, int medium, int hard) { + super(s); + + tracks = new int[3]; + tracks[0] = easy; + tracks[1] = medium; + tracks[2] = hard; + + createViews(); + } + + protected void createViews() { + Context context = getGDActivity(); + + layout = new MenuLinearLayout(context); + layout.setOrientation(LinearLayout.HORIZONTAL); + layout.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + tracksImages = new MenuImageView[3]; + for (int i = 0; i < 3; i++) { + tracksImages[i] = new MenuImageView(context); + tracksImages[i].setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); + } + + tracksImages[0].setImageResource(R.drawable.levels_wheel0); + tracksImages[1].setImageResource(R.drawable.levels_wheel1); + tracksImages[2].setImageResource(R.drawable.levels_wheel2); + + // Tracks texts + tracksTexts = new MenuTextView[3]; + for (int i = 0; i < 3; i++) { + tracksTexts[i] = new MenuTextView(context); + setTextParams(tracksTexts[i]); + + tracksTexts[i].setText(String.valueOf(tracks[i])); + tracksTexts[i].setPadding(getDp(PADDING_LEFT), 0, getDp(PADDING_RIGHT), 0); + } + + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + params.setMargins(0, 0, getDp(MARGIN_RIGHT), 0); + + textView.setLayoutParams(params); + + layout.addView(textView); + + // Add tracks to layout + for (int i = 0; i < 3; i++) { + layout.addView(tracksImages[i]); + layout.addView(tracksTexts[i]); + } + } + + @Override + public View getView() { + return layout; + } +} diff --git a/src/org/happysanta/gd/Menu/LevelsMenuScreen.java b/src/org/happysanta/gd/Menu/LevelsMenuScreen.java new file mode 100644 index 0000000..22b7539 --- /dev/null +++ b/src/org/happysanta/gd/Menu/LevelsMenuScreen.java @@ -0,0 +1,429 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.os.AsyncTask; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; +import org.happysanta.gd.R; +import org.happysanta.gd.Storage.Level; +import org.happysanta.gd.Storage.LevelsManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Vector; + +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getGDView; +import static org.happysanta.gd.Helpers.getGameMenu; +import static org.happysanta.gd.Helpers.getLevelsManager; +import static org.happysanta.gd.Helpers.getString; +import static org.happysanta.gd.Helpers.logDebug; + +public class LevelsMenuScreen extends MenuScreen { + + enum Statuses {NORMAL, DOWNLOADING, ERROR} + + protected final static int ERROR_COLOR = 0xff777777; + + protected Statuses status = Statuses.NORMAL; + protected int savedScrollY = 0; + + protected Vector elements; + protected ArrayList<Level> levels; + + protected FrameLayout progressWrap; + protected ProgressBar progressBar; + + protected MenuLinearLayout listLayout; + protected TextMenuElement errorText; + protected AsyncAddElements addElements = null; + protected boolean leftFromScreen = false; + + public LevelsMenuScreen(String title, MenuScreen navTarget) { + super(title, navTarget); + + elements = new Vector(); + levels = new ArrayList<>(); + + Context context = getGDActivity(); + + // Create progress + progressWrap = new FrameLayout(context); + progressWrap.setLayoutParams(new LinearLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + )); + + progressBar = new ProgressBar(context); + progressBar.setIndeterminate(true); + + // Create error + errorText = new TextMenuElement(getString(R.string.download_error)); + TextView errorTextView = (TextView) errorText.getView(); + + errorTextView.setTextColor(ERROR_COLOR); + errorTextView.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT + )); + errorTextView.setGravity(Gravity.CENTER); + + listLayout = new MenuLinearLayout(context); + listLayout.setOrientation(LinearLayout.VERTICAL); + listLayout.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT + )); + + layout.addView(listLayout); + + // List view + // listView = new ListView(context); + /*listView.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ));*/ + + // adapter = new LevelsAdapter(context, levels); + // listView.setAdapter(adapter); + + // layout.addView(listView); + } + + public int addListItem(MenuElement item) { + elements.addElement(item); + listLayout.addView(item.getView()); + + if (item instanceof ClickableMenuElement) + ((ClickableMenuElement) item).setOnHighlightListener(this); + + return elements.size() - 1; + } + + public void setStatus(Statuses status) { + this.status = status; + + getGDView().invalidate(); + } + + protected void clearList() { + elements.removeAllElements(); + levels.clear(); + listLayout.removeAllViews(); + lastHighlighted = null; + // System.gc(); + } + + protected void showError(String error) { + clearList(); + errorText.setText(error); + addListItem(errorText); + + setStatus(Statuses.ERROR); + } + + protected void showLoading() { + // clearList(); + + if (elements.isEmpty()) { + if (progressBar.getParent() == listLayout) { + listLayout.removeView(progressBar); + } else if (progressBar.getParent() != progressWrap) { + progressWrap.addView(progressBar, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL + )); + } + + listLayout.addView(progressWrap); + } else { + if (progressBar.getParent() == progressWrap) { + progressWrap.removeView(progressBar); + } else if (progressBar.getParent() != listLayout) { + listLayout.addView(progressBar, new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_HORIZONTAL + )); + } + } + + // setStatus(Statuses.DOWNLOADING); + } + + protected void hideLoading() { + if (progressBar.getParent() == listLayout) { + listLayout.removeView(progressBar); + } else if (progressBar.getParent() == progressWrap) { + // progressWrap.setVisibility(GameView.GONE); + listLayout.removeView(progressWrap); + } + } + + public void highlightFirstElement() { + for (int i = 0; i < elements.size(); i++) { + if (elements.elementAt(i) instanceof LevelMenuElement) { + highlightElementAt(i); + break; + } + } + } + + public void highlightElementAt(int index) { + LevelMenuElement item = null; + try { + item = (LevelMenuElement) elements.elementAt(index); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + item.showHelmet(); + lastHighlighted = item; + selectedIndex = index; + } + + protected void load() { + clearList(); + loadLevels(); + } + + protected void loadLevels() { + + } + + @Override + public void onShow() { + super.onShow(); + GDActivity activity = getGDActivity(); + + if (leftFromScreen) { + clearList(); + leftFromScreen = false; + } + + switch (status) { + case DOWNLOADING: + break; + + case NORMAL: + if (elements.isEmpty()) { + load(); + } + break; + } + + if (lastHighlighted != null) { + lastHighlighted.showHelmet(); + } + + if (savedScrollY != 0) { + activity.scrollView.scrollTo(0, savedScrollY); + } + } + + @Override + public void onHide(MenuScreen newMenu) { + GDActivity activity = getGDActivity(); + + if (newMenu != getGameMenu().levelScreen) { + if (addElements != null) { + addElements.cancel(true); + addElements = null; + } + + savedScrollY = 0; + status = Statuses.NORMAL; + + hideLoading(); + clearList(); + + leftFromScreen = true; + } else { + savedScrollY = activity.scrollView.getScrollY(); + } + } + + protected boolean hideDate() { + return false; + } + + protected LevelsMenuScreen getThis() { + return this; + } + + public void reloadLevels() { + if (addElements != null) { + addElements.cancel(true); + addElements = null; + } + + clearList(); + loadLevels(); + } + + public LevelMenuElement getElementByLevelId(long id, long apiId) { + for (Object _el : elements) { + LevelMenuElement el = (LevelMenuElement) _el; + + if ((id > 0 && el.level.getId() == id) || apiId > 0 && el.level.getApiId() == apiId) + return el; + } + + return null; + } + + public void deleteElement(LevelMenuElement el) { + View view = el.getView(); + listLayout.removeView(view); + + int index = elements.indexOf(el); + + elements.remove(el); + levels.remove(el.level); + + if (el == lastHighlighted) { + index--; + if (index < 0) + index = 0; + + highlightElementAt(index); + } + } + + @Override + public void performAction(int k) { + logDebug("LevelsMenuScreen.performAction: k = " + k); + int from = 0; + switch (k) { + default: + if (selectedIndex != -1) { + for (int i = selectedIndex; i < elements.size(); i++) { + MenuElement item; + if ((item = (MenuElement) elements.elementAt(i)) != null && item.isSelectable()) { + item.performAction(k); + return; + } + } + } + break; + + case KEY_UP: + if (selectedIndex > 0) { + from = selectedIndex - 1; + } else { + from = elements.size() - 1; + } + + for (int i = from; i >= 0; i--) { + MenuElement el = (MenuElement) elements.elementAt(i); + if (!(el instanceof LevelMenuElement)) { + continue; + } + + highlightElementAt(i); + scrollToItem(el); + break; + } + break; + + case KEY_DOWN: + if (selectedIndex < elements.size() - 1) { + from = selectedIndex + 1; + } else { + from = 0; + } + + for (int i = from; i < elements.size(); i++) { + MenuElement el = (MenuElement) elements.elementAt(i); + if (!(el instanceof LevelMenuElement)) { + continue; + } + + highlightElementAt(i); + scrollToItem(el); + break; + } + break; + } + } + + protected void scrollToItem(int index) { + LevelMenuElement el = (LevelMenuElement) elements.elementAt(index); + // logDebug(el); + scrollToItem(el); + } + + protected class AsyncAddElements extends AsyncTask<Level[], Void, Void> { + + @Override + protected Void doInBackground(Level[]... params) { + Level[] _levels = params[0]; + boolean checkInstalled = getThis() instanceof DownloadLevelsMenuScreen; + boolean checkActive = getThis() instanceof InstalledLevelsMenuScreen; + + ArrayList<Long> ids; + HashMap<Long, Long> installed = null; + LevelsManager levelsManager = getLevelsManager(); + + if (checkInstalled) { + ids = new ArrayList<>(); + + for (Level level : _levels) { + ids.add(level.getApiId()); + } + + installed = getGDActivity().levelsManager.findInstalledLevels(ids); + } + + boolean alreadyHl = false; + + for (Level level : _levels) { + if (isCancelled()) { + clearList(); + return null; + } + + LevelMenuElement el = new LevelMenuElement(level, getThis()); + boolean toHl = false; + + if (hideDate()) + el.setShowDate(false); + + if (checkInstalled && installed.containsKey(level.getApiId())) { + level.setId(installed.get(level.getApiId())); + el.setInstalled(true); + } + if (checkActive && level.getId() == levelsManager.getCurrentId()) { + el.setActive(true); + toHl = true; + } + + if (!isCancelled()) { + int index = addListItem(el); + if (toHl && !alreadyHl) { + highlightElementAt(index); + // scrollToItem(index); + alreadyHl = true; + } + + if (lastHighlighted == null) + highlightFirstElement(); + } + } + + levels.addAll(Arrays.asList(_levels)); + return null; + } + + } + +} diff --git a/src/org/happysanta/gd/Menu/Menu.java b/src/org/happysanta/gd/Menu/Menu.java new file mode 100755 index 0000000..7485176 --- /dev/null +++ b/src/org/happysanta/gd/Menu/Menu.java @@ -0,0 +1,1554 @@ +package org.happysanta.gd.Menu; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Environment; +import android.text.Html; +import android.text.InputType; +import android.widget.EditText; +import org.happysanta.gd.Command; +import org.happysanta.gd.FileDialog; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Game.GameView; +import org.happysanta.gd.Global; +import org.happysanta.gd.Levels.InvalidTrackException; +import org.happysanta.gd.Levels.Loader; +import org.happysanta.gd.R; +import org.happysanta.gd.Settings; +import org.happysanta.gd.Storage.HighScores; +import org.happysanta.gd.Storage.Level; +import org.happysanta.gd.Storage.LevelsManager; +import org.acra.ACRA; + +import java.io.File; +import java.io.UnsupportedEncodingException; + +import static org.happysanta.gd.Helpers.*; +import static org.happysanta.gd.Helpers.logDebug; + +public class Menu + implements MenuHandler { + + // private final static int SETTINGS_LENGTH = 21; + // private final static boolean ENABLE_MANAGER = true; + + public MenuScreen currentMenu; + public Level level; + private HighScores currentScores; + public int selectedLeague = 0; + public boolean m_blZ = false; + public boolean menuDisabled = false; + // byte[] unlockedTracks = new byte[3]; + // byte leaguesUnlockedCount = 0; + // byte levelsUnlockedCount = 0; + int[] selectedTrack = { + 0, 0, 0 + }; + String[][] trackNames; + String[] leagues = new String[3]; + String[] fullLeaguesList = new String[4]; + // private byte[] settings; + // private SaveManager saveManager; + private Command okCommand; + private Command backCommand; + private MenuScreen mainMenu; + private MenuScreen playMenu; + private MenuScreen optionsMenu; + private MenuScreen aboutScreen; + private MenuScreen helpMenu; + private MenuScreen eraseScreen; + private MenuScreen resetScreen; + private MenuScreen finishedMenu; + private MenuScreen ingameScreen; + private SimpleMenuElementNew gameMenuItem; + // private SimpleMenuElementNew optionsMenuItem; + // private SimpleMenuElementNew helpMenuItem; + private OptionsMenuElement levelSelector; + private MenuScreen levelSelectorCurrentMenu; + private OptionsMenuElement trackSelector; + private MenuScreen trackSelectorCurrentMenu; + private OptionsMenuElement leagueSelector; + private MenuScreen leagueSelectorCurrentMenu; + private MenuScreen highScoreMenu; + private SimpleMenuElementNew highscoreItem; + private ActionMenuElement startItem; + private OptionsMenuElement perspectiveOptionItem; + private OptionsMenuElement shadowsOptionItem; + private OptionsMenuElement driverSpriteOptionItem; + private OptionsMenuElement bikeSpriteOptionItem; + private OptionsMenuElement inputOptionItem; + private OptionsMenuElement lookAheadOptionItem; + private OptionsMenuElement keyboardInMenuOptionItem; + private OptionsMenuElement vibrateOnTouchOptionItem; + private SimpleMenuElementNew clearHighscoreOptionItem; + private SimpleMenuElementNew fullResetItem; + // private ActionMenuElement yesAction; + // private ActionMenuElement noAction; + private SimpleMenuElementNew aboutMenuItem; + private MenuScreen objectiveHelpScreen; + private SimpleMenuElementNew objectiveHelpItem; + private MenuScreen keysHelpScreen; + private SimpleMenuElementNew keysHelpItem; + private MenuScreen unlockingHelpScreen; + private SimpleMenuElementNew unlockingHelpItem; + private MenuScreen highscoreHelpScreen; + private SimpleMenuElementNew highscoreHelpItem; + private MenuScreen optionsHelpScreen; + private SimpleMenuElementNew optionsHelpItem; + private NameInputMenuScreen nameScreen; + private ActionMenuElement continueAction; + // private ActionMenuElement goToMainAction; + // private ActionMenuElement exitMenuItem; + private ActionMenuElement ingameRestartAction; + private ActionMenuElement finishedRestartAction; + private ActionMenuElement nextAction; + // private ActionMenuElement okAction; + private ActionMenuElement nameAction; + private long lastTrackTime; + private int m_ajI; + private int m_atI; + private String finishedTime; + private byte[] nameChars; + // private RecordStore recordStore; + // private int m_afI = -1; + private boolean settingsLoadedOK; + private int levelIndex = 0; + private int track = 0; + private boolean leagueCompleted = false; + private boolean m_SZ = false; + private Object m_BObject; + private String[] difficultyLevels = null; /* { + "Easy", "Medium", "Hard" + }; */ + // private long finishTime = 0L; + /*private byte perspectiveOptionEnabled = 0; + private byte shadowsOptionEnabled = 0; + private byte driverSpriteOptionEnabled = 0; + private byte bikerSpriteOptionEnabled = 0; + private byte inputOptionValue = 0; + private byte lookAheadOptionEnabled = 0; + private byte keyboardInMenuEnabled = 1; + private byte vibrateOnTouchEnabled = 1;*/ + // private byte selectedTrackIndex = 0; + // private byte selectedLevel = 0; + // private byte selectedLeague = 0; + // private byte m_aTB = 0; + // private byte m_arB = 0; + private String[] onOffStrings = null; + private String[] keysetStrings = null; + // private EmptyLineMenuElement emptyLine; + // private EmptyLineMenuElement emptyLineBeforeAction; + // private AlertDialog alertDialog = null; + private Paint bgPaint; + public MenuScreen managerScreen; + public InstalledLevelsMenuScreen managerInstalledScreen; + public DownloadLevelsMenuScreen managerDownloadScreen; + // private MenuScreen managerDownloadOptionsScreen; + private SimpleMenuElementNew managerMenuItem; + public MenuScreen levelScreen; + // private SimpleMenuElement managerInstalledItem; + // private SimpleMenuElement managerDownloadItem; + // private HelmetRotationTask helmetRotationTask; + // private Timer helmetRotationTimer; + // public int helmetAngle; + + public Menu() { + // Background color (instead of raster.png) + bgPaint = new Paint(); + bgPaint.setColor(0x80FFFFFF); + } + + public void load(int step) { + GDActivity activity = getGDActivity(); + Loader loader = getLevelLoader(); + LevelsManager levelsManager = getLevelsManager(); + + level = levelsManager.getCurrentLevel(); + + switch (step) { + case 1: + m_BObject = new Object(); + nameChars = new byte[]{ + 65, 65, 65 // A A A + }; + onOffStrings = getStringArray(R.array.on_off); + keysetStrings = getStringArray(R.array.keyset); + difficultyLevels = getStringArray(R.array.difficulty); + + // saveManager = new SaveManager(); + lastTrackTime = -1L; + m_ajI = -1; + m_atI = -1; + finishedTime = null; + // settingsLoadedOK = false; + /*settings = new byte[SETTINGS_LENGTH]; + for (int l = 0; l < SETTINGS_LENGTH; l++) + settings[l] = -127;*/ + + settingsLoadedOK = true; + /*try { + recordStore = RecordStore.openRecordStore(*//*(Loader.levelsFile != null ? Loader.levelsFile.getName().hashCode() : "") + *//* + getLevelsManager().getCurrentId() + "_" + "GDTRStates", true); + settingsLoadedOK = true; + return; + } catch (Exception _ex) { + settingsLoadedOK = false; + }*/ + + break; + + case 2: + // m_afI = -1; + /*RecordEnumeration enumeration; + try { + enumeration = recordStore.enumerateRecords(null, null, false); + } catch (*//*RecordStoreNotOpen*//*Exception _ex) { + return; + } + if (enumeration.numRecords() > 0) { + byte[] abyte0; + try { + abyte0 = enumeration.nextRecord(); + enumeration.reset(); + m_afI = enumeration.nextRecordId(); + } catch (Exception _ex) { + return; + } + if (abyte0.length <= SETTINGS_LENGTH) + System.arraycopy(abyte0, 0, settings, 0, abyte0.length); + enumeration.destroy(); + }*/ + + /*byte[] chars; + if ((chars = readNameChars(16, (byte) -1)) != null && chars[0] != -1) { + for (int i = 0; i < 3; i++) + nameChars[i] = chars[i]; + + }*/ + + nameChars = Settings.getName(); + // if (nameChars[0] == 82 && nameChars[1] == 75 && nameChars[2] == 69) { + if (isNameCheat(nameChars)) { + // Unlock everything for cheat + level.setUnlockedLeagues(3); + level.setUnlockedLevels(2); + level.setUnlocked( + loader.names[0].length - 1, + loader.names[1].length - 1, + loader.names[2].length - 1 + ); + // logDebug(level); + // leaguesUnlockedCount = 3; + // levelsUnlockedCount = 2; + /*unlockedTracks[0] = (byte) (loader.names[0].length - 1); + unlockedTracks[1] = (byte) (loader.names[1].length - 1); + unlockedTracks[2] = (byte) (loader.names[2].length - 1);*/ + } else if (level.isSettingsClear()) { + level.setUnlockedLeagues(0); + level.setUnlockedLevels(1); + level.setUnlocked(0, 0, -1); + // leaguesUnlockedCount = 0; + // levelsUnlockedCount = 1; + /*unlockedTracks[0] = 0; + unlockedTracks[1] = 0; + unlockedTracks[2] = -1;*/ + } + break; + + case 3: + // Load settings + /*perspectiveOptionEnabled = readSetting(0, perspectiveOptionEnabled); + shadowsOptionEnabled = readSetting(1, shadowsOptionEnabled); + driverSpriteOptionEnabled = readSetting(2, driverSpriteOptionEnabled); + bikerSpriteOptionEnabled = readSetting(3, bikerSpriteOptionEnabled); + lookAheadOptionEnabled = readSetting(4, lookAheadOptionEnabled); + + keyboardInMenuEnabled = readSetting(13, keyboardInMenuEnabled); + inputOptionValue = readSetting(14, inputOptionValue);*/ + // m_arB = readSetting(15, m_arB); // nonsense + + /*vibrateOnTouchEnabled = readSetting(19, keyboardInMenuEnabled); + + selectedLevel = readSetting(10, selectedLevel); + selectedTrackIndex = readSetting(11, selectedTrackIndex); + selectedLeague = readSetting(12, selectedLeague);*/ + + // byte levelsSort = readSetting(20, (byte)0); + + DownloadLevelsMenuScreen.sort = Settings.getLevelsSort(); + + + levelIndex = level.getSelectedLevel(); + track = level.getSelectedTrack(); + + if (nameChars[0] != 82 || nameChars[1] != 75 || nameChars[2] != 69) { + //level.setUnlockedLeagues(); + /*leaguesUnlockedCount = readSetting(5, leaguesUnlockedCount); + levelsUnlockedCount = readSetting(6, levelsUnlockedCount); + for (int i = 0; i < 3; i++) + unlockedTracks[i] = readSetting(7 + i, unlockedTracks[i]);*/ + } + + try { + selectedTrack[level.getSelectedLevel()] = level.getSelectedTrack(); + } catch (ArrayIndexOutOfBoundsException _ex) { + level.setSelectedLevel(0); + level.setSelectedTrack(0); + selectedTrack[level.getSelectedLevel()] = level.getSelectedTrack(); + } + getLevelLoader().setPerspectiveEnabled(Settings.isPerspectiveEnabled()); + getLevelLoader().setShadowsEnabled(Settings.isShadowsEnabled()); + activity.physEngine._ifZV(Settings.isLookAheadEnabled()); + getGDView().setInputOption(Settings.getInputOption()); + // getGDView()._aZV(m_aTB == 0); + getGDView()._aZV(true); + String[] leaguesList = getStringArray(R.array.leagues); + fullLeaguesList = getStringArray(R.array.leagues_full); + trackNames = getLevelLoader().names; + + if (level.getUnlockedLeagues() < 3) { + leagues = leaguesList; + } else { + leagues = fullLeaguesList; + } + + selectedLeague = level.getSelectedLeague(); + + break; + + case 4: + mainMenu = new MenuScreen(getString(R.string.main), null); + playMenu = new MenuScreen(getString(R.string.play), mainMenu); + managerScreen = new MenuScreen(getString(R.string.mods), mainMenu); + optionsMenu = new MenuScreen(getString(R.string.options), mainMenu); + aboutScreen = new MenuScreen(getString(R.string.about) + " v" + getAppVersion(), mainMenu); + helpMenu = new MenuScreen(getString(R.string.help), mainMenu); + + continueAction = new ActionMenuElement(getString(R.string._continue), ActionMenuElement.CONTINUE, this); + nextAction = new ActionMenuElement(getString(R.string.track) + ": " + getLevelLoader().getLevelName(0, 1), ActionMenuElement.NEXT, this); + ingameRestartAction = new ActionMenuElement(getString(R.string.restart) + ": " + getLevelLoader().getLevelName(0, 0), ActionMenuElement.RESTART, this); + finishedRestartAction = new ActionMenuElement(getString(R.string.restart) + ": " + getLevelLoader().getLevelName(0, 0), ActionMenuElement.RESTART, this); + + /*nextAction = new ActionMenuElement(getString(R.string.track) + ": DEFAULT", ActionMenuElement.NEXT, this); + ingameRestartAction = new ActionMenuElement(getString(R.string.restart) + ": DEFAULT", ActionMenuElement.RESTART, this); + finishedRestartAction = new ActionMenuElement(getString(R.string.restart) + ": DEFAULT", ActionMenuElement.RESTART, this);*/ + + highScoreMenu = new MenuScreen(getString(R.string.highscores), playMenu); + finishedMenu = new MenuScreen(getString(R.string.finished), playMenu); + ingameScreen = new MenuScreen(getString(R.string.ingame), playMenu); + nameScreen = new NameInputMenuScreen(getString(R.string.enter_name), finishedMenu, nameChars); + eraseScreen = new MenuScreen(getString(R.string.confirm_clear), optionsMenu); + resetScreen = new MenuScreen(getString(R.string.confirm_reset), eraseScreen); + + gameMenuItem = new SimpleMenuElementNew(getString(R.string.play_menu), playMenu, this); + managerMenuItem = new SimpleMenuElementNew(getString(R.string.mods), managerScreen, this); + aboutMenuItem = new SimpleMenuElementNew(getString(R.string.about), aboutScreen, this); + + mainMenu.addItem(gameMenuItem); + //if (ENABLE_MANAGER) + mainMenu.addItem(new SimpleMenuElementNew(getString(R.string.mods), managerScreen, this)); + mainMenu.addItem(new SimpleMenuElementNew(getString(R.string.options), optionsMenu, this)); + mainMenu.addItem(new SimpleMenuElementNew(getString(R.string.help), helpMenu, this)); + mainMenu.addItem(aboutMenuItem); + if (Global.DEBUG) { + // mainMenu.addItem(createAction(ActionMenuElement.RESTART_WITH_NEW_LEVEL)); + mainMenu.addItem(createAction(ActionMenuElement.SEND_LOGS)); + } + mainMenu.addItem(createAction(ActionMenuElement.EXIT)); + + levelSelector = new OptionsMenuElement(getString(R.string.level), level.getSelectedLevel(), this, difficultyLevels, false, playMenu); + trackSelector = new OptionsMenuElement(getString(R.string.track), selectedTrack[level.getSelectedLevel()], this, trackNames[level.getSelectedLevel()], false, playMenu); + leagueSelector = new OptionsMenuElement(getString(R.string.league), selectedLeague, this, leagues, false, playMenu); + try { + trackSelector.setUnlockedCount(level.getUnlocked(level.getSelectedLevel())); + } catch (ArrayIndexOutOfBoundsException _ex) { + trackSelector.setUnlockedCount(0); + } + levelSelector.setUnlockedCount(level.getUnlockedLevels()); + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + highscoreItem = new SimpleMenuElementNew(getString(R.string.highscores), highScoreMenu, this); + highScoreMenu.addItem(createAction(ActionMenuElement.BACK)); + startItem = new ActionMenuElement(getString(R.string.start) + ">", this); + playMenu.addItem(startItem); + playMenu.addItem(levelSelector); + playMenu.addItem(trackSelector); + playMenu.addItem(leagueSelector); + playMenu.addItem(highscoreItem); + playMenu.addItem(createAction(ActionMenuElement.GO_TO_MAIN)); + // if (hasPointer) + // softwareJoystickOptionItem = new ActionMenuElement("Software Joystick", m_aTB, this, onOffStrings, true, activity, optionsMenu, false); + perspectiveOptionItem = new OptionsMenuElement(getString(R.string.perspective), Settings.isPerspectiveEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + shadowsOptionItem = new OptionsMenuElement(getString(R.string.shadows), Settings.isShadowsEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + driverSpriteOptionItem = new OptionsMenuElement(getString(R.string.driver_sprite), Settings.isDriverSpriteEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + bikeSpriteOptionItem = new OptionsMenuElement(getString(R.string.bike_sprite), Settings.isBikeSpriteEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + inputOptionItem = new OptionsMenuElement(getString(R.string.input), Settings.getInputOption(), this, keysetStrings, false, optionsMenu); + lookAheadOptionItem = new OptionsMenuElement(getString(R.string.look_ahead), Settings.isLookAheadEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + vibrateOnTouchOptionItem = new OptionsMenuElement(getString(R.string.vibrate_on_touch), Settings.isVibrateOnTouchEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + keyboardInMenuOptionItem = new OptionsMenuElement(getString(R.string.keyboard_in_menu), Settings.isKeyboardInMenuEnabled() ? 0 : 1, this, onOffStrings, true, optionsMenu); + clearHighscoreOptionItem = new SimpleMenuElementNew(getString(R.string.clear_highscore), eraseScreen, this); + + // if (hasPointer) + // optionsMenu.addItem(softwareJoystickOptionItem); + optionsMenu.addItem(perspectiveOptionItem); + optionsMenu.addItem(shadowsOptionItem); + optionsMenu.addItem(driverSpriteOptionItem); + optionsMenu.addItem(bikeSpriteOptionItem); + optionsMenu.addItem(inputOptionItem); + optionsMenu.addItem(lookAheadOptionItem); + optionsMenu.addItem(vibrateOnTouchOptionItem); + optionsMenu.addItem(keyboardInMenuOptionItem); + optionsMenu.addItem(clearHighscoreOptionItem); + optionsMenu.addItem(createAction(ActionMenuElement.BACK)); + + // noAction = new ActionMenuElement(getString(R.string.no), 0, this, null, false, mainMenu, true); + // yesAction = new ActionMenuElement(getString(R.string.yes), 0, this, null, false, mainMenu, true); + fullResetItem = new SimpleMenuElementNew(getString(R.string.full_reset), resetScreen, this); + eraseScreen.addItem(new TextMenuElement(getString(R.string.erase_text1))); + eraseScreen.addItem(new TextMenuElement(getString(R.string.erase_text2))); + eraseScreen.addItem(createEmptyLine(true)); + eraseScreen.addItem(createAction(ActionMenuElement.NO)); + eraseScreen.addItem(createAction(ActionMenuElement.YES)); + eraseScreen.addItem(fullResetItem); + resetScreen.addItem(new TextMenuElement(getString(R.string.reset_text1))); + resetScreen.addItem(new TextMenuElement(getString(R.string.reset_text2))); + resetScreen.addItem(createEmptyLine(true)); + resetScreen.addItem(createAction(ActionMenuElement.NO)); + resetScreen.addItem(createAction(ActionMenuElement.YES)); + + objectiveHelpScreen = new MenuScreen(getString(R.string.objective), helpMenu); + objectiveHelpScreen.setIsTextScreen(true); + objectiveHelpItem = new SimpleMenuElementNew(getString(R.string.objective), objectiveHelpScreen, this); + objectiveHelpScreen.addItem(new TextMenuElement(Html.fromHtml(getString(R.string.objective_text)))); + objectiveHelpScreen.addItem(createAction(ActionMenuElement.BACK)); + + keysHelpScreen = new MenuScreen(getString(R.string.keys), helpMenu); + keysHelpScreen.setIsTextScreen(true); + keysHelpItem = new SimpleMenuElementNew(getString(R.string.keys), keysHelpScreen, this); + keysHelpScreen.addItem(new TextMenuElement(Html.fromHtml(getString(R.string.keyset_text)))); + keysHelpScreen.addItem(new ActionMenuElement(getString(R.string.back), ActionMenuElement.BACK, this)); + + unlockingHelpScreen = new MenuScreen(getString(R.string.unlocking), helpMenu); + unlockingHelpScreen.setIsTextScreen(true); + unlockingHelpItem = new SimpleMenuElementNew(getString(R.string.unlocking), unlockingHelpScreen, this); + unlockingHelpScreen.addItem(new TextMenuElement(Html.fromHtml(getString(R.string.unlocking_text)))); + unlockingHelpScreen.addItem(createAction(ActionMenuElement.BACK)); + + highscoreHelpScreen = new MenuScreen(getString(R.string.highscores), helpMenu); + highscoreHelpScreen.setIsTextScreen(true); + highscoreHelpItem = new SimpleMenuElementNew(getString(R.string.highscores), highscoreHelpScreen, this); + highscoreHelpScreen.addItem(new TextMenuElement(Html.fromHtml(getString(R.string.highscore_text)))); + highscoreHelpScreen.addItem(createAction(ActionMenuElement.BACK)); + + optionsHelpScreen = new MenuScreen(getString(R.string.options), helpMenu); + optionsHelpScreen.setIsTextScreen(true); + optionsHelpItem = new SimpleMenuElementNew(getString(R.string.options), optionsHelpScreen, this); + optionsHelpScreen.addItem(new TextMenuElement(Html.fromHtml(getString(R.string.options_text)))); + optionsHelpScreen.addItem(createAction(ActionMenuElement.BACK)); + + helpMenu.addItem(objectiveHelpItem); + helpMenu.addItem(keysHelpItem); + helpMenu.addItem(unlockingHelpItem); + helpMenu.addItem(highscoreHelpItem); + helpMenu.addItem(optionsHelpItem); + helpMenu.addItem(createAction(ActionMenuElement.BACK)); + + aboutScreen.setIsTextScreen(true); + aboutScreen.addItem(new TextMenuElement(Html.fromHtml(getString(R.string.about_text)))); + aboutScreen.addItem(createAction(ActionMenuElement.BACK)); + + ingameScreen.addItem(continueAction); + ingameScreen.addItem(ingameRestartAction); + ingameScreen.addItem(new SimpleMenuElementNew(getString(R.string.options), optionsMenu, this)); + ingameScreen.addItem(new SimpleMenuElementNew(getString(R.string.help), helpMenu, this)); + ingameScreen.addItem(createAction(ActionMenuElement.PLAY_MENU)); + nameAction = new ActionMenuElement(getString(R.string.name) + " - " + new String(nameChars), 0, this); + okCommand = new Command(getString(R.string.ok), 4, 1); + backCommand = new Command(getString(R.string.back), 2, 1); + setCurrentMenu(mainMenu, false); + + // LevelsManager + managerInstalledScreen = new InstalledLevelsMenuScreen(getString(R.string.installed_mods), managerScreen); + managerDownloadScreen = new DownloadLevelsMenuScreen(getString(R.string.download_mods), managerScreen); + // managerDownloadOptionsScreen = new MenuScreen(getString(R.string.download_options), managerDownloadScreen); + + /*managerInstalledScreen.setIsLevelsList(true); + managerDownloadScreen.setIsLevelsList(true);*/ + + // LevelsManager + managerScreen.addItem(new SimpleMenuElementNew(getString(R.string.download_mods), managerDownloadScreen, this)); + managerScreen.addItem(new SimpleMenuElementNew(getString(R.string.installed_mods), managerInstalledScreen, this)); + managerScreen.addItem(createEmptyLine(true)); + // managerScreen.addItem(new ActionMenuElement(getString(R.string.install_mrg), this)); + managerScreen.addItem(new ActionMenuElement(getString(R.string.install_mrg), ActionMenuElement.SELECT_FILE, this)); + + // LevelsManager installed + // managerInstalledScreen.addItem(new TextMenuElement(getString(R.string.installed_levels_text))); + + // Level screen + levelScreen = new MenuScreen("", null); + break; + } + } + + /*public void reloadLevels() { + Loader loader = getLevelLoader(); + trackNames = loader.names; + setUnlockedLevels(); + }*/ + + protected ActionMenuElement createAction(int action) { + int r; + switch (action) { + case ActionMenuElement.BACK: + r = R.string.back; + break; + + case ActionMenuElement.NO: + r = R.string.no; + break; + + case ActionMenuElement.YES: + r = R.string.yes; + break; + + case ActionMenuElement.EXIT: + r = R.string.exit; + break; + + case ActionMenuElement.OK: + r = R.string.ok; + break; + + case ActionMenuElement.PLAY_MENU: + r = R.string.play_menu; + break; + + case ActionMenuElement.GO_TO_MAIN: + r = R.string.go_to_main; + break; + + case ActionMenuElement.RESTART: + r = R.string.restart; + break; + + case ActionMenuElement.NEXT: + r = R.string.next; + break; + + case ActionMenuElement.CONTINUE: + r = R.string._continue; + break; + + case ActionMenuElement.LOAD: + r = R.string.load_this_game; + break; + + case ActionMenuElement.INSTALL: + r = R.string.install_kb; + break; + + case ActionMenuElement.DELETE: + r = R.string.delete; + break; + + case ActionMenuElement.RESTART_WITH_NEW_LEVEL: + r = R.string.restart_with_new_level; + break; + + case ActionMenuElement.SEND_LOGS: + r = R.string.send_logs; + break; + + default: + return null; + } + + return new ActionMenuElement(getString(r), action, this); + } + + public EmptyLineMenuElement createEmptyLine(boolean beforeAction) { + return new EmptyLineMenuElement(beforeAction ? 10 : 20); + } + + public int getSelectedLevel() { + return levelSelector.getSelectedOption(); + } + + public int getSelectedTrack() { + return trackSelector.getSelectedOption(); + } + + // not sure about this name + public boolean canStartTrack() { + if (m_SZ) { + m_SZ = false; + return true; + } else { + return false; + } + } + + private void saveCompletedTrack() { + // ATTENTION!!! + // WHEN CHANGING THIS CODE, COPY-PASTE TO startTrack() !!! + + LevelsManager levelsManager = getLevelsManager(); + + try { + currentScores.saveHighScore(leagueSelector.getSelectedOption(), new String(nameChars, "UTF-8"), lastTrackTime); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + showAlert(getString(R.string.error), e.getMessage(), null); + } + // saveManager.write(); + levelsManager.saveHighScores(currentScores); + + leagueCompleted = false; + + finishedMenu.clear(); + finishedMenu.addItem(new TextMenuElement(Html.fromHtml("<b>" + getString(R.string.time) + "</b>: " + finishedTime))); + + System.gc(); + String[] as = currentScores.getScores(leagueSelector.getSelectedOption()); + for (int k = 0; k < as.length; k++) + if (as[k] != null) + finishedMenu.addItem(new TextMenuElement("" + (k + 1) + ". " + as[k])); + + byte byte0 = -1; + // logDebug("trackSelector.getUnlockedCount() = " + trackSelector.getUnlockedCount()); + // logDebug("trackSelector.getSelectedOption() = " + trackSelector.getSelectedOption()); + + // { + // int unlockedTracks = trackSelector.getUnlockedCount(); + // int selectedTrack = trackSelector.getSelectedOption(); + // int selectedLevel = levelSelector.getSelectedOption(); + // int unlockedInLevel = level.getUnlocked(selectedLevel); + + // logDebug("unlockedTracks (trackSelector) = " + trackSelector.getUnlockedCount()); + // logDebug("selectedTrack (trackSelector) = " + selectedTrack); + // logDebug("selectedLevel (levelSelector) = " + levelSelector.getSelectedOption()); + // logDebug("unlockedInLevel (level.getUnlocked()) = " + level.getUnlocked(levelSelector.getSelectedOption())); + + if (trackSelector.getUnlockedCount() >= trackSelector.getSelectedOption()) { + trackSelector.setUnlockedCount( + trackSelector.getSelectedOption() + 1 >= level.getUnlocked(levelSelector.getSelectedOption()) + ? trackSelector.getSelectedOption() + 1 + : level.getUnlocked(levelSelector.getSelectedOption()) + ); + level.setUnlocked(levelSelector.getSelectedOption(), + trackSelector.getUnlockedCount() >= level.getUnlocked(levelSelector.getSelectedOption()) + ? trackSelector.getUnlockedCount() + : level.getUnlocked(levelSelector.getSelectedOption()) + ); + } + // } + + // Completed league + if (trackSelector.getSelectedOption() == trackSelector.getOptionCount()) { + leagueCompleted = true; + switch (levelSelector.getSelectedOption()) { + default: + break; + + case 0: + if (level.getUnlockedLeagues() < 1) { + byte0 = 1; + level.setUnlockedLeagues(1); + // leaguesUnlockedCount = 1; + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + } + break; + + case 1: + if (level.getUnlockedLeagues() < 2) { + byte0 = 2; + level.setUnlockedLeagues(2); + // leaguesUnlockedCount = 2; + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + } + break; + + case 2: + if (level.getUnlockedLeagues() < 3) { + byte0 = 3; + level.setUnlockedLeagues(3); + leagueSelector.setOptions(fullLeaguesList); + leagues = fullLeaguesList; + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + } + break; + } + + levelSelector.setUnlockedCount(levelSelector.getUnlockedCount() + 1); + + int newUnlocked = level.getUnlocked(levelSelector.getSelectedOption()) + 1, + tracksCount = level.getCount(levelSelector.getSelectedOption()); + + if (newUnlocked > tracksCount) + newUnlocked = tracksCount; + + level.setUnlocked(levelSelector.getSelectedOption(), newUnlocked); + if (level.getUnlocked(levelSelector.getUnlockedCount()) == -1) { + level.setUnlocked(levelSelector.getUnlockedCount(), 0); + } + // if (unlockedTracks[levelSelector.getUnlockedCount()] == -1) + // unlockedTracks[levelSelector.getUnlockedCount()] = 0; + } else { + trackSelector.performAction(MenuScreen.KEY_RIGHT); + } + + // int completedCount = _bbII(levelSelector.getSelectedOption()); + int completedCount = level.getUnlocked(levelSelector.getSelectedOption()); // TODO test + finishedMenu.addItem(new TextMenuElement(Html.fromHtml(String.format(getString(R.string.tracks_completed_tpl), + completedCount, trackNames[levelSelector.getSelectedOption()].length, difficultyLevels[levelSelector.getSelectedOption()])))); + System.gc(); + + if (!leagueCompleted) { + ingameRestartAction.setText(getString(R.string.restart) + ": " + getLevelLoader().getLevelName(levelSelector.getSelectedOption(), trackSelector.getSelectedOption())); + nextAction.setText(getString(R.string.next) + ": " + getLevelLoader().getLevelName(levelIndex, track + 1)); + + // getLevelsManager().updateLevelSettings(); + saveAll(); + } else { + // League completed + if (levelSelector.getSelectedOption() < levelSelector.getOptionCount()) { + levelSelector.setSelectedOption(levelSelector.getSelectedOption() + 1); + trackSelector.setSelectedOption(0); + trackSelector.setUnlockedCount(level.getUnlocked(levelSelector.getSelectedOption())); + } + + if (byte0 != -1) { + finishedMenu.addItem(new TextMenuElement(getString(R.string.congratulations) + leagues[byte0])); + if (byte0 == 3) + finishedMenu.addItem(new TextMenuElement(getString(R.string.enjoy))); + showAlert(getString(R.string.league_unlocked), getString(R.string.league_unlocked_text) + leagues[byte0], null); + + // getLevelsManager().updateLevelSettings(); + saveAll(); + } else { + boolean flag = true; + for (int i1 = 0; i1 < 3; i1++) + if (level.getUnlocked(i1) != getLevelLoader().names[i1].length - 1) + flag = false; + + if (!flag) + finishedMenu.addItem(new TextMenuElement(getString(R.string.level_completed_text))); + } + } + + if (!leagueCompleted) + finishedMenu.addItem(nextAction); + + finishedRestartAction.setText(getString(R.string.restart) + ": " + getLevelLoader().getLevelName(levelIndex, track)); + finishedMenu.addItem(finishedRestartAction); + finishedMenu.addItem(createAction(ActionMenuElement.PLAY_MENU)); + + setCurrentMenu(finishedMenu, false); + } + + //public void _hvV() { + // getGDActivity().m_di.postInvalidate(); + //} + + /* public int getGameViewScaledHeight() { + return getGDView().getScaledHeight(); + } + + public int getGameViewScaledWidth() { + return getGDView().getScaledWidth(); + } */ + + public void showMenu(int k) { + logDebug("[Menu] showMenu()"); + // k = 2; + + GDActivity gd = getGDActivity(); + GameView view = getGDView(); + Loader loader = getLevelLoader(); + + m_blZ = false; + menuDisabled = false; + switch (k) { + case 0: // Just started + setCurrentMenu(mainMenu, false); + gd.physEngine._casevV(); + m_SZ = true; + break; + + case 1: // Ingame + levelIndex = levelSelector.getSelectedOption(); + track = trackSelector.getSelectedOption(); + ingameRestartAction.setText(getString(R.string.restart) + ": " + loader.getLevelName(levelIndex, track)); + m_SZ = false; + ingameScreen.resetHighlighted(); + setCurrentMenu(ingameScreen, false); + break; + + case 2: // Finished + // finishTime = System.currentTimeMillis(); + finishedMenu.clear(); + + levelIndex = levelSelector.getSelectedOption(); + track = trackSelector.getSelectedOption(); + HighScores scores = getLevelsManager().getHighScores(levelSelector.getSelectedOption(), trackSelector.getSelectedOption()); + currentScores = scores; + + // saveManager.setTrack(levelSelector.getSelectedOption(), trackSelector.getSelectedOption()); + int place = scores.getPlace(leagueSelector.getSelectedOption(), lastTrackTime); + finishedTime = getDurationString(lastTrackTime); + + if (place >= 0 && place <= 2) { + HighScoreTextMenuElement placeText = new HighScoreTextMenuElement(""); + placeText.setText(getStringArray(R.array.finished_places)[place]); + placeText.setMedal(true, place); + + finishedMenu.addItem(placeText); + + TextMenuElement h2 = new TextMenuElement(finishedTime); + finishedMenu.addItem(h2); + + // finishedMenu.addItem(createEmptyLine(true)); + finishedMenu.addItem(createAction(ActionMenuElement.OK)); + finishedMenu.addItem(nameAction); + + setCurrentMenu(finishedMenu, false); + m_blZ = false; + } else { + saveCompletedTrack(); + } + break; + + default: + setCurrentMenu(mainMenu, false); + break; + } + + long l1 = System.currentTimeMillis(); + view.drawTimer = false; + long l4 = 0L; + int i1 = 50; + gd.physEngine._charvV(); + gd.gameToMenu(); + + do { + if (!gd.isMenuShown() || !gd.alive || currentMenu == null) + break; + + if (gd.m_cZ) { + while (gd.m_cZ) { + // logDebug("[Menu] showMenu() waiting loop"); + if (!gd.alive || currentMenu == null) { + break; + } + + try { + Thread.sleep(100L); + } catch (InterruptedException e) { + } + } + } + if (gd.physEngine != null && gd.physEngine._gotovZ()) { + int j1; + if ((j1 = gd.physEngine._dovI()) != 0 && j1 != 4) + try { + gd.physEngine._doZV(true); + } catch (NullPointerException e) { + } + gd.physEngine._charvV(); + // _hvV(); + long l2; + if ((l2 = System.currentTimeMillis()) - l4 < (long) i1) { + try { + synchronized (m_BObject) { + m_BObject.wait((long) i1 - (l2 - l4) >= 1L ? (long) i1 - (l2 - l4) : 1L); + } + } catch (InterruptedException e) { + } + l4 = System.currentTimeMillis(); + } else { + l4 = l2; + } + } else { + i1 = 50; + long l3; + if ((l3 = System.currentTimeMillis()) - l4 < (long) i1) { + Object obj; + try { + synchronized (obj = new Object()) { + obj.wait((long) i1 - (l3 - l4) >= 1L ? (long) i1 - (l3 - l4) : 1L); + } + } catch (InterruptedException e) { + } + l4 = System.currentTimeMillis(); + } else { + l4 = l3; + } + } + } while (true); + + logDebug("[Menu.showMenu] out loop"); + + gd.m_forJ += System.currentTimeMillis() - l1; + if (view != null) + view.drawTimer = true; + + if (currentMenu == null && gd != null) { + logDebug("[Menu.showMenu] currentMenu == null, set alive = false"); + gd.exiting = true; + gd.alive = false; + } + } + + public synchronized void draw(Canvas g1) { + if (currentMenu != null && !m_blZ) { + getGDView().drawGame(g1); + drawBackgroundColor(g1); + // currentMenu.draw(g1); + } + } + + private void drawBackgroundColor(Canvas g1) { + g1.drawRect(0, 0, getGDView().getScaledWidth(), getGDView().getScaledHeight(), bgPaint); + } + + public void _tryIV(int k) { + // logDebug("_tryIV k = " + k); + if (getGDView().getGameAction(k) != 8) + keyPressed(k); + } + + public void keyPressed(int k) { + if (currentMenu != null && !menuDisabled) + switch (getGDView().getGameAction(k)) { + case MenuScreen.KEY_UP: // up + currentMenu.performAction(MenuScreen.KEY_UP); + return; + + case MenuScreen.KEY_DOWN: // down + currentMenu.performAction(MenuScreen.KEY_DOWN); + return; + + case MenuScreen.KEY_FIRE: // fire + currentMenu.performAction(MenuScreen.KEY_FIRE); + return; + + case MenuScreen.KEY_RIGHT: // right + currentMenu.performAction(MenuScreen.KEY_RIGHT); + if (currentMenu == highScoreMenu) { + selectedLeague++; + if (selectedLeague > leagueSelector.getUnlockedCount()) + selectedLeague = leagueSelector.getUnlockedCount(); + showHighScoreMenu(selectedLeague); + return; + } + break; + + case MenuScreen.KEY_LEFT: // left + currentMenu.performAction(MenuScreen.KEY_LEFT); + if (currentMenu != highScoreMenu) + break; + selectedLeague--; + if (selectedLeague < 0) + selectedLeague = 0; + showHighScoreMenu(selectedLeague); + break; + } + } + + public void onCommand(Command command) { + if (command == okCommand) { + ok(); + } else if (command == backCommand && currentMenu != null) { + back(); + } + } + + public void back() { + if (currentMenu == ingameScreen) { + getGDActivity().menuToGame(); + return; + } + if (currentMenu != null) + setCurrentMenu(currentMenu.getNavTarget(), true); + } + + public void ok() { + if (currentMenu != null) { + currentMenu.performAction(1); + return; + } + } + + public MenuScreen getCurrentMenu() { + return currentMenu; + } + + public void setCurrentMenu(MenuScreen newMenu, boolean flag) { + menuDisabled = false; + GDActivity gd = getGDActivity(); + GameView view = getGDView(); + + if (!Settings.isKeyboardInMenuEnabled()) { + if (newMenu == nameScreen) { + gd.showKeyboardLayout(); + } else { + gd.hideKeyboardLayout(); + } + } + + view.removeCommand(backCommand); + if (newMenu != mainMenu && newMenu != finishedMenu && newMenu != null) + view.addCommand(backCommand); + + if (newMenu == highScoreMenu) { + selectedLeague = leagueSelector.getSelectedOption(); + showHighScoreMenu(selectedLeague); + } else if (newMenu == finishedMenu) { + // logDebug("it's finished!!!"); + nameChars = nameScreen.getChars(); + nameAction.setText(getString(R.string.name) + " - " + new String(nameChars)); + } else if (newMenu == playMenu) { + trackSelector.setOptions(getLevelLoader().names[levelSelector.getSelectedOption()], false); + if (currentMenu == trackSelectorCurrentMenu) { + selectedTrack[levelSelector.getSelectedOption()] = trackSelector.getSelectedOption(); + } + trackSelector.setUnlockedCount(level.getUnlocked(levelSelector.getSelectedOption())); + trackSelector.setSelectedOption(selectedTrack[levelSelector.getSelectedOption()]); + } + if (newMenu == mainMenu || newMenu == playMenu && gd.physEngine != null) + gd.physEngine._casevV(); + + if (currentMenu != null) + currentMenu.onHide(newMenu); + + currentMenu = newMenu; + if (currentMenu != null) { + gd.setMenu(currentMenu.getLayout()); + currentMenu.onShow(); + + // getGDActivity().setMenu(currentMenu.getTable()); + // if (!isOnOffToggle) currentMenu.scrollUp(); + } + + // getGDActivity().physEngine._casevV(); + m_blZ = false; + + // */ + } + + public void showHighScoreMenu(int league) { + HighScores highScores = getLevelsManager().getHighScores(levelSelector.getSelectedOption(), trackSelector.getSelectedOption()); + + highScoreMenu.clear(); + highScoreMenu.setTitle(getString(R.string.highscores) + ": " + getLevelLoader().getLevelName(levelSelector.getSelectedOption(), trackSelector.getSelectedOption())); + + HighScoreTextMenuElement subtitle = new HighScoreTextMenuElement(Html.fromHtml(getString(R.string.league) + ": " + leagueSelector.getOptions()[league])); + subtitle.setIsSubtitle(true); + + highScoreMenu.addItem(subtitle); + + String[] scores = highScores.getScores(league); + + for (int place = 0; place < scores.length; place++) { + if (scores[place] == null) + continue; + + HighScoreTextMenuElement h1 = new HighScoreTextMenuElement("" + (place + 1) + ". " + scores[place]); + if (place == 0) + h1.setMedal(true, 0); + else if (place == 1) + h1.setMedal(true, 1); + else if (place == 2) + h1.setMedal(true, 2); + + h1.setLayoutPadding(true); + highScoreMenu.addItem(h1); + } + + // saveManager.closeRecordStore(); + if (scores[0] == null) + highScoreMenu.addItem(new TextMenuElement(getString(R.string.no_highscores))); + + highScoreMenu.addItem(createAction(ActionMenuElement.BACK)); + highScoreMenu.highlightElement(); + + // System.gc(); + } + + public synchronized void destroy() { + currentMenu = null; + } + + public synchronized void saveAll() { + logDebug("saveAll()"); + + try { + if (level != null) { + Settings.setName(nameChars); + + level.setUnlockedLeagues(leagueSelector.getUnlockedCount()); + level.setUnlockedLevels(levelSelector.getUnlockedCount()); + + level.setSelectedLevel(levelSelector.getSelectedOption()); + level.setSelectedTrack(trackSelector.getSelectedOption()); + level.setSelectedLeague(leagueSelector.getSelectedOption()); + + getLevelsManager().updateLevelSettings(); + } else { + logDebug("saveAll(): level == null"); + } + } catch (Exception e) { + logDebug("saveAll exception: " + e); + } + } + + public void handleAction(MenuElement item) { + final GDActivity gd = getGDActivity(); + + if (currentMenu == null) { + return; + } + + if (item == startItem) + if (levelSelector.getSelectedOption() > levelSelector.getUnlockedCount() || trackSelector.getSelectedOption() > trackSelector.getUnlockedCount() || leagueSelector.getSelectedOption() > leagueSelector.getUnlockedCount()) { + showAlert("GD Classic", getString(R.string.complete_to_unlock), null); + return; + } else { + gd.physEngine._avV(); + startTrack(levelSelector.getSelectedOption(), trackSelector.getSelectedOption()); + gd.physEngine.setLeague(leagueSelector.getSelectedOption()); + m_SZ = true; + gd.menuToGame(); + return; + } + + if (item == vibrateOnTouchOptionItem) { + Settings.setVibrateOnTouchEnabled(((OptionsMenuElement) item).getSelectedOption() == 0); + } + if (item == keyboardInMenuOptionItem) { + boolean enabled = ((OptionsMenuElement) item).getSelectedOption() == 0; + Settings.setKeyboardInMenuEnabled(enabled); + if (enabled) gd.showKeyboardLayout(); + else gd.hideKeyboardLayout(); + } + if (item == perspectiveOptionItem) { + gd.physEngine._aZV(perspectiveOptionItem.getSelectedOption() == 0); + getLevelLoader().setPerspectiveEnabled(perspectiveOptionItem.getSelectedOption() == 0); + Settings.setPerspectiveEnabled(perspectiveOptionItem.getSelectedOption() == 0); + return; + } + if (item == shadowsOptionItem) { + getLevelLoader().setShadowsEnabled(shadowsOptionItem.getSelectedOption() == 0); + Settings.setShadowsEnabled(shadowsOptionItem.getSelectedOption() == 0); + return; + } + if (item == driverSpriteOptionItem) { + if (driverSpriteOptionItem._charvZ()) { + driverSpriteOptionItem.setSelectedOption(driverSpriteOptionItem.getSelectedOption() + 1); + } + Settings.setDriverSpriteEnabled(driverSpriteOptionItem.getSelectedOption() == 0); + } else if (item == bikeSpriteOptionItem) { + if (bikeSpriteOptionItem._charvZ()) { + bikeSpriteOptionItem.setSelectedOption(bikeSpriteOptionItem.getSelectedOption() + 1); + } + Settings.setBikeSpriteEnabled(bikeSpriteOptionItem.getSelectedOption() == 0); + } else { + if (item == inputOptionItem) { + if (inputOptionItem._charvZ()) + inputOptionItem.setSelectedOption(inputOptionItem.getSelectedOption() + 1); + getGDView().setInputOption(inputOptionItem.getSelectedOption()); + Settings.setInputOption(inputOptionItem.getSelectedOption()); + return; + } + if (item == lookAheadOptionItem) { + gd.physEngine._ifZV(lookAheadOptionItem.getSelectedOption() == 0); + Settings.setLookAheadEnabled(lookAheadOptionItem.getSelectedOption() == 0); + return; + } + if (item instanceof ActionMenuElement) { + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.RESTART_WITH_NEW_LEVEL) { + LevelsManager manager = gd.levelsManager; + long nextId = manager.getCurrentId() == 1 ? 2 : 1; + gd.levelsManager.load(manager.getLeveL(nextId)); + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.SEND_LOGS) { + gd.sendKeyboardLogs(); + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.SELECT_FILE) { + installFromFileBrowse(); + return; + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.YES) { + if (currentMenu == eraseScreen) { + getLevelsManager().clearHighScores(); + showAlert(getString(R.string.cleared), getString(R.string.cleared_text), null); + } else if (currentMenu == resetScreen) { + showAlert(getString(R.string.reset), getString(R.string.reset_text), new Runnable() { + @Override + public void run() { + resetAll(); + } + }); + } + setCurrentMenu(currentMenu.getNavTarget(), false); + return; + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.NO) { + setCurrentMenu(currentMenu.getNavTarget(), false); + return; + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.BACK) { + setCurrentMenu(currentMenu.getNavTarget(), true); + return; + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.PLAY_MENU) { + levelSelector.setSelectedOption(levelIndex); + trackSelector.setUnlockedCount(level.getUnlocked(levelIndex)); + trackSelector.setSelectedOption(track); + setCurrentMenu(currentMenu.getNavTarget(), false); + return; + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.GO_TO_MAIN) { + setCurrentMenu(mainMenu, false); + return; + } + if (((ActionMenuElement) item).getActionValue() == ActionMenuElement.EXIT) { + getGDActivity().exiting = true; + if (currentMenu != null) { + setCurrentMenu(currentMenu.getNavTarget(), false); + } else { + setCurrentMenu(null, false); + } + return; + } + } + + if (item == ingameRestartAction || item == finishedRestartAction) { + if (leagueSelector.getSelectedOption() <= leagueSelector.getUnlockedCount()) { + levelSelector.setSelectedOption(levelIndex); + trackSelector.setUnlockedCount(level.getUnlocked(levelIndex)); + trackSelector.setSelectedOption(track); + gd.physEngine.setLeague(leagueSelector.getSelectedOption()); + m_SZ = true; + gd.menuToGame(); + return; + } + } else { + if (item == nextAction) { + // if (!leagueCompleted) + // trackSelector.performAction(MenuScreen.KEY_RIGHT); + startTrack(levelSelector.getSelectedOption(), trackSelector.getSelectedOption()); + gd.physEngine.setLeague(leagueSelector.getSelectedOption()); + // saveAll(); + // getLevelsManager().updateLevelSettings(); + m_SZ = true; + gd.menuToGame(); + return; + } + if (item == continueAction) { + // _hvV(); + gd.menuToGame(); + return; + } + if (item == nameAction) { + nameScreen.resetCursorPosition(); + setCurrentMenu(nameScreen, false); + return; + } + if (item instanceof ActionMenuElement && ((ActionMenuElement) item).getActionValue() == ActionMenuElement.OK) { + saveCompletedTrack(); + return; + } + if (item == trackSelector) { + if (trackSelector._charvZ()) { + trackSelector.setUnlockedCount(level.getUnlocked(levelSelector.getSelectedOption())); + trackSelector.update(); + trackSelectorCurrentMenu = trackSelector.getCurrentMenu(); + setCurrentMenu(trackSelectorCurrentMenu, false); + // trackSelectorCurrentMenu._doIV(trackSelector.getSelectedOption()); + } + selectedTrack[levelSelector.getSelectedOption()] = trackSelector.getSelectedOption(); + return; + } + if (item == levelSelector) { + if (levelSelector._charvZ()) { + levelSelectorCurrentMenu = levelSelector.getCurrentMenu(); + setCurrentMenu(levelSelectorCurrentMenu, false); + } + trackSelector.setOptions(getLevelLoader().names[levelSelector.getSelectedOption()], false); + trackSelector.setUnlockedCount(level.getUnlocked(levelSelector.getSelectedOption())); + trackSelector.setSelectedOption(selectedTrack[levelSelector.getSelectedOption()]); + // trackSelector.update(); + // logDebug("update tracks "); + return; + } + if (item == leagueSelector && leagueSelector._charvZ()) { + leagueSelectorCurrentMenu = leagueSelector.getCurrentMenu(); + // leagueSelector.update(); + leagueSelector.setScreen(currentMenu); + setCurrentMenu(leagueSelectorCurrentMenu, false); + // leagueSelectorCurrentMenu._doIV(leagueSelector.getSelectedOption()); + } + } + } + } + + protected void startTrack(int levelIndex, int trackIndex) { + // ATTENTION!!! + // WHEN CHANGING THIS CODE, COPY-PASTE TO saveCompletedTrack() !!! + + if (Global.ACRA_ENABLED) { + ACRA.getErrorReporter().putCustomData("level_index:", String.valueOf(levelIndex)); + ACRA.getErrorReporter().putCustomData("track_index:", String.valueOf(trackIndex)); + } + + /*Menu _menu = null; + _menu.back();*/ + + try { + getLevelLoader()._doIII(levelIndex, trackIndex); + } catch (InvalidTrackException e) { + showConfirm(getString(R.string.oops), getString(R.string.e_level_damaged), new Runnable() { + @Override + public void run() { + if (trackSelector.getSelectedOption() + 1 < level.getCount(levelSelector.getSelectedOption())) { + trackSelector.setUnlockedCount(trackSelector.getSelectedOption() + 1); + level.setUnlocked(levelSelector.getSelectedOption(), trackSelector.getUnlockedCount()); + } else { + switch (levelSelector.getSelectedOption()) { + case 0: + if (level.getUnlockedLeagues() < 1) { + level.setUnlockedLeagues(1); + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + } + break; + + case 1: + if (level.getUnlockedLeagues() < 2) { + level.setUnlockedLeagues(2); + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + } + break; + + case 2: + if (level.getUnlockedLeagues() < 3) { + level.setUnlockedLeagues(3); + leagueSelector.setOptions(fullLeaguesList); + leagues = fullLeaguesList; + leagueSelector.setUnlockedCount(level.getUnlockedLeagues()); + } + break; + } + + int newUnlocked = level.getUnlocked(levelSelector.getSelectedOption()) + 1, + tracksCount = level.getCount(levelSelector.getSelectedOption()); + + if (newUnlocked > tracksCount) + newUnlocked = tracksCount; + + levelSelector.setUnlockedCount(levelSelector.getUnlockedCount() + 1); + level.setUnlocked(levelSelector.getSelectedOption(), newUnlocked); + } + } + }, null); + } + } + + public int _jvI() { + int k = 0; + if (driverSpriteOptionItem.getSelectedOption() == 0) + k |= 2; + if (bikeSpriteOptionItem.getSelectedOption() == 0) + k |= 1; + return k; + } + + public void _intIV(int k) { + bikeSpriteOptionItem.setSelectedOption(1); + driverSpriteOptionItem.setSelectedOption(1); + if ((k & 1) > 0) + bikeSpriteOptionItem.setSelectedOption(0); + if ((k & 2) > 0) + driverSpriteOptionItem.setSelectedOption(0); + } + + /*public int _ovI() { + return levelSelector.getSelectedOption(); + } + + public int _nvI() { + return trackSelector.getSelectedOption(); + } + + public int _lvI() { + return leagueSelector.getSelectedOption(); + }*/ + + public void setLastTrackTime(long l) { + lastTrackTime = l; + } + + /*private byte[] readNameChars(int pos, byte defaultValue) { + switch (pos) { + case 16: // '\020' + byte[] abyte0 = new byte[3]; + for (int l = 0; l < 3; l++) + abyte0[l] = settings[16 + l]; + + if (abyte0[0] == -127) + abyte0[0] = defaultValue; + return abyte0; + } + return null; + } + + private byte readSetting(int index, byte defaultValue) { + if (settings[index] == -127) + return defaultValue; + else + return settings[index]; + } + + private void saveNameChars(int pos, byte[] chars) { + if (settingsLoadedOK && pos == 16) { + for (int l = 0; l < 3; l++) + settings[16 + l] = chars[l]; + + } + }*/ + + private String getDurationString(long l) { + m_ajI = (int) (l / 100L); + m_atI = (int) (l % 100L); + String s; + if (m_ajI / 60 < 10) + s = " 0" + m_ajI / 60; + else + s = " " + m_ajI / 60; + if (m_ajI % 60 < 10) + s = s + ":0" + m_ajI % 60; + else + s = s + ":" + m_ajI % 60; + if (m_atI < 10) + s = s + ".0" + m_atI; + else + s = s + "." + m_atI; + return s; + } + + /*private void setSetting(int k, byte byte0) { + if (settingsLoadedOK) + settings[k] = byte0; + }*/ + + private void resetAll() { + Settings.resetAll(); + getLevelsManager().resetAllLevelsSettings(); + getLevelsManager().clearAllHighScores(); + + getGDActivity().fullResetting = true; + getGDActivity().destroyApp(true); + } + + public void removeCommands() { + getGDView().removeCommand(okCommand); + getGDView().removeCommand(backCommand); + } + + public void addCommands() { + if (currentMenu != mainMenu && currentMenu != finishedMenu && currentMenu != null) + getGDView().addCommand(backCommand); + getGDView().addCommand(okCommand); + } + + /*private int _bbII(int k) { + String[] as = RecordStore.listRecordStores(); + if (saveManager == null || as == null) + return 0; + int l = 0; + for (int i1 = 0; i1 < as.length; i1++) + if (as[i1].startsWith("" + k)) + l++; + + return l; + }*/ + + /*public boolean isKeyboardEnabled() { + return keyboardInMenuEnabled == 0; + }*/ + + // public boolean isVibrateOnTouchEnabled() { + // return vibrateOnTouchEnabled == 0; + //} + + /*public void hideKeyboard(boolean firstRun) { + if (!Settings.isKeyboardInMenuEnabled()) { + getGDActivity().hideKeyboardLayout(); + // MenuScreen.setSize(getGDView().getScaledWidth(), getGDView().getScaledHeight()); + } else if (firstRun) { + getGDActivity().showKeyboardLayout(); + }*//*else { + // MenuScreen.setSize(getGDView().getScaledWidth(), getGDView().getScaledHeight() - getGDActivity().getButtonsLayoutHeight()); + }*//* + } + + public void showKeyboard() { + getGDActivity().showKeyboardLayout(); + // MenuScreen.setSize(getGDView().getScaledWidth(), getGDView().getScaledHeight() - getGDActivity().getButtonsLayoutHeight()); + }*/ + + public void installFromFileBrowse() { + if (!LevelsManager.isExternalStorageReadable()) { + showAlert(getString(R.string.error), getString(R.string.e_external_storage_is_not_readable), null); + return; + } + + final GDActivity gd = getGDActivity(); + FileDialog fileDialog = new FileDialog(gd, Environment.getExternalStorageDirectory(), ".mrg"); + fileDialog.addFileListener(new FileDialog.FileSelectedListener() { + public void fileSelected(final File file) { + final EditText input = new EditText(gd); + input.setInputType(InputType.TYPE_CLASS_TEXT); + + AlertDialog.Builder alert = new AlertDialog.Builder(gd) + .setTitle(getString(R.string.enter_levels_name_title)) + .setMessage(getString(R.string.enter_levels_name)) + .setView(input) + .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + boolean ok = true; + String name = input.getText().toString(); + if (name.equals("")) name = file.getName(); + + ProgressDialog progressDialog = ProgressDialog.show(gd, getString(R.string.install), getString(R.string.installing), true); + + try { + gd.levelsManager.install(file, name, "", 0); + } catch (Exception e) { + ok = false; + e.printStackTrace(); + showAlert(getString(R.string.error), e.getMessage(), null); + } finally { + progressDialog.dismiss(); + } + + if (ok) { + gd.levelsManager.showSuccessfullyInstalledDialog(); + } + } + }) + .setNegativeButton(getString(R.string.cancel), null); + alert.show(); + } + }); + fileDialog.showDialog(); + } + + public static boolean isNameCheat(byte[] chars) { + return chars[0] == 82 && chars[1] == 75 && chars[2] == 69; + } + +} diff --git a/src/org/happysanta/gd/Menu/MenuElement.java b/src/org/happysanta/gd/Menu/MenuElement.java new file mode 100644 index 0000000..82fe490 --- /dev/null +++ b/src/org/happysanta/gd/Menu/MenuElement.java @@ -0,0 +1,20 @@ +package org.happysanta.gd.Menu; + +import android.view.View; + +/** + * Author: ch1p + */ +public interface MenuElement { + + // public abstract void setText(String s); + + public abstract boolean isSelectable(); + + public abstract View getView(); + + public abstract void setText(String text); + + public void performAction(int k); + +} diff --git a/src/org/happysanta/gd/Menu/MenuElementOld.java b/src/org/happysanta/gd/Menu/MenuElementOld.java new file mode 100755 index 0000000..6a4400f --- /dev/null +++ b/src/org/happysanta/gd/Menu/MenuElementOld.java @@ -0,0 +1,32 @@ +package org.happysanta.gd.Menu; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.View; + +public interface MenuElementOld { + + public abstract void setText(String s); + + // Why y before x?! + public abstract void draw(Canvas g, int y, int x); + + public abstract boolean isSelectable(); + + public abstract int getLineSpacing(); + + public abstract void performAction(int i); + + public abstract void setFont(Paint font); + + public abstract int getHeight(); + + public abstract int getFirstLineHeight(); + + public abstract int getXOffset(); + + public abstract void setPressed(boolean flag); + + public abstract View getView(); + +} diff --git a/src/org/happysanta/gd/Menu/MenuHandler.java b/src/org/happysanta/gd/Menu/MenuHandler.java new file mode 100755 index 0000000..208e579 --- /dev/null +++ b/src/org/happysanta/gd/Menu/MenuHandler.java @@ -0,0 +1,12 @@ +package org.happysanta.gd.Menu; + +public interface MenuHandler { + + public abstract MenuScreen getCurrentMenu(); + + public abstract void setCurrentMenu(MenuScreen e, boolean flag); + + // public abstract void destroy(); + + public abstract void handleAction(MenuElement item); +} diff --git a/src/org/happysanta/gd/Menu/MenuScreen.java b/src/org/happysanta/gd/Menu/MenuScreen.java new file mode 100755 index 0000000..c49c085 --- /dev/null +++ b/src/org/happysanta/gd/Menu/MenuScreen.java @@ -0,0 +1,277 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.view.ViewTreeObserver; +import android.widget.LinearLayout; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; + +import java.util.Vector; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.isSDK11OrHigher; +import static org.happysanta.gd.Helpers.logDebug; + +public class MenuScreen + implements OnMenuElementHighlightListener { + + public static final int KEY_FIRE = 5; + public static final int KEY_UP = 2; + public static final int KEY_DOWN = 8; + public static final int KEY_LEFT = 4; + public static final int KEY_RIGHT = 6; + + protected static final int LAYOUT_LEFT_PADDING = 30; + protected static final int LAYOUT_TOP_PADDING = 0; + protected static final int LAYOUT_BOTTOM_PADDING = 15; + + protected MenuScreen navTarget; + protected String title; + protected int selectedIndex; + protected Vector menuItems; + protected MenuLinearLayout layout; + protected ClickableMenuElement lastHighlighted; + protected boolean isTextScreen = false; + + public MenuScreen(String title, MenuScreen navTarget) { + this.title = title; + selectedIndex = -1; + menuItems = new Vector(); + this.navTarget = navTarget; + + Context context = getGDActivity(); + + layout = new MenuLinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(getDp(LAYOUT_LEFT_PADDING), getDp(LAYOUT_TOP_PADDING), getDp(LAYOUT_LEFT_PADDING), getDp(LAYOUT_BOTTOM_PADDING)); + + // Disable multi-touch in menu + if (isSDK11OrHigher()) + layout.setMotionEventSplittingEnabled(false); + } + + public void addItem(MenuElement item) { + layout.addView(item.getView()); + menuItems.add(item); + + if (item instanceof ClickableMenuElement) + ((ClickableMenuElement) item).setOnHighlightListener(this); + } + + protected void scrollToItem(MenuElement item) { + // int y = item.getView().getTop(); + // logDebug("scrollTo: y = " + y); + + // getGameMenu().scrollTo(y); + getGDActivity().scrollToView(item.getView()); + } + + public void performAction(int k) { + // logDebug("MenuScreen.performAction: k = " + k); + int from = 0; + switch (k) { + default: + // logDebug("selectedIndex = " + selectedIndex); + if (selectedIndex != -1) { + for (int i = selectedIndex; i < menuItems.size(); i++) { + MenuElement item; + if ((item = (MenuElement) menuItems.elementAt(i)) != null && item.isSelectable()) { + item.performAction(k); + return; + } + } + } + break; + + case KEY_UP: + if (isTextScreen) { + getGDActivity().scrollTextMenuUp(); + return; + } + + if (selectedIndex > 0 && !elementIsFirstClickable(selectedIndex)) { + from = selectedIndex - 1; + } else { + from = menuItems.size() - 1; + } + + for (int i = from; i >= 0; i--) { + MenuElement el = (MenuElement) menuItems.elementAt(i); + if (!(el instanceof ClickableMenuElement) || ((ClickableMenuElement) el).isDisabled()) { + continue; + } + + highlightElement((ClickableMenuElement) el); + selectedIndex = i; + scrollToItem(el); + break; + } + break; + + case KEY_DOWN: + if (isTextScreen) { + getGDActivity().scrollTextMenuDown(); + return; + } + + if (selectedIndex < menuItems.size() - 1) { + from = selectedIndex + 1; + } else { + from = 0; + } + for (int i = from; i < menuItems.size(); i++) { + MenuElement el = (MenuElement) menuItems.elementAt(i); + if (!(el instanceof ClickableMenuElement) || ((ClickableMenuElement) el).isDisabled()) { + continue; + } + + highlightElement((ClickableMenuElement) el); + selectedIndex = i; + scrollToItem(el); + break; + } + break; + } + } + + protected boolean elementIsFirstClickable(int index) { + for (int i = 0; i < menuItems.size(); i++) { + MenuElement el = (MenuElement) menuItems.elementAt(i); + if (!(el instanceof ClickableMenuElement) || ((ClickableMenuElement) el).isDisabled()) { + if (i == index) { + return false; + } + } else { + if (i < index) return false; + if (i == index) return true; + } + } + + return false; + } + + public MenuScreen getNavTarget() { + return navTarget; + } + + public void setNavTarget(MenuScreen target) { + navTarget = target; + } + + /*public void setIsLevelsList(boolean is) { + isLevelsList = is; + }*/ + + public void clear() { + menuItems.removeAllElements(); + layout.removeAllViews(); + + selectedIndex = -1; + lastHighlighted = null; + } + + public LinearLayout getLayout() { + return layout; + } + + protected void setTitle(String s) { + title = s; + } + + protected void updateTitle() { + final GDActivity gd = getGDActivity(); + gd.runOnUiThread(new Runnable() { + @Override + public void run() { + gd.menuTitleTextView.setText(title); + // activity.menuTitleTextView.invalidate(); + gd.titleLayout.invalidate(); + } + }); + } + + public void onHide(MenuScreen newMenu) { + } + + public void onShow() { + updateTitle(); + highlightElement(); + } + + public void resetHighlighted() { + lastHighlighted = null; + } + + public void highlightElement() { + if (lastHighlighted != null) { + lastHighlighted.showHelmet(); + final ViewTreeObserver obs = layout.getViewTreeObserver(); + obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + try { + obs.removeOnPreDrawListener(this); + scrollToItem(lastHighlighted); + } catch (Exception e) { + } + + return true; + } + }); + } else { + for (int i = 0; i < menuItems.size(); i++) { + if (menuItems.elementAt(i) instanceof ClickableMenuElement) { + ClickableMenuElement item = (ClickableMenuElement) menuItems.elementAt(i); + if (item.isDisabled()) continue; + + highlightElement(item); + scrollToItem(lastHighlighted); + selectedIndex = i; + + break; + } + } + } + } + + public void setSelected(int index) { + try { + if (menuItems.elementAt(index) instanceof ClickableMenuElement) { + ClickableMenuElement item = (ClickableMenuElement) menuItems.elementAt(index); + if (item.isDisabled()) return; + + highlightElement(item); + selectedIndex = index; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected void highlightElement(ClickableMenuElement el) { + el.showHelmet(); + lastHighlighted = el; + } + + public void onScroll(double percent) { + } + + @Override + public void onElementHighlight(ClickableMenuElement el) { + lastHighlighted = el; + + int index = menuItems.indexOf(el); + if (index != -1) + selectedIndex = index; + } + + public void setIsTextScreen(boolean isTextScreen) { + this.isTextScreen = isTextScreen; + } + + /*public boolean isTextScreen() { + return isTextScreen; + }*/ + +} diff --git a/src/org/happysanta/gd/Menu/NameInputMenuScreen.java b/src/org/happysanta/gd/Menu/NameInputMenuScreen.java new file mode 100644 index 0000000..e742c7c --- /dev/null +++ b/src/org/happysanta/gd/Menu/NameInputMenuScreen.java @@ -0,0 +1,175 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.MenuLinearLayout; +import org.happysanta.gd.Menu.Views.MenuTextView; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getGameMenu; + +public class NameInputMenuScreen extends MenuScreen { + + protected static final String CURSOR = "^"; + protected static final int WORD_SPACE = 3; + + protected static int wordWidth = 0; + + protected int cursorPosition = 0; + protected byte chars[]; + + protected MenuTextView nameTextViews[]; + protected MenuTextView cursorTextViews[]; + protected MenuLinearLayout nameLayout; + protected MenuLinearLayout cursorLayout; + + static { + wordWidth = getWordWidth(); + } + + public NameInputMenuScreen(String title, MenuScreen navTarget, byte nameChars[]) { + super(title, navTarget); + + chars = nameChars; + + Context context = getGDActivity(); + + nameTextViews = new MenuTextView[3]; + cursorTextViews = new MenuTextView[3]; + + nameLayout = new MenuLinearLayout(context); + nameLayout.setOrientation(LinearLayout.HORIZONTAL); + + cursorLayout = new MenuLinearLayout(context); + cursorLayout.setOrientation(LinearLayout.HORIZONTAL); + + for (int i = 0; i < 3; i++) { + nameTextViews[i] = createTextView(); + nameLayout.addView(nameTextViews[i]); + + cursorTextViews[i] = createTextView(); + cursorLayout.addView(cursorTextViews[i]); + } + + layout.addView(nameLayout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + layout.addView(cursorLayout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + updateText(); + updateCursorPosition(); + } + + protected MenuTextView createTextView() { + Context context = getGDActivity(); + MenuTextView textView = new MenuTextView(context); + textView.setTextColor(0xff000000); + textView.setTypeface(Global.robotoCondensedTypeface); + textView.setTextSize(ClickableMenuElement.TEXT_SIZE); + textView.setLayoutParams(new LinearLayout.LayoutParams( + wordWidth, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + return textView; + } + + protected static int getWordWidth() { + Context context = getGDActivity(); + + String text = "W"; + TextView textView = new TextView(context); + textView.setTextSize(ClickableMenuElement.TEXT_SIZE); + textView.setTypeface(Global.robotoCondensedTypeface); + + Rect bounds = new Rect(); + + Paint textPaint = textView.getPaint(); + textPaint.getTextBounds(text, 0, text.length(), bounds); + + return bounds.width() + getDp(WORD_SPACE); + } + + @Override + public void performAction(int k) { + switch (k) { + default: + break; + + case MenuScreen.KEY_FIRE: // select + if (cursorPosition == 2) { + getGameMenu().setCurrentMenu(navTarget, false); + } else { + cursorPosition++; + updateCursorPosition(); + } + break; + + case MenuScreen.KEY_RIGHT: // right + cursorPosition++; + if (cursorPosition > 2) { + cursorPosition = 2; + } + updateCursorPosition(); + break; + + case MenuScreen.KEY_LEFT: // left + cursorPosition--; + if (cursorPosition < 0) + cursorPosition = 0; + updateCursorPosition(); + break; + + case MenuScreen.KEY_UP: // up + if (chars[cursorPosition] == 32) { + chars[cursorPosition] = 65; + updateText(); + break; + } + chars[cursorPosition]++; + if (chars[cursorPosition] > 90) { + chars[cursorPosition] = 32; + } + updateText(); + break; + + case MenuScreen.KEY_DOWN: // down + if (chars[cursorPosition] == 32) { + chars[cursorPosition] = 90; + updateText(); + break; + } + chars[cursorPosition]--; + if (chars[cursorPosition] < 65) { + chars[cursorPosition] = 32; + } + updateText(); + break; + } + } + + protected void updateText() { + for (int i = 0; i < nameTextViews.length; i++) { + nameTextViews[i].setTextOnUiThread(String.valueOf((char) chars[i])); + } + } + + protected void updateCursorPosition() { + for (int i = 0; i < cursorTextViews.length; i++) { + cursorTextViews[i].setTextOnUiThread(i == cursorPosition ? CURSOR : ""); + } + } + + public byte[] getChars() { + return chars; + } + + public void resetCursorPosition() { + cursorPosition = 0; + updateCursorPosition(); + } + +} diff --git a/src/org/happysanta/gd/Menu/OnMenuElementHighlightListener.java b/src/org/happysanta/gd/Menu/OnMenuElementHighlightListener.java new file mode 100644 index 0000000..f065bf1 --- /dev/null +++ b/src/org/happysanta/gd/Menu/OnMenuElementHighlightListener.java @@ -0,0 +1,10 @@ +package org.happysanta.gd.Menu; + +/** + * Author: ch1p + */ +public interface OnMenuElementHighlightListener { + + public abstract void onElementHighlight(ClickableMenuElement el); + +} diff --git a/src/org/happysanta/gd/Menu/OptionsMenuElement.java b/src/org/happysanta/gd/Menu/OptionsMenuElement.java new file mode 100644 index 0000000..2119b32 --- /dev/null +++ b/src/org/happysanta/gd/Menu/OptionsMenuElement.java @@ -0,0 +1,301 @@ +package org.happysanta.gd.Menu; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.MenuImageView; +import org.happysanta.gd.Menu.Views.MenuTextView; +import org.happysanta.gd.R; +// import com.grishka.agdtr.R; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getString; +import static org.happysanta.gd.Helpers.logDebug; + +public class OptionsMenuElement + extends ClickableMenuElement + implements MenuElement, MenuHandler { + + protected int selectedIndex; + protected String options[]; + protected int unlockedCount; + protected MenuHandler handler; + protected MenuScreen optionsScreen = null; + protected MenuScreen screen = null; + protected boolean isOnOffToggle; + protected boolean m_oZ = false; + protected String selectedOption; + protected ActionMenuElement optionsScreenItems[] = null; + protected MenuImageView lockImage = null; + protected MenuTextView optionTextView = null; + + public OptionsMenuElement(String text, int selectedIndex, MenuHandler handler, String options[], boolean isOnOffToggle, MenuScreen screen) { + this.text = text; + this.selectedIndex = selectedIndex; + this.handler = handler; + this.options = options; + if (this.options == null) this.options = new String[]{""}; + unlockedCount = this.options.length - 1; + this.isOnOffToggle = isOnOffToggle; + + createAllViews(); + setSelectedOption(selectedIndex); + + if (isOnOffToggle) { + if (selectedIndex == 1) { + selectedOption = getString(R.string.off); + } else { + selectedOption = getString(R.string.on); + } + } else { + this.screen = screen; + updateSelectedOption(); + update(); + } + } + + @Override + protected void createAllViews() { + Context context = getGDActivity(); + + super.createAllViews(); + + textView.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + + optionTextView = new MenuTextView(context); + optionTextView.setText(selectedOption); + optionTextView.setTextColor(getMenuTextView().getTextColors()); + optionTextView.setTextSize(TEXT_SIZE); + optionTextView.setTypeface(Global.robotoCondensedTypeface); + optionTextView.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + )); + optionTextView.setPadding( + textView.getPaddingLeft(), + textView.getPaddingTop(), + textView.getPaddingRight(), + textView.getPaddingBottom() + ); + + lockImage = new MenuImageView(context); + lockImage.setImageResource(ActionMenuElement.locks[0]); + lockImage.setScaleType(ImageView.ScaleType.CENTER); + lockImage.setVisibility(View.GONE); + + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT); + lp.setMargins(0, 0, getDp(ActionMenuElement.LOCK_IMAGE_MARGIN_RIGHT), 0); + lockImage.setLayoutParams(lp); + lockImage.setVisibility(View.GONE); + + layout.addView(lockImage); + layout.addView(optionTextView); + } + + private void updateSelectedOption() { + selectedOption = options[selectedIndex]; + updateViewText(); + + if (selectedIndex > unlockedCount && !isOnOffToggle) { + lockImage.setVisibility(View.VISIBLE); + } else { + lockImage.setVisibility(View.GONE); + } + } + + public int getUnlockedCount() { + return unlockedCount; + } + + public void setUnlockedCount(int k) { + unlockedCount = k; + if (unlockedCount > options.length - 1) + unlockedCount = options.length - 1; + if (optionsScreen != null) { + for (int l = 0; l < optionsScreenItems.length; l++) + if (l > k) + optionsScreenItems[l].setLock(true, true); + else + optionsScreenItems[l].setLock(false, false); + } + updateSelectedOption(); + } + + public int getOptionCount() { + return options.length - 1; + } + + public String[] getOptions() { + return options; + } + + public void setOptions(String as[]) { + setOptions(as, true); + } + + public void setOptions(String as[], boolean update) { + options = as; + if (selectedIndex > options.length - 1) + selectedIndex = options.length - 1; + if (unlockedCount > options.length - 1) + unlockedCount = options.length - 1; + updateSelectedOption(); + if (update) update(); + } + + public int getSelectedOption() { + return selectedIndex; + } + + public void setSelectedOption(int k) { + selectedIndex = k; + if (selectedIndex > options.length - 1) + selectedIndex = 0; + if (selectedIndex < 0) + selectedIndex = options.length - 1; + updateSelectedOption(); + } + + public void update() { + optionsScreen = new MenuScreen(text, screen); + optionsScreenItems = new ActionMenuElement[options.length]; + for (int k = 0; k < optionsScreenItems.length; k++) { + if (k > unlockedCount) { + optionsScreenItems[k] = new ActionMenuElement(options[k], this); + optionsScreenItems[k].setLock(true, true); + } else { + optionsScreenItems[k] = new ActionMenuElement(options[k], this); + } + optionsScreen.addItem(optionsScreenItems[k]); + } + optionsScreen.setSelected(selectedIndex); + + // System.gc(); + } + + public boolean _charvZ() { + if (m_oZ) { + m_oZ = false; + return true; + } else { + return m_oZ; + } + } + + @Override + public void handleAction(MenuElement item) { + int k = 0; + do { + if (k >= optionsScreenItems.length) + break; + if (item == optionsScreenItems[k]) { + selectedIndex = k; + updateSelectedOption(); + break; + } + k++; + } while (true); + + handler.setCurrentMenu(screen, true); + handler.handleAction(this); + } + + @Override + public MenuScreen getCurrentMenu() { + return optionsScreen; + } + + @Override + public void setCurrentMenu(MenuScreen e1, boolean flag) { + } + + @Override + protected void updateViewText() { + if (textView != null && textView instanceof MenuTextView) + ((MenuTextView) textView).setTextOnUiThread(getTextForView()); + if (optionTextView != null) optionTextView.setTextOnUiThread(selectedOption); + } + + @Override + public void performAction(int k) { + // logDebug("OptionMenuElement performAction: k = " + k); + switch (k) { + case MenuScreen.KEY_FIRE: + if (isOnOffToggle) { + selectedIndex++; + if (selectedIndex > 1) + selectedIndex = 0; + if (selectedIndex == 1) + selectedOption = getString(R.string.off); + else + selectedOption = getString(R.string.on); + updateViewText(); + handler.handleAction(this); + return; + } else { + m_oZ = true; + handler.handleAction(this); + return; + } + + case MenuScreen.KEY_RIGHT: + if (isOnOffToggle) { + if (selectedIndex == 1) { + selectedIndex = 0; + selectedOption = getString(R.string.on); + handler.handleAction(this); + updateViewText(); + } + return; + } + selectedIndex++; + if (selectedIndex > options.length - 1) + selectedIndex = options.length - 1; + else + handler.handleAction(this); + updateSelectedOption(); + return; + + case MenuScreen.KEY_LEFT: // '\003' + if (isOnOffToggle) { + if (selectedIndex == 0) { + selectedIndex = 1; + selectedOption = getString(R.string.off); + handler.handleAction(this); + updateViewText(); + } + return; + } + selectedIndex--; + if (selectedIndex < 0) { + selectedIndex = 0; + } else { + updateSelectedOption(); + handler.handleAction(this); + } + updateSelectedOption(); + break; + } + } + + public void setScreen(MenuScreen screen) { + this.screen = screen; + } + + @Override + protected String getTextForView() { + return text + ": "; + } + + @Override + protected void onHighlightChanged() { + lockImage.setImageResource(ActionMenuElement.locks[isHighlighted ? 2 : 0]); + } + +} diff --git a/src/org/happysanta/gd/Menu/SimpleMenuElement.java b/src/org/happysanta/gd/Menu/SimpleMenuElement.java new file mode 100755 index 0000000..57842f5 --- /dev/null +++ b/src/org/happysanta/gd/Menu/SimpleMenuElement.java @@ -0,0 +1,176 @@ +package org.happysanta.gd.Menu; + +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.View; +import android.view.ViewGroup; +import org.happysanta.gd.Global; +import org.happysanta.gd.Menu.Views.MenuTextView; + +import java.util.TimerTask; + +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getGDView; + +public class SimpleMenuElement extends TimerTask + implements MenuElementOld { + + // public static final int LINE_SPACING = 15; + protected static Paint gFont; + + public int x; + public int y; + public int m_bI; + public int m_eI; + public int m_dI; + public int m_gotoI; + public int m_nullI; + public int m_longI; + public int m_fI; + int m_cI; + // GDActivity activity; + protected String text; + protected MenuScreen m_we; + protected MenuHandler m_hc; + protected Paint font; + protected boolean isPressed = false; + protected MenuTextView textView; + + /*static { + gFont = ActionMenuElement.getGFont(); + }*/ + + public SimpleMenuElement() { + init(); + } + + public SimpleMenuElement(int k) { + m_cI = k; + font = gFont; + } + + public SimpleMenuElement(String s, MenuScreen e1, MenuHandler c1) { + text = s + ">"; + m_we = e1; + m_hc = c1; + font = gFont; + + textView = new MenuTextView(getGDActivity()); + textView.setText(text); + textView.setTextColor(0xff000000); + // textView.setTextColor(R.drawable.menu_item_color); + textView.setTypeface(Global.robotoCondensedTypeface); + textView.setTextSize(20); + textView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + } + + public void init() { + x = y = m_bI = 0; + m_eI = m_dI = m_gotoI = 0; + m_nullI = m_longI = m_fI = 0; + } + + @Override + public View getView() { + return textView; + } + + @Override + public void run() { + getGDView()._tryIV(m_cI); + } + + @Override + public void setText(String s) { + text = s + ">"; + } + + public String getText() { + return text; + } + + @Override + public boolean isSelectable() { + return true; + } + + @Override + public void performAction(int k) { + /*switch (k) { + case MenuScreen.KEY_FIRE: + case MenuScreen.KEY_RIGHT: + m_hc.handleAction(this); + m_we.setNavTarget(m_hc.getCurrentMenu()); + m_hc.setCurrentMenu(m_we, false); + // fall through + + case 3: // '\003' + default: + return; + }*/ + } + + /* public void _aeV(MenuScreen e1) { + screen = e1; + } */ + + @Override + public void draw(Canvas g, int y, int x) { + // if (isPressed) + // setPressedColor(); + g.drawText(text, x, y - font.ascent(), font); + // if (isPressed) + // setNormalColor(); + } + + @Override + public int getLineSpacing() { + return ActionMenuElement.LINE_SPACING; + } + + @Override + public void setFont(Paint font) { + this.font = font; + } + + @Override + public int getHeight() { + return Math.round(font.descent() - font.ascent()); + } + + @Override + public int getFirstLineHeight() { + return getHeight(); + } + + /* @Override + public int getHeight() { + return getHeight() + getLineSpacing(); + } */ + + @Override + public int getXOffset() { + return ActionMenuElement.X_OFFSET; + } + + @Override + public void setPressed(boolean flag) { + isPressed = flag; + } + + /*protected void setPressedColor() { + font.setColor(ActionMenuElement.PRESSED_COLOR); + } + + protected void setNormalColor() { + font.setColor(ActionMenuElement.NORMAL_COLOR); + }*/ + +} diff --git a/src/org/happysanta/gd/Menu/SimpleMenuElementNew.java b/src/org/happysanta/gd/Menu/SimpleMenuElementNew.java new file mode 100644 index 0000000..474a6ad --- /dev/null +++ b/src/org/happysanta/gd/Menu/SimpleMenuElementNew.java @@ -0,0 +1,77 @@ +package org.happysanta.gd.Menu; + +import static org.happysanta.gd.Helpers.logDebug; + +public class SimpleMenuElementNew extends ClickableMenuElement + implements MenuElement { + + // protected static Paint gFont; + + public int x; + public int y; + /* public int m_bI; + public int m_eI; + public int m_dI; + public int m_gotoI; + public int m_nullI; + public int m_longI; + public int m_fI; + int m_cI; */ + protected MenuScreen screen; + protected MenuHandler handler; + // protected Paint font; + // protected boolean isPressed = false; + + /* static { + gFont = ActionMenuElement.getGFont(); + } */ + + /* public SimpleMenuElementNew() { + init(); + } + + public SimpleMenuElementNew(int k) { + m_cI = k; + // font = gFont; + } */ + + public SimpleMenuElementNew(String text, MenuScreen screen, MenuHandler handler) { + this.text = text + ">"; + this.screen = screen; + this.handler = handler; + + createAllViews(); + + // textView = createAllViews(); + } + + /* public void init() { + x = y = m_bI = 0; + m_eI = m_dI = m_gotoI = 0; + m_nullI = m_longI = m_fI = 0; + } */ + + @Override + public void setText(String s) { + super.setText(s + ">"); + } + + // @Override + public void performAction(int k) { + logDebug("SimpleMenuElementNew performAction k = " + k); + + switch (k) { + case MenuScreen.KEY_FIRE: + case MenuScreen.KEY_RIGHT: + handler.handleAction(this); + screen.setNavTarget(handler.getCurrentMenu()); + handler.setCurrentMenu(screen, false); + break; + } + } + + /* public void _aeV(MenuScreen e1) { + screen = e1; + } */ + +} diff --git a/src/org/happysanta/gd/Menu/TextMenuElement.java b/src/org/happysanta/gd/Menu/TextMenuElement.java new file mode 100755 index 0000000..7485389 --- /dev/null +++ b/src/org/happysanta/gd/Menu/TextMenuElement.java @@ -0,0 +1,80 @@ +package org.happysanta.gd.Menu; + +// Decompiled by Jad v1.5.8f. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) fieldsfirst ansi + +import android.content.Context; +import android.text.Html; +import android.text.Spanned; +import android.text.SpannedString; +import android.text.util.Linkify; +import android.view.View; +import android.view.ViewGroup; +import org.happysanta.gd.Menu.Views.MenuTextView; + +import static org.happysanta.gd.Helpers.getGDActivity; + +public class TextMenuElement + implements MenuElement { + + protected static final int TEXT_SIZE = 15; + protected static final int TEXT_COLOR = 0xff000000; + + protected Spanned spanned; + protected MenuTextView textView; + + public TextMenuElement(String text) { + this.spanned = SpannedString.valueOf(text); + textView = createTextView(); + } + + public TextMenuElement(Spanned text) { + this.spanned = text; + textView = createTextView(); + } + + protected MenuTextView createTextView() { + Context activity = getGDActivity(); + + MenuTextView textView = new MenuTextView(activity); + textView.setText(spanned); + textView.setTextColor(TEXT_COLOR); + textView.setTextSize(TEXT_SIZE); + textView.setLineSpacing(0f, 1.5f); + textView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + + Linkify.addLinks(textView, Linkify.WEB_URLS); + textView.setLinksClickable(true); + + return textView; + } + + @Override + public View getView() { + return textView; + } + + public String getText() { + return spanned.toString(); + } + + @Override + public void setText(String text) { + this.spanned = Html.fromHtml(text); + textView.setTextOnUiThread(spanned); + } + + @Override + public boolean isSelectable() { + return false; + } + + @Override + public void performAction(int k) { + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/LevelNameLeadingMarginSpan2.java b/src/org/happysanta/gd/Menu/Views/LevelNameLeadingMarginSpan2.java new file mode 100644 index 0000000..09c744d --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/LevelNameLeadingMarginSpan2.java @@ -0,0 +1,38 @@ +package org.happysanta.gd.Menu.Views; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.Layout; +import android.text.style.LeadingMarginSpan; + +public class LevelNameLeadingMarginSpan2 implements LeadingMarginSpan.LeadingMarginSpan2 { + + private int margin; + private int lines; + + public LevelNameLeadingMarginSpan2(int lines, int margin) { + this.margin = margin; + this.lines = lines; + } + + @Override + public int getLeadingMargin(boolean first) { + if (first) { + return margin; + } else { + return 0; + } + } + + @Override + public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, + int top, int baseline, int bottom, CharSequence text, + int start, int end, boolean first, Layout layout) { + } + + @Override + public int getLeadingMarginLineCount() { + return lines; + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuHelmetView.java b/src/org/happysanta/gd/Menu/Views/MenuHelmetView.java new file mode 100644 index 0000000..bb2a37a --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuHelmetView.java @@ -0,0 +1,111 @@ +package org.happysanta.gd.Menu.Views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import org.happysanta.gd.Game.Bitmap; +import org.happysanta.gd.Global; + +import static org.happysanta.gd.Helpers.getDp; +import static org.happysanta.gd.Helpers.isSDK11OrHigher; +import static org.happysanta.gd.Helpers.logDebug; + +public class MenuHelmetView extends View { + + protected static final int WIDTH = 8; + protected static final int HEIGHT = 8; + /*protected static final int PADDING_LEFT = 0; + protected static final int PADDING_TOP = 5; + protected static final int PADDING_RIGHT = 5; + protected static final int PADDING_BOTTOM = 0;*/ + + protected static int angle = 0; + protected static long angleLastMs = 0; + protected static final int angleInterval = 50; + protected static final int angleDelta = 10; + + protected boolean show = false; + protected boolean _setMeasuredHeight = false; + protected Bitmap helmet = Bitmap.get(Bitmap.HELMET); + protected static MenuHelmetView lastActive = null; + + public static void clearStaticFields() { + lastActive = null; + angle = 0; + angleLastMs = 0; + } + + public MenuHelmetView(Context context) { + super(context); + } + + public MenuHelmetView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + } + + @Override + public void onDraw(Canvas canvas) { + canvas.save(); + canvas.scale(Global.density, Global.density); + + drawHelmet(canvas); + + canvas.restore(); + invalidate(); + } + + protected void drawHelmet(Canvas canvas) { + if (show) { + long ms = System.currentTimeMillis(); + if (angleLastMs == 0 || ms - angleLastMs >= angleInterval) { + angle += angleDelta; + if (angle >= 360) angle -= 360; + angleLastMs = ms; + } + + int y = getScaledHeight() / 2 - helmet.getHeightDp() / 2; + + canvas.save(); + canvas.rotate(angle, helmet.getWidthDp() / 2, y + helmet.getHeightDp() / 2); + canvas.drawBitmap(helmet.bitmap, new Rect(0, 0, helmet.getWidth(), helmet.getHeight()), new RectF(0, y, helmet.getWidthDp(), y + helmet.getHeightDp()), null); + canvas.restore(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.getSize(getDp(WIDTH * 2.2f)); + int height = heightMeasureSpec; + if (_setMeasuredHeight) + height = MeasureSpec.getSize(getDp(HEIGHT * 2.2f)); + else if (!isSDK11OrHigher()) { + height = MeasureSpec.getSize(getDp(HEIGHT * 4.5f)); + } + setMeasuredDimension(width, height); + } + + public void setShow(boolean show) { + setShow(show, true); + } + + public void setShow(boolean show, boolean checkLast) { + if (checkLast && lastActive != null) { + lastActive.setShow(false, false); + } + this.show = show; + lastActive = this; + } + + protected int getScaledHeight() { + return Math.round(getHeight() / Global.density); + } + + public void setMeasuredHeight(boolean setMeasuredHeight) { + this._setMeasuredHeight = setMeasuredHeight; + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuImageView.java b/src/org/happysanta/gd/Menu/Views/MenuImageView.java new file mode 100644 index 0000000..1ef3f70 --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuImageView.java @@ -0,0 +1,34 @@ +package org.happysanta.gd.Menu.Views; + +import android.content.Context; +import android.widget.ImageView; + +import static org.happysanta.gd.Helpers.runOnUiThread; + +public class MenuImageView extends ImageView { + + public MenuImageView(Context context) { + super(context); + } + + @Override + public void setImageResource(final int resid) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuImageView.super.setImageResource(resid); + } + }); + } + + @Override + public void setVisibility(final int visibility) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuImageView.super.setVisibility(visibility); + } + }); + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuLinearLayout.java b/src/org/happysanta/gd/Menu/Views/MenuLinearLayout.java new file mode 100644 index 0000000..98f665e --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuLinearLayout.java @@ -0,0 +1,68 @@ +package org.happysanta.gd.Menu.Views; + +import android.content.Context; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; + +import static org.happysanta.gd.Helpers.runOnUiThread; + +public class MenuLinearLayout extends LinearLayout { + + boolean interceptTouchEvents = false; + + public MenuLinearLayout(Context context) { + super(context); + } + + public MenuLinearLayout(Context context, boolean interceptTouchEvents) { + super(context); + this.interceptTouchEvents = interceptTouchEvents; + } + + @Override + public void removeAllViews() { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuLinearLayout.super.removeAllViews(); + } + }); + } + + @Override + public void setVisibility(final int visibility) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuLinearLayout.super.setVisibility(visibility); + } + }); + } + + @Override + public void addView(final View view) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuLinearLayout.super.addView(view); + } + }); + } + + @Override + public void setPadding(final int left, final int top, final int right, final int bottom) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuLinearLayout.super.setPadding(left, top, right, bottom); + } + }); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent evt) { + return interceptTouchEvents; + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuRelativeLayout.java b/src/org/happysanta/gd/Menu/Views/MenuRelativeLayout.java new file mode 100644 index 0000000..3e5e0d2 --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuRelativeLayout.java @@ -0,0 +1,55 @@ +package org.happysanta.gd.Menu.Views; + +import android.content.Context; +import android.view.View; +import android.widget.RelativeLayout; + +import static org.happysanta.gd.Helpers.runOnUiThread; + +public class MenuRelativeLayout extends RelativeLayout { + + public MenuRelativeLayout(Context context) { + super(context); + } + + @Override + public void removeAllViews() { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuRelativeLayout.super.removeAllViews(); + } + }); + } + + @Override + public void setVisibility(final int visibility) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuRelativeLayout.super.setVisibility(visibility); + } + }); + } + + @Override + public void addView(final View view) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuRelativeLayout.super.addView(view); + } + }); + } + + @Override + public void setPadding(final int left, final int top, final int right, final int bottom) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuRelativeLayout.super.setPadding(left, top, right, bottom); + } + }); + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuTextView.java b/src/org/happysanta/gd/Menu/Views/MenuTextView.java new file mode 100644 index 0000000..4b48f5f --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuTextView.java @@ -0,0 +1,73 @@ +package org.happysanta.gd.Menu.Views; + +import android.content.Context; +import android.graphics.Typeface; +import android.widget.TextView; + +import static org.happysanta.gd.Helpers.runOnUiThread; + +public class MenuTextView extends TextView { + + protected boolean isAttached = false; + + public MenuTextView(Context context) { + super(context); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + isAttached = true; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + isAttached = false; + } + + @Override + public boolean isAttachedToWindow() { + return isAttached; + } + + public void setTextOnUiThread(final CharSequence sequence) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuTextView.super.setText(sequence); + } + }); + } + + @Override + public void setTextSize(final float size) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuTextView.super.setTextSize(size); + } + }); + } + + @Override + public void setTypeface(final Typeface typeface) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuTextView.super.setTypeface(typeface); + } + }); + } + + @Override + public void setVisibility(final int visibility) { + runOnUiThread(new Runnable() { + @Override + public void run() { + MenuTextView.super.setVisibility(visibility); + } + }); + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuTitleLinearLayout.java b/src/org/happysanta/gd/Menu/Views/MenuTitleLinearLayout.java new file mode 100644 index 0000000..5c3f790 --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuTitleLinearLayout.java @@ -0,0 +1,39 @@ +package org.happysanta.gd.Menu.Views; + +import android.app.Activity; +import android.widget.RelativeLayout; + +import static org.happysanta.gd.Helpers.logDebug; + +public class MenuTitleLinearLayout extends RelativeLayout { + + private Callback onSizeChangedCallback = null; + + public MenuTitleLinearLayout(Activity activity) { + super(activity); + } + + @Override + public void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + if (onSizeChangedCallback != null) { + onSizeChangedCallback.run(w, h, oldw, oldh); + } + } + + /*public void forceInvokeOnSizeChangedCallback() { + if (onSizeChangedCallback != null) { + onSizeChangedCallback.run(getWidth(), getHeight(), 0, 0); + } + }*/ + + public void setOnSizeChangedCallback(Callback callback) { + onSizeChangedCallback = callback; + } + + public interface Callback { + public abstract void run(int w, int h, int oldw, int oldh); + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/MenuView.java b/src/org/happysanta/gd/Menu/Views/MenuView.java new file mode 100644 index 0000000..ba47071 --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/MenuView.java @@ -0,0 +1,12 @@ +package org.happysanta.gd.Menu.Views; + +import android.view.View; +import org.happysanta.gd.GDActivity; + +public class MenuView extends View { + + public MenuView(GDActivity activity) { + super(activity); + } + +} diff --git a/src/org/happysanta/gd/Menu/Views/ObservableScrollView.java b/src/org/happysanta/gd/Menu/Views/ObservableScrollView.java new file mode 100644 index 0000000..5801928 --- /dev/null +++ b/src/org/happysanta/gd/Menu/Views/ObservableScrollView.java @@ -0,0 +1,31 @@ +package org.happysanta.gd.Menu.Views; + +import android.content.Context; +import android.widget.ScrollView; + +public class ObservableScrollView + extends ScrollView { + + private OnScrollListener scrollListener = null; + + public ObservableScrollView(Context context) { + super(context); + } + + public void setOnScrollListener(OnScrollListener scrollListener) { + this.scrollListener = scrollListener; + } + + @Override + protected void onScrollChanged(int x, int y, int oldx, int oldy) { + super.onScrollChanged(x, y, oldx, oldy); + if (scrollListener != null) { + scrollListener.onScroll(this, x, y, oldx, oldy); + } + } + + public interface OnScrollListener { + public abstract void onScroll(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); + } + +} diff --git a/src/org/happysanta/gd/Settings.java b/src/org/happysanta/gd/Settings.java new file mode 100644 index 0000000..93857ca --- /dev/null +++ b/src/org/happysanta/gd/Settings.java @@ -0,0 +1,215 @@ +package org.happysanta.gd; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; +import org.happysanta.gd.API.API; + +import static org.happysanta.gd.Helpers.getGDActivity; + +public class Settings { + + private static final String LEVEL_ID = "level_id"; + private static final int LEVEL_ID_DEFAULT = 0; + + private static final String PERSPECTIVE_ENABLED = "perspective_enabled"; + private static final boolean PERSPECTIVE_ENABLED_DEFAULT = true; + + private static final String SHADOWS_ENABLED = "shadows_enabled"; + private static final boolean SHADOWS_ENABLED_DEFAULT = true; + + private static final String DRIVER_SPRITE_ENABLED = "driver_sprite_enabled"; + private static final boolean DRIVER_SPRITE_ENABLED_DEFAULT = true; + + private static final String BIKE_SPRITE_ENABLED = "bike_sprite_enabled"; + private static final boolean BIKE_SPRITE_ENABLED_DEFAULT = true; + + private static final String INPUT_OPTION = "input_option"; + private static final int INPUT_OPTION_DEFAULT = 0; + + private static final String LOOK_AHEAD_ENABLED = "look_ahead_enabled"; + private static final boolean LOOK_AHEAD_ENABLED_DEFAULT = true; + + private static final String VIBRATE_ENABLED = "vibrate_enabled"; + private static final boolean VIBRATE_ENABLED_DEFAULT = true; + + private static final String KEYBOARD_IN_MENU_ENABLED = "keyboard_enabled"; + private static final boolean KEYBOARD_IN_MENU_ENABLED_DEFAULT = true; + + private static final String LAST_SEND_STATS = "last_send_stats"; + private static final long LAST_SEND_STATS_DEFAULT = 0; + + private static final String NAME = "name"; + public static final String NAME_DEFAULT = "AAA"; + public static final byte[] NAME_CHARS_DEFALUT = new byte[]{65, 65, 65}; + + private static final String LEVELS_SORT = "level_sort"; // in download list + private static final int LEVELS_SORT_DEFAULT = 0; + + private static SharedPreferences preferences; + + static { + preferences = getGDActivity().getSharedPreferences("GDSettings", Context.MODE_PRIVATE); + } + + public static void resetAll() { + setPerspectiveEnabled(PERSPECTIVE_ENABLED_DEFAULT); + setShadowsEnabled(SHADOWS_ENABLED_DEFAULT); + setDriverSpriteEnabled(DRIVER_SPRITE_ENABLED_DEFAULT); + setBikeSpriteEnabled(BIKE_SPRITE_ENABLED_DEFAULT); + setLookAheadEnabled(LOOK_AHEAD_ENABLED_DEFAULT); + setVibrateOnTouchEnabled(VIBRATE_ENABLED_DEFAULT); + setKeyboardInMenuEnabled(KEYBOARD_IN_MENU_ENABLED_DEFAULT); + setInputOption(INPUT_OPTION_DEFAULT); + setLevelsSort(LEVELS_SORT_DEFAULT); + setName(NAME_CHARS_DEFALUT); + } + + public static long getLevelId() { + return preferences.getLong(LEVEL_ID, LEVEL_ID_DEFAULT); + } + + public static void setLevelId(long levelId) { + setLong(LEVEL_ID, levelId); + } + + public static boolean isPerspectiveEnabled() { + return preferences.getBoolean(PERSPECTIVE_ENABLED, PERSPECTIVE_ENABLED_DEFAULT); + } + + public static void setPerspectiveEnabled(boolean enabled) { + setBoolean(PERSPECTIVE_ENABLED, enabled); + } + + public static boolean isShadowsEnabled() { + return preferences.getBoolean(SHADOWS_ENABLED, SHADOWS_ENABLED_DEFAULT); + } + + public static void setShadowsEnabled(boolean enabled) { + setBoolean(SHADOWS_ENABLED, enabled); + } + + public static boolean isDriverSpriteEnabled() { + return preferences.getBoolean(DRIVER_SPRITE_ENABLED, DRIVER_SPRITE_ENABLED_DEFAULT); + } + + public static void setDriverSpriteEnabled(boolean enabled) { + setBoolean(DRIVER_SPRITE_ENABLED, enabled); + } + + public static boolean isBikeSpriteEnabled() { + return preferences.getBoolean(BIKE_SPRITE_ENABLED, BIKE_SPRITE_ENABLED_DEFAULT); + } + + public static void setBikeSpriteEnabled(boolean enabled) { + setBoolean(BIKE_SPRITE_ENABLED, enabled); + } + + public static boolean isLookAheadEnabled() { + return preferences.getBoolean(LOOK_AHEAD_ENABLED, LOOK_AHEAD_ENABLED_DEFAULT); + } + + public static void setLookAheadEnabled(boolean enabled) { + setBoolean(LOOK_AHEAD_ENABLED, enabled); + } + + public static boolean isKeyboardInMenuEnabled() { + return preferences.getBoolean(KEYBOARD_IN_MENU_ENABLED, KEYBOARD_IN_MENU_ENABLED_DEFAULT); + } + + public static void setKeyboardInMenuEnabled(boolean enabled) { + setBoolean(KEYBOARD_IN_MENU_ENABLED, enabled); + } + + public static boolean isVibrateOnTouchEnabled() { + return preferences.getBoolean(VIBRATE_ENABLED, VIBRATE_ENABLED_DEFAULT); + } + + public static void setVibrateOnTouchEnabled(boolean enabled) { + setBoolean(VIBRATE_ENABLED, enabled); + } + + public static int getInputOption() { + return preferences.getInt(INPUT_OPTION, INPUT_OPTION_DEFAULT); + } + + public static void setInputOption(int value) { + setInt(INPUT_OPTION, value); + } + + public static long getLastSendStats() { + return preferences.getLong(LAST_SEND_STATS, LAST_SEND_STATS_DEFAULT); + } + + public static void setLastSendStats(long value) { + setLong(LAST_SEND_STATS, value); + } + + public static API.LevelsSortType getLevelsSort() { + return API.getSortTypeById(preferences.getInt(LEVELS_SORT, LEVELS_SORT_DEFAULT)); + } + + public static void setLevelsSort(API.LevelsSortType type) { + setInt(LEVELS_SORT, API.getIdBySortType(type)); + } + + public static void setLevelsSort(int type) { + setInt(LEVELS_SORT, type); + } + + public static byte[] getName() { + String name = preferences.getString(NAME, NAME_DEFAULT); + if (name.length() < 3) { + name = NAME_DEFAULT; + } + return new byte[]{ + (byte) name.charAt(0), + (byte) name.charAt(1), + (byte) name.charAt(2) + }; + } + + public static void setName(byte[] chars) { + if (chars.length < 3) { + setString(NAME, NAME_DEFAULT); + } else { + String name = ""; + for (int i = 0; i < 3; i++) { + name += String.valueOf((char) chars[i]); + } + setString(NAME, name); + } + } + + private static void setLong(String key, long value) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putLong(key, value); + editorApply(editor); + } + + private static void setInt(String key, int value) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt(key, value); + editorApply(editor); + } + + private static void setBoolean(String key, boolean value) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(key, value); + editorApply(editor); + } + + private static void setString(String key, String value) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(key, value); + editorApply(editor); + } + + private static void editorApply(SharedPreferences.Editor editor) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) + editor.apply(); + else + editor.commit(); + } + +} diff --git a/src/org/happysanta/gd/Storage/HighScores.java b/src/org/happysanta/gd/Storage/HighScores.java new file mode 100644 index 0000000..e3678c9 --- /dev/null +++ b/src/org/happysanta/gd/Storage/HighScores.java @@ -0,0 +1,152 @@ +package org.happysanta.gd.Storage; + +import org.happysanta.gd.Settings; + +public class HighScores { + + private static final long MAX_TIME = 0xffff28L; + + private long id; + private long levelId = 0; + private int level = 0; + private int track = 0; + private long[][] times = new long[4][3]; + private String[][] names = new String[4][3]; + + public HighScores() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getLevelId() { + return levelId; + } + + public void setLevelId(long levelId) { + this.levelId = levelId; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public long getTrack() { + return track; + } + + public void setTrack(int track) { + this.track = track; + } + + public long getTime(int league, int place) { + return times[league][place]; + } + + public void setTime(int league, int place, long value) { + times[league][place] = value; + } + + public String getName(int league, int place) { + return names[league][place]; + } + + public void setName(int league, int place, String value) { + names[league][place] = value; + } + + public String[] getScores(int league) { + String[] scores = new String[3]; + for (int places = 0; places < 3; places++) { + if (times[league][places] != 0L) { + int k = (int) times[league][places] / 100; + int l = (int) times[league][places] % 100; + scores[places] = names[league][places] + " "; + if (k / 60 < 10) + scores[places] += " 0" + k / 60; + else + scores[places] += " " + k / 60; + if (k % 60 < 10) + scores[places] += ":0" + k % 60; + else + scores[places] += ":" + k % 60; + if (l < 10) + scores[places] += ".0" + l; + else + scores[places] += "." + l; + } else { + scores[places] = null; + } + } + + return scores; + } + + public int getPlace(int league, long time) { + for (int place = 0; place < 3; place++) + if (times[league][place] > time || times[league][place] == 0L) + return place; + + return 3; + } + + private void clearTimes() { + for (int leagues = 0; leagues < 4; leagues++) { + for (int places = 0; places < 3; places++) + times[leagues][places] = 0L; + } + } + + public void saveHighScore(int league, String name, long time) { + name = trimName(name); + int place; + if ((place = getPlace(league, time)) != 3) { + if (time > MAX_TIME) + time = MAX_TIME; + moveScoreEntries(league, place); + + times[league][place] = time; + names[league][place] = name; + } + } + + private void moveScoreEntries(int league, int i) { + for (int place = 2; place > i; place--) { + times[league][place] = times[league][place - 1]; + names[league][place] = names[league][place - 1]; + } + } + + private static String trimName(String name) { + if (name.length() > 3) + name = name.substring(0, 3); + else if (name.length() < 3) + name = Settings.NAME_DEFAULT; + + return name.toUpperCase(); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("Storage.HighScores {"); + + s.append("id: " + id + ", "); + s.append("level_id: " + levelId + ", "); + s.append("level: " + level + ", "); + s.append("track: " + track); + + s.append("}"); + return s.toString(); + } + +} diff --git a/src/org/happysanta/gd/Storage/Level.java b/src/org/happysanta/gd/Storage/Level.java new file mode 100644 index 0000000..3030b7b --- /dev/null +++ b/src/org/happysanta/gd/Storage/Level.java @@ -0,0 +1,300 @@ +package org.happysanta.gd.Storage; + +import android.text.format.DateUtils; + +import static org.happysanta.gd.Helpers.getGDActivity; + +public class Level { + + private long id = 0; + private String name; + private String author; + private int[] count; + private int size = 0; + private long addedTs = 0; + private long installedTs = 0; + private boolean _isDefault = false; + private long apiId = 0; + private int[] unlocked; + private int selectedTrack = 0; + private int selectedLevel = 0; + private int selectedLeague = 0; + private int unlockedLevels = 0; + private int unlockedLeagues = 0; + + public Level() { + count = new int[3]; + unlocked = new int[3]; + } + + public Level(long id, String name, String author, int countEasy, int countMedium, int countHard, int addedTs, int size, long apiId) { + this(id, name, author, countEasy, countMedium, countHard, addedTs, size, apiId, 0, 0, 0); + } + + public Level(long id, String name, String author, int countEasy, int countMedium, int countHard, int addedTs, int size, long apiId, int unlockedEasy, int unlockedMedium, int unlockedHard) { + this.id = id; + this.name = name; + this.author = author; + this.count = new int[]{ + countEasy, countMedium, countHard + }; + this.addedTs = addedTs; + this.size = size; + this.apiId = apiId; + this.unlocked = new int[]{ + unlockedEasy, unlockedMedium, unlockedHard + }; + } + + public long getId() { + return id; + } + + public long getAnyId() { + return id > 0 ? id : apiId; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public int getCountEasy() { + return this.count[0]; + } + + public int getCountMedium() { + return this.count[1]; + } + + public int getCountHard() { + return this.count[2]; + } + + public int getCount(int level) { + return this.count[level]; + } + + public void setCountEasy(int count) { + this.count[0] = count; + } + + public void setCountMedium(int count) { + this.count[1] = count; + } + + public void setCountHard(int count) { + this.count[2] = count; + } + + public void setCount(int easy, int medium, int hard) { + setCountEasy(easy); + setCountMedium(medium); + setCountHard(hard); + } + + public long getAddedTs() { + return addedTs; + } + + public void setAddedTs(long ts) { + addedTs = ts; + } + + public long getInstalledTs() { + return installedTs; + } + + public void setInstalledTs(long ts) { + installedTs = ts; + } + + public void setIsDefault(boolean isDefault) { + this._isDefault = isDefault; + } + + public boolean isDefault() { + return _isDefault; + } + + public long getApiId() { + return apiId; + } + + public void setApiId(long apiId) { + this.apiId = apiId; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public boolean isInstalled() { + return id > 0; + } + + public String getSizeKb() { + return String.valueOf(Math.round((size / 1024f) * 100f) / 100f); + } + + public String getShortAddedDate() { + return getShortDate(addedTs); + } + + public String getFullAddedDate() { + return getFullDate(addedTs); + } + + public String getShortInstalledDate() { + return getShortDate(installedTs); + } + + public String getFullInstalledDate() { + return getFullDate(installedTs); + } + + public int getUnlockedEasy() { + return this.unlocked[0]; + } + + public int getUnlockedMedium() { + return this.unlocked[1]; + } + + public int getUnlockedHard() { + return this.unlocked[2]; + } + + public int getUnlocked(int level) { + //if (level < 3) + return unlocked[level]; + + //logDebug("Level.getUnlocked: level = " + level + ", out of bounds"); + //return 0; + } + + public int[] getUnlockedAll() { + return unlocked; + } + + public void setUnlockedEasy(int unlocked) { + this.unlocked[0] = unlocked; + } + + public void setUnlockedMedium(int unlocked) { + this.unlocked[1] = unlocked; + } + + public void setUnlockedHard(int unlocked) { + this.unlocked[2] = unlocked; + } + + public void setUnlocked(int easy, int medium, int hard) { + setUnlockedEasy(easy); + setUnlockedMedium(medium); + setUnlockedHard(hard); + } + + public void setUnlocked(int level, int value) { + unlocked[level] = value; + } + + public int getSelectedTrack() { + return selectedTrack; + } + + public int getSelectedLevel() { + return selectedLevel; + } + + public int getSelectedLeague() { + return selectedLeague; + } + + public void setSelectedTrack(int selectedTrack) { + this.selectedTrack = selectedTrack; + } + + public void setSelectedLevel(int selectedLevel) { + this.selectedLevel = selectedLevel; + } + + public void setSelectedLeague(int selectedLeague) { + this.selectedLeague = selectedLeague; + } + + public int getUnlockedLevels() { + return unlockedLevels; + } + + public int getUnlockedLeagues() { + return unlockedLeagues; + } + + public void setUnlockedLevels(int unlockedLevels) { + this.unlockedLevels = unlockedLevels; + } + + public void setUnlockedLeagues(int unlockedLeagues) { + this.unlockedLeagues = unlockedLeagues; + } + + public boolean isSettingsClear() { + return unlockedLevels == 0 + && unlocked[0] == 0 + && unlocked[1] == 0 + && unlocked[2] == 0; + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("Storage.Level {"); + + s.append("id: " + id + ", "); + s.append("name: \"" + name + "\", "); + s.append("author: \"" + author + "\", "); + s.append("count: " + count[0] + "/" + count[1] + "/" + count[2] + ", "); + s.append("added_ts: " + addedTs + ", "); + s.append("installed_ts: " + installedTs + ", "); + s.append("default: " + (_isDefault ? 1 : 0) + ", "); + s.append("api_id: " + apiId + ", "); + s.append("unlocked: " + unlocked[0] + "/" + unlocked[1] + "/" + unlocked[2] + ", "); + s.append("selected_track: " + selectedTrack + ", "); + s.append("selected_level: " + selectedLevel + ", "); + s.append("selected_league: " + selectedLeague + ", "); + s.append("unlocked_levels: " + unlockedLevels + ", "); + s.append("unlocked_leagues: " + unlockedLeagues); + + s.append("}"); + return s.toString(); + } + + private static String getShortDate(long date) { + return DateUtils.formatDateTime(getGDActivity(), date * 1000L, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_MONTH); + } + + private static String getFullDate(long date) { + return DateUtils.formatDateTime(getGDActivity(), date * 1000L, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR); + } + +} diff --git a/src/org/happysanta/gd/Storage/LevelsDataSource.java b/src/org/happysanta/gd/Storage/LevelsDataSource.java new file mode 100644 index 0000000..40e7f14 --- /dev/null +++ b/src/org/happysanta/gd/Storage/LevelsDataSource.java @@ -0,0 +1,293 @@ +package org.happysanta.gd.Storage; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static org.happysanta.gd.Helpers.logDebug; + +public class LevelsDataSource { + + private SQLiteDatabase db; + private LevelsSQLiteOpenHelper dbHelper; + + public LevelsDataSource(Context context) { + dbHelper = new LevelsSQLiteOpenHelper(context); + } + + public synchronized void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public synchronized void close() { + dbHelper.close(); + } + + public synchronized Level createLevel(String name, String author, int countEasy, int countMedium, int countHard, long addedTs, long installedTs, boolean isDefault, long apiId) { + ContentValues values = new ContentValues(); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_NAME, name); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_AUTHOR, author); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_COUNT_EASY, countEasy); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_COUNT_MEDIUM, countMedium); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_COUNT_HARD, countHard); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_ADDED, addedTs); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_INSTALLED, installedTs); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_IS_DEFAULT, isDefault ? 1 : 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_API_ID, apiId); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_EASY, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_MEDIUM, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_HARD, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_TRACK, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEVEL, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEAGUE, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEVELS, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEAGUES, 0); + + long insertId = db.insert(LevelsSQLiteOpenHelper.TABLE_LEVELS, null, values); + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_LEVELS, null, + LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID + " = " + insertId, + null, null, null, null); + + cursor.moveToFirst(); + + Level level = cursorToLevel(cursor); + cursor.close(); + return level; + } + + public synchronized void deleteLevel(Level level) { + long id = level.getId(); + db.delete(LevelsSQLiteOpenHelper.TABLE_LEVELS, LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID + " = " + id, null); + db.delete(LevelsSQLiteOpenHelper.TABLE_HIGHSCORES, LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_LEVEL_ID + " = " + id, null); + } + + // This will also reset auto increment counter + public synchronized void deleteAllLevels() { + db.delete(LevelsSQLiteOpenHelper.TABLE_LEVELS, null, null); + db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + LevelsSQLiteOpenHelper.TABLE_LEVELS + "'"); + } + + public synchronized void resetAllLevelsSettings() { + ContentValues values = new ContentValues(); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_EASY, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_MEDIUM, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_HARD, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEAGUE, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEVEL, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_TRACK, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEAGUES, 0); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEVELS, 0); + + int result = db.update(LevelsSQLiteOpenHelper.TABLE_LEVELS, values, null, null); + logDebug("LevelsDataSource.resetAllLevelsSettings: result = " + result); + } + + public synchronized void updateLevel(Level level) { + ContentValues values = new ContentValues(); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_EASY, level.getUnlockedEasy()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_MEDIUM, level.getUnlockedMedium()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_HARD, level.getUnlockedHard()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEAGUE, level.getSelectedLeague()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEVEL, level.getSelectedLevel()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_TRACK, level.getSelectedTrack()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEAGUES, level.getUnlockedLeagues()); + values.put(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEVELS, level.getUnlockedLevels()); + + // logDebug("LevelsDataSource.updateLevel selectedLeague: " + level.getSelectedLeague()); + + db.update(LevelsSQLiteOpenHelper.TABLE_LEVELS, values, LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID + " = " + level.getId(), null); + } + + public synchronized HashMap<Long, Long> findInstalledLevels(ArrayList<Long> apiIds) { + HashMap<Long, Long> installed = new HashMap<>(); + + String[] apiIdsArray = new String[apiIds.size()]; + for (int i = 0; i < apiIdsArray.length; i++) { + apiIdsArray[i] = apiIds.get(i).toString(); + } + + Cursor cursor = db.rawQuery("SELECT " + LevelsSQLiteOpenHelper.LEVELS_COLUMN_API_ID + ", " + LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID + " FROM " + LevelsSQLiteOpenHelper.TABLE_LEVELS + " WHERE " + LevelsSQLiteOpenHelper.LEVELS_COLUMN_API_ID + " IN (" + makePlaceholders(apiIdsArray.length) + ")", apiIdsArray); + cursor.moveToFirst(); + + while (!cursor.isAfterLast()) { + long apiId = cursor.getLong(0), + id = cursor.getLong(1); + installed.put(apiId, id); + cursor.moveToNext(); + } + cursor.close(); + + return installed; + } + + public synchronized List<Level> getAllLevels() { + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_LEVELS, null, null, null, null, null, null); + + List<Level> levels = levelsFromCursor(cursor); + cursor.close(); + + return levels; + } + + public synchronized List<Level> getLevels(int offset, int count) { + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_LEVELS, null, null, null, null, LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID + " ASC", offset + ", " + count); + + List<Level> levels = levelsFromCursor(cursor); + cursor.close(); + + return levels; + } + + public synchronized Level getLevel(long id) { + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_LEVELS, null, LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID + " = " + id, null, null, null, null); + cursor.moveToFirst(); + + Level level = null; + if (cursor.getCount() > 0) { + level = cursorToLevel(cursor); + } + + cursor.close(); + return level; + } + + public List<Level> levelsFromCursor(Cursor cursor) { + cursor.moveToFirst(); + List<Level> levels = new ArrayList<>(); + while (!cursor.isAfterLast()) { + Level level = cursorToLevel(cursor); + levels.add(level); + cursor.moveToNext(); + } + return levels; + } + + public synchronized boolean isDefaultLevelCreated() { + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_LEVELS, new String[]{LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID}, LevelsSQLiteOpenHelper.LEVELS_COLUMN_IS_DEFAULT + " = 1", null, null, null, null); + boolean created = cursor.getCount() > 0; + cursor.close(); + return created; + } + + public synchronized boolean isApiIdInstalled(long apiId) { + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_LEVELS, new String[]{LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID}, LevelsSQLiteOpenHelper.LEVELS_COLUMN_API_ID + " = " + apiId, null, null, null, null); + boolean installed = cursor.getCount() > 0; + cursor.close(); + return installed; + } + + public synchronized HighScores getHighScores(long levelId, int level, int track) { + Cursor cursor = db.query(LevelsSQLiteOpenHelper.TABLE_HIGHSCORES, null, + LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_LEVEL_ID + " = " + levelId + " AND " + LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_LEVEL + " = " + level + " AND " + LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_TRACK + " = " + track, + null, null, null, null); + cursor.moveToFirst(); + + HighScores highScores = new HighScores(); + highScores.setLevelId(levelId); + highScores.setLevel(level); + highScores.setTrack(track); + if (cursor.getCount() > 0) + fillHighScoresFromCursor(cursor, highScores); + else { + long id = createEmptyHighScore(levelId, level, track); + highScores.setId(id); + } + + cursor.close(); + return highScores; + } + + private synchronized long createEmptyHighScore(long levelId, int level, int track) { + ContentValues values = new ContentValues(); + values.put(LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_LEVEL_ID, levelId); + values.put(LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_LEVEL, level); + values.put(LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_TRACK, track); + for (int league = 0; league < 4; league++) { + for (int place = 0; place < 3; place++) { + values.put(LevelsSQLiteOpenHelper.getHighscoresTimeColumn(league, place), 0); + values.put(LevelsSQLiteOpenHelper.getHighscoresNameColumn(league, place), 0); + } + } + + long insertId = db.insert(LevelsSQLiteOpenHelper.TABLE_HIGHSCORES, null, values); + return insertId; + } + + public synchronized void updateHighScores(HighScores scores) { + ContentValues values = new ContentValues(); + for (int league = 0; league < 4; league++) { + for (int place = 0; place < 3; place++) { + values.put(LevelsSQLiteOpenHelper.getHighscoresTimeColumn(league, place), scores.getTime(league, place)); + values.put(LevelsSQLiteOpenHelper.getHighscoresNameColumn(league, place), scores.getName(league, place)); + } + } + + db.update(LevelsSQLiteOpenHelper.TABLE_HIGHSCORES, values, LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_ID + " = " + scores.getId(), null); + } + + public synchronized void clearHighScores(long levelId) { + db.delete(LevelsSQLiteOpenHelper.TABLE_HIGHSCORES, + levelId > 0 ? LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_LEVEL_ID + " = " + levelId : null, + null); + if (levelId == 0) { + db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" + LevelsSQLiteOpenHelper.TABLE_HIGHSCORES + "'"); + } + } + + private Level cursorToLevel(Cursor cursor) { + Level level = new Level(); + level.setId(cursor.getLong(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_ID))); + level.setName(cursor.getString(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_NAME))); + level.setAuthor(cursor.getString(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_AUTHOR))); + level.setCount( + cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_COUNT_EASY)), + cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_COUNT_MEDIUM)), + cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_COUNT_HARD))); + level.setAddedTs(cursor.getLong(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_ADDED))); + level.setInstalledTs(cursor.getLong(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_INSTALLED))); + level.setIsDefault(cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_IS_DEFAULT)) == 1); + level.setApiId(cursor.getLong(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_API_ID))); + level.setUnlocked( + cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_EASY)), + cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_MEDIUM)), + cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_HARD))); + level.setSelectedLevel(cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEVEL))); + level.setSelectedTrack(cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_TRACK))); + level.setSelectedLeague(cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_SELECTED_LEAGUE))); + level.setUnlockedLevels(cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEVELS))); + level.setUnlockedLeagues(cursor.getInt(cursor.getColumnIndex(LevelsSQLiteOpenHelper.LEVELS_COLUMN_UNLOCKED_LEAGUES))); + + return level; + } + + private void fillHighScoresFromCursor(Cursor cursor, HighScores highScores) { + highScores.setId(cursor.getLong(cursor.getColumnIndex(LevelsSQLiteOpenHelper.HIGHSCORES_COLUMN_ID))); + + for (int league = 0; league < 4; league++) { + for (int place = 0; place < 3; place++) { + highScores.setTime(league, place, cursor.getLong(cursor.getColumnIndex(LevelsSQLiteOpenHelper.getHighscoresTimeColumn(league, place)))); + highScores.setName(league, place, cursor.getString(cursor.getColumnIndex(LevelsSQLiteOpenHelper.getHighscoresNameColumn(league, place)))); + } + } + } + + private String makePlaceholders(int len) { + if (len < 1) { + throw new RuntimeException("No placeholders"); + } else { + StringBuilder sb = new StringBuilder(len * 2 - 1); + sb.append("?"); + for (int i = 1; i < len; i++) { + sb.append(",?"); + } + return sb.toString(); + } + } + +} diff --git a/src/org/happysanta/gd/Storage/LevelsManager.java b/src/org/happysanta/gd/Storage/LevelsManager.java new file mode 100644 index 0000000..697c9ff --- /dev/null +++ b/src/org/happysanta/gd/Storage/LevelsManager.java @@ -0,0 +1,503 @@ +package org.happysanta.gd.Storage; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.os.AsyncTask; +import android.os.Environment; +import android.os.StatFs; +import org.happysanta.gd.API.API; +import org.happysanta.gd.API.DownloadFile; +import org.happysanta.gd.API.DownloadHandler; +import org.happysanta.gd.Callback; +import org.happysanta.gd.DoubleCallback; +import org.happysanta.gd.GDActivity; +import org.happysanta.gd.Global; +import org.happysanta.gd.Levels.LevelHeader; +import org.happysanta.gd.Levels.Reader; +import org.happysanta.gd.Menu.Menu; +import org.happysanta.gd.Menu.MenuScreen; +import org.happysanta.gd.R; +import org.happysanta.gd.Settings; +import org.acra.ACRA; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; + +import static org.happysanta.gd.Helpers.getGDActivity; +import static org.happysanta.gd.Helpers.getGameMenu; +import static org.happysanta.gd.Helpers.getString; +import static org.happysanta.gd.Helpers.getTimestamp; +import static org.happysanta.gd.Helpers.isOnline; +import static org.happysanta.gd.Helpers.logDebug; +import static org.happysanta.gd.Helpers.showAlert; + +public class LevelsManager { + + private LevelsDataSource dataSource; + private boolean dbOK = false; + private Level currentLevel; + + public LevelsManager() { + GDActivity gd = getGDActivity(); + dataSource = new LevelsDataSource(gd); + + try { + dataSource.open(); + + if (!dataSource.isDefaultLevelCreated()) { + Level level = dataSource.createLevel("GDTR original", "Codebrew Software", 10, 10, 10, 0, 0, true, 1); + logDebug("LevelsManager: Default level created!"); + logDebug(level); + } + } catch (SQLException e) { + e.printStackTrace(); + logDebug("LevelsManager: db feels bad :("); + // return; + } + + logDebug("LevelsManager: db feels OK :)"); + + // Shared prefs + // SharedPreferences settings = getSharedPreferences(); + // long levelId = settings.getLong(PREFS_LEVEL_ID, 0); + long levelId = Settings.getLevelId(); + if (levelId < 1 || !mrgIsAvailable(levelId)) { + logDebug("LevelsManager: levelId = " + levelId + ", < 1 or mrg is not available; now: reset id"); + /*SharedPreferences.Editor editor = settings.edit(); + editor.putLong(PREFS_LEVEL_ID, 1); + editor.commit();*/ + resetId(); + } + + reload(); + dbOK = true; + } + + public void resetId() { + Settings.setLevelId(1); + } + + public void reload() { + long id = Settings.getLevelId(); + currentLevel = dataSource.getLevel(id); + + if (currentLevel == null) { + logDebug("LevelsManager: failed to load currentLevel; currentId = " + id); + } else { + logDebug("LevelsManager: level = " + currentLevel); + } + + if (Global.ACRA_ENABLED) { + ACRA.getErrorReporter().putCustomData("level_api_id:", String.valueOf(currentLevel.getApiId())); + } + } + + public void closeDataSource() { + dataSource.close(); + } + + public long getCurrentId() { + return currentLevel.getId(); + } + + public void setCurrentId(long id) { + // currentId = id; + Settings.setLevelId(id); + /*SharedPreferences settings = getSharedPreferences(); + SharedPreferences.Editor edit = settings.edit(); + edit.putLong(PREFS_LEVEL_ID, id); + edit.commit();*/ + } + + public Level getCurrentLevel() { + return currentLevel; + } + + public File getCurrentLevelsFile() { + if (currentLevel.getId() > 1) + return getMrgFileById(currentLevel.getId()); + + return null; + } + + private boolean mrgIsAvailable(long id) { + if (id == 1) // This is default built-in levels.mrg + return true; + + File file = getMrgFileById(id); + return isExternalStorageReadable() && file.exists(); + } + + public boolean isDbOK() { + return dbOK; + } + + public long install(File file, String name, String author, long apiId) throws Exception { + if (!isSpaceAvailable(file.length())) { + throw new Exception(getString(R.string.e_no_space_left)); + } + + InputStream inputStream = new FileInputStream(file); + LevelHeader header = Reader.readHeader(inputStream); + try { + inputStream.close(); + } catch (IOException e) { + } + + if (!header.isCountsOk()) { + throw new IOException(file.getName() + " is not valid"); + } + + Level level = dataSource.createLevel(name, author, header.getCount(0), header.getCount(1), header.getCount(2), 0, getTimestamp(), false, apiId); + long id = level.getId(); + if (id < 1) { + throw new Exception(getString(R.string.e_cannot_save_level)); + } + + File newFile = getMrgFileById(id); + copy(file, newFile); + + return id; + } + + public void installAsync(File file, String name, String author, long apiId, final DoubleCallback callback) { + GDActivity gd = getGDActivity(); + final ProgressDialog progressDialog = ProgressDialog.show(gd, getString(R.string.install), getString(R.string.installing), true); + + new AsyncInstallLevel() { + @Override + protected void onPostExecute(Object result) { + progressDialog.dismiss(); + + if (result instanceof Throwable) { + Throwable throwable = (Throwable) result; + throwable.printStackTrace(); + showAlert(getString(R.string.error), throwable.getMessage(), null); + if (callback != null) + callback.onFail(); + return; + } + + if (callback != null) + callback.onDone((long) result); + } + }.execute(file, name, author, apiId); + } + + public void load(Level level) throws RuntimeException { + /*File file = getMrgFileById(level.getId()); + if (!mrgIsAvailable(level.getId())) { + throw new RuntimeException("Unable to load levels \"" +level.getName() + "\""); + }*/ + + // Loader loader = getLevelLoader(); + // Menu menu = getGameMenu(); + + // loader.setLevelsFile(file); + // menu.reloadLevels(); + + setCurrentId(level.getId()); + getGDActivity().restartApp(); + } + + public boolean isApiIdInstalled(long apiId) { + return dataSource.isApiIdInstalled(apiId); + } + + public Level[] getInstalledLevels(int offset, int count) { + return dataSource.getLevels(offset, count).toArray(new Level[0]); + } + + public Level getLeveL(long id) { + return dataSource.getLevel(id); + } + + public Level[] getAllInstalledLevels() { + return dataSource.getAllLevels().toArray(new Level[0]); + } + + public synchronized HashMap<String, Double> getLevelsStat() { + Level[] levels = getAllInstalledLevels(); + HashMap<String, Double> stat = new HashMap<>(); + if (levels.length > 0) { + for (Level level : levels) { + int[] completed = level.getUnlockedAll(); + int completedCount = 0; + for (int i = 0; i < completed.length; i++) { + if (completed[i] < 0) completed[i] = 0; + completedCount += completed[i]; + } + + double totalCount = level.getCountEasy() + level.getCountMedium() + level.getCountHard(); + double per = completedCount / totalCount * 100; + + stat.put(String.valueOf(level.getApiId()), per); + } + } + return stat; + } + + public void delete(Level level) { + dataSource.deleteLevel(level); + File file = getMrgFileById(level.getId()); + try { + if (file.exists()) { + file.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void deleteAsync(Level level, final Runnable callback) { + GDActivity gd = getGDActivity(); + final ProgressDialog progressDialog = ProgressDialog.show(gd, getString(R.string.delete), getString(R.string.deleting), true); + + new AsyncDeleteLevel() { + @Override + protected void onPostExecute(Void v) { + progressDialog.dismiss(); + if (callback != null) + callback.run(); + } + }.execute(level); + } + + public void updateLevelSettings() { + dataSource.updateLevel(currentLevel); + } + + public void downloadLevel(final Level level, final Callback successCallback) { + final GDActivity gd = getGDActivity(); + File outputDir = gd.getCacheDir(); + + try { + boolean readable = isExternalStorageReadable(); + if (!readable) { + throw new Exception(getString(R.string.e_external_storage_is_not_readable)); + } + + if (!isOnline()) { + throw new Exception(getString(R.string.e_no_network_connection)); + } + + if (!isSpaceAvailable(level.getSize())) { + throw new Exception(getString(R.string.e_no_space_left)); + } + + final File outputFile = File.createTempFile("levels" + level.getApiId(), "mrg", outputDir); + FileOutputStream out = new FileOutputStream(outputFile); + + // logDebug("downloadLevel: 4"); + // final API api = new API(); + final ProgressDialog progress; + final DownloadFile downloadFile = new DownloadFile(API.getMrgURL(level.getApiId()), out); + + progress = new ProgressDialog(gd); + progress.setMessage(getString(R.string.downloading)); + progress.setIndeterminate(true); + progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progress.setCancelable(true); + + final DownloadHandler handler = new DownloadHandler() { + @Override + public void onFinish(Throwable error) { + progress.dismiss(); + + if (error != null) { + // error.printStackTrace(); + error.printStackTrace(); + showAlert(getString(R.string.error), error.getMessage(), null); + + outputFile.delete(); + return; + } + + // Install + installAsync(outputFile, level.getName(), level.getAuthor(), level.getApiId(), new DoubleCallback() { + @Override + public void onDone(Object... objects) { + long id = (long) objects[0]; + outputFile.delete(); + + if (successCallback != null) + successCallback.onDone(id); + } + + @Override + public void onFail() { + outputFile.delete(); + } + }); + } + + @Override + public void onStart() { + progress.show(); + } + + @Override + public void onProgress(int pr) { + progress.setIndeterminate(false); + progress.setMax(100); + progress.setProgress(pr); + } + }; + progress.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + downloadFile.cancel(); + handler.onFinish(new InterruptedException(getString(R.string.e_downloading_was_interrupted))); + } + }); + + downloadFile.setDownloadHandler(handler); + downloadFile.start(); + } catch (Exception e) { + showAlert(getString(R.string.error), e.getMessage(), null); + } + } + + public void showSuccessfullyInstalledDialog() { + GDActivity gd = getGDActivity(); + AlertDialog success = new AlertDialog.Builder(gd) + .setTitle(getString(R.string.installed)) + .setMessage(getString(R.string.successfully_installed)) + .setPositiveButton(getString(R.string.ok), null) + .setNegativeButton(getString(R.string.open_installed), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Menu menu = getGameMenu(); + MenuScreen currentMenu = getGameMenu().getCurrentMenu(), + newMenu = menu.managerInstalledScreen; + + if (currentMenu == menu.managerDownloadScreen || currentMenu.getNavTarget() == menu.managerDownloadScreen) { + menu.managerDownloadScreen.onHide(menu.managerScreen); + } + + menu.setCurrentMenu(newMenu, false); + } + }) + .create(); + success.show(); + } + + public HashMap<Long, Long> findInstalledLevels(ArrayList<Long> apiIds) { + return dataSource.findInstalledLevels(apiIds); + } + + public HighScores getHighScores(int level, int track) { + HighScores scores = dataSource.getHighScores(currentLevel.getId(), level, track); + // logDebug("LevelsManager.getHighScores: " + scores); + return scores; + } + + public void saveHighScores(HighScores scores) { + dataSource.updateHighScores(scores); + } + + public void clearHighScores() { + dataSource.clearHighScores(currentLevel.getId()); + } + + public void clearAllHighScores() { + dataSource.clearHighScores(0); + } + + public void resetAllLevelsSettings() { + dataSource.resetAllLevelsSettings(); + + logDebug("All levels now: " + dataSource.getAllLevels()); + logDebug("Level#1: " + dataSource.getLevel(1)); + } + + public static boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; + } + + public static boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + return false; + } + + public static File getLevelsDirectory() { + File file = new File(Environment.getExternalStorageDirectory(), "GDLevels"); + if (!file.mkdirs()) { + logDebug("LevelsManager.getLevelsDirectory: directory not created"); + } + return file; + } + + public static String getMrgFileNameById(long id) { + return getLevelsDirectory().getAbsolutePath() + "/" + id + ".mrg"; + } + + public static File getMrgFileById(long id) { + if (id == 1) return null; + return new File(getMrgFileNameById(id)); + } + + public static void copy(File src, File dst) throws IOException { + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dst); + + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + + in.close(); + out.close(); + } + + public static boolean isSpaceAvailable(long bytes) { + StatFs stat = new StatFs(getLevelsDirectory().getPath()); + long bytesAvailable = (long) stat.getBlockSize() * (long) stat.getAvailableBlocks(); + return bytesAvailable >= bytes; + } + + private class AsyncDeleteLevel extends AsyncTask<Level, Void, Void> { + @Override + protected Void doInBackground(Level... levels) { + delete(levels[0]); + return null; + } + } + + private class AsyncInstallLevel extends AsyncTask<Object, Void, Object> { + @Override + protected Object doInBackground(Object... objects) { + File file = (File) objects[0]; + String name = (String) objects[1]; + String author = (String) objects[2]; + long apiId = (long) objects[3]; + + long id = 0; + try { + id = install(file, name, author, apiId); + } catch (Throwable e) { + return e; + } + + return id; + } + } + +} diff --git a/src/org/happysanta/gd/Storage/LevelsSQLiteOpenHelper.java b/src/org/happysanta/gd/Storage/LevelsSQLiteOpenHelper.java new file mode 100644 index 0000000..024a17f --- /dev/null +++ b/src/org/happysanta/gd/Storage/LevelsSQLiteOpenHelper.java @@ -0,0 +1,141 @@ +package org.happysanta.gd.Storage; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public class LevelsSQLiteOpenHelper extends SQLiteOpenHelper { + + private static final int DATABASE_VERSION = 1; + private static final String DATABASE_NAME = "levels.db"; + + public static final String TABLE_LEVELS = "levels"; + public static final String TABLE_HIGHSCORES = "highscores"; + + public static final String LEVELS_COLUMN_ID = "_id"; + public static final String LEVELS_COLUMN_NAME = "name"; + public static final String LEVELS_COLUMN_AUTHOR = "author"; + public static final String LEVELS_COLUMN_COUNT_EASY = "count_easy"; + public static final String LEVELS_COLUMN_COUNT_MEDIUM = "count_medium"; + public static final String LEVELS_COLUMN_COUNT_HARD = "count_hard"; + public static final String LEVELS_COLUMN_ADDED = "added_ts"; + public static final String LEVELS_COLUMN_INSTALLED = "installed_ts"; + public static final String LEVELS_COLUMN_IS_DEFAULT = "is_default"; + public static final String LEVELS_COLUMN_API_ID = "api_id"; + public static final String LEVELS_COLUMN_UNLOCKED_EASY = "unlocked_easy"; + public static final String LEVELS_COLUMN_UNLOCKED_MEDIUM = "unlocked_medium"; + public static final String LEVELS_COLUMN_UNLOCKED_HARD = "unlocked_hard"; + public static final String LEVELS_COLUMN_SELECTED_LEVEL = "selected_level"; + public static final String LEVELS_COLUMN_SELECTED_TRACK = "selected_track"; + public static final String LEVELS_COLUMN_SELECTED_LEAGUE = "selected_league"; + public static final String LEVELS_COLUMN_UNLOCKED_LEVELS = "unlocked_levels"; + public static final String LEVELS_COLUMN_UNLOCKED_LEAGUES = "unlocked_leagues"; + + public static final String HIGHSCORES_COLUMN_ID = "_id"; + public static final String HIGHSCORES_COLUMN_LEVEL_ID = "level_id"; + public static final String HIGHSCORES_COLUMN_LEVEL = "level"; + public static final String HIGHSCORES_COLUMN_TRACK = "track"; + + private static final String TABLE_LEVELS_CREATE = "CREATE TABLE " + + TABLE_LEVELS + "(" + + LEVELS_COLUMN_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + + LEVELS_COLUMN_NAME + " TEXT NOT NULL, " + + LEVELS_COLUMN_AUTHOR + " TEXT NOT NULL, " + + LEVELS_COLUMN_COUNT_EASY + " INTEGER NOT NULL, " + + LEVELS_COLUMN_COUNT_MEDIUM + " INTEGER NOT NULL, " + + LEVELS_COLUMN_COUNT_HARD + " INTEGER NOT NULL, " + + LEVELS_COLUMN_ADDED + " INTEGER NOT NULL, " + + LEVELS_COLUMN_INSTALLED + " INTEGER NOT NULL, " + + LEVELS_COLUMN_IS_DEFAULT + " INTEGER NOT NULL, " + + LEVELS_COLUMN_API_ID + " INTEGER NOT NULL, " + + LEVELS_COLUMN_UNLOCKED_EASY + " INTEGER NOT NULL, " + + LEVELS_COLUMN_UNLOCKED_MEDIUM + " INTEGER NOT NULL, " + + LEVELS_COLUMN_UNLOCKED_HARD + " INTEGER NOT NULL, " + + LEVELS_COLUMN_SELECTED_LEVEL + " INTEGER NOT NULL, " + + LEVELS_COLUMN_SELECTED_TRACK + " INTEGER NOT NULL, " + + LEVELS_COLUMN_SELECTED_LEAGUE + " INTEGER NOT NULL, " + + LEVELS_COLUMN_UNLOCKED_LEVELS + " INTEGER NOT NULL, " + + LEVELS_COLUMN_UNLOCKED_LEAGUES + " INTEGER NOT NULL" + + ");"; + + private static final String TABLE_HIGHSCORES_CREATE = " CREATE TABLE " + + TABLE_HIGHSCORES + "(" + + HIGHSCORES_COLUMN_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + + HIGHSCORES_COLUMN_LEVEL_ID + " INTEGER NOT NULL, " + + HIGHSCORES_COLUMN_LEVEL + " INTEGER NOT NULL, " + + HIGHSCORES_COLUMN_TRACK + " INTEGER NOT NULL, " + + // 100cc + + getHighscoresTimeColumn(0, 0) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(0, 0) + " TEXT, " + + getHighscoresTimeColumn(0, 1) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(0, 1) + " TEXT, " + + getHighscoresTimeColumn(0, 2) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(0, 2) + " TEXT, " + + // 175cc + + getHighscoresTimeColumn(1, 0) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(1, 0) + " TEXT, " + + getHighscoresTimeColumn(1, 1) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(1, 1) + " TEXT, " + + getHighscoresTimeColumn(1, 2) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(1, 2) + " TEXT, " + + // 220cc + + getHighscoresTimeColumn(2, 0) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(2, 0) + " TEXT, " + + getHighscoresTimeColumn(2, 1) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(2, 1) + " TEXT, " + + getHighscoresTimeColumn(2, 2) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(2, 2) + " TEXT, " + + // 325cc + + getHighscoresTimeColumn(3, 0) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(3, 0) + " TEXT, " + + getHighscoresTimeColumn(3, 1) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(3, 1) + " TEXT, " + + getHighscoresTimeColumn(3, 2) + " INTEGER NOT NULL, " + + getHighscoresNameColumn(3, 2) + " TEXT" + + + ")"; + + LevelsSQLiteOpenHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(TABLE_LEVELS_CREATE); + createLevelsIndexes(db); + + db.execSQL(TABLE_HIGHSCORES_CREATE); + createHighscoresIndexes(db); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + + private void createLevelsIndexes(SQLiteDatabase db) { + db.execSQL("CREATE INDEX " + LEVELS_COLUMN_API_ID + "_index ON " + TABLE_LEVELS + "(" + LEVELS_COLUMN_API_ID + ")"); + db.execSQL("CREATE INDEX " + LEVELS_COLUMN_IS_DEFAULT + "_index ON " + TABLE_LEVELS + "(" + LEVELS_COLUMN_IS_DEFAULT + ")"); + } + + private void createHighscoresIndexes(SQLiteDatabase db) { + db.execSQL("CREATE INDEX level_id_level_track_index ON " + TABLE_HIGHSCORES + "(" + + HIGHSCORES_COLUMN_LEVEL_ID + ", " + + HIGHSCORES_COLUMN_LEVEL + ", " + + HIGHSCORES_COLUMN_TRACK + + ")"); + } + + public static String getHighscoresTimeColumn(int league, int place) { + return "l" + league + "_p" + place + "_time"; + } + + public static String getHighscoresNameColumn(int league, int place) { + return "l" + league + "_p" + place + "_name"; + } + +} diff --git a/src/org/happysanta/gd/Util/HexDump.java b/src/org/happysanta/gd/Util/HexDump.java new file mode 100755 index 0000000..443555c --- /dev/null +++ b/src/org/happysanta/gd/Util/HexDump.java @@ -0,0 +1,124 @@ +package org.happysanta.gd.Util; + +public class HexDump { + private final static char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + public static String dumpHexString(byte[] array) { + return dumpHexString(array, 0, array.length); + } + + public static String dumpHexString(byte[] array, int offset, int length) { + StringBuilder result = new StringBuilder(); + + byte[] line = new byte[16]; + int lineIndex = 0; + + result.append("\n0x"); + result.append(toHexString(offset)); + + for (int i = offset; i < offset + length; i++) { + if (lineIndex == 16) { + result.append(" "); + + for (int j = 0; j < 16; j++) { + if (line[j] > ' ' && line[j] < '~') { + result.append(new String(line, j, 1)); + } else { + result.append("."); + } + } + + result.append("\n0x"); + result.append(toHexString(i)); + lineIndex = 0; + } + + byte b = array[i]; + result.append(" "); + result.append(HEX_DIGITS[(b >>> 4) & 0x0F]); + result.append(HEX_DIGITS[b & 0x0F]); + + line[lineIndex++] = b; + } + + if (lineIndex != 16) { + int count = (16 - lineIndex) * 3; + count++; + for (int i = 0; i < count; i++) { + result.append(" "); + } + + for (int i = 0; i < lineIndex; i++) { + if (line[i] > ' ' && line[i] < '~') { + result.append(new String(line, i, 1)); + } else { + result.append("."); + } + } + } + + return result.toString(); + } + + public static String toHexString(byte b) { + return toHexString(toByteArray(b)); + } + + public static String toHexString(byte[] array) { + return toHexString(array, 0, array.length); + } + + public static String toHexString(byte[] array, int offset, int length) { + char[] buf = new char[length * 2]; + + int bufIndex = 0; + for (int i = offset; i < offset + length; i++) { + byte b = array[i]; + buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; + buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; + } + + return new String(buf); + } + + public static String toHexString(int i) { + return toHexString(toByteArray(i)); + } + + public static byte[] toByteArray(byte b) { + byte[] array = new byte[1]; + array[0] = b; + return array; + } + + public static byte[] toByteArray(int i) { + byte[] array = new byte[4]; + + array[3] = (byte) (i & 0xFF); + array[2] = (byte) ((i >> 8) & 0xFF); + array[1] = (byte) ((i >> 16) & 0xFF); + array[0] = (byte) ((i >> 24) & 0xFF); + + return array; + } + + private static int toByte(char c) { + if (c >= '0' && c <= '9') return (c - '0'); + if (c >= 'A' && c <= 'F') return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') return (c - 'a' + 10); + + throw new RuntimeException("Invalid hex char '" + c + "'"); + } + + public static byte[] hexStringToByteArray(String hexString) { + int length = hexString.length(); + byte[] buffer = new byte[length / 2]; + + for (int i = 0; i < length; i += 2) { + buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1))); + } + + return buffer; + } +} + diff --git a/src/org/happysanta/gd/WaitForNetworkConnection.java b/src/org/happysanta/gd/WaitForNetworkConnection.java new file mode 100644 index 0000000..d711715 --- /dev/null +++ b/src/org/happysanta/gd/WaitForNetworkConnection.java @@ -0,0 +1,34 @@ +package org.happysanta.gd; + +import android.os.AsyncTask; + +import static org.happysanta.gd.Helpers.isOnline; +import static org.happysanta.gd.Helpers.logDebug; + +public class WaitForNetworkConnection extends AsyncTask<Object, Void, Void> { + + protected Runnable callback; + + @Override + public Void doInBackground(Object... params) { + callback = (Runnable) params[1]; + + while (!isOnline()) { + logDebug("Waiting for network..."); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + } + + return null; + } + + @Override + public void onPostExecute(Void v) { + logDebug("Network OK, callback.run() now..."); + callback.run(); + } + +} |