Finishing Omnification of Dragon’s Dogma With Abomnification

The strange, strange game known as Dragon’s Dogma has been granted the power of the Apocalypse system and blessed with the Predator system. The time has come where we must implement the terrifying Abomnification system into the game, making it officially Omnified.

For every game I’ve Omnified since its creation, the Abomnification system has always been the one requiring the most work and skill. However, for Dragon’s Dogma, I’m very confident in saying that its implementation will be an incredibly easy one.

Why am I so confident? Because we previously discovered that this game actually has built-in, easy scaling support! The first game to have it since the Abomnification system was invented! I’m really looking forward to an easy, perfectly working Abomnification experience.

But what is the Abomnification system? Well sadly, at the time of writing, I lack an Omnified Design article on the topic. There isn’t even an easy to follow general overview video! I apologize! I will get to it! The following is a quick summary for you.

The Abomnification system is the latest of my game-neutral Omnified systems, and it is concerned with the generation of ever changing scaling dimensions for creatures based on randomly assigned morphing modes.

Basically, what you get is an insane acid trip in a game. It’s intensely entertaining for me (and hopefully my viewers) and it actually can really really impact the difficulty in very unforeseen ways. Let’s get some of that acid injected into Dragon’s Dogma‘s veins right now!

Where to Initiate the Abomnification?

Like all of my game-neutral systems, a proper initiation point must be created and put in the correct place in code in order for the system to operate properly. The Abomnification system is no different, however the disassembly requirements imposed by the system varies greatly based on whether or not the game has built-in easy scaling support.

So what is built-in easy scaling support? Basically, if the game has properties in a data structure belonging to a creature that directly influence the rendered scale of said creature, it has built-in easy scaling support. Most often these properties will appear in the location structure containing creature coordinates.

If the game does not have easy to find scaling parameters, we have to locate and hook into actual rendering methods and then perform some matrix math to effectuate changes to the skeletal structure of the creature. This is not the most easy thing to do, and to see how I do it, check out one of my other Abomnification articles.

In Dragon’s Dogma, we can find the scaling parameters in the location structure for a creature. The width, height, and depth multipliers are found at offsets 0x60, 0x64, and 0x68 respectively. Changing one of these multipliers immediately updates the look of the character.

In previous Abomnification articles I’ve usually had to create two separate hooks: one for Abomnification initiation, and another for Abomnification application. In this game, we can do everything in a single hook. This hook will execute the Abomnification system which will calculate new scaling values for us, and then immediately update the built-in scaling parameters with these new values.

So where should we do this? Typically, I have found that the best place for the Abomnification initiation hook is somewhere in the code that has access to all visible creatures on the map, and is executing enough to facilitate smooth animation. High execution frequency is important since each time the Abomnification system is called a morph step occurs (think of this as an animation frame in the shape changing process).

Naturally, a type of code that fits this description to a T is a general coordinate polling function. This is code that is constantly scanning the coordinates of all creatures on the map for whatever purpose. We’re going to find such a function right now.

Finding a General Coordinate Polling Function

Locating a general coordinate polling function is usually a trivial affair. However, we’ll want to make sure it’s one that suits our purposes. We’ll first start off by looking for code that is polling our own coordinates.

Shows how we start the general polling function search by right clicking on our X coordinate and choosing "Find out what accesses this address".
We start the search for the general coordinate polling function by seeing what code is reading our X coordinate.

This is going to pop up a list of instructions reading our X coordinate. We’re going to want to sort it by the number of times the instruction is called, so the most frequently executing ones are listed first. The more the function executes, the smoother the animation.

We’ll then want to go through each one and load the disassembler for the code, where we can do some further tests.

Shows the next part of finding the general coordinate polling function, clicking on instructions that are reading our coordinates and then clicking "Show disassembler".
Starting at the top, we load the disassembler for each of the most frequently executed instructions reading our coordinates to perform further checks for viability.

For each of these instructions, we want to find the first one that is accessing more than just the player coordinates. Indeed, we’ll want to find one that looks like it’s polling all the entities that might be on the map at a high frequency (although targets that are further away don’t need to be polled as often).

Shows the third step of finding the general coordinate polling function, right clicking on the instruction in question and clicking "Find out what addresses this instruction accesses".
Here’s how we’ll see what addresses are being read by this particular coordinate polling function.

