diff --git a/spinui_glass/AttackIndicator.tga b/spinui_glass/AttackIndicator.tga
index fad2a9c..c071f50 100644
Binary files a/spinui_glass/AttackIndicator.tga and b/spinui_glass/AttackIndicator.tga differ
diff --git a/spinui_glass/EQUI_PlayerWindow.xml b/spinui_glass/EQUI_PlayerWindow.xml
index a0e2bf1..4984b33 100644
--- a/spinui_glass/EQUI_PlayerWindow.xml
+++ b/spinui_glass/EQUI_PlayerWindow.xml
@@ -10,10 +10,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -28,7 +42,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -43,7 +57,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -58,7 +72,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -73,7 +87,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -88,7 +102,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -105,8 +119,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -120,8 +134,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -135,10 +149,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -150,9 +164,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -162,6 +176,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -845,7 +872,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1162,8 +1189,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1276,9 +1303,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1334,7 +1361,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1353,15 +1380,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/EQUI_PlayerWindow1.xml b/spinui_glass/EQUI_PlayerWindow1.xml
index 0504d81..4f370c8 100644
--- a/spinui_glass/EQUI_PlayerWindow1.xml
+++ b/spinui_glass/EQUI_PlayerWindow1.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/EQUI_PlayerWindow2.xml b/spinui_glass/EQUI_PlayerWindow2.xml
index 0504d81..4f370c8 100644
--- a/spinui_glass/EQUI_PlayerWindow2.xml
+++ b/spinui_glass/EQUI_PlayerWindow2.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/EQUI_PlayerWindow3.xml b/spinui_glass/EQUI_PlayerWindow3.xml
index 0504d81..4f370c8 100644
--- a/spinui_glass/EQUI_PlayerWindow3.xml
+++ b/spinui_glass/EQUI_PlayerWindow3.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/EQUI_PlayerWindow4.xml b/spinui_glass/EQUI_PlayerWindow4.xml
index 0504d81..4f370c8 100644
--- a/spinui_glass/EQUI_PlayerWindow4.xml
+++ b/spinui_glass/EQUI_PlayerWindow4.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/EQUI_PlayerWindow5.xml b/spinui_glass/EQUI_PlayerWindow5.xml
index 0504d81..4f370c8 100644
--- a/spinui_glass/EQUI_PlayerWindow5.xml
+++ b/spinui_glass/EQUI_PlayerWindow5.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/EQUI_PlayerWindow6.xml b/spinui_glass/EQUI_PlayerWindow6.xml
index 0504d81..4f370c8 100644
--- a/spinui_glass/EQUI_PlayerWindow6.xml
+++ b/spinui_glass/EQUI_PlayerWindow6.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_glass/SpinAttackPerimeter.tga b/spinui_glass/SpinAttackPerimeter.tga
new file mode 100644
index 0000000..fb21406
Binary files /dev/null and b/spinui_glass/SpinAttackPerimeter.tga differ
diff --git a/spinui_glass/SpinAttackRail.tga b/spinui_glass/SpinAttackRail.tga
new file mode 100644
index 0000000..c071f50
Binary files /dev/null and b/spinui_glass/SpinAttackRail.tga differ
diff --git a/spinui_reloaded/AttackIndicator.tga b/spinui_reloaded/AttackIndicator.tga
index fad2a9c..c071f50 100644
Binary files a/spinui_reloaded/AttackIndicator.tga and b/spinui_reloaded/AttackIndicator.tga differ
diff --git a/spinui_reloaded/EQUI_PlayerWindow.xml b/spinui_reloaded/EQUI_PlayerWindow.xml
index 26a78b9..72b974b 100644
--- a/spinui_reloaded/EQUI_PlayerWindow.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow.xml
@@ -10,10 +10,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -28,7 +42,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -43,7 +57,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -58,7 +72,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -73,7 +87,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -88,7 +102,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -105,8 +119,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -120,8 +134,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -135,10 +149,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -150,9 +164,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -162,6 +176,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -845,7 +872,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1162,8 +1189,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1276,9 +1303,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1334,7 +1361,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1353,15 +1380,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/EQUI_PlayerWindow1.xml b/spinui_reloaded/EQUI_PlayerWindow1.xml
index be90c4c..e6a0869 100644
--- a/spinui_reloaded/EQUI_PlayerWindow1.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow1.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/EQUI_PlayerWindow2.xml b/spinui_reloaded/EQUI_PlayerWindow2.xml
index be90c4c..e6a0869 100644
--- a/spinui_reloaded/EQUI_PlayerWindow2.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow2.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/EQUI_PlayerWindow3.xml b/spinui_reloaded/EQUI_PlayerWindow3.xml
index be90c4c..e6a0869 100644
--- a/spinui_reloaded/EQUI_PlayerWindow3.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow3.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/EQUI_PlayerWindow4.xml b/spinui_reloaded/EQUI_PlayerWindow4.xml
index be90c4c..e6a0869 100644
--- a/spinui_reloaded/EQUI_PlayerWindow4.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow4.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/EQUI_PlayerWindow5.xml b/spinui_reloaded/EQUI_PlayerWindow5.xml
index be90c4c..e6a0869 100644
--- a/spinui_reloaded/EQUI_PlayerWindow5.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow5.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/EQUI_PlayerWindow6.xml b/spinui_reloaded/EQUI_PlayerWindow6.xml
index be90c4c..e6a0869 100644
--- a/spinui_reloaded/EQUI_PlayerWindow6.xml
+++ b/spinui_reloaded/EQUI_PlayerWindow6.xml
@@ -12,10 +12,24 @@
+
+
+ 128
+ 32
+
+
+
+
+
+ 128
+ 32
+
+
+
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -30,7 +44,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -45,7 +59,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -60,7 +74,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -75,7 +89,7 @@
false
- AttackIndicator.tga
+ SpinAttackRail.tga
0
0
@@ -90,7 +104,7 @@
false
- AttackIndicator.tga
+ SpinAttackPerimeter.tga
0
0
@@ -107,8 +121,8 @@
A_AttackIndicatorTop
false
true
- 70
- 78
+ 67
+ 70
0
0
true
@@ -122,8 +136,8 @@
A_AttackIndicatorBottom
false
true
- 10
- 2
+ 9
+ 6
0
0
false
@@ -137,10 +151,10 @@
A_AttackIndicatorLeft
false
true
- 70
- 2
+ 67
+ 6
0
- 8
+ 3
true
false
true
@@ -152,9 +166,9 @@
A_AttackIndicatorRight
false
true
- 70
- 2
- 8
+ 67
+ 6
+ 3
0
true
false
@@ -164,6 +178,19 @@
A_AttackIndicatorAnimFill
+ A_AttackIndicatorFill
+ true
+ false
+ true
+ true
+ 70
+ 6
+ 0
+ 0
+ true
+ false
+ true
+ false
@@ -847,7 +874,7 @@
A_GaugeLinesFill
true
- 84
+ 83
94
1
1
@@ -1164,8 +1191,8 @@
false
2
2
- 72
- 2
+ 70
+ 0
false
false
true
@@ -1278,9 +1305,9 @@
false
false
70
- 2
- -1
- -1
+ 9
+ 3
+ 3
Player_HP
Pet_HP
Player_Mana
@@ -1335,7 +1362,7 @@
193
280
- 174
+ 193
false
false
WDT_RoundedTransparentNoArrow
@@ -1354,15 +1381,15 @@
-9
Screen:PlayerSubWindow
+ DragBox:PW_DragBox
+ DragBox:PW_DragBox2
+ DragBox:PWDragBox3
+ PW_BuffWindow
A_AttackIndicatorAnimTop
A_AttackIndicatorAnimBottom
A_AttackIndicatorAnimLeft
A_AttackIndicatorAnimRight
A_AttackIndicatorAnimFill
- DragBox:PW_DragBox
- DragBox:PW_DragBox2
- DragBox:PWDragBox3
- PW_BuffWindow
diff --git a/spinui_reloaded/SpinAttackPerimeter.tga b/spinui_reloaded/SpinAttackPerimeter.tga
new file mode 100644
index 0000000..fb21406
Binary files /dev/null and b/spinui_reloaded/SpinAttackPerimeter.tga differ
diff --git a/spinui_reloaded/SpinAttackRail.tga b/spinui_reloaded/SpinAttackRail.tga
new file mode 100644
index 0000000..c071f50
Binary files /dev/null and b/spinui_reloaded/SpinAttackRail.tga differ
diff --git a/tools/audit_combat_ui.py b/tools/audit_combat_ui.py
index aa97b9e..e3a55f0 100644
--- a/tools/audit_combat_ui.py
+++ b/tools/audit_combat_ui.py
@@ -13,7 +13,8 @@
# The effects-row grid is authored once in tools/restyle_combat.py; the audit
# imports it so a geometry change can never pass by editing only one side.
-from restyle_combat import (EFFECT_CHIP, EFFECT_ICON, EFFECT_NAME_WIDTH,
+from restyle_combat import (ATTACK_PERIMETER_TEXTURE, ATTACK_RAIL_TEXTURE,
+ EFFECT_CHIP, EFFECT_ICON, EFFECT_NAME_WIDTH,
EFFECT_NAME_X, EFFECT_PLATE_BLEED,
EFFECT_ROW_WIDTH, EFFECT_TIMER_FONT,
EFFECT_TIMER_HALF_WIDTH, EXTENDED_TARGET_COUNT,
@@ -36,13 +37,15 @@
COMBAT_SKINS = (SKIN, GLASS_SKIN)
STOCK = Path(r"C:\EQLegends\uifiles\default")
-# Pin the client-native attack contract independently of the generator. This
-# prevents a matching mistake in restyle_combat.py and paint_attack_indicator.py
-# from approving itself. The source slices and RLE texture envelope mirror the
-# known-working EQ Modern implementation; only destination thickness is SpinUI.
+# Pin the client-native attack contract independently of the generator. The
+# white RLE source maximizes the native red phase while EQ owns the cadence.
ATTACK_TEXTURE_SIZE = (128, 32)
-ATTACK_TEXTURE_COLOR = (189, 189, 189, 255)
-ATTACK_EDGE_WIDTH = 8
+ATTACK_TEXTURE_COLOR = (255, 255, 255, 255)
+ATTACK_PERIMETER_COLORS = {
+ (255, 255, 255, 255): 2 * 32 + (128 - 2),
+ (255, 255, 255, 0): 128 * 32 - (2 * 32 + (128 - 2)),
+}
+ATTACK_EDGE_WIDTH = 3
ATTACK_SOURCE_SIZES = {
"A_AttackIndicator": (128, 32),
"A_AttackIndicatorTop": (128, 2),
@@ -52,10 +55,10 @@
"A_AttackIndicatorFill": (128, 32),
}
ATTACK_GEOMETRY = {
- "A_AttackIndicatorAnimTop": (70, 78, 0, 0),
- "A_AttackIndicatorAnimBottom": (10, 2, 0, 0),
- "A_AttackIndicatorAnimLeft": (70, 2, 0, 8),
- "A_AttackIndicatorAnimRight": (70, 2, 8, 0),
+ "A_AttackIndicatorAnimTop": (67, 70, 0, 0),
+ "A_AttackIndicatorAnimBottom": (9, 6, 0, 0),
+ "A_AttackIndicatorAnimLeft": (67, 6, 0, 3),
+ "A_AttackIndicatorAnimRight": (67, 6, 3, 0),
}
ATTACK_ANCHORS = {
"A_AttackIndicatorAnimTop": ("true", "true", "true", "false"),
@@ -194,29 +197,36 @@ def anchored_rect(node: ET.Element, width: int,
def audit_attack_indicator_contract() -> None:
"""Prove every theme/variant keeps a visible native attack perimeter."""
for skin in COMBAT_SKINS:
- texture_path = skin / "AttackIndicator.tga"
- payload = texture_path.read_bytes()
- if len(payload) < 18:
- fail(f"{skin.name} AttackIndicator.tga has no complete TGA header")
- width = int.from_bytes(payload[12:14], "little")
- height = int.from_bytes(payload[14:16], "little")
- if ((width, height) != ATTACK_TEXTURE_SIZE
- or payload[2] != 10
- or payload[16] != 32
- or payload[17] & 0x0F != 8):
- fail(
- f"{skin.name} AttackIndicator.tga lost the proven 32-bit RLE "
- f"envelope (type={payload[2]}, size={width}x{height}, "
- f"depth={payload[16]}, descriptor={payload[17]})"
- )
- with Image.open(texture_path) as source:
- rgba = source.convert("RGBA")
- colors = rgba.getcolors(maxcolors=width * height)
- if colors != [(width * height, ATTACK_TEXTURE_COLOR)]:
- fail(
- f"{skin.name} AttackIndicator.tga is not the solid neutral "
- "native tint source"
- )
+ for texture_name, expected_colors in (
+ (ATTACK_RAIL_TEXTURE,
+ [(128 * 32, ATTACK_TEXTURE_COLOR)]),
+ (ATTACK_PERIMETER_TEXTURE, ATTACK_PERIMETER_COLORS)):
+ texture_path = skin / texture_name
+ payload = texture_path.read_bytes()
+ if len(payload) < 18:
+ fail(f"{skin.name}/{texture_name} has no complete TGA header")
+ width = int.from_bytes(payload[12:14], "little")
+ height = int.from_bytes(payload[14:16], "little")
+ if ((width, height) != ATTACK_TEXTURE_SIZE
+ or payload[2] != 10
+ or payload[16] != 32
+ or payload[17] & 0x0F != 8):
+ fail(
+ f"{skin.name}/{texture_name} lost the 32-bit RLE "
+ f"envelope (type={payload[2]}, size={width}x{height}, "
+ f"depth={payload[16]}, descriptor={payload[17]})"
+ )
+ with Image.open(texture_path) as source:
+ colors = source.convert("RGBA").getcolors(
+ maxcolors=width * height)
+ if isinstance(expected_colors, dict):
+ actual_colors = {
+ color_value: count for count, color_value in (colors or [])
+ }
+ if actual_colors != expected_colors:
+ fail(f"{skin.name}/{texture_name} lost perimeter alpha")
+ elif colors != expected_colors:
+ fail(f"{skin.name}/{texture_name} lost opaque white rail")
for filename in PLAYER_WINDOW_FILES:
path = skin / filename
@@ -227,15 +237,18 @@ def audit_attack_indicator_contract() -> None:
animation = item(root, "Ui2DAnimation", name)
frames = animation.findall("Frames")
if len(frames) != 1:
- fail(f"{label} {name} must have exactly one native frame")
+ fail(f"{label} {name} must have one native frame")
frame = frames[0]
+ expected_texture = (ATTACK_PERIMETER_TEXTURE
+ if name == "A_AttackIndicatorFill"
+ else ATTACK_RAIL_TEXTURE)
if (child_text(animation, "Cycle") != "false"
- or child_text(frame, "Texture") != "AttackIndicator.tga"
+ or child_text(frame, "Texture") != expected_texture
or dimensions_at(frame, "Size") != expected_size
or (child_int(frame, "Location/X"),
child_int(frame, "Location/Y")) != (0, 0)
or frame.find("Duration") is not None):
- fail(f"{label} {name} violates the native source contract")
+ fail(f"{label} {name} violates the native flash contract")
edge_nodes: dict[str, ET.Element] = {}
for name, expected_offsets in ATTACK_GEOMETRY.items():
@@ -259,14 +272,19 @@ def audit_attack_indicator_contract() -> None:
or actual_anchors != ATTACK_ANCHORS[name]):
fail(
f"{label} {name} lost its native state binding or "
- f"8px edge geometry: {actual_offsets} {actual_anchors}"
+ f"outer-seam geometry: {actual_offsets} {actual_anchors}"
)
fill = item(root, "StaticAnimation", "A_AttackIndicatorAnimFill")
if (child_text(fill, "ScreenID") != "A_AttackIndicatorAnimFill"
- or fill.find("Animation") is not None
- or fill.find("AutoDraw") is not None):
- fail(f"{label} attack fill must remain an unbound placeholder")
+ or child_text(fill, "Animation") != "A_AttackIndicatorFill"
+ or child_text(fill, "AutoDraw") != "false"
+ or child_text(fill, "AutoStretch") != "true"
+ or tuple(child_int(fill, tag) for tag in (
+ "TopAnchorOffset", "BottomAnchorOffset",
+ "LeftAnchorOffset", "RightAnchorOffset",
+ )) != (70, 6, 0, 0)):
+ fail(f"{label} attack fill lost its topmost perimeter binding")
window = item(root, "Screen", "PlayerWindow")
if dimensions(window) != (360, 193):
@@ -276,21 +294,44 @@ def audit_attack_indicator_contract() -> None:
)
if minimum != PLAYER_MIN_SIZE:
fail(f"{label} changed the safe minimum size: {minimum}")
- pieces = [(piece.text or "").strip()
- for piece in window.findall("Pieces")]
+ root_pieces = [(piece.text or "").strip()
+ for piece in window.findall("Pieces")]
expected_pieces = [
f"A_AttackIndicatorAnim{edge}"
for edge in ("Top", "Bottom", "Left", "Right", "Fill")
]
- player_subwindow_index = pieces.index("Screen:PlayerSubWindow")
- compositor_slice = pieces[
- player_subwindow_index + 1:player_subwindow_index + 6
- ]
- if (compositor_slice != expected_pieces
- or any(pieces.count(piece) != 1 for piece in expected_pieces)):
+ subwindow = item(root, "Screen", "PlayerSubWindow")
+ subwindow_pieces = [(piece.text or "").strip()
+ for piece in subwindow.findall("Pieces")]
+ if (root_pieces[-5:] != expected_pieces
+ or any(root_pieces.count(piece) != 1
+ for piece in expected_pieces)
+ or any(piece in subwindow_pieces
+ for piece in expected_pieces)):
+ fail(
+ f"{label} attack controls must be unique direct "
+ "PlayerWindow children in the final compositor slot"
+ )
+
+ subwindow_offsets = tuple(child_int(subwindow, tag) for tag in (
+ "TopAnchorOffset", "BottomAnchorOffset",
+ "LeftAnchorOffset", "RightAnchorOffset",
+ ))
+ if subwindow_offsets != (70, 9, 3, 3):
+ fail(
+ f"{label} themed player frame can cover the native "
+ f"attack perimeter: {subwindow_offsets}"
+ )
+
+ buff_window = item(root, "Screen", "PW_BuffWindow")
+ buff_offsets = (
+ child_int(buff_window, "TopAnchorOffset"),
+ child_int(buff_window, "BottomAnchorOffset"),
+ )
+ if buff_offsets != (0, 70):
fail(
- f"{label} attack rails must be unique and immediately "
- "follow PlayerSubWindow in the native compositor slot"
+ f"{label} buff strip can overlap the top attack rail: "
+ f"{buff_offsets}"
)
combat_state = item(root, "Button", "PW_CombatStateAnim")
@@ -304,15 +345,15 @@ def audit_attack_indicator_contract() -> None:
frame_width, frame_height = size
expected_rects = {
"A_AttackIndicatorAnimTop":
- (0, 70, frame_width, 70 + ATTACK_EDGE_WIDTH),
+ (0, 67, frame_width, 70),
"A_AttackIndicatorAnimBottom":
- (0, frame_height - 2 - ATTACK_EDGE_WIDTH,
- frame_width, frame_height - 2),
+ (0, frame_height - 9, frame_width,
+ frame_height - 6),
"A_AttackIndicatorAnimLeft":
- (0, 70, ATTACK_EDGE_WIDTH, frame_height - 2),
+ (0, 67, 3, frame_height - 6),
"A_AttackIndicatorAnimRight":
- (frame_width - ATTACK_EDGE_WIDTH, 70,
- frame_width, frame_height - 2),
+ (frame_width - 3, 67, frame_width,
+ frame_height - 6),
}
actual_rects = {
name: anchored_rect(node, frame_width, frame_height)
@@ -355,6 +396,15 @@ def audit_player_and_target() -> None:
for path in shared_progression_paths:
if child_text(exp, path) != child_text(alt_adv, path):
fail(f"player EXP and AA horizontal rendering differs at {path}")
+ exp_height = (child_int(exp, "BottomAnchorOffset")
+ - child_int(exp, "TopAnchorOffset"))
+ aa_height = (child_int(alt_adv, "BottomAnchorOffset")
+ - child_int(alt_adv, "TopAnchorOffset"))
+ if (exp_height, aa_height) != (10, 11):
+ fail(
+ "player AA gauge must retain its one-pixel fractional-scale "
+ f"weight correction: EXP {exp_height}, AA {aa_height}"
+ )
require_binding(player, "Gauge", "PW_Castspell_Gauge", "PW_Castspell_Gauge", 7)
require_binding(player, "Label", "Player_ManaLabel", "ManaLabel", 1009)
require_binding(player, "Label", "PW_MPNumbers", "PW_MPNumbers", 128)
@@ -1286,7 +1336,7 @@ def main() -> int:
print("Combat Command Center audit: ALL PASS")
print(" Player/Target/ToT | Group 1..11 | XTarget 0..22 | Raid groups 1..12")
print(" buffs 30 | songs 15 | spell gems 14 | hotbars 11 x 12 | stance + invocation")
- print(" 52 compatibility aliases + 14 native 8px attack perimeters + spell ledger")
+ print(" 52 compatibility aliases + 14 foreground native attack perimeters + spell ledger")
print(" contrast AAA/AA | July stock parity " + ("PASS" if stock_checked else "not available"))
return 0
diff --git a/tools/paint_attack_indicator.py b/tools/paint_attack_indicator.py
index 43624a2..de28b29 100644
--- a/tools/paint_attack_indicator.py
+++ b/tools/paint_attack_indicator.py
@@ -1,13 +1,11 @@
#!/usr/bin/env python3
"""Paint SpinUI's client-native auto-attack indicator texture.
-EverQuest owns the visibility and flashing cadence of the four
-``A_AttackIndicatorAnim*`` edge widgets in ``EQUI_PlayerWindow.xml``. The
-texture therefore remains a single, fully opaque neutral frame like the
-working Modern UI contract. EverQuest modulates that neutral source from
-white/gray to red; pre-coloring the source red destroys the visible flash
-because every tint phase remains red. Only narrow edge slices are drawn by
-the XML, and the fill widget is intentionally unbound.
+EverQuest owns the visibility and flashing cadence of the five recognized
+``A_AttackIndicatorAnim*`` widgets in ``EQUI_PlayerWindow.xml``. Narrow edge
+slices use a fully opaque neutral-white rail; the required Fill widget uses a
+transparent-center white perimeter. The client owns attack-on visibility,
+red tint, and flashing cadence.
Run from the repository root:
python tools/paint_attack_indicator.py
@@ -15,32 +13,45 @@
from pathlib import Path
-from PIL import Image
+from PIL import Image, ImageDraw
REPO = Path(__file__).resolve().parent.parent
OUTPUT = REPO / "spinui_reloaded" / "AttackIndicator.tga"
+RAIL_OUTPUT = REPO / "spinui_reloaded" / "SpinAttackRail.tga"
+PERIMETER_OUTPUT = REPO / "spinui_reloaded" / "SpinAttackPerimeter.tga"
FRAME_SIZE = (128, 32)
SIZE = FRAME_SIZE
-EDGE_WIDTH = 8
-# Use the exact neutral source proven by EQ's working Modern UI. The client
-# modulates this gray to its bright neutral/red phases only while attack is on.
-# Pre-coloring it red collapses the modulation, and an uncompressed 32-bit
-# pure-white texture is an unproven legacy-renderer combination.
-COLOR = (189, 189, 189, 255)
+EDGE_WIDTH = 3
+COLOR = (255, 255, 255, 255)
def render() -> Image.Image:
return Image.new("RGBA", SIZE, COLOR)
+def render_perimeter() -> Image.Image:
+ image = Image.new("RGBA", SIZE, (255, 255, 255, 0))
+ draw = ImageDraw.Draw(image)
+ draw.line((0, 0, 0, SIZE[1] - 1), fill=COLOR, width=1)
+ draw.line((SIZE[0] - 1, 0, SIZE[0] - 1, SIZE[1] - 1),
+ fill=COLOR, width=1)
+ draw.line((0, SIZE[1] - 1, SIZE[0] - 1, SIZE[1] - 1),
+ fill=COLOR, width=1)
+ return image
+
+
def main() -> int:
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
- # RLE 32-bit is the known-working Modern TGA envelope. For this solid
- # source Pillow emits a deterministic 204-byte file (type 10, alpha 8).
- render().save(OUTPUT, format="TGA", compression="tga_rle")
+ # Retain the proven 32-bit RLE envelope used by the legacy renderer.
+ rail = render()
+ rail.save(OUTPUT, format="TGA", compression="tga_rle")
+ rail.save(RAIL_OUTPUT, format="TGA", compression="tga_rle")
+ render_perimeter().save(
+ PERIMETER_OUTPUT, format="TGA", compression="tga_rle",
+ )
print(
- "AttackIndicator.tga: native neutral RLE attack rail painted | "
- "8px EverQuest tint-driven pulse | no fill wash"
+ "Spin attack textures: native white rail + transparent-center "
+ "foreground perimeter | client red flash | no fill wash"
)
return 0
diff --git a/tools/restyle_combat.py b/tools/restyle_combat.py
index 286124f..631a0f2 100644
--- a/tools/restyle_combat.py
+++ b/tools/restyle_combat.py
@@ -62,16 +62,18 @@
# The authored 360x193 command frames remain unchanged on first load. Their
# anchored subwindows can safely contract to these Legends-compatible bounds,
# so users may resize them without clipping the command rows.
-PLAYER_MIN_SIZE = (280, 174)
+PLAYER_MIN_SIZE = (280, 193)
TARGET_MIN_SIZE = (260, 174)
# EverQuest recognizes the attack indicator by exact animation and ScreenID
-# names, then owns its attack-on visibility and pulse. Keep the proven stock
-# source slices byte-for-byte compatible and make only the destination rails
-# bolder. Eight screen pixels remains clear at high resolutions without
-# washing over the command-frame contents.
-ATTACK_EDGE_WIDTH = 8
+# names, then owns its attack-on visibility, red tint, and flashing cadence.
+# Preserve that native one-frame contract. The rail occupies a crisp exposed
+# outer seam around the compact subwindow, where opaque themed chrome cannot
+# bury it. Three pixels stays resolution-visible without becoming a fill.
+ATTACK_EDGE_WIDTH = 3
ATTACK_FRAME_SIZE = (128, 32)
ATTACK_TEXTURE_SIZE = ATTACK_FRAME_SIZE
+ATTACK_RAIL_TEXTURE = "SpinAttackRail.tga"
+ATTACK_PERIMETER_TEXTURE = "SpinAttackPerimeter.tga"
ATTACK_SOURCE_SIZES = {
"A_AttackIndicator": ATTACK_FRAME_SIZE,
"A_AttackIndicatorTop": (128, 2),
@@ -465,6 +467,17 @@ def style_player() -> None:
text, "Gauge", name,
show_total_progression_ticks,
)
+
+ def match_aa_gauge_weight(block: str) -> str:
+ # At fractional UI scales the lower AA row loses one rasterized pixel
+ # even with the same authored height as EXP. Give its top edge one
+ # extra source pixel so both progression tracks read at equal weight
+ # in game, without changing the horizontal percentage calculation.
+ return set_value(block, "TopAnchorOffset", 83)
+
+ text = change_item(
+ text, "Gauge", "PW_AltAdvGauge", match_aa_gauge_weight,
+ )
for name, color in (("PW_Level", GOLD_BRIGHT), ("PW_Class", TEXT),
("PW_StanceLabel", GOLD_BRIGHT),
("PW_InvocationInfo", CYAN)):
@@ -499,16 +512,47 @@ def invocation_rail(block: str) -> str:
text = change_item(text, "Label", "PW_StanceLabel", stance_rail)
text = change_item(text, "Label", "PW_InvocationInfo", invocation_rail)
+ # Preserve the stock declaration for schema parity, while animations use
+ # Spin-specific filenames that cannot collide with an already cached skin.
+ stock_info = item_pattern("TextureInfo", "AttackIndicator.tga").search(text)
+ rail_info = item_pattern("TextureInfo", ATTACK_RAIL_TEXTURE).search(text)
+ if stock_info is None and rail_info is not None:
+ compatibility_info = rail_info.group(0).replace(
+ ATTACK_RAIL_TEXTURE, "AttackIndicator.tga", 1,
+ )
+ text = (text[:rail_info.start()] + compatibility_info + "\n\n\t"
+ + text[rail_info.start():])
+ stock_info = item_pattern(
+ "TextureInfo", "AttackIndicator.tga"
+ ).search(text)
+ if stock_info is None:
+ fail("stock attack TextureInfo disappeared")
+ if f'' not in text:
+ rail_block = stock_info.group(0).replace(
+ "AttackIndicator.tga", ATTACK_RAIL_TEXTURE, 1,
+ )
+ text = (text[:stock_info.end()] + "\n\n\t" + rail_block
+ + text[stock_info.end():])
text = change_item(
- text, "TextureInfo", "AttackIndicator.tga",
+ text, "TextureInfo", ATTACK_RAIL_TEXTURE,
lambda b: set_container(
b, "Size", CX=ATTACK_TEXTURE_SIZE[0], CY=ATTACK_TEXTURE_SIZE[1]),
)
-
- def attack_animation(block: str, size: tuple[int, int]) -> str:
- # Match the working native source contract exactly: EverQuest toggles,
- # tints, and flashes these stock-named widgets itself. A custom Cycle
- # can look correct in static audits while never advancing in game.
+ rail_info = item_pattern("TextureInfo", ATTACK_RAIL_TEXTURE).search(text)
+ if rail_info is None:
+ fail("attack rail TextureInfo disappeared")
+ if f'' not in text:
+ perimeter_info = rail_info.group(0).replace(
+ ATTACK_RAIL_TEXTURE, ATTACK_PERIMETER_TEXTURE, 1,
+ )
+ text = (text[:rail_info.end()] + "\n\n\t" + perimeter_info
+ + text[rail_info.end():])
+
+ def attack_animation(block: str, size: tuple[int, int],
+ texture: str) -> str:
+ # Match the client-owned attack state contract exactly. Custom cycles
+ # do not advance reliably while these AutoDraw=false widgets are under
+ # state control and suppress the game's native flash.
block = set_value(block, "Cycle", "false")
block = re.sub(r"\n\t\t