Variables in Origins fields, commands and scoreboards
Ways to connect variables to the rest of the game:
| You want to… | Use |
|---|---|
Put a variable into any field of an Origins action or condition: a command, a velocity, an effect duration, a compare_to | with_variables |
| Use variables in chat, command blocks or functions | /opp with |
| Read a scoreboard score in code, for example a value shared by a team | Scoreboard.get |
Read what item is in a slot: a vanilla slot, or one of your origins:inventory powers, for you or the other entity | Item.id and Item.count |
| Feed a number to a power field that's read continuously, such as a modifier | variable_bar + the modifier's resource |
With variables
origins-powerful-powers:with_variablesentity action, bi-entity action, entity condition, bi-entity condition
Wraps any Origins action or condition. Any string value inside it can contain ${expression}. Each time it runs, the placeholders are filled in for this entity and Origins reads the result.
| Field | Type | Default | Description |
|---|---|---|---|
action | Entity action type (or bi-entity action type) | required in the action versions | The action to run |
condition | Entity condition type (or bi-entity condition type) | required in the condition versions | The condition to check |
Placeholder rules:
- The whole string is one placeholder, like
"${speed}". It becomes a real JSON number, boolean or string, so it can fill number and true/false fields. - A placeholder inside text, like
"say I have ${coins} coins", is converted to text the way Java does ("" + coins). Adoubleprints as3.0, alongwithout anL. $${is a literal${.- Inside
${…}goes one read-only expression:${coins / 100},${(int) (mana * 20)},${tier.toUpperCase()},${x >= 25 ? "green" : "gray"},${Scoreboard.get("kills")}. String literals inside can contain}. - Bi-entity versions:
${other.name}reads the target and${self.name}the actor. - Inside a
for_each_readloop:${value},${index}and${size}read the current element (page 11).
A number into origins:add_velocity: launch upward with a strength stored in double jumpPower.
{
"type": "origins-powerful-powers:with_variables",
"action": {
"type": "origins:add_velocity",
"y": "${jumpPower * 0.1}",
"space": "world"
}
}A String into origins:execute_command:
{
"type": "origins-powerful-powers:with_variables",
"action": {
"type": "origins:execute_command",
"command": "title @s actionbar {\"text\":\"${rank}: ${mana}/${maxMana} mana\"}"
}
}Numbers into an effect. Cast to int for whole-number fields.
{
"type": "origins-powerful-powers:with_variables",
"action": {
"type": "origins:apply_effect",
"effect": {
"effect": "minecraft:speed",
"duration": "${(int) (mana * 20)}",
"amplifier": "${Math.min(level, 4)}"
}
}
}A condition with a threshold from a variable: true while the food level is below the player's hungerLine.
{
"type": "origins-powerful-powers:with_variables",
"condition": {
"type": "origins:food_level",
"comparison": "<",
"compare_to": "${hungerLine}"
}
}Bi-entity: damage the target by its own bounty variable.
{
"type": "origins:action_on_hit",
"bientity_action": {
"type": "origins-powerful-powers:with_variables",
"action": {
"type": "origins:target_action",
"action": {
"type": "origins:damage",
"amount": "${(float) other.bounty}",
"damage_type": "minecraft:magic"
}
}
}
}Things to know:
- Some mistakes only show up when the action runs. A syntax error inside
${…}fails the pack load. Origins reads the wrapped action after the values are filled in, so a wrong field name or value type is logged the first time it runs (prefixed[variables] with_variables:) and the action does nothing. A condition that fails this way counts asfalse. - Decimals are cut off in whole-number fields like
duration, so2.9becomes2. Round in the expression for rounding. - Quotes in String variables. A String is inserted as it is. A
"inside atellrawJSON text breaks that JSON. Usename.replace("\"", "'")in the expression when that can happen. - Caching. Origins reads each distinct filled-in result once and keeps it, up to 64 per
with_variables. A value that changes every tick (adoublethat never repeats) makes the action re-read every time, which is slower. Round values in actions that run every tick.
/opp with
For chat, command blocks and .mcfunction files, put opp with <targets> in front of any command:
opp with @s title @s actionbar {"text":"${rank}: ${mana}/${maxMana} mana"}
opp with @a[tag=saver] scoreboard players set @s bank ${(int) coins}
opp with @s tellraw @s {"text":"${history.size()} payouts so far"}- Each target's own values. For every target,
${…}is filled from that target's variables and lists. The command then runs as that target, likeexecute as, so@sis the target. Position, dimension and permission level stay those of whoever ran/opp with. For the target's position, useopp with @a execute at @s run …. - Everything becomes text. Every placeholder uses Java's text conversion.
${d}for adoubleprints3.0, so write${(int) d}where a command needs a whole number.$${is a literal${. - Plain quotes inside
${…}. The placeholder is replaced before the command runs, so write its quotes plainly, even inside JSON text:title @s actionbar {"text":"${Scoreboard.get("#bank", "team_bank")}"}. In power JSON, the whole command is a JSON string, so every"there is written\". - All or nothing. Every target is filled in before any command runs. If one fails (an unknown variable, a wrong type, a typo inside
${…}), nothing runs and/opp withfails with the reason. - Result. The sum of the commands' results, so
execute store result score @s x run opp with @s …works for one target. - Permission level 2, like the other
/oppcommands. Functions and command blocks have it.
Scoreboard
Code can read scores anywhere it runs: execute code, expression conditions, modify_variable values, for_each code and ${…}.
| Call | Returns | |
|---|---|---|
Scoreboard.get(objective) | int | this entity's score in objective |
Scoreboard.get(holder, objective) | int | the score of any holder: a player name, or a fake name like #bank |
Scoreboard.has(objective) | boolean | whether this entity has a score in objective |
Scoreboard.has(holder, objective) | boolean | whether holder has a score in objective |
teamBank = Scoreboard.get("#bank", "team_bank");
kills = Scoreboard.get("kills");
bonus = Scoreboard.has("#event", "active") ? Scoreboard.get("#event", "active") * 10 : 0;- A missing score is an error, as with vanilla's
/scoreboard players get. An action stops there, and a condition isfalse. An unknown objective is an error too. Check withScoreboard.hasfirst when a score may be unset. - "This entity" is the power holder (in bi-entity code, the actor), by its scoreboard name: a player's name, or the UUID for other entities. The bi-entity target's score is unreachable this way.
- Holders are exact names. Selectors like
@sor@pfail here. - It only reads. To write a score, run a command with the value, using
/opp withorwith_variables+execute_command, as below. - Field initializers can't use it, because they run when the pack loads, before a world exists.
Shared values through scoreboards. A team bank kept on the fake player #bank:
{
"type": "origins:and",
"actions": [
{
"type": "origins-powerful-powers:with_variables",
"action": {
"type": "origins:execute_command",
"command": "scoreboard players add #bank team_bank ${Math.min(coins, 10)}"
}
},
{
"type": "origins-powerful-powers:execute",
"code": "coins -= Math.min(coins, 10);"
}
]
}This deposits up to 10 of your coins. Anyone can check the shared total with Scoreboard.get("#bank", "team_bank"), for example in an expression condition or a HUD message.
Attributes into variables. Store an attribute in a score, then read it:
execute as @a store result score @s sprint run attribute @s origins-powerful-powers:sprint_ticks getlongestSprint = Math.max(longestSprint, Scoreboard.get("sprint"));Power fields: variable bar and modifier resource
Power fields, like a modify_jump modifier, are read when the power is granted, so with_variables can't reach them. For a number a power uses continuously, link the variable with a variable_bar and put the bar's id in the modifier's resource field. Origins then uses the bar's value as the modifier's value.
Example: bonus damage equal to an int rage variable, linked through a variable bar with the id mypack:rage_bar:
{
"type": "origins:modify_damage_dealt",
"modifier": {
"operation": "add_base_early",
"value": 0,
"resource": "mypack:rage_bar"
}
}This works for any power that takes an Origins modifier: modify_damage_dealt, modify_damage_taken, modify_jump, modify_break_speed, conditioned_attribute, and so on. A bar is a whole number, so store fractions scaled (such as int speedPercent) and pick an operation to match.