We also really only want a coordinate polling function that is polling exclusively player and non-player characters. There are other things that have coordinates too. A rock on the ground might have coordinates.

We don’t want any of that. So once we find some functions that are accessing a large number of coordinates, we’ll probably want to avoid the ones accessing a huge, huge number of them.

It isn’t long until we find some code (the seventh one listed in the second image) that is accessing a reasonable number of different coordinate addresses:

Shows us finding code that accesses the player's root structure while hacking Dark Souls III.
This is what we want to see, a map-wide polling of all creature’s coordinates.

Looks like we’ll be implementing our Abomnification initiation point at DDDA.exe+4866F6. We’re not quite ready to write the hook yet, however, as we still need to figure out where we’ll be storing each creature’s morph scale ID.

Finding Where to Stow Our Morph Scale ID

The morph scale ID is used by the Abomnification system to lookup and store morphing data specific to a particular creature. It will receive lots of attention in the design article specific to the Abomnification system, whenever that gets written!

If your desperate for more information, please refer to the relevant section in my Abomnification of Dark Souls III article for an explanation of what it is and why we need it.

In order to establish a relation between a creature and its morphing scale data, we will need to find some unused memory in a data structure associated with that creature. Preferably (since we’re working with them already) somewhere in the location structures of creatures.

For reasons that are listed in the previous Abomnification article I just linked (reasons which will also be enumerated in my Abomnification design article), it can be very tricky to find unused memory. We’re going to make use of one particular technique I use in order to find data that is safe to manipulate. A technique I’ll explain in detail now!

First, we’re going to open a new window of fresh addresses being accessed by our general coordinate polling function. After letting it run for a little bit, we will highlight all of the addresses and dissect the data.

Shows how we start our search for a good place to stow the morph scale ID, by right clicking all the highlight addresses in our "Accessed addresses" window and clicking "Open dissect data with selected addresses".
Here we highlight all the addresses and choose to dissect their data.

We click through the next few prompts, and then set the Structure to the one we previously dissected for a Location struct. After this we will scroll down, looking for areas where the memory looks empty. This will look like a few rows of all 0’s, with the color of the rows being green (indicating that all of the columns have the same value for that row).

Shows the next step of figuring out where to store the morph scale ID, looking for data where there are a lot of surrounding 0's.
We’ll want to find a place in the structure that has a bunch of empty memory apparently not being used.

Once we find some offsets, we’ll want to jot them down for reference later. Now, we want to see if we can change the values in these rows and, more importantly, see if they stick. We have far too many columns to manually set the rows to our test value, so let’s write some quick code to inject into the polling function that’ll do it for us.

Morphing Scale ID Test Hook

define(address,"DDDA.exe"+4866F6)
define(bytes,F3 0F 10 47 40)

[ENABLE]

assert(address,bytes)
alloc(newmem,$1000)

label(code)
label(return)

newmem:
  // Writes test value to one of the offsets we
  // noted as being empty.
  mov [edi+250],#44
code:
  movss xmm0,[edi+40]
  jmp return

address:
  jmp newmem
return:

[DISABLE]

address:
  db bytes
  // movss xmm0,[edi+40]

dealloc(newmem)

This is just some very simple, temporary code we’ll be using. We’ll add this script to our cheat table, and then enable it by checking it. While this code is running, we grab a fresh list of addresses being accessed by our polling function.

We let the test code run for awhile and keep a careful eye on the list of addresses being accessed. We are going to be checking these structures to see if the value sticks, however we only want to concern ourselves with structures that persist for awhile, and not temporary, brief-lived location structures created for God knows what.

After letting it run for a bit, we then disable our test code. We open up a new dissect structure window for the addresses that showed some permanency. Looking at our structure window, we check to see if the correct row has been updated to our test value, and if the row is green. If it isn’t green, we choose a new offset and try the test code again.

If the row is green, then we want to move our character around and interact with some of the enemies to get some reactionary code to execute. If the data still remains untouched, we may have found the perfect place to store our ID.

The last thing we’ll want to do is go to a new map area, and make sure the game remains running. Often I’ve noticed that crashes occur when memory-wide refreshes happen, which are typically triggered when going to a new map or dying.

We do the above steps until we find a good offset in the location structure where we can reliably store our data. From some brief initial testing, it looks like the offset 0x300 will do just fine!

