如何簡易的實現小數四則運算

指令技術

2020/09/01

以下範文皆以生物的Attributes標籤格式為主

屬性的格式與細則詳見:連結
備註:前導資訊內容皆源自此Wiki之內容,並無其餘特殊內容(僅略做統整),讀者可自行選擇跳過
此篇適用於Java Edition 1.14~1.16的版本

你可以在此篇文章學習到什麼 ?

  1. 理解實體的屬性(Attributes)和修飾符(Modifiers)的格式與規則
  2. 利用attribute指令進行小數點運算(加減乘除)與注意事項
  3. 如何存取小數運算的結果值

前導資訊

Attributes的結構

Attributes由2個必要的標籤:Name、Amount,以及1個可選標籤:Modifiers所組成:

  1. Name:功用在於指定要控制的目標屬性,如攻擊傷害(attack_damage)、生命值(health)等。
  2. Base:為該屬性的基礎值。
  3. Modifiers:列出套用加與乘法的修飾符(Modifier),在下文有更詳細的描述。

Modifiers的格式

Modifiers由4個必要的標籤組成:Name、Amount、Operation、UUID

  1. Name:功用在於方便被指令指定,如:/execute if data entity @s Attributes.Modifiers.[{Name:"sample"}]
    效果為:檢測自身標籤的Attributes中的Modifiers中是否有Name:"sample"的標籤。
  2. Amount:作為當前修飾符的設定值,並依據Operation指定的值來套用指定的計算模式。
  3. Operation:用來指定計算的模式,在下方有更詳細的描述。
  4. UUID:用來指定當前修飾符的編號(UUID),在同一個Modifiers中,具有相同UUID的修飾符僅有全部項目中最前面一項的修飾符會被套用。
ex. (1.16) Modifiers:[{Name:"multiply",Amount:0.5,Operation:2,UUID:[I;0,0,0,0]},{Name:"add",Amount:2,Operation:0,UUID:[I;0,0,0,0]}]

輸出值將等同於「base值*1.5倍」的效果。

Modifiers的規則

Attribute的Modifiers中有三項操作方式(Operation):
以下由修飾符所設定的值(Amount)簡稱為「設定值」,且假設base值皆為2.5d

  • 〔0 | add〕 加上設定值
    ex. {Amount:1.35,Operation:0} = 2.5+1.35,總值=3.85 
  • 〔1 | multiply_base〕 將屬性值乘上(1+設定值的總和)
    ex. [{Amount:6.5,Operation:1},{Amount:-3.5,Operation:1}] = 2.5*(1+6.5-3.5),總值=10
  • 〔2 | multiply〕 將屬性值乘上(1+設定值)
    ex. [{Amount:3,Operation:1},{Amount:2.65,Operation:1}] = 2.5*(1+3)*(1+2.65),總值=36.5

在Modifiers中有指定的運算順序規則,Operation:0 -> Operation:1 -> Operation:2 (先->後)

ex. [{Amount:1.6,Operation:2},{Amount:1.1,Operation:1},{Amount:0.9,Operation:0},{Amount:1.9,Operation:1},{Amount:1.8,Operation:2}] = (2.5+0.9)*(1+1.1+1.9)*(1+1.8)*(1+1.6),總值=99.008 
也可以看成:[base+(op0項的總和)]*[1+(op1項的總和)]*(1+op2)*(1+op2)*...

ex. 一個可行的生物標籤(1.16↑):Attributes:[{Name:"minecraft:generic.attack_damage",Base:1.8,Modifiers:[{Name:"add",Amount:0.07,Operation:0,UUID:[I;0,0,0,0]}]}]
ex. 一個可行的生物標籤(1.15↓):Attributes:[{Name:"minecraft:generic.attackDamage",Base:3.0,Modifiers:[{Name:"multiply",Amount:0.23,Operation:2,UUIDMost:1,UUIDLeast:1}]}]

