WIP 6 - Moved around lots of properties.

This commit is contained in:
Oskar Wiksten
2012-11-08 00:55:15 +01:00
parent be5298c247
commit ca4ad69f36
36 changed files with 758 additions and 316 deletions

View File

@@ -255,7 +255,7 @@ public class BulkSelectionInterface extends Activity implements TextWatcher {
if (amount > totalAvailableAmount) return false;
if (interfaceType == BULK_INTERFACE_BUY) {
if (amount * pricePerUnit > world.model.player.inventory.gold) return false;
if (amount * pricePerUnit > world.model.player.getGold()) return false;
}
return true;

View File

@@ -215,7 +215,7 @@ public final class ConversationActivity extends Activity implements OnKeyListene
return;
} else if (phraseID.equalsIgnoreCase(ConversationCollection.PHRASE_SHOP)) {
assert(npc != null);
assert(npc.dropList != null);
assert(npc.getDropList() != null);
Intent intent = new Intent(this, ShopActivity.class);
intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/shop"));
Dialogs.addMonsterIdentifiers(intent, npc);
@@ -350,7 +350,7 @@ public final class ConversationActivity extends Activity implements OnKeyListene
}
s.text = text;
s.color = color;
s.isPlayerActor = actor != null ? actor.isPlayer : false;
s.isPlayerActor = actor != null ? actor == player : false;
conversationHistory.add(s);
statementList.clearFocus();
listAdapter.notifyDataSetChanged();

View File

