diff --git a/AndorsTrail/res/anim/hidecombatbar.xml b/AndorsTrail/res/anim/hidecombatbar.xml
new file mode 100644
index 000000000..77f471c13
--- /dev/null
+++ b/AndorsTrail/res/anim/hidecombatbar.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/anim/scalebeat.xml b/AndorsTrail/res/anim/scalebeat.xml
new file mode 100644
index 000000000..3471f26ab
--- /dev/null
+++ b/AndorsTrail/res/anim/scalebeat.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/anim/scaledown.xml b/AndorsTrail/res/anim/scaledown.xml
new file mode 100644
index 000000000..0c15c5a1c
--- /dev/null
+++ b/AndorsTrail/res/anim/scaledown.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/AndorsTrail/res/anim/scaleup.xml b/AndorsTrail/res/anim/scaleup.xml
new file mode 100644
index 000000000..138d2a36b
--- /dev/null
+++ b/AndorsTrail/res/anim/scaleup.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/AndorsTrail/res/anim/showcombatbar.xml b/AndorsTrail/res/anim/showcombatbar.xml
new file mode 100644
index 000000000..aa6461964
--- /dev/null
+++ b/AndorsTrail/res/anim/showcombatbar.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/main.xml b/AndorsTrail/res/layout/main.xml
index fb98625f9..9be5d0193 100644
--- a/AndorsTrail/res/layout/main.xml
+++ b/AndorsTrail/res/layout/main.xml
@@ -54,13 +54,12 @@
android:shadowColor="#000"
/>
-
diff --git a/AndorsTrail/res/values/strings.xml b/AndorsTrail/res/values/strings.xml
index 1fcb53d3c..c8a2de429 100644
--- a/AndorsTrail/res/values/strings.xml
+++ b/AndorsTrail/res/values/strings.xml
@@ -504,5 +504,8 @@
When making an attack on a target whose block chance (BC) is at least %1$d lower than your attack chance (AC), there is a %2$d %% chance that the hit will cause a concussion on the target. A concussion will severely lower the target\'s offensive combat abilities, making the target less able to land successful attacks.
About
+ Interface
+ Enable animations
+ Show animations for various interface elements, such as the combat bar.
diff --git a/AndorsTrail/res/xml/preferences.xml b/AndorsTrail/res/xml/preferences.xml
index 1102f6a2b..656df7d0a 100644
--- a/AndorsTrail/res/xml/preferences.xml
+++ b/AndorsTrail/res/xml/preferences.xml
@@ -72,4 +72,12 @@
android:summary="@string/preferences_movement_dpad_minimizeable"
android:key="dpadMinimizeable" />
+
+
+
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java
index 0e84f3ec5..3993bb796 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java
@@ -34,6 +34,7 @@ public class AndorsTrailPreferences {
public int dpadPosition;
public boolean dpadMinimizeable = true;
public boolean optimizedDrawing = false;
+ public boolean enableUiAnimations = true;
public static void read(final Context androidContext, AndorsTrailPreferences dest) {
try {
@@ -48,6 +49,7 @@ public class AndorsTrailPreferences {
dest.dpadPosition = Integer.parseInt(prefs.getString("dpadposition", Integer.toString(DPAD_POSITION_DISABLED)));
dest.dpadMinimizeable = prefs.getBoolean("dpadMinimizeable", true);
dest.optimizedDrawing = prefs.getBoolean("optimized_drawing", false);
+ dest.enableUiAnimations = prefs.getBoolean("enableUiAnimations", true);
// This might be implemented as a skill in the future.
//dest.movementAggressiveness = Integer.parseInt(prefs.getString("movementaggressiveness", Integer.toString(MOVEMENTAGGRESSIVENESS_NORMAL)));
@@ -63,6 +65,7 @@ public class AndorsTrailPreferences {
dest.dpadPosition = DPAD_POSITION_DISABLED;
dest.dpadMinimizeable = true;
dest.optimizedDrawing = false;
+ dest.enableUiAnimations = true;
}
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java
index badc06f6a..0f70c143d 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java
@@ -16,6 +16,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.view.CombatView;
+import com.gpl.rpg.AndorsTrail.view.DisplayActiveActorConditionIcons;
import com.gpl.rpg.AndorsTrail.view.MainView;
import com.gpl.rpg.AndorsTrail.view.VirtualDpadView;
import com.gpl.rpg.AndorsTrail.view.QuickButton.QuickButtonContextMenuInfo;
@@ -33,7 +34,7 @@ import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View.OnClickListener;
-import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
@@ -59,7 +60,7 @@ public final class MainActivity extends Activity {
public StatusView statusview;
public CombatView combatview;
public QuickitemView quickitemview;
- private LinearLayout activeConditions;
+ private DisplayActiveActorConditionIcons activeConditions;
private VirtualDpadView dpad;
private static final int NUM_MESSAGES = 3;
@@ -84,7 +85,7 @@ public final class MainActivity extends Activity {
statusview = (StatusView) findViewById(R.id.main_statusview);
combatview = (CombatView) findViewById(R.id.main_combatview);
quickitemview = (QuickitemView) findViewById(R.id.main_quickitemview);
- activeConditions = (LinearLayout) findViewById(R.id.statusview_activeconditions);
+ activeConditions = new DisplayActiveActorConditionIcons(app.preferences, world.tileManager, this, (RelativeLayout) findViewById(R.id.statusview_activeconditions));
dpad = (VirtualDpadView) findViewById(R.id.main_virtual_dpad);
statusText = (TextView) findViewById(R.id.statusview_statustext);
@@ -165,6 +166,8 @@ public final class MainActivity extends Activity {
view.gameRoundController.pause();
view.movementController.stopMovement();
+ activeConditions.unsubscribe(world);
+
save(Savegames.SLOT_QUICKSAVE);
}
@@ -173,6 +176,8 @@ public final class MainActivity extends Activity {
super.onResume();
if (!AndorsTrailApplication.getApplicationFromActivity(this).setup.isSceneReady) return;
+ activeConditions.subscribe(world);
+
view.gameRoundController.resume();
if (world.model.uiSelections.isInCombat) {
@@ -257,7 +262,6 @@ public final class MainActivity extends Activity {
public void updateStatus() {
statusview.updateStatus();
- statusview.updateActiveConditions(this, activeConditions);
quickitemview.refreshQuickitems();
combatview.updateStatus();
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java
index 0d53eab0e..8937faaaf 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java
@@ -59,10 +59,12 @@ public class ActorStatsController {
if (!type.conditionTypeID.equals(c.conditionType.conditionTypeID)) continue;
if (c.duration != duration) continue;
- actor.conditions.remove(i);
- magnitude = c.magnitude - magnitude;
- if (magnitude > 0) {
- actor.conditions.add(new ActorCondition(type, magnitude, duration));
+ if (c.magnitude > magnitude) {
+ c.magnitude -= magnitude;
+ actor.conditionListener.onActorConditionMagnitudeChanged(actor, c);
+ } else {
+ actor.conditions.remove(i);
+ actor.conditionListener.onActorConditionRemoved(actor, c);
}
break;
}
@@ -109,12 +111,14 @@ public class ActorStatsController {
if (!type.conditionTypeID.equals(c.conditionType.conditionTypeID)) continue;
if (c.duration == duration) {
// If the actor already has a condition of this type and the same duration, just increase the magnitude instead.
- actor.conditions.remove(i);
- magnitude += c.magnitude;
- break;
+ c.magnitude += magnitude;
+ actor.conditionListener.onActorConditionMagnitudeChanged(actor, c);
+ return;
}
}
- actor.conditions.add(new ActorCondition(type, magnitude, duration));
+ ActorCondition c = new ActorCondition(type, magnitude, duration);
+ actor.conditions.add(c);
+ actor.conditionListener.onActorConditionAdded(actor, c);
}
private static void addNonStackableActorCondition(Actor actor, ActorConditionEffect e, int duration) {
final ActorConditionType type = e.conditionType;
@@ -123,24 +127,34 @@ public class ActorStatsController {
ActorCondition c = actor.conditions.get(i);
if (!type.conditionTypeID.equals(c.conditionType.conditionTypeID)) continue;
if (c.magnitude > e.magnitude) return;
+ else if (c.magnitude == e.magnitude) {
+ if (c.duration >= duration) return;
+ }
// If the actor already has this condition, but of a lower magnitude, we remove the old one and add this higher magnitude.
actor.conditions.remove(i);
+ actor.conditionListener.onActorConditionRemoved(actor, c);
}
- actor.conditions.add(e.createCondition(duration));
+
+ ActorCondition c = e.createCondition(duration);
+ actor.conditions.add(c);
+ actor.conditionListener.onActorConditionAdded(actor, c);
}
public static void removeAllTemporaryConditions(final Actor actor) {
for(int i = actor.conditions.size() - 1; i >= 0; --i) {
- if (!actor.conditions.get(i).isTemporaryEffect()) continue;
+ ActorCondition c = actor.conditions.get(i);
+ if (!c.isTemporaryEffect()) continue;
actor.conditions.remove(i);
+ actor.conditionListener.onActorConditionRemoved(actor, c);
}
}
private static void removeAllConditionsOfType(final Actor actor, final String conditionTypeID) {
for(int i = actor.conditions.size() - 1; i >= 0; --i) {
- if (actor.conditions.get(i).conditionType.conditionTypeID.equals(conditionTypeID)) {
- actor.conditions.remove(i);
- }
+ ActorCondition c = actor.conditions.get(i);
+ if (!c.conditionType.conditionTypeID.equals(conditionTypeID)) continue;
+ actor.conditions.remove(i);
+ actor.conditionListener.onActorConditionRemoved(actor, c);
}
}
@@ -210,10 +224,13 @@ public class ActorStatsController {
if (SkillController.rollForSkillChance(player, SkillCollection.SKILL_REJUVENATION, SkillCollection.PER_SKILLPOINT_INCREASE_REJUVENATION_CHANCE)) {
int i = getRandomConditionForRejuvenate(player);
if (i >= 0) {
- ActorCondition c = player.conditions.remove(i);
+ ActorCondition c = player.conditions.get(i);
if (c.magnitude > 1) {
- int magnitude = c.magnitude - 1;
- player.conditions.add(i, new ActorCondition(c.conditionType, magnitude, c.duration));
+ c.magnitude -= 1;
+ player.conditionListener.onActorConditionMagnitudeChanged(player, c);
+ } else {
+ player.conditions.remove(i);
+ player.conditionListener.onActorConditionRemoved(player, c);
}
recalculateActorCombatTraits(player);
}
@@ -258,6 +275,7 @@ public class ActorStatsController {
for (ActorCondition c : actor.conditions) {
StatsModifierTraits effect = isFullRound ? c.conditionType.statsEffect_everyFullRound : c.conditionType.statsEffect_everyRound;
effectToStart = applyStatsModifierEffect(actor, effect, c.magnitude, effectToStart);
+ if (effect != null) actor.conditionListener.onActorConditionRoundEffectApplied(actor, c);
}
startVisualEffect(actor, effectToStart);
}
@@ -267,10 +285,13 @@ public class ActorStatsController {
for(int i = actor.conditions.size() - 1; i >= 0; --i) {
ActorCondition c = actor.conditions.get(i);
if (!c.isTemporaryEffect()) continue;
- c.duration -= 1;
- if (c.duration <= 0) {
+ if (c.duration <= 1) {
actor.conditions.remove(i);
+ actor.conditionListener.onActorConditionRemoved(actor, c);
removedAnyConditions = true;
+ } else {
+ c.duration -= 1;
+ actor.conditionListener.onActorConditionDurationChanged(actor, c);
}
}
if (removedAnyConditions) {
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java
index a0911b735..ebc2da269 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java
@@ -6,7 +6,6 @@ import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
import android.util.FloatMath;
-import android.view.View;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.Dialogs;
@@ -49,8 +48,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
public static final int BEGIN_TURN_CONTINUE = 2;
public void enterCombat(int beginTurnAs) {
- context.mainActivity.combatview.setVisibility(View.VISIBLE);
- context.mainActivity.combatview.bringToFront();
+ context.mainActivity.combatview.show();
model.uiSelections.isInCombat = true;
killedMonsterBags.clear();
context.mainActivity.clearMessages();
@@ -61,7 +59,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
}
public void exitCombat(boolean pickupLootBags) {
setCombatSelection(null, null);
- context.mainActivity.combatview.setVisibility(View.GONE);
+ context.mainActivity.combatview.hide();
model.uiSelections.isInCombat = false;
context.mainActivity.clearMessages();
currentActiveMonster = null;
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java
index 32a061c5e..ce7fbe663 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java
@@ -241,16 +241,12 @@ public final class MovementController implements TimedMessageTask.Callback {
if (!world.model.currentMap.isWalkable(world.model.player.position)) {
// If the player somehow spawned on an unwalkable tile, we move the player to the first mapchange area.
// This could happen if we change some tile to non-walkable in a future version.
- MapObject dest = null;
for (MapObject o : model.currentMap.eventObjects) {
if (o.type == MapObject.MAPEVENT_NEWMAP) {
- dest = o;
+ model.player.position.set(o.position.topLeft);
break;
}
}
- if (dest != null) {
- model.player.position.set(dest.position.topLeft);
- }
}
// If any monsters somehow spawned on an unwalkable tile, we move the monster to a new position on the spawnarea
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ability/ActorCondition.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ability/ActorCondition.java
index 772a48f4b..bb0848e6f 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ability/ActorCondition.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ability/ActorCondition.java
@@ -11,7 +11,7 @@ public class ActorCondition {
public static final int DURATION_FOREVER = 999;
public final ActorConditionType conditionType;
- public final int magnitude;
+ public int magnitude;
public int duration;
public ActorCondition(ActorConditionType conditionType, int magnitude, int duration) {
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java
index bec0b1035..20efe7490 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java
@@ -8,6 +8,7 @@ import java.util.ArrayList;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
+import com.gpl.rpg.AndorsTrail.model.listeners.ActorConditionListeners;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Range;
@@ -20,6 +21,7 @@ public class Actor {
public final Coord position;
public final CoordRect rectPosition;
public final ArrayList conditions = new ArrayList();
+ public final ActorConditionListeners conditionListener = new ActorConditionListeners();
public final boolean isPlayer;
public final boolean isImmuneToCriticalHits;
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ActorConditionListener.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ActorConditionListener.java
new file mode 100644
index 000000000..6db177052
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ActorConditionListener.java
@@ -0,0 +1,12 @@
+package com.gpl.rpg.AndorsTrail.model.listeners;
+
+import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
+import com.gpl.rpg.AndorsTrail.model.actor.Actor;
+
+public interface ActorConditionListener {
+ public void onActorConditionAdded(Actor actor, ActorCondition condition);
+ public void onActorConditionRemoved(Actor actor, ActorCondition condition);
+ public void onActorConditionDurationChanged(Actor actor, ActorCondition condition);
+ public void onActorConditionMagnitudeChanged(Actor actor, ActorCondition condition);
+ public void onActorConditionRoundEffectApplied(Actor actor, ActorCondition condition);
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ActorConditionListeners.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ActorConditionListeners.java
new file mode 100644
index 000000000..3ea927190
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ActorConditionListeners.java
@@ -0,0 +1,48 @@
+package com.gpl.rpg.AndorsTrail.model.listeners;
+
+import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
+import com.gpl.rpg.AndorsTrail.model.actor.Actor;
+
+public class ActorConditionListeners extends ListOfListeners implements ActorConditionListener {
+
+ private final Function2 onActorConditionAdded = new Function2() {
+ @Override public void call(ActorConditionListener listener, Actor actor, ActorCondition condition) { listener.onActorConditionAdded(actor, condition); }
+ };
+ private final Function2 onActorConditionRemoved = new Function2() {
+ @Override public void call(ActorConditionListener listener, Actor actor, ActorCondition condition) { listener.onActorConditionRemoved(actor, condition); }
+ };
+ private final Function2 onActorConditionDurationChanged = new Function2() {
+ @Override public void call(ActorConditionListener listener, Actor actor, ActorCondition condition) { listener.onActorConditionDurationChanged(actor, condition); }
+ };
+ private final Function2 onActorConditionMagnitudeChanged = new Function2() {
+ @Override public void call(ActorConditionListener listener, Actor actor, ActorCondition condition) { listener.onActorConditionMagnitudeChanged(actor, condition); }
+ };
+ private final Function2 onActorConditionRoundEffectApplied = new Function2() {
+ @Override public void call(ActorConditionListener listener, Actor actor, ActorCondition condition) { listener.onActorConditionRoundEffectApplied(actor, condition); }
+ };
+
+ @Override
+ public void onActorConditionAdded(Actor actor, ActorCondition condition) {
+ callAllListeners(this.onActorConditionAdded, actor, condition);
+ }
+
+ @Override
+ public void onActorConditionRemoved(Actor actor, ActorCondition condition) {
+ callAllListeners(this.onActorConditionRemoved, actor, condition);
+ }
+
+ @Override
+ public void onActorConditionDurationChanged(Actor actor, ActorCondition condition) {
+ callAllListeners(this.onActorConditionDurationChanged, actor, condition);
+ }
+
+ @Override
+ public void onActorConditionMagnitudeChanged(Actor actor, ActorCondition condition) {
+ callAllListeners(this.onActorConditionMagnitudeChanged, actor, condition);
+ }
+
+ @Override
+ public void onActorConditionRoundEffectApplied(Actor actor, ActorCondition condition) {
+ callAllListeners(this.onActorConditionRoundEffectApplied, actor, condition);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ListOfListeners.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ListOfListeners.java
new file mode 100644
index 000000000..c968e3e46
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/listeners/ListOfListeners.java
@@ -0,0 +1,61 @@
+package com.gpl.rpg.AndorsTrail.model.listeners;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+
+public class ListOfListeners {
+ private final ArrayList> listeners = new ArrayList>();
+
+ public void add(T listener) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ for (WeakReference ref : listeners) {
+ if (ref.get() == listener) {
+ throw new IndexOutOfBoundsException("FAIL: listener added twice to ListOfListeners.");
+ }
+ }
+ }
+ listeners.add(new WeakReference(listener));
+ }
+ public void remove(T listenerToRemove) {
+ for (int i = listeners.size()-1; i >= 0; --i) {
+ T listener = listeners.get(i).get();
+ if (listener == null || listener == listenerToRemove) {
+ listeners.remove(i);
+ }
+ }
+ }
+
+ protected void callAllListeners(Function e) {
+ for (int i = listeners.size()-1; i >= 0; --i) {
+ T listener = listeners.get(i).get();
+ if (listener == null) listeners.remove(i);
+ else e.call(listener);
+ }
+ }
+ protected void callAllListeners(Function1 e, Arg1 arg) {
+ for (int i = listeners.size()-1; i >= 0; --i) {
+ T listener = listeners.get(i).get();
+ if (listener == null) listeners.remove(i);
+ else e.call(listener, arg);
+ }
+ }
+ protected void callAllListeners(Function2 e, Arg1 arg1, Arg2 arg2) {
+ for (int i = listeners.size()-1; i >= 0; --i) {
+ T listener = listeners.get(i).get();
+ if (listener == null) listeners.remove(i);
+ else e.call(listener, arg1, arg2);
+ }
+ }
+
+ protected static interface Function {
+ public void call(Listener listener);
+ }
+ protected static interface Function1 {
+ public void call(Listener listener, Arg1 arg1);
+ }
+ protected static interface Function2 {
+ public void call(Listener listener, Arg1 arg1, Arg2 arg2);
+ }
+}
\ No newline at end of file
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java
index a34722494..db6102635 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java
@@ -5,11 +5,15 @@ import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.Dialogs;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
@@ -33,15 +37,20 @@ public final class CombatView extends RelativeLayout {
private final WorldContext world;
private final ViewContext view;
private final Resources res;
+ private final AndorsTrailPreferences preferences;
private final Player player;
+ private final Animation displayAnimation;
+ private final Animation hideAnimation;
private Monster currentMonster;
+
public CombatView(final Context context, AttributeSet attr) {
super(context, attr);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
this.world = app.world;
this.player = world.model.player;
this.view = app.currentView.get();
+ this.preferences = app.preferences;
this.res = getResources();
setFocusable(false);
@@ -90,6 +99,16 @@ public final class CombatView extends RelativeLayout {
monsterBar.setBackgroundColor(res.getColor(color.transparent));
actionBar.setBackgroundColor(res.getColor(color.transparent));
+
+ displayAnimation = AnimationUtils.loadAnimation(context, R.anim.showcombatbar);
+ hideAnimation = AnimationUtils.loadAnimation(context, R.anim.hidecombatbar);
+ hideAnimation.setAnimationListener(new AnimationListener() {
+ @Override public void onAnimationStart(Animation animation) {}
+ @Override public void onAnimationRepeat(Animation animation) {}
+ @Override public void onAnimationEnd(Animation arg0) {
+ CombatView.this.setVisibility(View.GONE);
+ }
+ });
}
public void updateTurnInfo(Monster currentActiveMonster) {
@@ -135,4 +154,20 @@ public final class CombatView extends RelativeLayout {
}
updateCombatSelection(world.model.uiSelections.selectedMonster, world.model.uiSelections.selectedPosition);
}
+
+ public void show() {
+ setVisibility(View.VISIBLE);
+ bringToFront();
+ if (preferences.enableUiAnimations) {
+ startAnimation(displayAnimation);
+ }
+ }
+
+ public void hide() {
+ if (preferences.enableUiAnimations) {
+ startAnimation(hideAnimation);
+ } else {
+ setVisibility(View.GONE);
+ }
+ }
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/DisplayActiveActorConditionIcons.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/DisplayActiveActorConditionIcons.java
new file mode 100644
index 000000000..c14864707
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/DisplayActiveActorConditionIcons.java
@@ -0,0 +1,220 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.RelativeLayout.LayoutParams;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
+import com.gpl.rpg.AndorsTrail.model.actor.Actor;
+import com.gpl.rpg.AndorsTrail.model.listeners.ActorConditionListener;
+import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
+
+public class DisplayActiveActorConditionIcons implements ActorConditionListener {
+
+ private final AndorsTrailPreferences preferences;
+ private final TileManager tileManager;
+ private final RelativeLayout activeConditions;
+ private final ArrayList currentConditionIcons = new ArrayList();
+ private final WeakReference androidContext;
+
+ public DisplayActiveActorConditionIcons(
+ final AndorsTrailPreferences preferences,
+ final TileManager tileManager,
+ Context androidContext,
+ RelativeLayout activeConditions) {
+ this.preferences = preferences;
+ this.tileManager = tileManager;
+ this.androidContext = new WeakReference(androidContext);
+ this.activeConditions = activeConditions;
+ }
+
+ @Override
+ public void onActorConditionAdded(Actor actor, ActorCondition condition) {
+ ActiveConditionIcon icon = getFirstFreeIcon();
+ icon.setActiveCondition(condition);
+ icon.show();
+ }
+
+ @Override
+ public void onActorConditionRemoved(Actor actor, ActorCondition condition) {
+ ActiveConditionIcon icon = getIconFor(condition);
+ if (icon == null) return;
+ icon.hide(true);
+ }
+
+ @Override
+ public void onActorConditionDurationChanged(Actor actor, ActorCondition condition) {
+ }
+
+ @Override
+ public void onActorConditionMagnitudeChanged(Actor actor, ActorCondition condition) {
+ ActiveConditionIcon icon = getIconFor(condition);
+ if (icon == null) return;
+ icon.setIconText();
+ }
+
+ @Override
+ public void onActorConditionRoundEffectApplied(Actor actor, ActorCondition condition) {
+ ActiveConditionIcon icon = getIconFor(condition);
+ if (icon == null) return;
+ icon.pulseAnimate();
+ }
+
+ public void unsubscribe(final WorldContext world) {
+ world.model.player.conditionListener.remove(this);
+ for (ActiveConditionIcon icon : currentConditionIcons) icon.condition = null;
+ }
+
+ public void subscribe(final WorldContext world) {
+ for (ActiveConditionIcon icon : currentConditionIcons) icon.hide(false);
+ for (ActorCondition condition : world.model.player.conditions) {
+ getFirstFreeIcon().setActiveCondition(condition);
+ }
+ world.model.player.conditionListener.add(this);
+ }
+
+ private final class ActiveConditionIcon implements AnimationListener {
+ public final int id;
+ public ActorCondition condition;
+ public final ImageView image;
+ public final TextView text;
+ private final Animation onNewIconAnimation;
+ private final Animation onRemovedIconAnimation;
+ private final Animation onAppliedEffectAnimation;
+
+ public ActiveConditionIcon(Context context, int id) {
+ this.id = id;
+ this.image = new ImageView(context);
+ this.image.setId(id);
+ this.text = new TextView(context);
+ this.onNewIconAnimation = AnimationUtils.loadAnimation(context, R.anim.scaleup);
+ this.onRemovedIconAnimation = AnimationUtils.loadAnimation(context, R.anim.scaledown);
+ this.onAppliedEffectAnimation = AnimationUtils.loadAnimation(context, R.anim.scalebeat);
+ this.onRemovedIconAnimation.setAnimationListener(this);
+
+ final Resources res = context.getResources();
+
+ text.setTextColor(res.getColor(android.R.color.white));
+ text.setShadowLayer(1, 1, 1, res.getColor(android.R.color.black));
+ }
+
+ private void setActiveCondition(ActorCondition condition) {
+ this.condition = condition;
+ tileManager.setImageViewTile(image, condition.conditionType);
+ image.setVisibility(View.VISIBLE);
+ setIconText();
+ }
+
+ public void setIconText() {
+ boolean showMagnitude = (condition.magnitude != 1);
+ if (showMagnitude) {
+ text.setText(Integer.toString(condition.magnitude));
+ text.setVisibility(View.VISIBLE);
+ } else {
+ text.setVisibility(View.GONE);
+ }
+ }
+
+ public void hide(boolean useAnimation) {
+ if (useAnimation) {
+ if (preferences.enableUiAnimations) {
+ image.startAnimation(onRemovedIconAnimation);
+ } else {
+ onAnimationEnd(onRemovedIconAnimation);
+ }
+ } else {
+ image.setVisibility(View.GONE);
+ condition = null;
+ }
+ text.setVisibility(View.GONE);
+ }
+ public void show() {
+ if (!preferences.enableUiAnimations) return;
+ image.startAnimation(onNewIconAnimation);
+ if (text.getVisibility() == View.VISIBLE) text.startAnimation(onNewIconAnimation);
+ }
+
+ public void pulseAnimate() {
+ if (!preferences.enableUiAnimations) return;
+ image.startAnimation(onAppliedEffectAnimation);
+ }
+
+ public boolean isVisible() {
+ return condition != null;
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (animation == this.onRemovedIconAnimation) {
+ hide(false);
+ rearrangeIconsLeftOf(this);
+ }
+ }
+
+ @Override public void onAnimationRepeat(Animation animation) { }
+ @Override public void onAnimationStart(Animation animation) { }
+ }
+
+ protected void rearrangeIconsLeftOf(ActiveConditionIcon icon) {
+ int i = currentConditionIcons.indexOf(icon);
+ currentConditionIcons.remove(i);
+ currentConditionIcons.add(icon);
+ for(; i < currentConditionIcons.size(); ++i) {
+ currentConditionIcons.get(i).image.setLayoutParams(getLayoutParamsForIconIndex(i));
+ }
+ }
+
+ private ActiveConditionIcon getIconFor(ActorCondition condition) {
+ for (ActiveConditionIcon icon : currentConditionIcons) {
+ if (icon.condition == condition) return icon;
+ }
+ return null;
+ }
+ private ActiveConditionIcon getFirstFreeIcon() {
+ for (ActiveConditionIcon icon : currentConditionIcons) {
+ if (!icon.isVisible()) return icon;
+ }
+ return addNewActiveConditionIcon();
+ }
+
+ private RelativeLayout.LayoutParams getLayoutParamsForIconIndex(int index) {
+ RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ layout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ if (index == 0) {
+ layout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+ } else {
+ layout.addRule(RelativeLayout.LEFT_OF, currentConditionIcons.get(index-1).id);
+ }
+ return layout;
+ }
+
+ private ActiveConditionIcon addNewActiveConditionIcon() {
+ int index = currentConditionIcons.size();
+
+ ActiveConditionIcon icon = new ActiveConditionIcon(androidContext.get(), index+1);
+
+ activeConditions.addView(icon.image, getLayoutParamsForIconIndex(index));
+
+ RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ layout.addRule(RelativeLayout.ALIGN_RIGHT, icon.id);
+ layout.addRule(RelativeLayout.ALIGN_BOTTOM, icon.id);
+ activeConditions.addView(icon.text, layout);
+
+ currentConditionIcons.add(icon);
+
+ return icon;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java
index c6d0a36a8..f2897c781 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java
@@ -6,7 +6,6 @@ import com.gpl.rpg.AndorsTrail.activity.MainActivity;
import com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity;
import com.gpl.rpg.AndorsTrail.context.ViewContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
-import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
@@ -17,8 +16,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ImageButton;
@@ -97,15 +94,6 @@ public final class StatusView extends RelativeLayout {
world.tileManager.setImageViewTile(heroImage, player);
}
}
-
- public void updateActiveConditions(Context androidContext, LinearLayout activeConditions) {
- GreedyImageViewAppender t = new GreedyImageViewAppender(androidContext, activeConditions);
- for (ActorCondition condition : player.conditions) {
- ImageView iv = t.getNextImage();
- world.tileManager.setImageViewTile(iv, condition.conditionType);
- }
- t.removeOtherImages();
- }
public void updateQuickItemImage(boolean visible){
if(visible){
@@ -114,41 +102,4 @@ public final class StatusView extends RelativeLayout {
world.tileManager.setImageViewTileForUIIcon(quickToggle, TileManager.iconID_boxclosed);
}
}
-
- private static class GreedyImageViewAppender {
- private final LinearLayout container;
- private final Context context;
- private int currentChildIndex = 0;
- private final int previousChildCount;
- private final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
-
- public GreedyImageViewAppender(Context context, LinearLayout container) {
- this.container = container;
- this.context = context;
- this.previousChildCount = container.getChildCount();
- }
- public ImageView getNextImage() {
- // Since this is called a lot, we do not want to recreate the view objects every time.
- // Therefore, we reuse existing ImageView:s if they are present, but just change the image on them.
- ImageView iv;
- if (currentChildIndex < previousChildCount) {
- // There already is a create dimage on this position, reuse it.
- iv = (ImageView) container.getChildAt(currentChildIndex);
- iv.setVisibility(View.VISIBLE);
- } else {
- // The player has never had this many conditions, create a new ImageView to hold the condition image.
- iv = new ImageView(context);
- container.addView(iv, layoutParams);
- }
- ++currentChildIndex;
- return iv;
- }
- public void removeOtherImages() {
- for(int i = previousChildCount - 1; i >= currentChildIndex; --i) {
- //container.removeViewAt(i);
- // Don't actually remove them, just hide them (so we won't have to recreate them next time the player get a condition)
- container.getChildAt(i).setVisibility(View.GONE);
- }
- }
- }
}