Now we have everything we need to write the initiation point for the Abomnification system.

Implementing the Abomnification Initiation Point Code

We have a place to store our morph scale ID, and we have the place in code to stick our point into (hmm…don’t read into that too much). Let’s take a gander at what the starting template of our initiation point looks like first.

Abomnification Initiation Hook – Template

// Initiates the Abomnification system.
// edi: Address to creature's location structure.
define(omnifyAbomnificationHook, "DDDA.exe" + 4866F6)

assert(omnifyAbomnificationHook, F3 0F 10 47 40)
alloc(initiateAbomnification,$1000, omnifyAbomnificationHook)

registersymbol(omnifyAbomnificationHook)

initiateAbomnification:

initiateAbomnificationOriginalCode:
  movss xmm0,[edi+40]
  jmp initiateAbomnificationReturn


omnifyAbomnificationHook:
  jmp initiateAbomnification
initiateAbomnificationReturn:

The Abomnification system must be executed and the creature’s scaling dimensions must be updated prior to execution reaching the initiateAbomnificationOriginalCode label. Unlike other Omnified system initiation points, we won’t require much code here at all.

The main Abomnification function is named executeAbomnification, and extensive documentation regarding it will be found in the Abomnification design article. For now, all we need to know is the following info:

Parameters

  • Address to memory holding the creature’s morph scale ID.

Return Values

  • eax: Set to the updated width scale.
  • ebx: Set to the updated height scale.
  • ecx: Set to the updated depth scale.

So we’ll make the simple call to the executeAbomnification function and update the scaling parameters (which again also reside in the location structure) with the return values.

We’ll also want to make sure we back up the registers that will be holding the return values, as well as ensure the player character isn’t being Abomnified. We’ll make that a toggleable option later.

Usually I do these code writing sections in parts, however this should be so simple we should be able to write out the whole thing right away!

Abomnification Initiation Hook

// Initiates the Abomnification system.
// edi: Address to creature's location structure.
define(omnifyAbomnificationHook, "DDDA.exe" + 4866F6)

assert(omnifyAbomnificationHook, F3 0F 10 47 40)
alloc(initiateAbomnification,$1000, omnifyAbomnificationHook)

registersymbol(omnifyAbomnificationHook)

initiateAbomnification:
  pushf
  // Ensure that the player isn't the one being subjected to Abomnification.
  cmp [playerLocation],	edi
  je initiateAbomnificationOriginalCode
  push eax
  push ebx
  push ecx
  // Load the address for where the morph scale ID can be found.
  lea eax,[edi+300]
  // Push our morph scale ID address as the sole parameter, and then
  // get the Abomnification party started.
  push eax
  call executeAbomnification
  // The eax register will be set to a negative value if the system is
  // disabled or an error occurred.
  test eax,0x80000000  
  jne initiateAbomnificationCleanup
  // Set the width to the Abomnified value.
  mov [edi+60],eax
  // Set the height to the Abomnified value.
  mov [edi+64],ebx
  // Set the depth to the Abomnified value.
  mov [edi+68],ecx
initiateAbomnificationCleanup:
  pop ecx
  pop ebx
  pop eax
initiateAbomnificationOriginalCode:
  popf
  movss xmm0,[edi+40]
  jmp initiateAbomnificationReturn


omnifyAbomnificationHook:
  jmp initiateAbomnification
  
initiateAbomnificationReturn:

That’s it! Real short and simple! Yay for built-in scaling support, which is really the norm for most games — I’ve just had a streak of bad luck Omnifying FromSoft game after FromSoft game, all which lack such capabilities (and required some serious plumbing to get Abomnified).

But, Does It Work!?

Oh yeah, we thought it was going to be an easy Abomnification, and it definitely was! Only one slight problem: the scale of human heads is independent from the body scale. So when the body increases in size, the head remains the same. The position of the head, however, in relation to the ever changing body shape, is perfect.

On the flip side of this, the heads of monsters appear to scale just fine from changes made to the general scaling parameters — so no work is required on that front!

The unchanging size of just the head of an NPC is a rather unexpected outcome of things. In my “limited” experience, I’ve observed that when a game has built-in easy scaling support, the scaling parameters affect all parts of the character model.

