Folks have mentioned that creating solutions to your own problems helps a lot. Well it does, but it takes some out-of-the-box thinking to realize that you do have a problem to solve.
Programming is like using an Erector set. You get a lot of pieces and can place them together quite easily. But when push comes to shove, how many are going to (or willing to) build a baseball launcher so they can avoid "pickling the Beast" (Sandlot reference)?
That's where imagination and subdivision comes in. Yes, you can learn all the theories and syntax that you'd want, but if you don't use your imagination and divide-n-conquer methods, you'll never make it.
Once you'd get past all of that, the sky's the limit. I'm proof of that. I hear of all of these miracle languages and frameworks, but I stick to what I know. Why, because it had solved so many problems before. And its because I have a vivid imagination and know what it takes to get the task completed.