mirror of
https://github.com/collinsmith/riiablo.git
synced 2025-07-14 01:38:00 +07:00
Created AttributesUpdater and tests to fold attributes into each other
This commit is contained in:
126
core/src/com/riiablo/attributes/AttributesUpdater.java
Normal file
126
core/src/com/riiablo/attributes/AttributesUpdater.java
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package com.riiablo.attributes;
|
||||||
|
|
||||||
|
import com.riiablo.codec.excel.CharStats;
|
||||||
|
import com.riiablo.codec.excel.ItemStatCost;
|
||||||
|
import com.riiablo.logger.LogManager;
|
||||||
|
import com.riiablo.logger.Logger;
|
||||||
|
import com.riiablo.logger.MDC;
|
||||||
|
|
||||||
|
public class AttributesUpdater {
|
||||||
|
private static final Logger log = LogManager.getLogger(AttributesUpdater.class);
|
||||||
|
|
||||||
|
public Attributes update(Attributes attrs, Attributes opAttrs) {
|
||||||
|
log.traceEntry("update(attrs: {}, opAttrs: {})", attrs, opAttrs);
|
||||||
|
return update(attrs, opAttrs, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attributes update(Attributes attrs, Attributes opAttrs, CharStats.Entry charStats) {
|
||||||
|
log.traceEntry("update(attrs: {}, opAttrs: {}, charStats: {})", attrs, opAttrs, charStats);
|
||||||
|
final StatList list = attrs.list();
|
||||||
|
if (list.isEmpty()) return attrs;
|
||||||
|
final StatListGetter base = attrs.base();
|
||||||
|
final StatListBuilder agg = attrs.aggregate().builder();
|
||||||
|
final StatListBuilder rem = attrs.remaining().builder();
|
||||||
|
for (StatListGetter stats : list.listIterator()) {
|
||||||
|
update(opAttrs, charStats, stats, base, agg, rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void update(
|
||||||
|
final Attributes opAttrs,
|
||||||
|
final CharStats.Entry charStats,
|
||||||
|
final StatListGetter stats,
|
||||||
|
final StatListGetter base,
|
||||||
|
final StatListBuilder agg,
|
||||||
|
final StatListBuilder rem) {
|
||||||
|
for (StatGetter stat : stats) {
|
||||||
|
final ItemStatCost.Entry entry = stat.entry();
|
||||||
|
try {
|
||||||
|
MDC.put("updateStat", stat.id());
|
||||||
|
if (entry.op > 0) {
|
||||||
|
final int ops = op(opAttrs, charStats, agg, stat);
|
||||||
|
if (ops == 0) {
|
||||||
|
log.trace("Propagating stat({})", stat.debugString());
|
||||||
|
rem.add(stat);
|
||||||
|
}
|
||||||
|
} else if (!base.contains(stat)) {
|
||||||
|
log.trace("Propagating stat({})", stat.debugString());
|
||||||
|
rem.add(stat);
|
||||||
|
} else {
|
||||||
|
log.trace("Aggregating stat({})", stat.debugString());
|
||||||
|
agg.add(stat);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
MDC.remove("updateStat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int op(
|
||||||
|
final Attributes opAttrs,
|
||||||
|
final CharStats.Entry charStats,
|
||||||
|
final StatListBuilder agg,
|
||||||
|
final StatGetter stat) {
|
||||||
|
final ItemStatCost.Entry entry = stat.entry();
|
||||||
|
final int op = entry.op;
|
||||||
|
final int op_param = entry.op_param;
|
||||||
|
final int op_base = op_param > 0
|
||||||
|
? opAttrs.aggregate().get(Stat.index(entry.op_base)).value()
|
||||||
|
: 1;
|
||||||
|
int ops = 0;
|
||||||
|
for (String op_stat : entry.op_stat) {
|
||||||
|
if (op_stat.isEmpty()) break;
|
||||||
|
final short statId = Stat.index(op_stat);
|
||||||
|
final StatGetter opStat = agg.get(statId);
|
||||||
|
if (opStat != null) {
|
||||||
|
final int opValue = op(charStats, agg, stat, opStat, op, op_base, op_param);
|
||||||
|
opStat.add(opValue);
|
||||||
|
ops++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see StatFormatter#op(StatGetter, Attributes) */
|
||||||
|
private static int op(
|
||||||
|
final CharStats.Entry charStats,
|
||||||
|
final StatListBuilder agg,
|
||||||
|
final StatGetter stat,
|
||||||
|
final StatGetter opStat,
|
||||||
|
final int op,
|
||||||
|
final int op_base,
|
||||||
|
final int op_param) {
|
||||||
|
switch (op) {
|
||||||
|
case 1: return (stat.value() * opStat.value()) / 100;
|
||||||
|
case 2: return Fixed.intBitsToFloatFloor(stat.value() * op_base, op_param);
|
||||||
|
case 3: return Fixed.intBitsToFloatFloor(stat.value() * op_base, op_param) * opStat.value() / 100;
|
||||||
|
case 4: return Fixed.intBitsToFloatFloor(stat.value() * op_base, op_param);
|
||||||
|
case 5: return Fixed.intBitsToFloatFloor(stat.value() * op_base, op_param) * opStat.value() / 100;
|
||||||
|
case 6: return 0; // by-time
|
||||||
|
case 7: return 0; // by-time percent
|
||||||
|
case 8:
|
||||||
|
if (charStats == null) return 0;
|
||||||
|
agg.add(stat);
|
||||||
|
//mod.set(stat.id);
|
||||||
|
return stat.value() * charStats.ManaPerMagic; // max mana
|
||||||
|
case 9:
|
||||||
|
if (charStats == null) return 0;
|
||||||
|
if (opStat.id() == Stat.maxhp) { // only increment vit on maxhp op
|
||||||
|
agg.add(stat);
|
||||||
|
//mod.set(stat.id);
|
||||||
|
}
|
||||||
|
return stat.value() // max hitpoints or stamina
|
||||||
|
* (opStat.id() == Stat.maxhp
|
||||||
|
? charStats.LifePerVitality
|
||||||
|
: charStats.StaminaPerVitality);
|
||||||
|
case 10: return 0; // no-op
|
||||||
|
case 11: return (stat.value() * opStat.value()) / 100; // TODO: modify field value? used with item_maxhp_percent and item_maxmana_percent
|
||||||
|
case 12: return 0; // no-op
|
||||||
|
case 13: return (stat.value() * opStat.value()) / 100;
|
||||||
|
default: throw new AssertionError("Unsupported op: " + op + " for " + stat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
core/test/com/riiablo/attributes/AttributesTest.java
Normal file
48
core/test/com/riiablo/attributes/AttributesTest.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package com.riiablo.attributes;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ApplicationAdapter;
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.backends.headless.HeadlessApplication;
|
||||||
|
|
||||||
|
import com.riiablo.Files;
|
||||||
|
import com.riiablo.Riiablo;
|
||||||
|
import com.riiablo.codec.StringTBLs;
|
||||||
|
import com.riiablo.logger.Level;
|
||||||
|
import com.riiablo.logger.LogManager;
|
||||||
|
import com.riiablo.mpq.MPQFileHandleResolver;
|
||||||
|
|
||||||
|
public class AttributesTest {
|
||||||
|
@BeforeClass
|
||||||
|
public static void setup() {
|
||||||
|
Gdx.app = new HeadlessApplication(new ApplicationAdapter() {});
|
||||||
|
Riiablo.home = Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II");
|
||||||
|
Riiablo.mpqs = new MPQFileHandleResolver();
|
||||||
|
Riiablo.string = new StringTBLs(Riiablo.mpqs);
|
||||||
|
Riiablo.files = new Files();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void teardown() {
|
||||||
|
Gdx.app.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void before() {
|
||||||
|
LogManager.setLevel("com.riiablo.attributes", Level.TRACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void reset_does_not_reset_base() {
|
||||||
|
AggregateAttributes attrs = Attributes.aggregateAttributes();
|
||||||
|
attrs.base().builder().put(Stat.strength, 5).put(Stat.vitality, 15);
|
||||||
|
attrs.reset();
|
||||||
|
|
||||||
|
for (StatGetter stat : attrs) {
|
||||||
|
System.out.println(stat.debugString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user