Merge branch 'actortraits_refactoring'

This commit is contained in:
Oskar Wiksten
2013-01-28 01:27:20 +01:00
60 changed files with 1245 additions and 1080 deletions

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TableRow>
<TextView android:text="@string/traitsinfo_base_max_hp" android:layout_marginRight="10sp" />
<TextView android:id="@+id/basetraitsinfo_max_hp" />
</TableRow>
<TableRow>
<TextView android:text="@string/traitsinfo_base_max_ap" android:layout_marginRight="10sp" />
<TextView android:id="@+id/basetraitsinfo_max_ap" />
</TableRow>
<include layout="@layout/traitsinfoview" />
</merge>

View File

@@ -15,7 +15,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
android:orientation="vertical"
android:id="@+id/heroinfo_container"
>
<TextView
android:id="@+id/heroinfo_title"
@@ -32,24 +34,14 @@
android:layout_marginBottom="@dimen/section_margin" >
<TableRow>
<TextView android:layout_marginRight="10sp" android:text="@string/heroinfo_level" />
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_level" />
<TextView android:id="@+id/heroinfo_level" android:text="1" />
</TableRow>
<TableRow>
<TextView android:layout_marginRight="10sp" android:text="@string/heroinfo_totalexperience" />
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_totalexperience" />
<TextView android:id="@+id/heroinfo_totalexperience" android:text="1" />
</TableRow>
<TableRow>
<TextView android:layout_marginRight="10sp" android:text="@string/heroinfo_actionpoints" />
<TextView android:id="@+id/heroinfo_ap" android:text="10/10" />
</TableRow>
<TableRow>
<TextView android:layout_marginRight="10sp" android:text="@string/actorinfo_movecost" />
<TextView android:id="@+id/heroinfo_movecost" android:text="6" />
</TableRow>
</TableLayout>
<com.gpl.rpg.AndorsTrail.view.RangeBar
@@ -69,38 +61,75 @@
android:layout_marginTop="@dimen/section_margin"
android:text="@string/actorinfo_currenttraits" />
<com.gpl.rpg.AndorsTrail.view.TraitsInfoView
android:id="@+id/heroinfo_currenttraits"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.gpl.rpg.AndorsTrail.view.ItemEffectsView
android:id="@+id/heroinfo_itemeffects"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/heroinfo_currentconditions_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/section_margin"
android:text="@string/actorinfo_currentconditions" />
<com.gpl.rpg.AndorsTrail.view.ActorConditionList
android:id="@+id/heroinfo_currentconditions"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/actorinfo_stats_table"
>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_actionpoints" />
<TextView android:id="@+id/heroinfo_ap" />
</TableRow>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_reequip_cost" />
<TextView android:id="@+id/heroinfo_reequip_cost" />
</TableRow>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_useitem_cost" />
<TextView android:id="@+id/heroinfo_useitem_cost" />
</TableRow>
<include layout="@layout/traitsinfoview" />
</TableLayout>
<com.gpl.rpg.AndorsTrail.view.ItemEffectsView
android:id="@+id/actorinfo_onhiteffects"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/actorinfo_currentconditions"
android:id="@+id/actorinfo_currentconditions_title"
android:layout_marginTop="@dimen/section_margin"
/>
<com.gpl.rpg.AndorsTrail.view.ActorConditionList
android:id="@+id/actorinfo_currentconditions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/section_margin"
android:text="@string/actorinfo_basetraits" />
android:text="@string/actorinfo_basetraits"
/>
<com.gpl.rpg.AndorsTrail.view.BaseTraitsInfoView
android:id="@+id/heroinfo_basetraits"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/heroinfo_basestats_table"
>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_base_max_hp" />
<TextView android:id="@+id/basetraitsinfo_max_hp" />
</TableRow>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_base_max_ap" />
<TextView android:id="@+id/basetraitsinfo_max_ap" />
</TableRow>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_reequip_cost" />
<TextView android:id="@+id/heroinfo_base_reequip_cost" />
</TableRow>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/heroinfo_useitem_cost" />
<TextView android:id="@+id/heroinfo_base_useitem_cost" />
</TableRow>
<include layout="@layout/traitsinfoview" />
</TableLayout>
</LinearLayout>
</ScrollView>

View File

@@ -16,6 +16,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/dialog_margin"
android:id="@+id/monsterinfo_container"
>
<TextView
@@ -54,19 +55,20 @@
android:layout_marginBottom="@dimen/section_margin"
/>
<com.gpl.rpg.AndorsTrail.view.TraitsInfoView
android:id="@+id/monsterinfo_currenttraits"
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/actorinfo_immune_criticals"
android:id="@+id/monsterinfo_immune_criticals"
/>
android:id="@+id/actorinfo_stats_table"
>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_base_max_ap" />
<TextView android:id="@+id/monsterinfo_max_ap" />
</TableRow>
<include layout="@layout/traitsinfoview" />
</TableLayout>
<com.gpl.rpg.AndorsTrail.view.ItemEffectsView
android:id="@+id/monsterinfo_onhiteffects"
android:id="@+id/actorinfo_onhiteffects"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
@@ -75,11 +77,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/actorinfo_currentconditions"
android:id="@+id/monsterinfo_currentconditions_title"
android:id="@+id/actorinfo_currentconditions_title"
android:layout_marginTop="@dimen/section_margin"
/>
<com.gpl.rpg.AndorsTrail.view.ActorConditionList
android:id="@+id/monsterinfo_currentconditions"
android:id="@+id/actorinfo_currentconditions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

View File

@@ -1,56 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TableRow
android:id="@+id/traitsinfo_attack_row1"
>
<TextView android:text="@string/traitsinfo_attack_cost" android:layout_marginRight="10sp" />
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/actorinfo_movecost" />
<TextView android:id="@+id/traitsinfo_move_cost" />
</TableRow>
<TableRow>
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_attack_cost" />
<TextView android:id="@+id/traitsinfo_attack_cost" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_attack_row2"
>
<TextView android:text="@string/traitsinfo_attack_chance" android:layout_marginRight="10sp" />
<TableRow android:id="@+id/traitsinfo_attack_chance_row">
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_attack_chance" />
<TextView android:id="@+id/traitsinfo_attack_chance" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_attack_row3"
>
<TextView android:text="@string/traitsinfo_attack_damage" android:layout_marginRight="10sp" />
<TableRow android:id="@+id/traitsinfo_attack_damage_row" >
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_attack_damage" />
<TextView android:id="@+id/traitsinfo_attack_damage" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_critical_row1"
>
<TextView android:text="@string/traitsinfo_criticalhit_skill" android:layout_marginRight="10sp" />
<TableRow android:id="@+id/traitsinfo_criticalhit_skill_row">
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_criticalhit_skill" />
<TextView android:id="@+id/traitsinfo_criticalhit_skill" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_critical_row2"
>
<TextView android:text="@string/traitsinfo_criticalhit_multiplier" android:layout_marginRight="10sp" />
<TableRow android:id="@+id/traitsinfo_criticalhit_multiplier_row">
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_criticalhit_multiplier" />
<TextView android:id="@+id/traitsinfo_criticalhit_multiplier" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_critical_row3"
>
<TextView android:text="@string/traitsinfo_criticalhit_effectivechance" android:layout_marginRight="10sp" />
<TableRow android:id="@+id/traitsinfo_criticalhit_effectivechance_row">
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_criticalhit_effectivechance" />
<TextView android:id="@+id/traitsinfo_criticalhit_effectivechance" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_defense_row1"
>
<TextView android:text="@string/traitsinfo_defense_chance" android:layout_marginRight="10sp" />
<TextView android:id="@+id/traitsinfo_defense_chance" />
<TableRow android:id="@+id/traitsinfo_block_chance_row">
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_defense_chance" />
<TextView android:id="@+id/traitsinfo_block_chance" />
</TableRow>
<TableRow
android:id="@+id/traitsinfo_defense_row2"
>
<TextView android:text="@string/traitsinfo_defense_damageresist" android:layout_marginRight="10sp" />
<TextView android:id="@+id/traitsinfo_defense_damageresist" />
<TableRow android:id="@+id/traitsinfo_damageresist_row">
<TextView style="@style/traitsinfo_label" android:text="@string/traitsinfo_defense_damageresist" />
<TextView android:id="@+id/traitsinfo_damageresist" />
</TableRow>
</merge>
<TableRow android:id="@+id/traitsinfo_is_immune_to_critical_hits_row">
<TextView android:text="@string/actorinfo_immune_criticals" android:layout_span="2" />
</TableRow>
</merge>

View File

@@ -559,5 +559,10 @@
<string name="preferences_dialog_overwrite_savegame_title">Confirm overwriting savegames</string>
<string name="preferences_dialog_overwrite_savegame">Gives a question about whether you want to overwrite when saving to a savegame slot that already contains a savegame.</string>
<!-- =========================================== -->
<!-- Added in v0.7.0 -->
<string name="heroinfo_reequip_cost">Re-equip cost (AP):</string>
<string name="heroinfo_useitem_cost">Use item cost (AP):</string>
</resources>

View File

@@ -34,4 +34,8 @@
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="traitsinfo_label" parent="android:Widget.TextView">
<item name="android:layout_marginRight">10sp</item>
</style>
</resources>

View File

