Changeset View
Standalone View
binaries/data/mods/public/simulation/components/StatusBars.js
const g_NaturalColor = "255 255 255 255"; // pure white | const g_NaturalColor = "255 255 255 255"; // pure white | ||||
function StatusBars() {} | function StatusBars() {} | ||||
StatusBars.prototype.Schema = | StatusBars.prototype.Schema = | ||||
"<element name='BarWidth'>" + | "<element name='BarWidth'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='BarHeight'>" + | "<element name='BarHeight' a:help='Height of a normal sized bar. Some bars are scaled accordingly.'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='HeightOffset'>" + | "<element name='HeightOffset'>" + | ||||
"<data type='decimal'/>" + | "<data type='decimal'/>" + | ||||
"</element>"; | "</element>"; | ||||
elexis: ^ | |||||
Not Done Inline ActionsHeightOffset missing, normal is undefined, also I suppose the experience bar is normal too elexis: HeightOffset missing, normal is undefined, also I suppose the experience bar is normal too | |||||
Done Inline ActionsI think I was updating the diff while you commented. Imarok: I think I was updating the diff while you commented. | |||||
Done Inline ActionsFine? Imarok: Fine? | |||||
Not Done Inline Actions"Height of a normal sized bar" doesn't tell us which of the three bars are refered to, so why not just refer to "size of the health and capture bar" and that "size of experiencebar" is scaled proportionally by a factor of 2/3, then everyone knows what's happening. Would be good to have HeightOffset defined (at least we must know it's definition already in order to decide the correctness of the patch, so the only effort now is phrasing it). elexis: "Height of a normal sized bar" doesn't tell us which of the three bars are refered to, so why… | |||||
Done Inline ActionsImho that are internals irrelevant for the normal template editer. Imarok: Imho that are internals irrelevant for the normal template editer.
Also if we are too specific… | |||||
/** | /** | ||||
* For every sprite, the code will call their "Add" method when regenerating | * For every sprite, the code will call their "Add" method when regenerating | ||||
* the sprites. Every sprite adder should return the height it needs. | * the sprites. Every sprite adder should return the height it needs. | ||||
* | * | ||||
* Modders who need extra sprites can just modify this array, and | * Modders who need extra sprites can just modify this array, and | ||||
* provide the right methods. | * provide the right methods. | ||||
*/ | */ | ||||
StatusBars.prototype.Sprites = [ | StatusBars.prototype.Sprites = [ | ||||
"ExperienceBar", | |||||
"PackBar", | "PackBar", | ||||
"ResourceSupplyBar", | "ResourceSupplyBar", | ||||
"CaptureBar", | "CaptureBar", | ||||
"HealthBar", | "HealthBar", | ||||
"AuraIcons", | "AuraIcons", | ||||
Done Inline ActionsWhy not a full name? ExperienceBar, it's even shorter than ResourceSupplyBar and it saves the naming. vladislavbelov: Why not a full name? `ExperienceBar`, it's even shorter than `ResourceSupplyBar` and it saves… | |||||
"RankIcon" | "RankIcon" | ||||
]; | ]; | ||||
StatusBars.prototype.Init = function() | StatusBars.prototype.Init = function() | ||||
{ | { | ||||
this.enabled = false; | this.enabled = false; | ||||
this.showRank = false; | this.showRank = false; | ||||
this.showExperience = false; | |||||
// Whether the status bars used the player colors anywhere (e.g. in the capture bar) | // Whether the status bars used the player colors anywhere (e.g. in the capture bar) | ||||
this.usedPlayerColors = false; | this.usedPlayerColors = false; | ||||
this.auraSources = new Map(); | this.auraSources = new Map(); | ||||
}; | }; | ||||
/** | /** | ||||
* Don't serialise this.enabled since it's modified by the GUI. | * Don't serialise this.enabled since it's modified by the GUI. | ||||
*/ | */ | ||||
StatusBars.prototype.Serialize = function() | StatusBars.prototype.Serialize = function() | ||||
{ | { | ||||
return { "auraSources": this.auraSources }; | return { "auraSources": this.auraSources }; | ||||
}; | }; | ||||
StatusBars.prototype.Deserialize = function(data) | StatusBars.prototype.Deserialize = function(data) | ||||
{ | { | ||||
this.Init(); | this.Init(); | ||||
this.auraSources = data.auraSources; | this.auraSources = data.auraSources; | ||||
}; | }; | ||||
StatusBars.prototype.SetEnabled = function(enabled, showRank) | StatusBars.prototype.SetEnabled = function(enabled, showRank, showExperience) | ||||
{ | { | ||||
// Quick return if no change | // Quick return if no change | ||||
if (enabled == this.enabled && showRank == this.showRank) | if (enabled == this.enabled && showRank == this.showRank && showExperience == this.showExperience) | ||||
return; | return; | ||||
this.enabled = enabled; | this.enabled = enabled; | ||||
this.showRank = showRank; | this.showRank = showRank; | ||||
this.showExperience = showExperience; | |||||
// Update the displayed sprites | // Update the displayed sprites | ||||
this.RegenerateSprites(); | this.RegenerateSprites(); | ||||
}; | }; | ||||
StatusBars.prototype.AddAuraSource = function(source, auraName) | StatusBars.prototype.AddAuraSource = function(source, auraName) | ||||
{ | { | ||||
if (this.auraSources.has(source)) | if (this.auraSources.has(source)) | ||||
Show All 29 Lines | |||||
}; | }; | ||||
StatusBars.prototype.OnPackProgressUpdate = function(msg) | StatusBars.prototype.OnPackProgressUpdate = function(msg) | ||||
{ | { | ||||
if (this.enabled) | if (this.enabled) | ||||
this.RegenerateSprites(); | this.RegenerateSprites(); | ||||
}; | }; | ||||
StatusBars.prototype.OnExperienceChanged = function() | |||||
{ | |||||
if (this.enabled) | |||||
this.RegenerateSprites(); | |||||
}; | |||||
StatusBars.prototype.UpdateColor = function() | StatusBars.prototype.UpdateColor = function() | ||||
{ | { | ||||
if (this.usedPlayerColors) | if (this.usedPlayerColors) | ||||
this.RegenerateSprites(); | this.RegenerateSprites(); | ||||
}; | }; | ||||
StatusBars.prototype.RegenerateSprites = function() | StatusBars.prototype.RegenerateSprites = function() | ||||
{ | { | ||||
let cmpOverlayRenderer = Engine.QueryInterface(this.entity, IID_OverlayRenderer); | let cmpOverlayRenderer = Engine.QueryInterface(this.entity, IID_OverlayRenderer); | ||||
cmpOverlayRenderer.Reset(); | cmpOverlayRenderer.Reset(); | ||||
let yoffset = 0; | let yoffset = 0; | ||||
for (let sprite of this.Sprites) | for (let sprite of this.Sprites) | ||||
yoffset += this["Add" + sprite](cmpOverlayRenderer, yoffset); | yoffset += this["Add" + sprite](cmpOverlayRenderer, yoffset); | ||||
}; | }; | ||||
// Internal helper functions | // Internal helper functions | ||||
/** | /** | ||||
* Generic piece of code to add a bar. | * Generic piece of code to add a bar. | ||||
*/ | */ | ||||
StatusBars.prototype.AddBar = function(cmpOverlayRenderer, yoffset, type, amount) | StatusBars.prototype.AddBar = function(cmpOverlayRenderer, yoffset, type, amount, heightMultiplier = 1) | ||||
Not Done Inline ActionsAbout the default: About the semantics of the heightMultiplier argument: I wonder if the not-only-simulation template shouldn't specify the size of the three bars, rather than hardcoding the 2/3*healthBarSize here for every unit while every unit can change the number of the health bar size individually? (Then again not convinced that templates should store data for the pyrogenesis GUI that a second GUI may want to do differently, meh) elexis: **About the `default`:**
defaults are ok if they are the most straight forward option - in some… | |||||
Done Inline ActionsWe have 4 function calls. 3 with the default argument, so I'd say the default is legit. But if you insist, I can change that... Imarok: We have 4 function calls. 3 with the default argument, so I'd say the default is legit. But if… | |||||
Not Done Inline Actions
If I would insist I would have had clicked on requested changes. I don't care about these 3 lines, but the recognition of the possible disadvantages of default arguments that do not occur before the pattern was already extensively used. At least in rmgen there were a load of problems because defaults that are expected by the users were used, then it accumulated into an unreadable mess. These are only two cases #4989, rP21728, another one was the hardcoding of the tileclasses like clWood in the placement helper functions (which broke maps that wanted to not use the exact same variable names or didn't use some tileclasses). Maybe there is a reason that there are almost no default argumens in the simulation, but maybe it's just coincidence... Other than that there is still the point that if the template is supposed to determine the position and size of the health status bar, it seems contradictory that the simulation code and not the template would determine the position and size of the other status bar. (I personally don't insist or really care about that either though) elexis: > But if you insist, I can change that...
If I would insist I would have had clicked on… | |||||
{ | { | ||||
// Size of health bar (in world-space units) | // Size of health bar (in world-space units) | ||||
let width = +this.template.BarWidth; | let width = +this.template.BarWidth; | ||||
let height = +this.template.BarHeight; | let height = +this.template.BarHeight * heightMultiplier; | ||||
Not Done Inline Actionsack bb: ack | |||||
// World-space offset from the unit's position | // World-space offset from the unit's position | ||||
let offset = { "x": 0, "y": +this.template.HeightOffset, "z": 0 }; | let offset = { "x": 0, "y": +this.template.HeightOffset, "z": 0 }; | ||||
// background | // background | ||||
cmpOverlayRenderer.AddSprite( | cmpOverlayRenderer.AddSprite( | ||||
"art/textures/ui/session/icons/" + type + "_bg.png", | "art/textures/ui/session/icons/" + type + "_bg.png", | ||||
{ "x": -width / 2, "y": yoffset }, | { "x": -width / 2, "y": yoffset }, | ||||
Show All 9 Lines | cmpOverlayRenderer.AddSprite( | ||||
{ "x": width * (amount - 0.5), "y": height + yoffset }, | { "x": width * (amount - 0.5), "y": height + yoffset }, | ||||
offset, | offset, | ||||
g_NaturalColor | g_NaturalColor | ||||
); | ); | ||||
return height * 1.2; | return height * 1.2; | ||||
}; | }; | ||||
StatusBars.prototype.AddExperienceBar = function(cmpOverlayRenderer, yoffset) | |||||
Not Done Inline ActionsStill think that yoffset and the hardcoded 2/3 is a workaround / hack. Why does the StatusBars template specify the BarWidth, BarHeight, HeightOffset of the one bar but not of the other bar that uses a different BarHeight and HeightOffset? If we do a filesearch for <StatusBars>, we see that 74 templates specify different numbers. That the same hack was used for Capture bars doesn't bring us closer to fixing it if we keep adding to the workarounds but only makes it more work to fix for later, no? If you commit it I won't raise a concern, but the clean implementation is different from what I've seen so far. I guess it should be <StatusBars> <HealthBar> <BarWidth>... <BarHeight>... <HeightOffset>... </HealthBar <CaptureBar>... ... </StatusBars> Cleaning that however would require touching of all templates with StatusBars. That's what one can refer to when picking a reason not to do it now. elexis: Still think that yoffset and the hardcoded 2/3 is a workaround / hack.
Why does the StatusBars… | |||||
Done Inline ActionsThe template specifies the general size and position of all status bars above that entity. Imarok: The template specifies the general size and position of all status bars above that entity.
I… | |||||
Not Done Inline ActionsStatusBars.prototype.Schema doesn't actually define what it should be. The point is that the 2/3 number of the bars is considerably not an internal logic constant with inherent universal truth to it, but as much as a userchosen number like the other user chosen magic numbers that depend on the specific entity and are expressed in the template. The benefit of hardcoding the 2/3 is that one doesn't have to specify it in templates, which can make it less error prone, easier to manage; but perhaps there are some entities for which 2/3 isn't the best number? For example some entities have smaller status bars, the numbers were specified for health bars. Someone could have chosen a number that is so small that it's just right for health bars, but 2/3 * healthbar size would be too small for the template authors taste. 2/3 just smells like a magic number, and one that even obfuscates other hardcodings like the offset. As mentioned there might be no relevant vanilla 0ad entities that are use cases, since mostly animals have different status bars from what I recall, and animals don't have experience bars. Perhaps we one can construct an example use case of an entity where the hardcoded layout fails. The question is, why is the user granted the freedom to edit BarWidth, BarHeight and HeightOffset, but not the freedom to change the 2/3 and experience bar offset. StatusBars.prototype.Schema should receive the definition of that, so that we actually start documenting what the properties are supposed to change. So if you as the author and commiter decides for the fixed layout, BarWidth, BarHeight would relate to the size of the Health and Capture bar, and should state that the experience bar is scaled down proportionally, and HeightOffset being the vertical distance from the entities position (at the foot of the unit?) Just as a mathmatical consequence of the patch, adding a new experience bar of the size 2/3*BarWidth below the HeightOffset might make it possible for one entity to have it's head overlap with the newly added status bar. So one should check that this doesn't happen with the vanilla entities, but then again I think none of the entities were affected because animals don't have experience bars, and most of the bars of units are probably far enough away (one could ensure). Anyway, your choice as the author and committer to disregard those mere 3 bytes in the file that would take some time to get rid of, which can still be done by the hypothetical future 2/3 editor. elexis: `StatusBars.prototype.Schema` doesn't actually define what it should be.
The point is that the… | |||||
Done Inline ActionsThe Schema properties are used to set the size of a usual bar. I see no problem in always scaling the experience bar to 67% the size of a normal bar.
The experience bar is added above HeightOffset Imarok: The Schema properties are used to set the size of a usual bar. I see no problem in always… | |||||
Not Done Inline ActionsThen it might be wrong if there is negative HeightOffset somewhere, which I guess we don't have. elexis: Then it might be wrong if there is negative HeightOffset somewhere, which I guess we don't have. | |||||
Done Inline ActionsDon't get what you mean. Imarok: Don't get what you mean. | |||||
Not Done Inline ActionsThat there is a mathmatical possibility that an entity template exists for which 2/3 is not the best, or even a wrong magic number. Vice versa a proof that none such number can exist for all HeightOffset values ("decimal") would be part of a verification of this patch. elexis: That there is a mathmatical possibility that an entity template exists for which 2/3 is not the… | |||||
Done Inline ActionsI still don't get what HeightOffset should have to do with 2/3 which is a BarHeight scaling. Imarok: I still don't get what HeightOffset should have to do with `2/3` which is a BarHeight scaling. | |||||
{ | |||||
if (!this.enabled || !this.showExperience) | |||||
return 0; | |||||
let cmpPromotion = Engine.QueryInterface(this.entity, IID_Promotion); | |||||
if (!cmpPromotion || !cmpPromotion.GetCurrentXp() || !cmpPromotion.GetRequiredXp()) | |||||
return 0; | |||||
return this.AddBar(cmpOverlayRenderer, yoffset, "pack", cmpPromotion.GetCurrentXp() / cmpPromotion.GetRequiredXp(), 2/3); | |||||
Not Done Inline ActionsForgot to mention that the 2/3rd could also be moved to a constant (at least Vladislav raises that point often in C++ code), (but then the other constants that are currently 1 could become editable too, and it could also be moved to the template) elexis: Forgot to mention that the 2/3rd could also be moved to a constant (at least Vladislav raises… | |||||
}; | |||||
StatusBars.prototype.AddPackBar = function(cmpOverlayRenderer, yoffset) | StatusBars.prototype.AddPackBar = function(cmpOverlayRenderer, yoffset) | ||||
{ | { | ||||
if (!this.enabled) | if (!this.enabled) | ||||
return 0; | return 0; | ||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
if (!cmpPack || !cmpPack.IsPacking()) | if (!cmpPack || !cmpPack.IsPacking()) | ||||
return 0; | return 0; | ||||
▲ Show 20 Lines • Show All 140 Lines • Show Last 20 Lines |
^