ID:159203
 
Ah, the more I learn, the more it seems I don't know. Isn't that always the way?

In any case, I'm trying to work smarter, not harder, and if I can pull this off it would be awesome as it would save a lot of content generation work. Here's the code:

    /* RebuildIcon()
Created in mind of actually dynamically creating a character icon reflecting
various directions and equipment states. */

proc/RebuildIcon()
var/icon/baseIcon = icon('imgMobPlayer.dmi',"default")
var/icon/changeIcon

// baseIcon.Turn(45) // This works - my eventual goal is to make an 8-directional icon

// Unfortunately, I can't seem to make even a four-directional icon
changeIcon = new('imgMobPlayer.dmi',"default")
baseIcon.Insert(changeIcon,"default",dir=EAST)
changeIcon.Turn(90)
baseIcon.Insert(changeIcon,"default",dir=SOUTH)
changeIcon = new('imgMobPlayer.dmi',"default")
changeIcon.Turn(180)
baseIcon.Insert(changeIcon,"default",dir=WEST)
changeIcon = new('imgMobPlayer.dmi',"default")
changeIcon.Turn(270)
baseIcon.Insert(changeIcon,"default",dir=NORTH)

icon = baseIcon


What I want it to do: Take a single frame, single-directional icon (with only one facing) and, from this, use code to generate an 8 directional icon, then assign it to the mob under a the single icon variable.

What I seem to be getting: the single frame, single directional icon I started with.

My question: what mistake am I making that is preventing this code from creating four directions in a dynamically created icon?

Seeing how that baseIcon.Turn seems to work just fine, there are workarounds - such as having 8 variables for each direction or just reassigning the icon and turning it each time the character moves - but they're bloaty. A single icon variable with working directions is my goal.

Yes, I've seen the reference and ran a search over existing resources with "icon" as a keyword (and was predictably flooded).
The problem is that you're keep resetting the changeIcon (the = new part).

The following was not tested, may require a bit of tweaking.
    proc/RebuildIcon()
var/icon/baseIcon = icon('imgMobPlayer.dmi',"default")
var/icon/changeIcon = new('imgMobPlayer.dmi',"default")

for(var/i=1 to 4)
var/ndir = 0
switch(i)
if(1) ndir = NORTH
if(2) ndir = EAST
if(3) ndir = SOUTH
if(4) ndir = WEST
baseIcon.Insert(changeIcon,"default",dir = ndir)
changeIcon.Turn(90)

icon = baseIcon
In response to GhostAnime
It's true I kept resetting the changeIcon, but this shouldn't be problematic because I kept turning it by an increased amount.

I tried your code, and now the icon seems blank. This is an earlier problem I ran into and the decision why I kept resetting the changeIcon - a possible cause is trying to re-use the same memory space across multiple states.

I wouldn't call it the dynamic icon creation holy grail if it were that easy. Seems I stumped the forum on this one.

A good and effective workaround is just to rebuild the icon facing north, and then create a copy of this icon and Turn it before reassigning it to the mob every time you want to do the update.

It's a pity we couldn't find an answer though, it'd be much handier to just have dynamically constructed 8-dir icons.
In response to Geldonyetich
Suuuure, give up on the forum just like your last blog implies that you may have given up on the strategic focus of your game. It's only been a day, roleplayer. ;)

You told Insert() to create the extra directions in the "default" icon state. However, icon_state is set to an empty string, "", by default. That's also the only state in baseIcon after the icon() call and before the Insert() call. It's the the single directional picture you started with.

I plugged your code under a mob. Other than the redundancies, it works fine. You appear to be looking at the wrong state. You can set the src's icon_state to "default", but you probably want to make the Insert() calls with "" instead.

As for 8 directions, I'd recommend creating one diagonal frame on your own since angles other than multiples of 90 degrees will end up distorted. It's just the nature of pixel art (and one reason why I prefer to work with vectors). =)
In response to ACWraith
ACWraith wrote:
Suuuure, give up on the forum just like your last blog implies that you may have given up on the strategic focus of your game. It's only been a day, roleplayer. ;)

I like to think of it as just putting through another level of refinement. ;) What I'm probably going to end up with is more of an Adventure/RPG/Strategy game, along my current vein.

You told Insert() to create the extra directions in the "default" icon state. However, icon_state is set to an empty string, "", by default. That's also the only state in baseIcon after the icon() call and before the Insert() call. It's the the single directional picture you started with.

I plugged your code under a mob. Other than the redundancies, it works fine. You appear to be looking at the wrong state. You can set the src's icon_state to "default", but you probably want to make the Insert() calls with "" instead.

As for 8 directions, I'd recommend creating one diagonal frame on your own since angles other than multiples of 90 degrees will end up distorted. It's just the nature of pixel art (and one reason why I prefer to work with vectors). =)

So, if I'm reading this right... all I needed to do was set icon_state = "default" after assigning the icon?

