Combat System

A real .jv module using a local class and an accumulator via the Variable Bridge.

This module is real code, written and verified during the 1.1 stress test: it compiled and ran successfully on Paper 26.1.2 / Skript 2.16.1.

// modules/combat_core.jv
class Hit {
    final String attacker;
    final double damage;
    Hit(String attacker, double damage) { this.attacker = attacker; this.damage = damage; }
}

java.util.List<Hit> hits = new java.util.ArrayList<>();
hits.add(new Hit("Zombie", 4.5));
hits.add(new Hit("Skeleton", 3.0));
hits.add(new Hit("Creeper", 22.0));

double total = 0;
StringBuilder summaryBuilder = new StringBuilder();
for (int i = 0; i < hits.size(); i++) {
    Hit hit = (Hit) hits.get(i);
    total += hit.damage;
    if (i > 0) {
        summaryBuilder.append(", ");
    }
    summaryBuilder.append(hit.attacker).append("=").append(hit.damage);
}
String summary = summaryBuilder.toString();

setVar("combat_total_damage", total);
setVar("combat_summary", summary);
setVar("combat_hit_count", hits.size());

sender.sendMessage("[Combat] total=" + total + " hits=" + hits.size() + " (" + summary + ")");

Run from a command:

command /combat:
    trigger:
        run jv "modules/combat_core.jv"

What this demonstrates

  • A local class (class Hit { ... }) — works in Janino without a final modifier, see the Compatibility Matrix.
  • An explicit cast (Hit) hits.get(i) — works around a known limitation: Janino types a collection’s generic parameter as Object when it’s a local class.
  • setVar to collect results.

Values from this example are visible within a single invocation (e.g. via /jvdebug vars combat), but don’t survive separate command runs. See the Scope Warning for details.