/*
* Copyright 2015 Daniel Dittmar
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package dan.dit.whatsthat.riddle.games;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.MotionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import dan.dit.whatsthat.BuildConfig;
import dan.dit.whatsthat.R;
import dan.dit.whatsthat.achievement.AchievementDataEvent;
import dan.dit.whatsthat.achievement.AchievementProperties;
import dan.dit.whatsthat.image.Image;
import dan.dit.whatsthat.riddle.Riddle;
import dan.dit.whatsthat.riddle.RiddleConfig;
import dan.dit.whatsthat.riddle.achievement.holders.AchievementDice;
import dan.dit.whatsthat.riddle.control.LookRiddleAnimation;
import dan.dit.whatsthat.riddle.control.RiddleAnimation;
import dan.dit.whatsthat.riddle.control.RiddleGame;
import dan.dit.whatsthat.riddle.control.RiddleScore;
import dan.dit.whatsthat.riddle.types.TypesHolder;
import dan.dit.whatsthat.testsubject.TestSubject;
import dan.dit.whatsthat.testsubject.shopping.ShopArticleMulti;
import dan.dit.whatsthat.testsubject.shopping.sortiment.SortimentHolder;
import dan.dit.whatsthat.util.flatworld.look.FramesOneshot;
import dan.dit.whatsthat.util.general.BuildException;
import dan.dit.whatsthat.util.general.PercentProgressListener;
import dan.dit.whatsthat.util.compaction.CompactedDataCorruptException;
import dan.dit.whatsthat.util.compaction.Compacter;
import dan.dit.whatsthat.util.field.Field2D;
import dan.dit.whatsthat.util.field.FieldElement;
import dan.dit.whatsthat.util.image.BitmapUtil;
import dan.dit.whatsthat.util.image.ImageUtil;
/**
* A RiddleGame implementation that uses a Field2D and dices of various states.
* Created by daniel on 22.04.15.
*/
public class RiddleDice extends RiddleGame {
public static final int FIELD_X = 6;
public static final int FIELD_Y = 6;
private static final float DICE_DOT_BASE_RADIUS = 5.f;
private static final int NUMBERS_PER_STATE = 9;
private static final int[] STATE_COLOR = new int[]{0xFFFF0000, 0xFFE9F700, 0xFF0dd70d, 0xFF740A8B};
public static final int STATE_ALIEN = 3;
public static final int STATE_GREEN = 2;
public static final int STATE_YELLOW = 1;
public static final int STATE_RED = 0;
private static final int[] STATE_CURRENT_POSITION_TEMP_ALPHA = new int[] {5, 10, 30, 50};
private static final int[] STATE_NEIGHBOR_PERM_ALPHA_INCREASE = new int[] {1, 2, 3, 0};
private static final int STATE_NEIGHBOR_TEMP_ALPHA_DIVIDE_BY_NUMBER = 250;
private static final float ALPHA_RESET_PENALTY_FACTOR = 0.25f;
private static final FieldElement.Neighbor[][] NUMBER_NEIGBORS = new FieldElement.Neighbor[][] {
new FieldElement.Neighbor[] {FieldElement.Neighbor.SELF}, //1
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT}, //2
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.SELF}, //3
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.TOP_RIGHT, FieldElement.Neighbor.BOTTOM_LEFT}, //4
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.TOP_RIGHT, FieldElement.Neighbor.BOTTOM_LEFT, FieldElement.Neighbor.SELF}, //5
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.TOP_RIGHT, FieldElement.Neighbor.BOTTOM_LEFT, FieldElement.Neighbor.LEFT, FieldElement.Neighbor.RIGHT}, //6
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.TOP_RIGHT, FieldElement.Neighbor.BOTTOM_LEFT, FieldElement.Neighbor.LEFT, FieldElement.Neighbor.RIGHT, FieldElement.Neighbor.SELF}, //7
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.TOP_RIGHT, FieldElement.Neighbor.BOTTOM_LEFT, FieldElement.Neighbor.LEFT, FieldElement.Neighbor.RIGHT, FieldElement.Neighbor.TOP, FieldElement.Neighbor.BOTTOM}, //8
new FieldElement.Neighbor[] {FieldElement.Neighbor.TOP_LEFT, FieldElement.Neighbor.BOTTOM_RIGHT, FieldElement.Neighbor.TOP_RIGHT, FieldElement.Neighbor.BOTTOM_LEFT, FieldElement.Neighbor.LEFT, FieldElement.Neighbor.RIGHT, FieldElement.Neighbor.TOP, FieldElement.Neighbor.BOTTOM, FieldElement.Neighbor.SELF}, //9
};
private static final String CACHE_DICE_ALIEN = TypesHolder.Dice.NAME + "DiceAlien";
private Random mRand;
private Field2D<DicePosition> mField;
private Paint mBorderPaint;
private Paint mTransparentPaint;
private Bitmap mFieldArea;
private Canvas mFieldAreaCanvas;
private float mDiceDotRadius;
private Paint mDiceDotPaint;
private Paint mFieldPaint;
private boolean mDiceMoveForbidden;
private DicePosition mDiceToMove;
private List<DicePosition> mMarkedFields;
private int mMarkedColor;
private Bitmap mDiceAlien;
private int mMovedDistance;
private Bitmap[] mAlienSpawnFrames;
private int mFirstStartDiceState;
public RiddleDice(Riddle riddle, Image image, Bitmap bitmap, Resources res, RiddleConfig config, PercentProgressListener listener) {
super(riddle, image, bitmap, res, config, listener);
}
@Override
public void draw(Canvas canvas) {
canvas.drawBitmap(mFieldArea, 0, 0, null);
mBorderPaint.setColor(Color.BLACK);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBorderPaint);
}
private void drawFieldArea() {
mField.drawField(mFieldAreaCanvas);
}
@Override
public void onClose() {
super.onClose();
ImageUtil.CACHE.freeImage(CACHE_DICE_ALIEN, mDiceAlien);
mDiceAlien = null;
mBorderPaint = null;
mRand = null;
mFieldAreaCanvas = null;
mFieldArea = null;
mFieldPaint = null;
mField = null;
mMarkedFields = null;
mDiceToMove = null;
mDiceDotPaint = null;
mTransparentPaint = null;
mDiceDotPaint = null;
}
@Override
protected void initBitmap(Resources res, PercentProgressListener listener) {
mMarkedFields = new ArrayList<>();
mFieldPaint = new Paint();
mFieldPaint.setAntiAlias(true);
mFieldPaint.setStyle(Paint.Style.FILL);
mBitmap.setHasAlpha(true);
mDiceDotRadius = ImageUtil.convertDpToPixel(DICE_DOT_BASE_RADIUS, mConfig.mScreenDensity);
mDiceDotPaint = new Paint();
mDiceDotPaint.setStyle(Paint.Style.FILL);
mDiceDotPaint.setColor(Color.BLACK);
mDiceDotPaint.setAntiAlias(true);
mFieldArea = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());
mFieldAreaCanvas = new Canvas(mFieldArea);
listener.onProgressUpdate(30);
mTransparentPaint = new Paint();
mTransparentPaint.setColor(Color.TRANSPARENT);
mTransparentPaint.setAntiAlias(true);
mRand = new Random();
mBorderPaint = new Paint();
mBorderPaint.setColor(Color.BLACK);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(2.f);
listener.onProgressUpdate(50);
initFields(res, getCurrentState());
listener.onProgressUpdate(80);
drawFieldArea();
mAlienSpawnFrames = ImageUtil.loadFrames(res,
(int) mField.getFieldWidth(),
(int) mField.getFieldHeight(),
BitmapUtil.MODE_FIT_INSIDE,
R.drawable.dice_popup1, R.drawable.dice_popup2, R.drawable.dice_popup3);
listener.onProgressUpdate(100);
}
private void initFields(Resources res, Compacter loadedData) {
try {
DiceFieldBuilder builder = new DiceFieldBuilder(FIELD_X, FIELD_Y);
mField = builder.build(mBitmap.getWidth() / FIELD_X, mBitmap.getHeight() / FIELD_Y);
} catch (BuildException build) {
throw new IllegalStateException("Could not build dice field! " + build);
}
mDiceAlien = ImageUtil.CACHE.obtainImage(CACHE_DICE_ALIEN, res, R.drawable.dice_alien, (int) (mField.getFieldWidth() * 0.7f), (int) (mField.getFieldHeight() * 0.7f), false);
mDiceToMove = null;
if (loadedData != null) {
final int dataOffset = 1;
for (int i = 0; dataOffset + 3 * i + 2 < loadedData.getSize(); i++) {
int x = i % FIELD_X;
int y = i / FIELD_X;
if (mField.isValidPosition(x, y)) {
try {
DicePosition element = mField.getField(x, y);
element.mDiceNumber = loadedData.getInt(dataOffset + 3 * i);
element.mDiceState = loadedData.getInt(dataOffset + 3 * i + 1);
element.mAlpha = loadedData.getInt(dataOffset + 3 * i + 2);
} catch (CompactedDataCorruptException e) {
Log.e("Riddle", "Error reading compacted field number: " + e);
break;
}
}
}
} else {
DicePosition pos = mField.getRandomField(mRand);
mFirstStartDiceState = STATE_RED;
if (TestSubject.isInitialized()) {
int shopValue = TestSubject.getInstance().getShopValue(SortimentHolder
.ARTICLE_KEY_DICE_IMPROVED_START);
for (int i = 0; i < 3; i++) {
if (ShopArticleMulti.hasPurchased(shopValue, i)) {
mFirstStartDiceState = STATE_RED + i + 1;
}
}
mFirstStartDiceState = Math.min(STATE_ALIEN, mFirstStartDiceState);
}
if (pos != null) {
pos.createDice(mFirstStartDiceState,
mFirstStartDiceState == STATE_ALIEN ? 0 : rollDice());
}
}
}
private int rollDice() {
return 1 + mRand.nextInt(NUMBERS_PER_STATE);
}
private void putAchievementGameData(String key, long value) {
mConfig.mAchievementGameData.putValue(key, value, AchievementProperties.UPDATE_POLICY_ALWAYS);
}
private void incrementAchievementGameData(String key) {
mConfig.mAchievementGameData.increment(key, 1L, 0L);
}
private void resetFields() {
mDiceToMove = null;
for (DicePosition pos : mField) {
pos.onReset();
}
incrementAchievementGameData(AchievementDice.KEY_GAME_RESET_COUNT);
updateAchievementDataForFields();
}
private void updateAchievementDataForFields() {
int completelyVisible = 0;
int redCount = 0;
int yellowCount = 0;
int greenCount = 0;
int purpleCount = 0;
int alienCount = 0;
long redNumbersAvailable = 0;
long yellowNumbersAvailable = 0;
long greenNumbersAvailable = 0;
long purpleNumbersAvailable = 0;
for (DicePosition pos: mField) {
if (pos.mAlpha >= 255) {
completelyVisible++;
}
if (pos.isOccupied()) {
switch (pos.mDiceState) {
case STATE_GREEN:
greenNumbersAvailable |= 1L << pos.mDiceNumber; // this will only work if maximum dice number is below 64
greenCount++;
break;
case STATE_YELLOW:
yellowNumbersAvailable |= 1L << pos.mDiceNumber;
yellowCount++;
break;
case STATE_RED:
redNumbersAvailable |= 1L << pos.mDiceNumber;
redCount++;
break;
case STATE_ALIEN:
if (pos.isNumberedAlien()) {
purpleNumbersAvailable |= 1L << pos.mDiceNumber;
purpleCount++;
} else {
alienCount++;
}
}
}
}
mConfig.mAchievementGameData.enableSilentChanges(AchievementDataEvent.EVENT_TYPE_DATA_UPDATE);
putAchievementGameData(AchievementDice.KEY_GAME_FIELDS_COMPLETELY_VISIBLE_COUNT, completelyVisible);
putAchievementGameData(AchievementDice.KEY_GAME_RED_COUNT, redCount);
putAchievementGameData(AchievementDice.KEY_GAME_YELLOW_COUNT, yellowCount);
putAchievementGameData(AchievementDice.KEY_GAME_GREEN_COUNT, greenCount);
putAchievementGameData(AchievementDice.KEY_GAME_PURPLE_COUNT, purpleCount);
putAchievementGameData(AchievementDice.KEY_GAME_ALIEN_COUNT, alienCount);
putAchievementGameData(AchievementDice.KEY_GAME_RED_NUMBERS_AVAILABLE, redNumbersAvailable);
putAchievementGameData(AchievementDice.KEY_GAME_YELLOW_NUMBERS_AVAILABLE, yellowNumbersAvailable);
putAchievementGameData(AchievementDice.KEY_GAME_GREEN_NUMBERS_AVAILABLE, greenNumbersAvailable);
putAchievementGameData(AchievementDice.KEY_GAME_PURPLE_NUMBERS_AVAILABLE, purpleNumbersAvailable);
mConfig.mAchievementGameData.disableSilentChanges();
}
@Override
public boolean onMotionEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mDiceMoveForbidden = false;
DicePosition field = mField.getFieldByCoordinates(event.getX(), event.getY());
if (field != null) {
mDiceToMove = field;
return field.checkCreateDice();
}
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE && mDiceMoveForbidden && mDiceToMove != null) {
DicePosition currField = mField.getFieldByCoordinates(event.getX(), event.getY());
if (currField != null && currField.equals(mDiceToMove)) {
mDiceMoveForbidden = false;
}
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE && mDiceToMove != null & !mDiceMoveForbidden) {
DicePosition currField = mField.getFieldByCoordinates(event.getX(), event.getY());
boolean moveAntStyle = mDiceToMove.moveAntStyle();
long movedState = (long) mDiceToMove.mDiceState;
long movedNumber = (long) mDiceToMove.mDiceNumber;
mMovedDistance = 0;
if (executeDiceMove(currField, !moveAntStyle)) {
mConfig.mAchievementGameData.putValues(AchievementDice.KEY_GAME_LAST_DICE_MOVED_DISTANCE, (long) mMovedDistance, AchievementProperties.UPDATE_POLICY_ALWAYS,
AchievementDice.KEY_GAME_LAST_DICE_MOVED_STATE, movedState, AchievementProperties.UPDATE_POLICY_ALWAYS,
AchievementDice.KEY_GAME_LAST_DICE_MOVED_NUMBER, movedNumber, AchievementProperties.UPDATE_POLICY_ALWAYS);
return true;
}
return false;
} else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
mDiceMoveForbidden = false;
mDiceToMove = null;
}
return false;
}
private int checkDiceMove(DicePosition moveToField) {
if (mDiceToMove != null && !mDiceToMove.equals(moveToField) && mDiceToMove.isMoveable() && moveToField != null) {
if (mDiceToMove.moveAntStyle()) {
return mField.isReachable(mDiceToMove, moveToField, FieldElement.DIRECT_NEIGHBORS);
} else {
return FieldElement.areNeighbors(mDiceToMove, moveToField, FieldElement.DIRECT_NEIGHBORS) ? 1 : -1;
}
}
return -1;
}
private boolean executeDiceMove(DicePosition moveToField, boolean travelAsFarAsPossible) {
int distanceToMove = checkDiceMove(moveToField);
if (distanceToMove < 0) {
return false;
}
mMovedDistance += distanceToMove;
if (!moveToField.isBlocked()) {
// target field is empty
moveToField.mDiceNumber = mDiceToMove.mDiceNumber;
mDiceToMove.mDiceNumber = 0;
moveToField.mDiceState = mDiceToMove.mDiceState;
mDiceToMove.mDiceState = STATE_RED;
DicePosition movedDice = mDiceToMove;
mDiceToMove = moveToField;
drawFieldArea();
if (!mDiceMoveForbidden && travelAsFarAsPossible && !executeDiceMove(mField.travelDirection(movedDice, moveToField), true)) {
mDiceMoveForbidden = true;
}
return true;
} else if (mDiceToMove.isCombinableInto(moveToField)) {
mDiceToMove.combineInto(moveToField);
mDiceToMove = moveToField;
drawFieldArea();
mDiceMoveForbidden = true;
return true;
}
return false;
}
@NonNull
@Override
protected String compactCurrentState() {
Compacter cmp = new Compacter();
cmp.appendData(""); // in case we need it
for (DicePosition pos : mField) {
cmp.appendData(pos.mDiceNumber);
cmp.appendData(pos.mDiceState);
cmp.appendData(pos.mAlpha);
}
return cmp.compact();
}
@Override
protected void addBonusReward(@NonNull RiddleScore.Rewardable rewardable) {
boolean noResets = mConfig.mAchievementGameData != null && mConfig.mAchievementGameData.getValue(AchievementDice.KEY_GAME_RESET_COUNT, 0L) == 0L;
boolean noPurpleDices = mConfig.mAchievementGameData != null
&& mConfig.mAchievementGameData.getValue(AchievementDice.KEY_GAME_PURPLE_COUNT, 0L)
== 0L;
boolean noAliens = mConfig.mAchievementGameData != null && mConfig.mAchievementGameData
.getValue(AchievementDice.KEY_GAME_ALIEN_COUNT, 0L)
== (mFirstStartDiceState == STATE_ALIEN ? 1L : 0L);
int bonus = ((noResets && noPurpleDices && noAliens) ? TypesHolder.SCORE_VERY_HARD :
(noResets && noPurpleDices) ? TypesHolder.SCORE_MEDIUM : 0);
rewardable.addBonus(bonus);
}
@Override
public Bitmap makeSnapshot() {
return BitmapUtil.resize(mFieldArea, SNAPSHOT_DIMENSION.getWidthForDensity(mConfig.mScreenDensity), SNAPSHOT_DIMENSION.getHeightForDensity(mConfig.mScreenDensity));
}
@Override
protected void initAchievementData() {
}
private class DicePosition extends FieldElement implements RiddleAnimation.StateListener {
int mDiceNumber;
int mDiceState;
int mAlpha;
private boolean mHideDice;
@Override
public boolean isBlocked() {
return isOccupied();
}
public boolean isOccupied() {
return mDiceState == STATE_ALIEN || mDiceNumber > 0;
}
@Override
public void draw(Canvas canvas, Rect fieldRect) {
int alpha = mAlpha + (isOccupied() ? STATE_CURRENT_POSITION_TEMP_ALPHA[mDiceState] : 0);
for (FieldElement.Neighbor neighbor : FieldElement.DIRECT_AND_DIAGONAL_NEIGHBORS) {
if (mField.hasNeighbor(this, neighbor)) {
DicePosition pos = mField.getNeighbor(this, neighbor);
if (pos.isNumberedAlien() && FieldElement.areNeighbors(pos, this, NUMBER_NEIGBORS[pos.mDiceNumber - 1])) {
alpha += STATE_NEIGHBOR_TEMP_ALPHA_DIVIDE_BY_NUMBER / pos.mDiceNumber;
}
}
}
alpha = Math.min(255, alpha);
mTransparentPaint.setAlpha(alpha);
canvas.drawBitmap(mBitmap, fieldRect, fieldRect, mTransparentPaint);
if (mMarkedFields.contains(this)) {
mBorderPaint.setColor(mMarkedColor);
} else {
mBorderPaint.setColor(Color.BLACK);
}
canvas.drawRect(fieldRect, mBorderPaint);
if (isOccupied()) {
RectF diceRect = new RectF();
final float padding = ImageUtil.convertDpToPixel(2.f, mConfig.mScreenDensity);
diceRect.set(fieldRect.left + padding, fieldRect.top + padding, fieldRect.right - padding, fieldRect.bottom - padding);
drawDice(canvas, diceRect);
}
}
private void drawDice(Canvas canvas, RectF fieldRect) {
if (mHideDice) {
return;
}
mFieldPaint.setColor(STATE_COLOR[mDiceState]);
canvas.drawRoundRect(fieldRect, fieldRect.width() / 3.f, fieldRect.height() / 3.f, mFieldPaint);
if (mDiceNumber > 0) {
for (FieldElement.Neighbor n : NUMBER_NEIGBORS[mDiceNumber - 1]) {
canvas.drawCircle(fieldRect.centerX() + n.getXDelta() * fieldRect.width() / 4,
fieldRect.centerY() + n.getYDelta() * fieldRect.height() / 4,
mDiceDotRadius, mDiceDotPaint);
}
} else if (mDiceState == STATE_ALIEN) {
canvas.drawBitmap(mDiceAlien, fieldRect.left + (mField.getFieldWidth() - mDiceAlien.getWidth()) / 2.f,
fieldRect.top + (mField.getFieldHeight() - mDiceAlien.getHeight()) / 2.f, null);
}
}
private void increaseNeighborAlphaPermanently() {
int number = mDiceNumber;
if (number <= 0) {
return;
}
mMarkedFields.clear();
mMarkedColor = STATE_COLOR[mDiceState];
int alphaIncrease = STATE_NEIGHBOR_PERM_ALPHA_INCREASE[mDiceState];
if (alphaIncrease > 0) {
FieldElement.Neighbor[] neighbors = NUMBER_NEIGBORS[Math.max(mDiceNumber - 1, 0)];
for (FieldElement.Neighbor n : neighbors) {
if (mField.hasNeighbor(this, n)) {
DicePosition neighbor = mField.getNeighbor(this, n);
mMarkedFields.add(neighbor);
neighbor.mAlpha += alphaIncrease;
}
}
}
}
private boolean checkCreateDice() {
if (!isOccupied()) {
createDice(STATE_RED, rollDice());
return true;
}
return false;
}
private void createDice(int state, int number) {
mDiceNumber = number;
mDiceState = state;
int dicesCount = 0;
for (DicePosition pos : mField) {
if (pos.isOccupied()) {
dicesCount++;
}
}
if (dicesCount == mField.getFieldCount()) {
resetFields();
} else {
updateAchievementDataForFields();
}
drawFieldArea();
}
public void onReset() {
if (mDiceNumber <= 0) {
return;
}
switch (mDiceState) {
case STATE_RED: // no break
case STATE_YELLOW:
mDiceNumber = 0;
mDiceState = STATE_RED;
break;
case STATE_GREEN: // no break
mDiceNumber--;
break;
case STATE_ALIEN:
if (mDiceNumber > 0) {
mDiceNumber = 0;
mDiceState = STATE_RED;
}
}
mAlpha = (int) (ALPHA_RESET_PENALTY_FACTOR * mAlpha);
}
public boolean isMoveable() {
return isOccupied();
}
public boolean isCombinableInto(DicePosition target) {
return isOccupied() && target.isOccupied() &&
((mDiceState == STATE_ALIEN && mDiceNumber == 0 && target.mDiceState != STATE_ALIEN)
|| (mDiceState != STATE_ALIEN && mDiceState == target.mDiceState && mDiceNumber == target.mDiceNumber));
}
public void combineInto(DicePosition target) {
if (BuildConfig.DEBUG && !isCombinableInto(target)) {
Log.e("Riddle", "Trying to combine into not combinable.");
return;
}
mConfig.mAchievementGameData.putValues(AchievementDice.KEY_GAME_LAST_DICE_COMBINED_STATE, (long) mDiceState, AchievementProperties.UPDATE_POLICY_ALWAYS,
AchievementDice.KEY_GAME_LAST_DICE_COMBINED_POSITION, (long) (target.mX + target.mY * FIELD_X), AchievementProperties.UPDATE_POLICY_ALWAYS,
null, 0L, 0L);
if (mDiceState == STATE_ALIEN) {
if (target.mDiceState == STATE_RED) {
// skip yellow and get the same number with green
target.mDiceState = STATE_GREEN;
incrementAchievementGameData(AchievementDice.KEY_GAME_ALIEN_FUSED_WITH_RED);
} else if (target.mDiceState == STATE_YELLOW) {
// make target field completely visible and make it disappear
target.mAlpha += 255;
target.mDiceState = STATE_RED;
target.mDiceNumber = 0;
incrementAchievementGameData(AchievementDice.KEY_GAME_ALIEN_FUSED_WITH_YELLOW);
} else if (target.mDiceState == STATE_GREEN) {
// make target a numbered alien dice
target.mDiceState = STATE_ALIEN;
incrementAchievementGameData(AchievementDice.KEY_GAME_ALIEN_FUSED_WITH_GREEN);
}
} else {
target.mDiceState++;
if (target.mDiceState == STATE_ALIEN) {
// we created an alien dice
final long animTime = 900L;
target.mHideDice = true;
addAnimation(new LookRiddleAnimation(new FramesOneshot(mAlienSpawnFrames,
animTime),
(int) (target.mX * mField.getFieldWidth()),
(int) (target.mY * mField.getFieldHeight()),
animTime)
.setStateListener(target));
target.mDiceNumber = 0;
}
}
target.increaseNeighborAlphaPermanently();
mDiceNumber = 0;
mDiceState = STATE_RED;
updateAchievementDataForFields();
}
/**
* Returns if this dice (if any) is supposed to move ant style, that is field by field discovering
* any possible path. If false then the dice is just like a chess tower and moves in a straight line.
* @return If the dice is supposed to search any possible path to the target.
*/
public boolean moveAntStyle() {
return mDiceState == STATE_RED || mDiceState == STATE_YELLOW;
}
/**
* If this is an alien dice with a number.
* @return Is this a dotted alien?
*/
public boolean isNumberedAlien() {
return mDiceState == STATE_ALIEN && mDiceNumber > 0;
}
@Override
public void onBorn() {
// alien animation created
mHideDice = true;//make sure it is hidden
drawFieldArea();
}
@Override
public void onKilled(boolean murdered) {
// animation removed
mHideDice = false;
drawFieldArea();
}
}
/**
* Factory class mainly because we cannot instantiate generic arrays.
*/
private class DiceFieldBuilder extends Field2D.Builder<DicePosition> {
public DiceFieldBuilder(int xCount, int yCount) throws BuildException {
for (int y = 0; y < yCount; y++) {
nextRow();
for (int x = 0; x < xCount; x++) {
nextElement(new DicePosition());
}
}
}
@Override
protected DicePosition[][] makeArray(int rows, int columns) {
return new DicePosition[rows][columns];
}
}
}