Despite this, the fact that the head scaling is independent from the body scaling shouldn’t be a big surprise given that we are able to change the size of our characters’ heads in the character creation screen. So, I suppose it all makes sense then. As a result of all this, in order to have perfect Abomnification, we’re going to need to find where the head scaling parameters are stored.

Where Is My Head?

Like the body, I’d expect the head to have three dimensional scales: width, height, and depth. If we’re lucky, maybe we’ll stumble on the head scales nearby the body scales in the location structure.

No dice there. Looking at all floating point values nearby the body scales, I found absolutely nothing that had any effect on the head. I was ready to consider Abomnification and this article complete (accepting the improperly sized heads, which is kind of funny), but I couldn’t help but do what I usually do: go hard as hell or go bust.

In order to find the head scales, we were going to need to cause the size of the head to change somehow in the game, and isolate changing values in memory. The perfect place to do just that is in the character creation screen itself, where a slider exists for changing the head size.

So we restart our save game and get into the character creation screen. I then begin an Unknown initial value scan for all Float value types. Next, we increase the head size slider bar and do a follow up Increased value search. We do this a few more times until the head cannot get any bigger, and then do the reverse, performing many Decreased value searches.

We keep on doing this until we get it down to a reasonable number of addresses. We add all of these to our address list, and start tweaking their values until we isolate the one that actually causes our face to change shape. After a bit of sweat, we strike gold:

Shows the results of the head scaling search in the character creation screen, which is our character with a huge head.
Yup. That’s a big head.

Excellent. We’ve verified a rather large assumption: that easy built-in scaling parameters exist for human heads at all. Thank the heavens. Time to look at the structure these parameters exist in.

I do a check for the code accessing these scaling parameters, and note them down for later use. I then proceed into the game, and get some addresses being accessed by the code during normal gameplay.

As I feared, I see no address even remotely close to our character’s location structure. That means the head scaling parameters are definitely in a structure completely foreign to us at this point in time. Taking the address to my own character’s head scales, I throw it into a dissect structure window, and define a new structure simply named Scales (whether it’s the best name is debatable, I don’t know what the other members do, but I figure it may be a general body/head-related scales container).

If we are to propagate body scaling changes to the head, we need to be able to find this data structure from a creature’s location structure. Establishing relations between disparate data types can be a tall order in an application lacking RTTI.

Frustratingly, I quickly observed that while a pointer to a character’s location structure existed on its scales structure, there was seemingly no link at all from a character’s location structure to its scales structure. Since we’re working with the location structure and not the scales structure in the Abomnification method, this means we have absolutely nothing we can work with as of yet.

This is assembly we’re programming in — not a higher level programming language where we can just dish out relational dictionaries with ease. I need a link from location struct to scale struct, or we’re going to be stuck.

I then surmised that it might be possible that whatever “root” structure the scales structure is sourced from might also provide a link to and/or from the location structure. In order to find this root structure, I took a look at what might be accessing the beginning of the scales structure itself.

Shows how we begin the search for the root structure containing the scales structure, by adding the first member of the scales structure to our address list and then checking what code accesses it.
We’re going to add the first member of the scales struct to our address list and see what accesses it.

After the starting member of the head scales struct is added to our list, we monitor all the code making accesses to this particular place in memory. We’re going to use the results from this to learn how the game itself accesses this scales structure. We’ll also be gaining access to the root structure containing it in the process.

Shows the code accessing the start of our scales struct, with the first code result seeming to source it from a root structure.
Here is the code accessing the start of our scales struct, with the first result appearing promising.

Taking a look at the first result, we see the scales structure is being sourced from another place in memory with a large indexing offset added. The address of this root structure, pointed to by edx, is thrown into a structure dissect window, and yet another new data structure is defined, this time called “Scales Root”. Yeah not the most original. It is hard without RTTI OK!

With all these struct data types populated, it’s time to perform some relational linking, and see if we can bridge that gap between the location and head scales structures. On a structure dissect window, we click on Structure Options -> Find relations, and make sure the window is populated like so:

Shows the configuration of the structure linker, with the "Fill in 'Local' structures" checkbox checked, used in order to find a relation from our location structure to the scales structure.
Here is what our structure linker looks as we attempt to find a relationship between the location and scales structures.

Once we hit that Link button, any instance of one of these structures appearing in another will be labeled in our structure dissect window. After giving a location structure instance a cursory look, I found nothing.

