KKI LABS // PUBLIC RELEASE Banner Wheel Exposed by AJ 187 of KKI Labs Draft 1 Official Submission Date: September 20, 2008 -------------------------------------------- [Abstract] Background In some rhythm games, the music selection screen likes to implement banners or backgrounds, depending on the game chosen. Until recently, there were two ways to implement this in StepMania: 1) Use ScreenEz2SelectMusic, which hasn't been updated since 3.9 2) Hack the source code to include it yourself (Neon FM, Mungyodance) These days, people using StepMania 3.9 have access to 3.9+, which includes an incomplete banner wheel option. The reason it's incomplete is that it doesn't allow for groups to have banners on the wheel. However, 3.9 is not 4.0... Conclusion Using banners on the MusicWheel isn't as hard as you think, but you will need either a SVN version of StepMania 4 or some source hacks to get a 100% functioning banner wheel. ---------------------------------------- Banner Wheel: Implementation and Analyzation Introduction Before I introduce the problem, I feel I have a bit of explaining to do. First off, this idea was revealed to work in February 2008. This guide was written in September 2008, 7 months apart. "Why the wait?", you may ask. Well, I wanted to originally release the guide with a version of StepMania that supported the source hack mentioned in this guide. However, it's been eight months since the last SM4 release, and hypnodance is crawling along at a speed of one change every 6 months. Secondly, some people have given other people the banner wheel code without asking me. This is especially obvious in cerbo's PIU NX theme: http://www.youtube.com/watch?v=BIcIUltr7e4 If other people are using it, I don't really have any reason to hide it aside from the source code hack. So before I begin, I must say this: If you are using StepMania 4 CVS (latest version 20080103), the group banners will not work for you. If this is an issue, then you have two choices: 1) Move to SVN. 2) Hack the source. We now return you to your regularly scheduled release. Problem Get banners to show up for songs (and groups) on the MusicWheel. Hypothesis By using a Lua actor to replace MusicWheelItem, you can make a lot of things (including banner wheels) happen. Implementation This was my first time ever messing with Lua to replace MusicWheelItem, so I didn't know what to expect. After messing with it for a bit, I looked at Lua.xml for any possible classes I could use in here and I saw Banner. Banner has quite a few interesting functions in it, namely LoadFromSong(). However, that's only half of the story. You also need to get access to every single song that's on the wheel... and that's where it starts to get dirty, messy, and mind-blowing. Implementation Details There should be a file called [YourTheme]/Graphics/MusicWheel item/default.lua, which we will edit the crap out of. As mentioned above, there is a class called Banner (called in Lua files by using Def.Banner) that has a few useful functions such as LoadFromSong(). However, the problem is getting access to the songs, and this is where our friend MESSAGEMAN comes in. Thumbing through the source code of MusicWheelItem.cpp shows us a nice block of code to work with (code from SM4CVS): { Message msg( "Set" ); msg.SetParam( "Song", data->m_pSong ); msg.SetParam( "Course", data->m_pCourse ); msg.SetParam( "Index", iIndex ); msg.SetParam( "HasFocus", bHasFocus ); msg.SetParam( "SongGroup", pWID->m_sText ); this->HandleMessage( msg ); } That's fine and all if you're me, but since you're not, you probably don't have an idea of how to abuse messages. For every message sent, there is a way to capture it in a theme. The formula is [x]MessageCommand, where [x] is the name of the message. Since the message above is named Set, the command you need is SetMessageCommand. As you can see, it gives us a few parameters. If you've worked with long form command declarations before ( =function(self) ), then it's just a matter of adding one more parameter to the function. If not, though, then here's everything you need to know for this specific instance: SetMessageCommand=function(self,params) I use "params", some people use "param", others may use "p", it's all up to you. You just need to know what you use so you can call the parameters. Alright, so now that we have an idea of how to abuse the SetMessage called in MusicWheelItem, it's time to make a skeleton. local t = Def.ActorFrame{ Def.Banner{ InitCommand=cmd(scaletoclipped,256,80); SetMessageCommand=function(self,params) end; } } return t; So we have the skeleton. I've also thrown in an InitCommand that scales the banner down to 256x80. If you're not doing this with DDR banners or you want to have a different banner size, then change the two params to scaletoclipped. From here, we need to flesh out SetMessageCommand. Look at the param list above and think of what you would need from it. If you said params.Song, you win! From this point forward, all examples will only include SetMessageCommand unless otherwise stated. SetMessageCommand=function(self,params) local song = params.Song; end; Now, we need to test to see if there is a song or else things will go haywire: SetMessageCommand=function(self,params) local song = params.Song; if song then -- this is where we do all song-specific stuff self:LoadFromSong(params.Song); end; end; And if all you want to do is display the banner, then there you have it. Deceptively simple, but ultra-powerful. Perhaps one of the next KKI Labs guides will expose the true functionality of MusicWheelItem song/default.lua, but until then, you can look at dubaiOne and NAKET Coder Evolution to see how to abuse it. Of course, this is not a complete implementation, as this only deals with songs. For courses, change your SetMessageCommand to the following: SetMessageCommand=function(self,params) local song = params.Song; local course = params.Course; if song and not course then -- this is where we do all song-specific stuff self:LoadFromSong(params.Song); elseif course and not song then -- this is where we do all course-specific stuff self:LoadFromCourse(params.Course); end; end; Then that just leaves us with groups as one of the main things to consider. However, you really need to have a version of SM with Banner::LoadFromSongGroup() in order to even begin considering to have group banners on your wheel. The file you edit will also change (MusicWheelItem section/default.lua), but the code remains nearly the same. Remember msg.SetParam( "SongGroup", pWID->m_sText );? SetMessageCommand=function(self,params) local group = params.SongGroup; if group then self:LoadFromGroup(group); else -- call fallback self:Load( THEME:GetPathG("Common fallback","banner") ); end; end; From here, the sky's the limit, as you can implement other things on top of SetMessageCommand, since you get access to the raw Song and Course. Any commands you can run on those, you can run in here.