如何進行小數運算與存取結果值

每個屬性值會根據修飾符與基礎值(Base)進行運算而得出,進而我們可以利用修飾符與基礎值(Base)的關係來實現「小數運算」。

(1.16↑)利用attribute指令進行小數運算的做法

新版本中加入了attribute指令,這更加便於讓我們針對生物的屬性值(Attributes標籤)進行修改, 包含加上數值、乘以數值、取得結算值(get)等。
attribute指令格式詳見:連結

ex. 把自己的armor屬性值加上36.8,
可以視同使用指令:/attribute @s minecraft:generic.armor modifier add 0-0-0-0-1 add 36.8 add

ex. 把自己的armor屬性值乘以2.05,
可以視同使用指令:/attribute @s minecraft:generic.armor modifier add 0-0-0-0-2 multiply 1.05 multiply

ex. 把自己的armor屬性值除以5,
可以視同使用指令:/attribute @s minecraft:generic.armor modifier add 0-0-0-0-3 multiply -0.8 multiply

(1.14↑)利用data modify指令進行小數運算的做法

相比attribute的直觀設計,利用data modify的設計較為複雜,但實用性相對較高,是由於data modify有能將其他標籤的數值進行轉移(set from)的功能。
請注意:玩家的資料幾乎都不能被指令修改
以下皆使用1.16版本的格式作範例

ex. 把自己的max_health屬性值改變為:10.9*(1+5.1)=66.49。

  1. 設定好Modifiers的路徑:
    /data merge entity @s {Attributes:[{Name:"minecraft:generic.max_health",Base:8.0d,Modifiers:[{Amount:0,Operation:1,UUID:[I;0,0,0,1],Name:"multiply"}]}]}
  2. 設定被乘數(base值):
    /data modify entity @s Attributes[{Name:"minecraft:generic.max_health"}].Base set value 10.9
  3. 設定乘數(Amount值):
    /data modify entity @s Attributes[{Name:"minecraft:generic.max_health"}].Modifiers[{Name:"multiply"}].Amount set value 5.1

※請注意,1.16對於生物的Attributes格式略有規則上的更改:
部分屬性會被「隱藏」起來,如attack_damage最為常見(最常被隱藏),
可以將生物加上一個modifier再移除的方式來確保該屬性能出現於Attributes的列表中。

如何存取最後的計算結果值

在上述步驟,我們已經完成在屬性中進行計算的過程,
接下來最主要的問題則是:需要怎麼做才能取得此屬性最後輸出的結算值(在當前的生物標籤中,並沒有任何一項標籤能表示某個屬性的屬性值)。
於是我們在此一共會介紹2種取得屬性結算值做法:

〔1.16↑〕欲取得結算值(最終屬性值)可以利用指令:/attribute ... get [<scale>]
通常會搭配execute store,如:/execute store result score ... run attribute ... get [<scale>]

〔1.14↑〕相對於使用attribute get的效果,此方式取得結算值的限制非常大,
若欲取得屬性(max_health的結算值,需使用2步驟:

  1. 覆蓋Health的數值,使之數值與max_health值相等:data merge entity ... {Health:1024.0f}
    • 取得Health的數值(get):data get entity ... Health [<scale>]
    • 轉移Health的數值(set from):/data modify entity ... set from entity ... Health

使用此種取得結算值的作法需要注意以下幾點:

  1. 如果Health給予的值比maxHealth的值還要大,Health就會被替換為maxHealth值(這個替換是立即的,不需間隔tick)
  2. Health值的最大限制是1024.0f,即使maxHealth的值可以比1024.0d還要大。
  3. 由於是改變生物Health的方式,不得儲存0.0以下的數值(這會導致生物直接死亡而無法存取數值)。
  4. 請注意資料型態的變換:Health為float、maxHealth的值為double

(1.14↑取結果值的作法,目前只能想到用Health)

若讀者有其他想法與做法請務必向我們提出和建議owo