ID:1186336
 
Keywords: color, colour, rgb, scale
(See the best response by DarkCampainger.)
Code:
        proc
updateHealth()
if(src.client)
for(var/obj/HUD/Health/a in client.screen)
a.icon = (a.icon | rgb(health, 0, 0, 0))


Problem description:

I'd like to colour a HUD object on the player's screen to represent how 'healthy' they are. I've tried:
a.icon += rgb(health,0,0)

and whilst that coloured them when they were injured , it didn't uncolour them when they were injured (and -=rbg() did nothing either).

I've searched around a lot to no avail, even trying CaptFalcon's: http://www.byond.com/forum/?post=195047&hl=set%20rgb

CaptFalcon's let me set the colour however I wanted, but I couldn't then Scale it (The HUD object is scaled up from 32,32 to 96,96).

I'm struggling to use both rgb() and Scale appropriately. Why is it that I can't do "src.icon.Scale(X,Y)"? I wish I could create a var, set it to any icon (src.icon or var/icon/I or whatever) and it would replicate/copy it's size, rgb, e.t.c., maybe even overlays too.

Ignoring the rant; how can I set a HUD's icon to specific colours without changing it's Scale?
The issue is that you're repeatedly blending the color with the current icon, compounding the change instead of really "setting" it. You need to start fresh with the original icon each time for it to work properly. You can see CaptFalcon's snippet doing that with tmp_icon.

Also, you might want to check out Lummox JR's IconProcs library/article. It offers some interesting effects that you may be interested in.

I'm not sure what you mean by the second part of your post, but keep in mind that the atom/icon variable actually holds an RSC cache reference and not a /icon object:
When this variable is assigned to any dynamically created icon object, that object gets dumped into the world's resource cache (the .rsc file), and a reference to that cached file is assigned to atom.icon.

If you want to Blend(), Scale(), ect on an icon, you need to create your own /icon object and not use the atom's icon variable.

You may also be interested in this: GetFlatIcon. I just found a bug in it, but once I fix that, it sounds like it might do what you want.
I've noticed CaptFalcon using tmp_icon, but had some issues with doing it that way. I wish I hadn't slept between posting this Developer Help post and trying to reply now, as I can barely remember any thing =P

"If you want to Blend(), Scale(), ect on an icon, you need to create your own /icon object and not use the atom's icon variable."
- I'm beginning to realise this, but it really sucks (in my opinion). It makes it nigh-impossible to get an exact copy of the player's (or any!) icon after it's been in use for a while and had a few Scale()s and Blend()s and such applied to it.

I've looked at Lummox Jr's IconProcs for a fair few hours, and a lot of tinkering ended up with me just going in circles, spiraling in to the ground =P

GetFlatIcon looks like something I would have -killed- for a fortnight ago before I found a work-around for the exact same thing.

Thank you very much for the advice; I'll have another go at this and when I've got my thoughts in order I'll return to hopefully make a little more sense.
I've had some thoughts about storing the exact transformations done to an icon in a sort of bytecode, and naming icons via unique functions to store them in a pool. That way, when loading the icon datum from a savefile, it can be instructed to recreate the icon and reassign it to a global unique name. I just have to write a wrapper for the icon datum. I'll put it on my todo list for the week.
Why does this error saying "runtime error: Cannot execute null.Scale()."


                        var/icon/tempIcon
tempIcon = initial(a.icon)
//a.icon = (tempIcon | rgb(200, 0, 0, 0))
tempIcon.Scale(96,96)


I swear I have tried every configuration of ASCII characters in the known universe trying to get this to work, and every time either the icon|rgb or the Scale() throws a tiff.

Another attempt:
                        var/icon/tempIcon
tempIcon =icon(icon=src.icon,icon_state="",dir=SOUTH,frame = 1)
a.icon = (tempIcon | rgb(200, 0, 0, 0))



yielded this error: "runtime error: type mismatch: /icon (/icon) | "#c8000000"
proc name: updateHealth"
a is a relatively standard obj, and src is a /mob/Player which has a client, FYI.
You're forgetting to use new() (or icon(...) which is the same as icon = new(...)), so you're never actually creating an instance of the icon object, just a variable that points to absolutely nothing. In the second snippet you're actually creating the icon object but trying an invalid icon operation on it.

var/icon/tempIcon = icon(src.icon,dir=SOUTH,frame=1)
tempIcon += rgb(200,0,0,0)
a.icon = tempIcon


Or if you want more control over how the color is blended in use icon.Blend().

Your first snippet will work with the = icon(...) part, but you still need to set a.icon to tempIcon to see the effect.
I'm not exactly 'forgetting' it, just attempting any other variation of code after literally dozens of earlier more correct attempts.

Using the code you kindly suggested I still get the error: "runtime error: type mismatch: /icon (/icon) += "#c8000000"
proc name: updateHealth "

So the (expanded) code I now have is:
mob
Player
proc
updateHealth()
if(src.client)
for(var/obj/HUD/Health/a in client.screen)
var/icon/tempIcon = icon(src.icon,dir=SOUTH,frame=1)
tempIcon += rgb(200,0,0,0)
//tempIcon.Scale(96,96)
a.icon = tempIcon


This should be such a simple thing, and I'm having -such- issues with it :'( Really beginning to have a sense-of-humour failure.
Best response
The issue you're having relates back to my previous post. Basically, there are two different sets of icon operations: those that operate on a cache reference (such as src.icon), and those that operate on a /icon object (such as icon(src.icon)).

The basic operators ( + | & ) only work on a RSC cache reference, such as the one stored in src.icon and returned by fcopy_rsc(), and return a cache reference (to the dynamic RSC):
src.icon += rgb(200,0,0)
src.icon |= rgb(200,0,0)
src.icon &= rgb(200,0,0)
src.icon &= 'OtherIcon.dmi'


The /icon procs work only on /icon objects:
var/icon/I = icon(src.icon,dir=SOUTH,frame=1)
I.Blend(rgb(200,0,0,0), ICON_ADD)
I.Scale(96, 96)
a.icon = I


So you should choose one set or the other (otherwise you have to keep using fcopy_rsc() and icon() to convert between them, which is wasteful). Since you need Scale(), I would stick with /icon objects.
And it works! Perfectly! No errors, actual result=intended result, e.t.c.

Thank you so much DarkCampainger. I thoroughly read your previous post, but I guess it just didn't "click" properly in my head. But now, not only does it work, but I think I have a -much- better understanding of icons in general.

Thank you all, so much. I really appreciate it.