Elaborate color explanation
Information about how player colors are processed exactly by Armagetron is scarce. The purpose of this article is to change that. I assumed certain data types, but I think Armagetron (especially the networking) does as well.
Player color entry
Normally, when entered in the player setup menu, colors are RGB triplets in the range 0..15. Players have found that they can get multi-color walls that are brighter than the cycle by manually setting COLOR_<R, G, or B>_<player number> out of that range, using the console or by editing the configuration files. These settings are 32-bit signed integers with range -2147483648..2147483647.
When a color is absorbed from the configuration items and stored in a player it is truncated to three 16-bit unsigned integers with range 0..65535. There is no benefit to choosing a color outside of that range in the configuration item. -65536 simply becomes 0, just like 65536 and 131072. -65535 and 65537 become 1, etc. I call this the short color after the short data type in C.
The short color is then converted to 32-bit IEEE 754 floating-point, where 0..1 is the normal range. How that happens exactly depends on whether a team game is being played, but in both cases colors can be clamped to 0..15 beforehand. That has been added mainly because overflows could result in drastic deviations from the team color. FIXME: is this entirely true and what is the config item? I only have old code.
The float color is simply the short color divided by 15.
In a team game the short color is combined with the team color which is another short color. It appears to be built around a balancing constant, an RGB triplet which specifies how much of the player's color is used instead of the team's. Its value is R=2 G=1 B=2. The calculation is:
- OR = (BRPR + BSTR) / (15BS + 15BR)
- OG = (BGPG + BSTG) / (15BS + 15BG)
- OB = (BBPB + BSTB) / (15BS + 15BB)
O is the output color, B is the balancing constant, P is the player color and T is the team color. Element S is the sum R+G+B=5. It could be a separate value, and it is, but both its name and its value suggest it is a sum.
Standard team colors
For your information, here is a table of the hardcoded team colors.
Note that if at least 50% of all players on a team have "Name Team after Player" set (bots and the leader are an implicit no, but are not excluded), the team will be given the leader's color and name. The leader in team naming/coloring context is the human who has been on his team for the longest time, or bot if there is none. See also Code hacks#Hardcoded teams.
Floor color avoidance
Armagetron has a mechanism that prevents colors from coming too close to the floor color. When a color is too close, it will be brightened until it's no longer close to the floor color or approaches white.
We start off with several variables and a constant:
- The color.
- The floor color.
- Some value specifying the degree of avoidance.
- Sum of C's values, recalculated at the start of every loop.
- Always 1/45.
I admit choosing names which only differ in case isn't very good, but they're partly based on names used in the game.
To enter the loop, the following condition must be true: (CR < 0.95 AND CG < 0.95 AND CB < 0.95) AND ((|FR - CRf| + |FG - CGf| + |FB - CBf| < 0.5) OR (|CRf| + |CGf| + |CBf| < 0.5)). The loop is:
- S = CR + CG + CB
- (The game only adds a component if it is < 0.99, but that is implied by the loop condition of < 0.95.)
- If S < 0.02
- CR = CR + s
- CG = CG + s
- CB = CB + s
- Else (S ≥ 0.02)
- CR = CR + sCR/S
- CG = CG + sCG/S
- CB = CB + sCB/S
- CR = min(CR, 1)
- CG = min(CG, 1)
- CB = min(CB, 1)
- If the aforementioned condition is still true, enter the loop again.
C is the resulting color.
The text color is the floating-point color, multiplied with 255 and converted to an 8-bit unsigned integer (0..255) by rounding toward zero and clamping in case of overflow. This is then put in a 0x color code.
The cycle color is the floating-point color, passed through the floor color avoidance with f=1. This color will then be multiplied with 255, and converted to an 8-bit unsigned integer (0..255) by rounding toward zero and wrapping in case of overflow. The resulting color is then blended behind the cycle texture:
- TR = (TATR + (255 - TA)CR) / 256
- TG = (TATG + (255 - TA)CG) / 256
- TB = (TATB + (255 - TA)CB) / 256
- TA = 255
T is the texture color, and A is the alpha channel.
The wall color is the floating-point color, passed through the floor color avoidance with f=0.5. This color will be multiplied with 0.7..1 for every wall, depending on lighting. It is then passed to OpenGL which clamps it to 0..1, and multiplies the wall texture with it.
There are several ways to get multiple colors.
- Due to different overflow behaviors, it is possible to have different cycle and wall colors. The cycle color wraps around, but the wall color will only get brighter in a limited way.
- Because the wall color is lit before it is clamped, walls placed in different directions can have different colors when there's a slight overflow.
It should be noted that this behavior is technically a bug and unsupported. It is merely tolerated.
The viewer's monitor's.