So I had to dig deeper, and guess at likely pointers in the location structure that may be acting as links to data that will lead to the head scales structure. I popped open the nameless struct pointer at the 0xF8 offset, and then scrolled down for awhile until, at offset 0x6B0, I was greeted with the wonderful sight of a “scales root” structure pointer.

Opening that, all I had to do was scroll down a little more until I found our elusive solution:

Shows the very hard to find relational link between the location and scales structure. Refer to text for more details.
Here, buried very deep in the location structure, we’ve found a link to the head scales structure.

Yeesh. And thank God. Here is the link, and we’ll be using the offsets shown at the bottom left of the window to get the head scales structure from the location structure.

If you recall, the size of monster heads was shown to not be independent from the body scale. They do not have head scaling parameters. I made the important observation that if a creature does not have head scaling parameters, then the “scale root” pointer which we found earlier will always point to the address 0x3F8000000.

We got what we need to add support for scaling the heads. Let’s do it baby.

Failing at Head Scaling

Everything that has needed to be said has been said already. We’re going to add to our current initiation point code that will, after applying the body scales, walk down the structure path we charted above and resolve the character’s head scaling structure from their location structure.

Once we have that, we’ll just throw on the appropriate Abomnified scales to the various scaling dimensions for the creature’s noggin!

Well, I went ahead already and wrote up all the code.

And it failed. Hardcore. The path we have to walk in order to get the head scaling structure from the location structure is not a simple path. Lots of opportunity for bad data.

Indeed, I kept on running into instances of data that would have invalid pointers at the places we expected there to be a valid structure. I added bad pointer checking code; all the bells and whistles. In the end, I was left with code that actually did nothing at all. The path was, for the most part, invalid.

When things start to get too messy, that’s when you need to go outside the box a little bit and tap into that innovation muscle. I realized, with a start, that I was dead set in setting the head scaling values inside the Abomnification initiation point. The reason for which being no better than me just being stubborn about getting everything done in a single hook!

The game has built-in scaling support! Multiple hooks of code for Abomnification is heresy! Hah.

I managed to eventually shake off my stubbornness, and quickly came to the conclusion that it would be best to set the head scales to their proper values upon the head scaling structure itself being accessed!

Winning at Head Scaling

Getting the location structure from the scaling structure is much easier than the other way around. All you need to do is hit up the 0x54 offset on the scaling structure. So, I could just hook into code reading the head scaling parameters, and then copy over the body scaling values to the head scaling values!

I started by hooking into the code that directly reads head scaling dimensions. The code I wrote did everything it needed to do. Except when I ran it: horror. Too Abomnified.

It turns out the scaling structure is a container for not just head scales, but scales for all manner of body parts. More than just the head was getting its scale screwed with! Humans were turning into blobs!

After thinking a bit more, I realized that my previous “sojourn into worthless data” which yielded the path to get from the location structure to the scaling structure was not an entirely useless affair. Instead of hooking into the scaling value reads, I realized I could hook into the code where the scaling structure I was interested in was being pulled from the root scaling structure.

If you look at the image posted a ways up from here, where we’re looking at accesses on the first member of a head scaling structure, you might be able to figure out that the magic number here is 0x8F0. This is the offset that was added onto the scaling root structure in order to get our own head scaling parameters.

So hooking into “DDDA.exe”+41BD49 gave me a way to filter out all scaling structures not to do with the head. Let’s see what this code that copies over the Abomnified body scaling values to our head scaling structure looks like.

Abomnified Head Application

// Applies Abomnification scales to human heads.
// eax: A scales structure.
define(omnifyAbomnifyHeadsHook, "DDDA.exe" + 41BD49)

assert(omnifyAbomnifyHeadsHook, 8B 50 20 FF D2)
alloc(abomnifyHeads,$1000, omnifyAbomnifyHeadsHook)

registersymbol(omnifyAbomnifyHeadsHook)

abomnifyHeads:
  pushf
  // Head scaling structures are accessed with an offset of 0x8F0.
  cmp ebx,0x8F0
  jne abomnifyHeadsOriginalCode
  sub esp,10
  movdqu [esp],xmm0
  push eax
  // Load the location structure from the scales structure.
  mov eax,[ecx+54]
  // Load the body width scale into the head width scale.
  movss xmm0,[eax+60]
  movd [ecx+80],xmm0
  // Load the body height scale into the head height scale.
  movss xmm0,[eax+64]
  movd [ecx+84],xmm0
  // Load the body depth scale into the head depth scale.
  movss xmm0,[eax+68]
  movd [ecx+88],xmm0
  pop eax
  movdqu xmm0,[esp]
  add esp,10  
