Related: ๅจไฝไธๆ่ฝๆกฅ.md ยท APIๆฆ่ง.md ยท ่ๆฌAPI.md ยท ../05-ๅ่/ๆฏ่ฏญ่กจ.md
๐ Condition System & Expression Engine (ConditionSystem / ExpressionEngine) โ
This page covers two complementary evaluation tools:
- ConditionSystem โ a boolean judgment framework (condition chains, DSL programs, operators, composite conditions).
- ExpressionEngine โ an exp4j-based numeric expression engine (arithmetic, functions, random numbers).
Actions decide "what to do", conditions decide "whether to do it", and expressions compute the concrete numbers for actions. The three are usually used together โ see ๅจไฝไธๆ่ฝๆกฅ.md.
1. ConditionSystem โ
1.1 The Condition interface and ConditionContext โ
interface Condition {
val id: String
fun evaluate(context: ConditionContext): Boolean
}The evaluation context ConditionContext:
| Member | Description |
|---|---|
variables | Variable bag |
traceId (nullable) | Trace id |
debug | Whether to enable debug tracing |
Read/write methods:
context.setVar("hp", 18.0)
val hp: Double? = context.getVar("hp")
val name: String = context.getVarString("targetName")
context.traceBuilder()1.2 Implementing and registering a condition โ
class HasEnoughHpCondition : Condition {
override val id = "has_enough_hp"
override fun evaluate(context: ConditionContext): Boolean {
val hp = context.getVar<Double>("hp") ?: return false
return hp >= 10.0
}
}
// Register / look up / get all
ConditionRegistry.register(HasEnoughHpCondition())
val cond = ConditionRegistry.get("has_enough_hp")
val all = ConditionRegistry.all()1.3 ConditionPipeline โ condition chain โ
val pipeline = ConditionPipeline()
pipeline.addCondition(HasEnoughHpCondition())
// Or load a DSL program
pipeline.loadProgram(myConditionDslProgram)
val ctx = ConditionContext(variables = mutableMapOf("hp" to 18.0))
val ok: Boolean = pipeline.evaluate(ctx)1.4 DSL: ConditionNode / ConditionDslProgram โ
Write conditions as nodes, aggregated by logic as AND / OR. The compile / validate / optimize / execute four-stage flow is consistent with the action DSL.
val program = ConditionDslProgram(
id = "can_cast",
nodes = listOf(
ConditionNode(id = "n1", type = "var_eq", params = mapOf("key" to "class", "value" to "mage")),
ConditionNode(id = "n2", type = "exists", params = mapOf("key" to "mana")),
),
logic = "AND" // "AND" | "OR", defaults to "AND"
)
program.compile()
program.validate()
program.optimize()
val result: Boolean = program.execute(ctx)ConditionNode(id, type, params): type is one of the built-in operators in the table below, and params holds the arguments for that operator.
1.5 Built-in node operators โ
| Operator | Meaning |
|---|---|
eq | Equal |
neq | Not equal |
exists | Variable exists |
notnull | Not null |
contains | Contains |
var_eq | Variable equals a value |
1.6 CompositeCondition โ composite condition โ
Combine multiple conditions into one using a logical operator:
val composite = CompositeCondition(
conditions = listOf(condA, condB, condC),
operator = LogicOperator.AND // AND / OR / NOT
)
val ok = composite.evaluate(ctx)LogicOperator values: AND / OR / NOT.
2. ExpressionEngine โ the expression engine โ
ExpressionEngine is based on exp4j, computing a string expression together with a variable table into a single Double.
2.1 evaluate โ
val vars: Map<String, Double> = mapOf("level" to 12.0, "base" to 5.0)
val damage: Double = ExpressionEngine.evaluate("base + level * 1.5", vars)
// โ 5 + 12 * 1.5 = 23.0Signature: evaluate(expression: String, variables: Map<String, Double>): Double
2.2 Random functions โ
The engine has 4 built-in random functions that can be written directly into expressions:
| Function | Meaning |
|---|---|
randomDouble(min, max) | Uniform random decimal in the [min, max) interval |
randomInt(min, max) | Random integer in the interval |
randomGaussian(mean, stdDev) | Normally distributed random number (mean mean, standard deviation stdDev) |
randomExponential(lambda) | Exponentially distributed random number (rate lambda) |
// Base damage 10 ยฑ fluctuation, plus a bit of Gaussian jitter
val dmg = ExpressionEngine.evaluate(
"10 + randomDouble(0, 3) + randomGaussian(0, 0.5)",
emptyMap()
)
val crit = ExpressionEngine.evaluate("randomInt(1, 100)", emptyMap()) // 1~100 dice roll2.3 exp4j syntax and built-in functions โ
Supported operations and functions (built into exp4j):
- Arithmetic:
+-*/%(modulo),^orpow(power) - Comparison and logic: comparison operators, logical operators
- Math functions:
sincostanloglog10lnsqrtabsceilfloorexp, etc.
ExpressionEngine.evaluate("sqrt(level) * 2 + abs(offset)", mapOf("level" to 16.0, "offset" to -3.0))
// โ 4 * 2 + 3 = 11.0
ExpressionEngine.evaluate("ceil(hp / 2)", mapOf("hp" to 7.0)) // โ 4.0
ExpressionEngine.evaluate("2 ^ 10", emptyMap()) // โ 1024.03. Using conditions + expressions + actions together โ
A typical flow: first compute numbers with expressions and put them into the variable bag, then use conditions to decide whether to execute, and finally run the action.
val ctx = ActionContext(player = player, variables = mutableMapOf())
// 1. Compute damage with an expression
val dmg = ExpressionEngine.evaluate("base + level * 1.5", mapOf("base" to 5.0, "level" to 12.0))
ctx.setVar("damage", dmg)
ctx.setVar("hp", player.health)
// 2. Condition check
val condCtx = ConditionContext(variables = ctx.variables)
if (HasEnoughHpCondition().evaluate(condCtx)) {
// 3. Execute the action
ActionRegistry.get("heal")?.execute(ctx)
}๐ Continue reading โ
- ๅจไฝไธๆ่ฝๆกฅ.md โ Action system and cross-module skill contract
- ่ๆฌAPI.md โ Scriptable extension capabilities
- ../05-ๅ่/ๆฏ่ฏญ่กจ.md โ Terminology definitions