I knew it was something simple and easily overlooked, as coding problems oft are, but that's so simple as to invoke genuine sheepishness. :P I did have the icon_state set to "default" in the mob/player.New(), and I didn't realize I'd need to set it again if I'm reassigning the icon.

(I'm trying to preserve having multiple states for the icon, so I'd want to keep the "default" for the "doing nothing" state, and I'd move on to rebuild other states for things such as "moving".)
In response to Geldonyetich
Geldonyetich wrote:
So, if I'm reading this right... all I needed to do was set icon_state = "default" after assigning the icon?

Not quite. If I remember how this works correctly, then the following is true.

If icon_state is not set (or, if set incorrectly, though I don't remember for sure on that one), you use the icon state called "" in the dmi file. That is, icon state without a name (named ""), is the default icon state for a dmi file.

Now, your icon might have an icon state in it that you call "default" and that's all well and good, and you can use that as default if you want, setting object.icon_state="default" However, as soon as you do the following:
var/icon/myIconVar = new ('myIcon.dmi', "myIconState")
,
you are creating a new icon object that represents ONLY "myIconState" icon state in 'myIcon.dmi' That is, myIconVar references a newly created icon that has 1 single icon state in it, that icon state is the default one (called "") and it has the graphical data that "myIconState" icon state from 'myIcon.dmi' had.

Remember, new('myIcon.dmi', "myIconState") does not return the myIcon.dmi icon, it returns a new icon with the same (or almost the same, since you specify an icon state as well) data.

So, if you want to insert into myIconVar in my example, you need to insert into icon state "", the default icon state, since it has no other icon states at all, "default" or otherwise.

If you want to return an icon object that has all the data that a dmi file has, use new('myIcon.dmi') (that is, don't specify an icon state.) When you do this, your "default" icon state will still be called "default" in the new icon object, and it will also preserve all icon states that the original icon had. However, if you only want to extract the icon state, manipulate it, then insert that icon state back into the original icon in some manner, then you don't need to preserve any of the extra-baggage data.
In response to Loduwijk
Loduwijk wrote:
If icon_state is not set (or, if set incorrectly, though I don't remember for sure on that one), you use the icon state called ""

Yes, this is generally the case, and so I assume it to be here as well. If you use a non-existent (in the icon) icon_state, it defaults to the blank state, if any.
In response to Loduwijk
Ah - there might have been some confusion there.

I do have an icon_state named "default" - I was aware that it will use an icon_state of "" by default, but I had called the state I was working with "default" because I wanted to remove any ambiguity.

Sure, it's redundant, but lets say I wanted to do that. What then? That I used "default" as a state_name shoudn't have changed anything unless Include() has a problem with adding states that aren't "".
In response to Geldonyetich
Geldonyetich wrote:
That I used "default" as a state_name shoudn't have changed anything unless Include() has a problem with adding states that aren't "".

You using an icon_state called "default" will not effect anything at all under normal circumstances. It will, as there is no reason it shouldn't, act just like any other icon state.

The problem arrises when you extract an icon state from an icon, creating a new icon object with a single icon state, "", which has the graphical data of the icon state extracted from the original.

For example...

Let's say you have icon 'myDMI.dmi' which has an icon state that is not named (left as ""), and the icon state represents a red line. 'myDMI.dmi' also has an icon state called "pi" that is a blue square, and one called "pi are not squared" that is a green circle.
proc/iconTester()
var/icon
I1 = new('myDMI.dmi')
I2 = new('myDMI.dmi', "pi are not squared")

I1 now references an icon object that represents 'myDMI.dmi' in all respects.

Because you specified an icon state, I2 now represents an icon which does NOT represent 'myDMI.dmi' accurately.

I1 is an icon object that has the following icon states and representations:
"" = red line
"pi" = blue square
"pi are not squared" = green circle

But I2 is an icon that has the following icon states:
"" = green circle

That is all that I2 has in it.

So, in your code, when you do the following
var/icon/baseIcon = icon 'imgMobPlayer.dmi',"default")
changeIcon = new('imgMobPlayer.dmi',"default")

baseIcon and changeIcon both represent icon objects with a single icon state. Both of them have only the icon state "", and the icon state "" in them has the graphical data of imgMobPlayer.dmi's "default" icon state.
In response to Loduwijk
Ah, I think I'm beginning to get this, thanks for the patience clarification.

To recap, in using the icon() proc (or the new() proc as pertains to icons) and specifying both the file and the icon_state (most importantly the icon state) what is returned is an icon with only that one state except now under the name of "" instead of the state name.

So, if I'm understanding this right, a large reason why my rebuilt icon didn't show up after I reassigned it wasn't because I forgot the add the icon_state of default, but rather specifically because the icon_state was set to "default" when it needed to now be "" to view the states of the newly dynamically created icon.

If I wanted to keep all my states, I should have left the state argument out. That actually sounds like a pretty good way to go about it, because that way I could rebuild multiple states at once. (e.g. "moving" "firing" "duck" can be made octo-directional from one state.)