abomnifyHeadsOriginalCode:
  popf
  mov edx,[eax+20]
  call edx
  jmp abomnifyHeadsReturn


omnifyAbomnifyHeadsHook:
  jmp abomnifyHeads
abomnifyHeadsReturn:

And voila! All parts of the body, now Abomnified.

So It Works?

You’re god damn right it works. Not only are humans and monsters morphing perfectly, but even some inanimate objects are changing shape and size! Crates! Logs! Rocks! It’s really going to look like an acid trip playing this game.

Shows the results of Abomnification, with Rook morphing all over the place.
Dragon’s Dogma has become Abomnified.

Since we were able to leverage built-in scaling support, this game will feature perfect Abomnification with every particle of all creatures subject to its shape bending will.

Here is our final (well, initial final) code for the Abomnification implementation:

Abomnification Hooks – Complete

// Initiates the Abomnification system.
// edi: Address to creature's location structure.
define(omnifyAbomnificationHook, "DDDA.exe" + 4866F6)

assert(omnifyAbomnificationHook, F3 0F 10 47 40)
alloc(initiateAbomnification,$1000, omnifyAbomnificationHook)

registersymbol(omnifyAbomnificationHook)

initiateAbomnification:
  pushf
  // Ensure that the player isn't the one being subjected to Abomnification.
  cmp [playerLocation],	edi
  je initiateAbomnificationOriginalCode
  push eax
  push ebx
  push ecx
  // Load the address for where the morph scale ID can be found.
  lea eax,[edi+300]
  // Push our morph scale ID address as the sole parameter, and then
  // get the Abomnification party started.
  push eax
  call executeAbomnification
  // The eax register will be set to a negative value if the system is
  // disabled or an error occurred.
  test eax,0x80000000  
  jne initiateAbomnificationCleanup
  // Set the width to the Abomnified value.
  mov [edi+60],eax
  // Set the height to the Abomnified value.
  mov [edi+64],ebx
  // Set the depth to the Abomnified value.
  mov [edi+68],ecx 
initiateAbomnificationCleanup:
  pop ecx
  pop ebx
  pop eax
initiateAbomnificationOriginalCode:
  popf
  movss xmm0,[edi+40]
  jmp initiateAbomnificationReturn


omnifyAbomnificationHook:
  jmp initiateAbomnification
initiateAbomnificationReturn:


// Applies Abomnification scales to human heads.
// eax: A scales structure.
define(omnifyAbomnifyHeadsHook, "DDDA.exe" + 41BD49)

assert(omnifyAbomnifyHeadsHook, 8B 50 20 FF D2)
alloc(abomnifyHeads,$1000, omnifyAbomnifyHeadsHook)

registersymbol(omnifyAbomnifyHeadsHook)

abomnifyHeads:
  pushf
  // Head scaling structures are accessed with an offset of 0x8F0.
  cmp ebx,0x8F0
  jne abomnifyHeadsOriginalCode
  sub esp,10
  movdqu [esp],xmm0
  push eax
  // Load the location structure from the scales structure.
  mov eax,[ecx+54]
  // Load the body width scale into the head width scale.
  movss xmm0,[eax+60]
  movd [ecx+80],xmm0
  // Load the body height scale into the head height scale.
  movss xmm0,[eax+64]
  movd [ecx+84],xmm0
  // Load the body depth scale into the head depth scale.
  movss xmm0,[eax+68]
  movd [ecx+88],xmm0
  pop eax
  movdqu xmm0,[esp]
  add esp,10  
abomnifyHeadsOriginalCode:
  popf
  mov edx,[eax+20]
  call edx
  jmp abomnifyHeadsReturn


omnifyAbomnifyHeadsHook:
  jmp abomnifyHeads
abomnifyHeadsReturn:

With Abomnification in, Dragon’s Dogma is now officially Omnified and eligible for being streamed on…you guessed it: my stream! That’s the only place you’ll be able to catch it live, so make sure to stop on by!

Hope you found the article interesting or at least overwhelming in all other aspects. Until next time, keep it real everyone.

~Omni