@@ -34,9 +34,9 @@ public final class DebugInterface {
new DebugButton("dmg", new OnClickListener() {
@Override
public void onClick(View arg0) {
world.model.player.combatTraits.damagePotential.set(99, 99);
world.model.player.combatTraits.attackChance = 200;
world.model.player.combatTraits.attackCost = 1;
world.model.player.damagePotential.set(99, 99);
world.model.player.attackChance = 200;
world.model.player.attackCost = 1;
mainActivity.updateStatus();
mainActivity.showToast("DEBUG: damagePotential=99, chance=200%, cost=1", Toast.LENGTH_SHORT);
}
@@ -129,7 +129,7 @@ public final class DebugInterface {
public void onClick(View arg0) {
world.model.player.baseTraits.maxHP = 200;
world.model.player.health.max = world.model.player.baseTraits.maxHP;
world.model.player.health.setMax();
world.model.player.setMaxHP();
world.model.player.conditions.clear();
mainActivity.updateStatus();
mainActivity.showToast("DEBUG: hp set to max", Toast.LENGTH_SHORT);

View File

@@ -6,7 +6,6 @@ import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.ViewContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.ItemController;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.model.item.Inventory;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
@@ -164,14 +163,19 @@ public final class HeroinfoActivity_Inventory extends Activity {
private void updateTraits() {
heroinfo_stats_gold.setText(getResources().getString(R.string.heroinfo_gold, player.inventory.gold));
CombatTraits c = player.combatTraits;
StringBuilder sb = new StringBuilder();
ItemController.describeAttackEffect(c.attackChance, c.damagePotential.current, c.damagePotential.max, c.criticalSkill, c.criticalMultiplier, sb);
ItemController.describeAttackEffect(
player.getAttackChance(),
player.getDamagePotential().current,
player.getDamagePotential().max,
player.getCriticalSkill(),
player.getCriticalMultiplier(),
sb);
heroinfo_stats_attack.setText(sb.toString());
sb = new StringBuilder();
ItemController.describeBlockEffect(c.blockChance, c.damageResistance, sb);
ItemController.describeBlockEffect(player.getBlockChance(), player.getDamageResistance(), sb);
heroinfo_stats_defense.setText(sb.toString());
}
@@ -281,12 +285,10 @@ public final class HeroinfoActivity_Inventory extends Activity {
boolean enabled = true;
if (world.model.uiSelections.isInCombat) {
int ap = world.model.player.reequipCost;
int ap = world.model.player.getReequipCost();
text = getResources().getString(R.string.iteminfo_action_unequip_ap, ap);
if (ap > 0) {
if (world.model.player.ap.current < ap) {
enabled = false;
}
enabled = world.model.player.hasAPs(ap);
}
} else {
text = getResources().getString(R.string.iteminfo_action_unequip);
@@ -304,7 +306,7 @@ public final class HeroinfoActivity_Inventory extends Activity {
final boolean isInCombat = world.model.uiSelections.isInCombat;
if (itemType.isEquippable()) {
if (isInCombat) {
ap = world.model.player.reequipCost;
ap = world.model.player.getReequipCost();
text = getResources().getString(R.string.iteminfo_action_equip_ap, ap);
} else {
text = getResources().getString(R.string.iteminfo_action_equip);
@@ -312,7 +314,7 @@ public final class HeroinfoActivity_Inventory extends Activity {
action = ItemInfoActivity.ITEMACTION_EQUIP;
} else if (itemType.isUsable()) {
if (isInCombat) {
ap = world.model.player.useItemCost;
ap = world.model.player.getUseItemCost();
text = getResources().getString(R.string.iteminfo_action_use_ap, ap);
} else {
text = getResources().getString(R.string.iteminfo_action_use);
@@ -320,9 +322,7 @@ public final class HeroinfoActivity_Inventory extends Activity {
action = ItemInfoActivity.ITEMACTION_USE;
}
if (isInCombat && ap > 0) {
if (world.model.player.ap.current < ap) {
enabled = false;
}
enabled = world.model.player.hasAPs(ap);
}
Dialogs.showItemInfo(HeroinfoActivity_Inventory.this, itemType.id, action, text, enabled, -1);

View File

@@ -67,7 +67,7 @@ public final class HeroinfoActivity_Skills extends Activity {
private void updateSkillList() {
TextView listskills_number_of_increases = (TextView) findViewById(R.id.heroinfo_listskills_number_of_increases);
int numberOfSkillIncreases = player.availableSkillIncreases;
int numberOfSkillIncreases = player.getAvailableSkillIncreases();
if (numberOfSkillIncreases > 0) {
if (numberOfSkillIncreases == 1) {
listskills_number_of_increases.setText(R.string.skill_number_of_increases_one);

View File

@@ -107,10 +107,10 @@ public final class HeroinfoActivity_Stats extends Activity {
}
private void updateTraits() {
heroinfo_level.setText(Integer.toString(player.level));
heroinfo_totalexperience.setText(Integer.toString(player.totalExperience));
heroinfo_level.setText(Integer.toString(player.getLevel()));
heroinfo_totalexperience.setText(Integer.toString(player.getTotalExperience()));
heroinfo_ap.setText(player.ap.toString());
heroinfo_movecost.setText(Integer.toString(player.baseTraits.moveCost));
heroinfo_movecost.setText(Integer.toString(player.getMoveCost()));
rangebar_hp.update(player.health);
rangebar_exp.update(player.levelExperience);

View File

@@ -91,7 +91,7 @@ public final class LevelUpActivity extends Activity {
}
world.tileManager.setImageViewTile(levelup_title, player);
levelup_description.setText(res.getString(R.string.levelup_description, player.level+1));
levelup_description.setText(res.getString(R.string.levelup_description, player.getLevel() + 1));
if (player.nextLevelAddsNewSkillpoint()) {
levelup_adds_new_skillpoint.setVisibility(View.VISIBLE);
} else {

View File

@@ -132,7 +132,7 @@ public final class MainActivity extends Activity {
final Coord p = world.model.player.nextPosition;
Monster m = world.model.currentMap.getMonsterAt(p);
if (m == null) return; //Shouldn't happen.
m.forceAggressive = true;
m.forceAggressive();
view.combatController.setCombatSelection(m, p);
view.combatController.enterCombat(CombatController.BEGIN_TURN_PLAYER);
} else if (resultCode == ConversationActivity.ACTIVITYRESULT_REMOVE) {
@@ -163,7 +163,7 @@ public final class MainActivity extends Activity {
private boolean save(int slot) {
final Player player = world.model.player;
return Savegames.saveWorld(world, this, slot, getString(R.string.savegame_currenthero_displayinfo, player.level, player.totalExperience, player.inventory.gold));
return Savegames.saveWorld(world, this, slot, getString(R.string.savegame_currenthero_displayinfo, player.getLevel(), player.getTotalExperience(), player.getGold()));
}
@Override

View File

@@ -1,7 +1,5 @@
package com.gpl.rpg.AndorsTrail.activity;
import java.util.Arrays;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.Dialogs;
import com.gpl.rpg.AndorsTrail.R;
@@ -89,11 +87,11 @@ public final class MonsterInfoActivity extends Activity {
monsterinfo_onhiteffects.update(
null,
null,
monster.baseTraits.onHitEffects == null ? null : Arrays.asList(monster.baseTraits.onHitEffects),
monster.getOnHitEffectsAsList(),
null,
false);
hp.update(monster.health);
monsterinfo_immune_criticals.setVisibility(monster.isImmuneToCriticalHits ? View.VISIBLE : View.GONE);
monsterinfo_immune_criticals.setVisibility(monster.isImmuneToCriticalHits() ? View.VISIBLE : View.GONE);
}
public static int getMonsterDifficultyResource(WorldContext world, Monster monster) {

View File

@@ -190,7 +190,7 @@ public final class ShopActivity extends TabActivity implements OnContainerItemCl
}
private void updateGc() {
String gc = getResources().getString(R.string.shop_yourgold, player.inventory.gold);
String gc = getResources().getString(R.string.shop_yourgold, player.getGold());
shop_buy_gc.setText(gc);
shop_sell_gc.setText(gc);
}

View File

@@ -167,37 +167,43 @@ public class ActorStatsController {
public static void applyAbilityEffects(Actor actor, AbilityModifierTraits effects, int multiplier) {
if (effects == null) return;
CombatTraits actorCombatTraits = actor.combatTraits;
actor.health.addToMax(effects.increaseMaxHP * multiplier);
actor.ap.addToMax(effects.increaseMaxAP * multiplier);
actor.baseTraits.moveCost += effects.increaseMoveCost * multiplier;
actor.moveCost += effects.increaseMoveCost * multiplier;
actorCombatTraits.attackCost += effects.increaseAttackCost * multiplier;
actor.attackCost += effects.increaseAttackCost * multiplier;
//criticalMultiplier should not be increased. It is always defined by the weapon in use.
actorCombatTraits.attackChance += effects.increaseAttackChance * multiplier;
actorCombatTraits.criticalSkill += effects.increaseCriticalSkill * multiplier;
actorCombatTraits.damagePotential.add(effects.increaseMinDamage * multiplier, true);
actorCombatTraits.damagePotential.addToMax(effects.increaseMaxDamage * multiplier);
actorCombatTraits.blockChance += effects.increaseBlockChance * multiplier;
actorCombatTraits.damageResistance += effects.increaseDamageResistance * multiplier;
actor.attackChance += effects.increaseAttackChance * multiplier;
actor.criticalSkill += effects.increaseCriticalSkill * multiplier;
actor.damagePotential.add(effects.increaseMinDamage * multiplier, true);
actor.damagePotential.addToMax(effects.increaseMaxDamage * multiplier);
actor.blockChance += effects.increaseBlockChance * multiplier;
actor.damageResistance += effects.increaseDamageResistance * multiplier;
if (actorCombatTraits.attackCost <= 0) actorCombatTraits.attackCost = 1;
if (actorCombatTraits.attackChance < 0) actorCombatTraits.attackChance = 0;
if (actor.baseTraits.moveCost <= 0) actor.baseTraits.moveCost = 1;
if (actorCombatTraits.damagePotential.max < 0) actorCombatTraits.damagePotential.set(0, 0);
if (actor.attackCost <= 0) actor.attackCost = 1;
if (actor.attackChance < 0) actor.attackChance = 0;
if (actor.moveCost <= 0) actor.moveCost = 1;
if (actor.damagePotential.max < 0) actor.damagePotential.set(0, 0);
}
public static void recalculatePlayerCombatTraits(Player player) { recalculateActorCombatTraits(player); }
public static void recalculateMonsterCombatTraits(Monster monster) { recalculateActorCombatTraits(monster); }
public static void recalculatePlayerCombatTraits(Player player) {
player.resetStatsToBaseTraits();
ItemController.applyInventoryEffects(player);
SkillController.applySkillEffects(player);
applyEffectsFromCurrentConditions(player);
ItemController.recalculateHitEffectsFromWornItems(player);
player.health.capAtMax();
player.ap.capAtMax();
}
public static void recalculateMonsterCombatTraits(Monster monster) {
monster.resetStatsToBaseTraits();
applyEffectsFromCurrentConditions(monster);
monster.health.capAtMax();
monster.ap.capAtMax();
}
private static void recalculateActorCombatTraits(Actor actor) {
actor.resetStatsToBaseTraits();
if (actor.isPlayer) ItemController.applyInventoryEffects((Player) actor);
if (actor.isPlayer) SkillController.applySkillEffects((Player) actor);
applyEffectsFromCurrentConditions(actor);
if (actor.isPlayer) ItemController.recalculateHitEffectsFromWornItems((Player) actor);
actor.health.capAtMax();
actor.ap.capAtMax();
if (actor.isPlayer) recalculatePlayerCombatTraits((Player) actor);
else recalculateMonsterCombatTraits((Monster) actor);
}
public void applyConditionsToPlayer(Player player, boolean isFullRound) {
@@ -227,7 +233,7 @@ public class ActorStatsController {
player.conditions.remove(i);
player.conditionListener.onActorConditionRemoved(player, c);
}
recalculateActorCombatTraits(player);
recalculatePlayerCombatTraits(player);
}
}
}
@@ -398,7 +404,7 @@ public class ActorStatsController {
public void applySkillEffectsForNewRound(Player player, PredefinedMap currentMap) {
int level = player.getSkillLevel(SkillCollection.SKILL_REGENERATION);
if (level > 0) {
boolean hasAdjacentMonster = MovementController.hasAdjacentAggressiveMonster(currentMap, player.position);
boolean hasAdjacentMonster = MovementController.hasAdjacentAggressiveMonster(currentMap, player);
if (!hasAdjacentMonster) {
boolean changed = player.health.add(level * SkillCollection.PER_SKILLPOINT_INCREASE_REGENERATION, false);
if (changed) view.mainActivity.updateStatus();

View File

@@ -15,7 +15,6 @@ import com.gpl.rpg.AndorsTrail.context.ViewContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectCompletedCallback;
import com.gpl.rpg.AndorsTrail.model.AttackResult;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
import com.gpl.rpg.AndorsTrail.model.actor.Actor;
@@ -134,7 +133,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
public boolean canExitCombat() { return getAdjacentMonster() == null; }
private Monster getAdjacentMonster() {
return MovementController.getAdjacentAggressiveMonster(model.currentMap, model.player.position);
return MovementController.getAdjacentAggressiveMonster(model.currentMap, model.player);
}
public void executeMoveAttack(int dx, int dy) {
@@ -168,7 +167,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
private AttackResult lastAttackResult;
private void executePlayerAttack() {
if (context.effectController.isRunningVisualEffect()) return;
if (!useAPs(model.player.combatTraits.attackCost)) return;
if (!useAPs(model.player.getAttackCost())) return;
final Monster target = model.uiSelections.selectedMonster;
this.currentlyAttackedMonster = target;
@@ -228,7 +227,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
player.ap.add(player.getSkillLevel(SkillCollection.SKILL_CLEAVE) * SkillCollection.PER_SKILLPOINT_INCREASE_CLEAVE_AP, false);
player.health.add(player.getSkillLevel(SkillCollection.SKILL_EATER) * SkillCollection.PER_SKILLPOINT_INCREASE_EATER_HEALTH, false);
model.statistics.addMonsterKill(killedMonster.monsterTypeID);
model.statistics.addMonsterKill(killedMonster.getMonsterTypeID());
model.player.addExperience(loot.exp);
totalExpThisFight += loot.exp;
loot.exp = 0;
@@ -248,9 +247,9 @@ public final class CombatController implements VisualEffectCompletedCallback {
private boolean playerHasApLeft() {
final Player player = model.player;
if (player.hasAPs(player.useItemCost)) return true;
if (player.hasAPs(player.combatTraits.attackCost)) return true;
if (player.hasAPs(player.baseTraits.moveCost)) return true;
if (player.hasAPs(player.getUseItemCost())) return true;
if (player.hasAPs(player.getAttackCost())) return true;
if (player.hasAPs(player.getMoveCost())) return true;
return false;
}
private void playerActionCompleted() {
@@ -266,7 +265,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
private void executeCombatMove(final Coord dest) {
if (model.uiSelections.selectedMonster != null) return;
if (dest == null) return;
if (!useAPs(model.player.baseTraits.moveCost)) return;
if (!useAPs(model.player.getMoveCost())) return;
int fleeChanceBias = model.player.getSkillLevel(SkillCollection.SKILL_EVASION) * SkillCollection.PER_SKILLPOINT_INCREASE_EVASION_FLEE_CHANCE_PERCENTAGE;
if (Constants.roll100(Constants.FLEE_FAIL_CHANCE_PERCENT - fleeChanceBias)) {
@@ -309,15 +308,15 @@ public final class CombatController implements VisualEffectCompletedCallback {
private Monster determineNextMonster(Monster previousMonster) {
if (previousMonster != null) {
if (previousMonster.hasAPs(previousMonster.combatTraits.attackCost)) return previousMonster;
if (previousMonster.hasAPs(previousMonster.getAttackCost())) return previousMonster;
}
for (MonsterSpawnArea a : model.currentMap.spawnAreas) {
for (Monster m : a.monsters) {
if (!m.isAgressive()) continue;
if (m.rectPosition.isAdjacentTo(model.player.position)) {
if (m.hasAPs(m.combatTraits.attackCost)) return m;
if (m.isAdjacentTo(model.player)) {
if (m.hasAPs(m.getAttackCost())) return m;
}
}
}
@@ -332,7 +331,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
endMonsterTurn();
return;
}
currentActiveMonster.useAPs(currentActiveMonster.combatTraits.attackCost);
currentActiveMonster.useAPs(currentActiveMonster.getAttackCost());
context.mainActivity.combatview.updateTurnInfo(currentActiveMonster);
Resources r = context.mainActivity.getResources();
@@ -407,16 +406,16 @@ public final class CombatController implements VisualEffectCompletedCallback {
}
private static boolean hasCriticalAttack(Actor attacker, Actor target) {
if (!attacker.combatTraits.hasCriticalAttacks()) return false;
if (target.isImmuneToCriticalHits) return false;
if (!attacker.hasCriticalAttacks()) return false;
if (target.isImmuneToCriticalHits()) return false;
return true;
}
private static float getAverageDamagePerHit(Actor attacker, Actor target) {
float result = (float) (getAttackHitChance(attacker.combatTraits, target.combatTraits)) * attacker.combatTraits.damagePotential.average() / 100;
float result = (float) (getAttackHitChance(attacker, target)) * attacker.getDamagePotential().average() / 100;
if (hasCriticalAttack(attacker, target)) {
result += (float) attacker.combatTraits.getEffectiveCriticalChance() * result * attacker.combatTraits.criticalMultiplier / 100;
result += (float) attacker.getEffectiveCriticalChance() * result * attacker.getCriticalMultiplier() / 100;
}
result -= target.combatTraits.damageResistance;
result -= target.getDamageResistance();
return result;
}
private static float getAverageDamagePerTurn(Actor attacker, Actor target) {
@@ -424,14 +423,14 @@ public final class CombatController implements VisualEffectCompletedCallback {
}
private static int getTurnsToKillTarget(Actor attacker, Actor target) {
if (hasCriticalAttack(attacker, target)) {
if (attacker.combatTraits.damagePotential.max * attacker.combatTraits.criticalMultiplier <= target.combatTraits.damageResistance) return 999;
if (attacker.getDamagePotential().max * attacker.getCriticalMultiplier() <= target.getDamageResistance()) return 999;
} else {
if (attacker.combatTraits.damagePotential.max <= target.combatTraits.damageResistance) return 999;
if (attacker.getDamagePotential().max <= target.getDamageResistance()) return 999;
}
float averageDamagePerTurn = getAverageDamagePerTurn(attacker, target);
if (averageDamagePerTurn <= 0) return 100;
return (int) FloatMath.ceil(target.health.max / averageDamagePerTurn);
return (int) FloatMath.ceil(target.getMaxHP() / averageDamagePerTurn);
}
public static int getMonsterDifficulty(WorldContext world, Monster monster) {
// returns [0..100) . 100 == easy.
@@ -460,25 +459,25 @@ public final class CombatController implements VisualEffectCompletedCallback {
private static final int n = 50;
private static final int F = 40;
private static final float two_divided_by_PI = (float) (2f / Math.PI);
private static int getAttackHitChance(final CombatTraits attacker, final CombatTraits target) {
final int c = attacker.attackChance - target.blockChance;
private static int getAttackHitChance(final Actor attacker, final Actor target) {
final int c = attacker.getAttackChance() - target.getBlockChance();
// (2/pi)*atan(..) will vary from -1 to +1 .
return (int) (50 * (1 + two_divided_by_PI * (float)Math.atan((float)(c-n) / F)));
}
private AttackResult attack(final Actor attacker, final Actor target) {
int hitChance = getAttackHitChance(attacker.combatTraits, target.combatTraits);
int hitChance = getAttackHitChance(attacker, target);
if (!Constants.roll100(hitChance)) return AttackResult.MISS;
int damage = Constants.rollValue(attacker.combatTraits.damagePotential);
int damage = Constants.rollValue(attacker.getDamagePotential());
boolean isCriticalHit = false;
if (hasCriticalAttack(attacker, target)) {
isCriticalHit = Constants.roll100(attacker.combatTraits.getEffectiveCriticalChance());
isCriticalHit = Constants.roll100(attacker.getEffectiveCriticalChance());
if (isCriticalHit) {
damage *= attacker.combatTraits.criticalMultiplier;
damage *= attacker.getCriticalMultiplier();
}
}
damage -= target.combatTraits.damageResistance;
damage -= target.getDamageResistance();
if (damage < 0) damage = 0;
target.health.subtract(damage, false);
@@ -488,9 +487,10 @@ public final class CombatController implements VisualEffectCompletedCallback {
}
private void applyAttackHitStatusEffects(Actor attacker, Actor target) {
if (attacker.baseTraits.onHitEffects == null) return;
ItemTraits_OnUse[] onHitEffects = attacker.getOnHitEffects();
if (onHitEffects == null) return;
for (ItemTraits_OnUse e : attacker.baseTraits.onHitEffects) {
for (ItemTraits_OnUse e : onHitEffects) {
context.actorStatsController.applyUseEffect(attacker, target, e);
}
}

View File

@@ -54,7 +54,7 @@ public final class Controller {
Dialogs.showMonsterEncounter(view.mainActivity, view, m);
}
} else {
Dialogs.showConversation(view.mainActivity, view, m.phraseID, m);
Dialogs.showConversation(view.mainActivity, view, m.getPhraseID(), m);
}
}
@@ -82,8 +82,7 @@ public final class Controller {
player.setMaxAP();
player.setMaxHP();
if (area != null) {
player.spawnPlace = area.id;
player.spawnMap = world.model.currentMap.name;
player.setSpawnPlace(world.model.currentMap.name, area.id);
}
for (PredefinedMap m : world.maps.predefinedMaps) {
m.resetTemporaryData();

View File

@@ -39,7 +39,7 @@ public final class ItemController {
if (!type.isEquippable()) return;
final Player player = model.player;
if (model.uiSelections.isInCombat) {
if (!player.useAPs(player.reequipCost)) return;
if (!player.useAPs(player.getReequipCost())) return;
}
if (!player.inventory.removeItem(type.id, 1)) return;
@@ -62,7 +62,7 @@ public final class ItemController {
if (player.inventory.isEmptySlot(slot)) return;
if (model.uiSelections.isInCombat) {
if (!player.useAPs(player.reequipCost)) return;
if (!player.useAPs(player.getReequipCost())) return;
}
unequipSlot(player, slot);
@@ -81,7 +81,7 @@ public final class ItemController {
if (!type.isUsable()) return;
final Player player = model.player;
if (model.uiSelections.isInCombat) {
if (!player.useAPs(player.useItemCost)) return;
if (!player.useAPs(player.getUseItemCost())) return;
}
if (!player.inventory.removeItem(type.id, 1)) return;
@@ -101,8 +101,8 @@ public final class ItemController {
public static void applyInventoryEffects(Player player) {
ItemType weapon = getMainWeapon(player);
if (weapon != null) {
player.combatTraits.attackCost = 0;
player.combatTraits.criticalMultiplier = weapon.effects_equip.stats.setCriticalMultiplier;
player.attackCost = 0;
player.criticalMultiplier = weapon.effects_equip.stats.setCriticalMultiplier;
}
applyInventoryEffects(player, Inventory.WEARSLOT_WEAPON);
@@ -153,9 +153,9 @@ public final class ItemController {
if (effects != null) {
ItemTraits_OnUse[] effects_ = new ItemTraits_OnUse[effects.size()];
effects_ = effects.toArray(effects_);
player.baseTraits.onHitEffects = effects_;
player.onHitEffects = effects_;
} else {
player.baseTraits.onHitEffects = null;
player.onHitEffects = null;
}
}

View File

@@ -38,7 +38,7 @@ public final class MonsterMovementController {
for (MonsterSpawnArea a : model.currentMap.spawnAreas) {
for (Monster m : a.monsters) {
if (!m.isAgressive()) continue;
if (!m.rectPosition.isAdjacentTo(model.player.position)) continue;
if (!m.isAdjacentTo(model.player)) continue;
int aggressionChanceBias = model.player.getSkillLevel(SkillCollection.SKILL_EVASION) * SkillCollection.PER_SKILLPOINT_INCREASE_EVASION_MONSTER_ATTACK_CHANCE_PERCENTAGE;
if (Constants.roll100(Constants.MONSTER_AGGRESSION_CHANCE_PERCENT - aggressionChanceBias)) {
@@ -50,7 +50,7 @@ public final class MonsterMovementController {
}
private boolean moveMonster(final Monster m, final MonsterSpawnArea area, long currentTime) {
m.nextActionTime += m.millisecondsPerMove;
m.nextActionTime += getMillisecondsPerMove(m);
if (m.movementDestination == null) {
// Monster has waited and should start to move again.
m.movementDestination = new Coord(m.position);
@@ -89,7 +89,11 @@ public final class MonsterMovementController {
private void cancelCurrentMonsterMovement(final Monster m) {
m.movementDestination = null;
m.nextActionTime += m.millisecondsPerMove * Constants.rollValue(Constants.monsterWaitTurns);
m.nextActionTime += getMillisecondsPerMove(m) * Constants.rollValue(Constants.monsterWaitTurns);
}
private static int getMillisecondsPerMove(Monster m) {
return Constants.MONSTER_MOVEMENT_TURN_DURATION_MS * m.getMoveCost() / m.getMaxAP();
}
private static int sgn(int i) {

View File

@@ -233,7 +233,7 @@ public final class MovementController implements TimedMessageTask.Callback {
}
public static void respawnPlayer(final Resources res, final WorldContext world) {
placePlayerAt(res, world, MapObject.MAPEVENT_REST, world.model.player.spawnMap, world.model.player.spawnPlace, 0, 0);
placePlayerAt(res, world, MapObject.MAPEVENT_REST, world.model.player.getSpawnMap(), world.model.player.getSpawnPlace(), 0, 0);
}
public static void moveBlockedActors(final WorldContext world) {
@@ -304,20 +304,21 @@ public final class MovementController implements TimedMessageTask.Callback {
public static void refreshMonsterAggressiveness(final PredefinedMap map, final Player player) {
for(MonsterSpawnArea a : map.spawnAreas) {
for (Monster m : a.monsters) {
if (m.faction == null) continue;
if (player.getAlignment(m.faction) < 0) m.forceAggressive = true;
String faction = m.getFaction();
if (faction == null) continue;
if (player.getAlignment(faction) < 0) m.forceAggressive();
}
}
}
public static boolean hasAdjacentAggressiveMonster(PredefinedMap map, Coord position) {
return getAdjacentAggressiveMonster(map, position) != null;
public static boolean hasAdjacentAggressiveMonster(PredefinedMap map, Player player) {
return getAdjacentAggressiveMonster(map, player) != null;
}
public static Monster getAdjacentAggressiveMonster(PredefinedMap map, Coord position) {
public static Monster getAdjacentAggressiveMonster(PredefinedMap map, Player player) {
for (MonsterSpawnArea a : map.spawnAreas) {
for (Monster m : a.monsters) {
if (!m.isAgressive()) continue;
if (m.rectPosition.isAdjacentTo(position)) return m;
if (m.isAdjacentTo(player)) return m;
}
}
return null;

View File

@@ -17,17 +17,16 @@ import com.gpl.rpg.AndorsTrail.util.ConstRange;
public final class SkillController {
public static void applySkillEffects(Player player) {
CombatTraits combatTraits = player.combatTraits;
combatTraits.attackChance += SkillCollection.PER_SKILLPOINT_INCREASE_WEAPON_CHANCE * player.getSkillLevel(SkillCollection.SKILL_WEAPON_CHANCE);
combatTraits.damagePotential.addToMax(SkillCollection.PER_SKILLPOINT_INCREASE_WEAPON_DAMAGE_MAX * player.getSkillLevel(SkillCollection.SKILL_WEAPON_DMG));
combatTraits.damagePotential.add(SkillCollection.PER_SKILLPOINT_INCREASE_WEAPON_DAMAGE_MIN * player.getSkillLevel(SkillCollection.SKILL_WEAPON_DMG), false);
combatTraits.blockChance += SkillCollection.PER_SKILLPOINT_INCREASE_DODGE * player.getSkillLevel(SkillCollection.SKILL_DODGE);
combatTraits.damageResistance += SkillCollection.PER_SKILLPOINT_INCREASE_BARKSKIN * player.getSkillLevel(SkillCollection.SKILL_BARKSKIN);
if (combatTraits.hasCriticalSkillEffect()) {
combatTraits.criticalSkill += combatTraits.criticalSkill * SkillCollection.PER_SKILLPOINT_INCREASE_MORE_CRITICALS_PERCENT * player.getSkillLevel(SkillCollection.SKILL_MORE_CRITICALS) / 100;
player.attackChance += SkillCollection.PER_SKILLPOINT_INCREASE_WEAPON_CHANCE * player.getSkillLevel(SkillCollection.SKILL_WEAPON_CHANCE);
player.damagePotential.addToMax(SkillCollection.PER_SKILLPOINT_INCREASE_WEAPON_DAMAGE_MAX * player.getSkillLevel(SkillCollection.SKILL_WEAPON_DMG));
player.damagePotential.add(SkillCollection.PER_SKILLPOINT_INCREASE_WEAPON_DAMAGE_MIN * player.getSkillLevel(SkillCollection.SKILL_WEAPON_DMG), false);
player.blockChance += SkillCollection.PER_SKILLPOINT_INCREASE_DODGE * player.getSkillLevel(SkillCollection.SKILL_DODGE);
player.damageResistance += SkillCollection.PER_SKILLPOINT_INCREASE_BARKSKIN * player.getSkillLevel(SkillCollection.SKILL_BARKSKIN);
if (player.hasCriticalSkillEffect()) {
player.criticalSkill += player.criticalSkill * SkillCollection.PER_SKILLPOINT_INCREASE_MORE_CRITICALS_PERCENT * player.getSkillLevel(SkillCollection.SKILL_MORE_CRITICALS) / 100;
}
if (combatTraits.hasCriticalMultiplierEffect()) {
combatTraits.criticalMultiplier += combatTraits.criticalMultiplier * SkillCollection.PER_SKILLPOINT_INCREASE_BETTER_CRITICALS_PERCENT * player.getSkillLevel(SkillCollection.SKILL_BETTER_CRITICALS) / 100;
if (player.hasCriticalMultiplierEffect()) {
player.criticalMultiplier += player.criticalMultiplier * SkillCollection.PER_SKILLPOINT_INCREASE_BETTER_CRITICALS_PERCENT * player.getSkillLevel(SkillCollection.SKILL_BETTER_CRITICALS) / 100;
}
player.ap.addToMax(SkillCollection.PER_SKILLPOINT_INCREASE_SPEED * player.getSkillLevel(SkillCollection.SKILL_SPEED));
/*final int berserkLevel = player.getSkillLevel(Skills.SKILL_BERSERKER);
@@ -145,7 +144,7 @@ public final class SkillController {
Player player = world.model.player;
if (player.combatTraits.attackChance - monster.combatTraits.blockChance > SkillCollection.CONCUSSION_THRESHOLD) {
if (player.getAttackChance() - monster.getBlockChance() > SkillCollection.CONCUSSION_THRESHOLD) {
if (rollForSkillChance(player, SkillCollection.SKILL_CONCUSSION, SkillCollection.PER_SKILLPOINT_INCREASE_CONCUSSION_CHANCE)) {
addConditionToActor(monster, world, "concussion", 1, 5);
}

View File

@@ -141,7 +141,7 @@ public final class VisualEffectController {
}
public static void addSplatter(PredefinedMap map, Monster m) {
int iconID = getSplatterIconFromMonsterClass(m.monsterClass);
int iconID = getSplatterIconFromMonsterClass(m.getMonsterClass());
if (iconID > 0) map.splatters.add(new BloodSplatter(iconID, m.position));
}

View File

@@ -81,9 +81,9 @@ public class SkillInfo {
private int getRequirementActualValue(Player player) {
switch (requirementType) {
case REQUIREMENT_TYPE_SKILL_LEVEL: return player.getSkillLevel(skillOrStatID);
case REQUIREMENT_TYPE_EXPERIENCE_LEVEL: return player.level;
case REQUIREMENT_TYPE_COMBAT_STAT: return player.baseTraits.getCombatStats(skillOrStatID);
case REQUIREMENT_TYPE_ACTOR_STAT: return player.baseTraits.getActorStats(skillOrStatID);
case REQUIREMENT_TYPE_EXPERIENCE_LEVEL: return player.getLevel();
case REQUIREMENT_TYPE_COMBAT_STAT: return player.getCombatStats(skillOrStatID);
case REQUIREMENT_TYPE_ACTOR_STAT: return player.getActorStats(skillOrStatID);
default: return 0;
}
}

View File

@@ -4,10 +4,15 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.util.FloatMath;
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.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.model.listeners.ActorConditionListeners;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForPlayer.LegacySavegameData_Actor;
import com.gpl.rpg.AndorsTrail.util.Coord;
@@ -16,34 +21,68 @@ import com.gpl.rpg.AndorsTrail.util.Range;
import com.gpl.rpg.AndorsTrail.util.Size;
public class Actor {
public final ActorTraits baseTraits;
public final CombatTraits combatTraits;
public final int iconID;
public String name;
public final Size tileSize;
public final Range ap;
public final Range health;
public final Coord position;
public final Coord position = new Coord();
public final CoordRect rectPosition;
public final boolean isPlayer;
private final boolean isImmuneToCriticalHits;
protected String name;
// TODO: Should be privates
public final Range ap = new Range();
public final Range health = new Range();
public final ArrayList<ActorCondition> conditions = new ArrayList<ActorCondition>();
public final ActorConditionListeners conditionListener = new ActorConditionListeners();
public final boolean isPlayer;
public final boolean isImmuneToCriticalHits;
public int moveCost;
public int attackCost;
public int attackChance;
public int criticalSkill;
public float criticalMultiplier;
public final Range damagePotential = new Range();
public int blockChance;
public int damageResistance;
public ItemTraits_OnUse[] onHitEffects;
public Actor(ActorTraits baseTraits, Size tileSize, boolean isPlayer, boolean isImmuneToCriticalHits) {
this.combatTraits = new CombatTraits(baseTraits);
this.baseTraits = baseTraits;
this.iconID = baseTraits.iconID;
public Actor(int iconID, Size tileSize, boolean isPlayer, boolean isImmuneToCriticalHits) {
this.iconID = iconID;
this.tileSize = tileSize;
this.ap = new Range(baseTraits.maxAP, baseTraits.maxAP);
this.health = new Range(baseTraits.maxHP, baseTraits.maxHP);
this.position = new Coord();
this.rectPosition = new CoordRect(position, tileSize);
this.rectPosition = new CoordRect(this.position, this.tileSize);
this.isPlayer = isPlayer;
this.isImmuneToCriticalHits = isImmuneToCriticalHits;
}
public int getAttacksPerTurn() { return combatTraits.getAttacksPerTurn(baseTraits.maxAP); }
public boolean isImmuneToCriticalHits() { return isImmuneToCriticalHits; }
public String getName() { return name; }
public int getMaxAP() { return ap.max; }
public int getMaxHP() { return health.max; }
public int getMoveCost() { return moveCost; }
public int getAttackCost() { return attackCost; }
public int getAttackChance() { return attackChance; }
public int getCriticalSkill() { return criticalSkill; }
public float getCriticalMultiplier() { return criticalMultiplier; }
public Range getDamagePotential() { return damagePotential; }
public int getBlockChance() { return blockChance; }
public int getDamageResistance() { return damageResistance; }
public ItemTraits_OnUse[] getOnHitEffects() { return onHitEffects; }
public List<ItemTraits_OnUse> getOnHitEffectsAsList() { return onHitEffects == null ? null : Arrays.asList(onHitEffects); }
public boolean hasAttackChanceEffect_() { return getAttackChance() != 0; }
public boolean hasAttackDamageEffect_() { return getDamagePotential().max != 0; }
public boolean hasBlockEffect_() { return getBlockChance() != 0; }
public boolean hasCriticalSkillEffect() { return getCriticalSkill() != 0; }
public boolean hasCriticalMultiplierEffect() { float m = getCriticalMultiplier(); return m != 0 && m != 1; }
public boolean hasCriticalAttacks() { return hasCriticalSkillEffect() && hasCriticalMultiplierEffect(); }
public int getAttacksPerTurn() { return (int) Math.floor(getMaxAP() / getAttackCost()); }
public int getEffectiveCriticalChance() { return getEffectiveCriticalChance(getCriticalSkill()); }
public static int getEffectiveCriticalChance(int criticalSkill) {
if (criticalSkill <= 0) return 0;
int v = (int) (-5 + 2 * FloatMath.sqrt(5*criticalSkill));
if (v < 0) return 0;
return v;
}
public boolean isDead() {
return health.current <= 0;
@@ -54,7 +93,6 @@ public class Actor {
public void setMaxHP() {
health.setMax();
}
public String getName() { return name; }
public boolean useAPs(int cost) {
if (ap.current < cost) return false;
@@ -71,18 +109,11 @@ public class Actor {
}
return false;
}
public void resetStatsToBaseTraits() {
combatTraits.set(baseTraits);
health.set(baseTraits.maxHP, health.current);
ap.set(baseTraits.maxAP, ap.current);
baseTraits.moveCost = baseTraits.baseMoveCost;
}
// ====== PARCELABLE ===================================================================
/*
public Actor(DataInputStream src, WorldContext world, int fileversion, boolean isPlayer, boolean isImmuneToCriticalHits, Size tileSize, ActorTraits baseTraits) throws IOException {
this.isPlayer = isPlayer;
this.isImmuneToCriticalHits = isImmuneToCriticalHits;
@@ -140,5 +171,5 @@ public class Actor {
for (ActorCondition c : conditions) {
c.writeToParcel(dest, flags);
}
}
}*/
}

View File

@@ -5,65 +5,86 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
import com.gpl.rpg.AndorsTrail.model.item.DropList;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
import com.gpl.rpg.AndorsTrail.model.item.Loot;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForMonster;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForMonster.LegacySavegameData_Monster;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Range;
public final class Monster extends Actor {
public final String monsterTypeID;
public final int millisecondsPerMove;
public Coord movementDestination = null;
public long nextActionTime = 0;
public boolean forceAggressive = false;
public final CoordRect nextPosition;
public final String phraseID;
public final int exp;
public final DropList dropList;
public final String faction;
private boolean forceAggressive = false;
private ItemContainer shopItems = null;
public final int monsterClass;
public Monster(MonsterType monsterType, Coord position) {
super(monsterType.baseTraits, monsterType.tileSize, false, monsterType.isImmuneToCriticalHits());
this.monsterTypeID = monsterType.id;
this.position.set(position);
this.millisecondsPerMove = Constants.MONSTER_MOVEMENT_TURN_DURATION_MS / monsterType.baseTraits.getMovesPerTurn();
private final MonsterType monsterType;
public Monster(MonsterType monsterType) {
super(monsterType.iconID, monsterType.tileSize, false, monsterType.isImmuneToCriticalHits());
this.monsterType = monsterType;
this.nextPosition = new CoordRect(new Coord(), monsterType.tileSize);
this.phraseID = monsterType.phraseID;
this.exp = monsterType.exp;
this.dropList = monsterType.dropList;
this.faction = monsterType.faction;
this.monsterClass = monsterType.monsterClass;
resetStatsToBaseTraits();
}
public void resetStatsToBaseTraits() {
this.name = monsterType.name;
this.ap.set(monsterType.maxAP, monsterType.maxAP);
this.health.set(monsterType.maxHP, monsterType.maxHP);
this.position.set(position);
this.moveCost = monsterType.moveCost;
this.attackCost = monsterType.attackCost;
this.attackChance = monsterType.attackChance;
this.criticalSkill = monsterType.criticalSkill;
this.criticalMultiplier = monsterType.criticalMultiplier;
if (monsterType.damagePotential != null) this.damagePotential.set(monsterType.damagePotential);
else this.damagePotential.set(0, 0);
this.blockChance = monsterType.blockChance;
this.damageResistance = monsterType.damageResistance;
this.onHitEffects = monsterType.onHitEffects;
}
public DropList getDropList() { return monsterType.dropList; }
public int getExp() { return monsterType.exp; }
public String getPhraseID() { return monsterType.phraseID; }
public String getMonsterTypeID() { return monsterType.id; }
public String getFaction() { return monsterType.faction; }
public int getMonsterClass() { return monsterType.monsterClass; }
public void createLoot(Loot container, Player player) {
int exp = this.exp;
int exp = this.getExp();
exp += exp * player.getSkillLevel(SkillCollection.SKILL_MORE_EXP) * SkillCollection.PER_SKILLPOINT_INCREASE_MORE_EXP_PERCENT / 100;
container.exp += exp;
if (this.dropList == null) return;
this.dropList.createRandomLoot(container, player);
DropList dropList = getDropList();
if (dropList == null) return;
dropList.createRandomLoot(container, player);
}
public ItemContainer getShopItems(Player player) {
if (shopItems != null) return shopItems;
Loot loot = new Loot();
shopItems = loot.items;
this.dropList.createRandomLoot(loot, player);
getDropList().createRandomLoot(loot, player);
return shopItems;
}
public void resetShopItems() {
this.shopItems = null;
}
public boolean isAdjacentTo(Player p) {
return this.rectPosition.isAdjacentTo(p.position);
}
public boolean isAgressive() {
return phraseID == null || forceAggressive;
return getPhraseID() == null || forceAggressive;
}
public void forceAggressive() {
forceAggressive = true;
}
@@ -77,44 +98,104 @@ public final class Monster extends Actor {
MonsterType monsterType = world.monsterTypes.getMonsterType(monsterTypeId);
if (fileversion < 25) return LegacySavegameFormatReaderForMonster.readFromParcel_pre_v25(src, fileversion, monsterType);
if (fileversion < 33) return LegacySavegameFormatReaderForMonster.readFromParcel_pre_v33(src, world, fileversion, monsterType);
//if (fileversion < 33) return LegacySavegameFormatReaderForMonster.readFromParcel_pre_v33(src, world, fileversion, monsterType);
return new Monster(src, world, fileversion, monsterType);
}
public Monster(DataInputStream src, WorldContext world, int fileversion, MonsterType monsterType) throws IOException {
super(src, world, fileversion, false, monsterType.isImmuneToCriticalHits(), monsterType.tileSize, monsterType.baseTraits);
this.monsterTypeID = monsterType.id;
this.millisecondsPerMove = Constants.MONSTER_MOVEMENT_TURN_DURATION_MS / monsterType.baseTraits.getMovesPerTurn();
this.nextPosition = new CoordRect(new Coord(), monsterType.tileSize);
this.phraseID = monsterType.phraseID;
this.exp = monsterType.exp;
this.dropList = monsterType.dropList;
this(monsterType);
boolean readCombatTraits = true;
if (fileversion >= 25) readCombatTraits = src.readBoolean();
if (readCombatTraits) {
this.attackCost = src.readInt();
this.attackChance = src.readInt();
this.criticalSkill = src.readInt();
this.criticalMultiplier = src.readFloat();
this.damagePotential.set(new Range(src, fileversion));
this.blockChance = src.readInt();
this.damageResistance = src.readInt();
}
/*this.name = src.readUTF();*/
this.ap.readFromParcel(src, fileversion);
this.health.readFromParcel(src, fileversion);
this.position.readFromParcel(src, fileversion);
if (fileversion > 16) {
final int numConditions = src.readInt();
for(int i = 0; i < numConditions; ++i) {
conditions.add(new ActorCondition(src, world, fileversion));
}
}
if (fileversion >= 34) {
this.moveCost = src.readInt();
}
this.forceAggressive = src.readBoolean();
this.faction = monsterType.faction;
this.monsterClass = monsterType.monsterClass;
if (src.readBoolean()) {
this.shopItems = new ItemContainer(src, world, fileversion);
if (fileversion >= 31) {
if (src.readBoolean()) {
this.shopItems = new ItemContainer(src, world, fileversion);
}
}
}
/*
public Monster(LegacySavegameData_Monster savegameData, MonsterType monsterType) {
super(savegameData, false);
this(monsterType, savegameData.position);
this.isPlayer = isPlayer;
this.isImmuneToCriticalHits = savegameData.isImmuneToCriticalHits;
this.baseTraits = new ActorTraits(savegameData);
this.name = savegameData.name;
this.iconID = savegameData.iconID;
this.tileSize = savegameData.tileSize;
this.combatTraits = new CombatTraits(savegameData);
this.ap = savegameData.ap;
this.health = savegameData.health;
this.position = savegameData.position;
this.rectPosition = savegameData.rectPosition;
this.conditions.addAll(savegameData.conditions);
this.monsterTypeID = monsterType.id;
this.millisecondsPerMove = Constants.MONSTER_MOVEMENT_TURN_DURATION_MS / monsterType.baseTraits.getMovesPerTurn();
this.nextPosition = new CoordRect(new Coord(), monsterType.tileSize);
this.phraseID = monsterType.phraseID;
this.exp = monsterType.exp;
this.dropList = monsterType.dropList;
this.forceAggressive = savegameData.forceAggressive;
this.faction = monsterType.faction;
this.monsterClass = monsterType.monsterClass;
this.shopItems = savegameData.shopItems;
}
*/
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
dest.writeUTF(monsterTypeID);
super.writeToParcel(dest, flags);
dest.writeUTF(getMonsterTypeID());
if (attackCost == monsterType.attackCost
&& attackChance == monsterType.attackChance
&& criticalSkill == monsterType.criticalSkill
&& criticalMultiplier == monsterType.criticalMultiplier
&& damagePotential.equals(monsterType.damagePotential)
&& blockChance == monsterType.blockChance
&& damageResistance == monsterType.damageResistance
) {
dest.writeBoolean(false);
} else {
dest.writeBoolean(true);
dest.writeInt(attackCost);
dest.writeInt(attackChance);
dest.writeInt(criticalSkill);
dest.writeFloat(criticalMultiplier);
damagePotential.writeToParcel(dest, flags);
dest.writeInt(blockChance);
dest.writeInt(damageResistance);
}
ap.writeToParcel(dest, flags);
health.writeToParcel(dest, flags);
position.writeToParcel(dest, flags);
dest.writeInt(conditions.size());
for (ActorCondition c : conditions) {
c.writeToParcel(dest, flags);
}
dest.writeInt(moveCost);
dest.writeBoolean(forceAggressive);
if (shopItems != null) {
dest.writeBoolean(true);

View File

@@ -1,6 +1,8 @@
package com.gpl.rpg.AndorsTrail.model.actor;
import com.gpl.rpg.AndorsTrail.model.item.DropList;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.util.ConstRange;
import com.gpl.rpg.AndorsTrail.util.Size;
public final class MonsterType {
@@ -23,9 +25,20 @@ public final class MonsterType {
public final boolean isUnique; // Unique monsters are not respawned.
public final String faction;
public final int monsterClass;
public final ActorTraits baseTraits;
public final Size tileSize;
public final int iconID;
public final int maxAP;
public final int maxHP;
public final int moveCost;
public final int attackCost;
public final int attackChance;
public final int criticalSkill;
public final float criticalMultiplier;
public final ConstRange damagePotential;
public final int blockChance;
public final int damageResistance;
public final ItemTraits_OnUse[] onHitEffects;
public MonsterType(
String id,
String name,
@@ -37,7 +50,18 @@ public final class MonsterType {
String faction,
int monsterClass,
Size tileSize,
ActorTraits baseTraits) {
int iconID,
int maxAP,
int maxHP,
int moveCost,
int attackCost,
int attackChance,
int criticalSkill,
float criticalMultiplier,
ConstRange damagePotential,
int blockChance,
int damageResistance,
ItemTraits_OnUse[] onHitEffects) {
this.id = id;
this.name = name;
this.spawnGroup = spawnGroup;
@@ -48,7 +72,18 @@ public final class MonsterType {
this.isUnique = isUnique;
this.monsterClass = monsterClass;
this.tileSize = tileSize;
this.baseTraits = baseTraits;
this.iconID = iconID;
this.maxAP = maxAP;
this.maxHP = maxHP;
this.moveCost = moveCost;
this.attackCost = attackCost;
this.attackChance = attackChance;
this.criticalSkill = criticalSkill;
this.criticalMultiplier = criticalMultiplier;
this.damagePotential = damagePotential;
this.blockChance = blockChance;
this.damageResistance = damageResistance;
this.onHitEffects = onHitEffects;
}
public boolean isImmuneToCriticalHits() {
@@ -57,4 +92,16 @@ public final class MonsterType {
else if (monsterClass == MONSTERCLASS_DEMON) return true;
return false;
}
public boolean hasCombatStats() {
if (attackCost != 10) return true;
if (attackChance != 0) return true;
if (criticalSkill != 0) return true;
if (criticalMultiplier != 0) return true;
if (damagePotential.current != 0) return true;
if (damagePotential.max != 0) return true;
if (blockChance != 0) return true;
if (damageResistance != 0) return true;
return false;
}
}

View File

@@ -3,24 +3,29 @@ package com.gpl.rpg.AndorsTrail.model.actor;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import android.util.FloatMath;
import android.util.SparseIntArray;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.ActorStatsController;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
import com.gpl.rpg.AndorsTrail.model.item.Inventory;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection;
import com.gpl.rpg.AndorsTrail.model.item.Loot;
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForPlayer;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForPlayer.LegacySavegameData_Player;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.Range;
import com.gpl.rpg.AndorsTrail.util.Size;
@@ -31,32 +36,56 @@ public final class Player extends Actor {
public static final Size DEFAULT_PLAYER_SIZE = new Size(1, 1);
public final Coord lastPosition;
public final Coord nextPosition;
// TODO: Should be privates
public int level;
public int totalExperience;
public final PlayerBaseTraits baseTraits = new PlayerBaseTraits();
public final Range levelExperience; // ranges from 0 to the delta-amount of exp required for next level
public final Inventory inventory;
private final HashMap<String, HashSet<Integer> > questProgress = new HashMap<String, HashSet<Integer> >();
public int availableSkillIncreases = 0;
public int useItemCost;
public int reequipCost;
private int totalExperience;
private final HashMap<String, HashSet<Integer> > questProgress = new HashMap<String, HashSet<Integer> >();
private final SparseIntArray skillLevels = new SparseIntArray();
public String spawnMap;
public String spawnPlace;
public int availableSkillIncreases = 0;
private String spawnMap;
private String spawnPlace;
private final HashMap<String, Integer> alignments = new HashMap<String, Integer>();
public class PlayerBaseTraits {
public int maxAP;
public int maxHP;
public int moveCost;
public int attackCost;
public int attackChance;
public int criticalSkill;
public float criticalMultiplier;
public final Range damagePotential = new Range();
public int blockChance;
public int damageResistance;
public int useItemCost;
public int reequipCost;
}
public void resetStatsToBaseTraits() {
this.ap.max = this.baseTraits.maxAP;
this.health.max = this.baseTraits.maxHP;
this.moveCost = this.baseTraits.moveCost;
this.attackCost = this.baseTraits.attackCost;
this.attackChance = this.baseTraits.attackChance;
this.criticalSkill = this.baseTraits.criticalSkill;
this.criticalMultiplier = this.baseTraits.criticalMultiplier;
this.damagePotential.set(this.baseTraits.damagePotential);
this.blockChance = this.baseTraits.blockChance;
this.damageResistance = this.baseTraits.damageResistance;
this.useItemCost = this.baseTraits.useItemCost;
this.reequipCost = this.baseTraits.reequipCost;
}
public Player() {
super(
new ActorTraits(
TileManager.CHAR_HERO
, 0 // attackCost
, 0 // attackChance
, 0 // criticalSkill
, 0 // criticalMultiplier
, new Range() // damagePotential
, 0 // blockChance
, 0 // damageResistance
, DEFAULT_PLAYER_MOVECOST
, null)
TileManager.CHAR_HERO
, DEFAULT_PLAYER_SIZE
, true // isPlayer
, false // isImmuneToCriticalHits
@@ -68,6 +97,9 @@ public final class Player extends Actor {
}
public void initializeNewPlayer(ItemTypeCollection types, DropListCollection dropLists, String name) {
baseTraits.maxAP = 10;
baseTraits.maxHP = 25;
baseTraits.moveCost = DEFAULT_PLAYER_MOVECOST;
baseTraits.attackCost = DEFAULT_PLAYER_ATTACKCOST;
baseTraits.attackChance = 60;
baseTraits.criticalSkill = 0;
@@ -75,18 +107,16 @@ public final class Player extends Actor {
baseTraits.damagePotential.set(1, 1);
baseTraits.blockChance = 0;
baseTraits.damageResistance = 0;
baseTraits.maxAP = 10;
baseTraits.maxHP = 25;
baseTraits.useItemCost = 5;
baseTraits.reequipCost = 5;
this.name = name;
baseTraits.moveCost = DEFAULT_PLAYER_MOVECOST;
useItemCost = 5;
reequipCost = 5;
level = 1;
totalExperience = 1;
availableSkillIncreases = 0;
skillLevels.clear();
alignments.clear();
this.level = 1;
this.totalExperience = 1;
this.inventory.clear();
this.questProgress.clear();
this.skillLevels.clear();
this.availableSkillIncreases = 0;
this.alignments.clear();
recalculateLevelExperience();
Loot startItems = new Loot();
@@ -94,11 +124,11 @@ public final class Player extends Actor {
inventory.add(startItems);
if (AndorsTrailApplication.DEVELOPMENT_DEBUGRESOURCES) {
spawnMap = "debugmap";
spawnPlace = "start";
this.spawnMap = "debugmap";
this.spawnPlace = "start";
} else {
spawnMap = "home";
spawnPlace = "rest";
this.spawnMap = "home";
this.spawnPlace = "rest";
}
ActorStatsController.recalculatePlayerCombatTraits(this);
@@ -176,20 +206,62 @@ public final class Player extends Actor {
alignments.put(faction, newValue);
}
public void setSpawnPlace(String spawnMap, String spawnPlace) {
this.spawnPlace = spawnPlace;
this.spawnMap = spawnMap;
}
public void setName(String name) {
this.name = name;
}
public int getReequipCost() { return reequipCost; }
public int getUseItemCost() { return useItemCost; }
public int getAvailableSkillIncreases() { return availableSkillIncreases; }
public int getLevel() { return level; }
public int getTotalExperience() { return totalExperience; }
public int getGold() { return inventory.gold; }
public String getSpawnMap() { return spawnMap; }
public String getSpawnPlace() { return spawnPlace; }
public int getActorStats(int statID) {
switch (statID) {
case ActorTraits.STAT_ACTOR_MAX_HP: return baseTraits.maxHP;
case ActorTraits.STAT_ACTOR_MAX_AP: return baseTraits.maxAP;
case ActorTraits.STAT_ACTOR_MOVECOST: return baseTraits.moveCost;
}
return 0;
}
public int getCombatStats(int statID) {
switch (statID) {
case CombatTraits.STAT_COMBAT_ATTACK_COST: return baseTraits.attackCost;
case CombatTraits.STAT_COMBAT_ATTACK_CHANCE: return baseTraits.attackChance;
case CombatTraits.STAT_COMBAT_CRITICAL_SKILL: return baseTraits.criticalSkill;
case CombatTraits.STAT_COMBAT_CRITICAL_MULTIPLIER: return (int) FloatMath.floor(baseTraits.criticalMultiplier);
case CombatTraits.STAT_COMBAT_DAMAGE_POTENTIAL_MIN: return baseTraits.damagePotential.current;
case CombatTraits.STAT_COMBAT_DAMAGE_POTENTIAL_MAX: return baseTraits.damagePotential.max;
case CombatTraits.STAT_COMBAT_BLOCK_CHANCE: return baseTraits.blockChance;
case CombatTraits.STAT_COMBAT_DAMAGE_RESISTANCE: return baseTraits.damageResistance;
}
return 0;
}
// ====== PARCELABLE ===================================================================
public static Player readFromParcel(DataInputStream src, WorldContext world, int fileversion) throws IOException {
Player player;
/* Player player;
if (fileversion < 34) player = LegacySavegameFormatReaderForPlayer.readFromParcel_pre_v34(src, world, fileversion);
else player = new Player(src, world, fileversion);
*/
Player player = new Player(src, world, fileversion);
LegacySavegameFormatReaderForPlayer.upgradeSavegame(player, world, fileversion);
return player;
}
/*
public Player(DataInputStream src, WorldContext world, int fileversion) throws IOException {
super(src, world, fileversion, true, false, DEFAULT_PLAYER_SIZE, null);
this.lastPosition = new Coord(src, fileversion);
@@ -229,7 +301,103 @@ public final class Player extends Actor {
alignments.put(faction, alignment);
}
}
*/
public Player(DataInputStream src, WorldContext world, int fileversion) throws IOException {
this();
this.name = src.readUTF();
this.iconID = src.readInt();
if (fileversion <= 33) {
LegacySavegameFormatReaderForPlayer.readCombatTraitsPreV034(src, fileversion);
/*this.iconID = */src.readInt();
/*this.tileSize = */new Size(src, fileversion);
}
this.baseTraits.maxAP = src.readInt();
this.baseTraits.maxHP = src.readInt();
this.moveCost = src.readInt();
this.baseTraits.attackCost = src.readInt();
this.baseTraits.attackChance = src.readInt();
this.baseTraits.criticalSkill = src.readInt();
if (fileversion <= 20) {
this.baseTraits.criticalMultiplier = src.readInt();
} else {
this.baseTraits.criticalMultiplier = src.readFloat();
}
this.baseTraits.damagePotential.readFromParcel(src, fileversion);
this.baseTraits.blockChance = src.readInt();
this.baseTraits.damageResistance = src.readInt();
if (fileversion <= 16) {
this.baseTraits.moveCost = this.moveCost;
} else {
this.baseTraits.moveCost = src.readInt();
}
this.ap.set(new Range(src, fileversion));
this.health.set(new Range(src, fileversion));
this.position.set(new Coord(src, fileversion));
if (fileversion > 16) {
final int n = src.readInt();
for(int i = 0; i < n ; ++i) {
this.conditions.add(new ActorCondition(src, world, fileversion));
}
}
this.lastPosition.readFromParcel(src, fileversion);
this.nextPosition.readFromParcel(src, fileversion);
this.level = src.readInt();
this.totalExperience = src.readInt();
this.inventory.readFromParcel(src, world, fileversion);
if (fileversion <= 13) LegacySavegameFormatReaderForPlayer.readQuestProgressPreV13(this, src, world, fileversion);
this.useItemCost = src.readInt();
this.reequipCost = src.readInt();
final int size2 = src.readInt();
for(int i = 0; i < size2; ++i) {
if (fileversion <= 21) {
this.skillLevels.put(i, src.readInt());
} else {
final int skillID = src.readInt();
this.skillLevels.put(skillID, src.readInt());
}
}
this.spawnMap = src.readUTF();
this.spawnPlace = src.readUTF();
if (fileversion > 13) {
final int numquests = src.readInt();
for(int i = 0; i < numquests; ++i) {
final String questID = src.readUTF();
this.questProgress.put(questID, new HashSet<Integer>());
final int numprogress = src.readInt();
for(int j = 0; j < numprogress; ++j) {
int progress = src.readInt();
this.questProgress.get(questID).add(progress);
}
}
}
this.availableSkillIncreases = 0;
if (fileversion > 21) {
this.availableSkillIncreases = src.readInt();
}
if (fileversion >= 26) {
final int size3 = src.readInt();
for(int i = 0; i < size3; ++i) {
final String faction = src.readUTF();
final int alignment = src.readInt();
this.alignments.put(faction, alignment);
}
}
}
/*
public Player(LegacySavegameData_Player savegameData) {
super(savegameData, true);
this.lastPosition = savegameData.lastPosition;
@@ -250,9 +418,29 @@ public final class Player extends Actor {
this.availableSkillIncreases = savegameData.availableSkillIncreases;
this.alignments.putAll(savegameData.alignments);
}
*/
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
super.writeToParcel(dest, flags);
dest.writeUTF(name);
dest.writeInt(iconID);
dest.writeInt(baseTraits.maxAP);
dest.writeInt(baseTraits.maxHP);
dest.writeInt(moveCost);
dest.writeInt(baseTraits.attackCost);
dest.writeInt(baseTraits.attackChance);
dest.writeInt(baseTraits.criticalSkill);
dest.writeFloat(baseTraits.criticalMultiplier);
baseTraits.damagePotential.writeToParcel(dest, flags);
dest.writeInt(baseTraits.blockChance);
dest.writeInt(baseTraits.damageResistance);
dest.writeInt(baseTraits.moveCost);
ap.writeToParcel(dest, flags);
health.writeToParcel(dest, flags);
position.writeToParcel(dest, flags);
dest.writeInt(conditions.size());
for (ActorCondition c : conditions) {
c.writeToParcel(dest, flags);
}
lastPosition.writeToParcel(dest, flags);
nextPosition.writeToParcel(dest, flags);
dest.writeInt(level);

View File

@@ -27,6 +27,13 @@ public final class Inventory extends ItemContainer {
public Inventory() { }
public void clear() {
for(int i = 0; i < NUM_WORN_SLOTS; ++i) wear[i] = null;
for(int i = 0; i < NUM_QUICK_SLOTS; ++i) quickitem[i] = null;
gold = 0;
items.clear();
}
public void add(final Loot loot) {
this.gold += loot.gold;
this.add(loot.items);
@@ -56,26 +63,31 @@ public final class Inventory extends ItemContainer {
// ====== PARCELABLE ===================================================================
public Inventory(DataInputStream src, WorldContext world, int fileversion) throws IOException {
super(src, world, fileversion);
this.readFromParcel(src, world, fileversion);
}
public void readFromParcel(DataInputStream src, WorldContext world, int fileversion) throws IOException {
super.readFromParcel(src, world, fileversion);
gold = src.readInt();
if (fileversion < 23) LegacySavegameFormatReaderForItemContainer.refundUpgradedItems(this);
final int size = src.readInt();
for(int i = 0; i < size; ++i) {
for(int i = 0; i < NUM_WORN_SLOTS; ++i) {
wear[i] = null;
}
final int numWornSlots = src.readInt();
for(int i = 0; i < numWornSlots; ++i) {
if (src.readBoolean()) {
wear[i] = world.itemTypes.getItemType(src.readUTF());
} else {
wear[i] = null;
}
}
for(int i = 0; i < NUM_QUICK_SLOTS; ++i) {
quickitem[i] = null;
}
if (fileversion >= 19) {
final int quickSlots = src.readInt();
for(int i = 0; i < quickSlots; ++i) {
if (src.readBoolean()) {
quickitem[i] = world.itemTypes.getItemType(src.readUTF());
} else {
quickitem[i] = null;
}
}
}

View File

@@ -118,6 +118,11 @@ public class ItemContainer {
// ====== PARCELABLE ===================================================================
public ItemContainer(DataInputStream src, WorldContext world, int fileversion) throws IOException {
readFromParcel(src, world, fileversion);
}
public void readFromParcel(DataInputStream src, WorldContext world, int fileversion) throws IOException {
items.clear();
final int size = src.readInt();
for(int i = 0; i < size; ++i) {
ItemEntry entry = new ItemEntry(src, world, fileversion);

View File

@@ -62,7 +62,9 @@ public final class MonsterSpawnArea {
spawn(p, context.monsterTypes.getMonsterType(monsterTypeID));
}
public void spawn(Coord p, MonsterType type) {
monsters.add(new Monster(type, p));
Monster m = new Monster(type);
m.position.set(p);
monsters.add(m);
quantity.current++;
}

View File

@@ -3,14 +3,13 @@ package com.gpl.rpg.AndorsTrail.resource.parsers;
import android.util.FloatMath;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionTypeCollection;
import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
import com.gpl.rpg.AndorsTrail.resource.ResourceFileTokenizer.ResourceParserFor;
import com.gpl.rpg.AndorsTrail.util.ConstRange;
import com.gpl.rpg.AndorsTrail.util.Pair;
import com.gpl.rpg.AndorsTrail.util.Size;
@@ -30,29 +29,24 @@ public final class MonsterTypeParser extends ResourceParserFor<MonsterType> {
@Override
public Pair<String, MonsterType> parseRow(String[] parts) {
final String monsterTypeId = parts[0];
final CombatTraits combatTraits = ResourceParserUtils.parseCombatTraits(parts, 11);
final ItemTraits_OnUse hitEffect = itemTraitsParser.parseItemTraits_OnUse(parts, 21, true);
final ActorTraits baseTraits = new ActorTraits(
ResourceParserUtils.parseImageID(tileLoader, parts[1]) // IconID
, ResourceParserUtils.parseInt(parts[11], 10) // AttackCost
, ResourceParserUtils.parseInt(parts[12], 0) //AttackChance
, ResourceParserUtils.parseInt(parts[13], 0) //CriticalSkill
, ResourceParserUtils.parseFloat(parts[14], 0) //CriticalMultiplier
, ResourceParserUtils.parseRange(parts[15], parts[16]) //DamagePotential
, ResourceParserUtils.parseInt(parts[17], 0) //BlockChance
, ResourceParserUtils.parseInt(parts[18], 0) //DamageResistance
, ResourceParserUtils.parseInt(parts[10], 10) // MoveCost
, hitEffect == null ? null : new ItemTraits_OnUse[] { hitEffect }
);
baseTraits.maxHP = ResourceParserUtils.parseInt(parts[8], 1);
baseTraits.maxAP = ResourceParserUtils.parseInt(parts[9], 10);
int maxHP = ResourceParserUtils.parseInt(parts[8], 1);
int maxAP = ResourceParserUtils.parseInt(parts[9], 10);
int attackCost = ResourceParserUtils.parseInt(parts[11], 10);
int attackChance = ResourceParserUtils.parseInt(parts[12], 0);
ConstRange damagePotential = ResourceParserUtils.parseConstRange(parts[15], parts[16]);
int criticalSkill = ResourceParserUtils.parseInt(parts[13], 0);
float criticalMultiplier = ResourceParserUtils.parseFloat(parts[14], 0);
int blockChance = ResourceParserUtils.parseInt(parts[17], 0);
int damageResistance = ResourceParserUtils.parseInt(parts[18], 0);
final int exp = getExpectedMonsterExperience(combatTraits, hitEffect, baseTraits.maxHP, baseTraits.maxAP);
final int exp = getExpectedMonsterExperience(attackCost, attackChance, damagePotential, criticalSkill, criticalMultiplier, blockChance, damageResistance, hitEffect, maxHP, maxAP);
final String monsterTypeId = parts[0];
return new Pair<String, MonsterType>(monsterTypeId, new MonsterType(
monsterTypeId
, parts[2] // Name
, parts[3] // Tags
, parts[3] // SpawnGroup
, exp // Exp
, droplists.getDropList(parts[19]) // Droplist
, ResourceParserUtils.parseNullableString(parts[20]) // PhraseID
@@ -60,21 +54,45 @@ public final class MonsterTypeParser extends ResourceParserFor<MonsterType> {
, ResourceParserUtils.parseNullableString(parts[7]) // Faction
, ResourceParserUtils.parseInt(parts[5], MonsterType.MONSTERCLASS_HUMANOID) // MonsterClass
, ResourceParserUtils.parseSize(parts[4], size1x1) //TODO: This could be loaded from the tileset size instead.
, baseTraits
, ResourceParserUtils.parseImageID(tileLoader, parts[1]) // IconID
, maxAP
, maxHP
, ResourceParserUtils.parseInt(parts[10], 10) // MoveCost
, attackCost
, attackChance
, criticalSkill
, criticalMultiplier
, damagePotential
, blockChance
, damageResistance
, hitEffect == null ? null : new ItemTraits_OnUse[] { hitEffect }
));
}
private static float div100(int v) {
return (float) v / 100f;
}
private static int getExpectedMonsterExperience(final CombatTraits t, ItemTraits_OnUse hitEffect, final int maxHP, final int maxAP) {
if (t == null) return 0;
final float avgAttackHP = t.getAttacksPerTurn(maxAP) * div100(t.attackChance) * t.damagePotential.averagef() * (1 + div100(t.criticalSkill) * t.criticalMultiplier);
final float avgDefenseHP = maxHP * (1 + div100(t.blockChance)) + Constants.EXP_FACTOR_DAMAGERESISTANCE * t.damageResistance;
private static int getExpectedMonsterExperience(
int attackCost,
int attackChance,
ConstRange damagePotential,
int criticalSkill,
float criticalMultiplier,
int blockChance,
int damageResistance,
ItemTraits_OnUse hitEffect,
final int maxHP,
final int maxAP) {
final float averageDamage = damagePotential != null ? damagePotential.averagef() : 0;
final float avgAttackHP = getAttacksPerTurn(maxAP, attackCost) * div100(attackChance) * averageDamage * (1 + div100(criticalSkill) * criticalMultiplier);
final float avgDefenseHP = maxHP * (1 + div100(blockChance)) + Constants.EXP_FACTOR_DAMAGERESISTANCE * damageResistance;
int attackConditionBonus = 0;
if (hitEffect != null && hitEffect.addedConditions_target != null && hitEffect.addedConditions_target.length > 0) {
attackConditionBonus += 50;
}
return (int) FloatMath.ceil((avgAttackHP * 3 + avgDefenseHP) * Constants.EXP_FACTOR_SCALING) + attackConditionBonus;
}
private static int getAttacksPerTurn(int maxAP, int attackCost) {
return (int) Math.floor(maxAP / attackCost);
}
}

View File

@@ -106,7 +106,7 @@ public final class TileManager {
HashSet<Integer> iconIDs = new HashSet<Integer>();
for(MonsterSpawnArea a : map.spawnAreas) {
for(String monsterTypeID : a.monsterTypeIDs) {
iconIDs.add(world.monsterTypes.getMonsterType(monsterTypeID).baseTraits.iconID);
iconIDs.add(world.monsterTypes.getMonsterType(monsterTypeID).iconID);
}
}
iconIDs.addAll(tileMap.usedTileIDs);

View File

@@ -15,16 +15,17 @@ import com.gpl.rpg.AndorsTrail.util.Range;
public class LegacySavegameFormatReaderForMonster {
public static Monster readFromParcel_pre_v25(DataInputStream src, int fileversion, MonsterType monsterType) throws IOException {
Coord position = new Coord(src, fileversion);
Monster m = new Monster(monsterType, position);
Monster m = new Monster(monsterType);
m.position.set(new Coord(src, fileversion));
m.ap.current = src.readInt();
m.health.current = src.readInt();
if (fileversion >= 12) {
m.forceAggressive = src.readBoolean();
if (src.readBoolean()) m.forceAggressive();
}
return m;
}
/*
public static Monster readFromParcel_pre_v33(DataInputStream src, WorldContext world, int fileversion, MonsterType monsterType) throws IOException {
LegacySavegameData_Monster savegameData = readMonsterDataPreV33(src, world, fileversion, monsterType);
return new Monster(savegameData, monsterType);
@@ -50,21 +51,21 @@ public class LegacySavegameFormatReaderForMonster {
result.damageResistance = src.readInt();
}
result.iconID = monsterType.baseTraits.iconID;
result.iconID = monsterType.iconID;
result.tileSize = monsterType.tileSize;
result.maxAP = monsterType.baseTraits.maxAP;
result.maxHP = monsterType.baseTraits.maxHP;
result.maxAP = monsterType.maxAP;
result.maxHP = monsterType.maxHP;
result.name = monsterType.name;
result.moveCost = monsterType.baseTraits.moveCost;
result.moveCost = monsterType.moveCost;
result.baseAttackCost = monsterType.baseTraits.attackCost;
result.baseAttackChance = monsterType.baseTraits.attackChance;
result.baseCriticalSkill = monsterType.baseTraits.criticalSkill;
result.baseCriticalMultiplier = monsterType.baseTraits.criticalMultiplier;
result.baseDamagePotential = monsterType.baseTraits.damagePotential;
result.baseBlockChance = monsterType.baseTraits.blockChance;
result.baseDamageResistance = monsterType.baseTraits.damageResistance;
result.baseMoveCost = monsterType.baseTraits.baseMoveCost;
result.baseAttackCost = monsterType.attackCost;
result.baseAttackChance = monsterType.attackChance;
result.baseCriticalSkill = monsterType.criticalSkill;
result.baseCriticalMultiplier = monsterType.criticalMultiplier;
result.baseDamagePotential = new Range(monsterType.damagePotential);
result.baseBlockChance = monsterType.blockChance;
result.baseDamageResistance = monsterType.damageResistance;
result.baseMoveCost = monsterType.moveCost;
if (!readCombatTraits) {
result.attackCost = result.baseAttackCost;
@@ -101,5 +102,5 @@ public class LegacySavegameFormatReaderForMonster {
// from Monster
public boolean forceAggressive;
public ItemContainer shopItems;
}
}*/
}

View File

@@ -25,6 +25,7 @@ import com.gpl.rpg.AndorsTrail.util.Range;
import com.gpl.rpg.AndorsTrail.util.Size;
public final class LegacySavegameFormatReaderForPlayer {
/*
public static Player readFromParcel_pre_v34(DataInputStream src, WorldContext world, int fileversion) throws IOException {
LegacySavegameData_Player savegameData = readPlayerDataPreV34(src, world, fileversion);
return new Player(savegameData);
@@ -164,6 +165,7 @@ public final class LegacySavegameFormatReaderForPlayer {
public String spawnPlace;
public int availableSkillIncreases = 0;
}
*/
public static class LegacySavegameData_Actor {
// from Actor
@@ -200,7 +202,7 @@ public final class LegacySavegameFormatReaderForPlayer {
public int damageResistance;
}
private static void readQuestProgressPreV13(LegacySavegameData_Player player, DataInputStream src, WorldContext world, int fileversion) throws IOException {
public static void readQuestProgressPreV13(Player player, DataInputStream src, WorldContext world, int fileversion) throws IOException {
final int size1 = src.readInt();
for(int i = 0; i < size1; ++i) {
String keyName = src.readUTF();
@@ -245,10 +247,11 @@ public final class LegacySavegameFormatReaderForPlayer {
}
}
private static void addQuestProgress(LegacySavegameData_Player player, String questID, int progress) {
if (!player.questProgress.containsKey(questID)) player.questProgress.put(questID, new HashSet<Integer>());
private static void addQuestProgress(Player player, String questID, int progress) {
player.addQuestProgress(new QuestProgress(questID, progress));
/*if (!player.questProgress.containsKey(questID)) player.questProgress.put(questID, new HashSet<Integer>());
else if (player.questProgress.get(questID).contains(progress)) return;
player.questProgress.get(questID).add(progress);
player.questProgress.get(questID).add(progress);*/
}
public static void upgradeSavegame(Player player, WorldContext world, int fileversion) {
@@ -265,7 +268,7 @@ public final class LegacySavegameFormatReaderForPlayer {
for(SkillInfo skill : world.skills.getAllSkills()) {
assignedSkillpoints += player.getSkillLevel(skill.id);
}
player.availableSkillIncreases = getExpectedNumberOfSkillpointsForLevel(player.level) - assignedSkillpoints;
player.availableSkillIncreases = getExpectedNumberOfSkillpointsForLevel(player.getLevel()) - assignedSkillpoints;
}
if (fileversion <= 21) {
@@ -307,4 +310,21 @@ public final class LegacySavegameFormatReaderForPlayer {
ActorStatsController.removeConditionsFromUnequippedItem(player, world.itemTypes.getItemType(itemTypeIDWithCondition));
}
public static void readCombatTraitsPreV034(DataInputStream src, int fileversion) throws IOException {
if (fileversion < 25) return;
if (!src.readBoolean()) return;
/*attackCost = */src.readInt();
/*attackChance = */src.readInt();
/*criticalSkill = */src.readInt();
if (fileversion <= 20) {
/*criticalMultiplier = */src.readInt();
} else {
/*criticalMultiplier = */src.readFloat();
}
/*damagePotential = */new Range(src, fileversion);
/*blockChance = */src.readInt();
/*damageResistance = */src.readInt();
}
}

View File

@@ -36,6 +36,9 @@ public final class Coord {
// ====== PARCELABLE ===================================================================
public Coord(DataInputStream src, int fileversion) throws IOException {
this.readFromParcel(src, fileversion);
}
public void readFromParcel(DataInputStream src, int fileversion) throws IOException {
this.x = src.readInt();
this.y = src.readInt();
}

View File

@@ -79,6 +79,9 @@ public final class Range {
// ====== PARCELABLE ===================================================================
public Range(DataInputStream src, int fileversion) throws IOException {
this.readFromParcel(src, fileversion);
}
public void readFromParcel(DataInputStream src, int fileversion) throws IOException {
this.max = src.readInt();
this.current = src.readInt();
}

View File

@@ -1,7 +1,5 @@
package com.gpl.rpg.AndorsTrail.view;
import java.util.Collection;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.Dialogs;
import com.gpl.rpg.AndorsTrail.R;
@@ -31,7 +29,7 @@ public final class ActorConditionList extends LinearLayout {
this.world = app.world;
}
public void update(Collection<ActorCondition> conditions) {
public void update(Iterable<ActorCondition> conditions) {
removeAllViews();
if (conditions == null) return;

View File

@@ -1,7 +1,7 @@
package com.gpl.rpg.AndorsTrail.view;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
import com.gpl.rpg.AndorsTrail.model.actor.Player.PlayerBaseTraits;
import android.content.Context;
import android.util.AttributeSet;
@@ -18,9 +18,15 @@ public final class BaseTraitsInfoView extends TraitsInfoView {
basetraitsinfo_max_ap = (TextView) findViewById(R.id.basetraitsinfo_max_ap);
}
public void update(ActorTraits traits) {
super.update(traits);
public void update(PlayerBaseTraits traits) {
super.update(
traits.attackCost
,traits.attackChance
,traits.damagePotential
,traits.criticalSkill
,traits.criticalMultiplier
,traits.blockChance
,traits.damageResistance);
basetraitsinfo_max_hp.setText(Integer.toString(traits.maxHP));
basetraitsinfo_max_ap.setText(Integer.toString(traits.maxAP));
}

View File

@@ -135,15 +135,15 @@ public final class CombatView extends RelativeLayout {
monsterBar.setVisibility(View.INVISIBLE);
currentMonster = null;
if (selectedMonster != null) {
attackMoveButton.setText(res.getString(R.string.combat_attack, player.combatTraits.attackCost));
attackMoveButton.setText(res.getString(R.string.combat_attack, player.getAttackCost()));
monsterBar.setVisibility(View.VISIBLE);
world.tileManager.setImageViewTile(monsterInfo, selectedMonster);
updateMonsterHealth(selectedMonster.health);
currentMonster = selectedMonster;
} else if (selectedMovePosition != null) {
attackMoveButton.setText(res.getString(R.string.combat_move, player.baseTraits.moveCost));
attackMoveButton.setText(res.getString(R.string.combat_move, player.getMoveCost()));
} else {
attackMoveButton.setText(res.getString(R.string.combat_attack, player.combatTraits.attackCost));
attackMoveButton.setText(res.getString(R.string.combat_attack, player.getAttackCost()));
}
}

View File

@@ -1,9 +1,9 @@
package com.gpl.rpg.AndorsTrail.view;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.actor.Actor;
import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
import com.gpl.rpg.AndorsTrail.util.Range;
import android.content.Context;
import android.util.AttributeSet;
@@ -57,58 +57,77 @@ public class TraitsInfoView extends TableLayout {
traitsinfo_defense_damageresist = (TextView) findViewById(R.id.traitsinfo_defense_damageresist);
}
public void update(Actor actor) { update(actor.combatTraits); }
private void update(CombatTraits traits) {
if (traits != null && traits.attackCost != 0) {
public void update(Actor actor) {
update(
actor.getAttackCost()
,actor.getAttackChance()
,actor.getDamagePotential()
,actor.getCriticalSkill()
,actor.getCriticalMultiplier()
,actor.getBlockChance()
,actor.getDamageResistance());
}
public void update(
int attackCost
,int attackChance
,Range damagePotential
,int criticalSkill
,float criticalMultiplier
,int blockChance
,int damageResistance
) {
if (attackCost != 0) {
traitsinfo_attack_row1.setVisibility(View.VISIBLE);
traitsinfo_attack_cost.setText(Integer.toString(traits.attackCost));
traitsinfo_attack_cost.setText(Integer.toString(attackCost));
} else {
traitsinfo_attack_row1.setVisibility(View.GONE);
}
if (traits != null && traits.hasAttackChanceEffect()) {
if (attackChance != 0) {
traitsinfo_attack_row2.setVisibility(View.VISIBLE);
traitsinfo_attack_chance.setText(Integer.toString(traits.attackChance) + "%");
traitsinfo_attack_chance.setText(Integer.toString(attackChance) + "%");
} else {
traitsinfo_attack_row2.setVisibility(View.GONE);
}
if (traits != null && traits.hasAttackDamageEffect()) {
if (damagePotential.max != 0) {
traitsinfo_attack_row3.setVisibility(View.VISIBLE);
traitsinfo_attack_damage.setText(traits.damagePotential.toMinMaxString());
traitsinfo_attack_damage.setText(damagePotential.toMinMaxString());
} else {
traitsinfo_attack_row3.setVisibility(View.GONE);
}
if (traits != null && traits.hasCriticalSkillEffect()) {
if (criticalSkill != 0) {
traitsinfo_critical_row1.setVisibility(View.VISIBLE);
traitsinfo_criticalhit_skill.setText(Integer.toString(traits.criticalSkill));
traitsinfo_criticalhit_skill.setText(Integer.toString(criticalSkill));
} else {
traitsinfo_critical_row1.setVisibility(View.GONE);
}
if (traits != null && traits.hasCriticalMultiplierEffect()) {
if (criticalMultiplier != 0 && criticalMultiplier != 1) {
traitsinfo_critical_row2.setVisibility(View.VISIBLE);
traitsinfo_criticalhit_multiplier.setText(Float.toString(traits.criticalMultiplier));
traitsinfo_criticalhit_multiplier.setText(Float.toString(criticalMultiplier));
} else {
traitsinfo_critical_row2.setVisibility(View.GONE);
}
if (traits != null && traits.hasCriticalAttacks()) {
if (criticalSkill != 0 && criticalMultiplier != 0 && criticalMultiplier != 1) {
traitsinfo_critical_row3.setVisibility(View.VISIBLE);
traitsinfo_criticalhit_effectivechance.setText(Integer.toString(traits.getEffectiveCriticalChance()) + "%");
traitsinfo_criticalhit_effectivechance.setText(Integer.toString(Actor.getEffectiveCriticalChance(criticalSkill)) + "%");
} else {
traitsinfo_critical_row3.setVisibility(View.GONE);
}
if (traits != null && traits.hasBlockEffect()) {
if (blockChance != 0) {
traitsinfo_defense_row1.setVisibility(View.VISIBLE);
traitsinfo_defense_chance.setText(Integer.toString(traits.blockChance) + "%");
traitsinfo_defense_chance.setText(Integer.toString(blockChance) + "%");
} else {
traitsinfo_defense_row1.setVisibility(View.GONE);
}
if (traits != null && traits.damageResistance != 0) {
if (damageResistance != 0) {
traitsinfo_defense_row2.setVisibility(View.VISIBLE);
traitsinfo_defense_damageresist.setText(Integer.toString(traits.damageResistance));
traitsinfo_defense_damageresist.setText(Integer.toString(damageResistance));
} else {
traitsinfo_defense_row2.setVisibility(View.GONE);
}
}
/*
public void update(ActorTraits traits) {
if (traits != null && traits.attackCost != 0) {
traitsinfo_attack_row1.setVisibility(View.VISIBLE);
@@ -159,4 +178,5 @@ public class TraitsInfoView extends TableLayout {
traitsinfo_defense_row2.setVisibility(View.GONE);
}
}
*/
}