@@ -106,7 +106,7 @@ public final class Savegames {
public static void saveWorld(WorldContext world, OutputStream outStream, String displayInfo) throws IOException {
DataOutputStream dest = new DataOutputStream(outStream);
final int flags = 0;
FileHeader.writeToParcel(dest, world.model.player.actorTraits.name, displayInfo);
FileHeader.writeToParcel(dest, world.model.player.getName(), displayInfo);
world.maps.writeToParcel(dest, flags);
world.model.writeToParcel(dest, flags);
dest.close();
@@ -127,7 +127,7 @@ public final class Savegames {
}
private static void onWorldLoaded(WorldContext world) {
ActorStatsController.recalculatePlayerCombatTraits(world.model.player);
ActorStatsController.recalculatePlayerStats(world.model.player);
Controller.resetMapsNotRecentlyVisited(world);
MovementController.moveBlockedActors(world);
}

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);
@@ -343,14 +343,14 @@ public final class ConversationActivity extends Activity implements OnKeyListene
ConversationStatement s = new ConversationStatement();
if (displayActors) {
assert(actor != null);
s.iconID = actor.actorTraits.iconID;
s.actorName = actor.actorTraits.name;
s.iconID = actor.iconID;
s.actorName = actor.getName();
} else {
s.iconID = ConversationStatement.NO_ICON;
}
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);
}
@@ -127,9 +127,9 @@ public final class DebugInterface {
,new DebugButton("hp", new OnClickListener() {
@Override
public void onClick(View arg0) {
world.model.player.actorTraits.maxHP = 200;
world.model.player.health.max = world.model.player.actorTraits.maxHP;
world.model.player.health.setMax();
world.model.player.baseTraits.maxHP = 200;
world.model.player.health.max = world.model.player.baseTraits.maxHP;
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

@@ -10,8 +10,6 @@ import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.model.item.Inventory;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.view.ActorConditionList;
import com.gpl.rpg.AndorsTrail.view.BaseTraitsInfoView;
import com.gpl.rpg.AndorsTrail.view.ItemEffectsView;
import com.gpl.rpg.AndorsTrail.view.RangeBar;
import com.gpl.rpg.AndorsTrail.view.TraitsInfoView;
@@ -21,7 +19,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TextView;
public final class HeroinfoActivity_Stats extends Activity {
@@ -31,16 +31,19 @@ public final class HeroinfoActivity_Stats extends Activity {
private Button levelUpButton;
private TextView heroinfo_ap;
private TextView heroinfo_movecost;
private TraitsInfoView heroinfo_currenttraits;
private ItemEffectsView heroinfo_itemeffects;
private TextView heroinfo_currentconditions_title;
private ActorConditionList heroinfo_currentconditions;
private TextView heroinfo_reequip_cost;
private TextView heroinfo_useitem_cost;
private TextView heroinfo_level;
private TextView heroinfo_totalexperience;
private TextView basetraitsinfo_max_hp;
private TextView basetraitsinfo_max_ap;
private TextView heroinfo_base_reequip_cost;
private TextView heroinfo_base_useitem_cost;
private RangeBar rangebar_hp;
private RangeBar rangebar_exp;
private BaseTraitsInfoView heroinfo_basetraits;
private ItemEffectsView actorinfo_onhiteffects;
private TableLayout heroinfo_basestats_table;
private ViewGroup heroinfo_container;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -53,17 +56,22 @@ public final class HeroinfoActivity_Stats extends Activity {
setContentView(R.layout.heroinfo_stats);
TextView tv = (TextView) findViewById(R.id.heroinfo_title);
tv.setText(player.actorTraits.name);
tv.setText(player.getName());
world.tileManager.setImageViewTile(tv, player);
heroinfo_container = (ViewGroup) findViewById(R.id.heroinfo_container);
heroinfo_ap = (TextView) findViewById(R.id.heroinfo_ap);
heroinfo_movecost = (TextView) findViewById(R.id.heroinfo_movecost);
heroinfo_currenttraits = (TraitsInfoView) findViewById(R.id.heroinfo_currenttraits);
heroinfo_itemeffects = (ItemEffectsView) findViewById(R.id.heroinfo_itemeffects);
heroinfo_currentconditions_title = (TextView) findViewById(R.id.heroinfo_currentconditions_title);
heroinfo_currentconditions = (ActorConditionList) findViewById(R.id.heroinfo_currentconditions);
heroinfo_reequip_cost = (TextView) findViewById(R.id.heroinfo_reequip_cost);
heroinfo_useitem_cost = (TextView) findViewById(R.id.heroinfo_useitem_cost);
basetraitsinfo_max_hp = (TextView) findViewById(R.id.basetraitsinfo_max_hp);
basetraitsinfo_max_ap = (TextView) findViewById(R.id.basetraitsinfo_max_ap);
heroinfo_base_reequip_cost = (TextView) findViewById(R.id.heroinfo_base_reequip_cost);
heroinfo_base_useitem_cost = (TextView) findViewById(R.id.heroinfo_base_useitem_cost);
heroinfo_level = (TextView) findViewById(R.id.heroinfo_level);
heroinfo_totalexperience = (TextView) findViewById(R.id.heroinfo_totalexperience);
actorinfo_onhiteffects = (ItemEffectsView) findViewById(R.id.actorinfo_onhiteffects);
heroinfo_basestats_table = (TableLayout) findViewById(R.id.heroinfo_basestats_table);
rangebar_hp = (RangeBar) findViewById(R.id.heroinfo_healthbar);
rangebar_hp.init(R.drawable.ui_progress_health, R.string.status_hp);
rangebar_exp = (RangeBar) findViewById(R.id.heroinfo_expbar);
@@ -81,8 +89,6 @@ public final class HeroinfoActivity_Stats extends Activity {
levelUpButton.setEnabled(false);
}
});
heroinfo_basetraits = (BaseTraitsInfoView) findViewById(R.id.heroinfo_basetraits);
}
@Override
@@ -90,7 +96,6 @@ public final class HeroinfoActivity_Stats extends Activity {
super.onResume();
updateTraits();
updateLevelup();
updateConditions();
}
@Override
@@ -105,17 +110,35 @@ public final class HeroinfoActivity_Stats extends Activity {
private void updateLevelup() {
levelUpButton.setEnabled(player.canLevelup());
}
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.actorTraits.moveCost));
heroinfo_reequip_cost.setText(Integer.toString(player.getReequipCost()));
heroinfo_useitem_cost.setText(Integer.toString(player.getUseItemCost()));
basetraitsinfo_max_hp.setText(Integer.toString(player.baseTraits.maxHP));
basetraitsinfo_max_ap.setText(Integer.toString(player.baseTraits.maxAP));
heroinfo_base_reequip_cost.setText(Integer.toString(player.baseTraits.reequipCost));
heroinfo_base_useitem_cost.setText(Integer.toString(player.baseTraits.useItemCost));
rangebar_hp.update(player.health);
rangebar_exp.update(player.levelExperience);
heroinfo_currenttraits.update(player);
ArrayList<ItemTraits_OnUse> effects_hit = new ArrayList<ItemTraits_OnUse>();
TraitsInfoView.update(heroinfo_container, player);
TraitsInfoView.updateTraitsTable(
heroinfo_basestats_table
, player.baseTraits.moveCost
, player.baseTraits.attackCost
, player.baseTraits.attackChance
, player.baseTraits.damagePotential
, player.baseTraits.criticalSkill
, player.baseTraits.criticalMultiplier
, player.baseTraits.blockChance
, player.baseTraits.damageResistance
, false
);
ArrayList<ItemTraits_OnUse> effects_hit = new ArrayList<ItemTraits_OnUse>();
ArrayList<ItemTraits_OnUse> effects_kill = new ArrayList<ItemTraits_OnUse>();
for (int i = 0; i < Inventory.NUM_WORN_SLOTS; ++i) {
ItemType type = player.inventory.wear[i];
@@ -125,18 +148,6 @@ public final class HeroinfoActivity_Stats extends Activity {
}
if (effects_hit.isEmpty()) effects_hit = null;
if (effects_kill.isEmpty()) effects_kill = null;
heroinfo_itemeffects.update(null, null, effects_hit, effects_kill, false);
heroinfo_basetraits.update(player.actorTraits);
actorinfo_onhiteffects.update(null, null, effects_hit, effects_kill, false);
}
private void updateConditions() {
if (player.conditions.isEmpty()) {
heroinfo_currentconditions_title.setVisibility(View.GONE);
heroinfo_currentconditions.setVisibility(View.GONE);
} else {
heroinfo_currentconditions_title.setVisibility(View.VISIBLE);
heroinfo_currentconditions.setVisibility(View.VISIBLE);
heroinfo_currentconditions.update(player.conditions);
}
}
}

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 {
@@ -118,14 +118,14 @@ public final class LevelUpActivity extends Activity {
hpIncrease = Constants.LEVELUP_EFFECT_HEALTH;
break;
case SELECT_ATK_CH:
player.actorTraits.baseCombatTraits.attackChance += Constants.LEVELUP_EFFECT_ATK_CH;
player.baseTraits.attackChance += Constants.LEVELUP_EFFECT_ATK_CH;
break;
case SELECT_ATK_DMG:
player.actorTraits.baseCombatTraits.damagePotential.max += Constants.LEVELUP_EFFECT_ATK_DMG;
player.actorTraits.baseCombatTraits.damagePotential.current += Constants.LEVELUP_EFFECT_ATK_DMG;
player.baseTraits.damagePotential.max += Constants.LEVELUP_EFFECT_ATK_DMG;
player.baseTraits.damagePotential.current += Constants.LEVELUP_EFFECT_ATK_DMG;
break;
case SELECT_DEF_CH:
player.actorTraits.baseCombatTraits.blockChance += Constants.LEVELUP_EFFECT_DEF_CH;
player.baseTraits.blockChance += Constants.LEVELUP_EFFECT_DEF_CH;
break;
}
if (player.nextLevelAddsNewSkillpoint()) {
@@ -135,10 +135,9 @@ public final class LevelUpActivity extends Activity {
hpIncrease += player.getSkillLevel(SkillCollection.SKILL_FORTITUDE) * SkillCollection.PER_SKILLPOINT_INCREASE_FORTITUDE_HEALTH;
player.health.max += hpIncrease;
player.actorTraits.maxHP += hpIncrease;
player.baseTraits.maxHP += hpIncrease;
player.health.current += hpIncrease;
player.recalculateLevelExperience();
ActorStatsController.recalculatePlayerCombatTraits(player);
ActorStatsController.recalculatePlayerStats(player);
}
}

View File

@@ -109,7 +109,7 @@ public final class LoadSaveActivity extends Activity implements OnClickListener
return null;
}
final String currentPlayerName = model.player.actorTraits.name;
final String currentPlayerName = model.player.getName();
final FileHeader header = Savegames.quickload(this, slot);
if (header == null) return null;

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

@@ -37,7 +37,7 @@ public final class MonsterEncounterActivity extends Activity {
CharSequence difficulty = getText(MonsterInfoActivity.getMonsterDifficultyResource(world, monster));
TextView tv = (TextView) findViewById(R.id.monsterencounter_title);
tv.setText(monster.actorTraits.name);
tv.setText(monster.getName());
world.tileManager.setImageViewTile(tv, monster);
tv = (TextView) findViewById(R.id.monsterencounter_description);

View File

@@ -1,14 +1,11 @@
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;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.CombatController;
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
import com.gpl.rpg.AndorsTrail.view.ActorConditionList;
import com.gpl.rpg.AndorsTrail.view.ItemEffectsView;
import com.gpl.rpg.AndorsTrail.view.RangeBar;
import com.gpl.rpg.AndorsTrail.view.TraitsInfoView;
@@ -16,6 +13,7 @@ import com.gpl.rpg.AndorsTrail.view.TraitsInfoView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -23,16 +21,16 @@ import android.widget.TextView;
public final class MonsterInfoActivity extends Activity {
private TextView monsterinfo_title;
private TextView monsterinfo_difficulty;
private TraitsInfoView monsterinfo_currenttraits;
private ItemEffectsView monsterinfo_onhiteffects;
private TextView monsterinfo_currentconditions_title;
private TextView monsterinfo_immune_criticals;
private ActorConditionList monsterinfo_currentconditions;
private RangeBar hp;
private WorldContext world;
private TextView monsterinfo_title;
private TextView monsterinfo_difficulty;
private ItemEffectsView monsterinfo_onhiteffects;
private RangeBar hp;
private ViewGroup monsterinfo_container;
private TextView monsterinfo_max_ap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -45,7 +43,7 @@ public final class MonsterInfoActivity extends Activity {
monsterinfo_title = (TextView) findViewById(R.id.monsterinfo_title);
monsterinfo_difficulty = (TextView) findViewById(R.id.monsterinfo_difficulty);
monsterinfo_immune_criticals = (TextView) findViewById(R.id.monsterinfo_immune_criticals);
monsterinfo_max_ap = (TextView) findViewById(R.id.monsterinfo_max_ap);
Button b = (Button) findViewById(R.id.monsterinfo_close);
b.setOnClickListener(new OnClickListener() {
@@ -55,12 +53,10 @@ public final class MonsterInfoActivity extends Activity {
}
});
monsterinfo_currenttraits = (TraitsInfoView) findViewById(R.id.monsterinfo_currenttraits);
monsterinfo_onhiteffects = (ItemEffectsView) findViewById(R.id.monsterinfo_onhiteffects);
monsterinfo_currentconditions_title = (TextView) findViewById(R.id.monsterinfo_currentconditions_title);
monsterinfo_currentconditions = (ActorConditionList) findViewById(R.id.monsterinfo_currentconditions);
monsterinfo_onhiteffects = (ItemEffectsView) findViewById(R.id.actorinfo_onhiteffects);
hp = (RangeBar) findViewById(R.id.monsterinfo_healthbar);
hp.init(R.drawable.ui_progress_health, R.string.status_hp);
monsterinfo_container = (ViewGroup) findViewById(R.id.monsterinfo_container);
}
@Override
@@ -75,25 +71,24 @@ public final class MonsterInfoActivity extends Activity {
updateTitle(monster);
updateTraits(monster);
updateConditions(monster);
}
private void updateTitle(Monster monster) {
monsterinfo_title.setText(monster.actorTraits.name);
monsterinfo_title.setText(monster.getName());
world.tileManager.setImageViewTile(monsterinfo_title, monster);
monsterinfo_difficulty.setText(getMonsterDifficultyResource(world, monster));
}
private void updateTraits(Monster monster) {
monsterinfo_currenttraits.update(monster);
TraitsInfoView.update(monsterinfo_container, monster);
monsterinfo_onhiteffects.update(
null,
null,
monster.actorTraits.onHitEffects == null ? null : Arrays.asList(monster.actorTraits.onHitEffects),
monster.getOnHitEffectsAsList(),
null,
false);
hp.update(monster.health);
monsterinfo_immune_criticals.setVisibility(monster.isImmuneToCriticalHits ? View.VISIBLE : View.GONE);
monsterinfo_max_ap.setText(Integer.toString(monster.ap.max));
}
public static int getMonsterDifficultyResource(WorldContext world, Monster monster) {
@@ -105,15 +100,4 @@ public final class MonsterInfoActivity extends Activity {
else if (difficulty == 0) return R.string.monster_difficulty_impossible;
else return R.string.monster_difficulty_veryhard;
}
private void updateConditions(Monster monster) {
if (monster.conditions.isEmpty()) {
monsterinfo_currentconditions_title.setVisibility(View.GONE);
monsterinfo_currentconditions.setVisibility(View.GONE);
} else {
monsterinfo_currentconditions_title.setVisibility(View.VISIBLE);
monsterinfo_currentconditions.setVisibility(View.VISIBLE);
monsterinfo_currentconditions.update(monster.conditions);
}
}
}

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

@@ -4,11 +4,9 @@ import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.SkillController;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
import com.gpl.rpg.AndorsTrail.model.ability.SkillInfo;
import com.gpl.rpg.AndorsTrail.model.ability.SkillInfo.SkillLevelRequirement;
import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
import android.app.Activity;
@@ -194,9 +192,9 @@ public final class SkillInfoActivity extends Activity {
private static int getRequirementActorStatsResourceID(int statID) {
switch (statID) {
case ActorTraits.STAT_ACTOR_MAX_HP: return R.string.actorinfo_health;
case ActorTraits.STAT_ACTOR_MAX_AP: return R.string.heroinfo_actionpoints;
case ActorTraits.STAT_ACTOR_MOVECOST: return R.string.actorinfo_movecost;
case Player.STAT_ACTOR_MAX_HP: return R.string.actorinfo_health;
case Player.STAT_ACTOR_MAX_AP: return R.string.heroinfo_actionpoints;
case Player.STAT_ACTOR_MOVECOST: return R.string.actorinfo_movecost;
default:
return -1;
}
@@ -204,14 +202,14 @@ public final class SkillInfoActivity extends Activity {
private static int getRequirementCombatStatsResourceID(int statID) {
switch (statID) {
case CombatTraits.STAT_COMBAT_ATTACK_COST: return R.string.traitsinfo_attack_cost;
case CombatTraits.STAT_COMBAT_ATTACK_CHANCE: return R.string.traitsinfo_attack_chance;
case CombatTraits.STAT_COMBAT_CRITICAL_SKILL: return R.string.traitsinfo_criticalhit_skill;
case CombatTraits.STAT_COMBAT_CRITICAL_MULTIPLIER: return R.string.traitsinfo_criticalhit_multiplier;
case CombatTraits.STAT_COMBAT_DAMAGE_POTENTIAL_MIN: return R.string.traitsinfo_attack_damage;
case CombatTraits.STAT_COMBAT_DAMAGE_POTENTIAL_MAX: return R.string.traitsinfo_attack_damage;
case CombatTraits.STAT_COMBAT_BLOCK_CHANCE: return R.string.traitsinfo_defense_chance;
case CombatTraits.STAT_COMBAT_DAMAGE_RESISTANCE: return R.string.traitsinfo_defense_damageresist;
case Player.STAT_COMBAT_ATTACK_COST: return R.string.traitsinfo_attack_cost;
case Player.STAT_COMBAT_ATTACK_CHANCE: return R.string.traitsinfo_attack_chance;
case Player.STAT_COMBAT_CRITICAL_SKILL: return R.string.traitsinfo_criticalhit_skill;
case Player.STAT_COMBAT_CRITICAL_MULTIPLIER: return R.string.traitsinfo_criticalhit_multiplier;
case Player.STAT_COMBAT_DAMAGE_POTENTIAL_MIN: return R.string.traitsinfo_attack_damage;
case Player.STAT_COMBAT_DAMAGE_POTENTIAL_MAX: return R.string.traitsinfo_attack_damage;
case Player.STAT_COMBAT_BLOCK_CHANCE: return R.string.traitsinfo_defense_chance;
case Player.STAT_COMBAT_DAMAGE_RESISTANCE: return R.string.traitsinfo_defense_damageresist;
default:
return -1;
}

View File

@@ -4,7 +4,6 @@ import java.util.ArrayList;
import com.gpl.rpg.AndorsTrail.VisualEffectCollection;
import com.gpl.rpg.AndorsTrail.context.ViewContext;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionType;
@@ -167,37 +166,44 @@ 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.actorTraits.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.actorTraits.moveCost <= 0) actor.actorTraits.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 recalculatePlayerStats(Player player) {
player.resetStatsToBaseTraits();
player.recalculateLevelExperience();
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) recalculatePlayerStats((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);
recalculatePlayerStats(player);
}
}
}
@@ -311,8 +317,10 @@ public class ActorStatsController {
}
}
}
VisualEffect effectToStart = applyStatsModifierEffect(source, effect, 1, null);
startVisualEffect(source, effectToStart);
if (effect.changedStats != null) {
VisualEffect effectToStart = applyStatsModifierEffect(source, effect.changedStats, 1, null);
startVisualEffect(source, effectToStart);
}
}
private static void rollForConditionEffect(Actor actor, ActorConditionEffect conditionEffect) {
@@ -396,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;
@@ -179,7 +178,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
if (attack.isHit) {
String msg;
final String monsterName = target.actorTraits.name;
final String monsterName = target.getName();
if (attack.isCriticalHit) {
msg = r.getString(R.string.combat_result_herohitcritical, monsterName, attack.damage);
} else {
@@ -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.actorTraits.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.actorTraits.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,14 +331,14 @@ 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();
AttackResult attack = monsterAttacks(model, currentActiveMonster);
this.lastAttackResult = attack;
String monsterName = currentActiveMonster.actorTraits.name;
String monsterName = currentActiveMonster.getName();
if (attack.isHit) {
if (attack.isCriticalHit) {
message(r.getString(R.string.combat_result_monsterhitcritical, monsterName, attack.damage));
@@ -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.actorTraits.maxHP / 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.actorTraits.onHitEffects == null) return;
ItemTraits_OnUse[] onHitEffects = attacker.getOnHitEffects();
if (onHitEffects == null) return;
for (ItemTraits_OnUse e : attacker.actorTraits.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);
}
}
@@ -78,12 +78,11 @@ public final class Controller {
public static void playerRested(final WorldContext world, MapObject area) {
final Player player = world.model.player;
ActorStatsController.removeAllTemporaryConditions(player);
ActorStatsController.recalculatePlayerCombatTraits(player);
ActorStatsController.recalculatePlayerStats(player);
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

@@ -100,6 +100,6 @@ public final class ConversationController {
public static String getDisplayMessage(Phrase phrase, Player player) { return replacePlayerName(phrase.message, player); }
public static String getDisplayMessage(Reply reply, Player player) { return replacePlayerName(reply.text, player); }
public static String replacePlayerName(String s, Player player) {
return s.replace(Constants.PLACEHOLDER_PLAYERNAME, player.actorTraits.name);
return s.replace(Constants.PLACEHOLDER_PLAYERNAME, player.getName());
}
}

View File

@@ -6,7 +6,6 @@ import com.gpl.rpg.AndorsTrail.Dialogs;
import com.gpl.rpg.AndorsTrail.context.ViewContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
import com.gpl.rpg.AndorsTrail.model.ability.traits.AbilityModifierTraits;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
@@ -40,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;
@@ -54,7 +53,7 @@ public final class ItemController {
player.inventory.wear[slot] = type;
ActorStatsController.addConditionsFromEquippedItem(player, type);
ActorStatsController.recalculatePlayerCombatTraits(player);
ActorStatsController.recalculatePlayerStats(player);
}
public void unequipSlot(ItemType type, int slot) {
@@ -63,11 +62,11 @@ 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);
ActorStatsController.recalculatePlayerCombatTraits(player);
ActorStatsController.recalculatePlayerStats(player);
}
private static void unequipSlot(Player player, int slot) {
@@ -82,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;
@@ -102,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);
@@ -154,9 +153,9 @@ public final class ItemController {
if (effects != null) {
ItemTraits_OnUse[] effects_ = new ItemTraits_OnUse[effects.size()];
effects_ = effects.toArray(effects_);
player.actorTraits.onHitEffects = effects_;
player.onHitEffects = effects_;
} else {
player.actorTraits.onHitEffects = null;
player.onHitEffects = null;
}
}
@@ -325,22 +324,4 @@ public final class ItemController {
model.player.inventory.quickitem[quickSlotId] = itemType;
view.mainActivity.updateStatus();
}
public static void correctActorConditionsFromItemsPre0611b1(Player player, String conditionTypeID, WorldContext world, String itemTypeIDWithCondition) {
if (!player.hasCondition(conditionTypeID)) return;
boolean hasItemWithCondition = false;
for (ItemType t : player.inventory.wear) {
if (t == null) continue;
if (t.effects_equip == null) continue;
if (t.effects_equip.addedConditions == null) continue;
for(ActorConditionEffect e : t.effects_equip.addedConditions) {
if (!e.conditionType.conditionTypeID.equals(conditionTypeID)) continue;
hasItemWithCondition = true;
break;
}
}
if (hasItemWithCondition) return;
ActorStatsController.removeConditionsFromUnequippedItem(player, world.itemTypes.getItemType(itemTypeIDWithCondition));
}
}

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) {
@@ -257,7 +257,7 @@ public final class MovementController implements TimedMessageTask.Callback {
for (MonsterSpawnArea a : map.spawnAreas) {
for (Monster m : a.monsters) {
if (!map.isWalkable(m.rectPosition)) {
Coord p = map.getRandomFreePosition(a.area, m.actorTraits.tileSize, playerPosition);
Coord p = map.getRandomFreePosition(a.area, m.tileSize, playerPosition);
if (p == null) continue;
m.position.set(p);
}
@@ -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

@@ -2,7 +2,6 @@ package com.gpl.rpg.AndorsTrail.controller;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.model.AttackResult;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionType;
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
@@ -17,17 +16,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 +143,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

@@ -1,132 +0,0 @@
package com.gpl.rpg.AndorsTrail.model;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import android.util.FloatMath;
import com.gpl.rpg.AndorsTrail.util.Range;
public class CombatTraits {
public static final int STAT_COMBAT_ATTACK_COST = 0;
public static final int STAT_COMBAT_ATTACK_CHANCE = 1;
public static final int STAT_COMBAT_CRITICAL_SKILL = 2;
public static final int STAT_COMBAT_CRITICAL_MULTIPLIER = 3;
public static final int STAT_COMBAT_DAMAGE_POTENTIAL_MIN = 4;
public static final int STAT_COMBAT_DAMAGE_POTENTIAL_MAX = 5;
public static final int STAT_COMBAT_BLOCK_CHANCE = 6;
public static final int STAT_COMBAT_DAMAGE_RESISTANCE = 7;
public int attackCost;
public int attackChance;
public int criticalSkill;
public float criticalMultiplier;
public final Range damagePotential;
public int blockChance;
public int damageResistance;
public CombatTraits() {
this.damagePotential = new Range();
}
public CombatTraits(CombatTraits copy) {
this();
set(copy);
}
public void set(CombatTraits copy) {
if (copy == null) return;
this.attackCost = copy.attackCost;
this.attackChance = copy.attackChance;
this.criticalSkill = copy.criticalSkill;
this.criticalMultiplier = copy.criticalMultiplier;
this.damagePotential.set(copy.damagePotential);
this.blockChance = copy.blockChance;
this.damageResistance = copy.damageResistance;
}
public boolean equals(CombatTraits other) {
if (other == null) return isZero();
return
this.attackCost == other.attackCost
&& this.attackChance == other.attackChance
&& this.criticalSkill == other.criticalSkill
&& this.criticalMultiplier == other.criticalMultiplier
&& this.damagePotential.equals(other.damagePotential)
&& this.blockChance == other.blockChance
&& this.damageResistance == other.damageResistance;
}
private boolean isZero() {
return
this.attackCost == 0
&& this.attackChance == 0
&& this.criticalSkill == 0
&& this.criticalMultiplier == 0
&& this.damagePotential.current == 0
&& this.damagePotential.max == 0
&& this.blockChance == 0
&& this.damageResistance == 0;
}
public boolean hasAttackChanceEffect() { return attackChance != 0; }
public boolean hasAttackDamageEffect() { return damagePotential.max != 0; }
public boolean hasBlockEffect() { return blockChance != 0; }
public boolean hasCriticalSkillEffect() { return criticalSkill != 0; }
public boolean hasCriticalMultiplierEffect() { return criticalMultiplier != 0 && criticalMultiplier != 1; }
public boolean hasCriticalAttacks() { return hasCriticalSkillEffect() && hasCriticalMultiplierEffect(); }
public int getEffectiveCriticalChance() {
if (criticalSkill <= 0) return 0;
int v = (int) (-5 + 2 * FloatMath.sqrt(5*criticalSkill));
if (v < 0) return 0;
return v;
}
public int getAttacksPerTurn(final int maxAP) {
return (int) Math.floor(maxAP / attackCost);
}
public int getCombatStats(int statID) {
switch (statID) {
case STAT_COMBAT_ATTACK_COST: return attackCost;
case STAT_COMBAT_ATTACK_CHANCE: return attackChance;
case STAT_COMBAT_CRITICAL_SKILL: return criticalSkill;
case STAT_COMBAT_CRITICAL_MULTIPLIER: return (int) FloatMath.floor(criticalMultiplier);
case STAT_COMBAT_DAMAGE_POTENTIAL_MIN: return damagePotential.current;
case STAT_COMBAT_DAMAGE_POTENTIAL_MAX: return damagePotential.max;
case STAT_COMBAT_BLOCK_CHANCE: return blockChance;
case STAT_COMBAT_DAMAGE_RESISTANCE: return damageResistance;
}
return 0;
}
// ====== PARCELABLE ===================================================================
public CombatTraits(DataInputStream src, int fileversion) throws IOException {
this.attackCost = src.readInt();
this.attackChance = src.readInt();
this.criticalSkill = src.readInt();
if (fileversion <= 20) {
this.criticalMultiplier = src.readInt();
} else {
this.criticalMultiplier = src.readFloat();
}
this.damagePotential = new Range(src, fileversion);
this.blockChance = src.readInt();
this.damageResistance = src.readInt();
}
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
dest.writeInt(attackCost);
dest.writeInt(attackChance);
dest.writeInt(criticalSkill);
dest.writeFloat(criticalMultiplier);
damagePotential.writeToParcel(dest, flags);
dest.writeInt(blockChance);
dest.writeInt(damageResistance);
}
}

View File

@@ -26,7 +26,7 @@ public final class ModelContainer {
// ====== PARCELABLE ===================================================================
public ModelContainer(DataInputStream src, WorldContext world, int fileversion) throws IOException {
this.player = new Player(src, world, fileversion);
this.player = Player.readFromParcel(src, world, fileversion);
this.currentMap = world.maps.findPredefinedMap(src.readUTF());
this.uiSelections = new InterfaceData(src, world, fileversion);
if (uiSelections.selectedPosition != null) {

View File

@@ -6,9 +6,8 @@ import java.util.Collection;
import android.util.SparseArray;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.SkillInfo.SkillLevelRequirement;
import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
public final class SkillCollection {
public static final int SKILL_WEAPON_CHANCE = 0;
@@ -91,7 +90,7 @@ public final class SkillCollection {
initializeSkill(new SkillInfo(SKILL_DODGE, SkillInfo.MAXLEVEL_NONE, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, null));
initializeSkill(new SkillInfo(SKILL_BARKSKIN, MAX_LEVEL_BARKSKIN, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, new SkillLevelRequirement[] {
SkillLevelRequirement.requireExperienceLevels(10, 0)
,SkillLevelRequirement.requireCombatStats(CombatTraits.STAT_COMBAT_BLOCK_CHANCE, 15, 0)
,SkillLevelRequirement.requireCombatStats(Player.STAT_COMBAT_BLOCK_CHANCE, 15, 0)
}));
initializeSkill(new SkillInfo(SKILL_MORE_CRITICALS, SkillInfo.MAXLEVEL_NONE, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, null));
initializeSkill(new SkillInfo(SKILL_BETTER_CRITICALS, SkillInfo.MAXLEVEL_NONE, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, new SkillLevelRequirement[] {
@@ -107,14 +106,14 @@ public final class SkillCollection {
,SkillLevelRequirement.requireOtherSkill(SKILL_WEAPON_DMG, 1)
}));
initializeSkill(new SkillInfo(SKILL_EATER, SkillInfo.MAXLEVEL_NONE, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, new SkillLevelRequirement[] {
SkillLevelRequirement.requireActorStats(ActorTraits.STAT_ACTOR_MAX_HP, 20, 20)
SkillLevelRequirement.requireActorStats(Player.STAT_ACTOR_MAX_HP, 20, 20)
}));
initializeSkill(new SkillInfo(SKILL_FORTITUDE, SkillInfo.MAXLEVEL_NONE, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, new SkillLevelRequirement[] {
SkillLevelRequirement.requireExperienceLevels(15, -10)
}));
initializeSkill(new SkillInfo(SKILL_EVASION, MAX_LEVEL_EVASION, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, null));
initializeSkill(new SkillInfo(SKILL_REGENERATION, SkillInfo.MAXLEVEL_NONE, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, new SkillLevelRequirement[] {
SkillLevelRequirement.requireActorStats(ActorTraits.STAT_ACTOR_MAX_HP, 30, 0)
SkillLevelRequirement.requireActorStats(Player.STAT_ACTOR_MAX_HP, 30, 0)
,SkillLevelRequirement.requireOtherSkill(SKILL_FORTITUDE, 1)
}));
initializeSkill(new SkillInfo(SKILL_LOWER_EXPLOSS, MAX_LEVEL_LOWER_EXPLOSS, SkillInfo.LEVELUP_TYPE_ALWAYS_SHOWN, null));

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.actorTraits.baseCombatTraits.getCombatStats(skillOrStatID);
case REQUIREMENT_TYPE_ACTOR_STAT: return player.actorTraits.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

@@ -1,42 +1,77 @@
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.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.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Range;
import com.gpl.rpg.AndorsTrail.util.Size;
public class Actor {
public final ActorTraits actorTraits;
public final CombatTraits combatTraits;
public final Range ap;
public final Range health;
public final Coord position;
public int iconID;
public final Size tileSize;
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 actorTraits, boolean isPlayer, boolean isImmuneToCriticalHits) {
this.combatTraits = new CombatTraits(actorTraits.baseCombatTraits);
this.actorTraits = actorTraits;
this.ap = new Range(actorTraits.maxAP, actorTraits.maxAP);
this.health = new Range(actorTraits.maxHP, actorTraits.maxHP);
this.position = new Coord();
this.rectPosition = new CoordRect(position, actorTraits.tileSize);
public Actor(Size tileSize, boolean isPlayer, boolean isImmuneToCriticalHits) {
this.tileSize = tileSize;
this.rectPosition = new CoordRect(this.position, this.tileSize);
this.isPlayer = isPlayer;
this.isImmuneToCriticalHits = isImmuneToCriticalHits;
}
public int getAttacksPerTurn() { return combatTraits.getAttacksPerTurn(actorTraits.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 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;
@@ -63,56 +98,4 @@ public class Actor {
}
return false;
}
public void resetStatsToBaseTraits() {
combatTraits.set(actorTraits.baseCombatTraits);
health.set(actorTraits.maxHP, health.current);
ap.set(actorTraits.maxAP, ap.current);
actorTraits.moveCost = actorTraits.baseMoveCost;
}
// ====== PARCELABLE ===================================================================
public Actor(DataInputStream src, WorldContext world, int fileversion, boolean isPlayer, boolean isImmuneToCriticalHits, ActorTraits actorTraits) throws IOException {
this.isPlayer = isPlayer;
this.isImmuneToCriticalHits = isImmuneToCriticalHits;
CombatTraits combatTraits = null;
boolean readCombatTraits = true;
if (fileversion >= 25) readCombatTraits = src.readBoolean();
if (readCombatTraits) combatTraits = new CombatTraits(src, fileversion);
this.actorTraits = isPlayer ? new ActorTraits(src, world, fileversion) : actorTraits;
if (!readCombatTraits) combatTraits = new CombatTraits(this.actorTraits.baseCombatTraits);
this.combatTraits = combatTraits;
this.ap = new Range(src, fileversion);
this.health = new Range(src, fileversion);
this.position = new Coord(src, fileversion);
this.rectPosition = new CoordRect(position, this.actorTraits.tileSize);
if (fileversion <= 16) return;
final int n = src.readInt();
for(int i = 0; i < n ; ++i) {
conditions.add(new ActorCondition(src, world, fileversion));
}
}
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
if (this.combatTraits.equals(actorTraits.baseCombatTraits)) {
dest.writeBoolean(false);
} else {
dest.writeBoolean(true);
combatTraits.writeToParcel(dest, flags);
}
if (isPlayer) actorTraits.writeToParcel(dest, flags);
ap.writeToParcel(dest, flags);
health.writeToParcel(dest, flags);
position.writeToParcel(dest, flags);
dest.writeInt(conditions.size());
for (ActorCondition c : conditions) {
c.writeToParcel(dest, flags);
}
}
}

View File

@@ -1,84 +0,0 @@
package com.gpl.rpg.AndorsTrail.model.actor;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.util.Size;
public class ActorTraits {
public static final int STAT_ACTOR_MAX_HP = 0;
public static final int STAT_ACTOR_MAX_AP = 1;
public static final int STAT_ACTOR_MOVECOST = 2;
public final int iconID;
public final Size tileSize;
public int maxAP;
public int maxHP;
public String name;
public int moveCost;
public final int baseMoveCost;
public final CombatTraits baseCombatTraits;
public ItemTraits_OnUse[] onHitEffects;
public ActorTraits(
int iconID
, Size tileSize
, CombatTraits baseCombatTraits
, int standardMoveCost
, ItemTraits_OnUse[] onHitEffects
) {
this.iconID = iconID;
this.tileSize = tileSize;
this.baseCombatTraits = baseCombatTraits;
this.baseMoveCost = standardMoveCost;
this.onHitEffects = onHitEffects;
}
public int getMovesPerTurn() {
return (int) Math.floor(maxAP / moveCost);
}
public int getActorStats(int statID) {
switch (statID) {
case STAT_ACTOR_MAX_HP: return maxHP;
case STAT_ACTOR_MAX_AP: return maxAP;
case STAT_ACTOR_MOVECOST: return moveCost;
}
return 0;
}
// ====== PARCELABLE ===================================================================
public ActorTraits(DataInputStream src, WorldContext world, int fileversion) throws IOException {
this.iconID = src.readInt();
this.tileSize = new Size(src, fileversion);
this.maxAP = src.readInt();
this.maxHP = src.readInt();
this.name = src.readUTF();
this.moveCost = src.readInt();
this.baseCombatTraits = new CombatTraits(src, fileversion);
if (fileversion <= 16) {
this.baseMoveCost = this.moveCost;
} else {
this.baseMoveCost = src.readInt();
}
}
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
dest.writeInt(iconID);
tileSize.writeToParcel(dest, flags);
dest.writeInt(maxAP);
dest.writeInt(maxHP);
dest.writeUTF(name);
dest.writeInt(moveCost);
baseCombatTraits.writeToParcel(dest, flags);
dest.writeInt(baseMoveCost);
}
}

View File

@@ -5,63 +5,89 @@ 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.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, false, monsterType.isImmuneToCriticalHits());
this.monsterTypeID = monsterType.id;
this.position.set(position);
this.millisecondsPerMove = Constants.MONSTER_MOVEMENT_TURN_DURATION_MS / monsterType.getMovesPerTurn();
this.nextPosition = new CoordRect(new Coord(), actorTraits.tileSize);
this.phraseID = monsterType.phraseID;
this.exp = monsterType.exp;
this.dropList = monsterType.dropList;
this.faction = monsterType.faction;
this.monsterClass = monsterType.monsterClass;
private final MonsterType monsterType;
public Monster(MonsterType monsterType) {
super(monsterType.tileSize, false, monsterType.isImmuneToCriticalHits());
this.monsterType = monsterType;
this.iconID = monsterType.iconID;
this.nextPosition = new CoordRect(new Coord(), monsterType.tileSize);
resetStatsToBaseTraits();
setMaxAP();
setMaxHP();
}
public void resetStatsToBaseTraits() {
this.name = monsterType.name;
this.ap.max = monsterType.maxAP;
this.health.max = 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;
}
@@ -74,22 +100,45 @@ public final class Monster extends Actor {
}
MonsterType monsterType = world.monsterTypes.getMonsterType(monsterTypeId);
if (fileversion < 25) return readFromParcel_pre_v0610(src, fileversion, monsterType);
if (fileversion < 25) return LegacySavegameFormatReaderForMonster.readFromParcel_pre_v25(src, 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);
this.monsterTypeID = monsterType.id;
this.millisecondsPerMove = Constants.MONSTER_MOVEMENT_TURN_DURATION_MS / monsterType.getMovesPerTurn();
this.nextPosition = new CoordRect(new Coord(), actorTraits.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();
if (fileversion <= 20) {
this.criticalMultiplier = src.readInt();
} else {
this.criticalMultiplier = src.readFloat();
}
this.damagePotential.set(new Range(src, fileversion));
this.blockChance = src.readInt();
this.damageResistance = src.readInt();
}
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 (fileversion >= 31) {
if (src.readBoolean()) {
this.shopItems = new ItemContainer(src, world, fileversion);
@@ -97,20 +146,36 @@ public final class Monster extends Actor {
}
}
private static Monster readFromParcel_pre_v0610(DataInputStream src, int fileversion, MonsterType monsterType) throws IOException {
Coord position = new Coord(src, fileversion);
Monster m = new Monster(monsterType, position);
m.ap.current = src.readInt();
m.health.current = src.readInt();
if (fileversion >= 12) {
m.forceAggressive = src.readBoolean();
}
return m;
}
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,11 +1,11 @@
package com.gpl.rpg.AndorsTrail.model.actor;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
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 extends ActorTraits {
public final class MonsterType {
public static final int MONSTERCLASS_HUMANOID = 0;
public static final int MONSTERCLASS_INSECT = 1;
public static final int MONSTERCLASS_DEMON = 2;
@@ -17,6 +17,7 @@ public final class MonsterType extends ActorTraits {
public static final int MONSTERCLASS_GHOST = 8;
public final String id;
public final String name;
public final String spawnGroup;
public final int exp;
public final DropList dropList;
@@ -24,37 +25,65 @@ public final class MonsterType extends ActorTraits {
public final boolean isUnique; // Unique monsters are not respawned.
public final String faction;
public final int monsterClass;
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,
String name,
String spawnGroup,
int iconID,
Size tileSize,
int maxHP,
int maxAP,
int moveCost,
CombatTraits baseCombatTraits,
ItemTraits_OnUse onHitEffects,
int exp,
DropList dropList,
String phraseID,
boolean isUnique,
String faction,
int monsterClass) {
super(iconID, tileSize, baseCombatTraits, moveCost, onHitEffects == null ? null : new ItemTraits_OnUse[] { onHitEffects });
int monsterClass,
Size tileSize,
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;
this.exp = exp;
this.name = name;
this.maxHP = maxHP;
this.maxAP = maxAP;
this.moveCost = moveCost;
this.dropList = dropList;
this.phraseID = phraseID;
this.faction = faction;
this.isUnique = isUnique;
this.monsterClass = monsterClass;
this.tileSize = tileSize;
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() {
@@ -63,4 +92,15 @@ public final class MonsterType extends ActorTraits {
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 != null) return true;
if (blockChance != 0) return true;
if (damageResistance != 0) return true;
return false;
}
}

View File

@@ -14,38 +14,90 @@ 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.controller.ItemController;
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.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.util.Coord;
import com.gpl.rpg.AndorsTrail.util.Range;
import com.gpl.rpg.AndorsTrail.util.Size;
public final class Player extends Actor {
public static final int DEFAULT_PLAYER_MOVECOST = 6;
public static final int STAT_ACTOR_MAX_HP = 0;
public static final int STAT_ACTOR_MAX_AP = 1;
public static final int STAT_ACTOR_MOVECOST = 2;
public static final int STAT_COMBAT_ATTACK_COST = 0;
public static final int STAT_COMBAT_ATTACK_CHANCE = 1;
public static final int STAT_COMBAT_CRITICAL_SKILL = 2;
public static final int STAT_COMBAT_CRITICAL_MULTIPLIER = 3;
public static final int STAT_COMBAT_DAMAGE_POTENTIAL_MIN = 4;
public static final int STAT_COMBAT_DAMAGE_POTENTIAL_MAX = 5;
public static final int STAT_COMBAT_BLOCK_CHANCE = 6;
public static final int STAT_COMBAT_DAMAGE_RESISTANCE = 7;
public static final int DEFAULT_PLAYER_ATTACKCOST = 4;
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>();
// Unequipped stats
public class PlayerBaseTraits {
public int iconID;
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.iconID = this.baseTraits.iconID;
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, new Size(1, 1), new CombatTraits(), DEFAULT_PLAYER_MOVECOST, null), true, false);
super(
new Size(1, 1)
, true // isPlayer
, false // isImmuneToCriticalHits
);
this.lastPosition = new Coord();
this.nextPosition = new Coord();
this.levelExperience = new Range();
@@ -53,45 +105,44 @@ public final class Player extends Actor {
}
public void initializeNewPlayer(ItemTypeCollection types, DropListCollection dropLists, String name) {
CombatTraits combat = new CombatTraits();
combat.attackCost = DEFAULT_PLAYER_ATTACKCOST;
combat.attackChance = 60;
combat.criticalSkill = 0;
combat.criticalMultiplier = 1;
combat.damagePotential.set(1, 1);
combat.blockChance = 0;
combat.damageResistance = 0;
actorTraits.baseCombatTraits.set(combat);
actorTraits.maxAP = 10;
actorTraits.maxHP = 25;
actorTraits.name = name;
actorTraits.moveCost = DEFAULT_PLAYER_MOVECOST;
useItemCost = 5;
reequipCost = 5;
level = 1;
totalExperience = 1;
availableSkillIncreases = 0;
skillLevels.clear();
alignments.clear();
recalculateLevelExperience();
baseTraits.iconID = TileManager.CHAR_HERO;
baseTraits.maxAP = 10;
baseTraits.maxHP = 25;
baseTraits.moveCost = 6;
baseTraits.attackCost = DEFAULT_PLAYER_ATTACKCOST;
baseTraits.attackChance = 60;
baseTraits.criticalSkill = 0;
baseTraits.criticalMultiplier = 1;
baseTraits.damagePotential.set(1, 1);
baseTraits.blockChance = 0;
baseTraits.damageResistance = 0;
baseTraits.useItemCost = 5;
baseTraits.reequipCost = 5;
this.name = name;
this.level = 1;
this.totalExperience = 1;
this.inventory.clear();
this.questProgress.clear();
this.skillLevels.clear();
this.availableSkillIncreases = 0;
this.alignments.clear();
this.ap.set(baseTraits.maxAP, baseTraits.maxAP);
this.health.set(baseTraits.maxHP, baseTraits.maxHP);
this.conditions.clear();
Loot startItems = new Loot();
dropLists.getDropList(DropListCollection.DROPLIST_STARTITEMS).createRandomLoot(startItems, this);
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);
ActorStatsController.recalculatePlayerStats(this);
}
public boolean hasExactQuestProgress(QuestProgress progress) { return hasExactQuestProgress(progress.questID, progress.progress); }
@@ -144,7 +195,7 @@ public final class Player extends Actor {
}
public void addSkillLevel(int skillID) {
skillLevels.put(skillID, skillLevels.get(skillID) + 1);
ActorStatsController.recalculatePlayerCombatTraits(this);
ActorStatsController.recalculatePlayerStats(this);
}
public boolean nextLevelAddsNewSkillpoint() {
return thisLevelAddsNewSkillpoint(level + 1);
@@ -152,11 +203,6 @@ public final class Player extends Actor {
public static boolean thisLevelAddsNewSkillpoint(int level) {
return ((level - Constants.FIRST_SKILL_POINT_IS_GIVEN_AT_LEVEL) % Constants.NEW_SKILL_POINT_EVERY_N_LEVELS == 0);
}
public static int getExpectedNumberOfSkillpointsForLevel(int level) {
level -= Constants.FIRST_SKILL_POINT_IS_GIVEN_AT_LEVEL;
if (level < 0) return 0;
return 1 + (int) FloatMath.floor((float) level / Constants.NEW_SKILL_POINT_EVERY_N_LEVELS);
}
public boolean hasAvailableSkillpoints() {
return availableSkillIncreases > 0;
}
@@ -171,68 +217,108 @@ 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 Player.STAT_ACTOR_MAX_HP: return baseTraits.maxHP;
case Player.STAT_ACTOR_MAX_AP: return baseTraits.maxAP;
case Player.STAT_ACTOR_MOVECOST: return baseTraits.moveCost;
}
return 0;
}
public int getCombatStats(int statID) {
switch (statID) {
case Player.STAT_COMBAT_ATTACK_COST: return baseTraits.attackCost;
case Player.STAT_COMBAT_ATTACK_CHANCE: return baseTraits.attackChance;
case Player.STAT_COMBAT_CRITICAL_SKILL: return baseTraits.criticalSkill;
case Player.STAT_COMBAT_CRITICAL_MULTIPLIER: return (int) FloatMath.floor(baseTraits.criticalMultiplier);
case Player.STAT_COMBAT_DAMAGE_POTENTIAL_MIN: return baseTraits.damagePotential.current;
case Player.STAT_COMBAT_DAMAGE_POTENTIAL_MAX: return baseTraits.damagePotential.max;
case Player.STAT_COMBAT_BLOCK_CHANCE: return baseTraits.blockChance;
case Player.STAT_COMBAT_DAMAGE_RESISTANCE: return baseTraits.damageResistance;
}
return 0;
}
// ====== PARCELABLE ===================================================================
public static Player readFromParcel(DataInputStream src, WorldContext world, int fileversion) throws IOException {
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, null);
this.lastPosition = new Coord(src, fileversion);
this.nextPosition = new Coord(src, fileversion);
this.level = src.readInt();
this.totalExperience = src.readInt();
this.levelExperience = new Range();
this.recalculateLevelExperience();
this.inventory = new Inventory(src, world, fileversion);
this();
if (fileversion <= 13) {
final int size1 = src.readInt();
for(int i = 0; i < size1; ++i) {
String keyName = src.readUTF();
if ("mikhail_visited".equals(keyName)) addQuestProgress(new QuestProgress("andor", 1));
else if ("qmikhail_bread_complete".equals(keyName)) addQuestProgress(new QuestProgress("mikhail_bread", 100));
else if ("qmikhail_bread".equals(keyName)) addQuestProgress(new QuestProgress("mikhail_bread", 10));
else if ("qmikhail_rats_complete".equals(keyName)) addQuestProgress(new QuestProgress("mikhail_rats", 100));
else if ("qmikhail_rats".equals(keyName)) addQuestProgress(new QuestProgress("mikhail_rats", 10));
else if ("oromir".equals(keyName)) addQuestProgress(new QuestProgress("leta", 20));
else if ("qleta_complete".equals(keyName)) addQuestProgress(new QuestProgress("leta", 100));
else if ("qodair".equals(keyName)) addQuestProgress(new QuestProgress("odair", 10));
else if ("qodair_complete".equals(keyName)) addQuestProgress(new QuestProgress("odair", 100));
else if ("qleonid_bonemeal".equals(keyName)) {
addQuestProgress(new QuestProgress("bonemeal", 10));
addQuestProgress(new QuestProgress("bonemeal", 20));
}
else if ("qtharal_complete".equals(keyName)) addQuestProgress(new QuestProgress("bonemeal", 30));
else if ("qthoronir_complete".equals(keyName)) addQuestProgress(new QuestProgress("bonemeal", 100));
else if ("qleonid_andor".equals(keyName)) addQuestProgress(new QuestProgress("andor", 10));
else if ("qgruil_andor".equals(keyName)) addQuestProgress(new QuestProgress("andor", 20));
else if ("qgruil_andor_complete".equals(keyName)) addQuestProgress(new QuestProgress("andor", 30));
else if ("qleonid_crossglen".equals(keyName)) addQuestProgress(new QuestProgress("crossglen", 1));
else if ("qjan".equals(keyName)) addQuestProgress(new QuestProgress("jan", 10));
else if ("qjan_complete".equals(keyName)) addQuestProgress(new QuestProgress("jan", 100));
else if ("qbucus_thieves".equals(keyName)) addQuestProgress(new QuestProgress("andor", 40));
else if ("qfallhaven_derelict".equals(keyName)) addQuestProgress(new QuestProgress("andor", 50));
else if ("qfallhaven_drunk".equals(keyName)) addQuestProgress(new QuestProgress("fallhavendrunk", 10));
else if ("qfallhaven_drunk_complete".equals(keyName)) addQuestProgress(new QuestProgress("fallhavendrunk", 100));
else if ("qnocmar_unnmir".equals(keyName)) addQuestProgress(new QuestProgress("nocmar", 10));
else if ("qnocmar".equals(keyName)) addQuestProgress(new QuestProgress("nocmar", 20));
else if ("qnocmar_complete".equals(keyName)) addQuestProgress(new QuestProgress("nocmar", 200));
else if ("qfallhaven_tavern_room2".equals(keyName)) addQuestProgress(new QuestProgress("fallhaventavern", 10));
else if ("qarcir".equals(keyName)) addQuestProgress(new QuestProgress("arcir", 10));
else if ("qfallhaven_oldman".equals(keyName)) addQuestProgress(new QuestProgress("calomyran", 10));
else if ("qcalomyran_tornpage".equals(keyName)) addQuestProgress(new QuestProgress("calomyran", 20));
else if ("qfallhaven_oldman_complete".equals(keyName)) addQuestProgress(new QuestProgress("calomyran", 100));
else if ("qbucus".equals(keyName)) addQuestProgress(new QuestProgress("bucus", 10));
else if ("qthoronir_catacombs".equals(keyName)) addQuestProgress(new QuestProgress("bucus", 20));
else if ("qathamyr_complete".equals(keyName)) addQuestProgress(new QuestProgress("bucus", 40));
else if ("qfallhaven_church".equals(keyName)) addQuestProgress(new QuestProgress("bucus", 50));
else if ("qbucus_complete".equals(keyName)) addQuestProgress(new QuestProgress("bucus", 100));
if (fileversion <= 33) LegacySavegameFormatReaderForPlayer.readCombatTraitsPreV034(src, fileversion);
this.baseTraits.iconID = src.readInt();
if (fileversion <= 33) /*this.tileSize = */new Size(src, fileversion);
this.baseTraits.maxAP = src.readInt();
this.baseTraits.maxHP = src.readInt();
this.name = src.readUTF();
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 numConditions = src.readInt();
for(int i = 0; i < numConditions; ++i) {
this.conditions.add(new ActorCondition(src, world, fileversion));
}
}
this.useItemCost = src.readInt();
this.reequipCost = src.readInt();
final int size2 = src.readInt();
for(int i = 0; i < size2; ++i) {
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.baseTraits.useItemCost = src.readInt();
this.baseTraits.reequipCost = src.readInt();
final int numSkills = src.readInt();
for(int i = 0; i < numSkills; ++i) {
if (fileversion <= 21) {
this.skillLevels.put(i, src.readInt());
} else {
@@ -242,69 +328,64 @@ public final class Player extends Actor {
}
this.spawnMap = src.readUTF();
this.spawnPlace = src.readUTF();
if (fileversion <= 12) {
useItemCost = 5;
health.max += 5;
health.current += 5;
actorTraits.maxHP += 5;
}
if (fileversion <= 13) return;
final int numquests = src.readInt();
for(int i = 0; i < numquests; ++i) {
final String questID = src.readUTF();
questProgress.put(questID, new HashSet<Integer>());
final int numprogress = src.readInt();
for(int j = 0; j < numprogress; ++j) {
int progress = src.readInt();
questProgress.get(questID).add(progress);
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);
}
}
}
if (fileversion <= 21) {
int assignedSkillpoints = 0;
for (int i = 0; i < skillLevels.size(); ++i) assignedSkillpoints += skillLevels.valueAt(i);
this.availableSkillIncreases = getExpectedNumberOfSkillpointsForLevel(this.level) - assignedSkillpoints;
} else {
this.availableSkillIncreases = 0;
if (fileversion > 21) {
this.availableSkillIncreases = src.readInt();
}
if (fileversion <= 21) {
if (hasExactQuestProgress("prim_hunt", 240)) addQuestProgress(new QuestProgress("bwm_agent", 250));
if (hasExactQuestProgress("bwm_agent", 240)) addQuestProgress(new QuestProgress("prim_hunt", 250));
}
if (fileversion >= 26) {
final int size3 = src.readInt();
for(int i = 0; i < size3; ++i) {
final int numAlignments = src.readInt();
for(int i = 0; i < numAlignments; ++i) {
final String faction = src.readUTF();
final int alignment = src.readInt();
alignments.put(faction, alignment);
this.alignments.put(faction, alignment);
}
}
if (fileversion <= 27) {
ItemController.correctActorConditionsFromItemsPre0611b1(this, "bless", world, "elytharan_redeemer");
ItemController.correctActorConditionsFromItemsPre0611b1(this, "blackwater_misery", world, "bwm_dagger");
ItemController.correctActorConditionsFromItemsPre0611b1(this, "regen", world, "ring_shadow0");
}
if (fileversion <= 30) {
this.actorTraits.baseCombatTraits.attackCost = DEFAULT_PLAYER_ATTACKCOST;
}
}
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
super.writeToParcel(dest, flags);
dest.writeInt(baseTraits.iconID);
dest.writeInt(baseTraits.maxAP);
dest.writeInt(baseTraits.maxHP);
dest.writeUTF(name);
dest.writeInt(moveCost); // TODO: Should we really write this?
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);
dest.writeInt(totalExperience);
inventory.writeToParcel(dest, flags);
dest.writeInt(useItemCost);
dest.writeInt(reequipCost);
dest.writeInt(baseTraits.useItemCost);
dest.writeInt(baseTraits.reequipCost);
dest.writeInt(skillLevels.size());
for (int i = 0; i < skillLevels.size(); ++i) {
dest.writeInt(skillLevels.keyAt(i));

View File

@@ -5,6 +5,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForItemContainer;
public final class Inventory extends ItemContainer {
@@ -26,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);
@@ -55,26 +63,32 @@ 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) this.gold += ItemContainer.SavegameUpdate.refundUpgradedItems(this);
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;
}
}
if (fileversion < 19) return;
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;
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());
}
}
}
}

View File

@@ -5,9 +5,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.util.L;
public class ItemContainer {
public final ArrayList<ItemEntry> items = new ArrayList<ItemEntry>();
@@ -120,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);
@@ -133,28 +136,4 @@ public class ItemContainer {
e.writeToParcel(dest, flags);
}
}
public static class SavegameUpdate {
public static int refundUpgradedItems(ItemContainer container) {
int removedCost = 0;
for (ItemEntry e : container.items) {
if (e.quantity >= 2 && isRefundableItem(e.itemType)) {
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("INFO: Refunding " + (e.quantity-1) + " items of type \"" + e.itemType.id + "\" for a total of " + ((e.quantity-1) * e.itemType.fixedBaseMarketCost) + "gc.");
}
removedCost += (e.quantity-1) * e.itemType.fixedBaseMarketCost;
e.quantity = 1;
}
}
return removedCost;
}
private static boolean isRefundableItem(ItemType itemType) {
if (itemType.hasManualPrice) return false;
if (itemType.isQuestItem()) return false;
if (itemType.displayType == ItemType.DISPLAYTYPE_EXTRAORDINARY) return false;
if (itemType.displayType == ItemType.DISPLAYTYPE_LEGENDARY) return false;
return itemType.baseMarketCost > itemType.fixedBaseMarketCost;
}
}
}

View File

@@ -2,15 +2,20 @@ package com.gpl.rpg.AndorsTrail.model.item;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.traits.StatsModifierTraits;
import com.gpl.rpg.AndorsTrail.util.ConstRange;
public final class ItemTraits_OnUse extends StatsModifierTraits {
public final class ItemTraits_OnUse {
public final StatsModifierTraits changedStats;
public final ActorConditionEffect[] addedConditions_source;
public final ActorConditionEffect[] addedConditions_target;
public ItemTraits_OnUse(int visualEffectID, ConstRange currentHPBoost, ConstRange currentAPBoost, ActorConditionEffect[] addedConditions_source, ActorConditionEffect[] addedConditions_target) {
super(visualEffectID, currentHPBoost, currentAPBoost);
public ItemTraits_OnUse(StatsModifierTraits changedStats, ActorConditionEffect[] addedConditions_source, ActorConditionEffect[] addedConditions_target) {
this.changedStats = changedStats;
this.addedConditions_source = addedConditions_source;
this.addedConditions_target = addedConditions_target;
}
public int calculateCost() {
final int costStats = changedStats == null ? 0 : changedStats.calculateCost();
return costStats;
}
}

View File

@@ -71,7 +71,7 @@ public final class ItemType {
public String getName(Player p) {
if (!hasPersonalizedName) return name;
else return name.replace(Constants.PLACEHOLDER_PLAYERNAME, p.actorTraits.name);
else return name.replace(Constants.PLACEHOLDER_PLAYERNAME, p.getName());
}
public int getOverlayTileID() {

View File

@@ -5,6 +5,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForItemContainer;
import com.gpl.rpg.AndorsTrail.util.Coord;
public final class Loot {
@@ -51,7 +52,7 @@ public final class Loot {
this.exp = src.readInt();
this.gold = src.readInt();
this.items = new ItemContainer(src, world, fileversion);
if (fileversion < 23) this.gold += ItemContainer.SavegameUpdate.refundUpgradedItems(this.items);
if (fileversion < 23) LegacySavegameFormatReaderForItemContainer.refundUpgradedItems(this);
this.position = new Coord(src, fileversion);
if (fileversion <= 15) {

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

@@ -7,6 +7,7 @@ import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionTypeCollection;
import com.gpl.rpg.AndorsTrail.model.ability.traits.AbilityModifierTraits;
import com.gpl.rpg.AndorsTrail.model.ability.traits.StatsModifierTraits;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnEquip;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
import com.gpl.rpg.AndorsTrail.resource.ResourceFileTokenizer;
@@ -49,8 +50,8 @@ public final class ItemTraitsParser {
boolean hasEffect = ResourceParserUtils.parseBoolean(parts[startIndex], false);
if (!hasEffect) return null;
ConstRange boostCurrentHP = ResourceParserUtils.parseRange(parts[startIndex + 1], parts[startIndex + 2]);
ConstRange boostCurrentAP = ResourceParserUtils.parseRange(parts[startIndex + 3], parts[startIndex + 4]);
ConstRange boostCurrentHP = ResourceParserUtils.parseConstRange(parts[startIndex + 1], parts[startIndex + 2]);
ConstRange boostCurrentAP = ResourceParserUtils.parseConstRange(parts[startIndex + 3], parts[startIndex + 4]);
final ArrayList<ActorConditionEffect> addedConditions_source = new ArrayList<ActorConditionEffect>();
final ArrayList<ActorConditionEffect> addedConditions_target = new ArrayList<ActorConditionEffect>();
tokenize4Fields.tokenizeArray(parts[startIndex + 5], addedConditions_source, actorConditionEffectParser_withDuration);
@@ -68,9 +69,11 @@ public final class ItemTraitsParser {
return null;
} else {
return new ItemTraits_OnUse(
ItemTraits_OnUse.VISUAL_EFFECT_NONE
,boostCurrentHP
,boostCurrentAP
new StatsModifierTraits(
StatsModifierTraits.VISUAL_EFFECT_NONE
,boostCurrentHP
,boostCurrentAP
)
,listToArray(addedConditions_source)
,listToArray(addedConditions_target)
);

View File

@@ -3,13 +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.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;
@@ -29,43 +29,70 @@ public final class MonsterTypeParser extends ResourceParserFor<MonsterType> {
@Override
public Pair<String, MonsterType> parseRow(String[] parts) {
final String monsterTypeId = parts[0];
final int maxHP = ResourceParserUtils.parseInt(parts[8], 1);
final int maxAP = ResourceParserUtils.parseInt(parts[9], 10);
final CombatTraits combatTraits = ResourceParserUtils.parseCombatTraits(parts, 11);
final ItemTraits_OnUse hitEffect = itemTraitsParser.parseItemTraits_OnUse(parts, 21, true);
final int exp = getExpectedMonsterExperience(combatTraits, hitEffect, maxHP, maxAP);
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(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
, ResourceParserUtils.parseImageID(tileLoader, parts[1])
, ResourceParserUtils.parseSize(parts[4], size1x1) //TODO: This could be loaded from the tileset size instead.
, maxHP // HP
, maxAP // AP
, ResourceParserUtils.parseInt(parts[10], 10) // MoveCost
, combatTraits
, hitEffect
, parts[3] // SpawnGroup
, exp // Exp
, droplists.getDropList(parts[19]) // Droplist
, ResourceParserUtils.parseNullableString(parts[20]) // PhraseID
, ResourceParserUtils.parseBoolean(parts[6], false) // isUnique
, 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.
, 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

@@ -1,12 +1,12 @@
package com.gpl.rpg.AndorsTrail.resource.parsers;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.model.CombatTraits;
import com.gpl.rpg.AndorsTrail.model.ability.traits.AbilityModifierTraits;
import com.gpl.rpg.AndorsTrail.model.ability.traits.StatsModifierTraits;
import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
import com.gpl.rpg.AndorsTrail.util.ConstRange;
import com.gpl.rpg.AndorsTrail.util.L;
import com.gpl.rpg.AndorsTrail.util.Range;
import com.gpl.rpg.AndorsTrail.util.Size;
public final class ResourceParserUtils {
@@ -15,7 +15,27 @@ public final class ResourceParserUtils {
String[] parts = s.split(":");
return tileLoader.prepareTileID(parts[0], Integer.parseInt(parts[1]));
}
public static ConstRange parseRange(String min, String max) {
public static Range parseRange(String min, String max) {
if ( (max == null || max.length() <= 0)
&& (min == null || min.length() <= 0) ) {
return null;
}
if (max == null || max.length() <= 0) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
L.log("OPTIMIZE: Unable to parse range with min=" + min + " because max was empty.");
}
return null;
}
if (min == null || min.length() <= 0) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
L.log("OPTIMIZE: Unable to parse range with max=" + max + " because min was empty.");
}
return null;
}
return new Range(Integer.parseInt(max), Integer.parseInt(min));
}
public static ConstRange parseConstRange(String min, String max) {
if ( (max == null || max.length() <= 0)
&& (min == null || min.length() <= 0) ) {
return null;
@@ -45,35 +65,6 @@ public final class ResourceParserUtils {
return new Size(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
}
public static CombatTraits parseCombatTraits(String[] parts, int startIndex) {
String attackCost = parts[startIndex];
String attackChance = parts[startIndex + 1];
String criticalSkill = parts[startIndex + 2];
String criticalMultiplier = parts[startIndex + 3];
ConstRange attackDamage = parseRange(parts[startIndex + 4], parts[startIndex + 5]);
String blockChance = parts[startIndex + 6];
String damageResistance = parts[startIndex + 7];
if ( attackCost.length() <= 0
&& attackChance.length() <= 0
&& criticalSkill.length() <= 0
&& criticalMultiplier.length() <= 0
&& attackDamage == null
&& blockChance.length() <= 0
&& damageResistance.length() <= 0
) {
return null;
} else {
CombatTraits result = new CombatTraits();
result.attackCost = parseInt(attackCost, 0);
result.attackChance = parseInt(attackChance, 0);
result.criticalSkill = parseInt(criticalSkill, 0);
result.criticalMultiplier = parseFloat(criticalMultiplier, 0);
if (attackDamage != null) result.damagePotential.set(attackDamage);
result.blockChance = parseInt(blockChance, 0);
result.damageResistance = parseInt(damageResistance, 0);
return result;
}
}
public static String parseNullableString(String s) {
if (s == null || s.length() <= 0) return null;
return s;
@@ -102,8 +93,8 @@ public final class ResourceParserUtils {
if (!hasEffect) return null;
String visualEffectID = parts[startIndex + 1];
ConstRange boostCurrentHP = parseRange(parts[startIndex + 2], parts[startIndex + 3]);
ConstRange boostCurrentAP = parseRange(parts[startIndex + 4], parts[startIndex + 5]);
ConstRange boostCurrentHP = parseConstRange(parts[startIndex + 2], parts[startIndex + 3]);
ConstRange boostCurrentAP = parseConstRange(parts[startIndex + 4], parts[startIndex + 5]);
if ( boostCurrentHP == null
&& boostCurrentAP == null
) {
@@ -174,7 +165,7 @@ public final class ResourceParserUtils {
else if (min.equals("1") && max.equals("1")) return one;
else if (min.equals("5") && max.equals("5")) return five;
else if (min.equals("10") && max.equals("10")) return ten;
return parseRange(min, max);
return parseConstRange(min, max);
}
public static final ConstRange always = one;

View File

@@ -125,8 +125,8 @@ public final class TileManager {
public void setImageViewTile(TextView textView, Monster monster) { setImageViewTileForMonster(textView, monster.actorTraits.iconID); }
public void setImageViewTile(TextView textView, Player player) { setImageViewTileForPlayer(textView, player.actorTraits.iconID); }
public void setImageViewTile(TextView textView, Monster monster) { setImageViewTileForMonster(textView, monster.iconID); }
public void setImageViewTile(TextView textView, Player player) { setImageViewTileForPlayer(textView, player.iconID); }
public void setImageViewTileForMonster(TextView textView, int iconID) { setImageViewTile(textView, currentMapTiles.getBitmap(iconID)); }
public void setImageViewTileForPlayer(TextView textView, int iconID) { setImageViewTile(textView, preloadedTiles.getBitmap(iconID)); }
public void setImageViewTile(TextView textView, ActorConditionType conditionType) { setImageViewTile(textView, preloadedTiles.getBitmap(conditionType.iconID)); }
@@ -155,8 +155,8 @@ public final class TileManager {
}
}
public void setImageViewTile(ImageView imageView, Monster monster) { setImageViewTileForMonster(imageView, monster.actorTraits.iconID); }
public void setImageViewTile(ImageView imageView, Player player) { setImageViewTileForPlayer(imageView, player.actorTraits.iconID); }
public void setImageViewTile(ImageView imageView, Monster monster) { setImageViewTileForMonster(imageView, monster.iconID); }
public void setImageViewTile(ImageView imageView, Player player) { setImageViewTileForPlayer(imageView, player.iconID); }
public void setImageViewTileForMonster(ImageView imageView, int iconID) { imageView.setImageBitmap(currentMapTiles.getBitmap(iconID)); }
public void setImageViewTileForPlayer(ImageView imageView, int iconID) { imageView.setImageBitmap(preloadedTiles.getBitmap(iconID)); }
public void setImageViewTile(ImageView imageView, ActorConditionType conditionType) { imageView.setImageBitmap(preloadedTiles.getBitmap(conditionType.iconID)); }

View File

@@ -0,0 +1,40 @@
package com.gpl.rpg.AndorsTrail.savegames;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.model.item.Inventory;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry;
import com.gpl.rpg.AndorsTrail.model.item.Loot;
import com.gpl.rpg.AndorsTrail.util.L;
public final class LegacySavegameFormatReaderForItemContainer {
public static void refundUpgradedItems(Inventory inventory) {
inventory.gold += getRefundForUpgradedItems(inventory);
}
public static void refundUpgradedItems(Loot loot) {
loot.gold += getRefundForUpgradedItems(loot.items);
}
private static int getRefundForUpgradedItems(ItemContainer container) {
int removedCost = 0;
for (ItemEntry e : container.items) {
if (e.quantity >= 2 && isRefundableItem(e.itemType)) {
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("INFO: Refunding " + (e.quantity-1) + " items of type \"" + e.itemType.id + "\" for a total of " + ((e.quantity-1) * e.itemType.fixedBaseMarketCost) + "gc.");
}
removedCost += (e.quantity-1) * e.itemType.fixedBaseMarketCost;
e.quantity = 1;
}
}
return removedCost;
}
private static boolean isRefundableItem(ItemType itemType) {
if (itemType.hasManualPrice) return false;
if (itemType.isQuestItem()) return false;
if (itemType.displayType == ItemType.DISPLAYTYPE_EXTRAORDINARY) return false;
if (itemType.displayType == ItemType.DISPLAYTYPE_LEGENDARY) return false;
return itemType.baseMarketCost > itemType.fixedBaseMarketCost;
}
}

View File

@@ -0,0 +1,21 @@
package com.gpl.rpg.AndorsTrail.savegames;
import java.io.DataInputStream;
import java.io.IOException;
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
import com.gpl.rpg.AndorsTrail.util.Coord;
public class LegacySavegameFormatReaderForMonster {
public static Monster readFromParcel_pre_v25(DataInputStream src, int fileversion, MonsterType monsterType) throws IOException {
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) {
if (src.readBoolean()) m.forceAggressive();
}
return m;
}
}

View File

@@ -0,0 +1,143 @@
package com.gpl.rpg.AndorsTrail.savegames;
import java.io.DataInputStream;
import java.io.IOException;
import android.util.FloatMath;
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.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.SkillInfo;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
import com.gpl.rpg.AndorsTrail.util.Range;
public final class LegacySavegameFormatReaderForPlayer {
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();
if ("mikhail_visited".equals(keyName)) addQuestProgress(player, "andor", 1);
else if ("qmikhail_bread_complete".equals(keyName)) addQuestProgress(player, "mikhail_bread", 100);
else if ("qmikhail_bread".equals(keyName)) addQuestProgress(player, "mikhail_bread", 10);
else if ("qmikhail_rats_complete".equals(keyName)) addQuestProgress(player, "mikhail_rats", 100);
else if ("qmikhail_rats".equals(keyName)) addQuestProgress(player, "mikhail_rats", 10);
else if ("oromir".equals(keyName)) addQuestProgress(player, "leta", 20);
else if ("qleta_complete".equals(keyName)) addQuestProgress(player, "leta", 100);
else if ("qodair".equals(keyName)) addQuestProgress(player, "odair", 10);
else if ("qodair_complete".equals(keyName)) addQuestProgress(player, "odair", 100);
else if ("qleonid_bonemeal".equals(keyName)) {
addQuestProgress(player, "bonemeal", 10);
addQuestProgress(player, "bonemeal", 20);
}
else if ("qtharal_complete".equals(keyName)) addQuestProgress(player, "bonemeal", 30);
else if ("qthoronir_complete".equals(keyName)) addQuestProgress(player, "bonemeal", 100);
else if ("qleonid_andor".equals(keyName)) addQuestProgress(player, "andor", 10);
else if ("qgruil_andor".equals(keyName)) addQuestProgress(player, "andor", 20);
else if ("qgruil_andor_complete".equals(keyName)) addQuestProgress(player, "andor", 30);
else if ("qleonid_crossglen".equals(keyName)) addQuestProgress(player, "crossglen", 1);
else if ("qjan".equals(keyName)) addQuestProgress(player, "jan", 10);
else if ("qjan_complete".equals(keyName)) addQuestProgress(player, "jan", 100);
else if ("qbucus_thieves".equals(keyName)) addQuestProgress(player, "andor", 40);
else if ("qfallhaven_derelict".equals(keyName)) addQuestProgress(player, "andor", 50);
else if ("qfallhaven_drunk".equals(keyName)) addQuestProgress(player, "fallhavendrunk", 10);
else if ("qfallhaven_drunk_complete".equals(keyName)) addQuestProgress(player, "fallhavendrunk", 100);
else if ("qnocmar_unnmir".equals(keyName)) addQuestProgress(player, "nocmar", 10);
else if ("qnocmar".equals(keyName)) addQuestProgress(player, "nocmar", 20);
else if ("qnocmar_complete".equals(keyName)) addQuestProgress(player, "nocmar", 200);
else if ("qfallhaven_tavern_room2".equals(keyName)) addQuestProgress(player, "fallhaventavern", 10);
else if ("qarcir".equals(keyName)) addQuestProgress(player, "arcir", 10);
else if ("qfallhaven_oldman".equals(keyName)) addQuestProgress(player, "calomyran", 10);
else if ("qcalomyran_tornpage".equals(keyName)) addQuestProgress(player, "calomyran", 20);
else if ("qfallhaven_oldman_complete".equals(keyName)) addQuestProgress(player, "calomyran", 100);
else if ("qbucus".equals(keyName)) addQuestProgress(player, "bucus", 10);
else if ("qthoronir_catacombs".equals(keyName)) addQuestProgress(player, "bucus", 20);
else if ("qathamyr_complete".equals(keyName)) addQuestProgress(player, "bucus", 40);
else if ("qfallhaven_church".equals(keyName)) addQuestProgress(player, "bucus", 50);
else if ("qbucus_complete".equals(keyName)) addQuestProgress(player, "bucus", 100);
}
}
private static void addQuestProgress(Player player, String questID, int progress) {
player.addQuestProgress(new QuestProgress(questID, progress));
}
public static void upgradeSavegame(Player player, WorldContext world, int fileversion) {
if (fileversion <= 12) {
player.useItemCost = 5;
player.health.max += 5;
player.health.current += 5;
player.baseTraits.maxHP += 5;
}
if (fileversion <= 21) {
int assignedSkillpoints = 0;
for(SkillInfo skill : world.skills.getAllSkills()) {
assignedSkillpoints += player.getSkillLevel(skill.id);
}
player.availableSkillIncreases = getExpectedNumberOfSkillpointsForLevel(player.getLevel()) - assignedSkillpoints;
}
if (fileversion <= 21) {
if (player.hasExactQuestProgress("prim_hunt", 240)) player.addQuestProgress(new QuestProgress("bwm_agent", 250));
if (player.hasExactQuestProgress("bwm_agent", 240)) player.addQuestProgress(new QuestProgress("prim_hunt", 250));
}
if (fileversion <= 27) {
correctActorConditionsFromItemsPre0611b1(player, "bless", world, "elytharan_redeemer");
correctActorConditionsFromItemsPre0611b1(player, "blackwater_misery", world, "bwm_dagger");
correctActorConditionsFromItemsPre0611b1(player, "regen", world, "ring_shadow0");
}
if (fileversion <= 30) {
player.baseTraits.attackCost = Player.DEFAULT_PLAYER_ATTACKCOST;
}
}
public static int getExpectedNumberOfSkillpointsForLevel(int level) {
level -= Constants.FIRST_SKILL_POINT_IS_GIVEN_AT_LEVEL;
if (level < 0) return 0;
return 1 + (int) FloatMath.floor((float) level / Constants.NEW_SKILL_POINT_EVERY_N_LEVELS);
}
private static void correctActorConditionsFromItemsPre0611b1(Player player, String conditionTypeID, WorldContext world, String itemTypeIDWithCondition) {
if (!player.hasCondition(conditionTypeID)) return;
boolean hasItemWithCondition = false;
for (ItemType t : player.inventory.wear) {
if (t == null) continue;
if (t.effects_equip == null) continue;
if (t.effects_equip.addedConditions == null) continue;
for(ActorConditionEffect e : t.effects_equip.addedConditions) {
if (!e.conditionType.conditionTypeID.equals(conditionTypeID)) continue;
hasItemWithCondition = true;
break;
}
}
if (hasItemWithCondition) return;
ActorStatsController.removeConditionsFromUnequippedItem(player, world.itemTypes.getItemType(itemTypeIDWithCondition));
}
public static void readCombatTraitsPreV034(DataInputStream src, int fileversion) throws IOException {
if (fileversion >= 25) {
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,27 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public final class BaseTraitsInfoView extends TraitsInfoView {
private final TextView basetraitsinfo_max_hp;
private final TextView basetraitsinfo_max_ap;
public BaseTraitsInfoView(Context context, AttributeSet attr) {
super(context, attr, R.layout.basetraitsinfoview);
basetraitsinfo_max_hp = (TextView) findViewById(R.id.basetraitsinfo_max_hp);
basetraitsinfo_max_ap = (TextView) findViewById(R.id.basetraitsinfo_max_ap);
}
public void update(ActorTraits traits) {
super.update(traits);
basetraitsinfo_max_hp.setText(Integer.toString(traits.maxHP));
basetraitsinfo_max_ap.setText(Integer.toString(traits.maxAP));
}
}

View File

@@ -115,7 +115,7 @@ public final class CombatView extends RelativeLayout {
if (currentActiveMonster != null) {
actionBar.setVisibility(View.INVISIBLE);
monsterActionText.setVisibility(View.VISIBLE);
monsterActionText.setText(res.getString(R.string.combat_monsteraction, currentActiveMonster.actorTraits.name));
monsterActionText.setText(res.getString(R.string.combat_monsteraction, currentActiveMonster.getName()));
} else {
actionBar.setVisibility(View.VISIBLE);
monsterActionText.setVisibility(View.GONE);
@@ -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.actorTraits.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

@@ -48,7 +48,7 @@ public final class ItemEffectsView_OnUse extends LinearLayout {
if (t.addedConditions_source != null) sourceEffects.addAll(Arrays.asList(t.addedConditions_source));
if (t.addedConditions_target != null) targetEffects.addAll(Arrays.asList(t.addedConditions_target));
describeStatsModifierTraits(t, context, res, itemeffect_onuse_list);
describeStatsModifierTraits(t.changedStats, context, res, itemeffect_onuse_list);
}
}
itemeffect_onuse_conditions_source.update(sourceEffects);

View File

@@ -278,10 +278,10 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac
}
}
drawFromMapPosition(canvas, area, playerPosition, model.player.actorTraits.iconID);
drawFromMapPosition(canvas, area, playerPosition, model.player.iconID);
for (MonsterSpawnArea a : currentMap.spawnAreas) {
for (Monster m : a.monsters) {
drawFromMapPosition(canvas, area, m.rectPosition, m.actorTraits.iconID);
drawFromMapPosition(canvas, area, m.rectPosition, m.iconID);
}
}

View File

@@ -56,7 +56,7 @@ public final class StatusView extends RelativeLayout {
expBar.init(R.drawable.ui_progress_exp, R.string.status_exp);
levelupDrawable = new LayerDrawable(new Drawable[] {
new BitmapDrawable(world.tileManager.preloadedTiles.getBitmap(player.actorTraits.iconID))
new BitmapDrawable(world.tileManager.preloadedTiles.getBitmap(player.iconID))
,new BitmapDrawable(world.tileManager.preloadedTiles.getBitmap(TileManager.iconID_moveselect))
});

View File

@@ -1,112 +1,129 @@
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;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
public class TraitsInfoView extends TableLayout {
private final TableRow traitsinfo_attack_row1;
private final TableRow traitsinfo_attack_row2;
private final TableRow traitsinfo_attack_row3;
private final TableRow traitsinfo_critical_row1;
private final TableRow traitsinfo_critical_row2;
private final TableRow traitsinfo_critical_row3;
private final TableRow traitsinfo_defense_row1;
private final TableRow traitsinfo_defense_row2;
private final TextView traitsinfo_attack_cost;
private final TextView traitsinfo_attack_chance;
private final TextView traitsinfo_attack_damage;
private final TextView traitsinfo_criticalhit_skill;
private final TextView traitsinfo_criticalhit_multiplier;
private final TextView traitsinfo_criticalhit_effectivechance;
private final TextView traitsinfo_defense_chance;
private final TextView traitsinfo_defense_damageresist;
public final class TraitsInfoView {
public TraitsInfoView(Context context, AttributeSet attr) {
this(context, attr, R.layout.traitsinfoview);
public static void update(ViewGroup group, Actor actor) {
TableLayout actorinfo_stats_table = (TableLayout) group.findViewById(R.id.actorinfo_stats_table);
updateTraitsTable(
actorinfo_stats_table
,actor.getMoveCost()
,actor.getAttackCost()
,actor.getAttackChance()
,actor.getDamagePotential()
,actor.getCriticalSkill()
,actor.getCriticalMultiplier()
,actor.getBlockChance()
,actor.getDamageResistance()
,actor.isImmuneToCriticalHits());
TextView actorinfo_currentconditions_title = (TextView) group.findViewById(R.id.actorinfo_currentconditions_title);
ActorConditionList actorinfo_currentconditions = (ActorConditionList) group.findViewById(R.id.actorinfo_currentconditions);
if (actor.conditions.isEmpty()) {
actorinfo_currentconditions_title.setVisibility(View.GONE);
actorinfo_currentconditions.setVisibility(View.GONE);
} else {
actorinfo_currentconditions_title.setVisibility(View.VISIBLE);
actorinfo_currentconditions.setVisibility(View.VISIBLE);
actorinfo_currentconditions.update(actor.conditions);
}
}
public TraitsInfoView(Context context, AttributeSet attr, int layoutResourceID) {
super(context, attr);
setFocusable(false);
inflate(context, layoutResourceID, this);
traitsinfo_attack_row1 = (TableRow) findViewById(R.id.traitsinfo_attack_row1);
traitsinfo_attack_row2 = (TableRow) findViewById(R.id.traitsinfo_attack_row2);
traitsinfo_attack_row3 = (TableRow) findViewById(R.id.traitsinfo_attack_row3);
traitsinfo_critical_row1 = (TableRow) findViewById(R.id.traitsinfo_critical_row1);
traitsinfo_critical_row2 = (TableRow) findViewById(R.id.traitsinfo_critical_row2);
traitsinfo_critical_row3 = (TableRow) findViewById(R.id.traitsinfo_critical_row3);
traitsinfo_defense_row1 = (TableRow) findViewById(R.id.traitsinfo_defense_row1);
traitsinfo_defense_row2 = (TableRow) findViewById(R.id.traitsinfo_defense_row2);
traitsinfo_attack_cost = (TextView) findViewById(R.id.traitsinfo_attack_cost);
traitsinfo_attack_chance = (TextView) findViewById(R.id.traitsinfo_attack_chance);
traitsinfo_attack_damage = (TextView) findViewById(R.id.traitsinfo_attack_damage);
traitsinfo_criticalhit_skill = (TextView) findViewById(R.id.traitsinfo_criticalhit_skill);
traitsinfo_criticalhit_multiplier = (TextView) findViewById(R.id.traitsinfo_criticalhit_multiplier);
traitsinfo_criticalhit_effectivechance = (TextView) findViewById(R.id.traitsinfo_criticalhit_effectivechance);
traitsinfo_defense_chance = (TextView) findViewById(R.id.traitsinfo_defense_chance);
traitsinfo_defense_damageresist = (TextView) findViewById(R.id.traitsinfo_defense_damageresist);
}
public static void updateTraitsTable(
ViewGroup group
,int moveCost
,int attackCost
,int attackChance
,Range damagePotential
,int criticalSkill
,float criticalMultiplier
,int blockChance
,int damageResistance
,boolean isImmuneToCriticalHits
) {
TableRow row;
TextView tv;
tv = (TextView) group.findViewById(R.id.traitsinfo_move_cost);
tv.setText(Integer.toString(moveCost));
tv = (TextView) group.findViewById(R.id.traitsinfo_attack_cost);
tv.setText(Integer.toString(attackCost));
public void update(Actor actor) { update(actor.combatTraits, true); }
public void update(ActorTraits actorTraits) { update(actorTraits.baseCombatTraits, true); }
private void update(CombatTraits traits, boolean showEffectiveCriticalChance) {
if (traits != null && traits.attackCost != 0) {
traitsinfo_attack_row1.setVisibility(View.VISIBLE);
traitsinfo_attack_cost.setText(Integer.toString(traits.attackCost));
row = (TableRow) group.findViewById(R.id.traitsinfo_attack_chance_row);
if (attackChance != 0) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_attack_chance);
tv.setText(Integer.toString(attackChance) + "%");
} else {
traitsinfo_attack_row1.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
if (traits != null && traits.hasAttackChanceEffect()) {
traitsinfo_attack_row2.setVisibility(View.VISIBLE);
traitsinfo_attack_chance.setText(Integer.toString(traits.attackChance) + "%");
row = (TableRow) group.findViewById(R.id.traitsinfo_attack_damage_row);
if (damagePotential != null && damagePotential.max != 0) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_attack_damage);
tv.setText(damagePotential.toMinMaxString());
} else {
traitsinfo_attack_row2.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
if (traits != null && traits.hasAttackDamageEffect()) {
traitsinfo_attack_row3.setVisibility(View.VISIBLE);
traitsinfo_attack_damage.setText(traits.damagePotential.toMinMaxString());
row = (TableRow) group.findViewById(R.id.traitsinfo_criticalhit_skill_row);
if (criticalSkill != 0) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_criticalhit_skill);
tv.setText(Integer.toString(criticalSkill));
} else {
traitsinfo_attack_row3.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
if (traits != null && traits.hasCriticalSkillEffect()) {
traitsinfo_critical_row1.setVisibility(View.VISIBLE);
traitsinfo_criticalhit_skill.setText(Integer.toString(traits.criticalSkill));
row = (TableRow) group.findViewById(R.id.traitsinfo_criticalhit_multiplier_row);
if (criticalMultiplier != 0 && criticalMultiplier != 1) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_criticalhit_multiplier);
tv.setText(Float.toString(criticalMultiplier));
} else {
traitsinfo_critical_row1.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
if (traits != null && traits.hasCriticalMultiplierEffect()) {
traitsinfo_critical_row2.setVisibility(View.VISIBLE);
traitsinfo_criticalhit_multiplier.setText(Float.toString(traits.criticalMultiplier));
row = (TableRow) group.findViewById(R.id.traitsinfo_criticalhit_effectivechance_row);
if (criticalSkill != 0 && criticalMultiplier != 0 && criticalMultiplier != 1) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_criticalhit_effectivechance);
tv.setText(Integer.toString(Actor.getEffectiveCriticalChance(criticalSkill)) + "%");
} else {
traitsinfo_critical_row2.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
if (showEffectiveCriticalChance && traits != null && traits.hasCriticalAttacks()) {
traitsinfo_critical_row3.setVisibility(View.VISIBLE);
traitsinfo_criticalhit_effectivechance.setText(Integer.toString(traits.getEffectiveCriticalChance()) + "%");
row = (TableRow) group.findViewById(R.id.traitsinfo_block_chance_row);
if (blockChance != 0) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_block_chance);
tv.setText(Integer.toString(blockChance) + "%");
} else {
traitsinfo_critical_row3.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
if (traits != null && traits.hasBlockEffect()) {
traitsinfo_defense_row1.setVisibility(View.VISIBLE);
traitsinfo_defense_chance.setText(Integer.toString(traits.blockChance) + "%");
row = (TableRow) group.findViewById(R.id.traitsinfo_damageresist_row);
if (damageResistance != 0) {
row.setVisibility(View.VISIBLE);
tv = (TextView) group.findViewById(R.id.traitsinfo_damageresist);
tv.setText(Integer.toString(damageResistance));
} else {
traitsinfo_defense_row1.setVisibility(View.GONE);
}
if (traits != null && traits.damageResistance != 0) {
traitsinfo_defense_row2.setVisibility(View.VISIBLE);
traitsinfo_defense_damageresist.setText(Integer.toString(traits.damageResistance));
} else {
traitsinfo_defense_row2.setVisibility(View.GONE);
row.setVisibility(View.GONE);
}
row = (TableRow) group.findViewById(R.id.traitsinfo_is_immune_to_critical_hits_row);
row.setVisibility(isImmuneToCriticalHits ? View.VISIBLE : View.GONE);
}
}