An Overview of the Apocalypse System

The Apocalypse system is a game-neutral Omnified process that completely overhauls the system in a game responsible for handling damage dealt to and by the player. When implemented into a game, the existing damage system is augmented by the introduction of several dice rolls that apply random effects of varying punishment to the character. These random effects are then typically displayed on screen in the form of an event log.

The Apocalypse system was the first formalized Omnified system that I made, and therefore it will be the first to have its own detailed analysis article. All aspects of the Apocalypse system, from its usage to its inner workings, will be covered here. If you would like to start off with a quick primer on what my Apocalypse system is all about, check out the video below for a general overview:

New to the Apocalypse? Get up to speed with this quick general overview video.

Origins of the Apocalypse System

The Apocalypse system evolved from the earliest of my hacks, which primarily dealt with increases of damage to the player. The first of these hacks would simply cause the player to die upon receiving any kind of damage, but eventually I figured out how to apply a static increase to the damage, such as 69x damage (which is just the most perfect multiplier one could apply to damage, ya hear?).

Shows how most damage would affect the player before the Apocalypse system: by simply murdering them in one hit.
Prior to the Apocalypse system, damage hacks simply made it so you always got one shot.

In the early days of this Omnified adventure I’m on, I really desired to try to do something new and exciting for each game that I Omnified. So instead of doing just an across-the-board damage increase for all damage, I eventually would apply different increases to the damage based on where the damage was going (shields vs health, etc.). Sometimes the damage would be enough to one shot the player all the time, or sometimes it would require several shots. The amount of damage was dependent on the game; it was whatever made sense.

One day, that all changed. I discovered the power of randomness. Put a different way: I figured out how to write some code that allowed me to generate random numbers in assembly easily. Instead of static damage amounts, what about random damage amounts? Instead of random damage amounts, what if we had random effects based on the damage? Of course, there would also need to be some way to display to viewers on my stream which random effects were going off at a given point of time.

So, one fateful evening, while Omnifying Resident Evil 3 on stream, I wrote the first implementation of the Apocalypse system, which eventually became game-neutralized and the first of my Omnified systems. A new era was dawning!

Basic Mechanics of the Apocalypse System

The Apocalypse system is composed of two separate and distinct modules: the Player Apocalypse and the Enemy Apocalypse. The Player Apocalypse handles damage being done to the player from an enemy. The Enemy Apocalypse handles damage being done to an enemy from the player.

Both of these modules introduce probability and chance into how damage is handled in the game, albeit in very different ways, with the odds definitely being stacked against the player. They are also both responsible for data collection and recordkeeping of various statistics specific to the area the respective module operates in.

Player Apocalypse

The Player Apocalypse, as stated previously, is responsible for handling damage done to the player by enemies.

The Apocalypse system changes what happens following the player getting smacked by a baddie. Right before the game applies the damage from the hit to the player’s health, a (typically) 10-sided die is cast. What happens next is dependent on the result of the roll.

Primary Dice Roll Effects

The potential outcomes from the primary dice roll are as follows:

  • 1-4: Extra Damage
    • Damage is increased by extraDamageX (default: 2.0).
  • 5-6: Teleportitis
    • Normal damage applies.
    • The player is teleported by having all coordinate axes shifted by +/- 5 units, all randomly determined and then multiplied by teleportitisDisplacementX (default: 1.0).
    • If negativeVerticalDisplacementEnabled (default: 1) is false, the Y-axis (or Z-axis, depending on the value of yIsVertical (default: 1)) will be shifted by 0-10 instead, to prevent negative vertical displacement.
    • A copyright friendly length Tom Petty’s Free Fallin’ plays if we’re being teleported beneath the ground (because we will most likely fall to our deaths).
Shows the player falling through the ground to their death due to the Apocalypse system.
Due to a teleportitis effect, the player is teleported beneath the ground and falls to death.
  • 7-9: Risk of Murder Roll
    • A separate 5-sided die is cast, which depending on the result, causes the following:
      • 1-3: Normal damage applies.
      • 4-5: 69x damage. You just got SIXTY NINED.
        • A Duke Nukem Holy Shit! sound effect plays.
  • 10: Sudden Orgasm
    • The player experiences a spontaneous orgasm on the battle field and is fully healed.
    • The classic anime WOWWWW! sound effect plays.

Once the roll concludes, a signal fires to the display system (which we’ll cover in much greater detail in an Omnified display system article) to create an event log entry concerning the roll, so that the player and audience are cognizant of WTF just happened.

The full heal effect that the player receives if the die roll is 10 is meant to be a bit of fun randomness injected into the overly oppressive nature of all the other effects. It has a very small chance of happening, but when it does, it can feel damn good!

You may have noticed several terms in bold. These are what are known as external parameters, and are meant to be able to be configurable by consuming bits of code (i.e. the game specific hacks that are initiating the Omnified system). These will be covered in greater detail and grouped together in a list in a later section in this article.

The primary dice roll is the main feature of the Player Apocalypse, however it also provides other functionality appropriate for the place in code it has been injected into…including the power of immortality (queue omnGasm).

God Mode Powers!

That’s right, nestled in with all the horrifying and punishing code of the Player Apocalypse, there is code that provides god mode support! If the playerGodMode (default: 0) external parameter is set to 1, no roll occurs in response to damage, and the damage amount is reset to 0.

This is mainly used for debugging purposes…however I have been known from time to time to get tired of the bullshit difficult encounters (whose bullshittiness is entirely my own fault!) and throw it on. In secret. Shh…

But that aside, it is quite handy to have automatic god mode support added to a game whenever I implement Apocalypse system support into it. So, if you are ever just looking to cheat like a bad panda, and you see an Omnified hack available for a game, it’ll serve your purposes (if you know how to turn it on that is ;)).

Enemy Damage Statistics

Since the Player Apocalypse becomes the authority ultimately on how much damage the player is receiving from enemy sources, it also makes sense that it should govern statistics related to damage done to the player by enemies. The Apocalypse system tracks a number of game-related statistics, with the Player Apocalypse being responsible for three enemy damage related stats:

  • lastDamageToPlayer: The most recent amount of damage done to the player.
  • maxDamageToPlayer: The highest amount of damage done to the player during the current session.
  • totalDamageToPlayer: The cumulative amount of damage done to the player over the current session.

These statistics are made available as simple text dumps for on-stream display; however, there is currently work being done on formal data contracts for the statistics that will be fed into specialized stat display programs (an article will be written for that later!).

That wraps up basic functionality for the Player Apocalypse! Now onto the other important component of the Apocalypse system: the Enemy Apocalypse!

Enemy Apocalypse

Whereas the Player Apocalypse handles damage done to the player from enemies, the Enemy Apocalypse handles damage done to enemies from the player.

The intended purpose of the Enemy Apocalypse was to collect statistics related to damage done to enemies by the player as well as provide the ability to fine tune the player’s damage. A number of other little features have come about however along this Omnified journey.

Some random effects that benefit the player have also been added! However, these are meant to be brief bits of respite for gameplay, and are not in any way meant to compete with the punishing random effects caused by the Player Apocalypse.

With that, let’s go over the basic mechanics of the Enemy Apocalypse.

Base Player Damage Adjustments

At the outset of the Enemy Apocalypse, the player damage is multiplied against the playerDamageX (default: 1.0) external parameter. Since we’re overhauling damage to enemies, why not provide the means to shape player damage at its base. This is typically always left at its default value, however I may adjust this if I disagree with a particular game design decision (e.g. hardest difficulty nerfs player damage by 50%, I don’t subscribe to that crap).

Chance of Player Critical Damage

Implementation of the Apocalypse system adds a bit of spice to normal combat by adding the ability for the player to score critical damage! The amount of extra damage is not massive, however it is enough that it definitely feels good when it happens!

A roll to first see if the player scores a critical hit is cast. The chance that damage by the player becomes critical is 6.25%. And yes, this critical hit chance percentage was borrowed directly from Pokémon. No, believe it or not, I have never played Pokémon, however it was the first percentage that popped up when I Googled “critical hit chance” (I was looking for what a good percentage was!). That made me laugh, so it stuck.

If the roll is such that the damage will be critical, another roll is cast to determine the critical damage multiplier, which can be anywhere from 2.0 to 5.0. If a critical hit does occur, it is logged in the Apocalypse event log so the stream can see the details, and a lovely Chocobo “Kweh” (or “Woheeho”, or “Wark”!?) sound effect is played live for all the sleeping viewers to wake up to.

Kamehameha

I love it when overwhelming odds are stacked against the player; creating those very kinds of experiences are what I do! However, I do love it when there’s that very, very rare bit of RNG that can just change everything. Something that should only ever happen once per game, if even that. With the Apocalypse system, the chance for a Kamehameha is that something.

Yes, the term “Kamehameha” is a reference to that ultimate attack ability used by the protagonist in Dragon Ball Z…and that’s basically what it is. An attack that does a ridiculous amount of damage. 10000x the amount of damage that would’ve been otherwise applied, actually. When one occurs, the audience will hear Goku doing his “Kamehameha” war cry (from the Japanese version of the show — apparently people find this version annoying so I thought it perfect!).

But, there’s only a 1 in 1000 chance for it to occur for any given attack by the player. So…it definitely doesn’t happen that much. But if it does, and if it happens to be on the right target, it is game changing! RNG is RNG however, and sometimes we’ll go through entire games without having it go off!

This is checked after the critical hit chance rolls, so it is technically possible for a critical attack to also be Kamehameha’d. Not sure if that’s ever happened however! Also completely unnecessary.

Player Damage Statistics

The Enemy Apocalypse is the ultimate authority on how much damage enemies receive from the player. Because of this, it is also responsible for statistical data collection of the player’s damage to enemies; indeed, this is the primary purpose of the Enemy Apocalypse.

The Enemy Apocalypse is responsible for maintaining three player damage related stats:

  • lastDamageByPlayer: The most recent amount of damage done by the player.
  • maxDamageByPlayer: The highest amount of damage done by the player during the current session.
  • totalDamageByPlayer: The cumulative amount of damage done by the player over the current session.

Like how the Player Apocalypse handles its own statistics, these are made available as simple text dumps for on-stream display, with more to come in the future.

And that’s the Enemy Apocalypse for you. Now that basic mechanics have been covered, we’ll go over the API for the Apocalypse system, used to integrate it into whatever game we’re hacking.

Apocalypse System API

Integration of the Apocalypse system and its subsystems require proper construction of initiation points that call Player and Enemy Apocalypse functions when the game is processing incoming damage. This section serves to list these functions, the parameters they require, and other important information certain to be useful if correct operation is desired.

All external parameters supported by the Apocalypse system are also covered here. These allow for extensive customization of the Apocalypse system’s behavior from a consuming hack.

The physical organization and location of the functions described in this section is covered in the next section after this that provides an overview of the Apocalypse code itself.

Player Apocalypse Function

Player Apocalypse functionality is initiated by calling the executePlayerApocalypse function. It must be called whenever the player is receiving enemy damage.

Parameters

  1. Damage Amount
    • Data Type: float
    • This is the amount of damage the game is trying to apply to the players health.
    • Expected to be a positive value.
    • Damage amounts below a configurable threshold will be ignored by the Apocalypse system.
  2. Player’s Current Health Value
    • Data Type: float
    • While this will often be identical to the source of truth for the player’s current health in memory, it is most important that the value provided here is what is being used as the working health value that is about to have the damage amount subtracted from it in the original game code. This temporary value will either be stored in a register or nearby on the stack. More information will be provided in additional initiation point implementation information found below.
  3. Player’s Maximum Health Value
    • Data Type: float
    • This is used if a spontaneous orgasm (full heal) outcome is rolled.
  4. Player Coordinates (aligned at X-coordinate)
    • Data Type: memory address
    • This must be the address in memory to the start of the player’s live location coordinates.
    • The coordinates may be directly manipulated by the Apocalypse function, so it must be the source of truth for the player’s coordinates.
    • The data type of the individual coordinates is expected to be floating point. I have only hacked a single game that used anything other than floating point for player coordinates (and it was only used when the player was on land and not underwater). Support will be added for additional data types if needed.

Return Values

  • eax: Set to an updated damage amount.
  • ebx: Set to an updated working health value for the player.

Initiation Point Implementation

The location of an Omnified process’s initiation point is critical in the successful operation of all Omnified game-neutral systems. The initiation point for the Player Apocalypse needs to be injected right into the game’s damage application code for damage occurring to the player.

The damage application code is made up of instructions that are applying a damage amount to a current, working health value. It is many times a simple arithmetic operation that is taking a current health value, and subtracting the damage amount from it.

This is markedly different from the much more easily located health update code, which is where the player’s source of truth health value is being assigned a new, updated health value (that has had an amount of damage subtracted from it).

Finding the damage application code requires the that the intrepid reverse engineer start at the health update code (easily found by looking for code writing to the health in memory), and then working your way backwards. The damage update code can sometimes be very far from the health update code, and it is sometimes nearby.

To learn skills and techniques that will help you do this, check out Apocalypse implementation articles I’ve written for specific games.

Around 60% of the games I’ve Omnified use the same damage application code for both damage going to the player and damage going to enemies. The remaining 40% have had separate (and sometimes very far apart in terms of location in the code) damage application code functions for damage going to the player vs enemies.

So, obviously, in the event that damage application code is being shared between the two, you’ll want to ensure that we can identify the target and see if it matches known player vitality structures.

When you’ve found a good place for the initiation point, you should be able to provide values for the damage amount and working player health easily. Once the Player Apocalypse function is done executing, you will want to replace the values where you got the damage amount and working player health from with the values found in the eax and ebx registers respectively.

Enemy Apocalypse Function

Enemy Apocalypse functionality is initiated by calling the executeEnemyApocalypse function. It must be called whenever enemies are receiving damage from the player, and only the player.

Parameters

  1. Damage Amount
    • Data Type: float
    • This is the amount of damage the game is trying to apply to the enemy’s health.
    • Expected to be a positive value.
    • Damage amounts below a configurable threshold will be ignored by the Apocalypse system.
  2. Enemy’s Current Health Value
    • Data Type: float
    • Much like the second parameter for the executePlayerApocalypse function, it is better if this is the working, temporary value of the health involved in the damage application operation.

Return Values

  • eax: Set to an updated damage amount.
  • ebx: Set to an updated working health value for the enemy.

Initiation Point Implementation

Refer to the Initiation Point Implementation section for the executePlayerApocalypse function. All of that applies here as well, except that we should only be calling this function if an enemy is receiving the damage. Additionally, we ideally only want to call this if it is the player that is doing the damage.

The purpose of the Enemy Apocalypse is to record player-specific damage statistics as well as shape the damage done by the player. It is not intended to handle damage to enemies from other enemies or the environment. This can lead to “Chocobo overload” (as I like to put it) during big battles with all the critical hits going off.

While determining the target of the damage is typically very easy to do, determining the source of the damage is something I’ve observed to often be very difficult. The damage application code may exist as a common routine purposed for abstract number crunching and it has no need at all to know where the damage is coming from. You will need to really flex your reverse engineering muscles to find it.

Luckily for you, can pick up tips and techniques I use to find this sort of thing by referring to my (hopefully soon to be many) game-specific Apocalypse implementation articles.

External Parameters

The Apocalypse system, like the other Omnified systems, have a number of configurable parameters that we can set to fine tune the system’s implementation into a particular game. To change the value of these parameters, we simple can re-define the value right under the Apocalypse systems’ initiation points like so:

Example of Changing Parameter Value

nameOfExternalParameter:
  dd (float)3.0

The above code changes the value of this parameter from whatever its default is to a new value of 3.0. Let’s now go over all the external parameters made available by the Apocalypse system:

  • damageThreshold
    • Data Type: float
    • Default: 3.5
    • This is the minimum value the damage amount must be to be eligible for Apocalypse system processing. This is useful to avoid insignificant dot damage triggering random effect rolls. This parameter also helps in getting around issues that will occur for games that enjoy executing damage application code even if the damage amount is 0.
  • negativeVerticalDisplacementEnabled
    • Data Type: 4 bytes
    • Default: 1
    • Normally, the vertical axis is subjected to the same range of potential modification during teleportitis as the other axes (+/-5). Obviously, if the vertical axis is changed by a negative amount, it can (and often will) result in the player falling through the ground.
    • This is great as falling through the ground into the abyss and dying is one of the most hilarious deaths possible — however, not all games have a “killzone” beneath the walkable terrain (cough Monster Hunter World cough).
    • When that is the case, the player will just fall forever, probably in a sort of loop. This is obviously not good behavior, and is why this option exists. When negative vertical displacement is disabled, the vertical axis will instead be subjected to a (base) 0-10 modification range.
    • Setting this to any value other than 1 disables the option.
  • yIsVertical
    • Data Type: 4 bytes
    • Default: 1
    • Because the vertical axis is treated differently during teleportitis, it is important to know exactly which coordinate axis is the vertical one. In most games, the Y axis is, however there are a few I’ve encountered where the Z axis is instead.
    • Setting this to any value other than 1 will cause the Z axis to be treated as the vertical axis.
  • teleportDisplacementX
    • Data Type: float
    • Default: 1.0
    • The base +/-5 randomly generated displacement amounts generated during teleportitis are multiplied by this prior to effectuating the change. So, if you wish to, for example, double the average displacement amounts, you would want to set this to 2.0, etc.
  • extraDamageX
    • Data Type: float
    • Default: 2.0
    • Rolling a 1 through 4 during the Player Apocalypse primary dice roll will multiply the base damage amount by extraDamageX. This effect is the most likely outcome of any that can occur during the primary dice roll.
    • This essentially means that the majority of damage done in the game will always be higher than it ever would’ve been in a non-Omnified game; however, in some games, double damage is still not enough to present a challenge (cough Yakuza cough), and this allows us to bump up the typical damage to be higher.
    • Be aware, however, that the intention behind the extra damage effect is for it to seriously maim the character, and not one-shot them typically (that’s for the 69’s baby!). So if too many one shots are occurring from extra damage rolls, you could lower this — interestingly enough, however, I’ve never lowered this to below 2.0. I’ve actually only ever increased it. I’ve made other changes to gameplay to ensure a fine balance of one-shots and maim-shots.
  • playerGodMode
    • Data Type: 4 bytes
    • Default: 0
    • If this is set to 1, then no Apocalypse rolls will occur when the player receives damage, and damage is reset. If the Apocalypse system has been implemented correctly, the player will be impervious to damage from enemies.
    • Only dirty cheaters would ever think of using this.
    • Great for testing though!
  • gokuResultUpper
    • Data Type: 4 bytes
    • Default: 1000 (decimal)
    • This is the upper bounds for the Kamehameha roll during the Enemy Apocalypse. A Kamehameha will only occur if the resulting random roll yields a value of 69 (decimal), so increasing this will decrease the odds of that happening.
    • 1 in 1000 is, from my experience, good odds for this powerful ability — however you may wish to increase this value for games where attacks from the player are very rapid (for example, this was increased to 5000 for Yakuza 0).
  • playerCritChanceResultUpper
    • Data Type: 4 bytes
    • Default: 800 (decimal)
    • This is the upper bounds for the critical hit chance roll during the Enemy Apocalypse. Increasing this will decrease the chance of a critical hit occurring.
  • playerCritDamageResultUpper
    • Data Type: 4 bytes
    • Default: 50
    • This is the upper bounds for the critical damage roll during the Enemy Apocalypse. The damage roll is divided by 10.0 to get the final (in float) damage amount. So, to increase the maximum damage to, let’s say, 6.5x, you’d want to set this to 65.
  • playerCritDamageResultLower
    • Data Type: 4 bytes
    • Default: 20
    • This is the lower bounds for the critical damage roll during the Enemy Apocalypse. The damage roll is divided by 10.0 to get the final (in float) damage amount. So, to decrease the minimum damage to, let’s say, 1.5x, you’d want to set this to 15.
  • disableTeleportitis
    • Data Type: 4 bytes
    • Default: 0
    • This will disable the teleportitis effect from being applied to the player if set to 1. Instead, the default effect of Extra Damage will be applied.
  • disableSixtyNine
    • Data Type: 4 bytes
    • Default: 0
    • This will disable the sixty nine effect from being applied to the player if set to 1. Instead, the default Risk of Murder effect of Normal Damage will be applied.

Note that other symbols like the ones listed above do exist in the Apocalypse code, however they really aren’t intended to ever be changed outside of the Omnified framework. You will only ever see the above parameters modified in Omnified game hacks that use the Apocalypse system.

Apocalypse System Code Analysis

Let’s take a look at how the Apocalypse system actually works. The code for the Apocalypse system can be found in the Omnified framework library file (Omnified.lua) and is referenced and imported by a particular Omnified game’s hack file.

I’ll be writing an Omnified Design article talking about how I make use of these kinds of “include files” inside the assembly in Cheat Engine, and will link it here when that becomes available!

We’re going to take a look at the code inside the Omnified framework right now that deals with the Apocalypse system. To find examples and explanations for writing code to consume the Apocalypse functions, I again will refer you to the various Apocalypse implementation articles that have been written for my Omnified games.

Player Apocalypse

The Player Apocalypse’s code is found in the function executePlayerApocalypse. Refer to the Apocalypse System API section above for high level information concerning this function. In this section, we’re going to get down and dirty with the code.

The chief responsibility of the code at the start of the Player Apocalypse function is to preserve all the data found in registers that we’ll be writing to. Following that, it must load the parameters for the function required at the start from the stack into temporary registers so we can work with them.

The only registers that aren’t backed up are the registers that we’ll be using to hold the function’s return values: rax and rbx. Also, while I normally back up conditional registers in most of my assembly injections (with pushf and popf), note that I do not do that here, as this is code to be called from our code, and not code that is an invader in enemy lands (i.e. not-our-code).

Finally, we determine whether or not we want Player Apocalypse execution to occur; if the damage amount is below our configured damage threshold or if God Mode is enabled, we do not want execution to occur and we exit immediately.

Player Apocalypse Code – First Steps

executePlayerApocalypse:
  // Backing up a few SSE registers we'll be using to
  // hold the parameters provided to this function.
  sub rsp,10
  movdqu [rsp],xmm0
  sub rsp,10
  movdqu [rsp],xmm1
  sub rsp,10
  movdqu [rsp],xmm2
  sub rsp,10
  movdqu [rsp],xmm3  
  // Load the player's health parameter.
  movss xmm3,[rsp+58]
  // Load the damage amount parameter.
  movss xmm0,[rsp+60]
  // Check if the damage being done is enough to warrant Apocalypse execution.
  mov rax,damageThreshold
  ucomiss xmm0,[rax]  
  jbe exitPlayerApocalypse
  // If God Mode is disabled, then we apply the Apocalypse.
  cmp [playerGodMode],1
  jne applyApocalypse
  // Otherwise, we zero out our final damage amount register and exit.
  xorps xmm0,xmm0
  jmp exitPlayerApocalypse  

Once we’ve determine to go on and apply the Apocalypse, we go about conducting the main function of the Player Apocalypse: the primary dice roll. We then direct execution to the particular area of code corresponding to whatever effect must occur due to the result of the roll.

Player Apocalypse Code – Primary Dice Roll

applyApocalypse:
  // Load the parameters for generating the dice roll random number.
  push [apocalypseResultLower]
  push [apocalypseResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the "apocalypseResult"
  // symbol so that the value can be displayed by the event logging display code.
  mov [apocalypseResult],eax
  cmp eax,4
  jle extraDamage
  cmp eax,6
  jle teleportitis
  cmp eax,9
  jle riskOfMurder
  jmp suddenGasm

The labels used in the jump statements should all be self-explanatory as they all correspond to the effect documented in the Player Apocalypse Basic Mechanics section.

The first effect we must implement is the extra damage effect. It occurs if the roll is 1 through 4. This is a rather simple effect to implement; all it must do is multiply the working damage amount by the extraDamageX external parameter.

Player Apocalypse Code – Extra Damage

extraDamage:
  mulss xmm0,[extraDamageX]
  jmp updateEnemyDamageStats

The next effect to implement is the much more complicated teleportitis effect, which occurs if the roll is 5 or 6. Refer to the basic mechanics section for a high level description of what teleportitis does.

Player Apocalypse Code – Teleportitis

teleportitis:
  // Check if teleportitis is disabled. If so, we instead apply extra damage.
  cmp [disableTeleportitis],1
  jne commitTeleportitis
  mov [apocalypseResult],1
  jmp extraDamage
commitTeleportitis:
  // Some games will disable modifications being made to the player's coordinates
  // during certain animations such as weapon attacks or getting knocked back.
  // This code needs to be hooked into and temporarily disabled in order for 
  // teleportitis to work. This can be done by checking the "teleported" symbol 
  // and preventing those coordinates from being reset. That code will then 
  // need to set this symbol to 0. In most games I've hacked, this is not 
  // required. In fact, only one: Dark Souls I.
  mov [teleported],1
  // Load the player coordinates address parameter.
  mov rbx,[rsp+48]
  // Load the parameters for generating the random displacement value to be 
  // applied to the X coordinate.
  push [teleportitisResultLower]
  push [teleportitisResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  // The random number is an integer and will need to be converted to a float.
  mov [teleportitisResult],eax
  cvtsi2ss xmm1,[teleportitisResult]
  // The random number is divided by the following divisor to bring it into the
  // expected range (0-10) along with some decimal precision (3 decimal places).
  divss xmm1,[teleportitisDivisor]
  // We cannot generate random negative integers, we instead shift what we have 
  // here by a negative amount. The range 0 to 10 becomes -5 to 5.
  subss xmm1,[teleportitisShifter]
  // We finally take what we have and then multiply it by the displacement 
  // multiplier to get the final displacement value to apply to the player's 
  // X coordinate.
  mulss xmm1,[teleportitisDisplacementX]
  // We then take the player's current X coordinate from memory and add the
  // displacement value to it.
  movss xmm2,[rbx]
  addss xmm2,xmm1
  // The updated X coordinate is committed back into the memory, which will 
  // move the player.
  movss [rbx],xmm2
  // Load the parameters for generating the random displacement value to be 
  // applied to the Y coordinate. 
  push [teleportitisResultLower]
  push [teleportitisResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  mov [teleportitisResult],eax
  cvtsi2ss xmm1,[teleportitisResult]
  divss xmm1,[teleportitisDivisor]
  // If the Y-axis is not the vertical axis, then we we don't need to check 
  // whether vertical displacement is enabled.
  cmp [yIsVertical],1
  jne skipYSkipCheck
  // If negative vertical displacement is not enabled we do not want to shift it,
  // this causes the random value to remain in the range of 0 to 10.
  cmp [negativeVerticalDisplacementEnabled],1
  jne skipNegativeVerticalYDisplacement
skipYSkipCheck:
  subss xmm1,[teleportitisShifter]
skipNegativeVerticalYDisplacement:
  mulss xmm1,[teleportitisDisplacementX]
  // The vertical displacement value is logged and displayed to viewers as 
  // changes to are often the most consequential. We make sure the Y-axis is 
  // the vertical one before logging it.
  cmp [yIsVertical],1
  jne skipLastYVerticalDisplacement
  movss [lastVerticalDisplacement],xmm1
skipLastYVerticalDisplacement:
  // We then take the player's current Y coordinate from memory and add the
  // displacement value to it.
  movss xmm2,[rbx+4]
  addss xmm2,xmm1
  // The updated Y coordinate is committed back into the memory, which will 
  // move the player.
  movss [rbx+4],xmm2
  // Load the parameters for generating the random displacement value to be 
  // applied to the Z coordinate. 
  push [teleportitisResultLower]
  push [teleportitisResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  mov [teleportitisResult],eax
  cvtsi2ss xmm1,[teleportitisResult]
  divss xmm1,[teleportitisDivisor]
  // Like the Y-axis, the Z-axis can sometimes be the vertical axis. So checks 
  // similar to the ones made in the Y coordinate displacement code are made.
  cmp [yIsVertical],0
  jne skipZSkipCheck
  cmp [negativeVerticalDisplacementEnabled],1
  jne skipNegativeVerticalZDisplacement
skipZSkipCheck:
  subss xmm1,[teleportitisShifter]
skipNegativeVerticalZDisplacement:
  mulss xmm1,[teleportitisDisplacementX]
  cmp [yIsVertical],0
  jne skipLastZVerticalDisplacement
  movss [lastVerticalDisplacement],xmm1
skipLastZVerticalDisplacement:
  // We then take the player's current Z coordinate from memory and add the
  // displacement value to it.
  movss xmm2,[rbx+8]
  addss xmm2,xmm1
  // The updated Z coordinate is committed back into the memory, which will 
  // move the player.
  movss [rbx+8],xmm2
  jmp updateEnemyDamageStats

Next, we need to implement the effect that occurs if the roll is 7, 8, or 9: the risk of murder roll. This is another dice roll that then needs to occur, be logged, and have its own special effects executed. Let’s go over the code for this special roll as well as all of its effects.

Player Apocalypse Code – Risk of Murder Roll

riskOfMurder:
  // Load the parameters for generating the Risk of Murder dice roll random 
  // number.
  push [riskOfMurderResultLower]
  push [riskOfMurderResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our Risk of Murder roll is in eax -- we back it up to the "riskOfMurder" 
  // symbol so that the value can be displayed by the event logging display code.
  mov [riskOfMurderResult],eax
  cmp eax,3
  // If the resulting roll is 1 to 3, normal damage applies, which means we don't
  // need to do anything at all.
  jle updateEnemyDamageStats
  jmp sixtyNine
sixtyNine:
  // Check if sixty nine is disabled, if so, just apply normal damage.
  cmp [disableSixtyNine],1
  jne commitSixtyNine
  mov [riskOfMurderResult],1
  jmp updateEnemyDamageStats
commitSixtyNine:
  mulss xmm0,[sixtyNineDamageX]
  jmp updateEnemyDamageStats

The final effect from the primary dice roll is the sudden orgasm effect, which is only if the roll lands on a 10 (decimal). This needs to heal the player to full and nullify the damage.

Player Apocalypse Code – Sudden Orgasm

suddenGasm:  
  // Load the player's maximum health parameter. This is stored in the final 
  // player health (prior to damage applied) register.
  movss xmm3,[rsp+50]
  // We zero out our final damage amount register.
  xorps xmm0,xmm0
  jmp applyPlayerApocalypseExit

All effects are implemented! We are getting to the end. The final parts of the code need to update the three separate game statistics being maintained by the Player Apocalypse, set the return values, and restore backed up values to the stack.

Player Apocalypse Code – Update Stats and Cleanup

updateEnemyDamageStats:
  // If the final damage amount is less than or equal to the current max damage 
  // to the player, it doesn't need to be updated obviously!
  ucomiss xmm0,[maxDamageToPlayer]
  jna skipMaxEnemyDamageUpdate
  movss [maxDamageToPlayer],xmm0
skipMaxEnemyDamageUpdate:
  // We save the final damage amount as the last damage to be done to the player,
  // and add it to the running total.
  movss [lastDamageToPlayer],xmm0
  movss xmm1,xmm0
  addss xmm1,[totalDamageToPlayer]
  movss [totalDamageToPlayer],xmm1
applyPlayerApocalypseExit:
  // Because Apocalypse execution is complete, we trigger an event log entry for 
  // it by setting "logApocalypse" to 1.
  mov [logApocalypse],1
  jmp exitPlayerApocalypse
exitPlayerApocalypse:
  // We commit our final damage amount to eax.
  movd eax,xmm0
  // We commit our final working player health to ebx.
  movd ebx,xmm3
  // Restore backed up values.
  movdqu xmm3,[rsp]
  add rsp,10
  movdqu xmm2,[rsp]
  add rsp,10
  movdqu xmm1,[rsp]
  add rsp,10
  movdqu xmm0,[rsp]
  add rsp,10  
  // This function has 4 parameters, each require 8 bytes. 4x8 == 20 (hex).
  ret 20

Tada! We’ve covered the code for the Player Apocalypse. To get the entire working code, check out the complete Apocalypse code section.

Enemy Apocalypse

The Enemy Apocalypse’s code is found in the function executeEnemyApocalypse. Refer to the Apocalypse System API section above for high level information concerning this function. Let’s get down and dirty with this little bit of code now!

Much like the Player Apocalypse code, the chief responsibility of the code at the start of this function is to preserve data to the stack and to load parameter values that are needed. Also like the Player Apocalypse code, the eax and ebx registers aren’t backed up as they are used as return values.

And finally…also like the Player Apocalypse code, we want to completely forego Enemy Apocalypse execution if the damage doesn’t meet defined thresholds — fortunately for us, there is no God Mode for enemies!

Enemy Apocalypse Code – First Steps

executeEnemyApocalypse:
  // Backing up a few SSE registers we'll be using to
  // hold the parameters provided to this function.
  sub rsp,10
  movdqu [rsp],xmm0
  sub rsp,10
  movdqu [rsp],xmm1  
  sub rsp,10
  movdqu [rsp],xmm2
  // Load the enemy's health parameter.  
  movss xmm1,[rsp+38]
  // Load the damage amount parameter.
  movss xmm0,[rsp+40]
  // Check if the damage being done is enough to warrant Apocalypse execution.
  mov rax,damageThreshold
  ucomiss xmm0,[rax]  
  jbe exitEnemyApocalypse  

Already simpler than the Player Apocalypse! The next thing we need to do is apply the player damage multiplier to the damage amount and perform critical hit chance evaluation. If the hit is a critical one, we want to then see how much extra damage is done, otherwise we continue on.

Enemy Apocalypse Code – Base Damage and Critical Hits

applyPlayerDamage:
  // Apply our base player damage multiplier to the damage amount.
  mulss xmm0,[playerDamageX]
  // Load the parameters for generating the critical hit check.
  push [playerCritChanceResultLower]
  push [playerCritChanceResultUpper]
  mov rax,enemyApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the 
  // "playerCritChanceResult" symbol so that the value can be displayed by the 
  // event logging display code.
  mov [playerCritChanceResult],eax
  // We can't generate random floats, only random integers. So, to have 
  // a 6.25% crit chance, we generate a number in the range of 0 to 400, and 
  // then check if the value is less than or equal to 25 (25/400 = 0.0625).
  cmp eax,25
  jg checkKamehameha  
  // Load the parameters for generating the critical hit damage.
  push [playerCritDamageResultLower]
  push [playerCritDamageResultUpper]
  mov rax,enemyApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the 
  // "playerCritDamageResult" symbol so that the value can be displayed by 
  // the event logging display code.
  mov [playerCritDamageResult],eax
  // We can't generate floating point random numbers, so we convert it to float
  // and divide it by our divisor to put it in range with one level of decimal
  // precision.
  cvtsi2ss xmm2,[playerCritDamageResult]
  divss xmm2,[playerCritDamageDivisor]
  mulss xmm0,xmm2
  // We signal to the event logging system that a crit occurred by setting
  // the "logPlayerCrit" symbol to 1.
  mov [logPlayerCrit],1

We now have a beautifully functional critical hit system in any game of our choosing! Next we need to implement the final pro-player goodie: the amazing Kamehameha!

Enemy Apocalypse Code – Kamehameha

checkKamehameha:
  // Load the parameters for generating the Kamehameha check.
  push [gokuResultLower]
  push [gokuResultUpper]
  mov rax,enemyApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the "gokuResult"
  // symbol so that the value can be displayed by the event logging display code.
  mov [gokuResult],eax
  // If the roll is exactly 69, a Kamehameha has occurred! Big damage time baby.
  cmp eax,#69
  jne updatePlayerDamageStats
  // We signal to the event logging system that a Kamehameha occurred by setting
  // the "logKamehameha" symbol to 1.
  mov [logKamehameha],1
  mulss xmm0,[gokuDamageX]  

The final bits of code deal with updating relevant damage statistics, setting return values, and restoring backed up values. All very similar to the Player Apocalypse, except in the enemy domain.

Enemy Apocalypse Code – Update Stats and Cleanup

updatePlayerDamageStats:
  // Sometimes the enemy health is hidden from the player by the game. Well I like
  // flexing my muscle and displaying it anyway on stream with the 
  // "lastEnemyHealthValue" symbol. We perform a mock damage application here and 
  // store it there.
  subss xmm1,xmm0
  movss [lastEnemyHealthValue],xmm1
  // If the final damage amount is less than or equal to the current max damage 
  // from the player, it doesn't need to be updated obviously!
  ucomiss xmm0,[maxDamageByPlayer]
  jna skipMaxPlayerDamageUpdate
  movss [maxDamageByPlayer],xmm0
skipMaxPlayerDamageUpdate:
  // We save the final damage amount as the last damage to be done from the 
  // player, and add it to the running total.
  movss [lastDamageByPlayer],xmm0
  movss xmm1,xmm0
  addss xmm1,[totalDamageByPlayer]
  movss [totalDamageByPlayer],xmm1
exitEnemyApocalypse:
  // We commit our final damage amount to eax.
  movd eax,xmm0
  // We commit our final damage amount to ebx, which actually never changes. It
  // is simply used to calculate what the health will be to display with the
  // "lastEnemyHealthValue" stat, and also for purposes of polymorphism, in a 
  // manner of speaking.
  movss xmm1,[rsp+38]
  movd ebx,xmm1
  movdqu xmm2,[rsp]
  add rsp,10
  movdqu xmm1,[rsp]
  add rsp,10
  movdqu xmm0,[rsp]
  add rsp,10
  // This function has 2 parameters, each require 8 bytes. 2x8 == 10 (hex).
  ret 10

Hooray! That’s all the code for the Apocalypse system!

Well almost. You may be wondering about the code that actually ends up displaying all the events and stats to the viewer on the stream. Well, these technologies are actually independent of the Apocalypse system, and are meant to be used with other systems and code as well.

I have some big things going on with them, development-wise, and when that concludes, that technology will get its own article. Until then, let it suffice to say that the data is made available by the already provided assembly code, and that we have a bunch of LUA running on an independent timer throwing all the data together and piping it out to the stream.

Complete Code for the Apocalypse

Here is the complete code for the Apocalypse system. Note that the cleanup portion of the code is not included — it is all boilerplate and simple dealloc and unregistersymbol statements. I’ll be putting up an actual code repository and/or download for the Omnified framework sooner or later, and if you need it real bad, you can grab it for there.

Let’s start with the Player Apocalypse:

Player Apocalypse Code – Complete

// Player Apocalypse System Function
// [rsp+48]: Player's coordinates (aligned at X-coord)
// [rsp+50]: Max Player Health Amount
// [rsp+58]: Player's Health Amount
// [rsp+60]: Damage Amount
// Updated damage is in EAX. 
// Updated health before damage is in EBX.
alloc(executePlayerApocalypse,$1000)
alloc(playerApocalypseRandomState,8)
alloc(logApocalypse,8)
alloc(negativeOne,8)
alloc(apocalypseResult,8)
alloc(apocalypseResultUpper,8)
alloc(apocalypseResultLower,8)
alloc(teleported,8)
alloc(teleportitisResult,8)
alloc(teleportitisResultUpper,8)
alloc(teleportitisResultLower,8)
alloc(teleportitisDivisor,8)
alloc(teleportitisShifter,8)
alloc(lastVerticalDisplacement,8)
alloc(negativeVerticalDisplacementEnabled,8)
alloc(yIsVertical,8)
alloc(teleportitisDisplacementX,8)
alloc(riskOfMurderResult,8)
alloc(riskOfMurderResultUpper,8)
alloc(riskOfMurderResultLower,8)
alloc(extraDamageX,8)
alloc(sixtyNineDamageX,8)
alloc(maxDamageToPlayer,8)
alloc(lastDamageToPlayer,8)
alloc(totalDamageToPlayer,8)
alloc(playerGodMode,8)
alloc(disableTeleportitis,8)
alloc(disableSixtyNine,8)

registersymbol(executePlayerApocalypse)
registersymbol(logApocalypse)
registersymbol(teleported)
registersymbol(apocalypseResult)
registersymbol(negativeVerticalDisplacementEnabled)
registersymbol(yIsVertical)
registersymbol(teleportitisDisplacementX)
registersymbol(riskOfMurderResult)
registersymbol(extraDamageX)
registersymbol(maxDamageToPlayer)
registersymbol(lastDamageToPlayer)
registersymbol(totalDamageToPlayer)
registersymbol(lastVerticalDisplacement)
registersymbol(playerGodMode)
registersymbol(disableTeleportitis)
registersymbol(disableSixtyNine)

executePlayerApocalypse:
  // Backing up a few SSE registers we'll be using to
  // hold the parameters provided to this function.
  sub rsp,10
  movdqu [rsp],xmm0
  sub rsp,10
  movdqu [rsp],xmm1
  sub rsp,10
  movdqu [rsp],xmm2
  sub rsp,10
  movdqu [rsp],xmm3  
  // Load the player's health parameter.
  movss xmm3,[rsp+58]
  // Load the damage amount parameter.
  movss xmm0,[rsp+60]
  // Check if the damage being done is enough to warrant Apocalypse execution.
  mov rax,damageThreshold
  ucomiss xmm0,[rax]  
  jbe exitPlayerApocalypse
  // If God Mode is disabled, then we apply the Apocalypse.
  cmp [playerGodMode],1
  jne applyApocalypse
  // Otherwise, we zero out our final damage amount register and exit.
  xorps xmm0,xmm0
  jmp exitPlayerApocalypse  
applyApocalypse:
  // Load the parameters for generating the dice roll random number.
  push [apocalypseResultLower]
  push [apocalypseResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the "apocalypseResult"
  // symbol so that the value can be displayed by the event logging display code.
  mov [apocalypseResult],eax
  cmp eax,4
  jle extraDamage
  cmp eax,6
  jle teleportitis
  cmp eax,9
  jle riskOfMurder
  jmp suddenGasm
extraDamage:
  mulss xmm0,[extraDamageX]
  jmp updateEnemyDamageStats
teleportitis:
  // Check if teleportitis is disabled. If so, we instead apply extra damage.
  cmp [disableTeleportitis],1
  jne commitTeleportitis
  mov [apocalypseResult],1
  jmp extraDamage
commitTeleportitis:
  // Some games will disable modifications being made to the player's coordinates
  // during certain animations such as weapon attacks or getting knocked back.
  // This code needs to be hooked into and temporarily disabled in order for 
  // teleportitis to work. This can be done by checking the "teleported" symbol 
  // and preventing those coordinates from being reset. That code will then 
  // need to set this symbol to 0. In most games I've hacked, this is not 
  // required. In fact, only one: Dark Souls I.
  mov [teleported],1
  // Load the player coordinates address parameter.
  mov rbx,[rsp+48]
  // Load the parameters for generating the random displacement value to be 
  // applied to the X coordinate.
  push [teleportitisResultLower]
  push [teleportitisResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  // The random number is an integer and will need to be converted to a float.
  mov [teleportitisResult],eax
  cvtsi2ss xmm1,[teleportitisResult]
  // The random number is divided by the following divisor to bring it into the
  // expected range (0-10) along with some decimal precision (3 decimal places).
  divss xmm1,[teleportitisDivisor]
  // We cannot generate random negative integers, we instead shift what we have 
  // here by a negative amount. The range 0 to 10 becomes -5 to 5.
  subss xmm1,[teleportitisShifter]
  // We finally take what we have and then multiply it by the displacement 
  // multiplier to get the final displacement value to apply to the player's 
  // X coordinate.
  mulss xmm1,[teleportitisDisplacementX]
  // We then take the player's current X coordinate from memory and add the
  // displacement value to it.
  movss xmm2,[rbx]
  addss xmm2,xmm1
  // The updated X coordinate is committed back into the memory, which will 
  // move the player.
  movss [rbx],xmm2
  // Load the parameters for generating the random displacement value to be 
  // applied to the Y coordinate. 
  push [teleportitisResultLower]
  push [teleportitisResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  mov [teleportitisResult],eax
  cvtsi2ss xmm1,[teleportitisResult]
  divss xmm1,[teleportitisDivisor]
  // If the Y-axis is not the vertical axis, then we we don't need to check 
  // whether vertical displacement is enabled.
  cmp [yIsVertical],1
  jne skipYSkipCheck
  // If negative vertical displacement is not enabled we do not want to shift it,
  // this causes the random value to remain in the range of 0 to 10.
  cmp [negativeVerticalDisplacementEnabled],1
  jne skipNegativeVerticalYDisplacement
skipYSkipCheck:
  subss xmm1,[teleportitisShifter]
skipNegativeVerticalYDisplacement:
  mulss xmm1,[teleportitisDisplacementX]
  // The vertical displacement value is logged and displayed to viewers as 
  // changes to are often the most consequential. We make sure the Y-axis is 
  // the vertical one before logging it.
  cmp [yIsVertical],1
  jne skipLastYVerticalDisplacement
  movss [lastVerticalDisplacement],xmm1
skipLastYVerticalDisplacement:
  // We then take the player's current Y coordinate from memory and add the
  // displacement value to it.
  movss xmm2,[rbx+4]
  addss xmm2,xmm1
  // The updated Y coordinate is commited back into the memory, which will 
  // move the player.
  movss [rbx+4],xmm2
  // Load the parameters for generating the random displacement value to be 
  // applied to the Z coordinate. 
  push [teleportitisResultLower]
  push [teleportitisResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  mov [teleportitisResult],eax
  cvtsi2ss xmm1,[teleportitisResult]
  divss xmm1,[teleportitisDivisor]
  // Like the Y-axis, the Z-axis can sometimes be the vertical axis. So checks 
  // similar to the ones made in the Y coordinate displacement code are made.
  cmp [yIsVertical],0
  jne skipZSkipCheck
  cmp [negativeVerticalDisplacementEnabled],1
  jne skipNegativeVerticalZDisplacement
skipZSkipCheck:
  subss xmm1,[teleportitisShifter]
skipNegativeVerticalZDisplacement:
  mulss xmm1,[teleportitisDisplacementX]
  cmp [yIsVertical],0
  jne skipLastZVerticalDisplacement
  movss [lastVerticalDisplacement],xmm1
skipLastZVerticalDisplacement:
  // We then take the player's current Z coordinate from memory and add the
  // displacement value to it.
  movss xmm2,[rbx+8]
  addss xmm2,xmm1
  // The updated Z coordinate is commited back into the memory, which will 
  // move the player.
  movss [rbx+8],xmm2
  jmp updateEnemyDamageStats
riskOfMurder:
  // Load the parameters for generating the Risk of Murder dice roll random 
  // number.
  push [riskOfMurderResultLower]
  push [riskOfMurderResultUpper]
  mov rax,playerApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our Risk of Murder roll is in eax -- we back it up to the "riskOfMurder" 
  // symbol so that the value can be displayed by the event logging display code.
  mov [riskOfMurderResult],eax
  cmp eax,3
  // If the resulting roll is 1 to 3, normal damage applies, which means we don't
  // need to do anything at all.
  jle updateEnemyDamageStats
  jmp sixtyNine
sixtyNine:
  // Check if sixty nine is disabled, if so, just apply normal damage.
  cmp [disableSixtyNine],1
  jne commitSixtyNine
  mov [riskOfMurderResult],1
  jmp updateEnemyDamageStats
commitSixtyNine:
  mulss xmm0,[sixtyNineDamageX]
  jmp updateEnemyDamageStats
suddenGasm:  
  // Load the player's maximum health parameter. This is stored in the final 
  // player health (prior to damage applied) register.
  movss xmm3,[rsp+50]
  // We zero out our final damage amount register.
  xorps xmm0,xmm0
  jmp applyPlayerApocalypseExit
updateEnemyDamageStats:
  // If the final damage amount is less than or equal to the current max damage 
  // to the player, it doesn't need to be updated obviously!
  ucomiss xmm0,[maxDamageToPlayer]
  jna skipMaxEnemyDamageUpdate
  movss [maxDamageToPlayer],xmm0
skipMaxEnemyDamageUpdate:
  // We save the final damage amount as the last damage to be done to the player,
  // and add it to the running total.
  movss [lastDamageToPlayer],xmm0
  movss xmm1,xmm0
  addss xmm1,[totalDamageToPlayer]
  movss [totalDamageToPlayer],xmm1
applyPlayerApocalypseExit:
  // Because Apocalypse execution is complete, we trigger an event log entry for 
  // it by setting "logApocalypse" to 1.
  mov [logApocalypse],1
  jmp exitPlayerApocalypse
exitPlayerApocalypse:
  // We commit our final damage amount to eax.
  movd eax,xmm0
  // We commit our final working player health to ebx.
  movd ebx,xmm3
  // Restore backed up values.
  movdqu xmm3,[rsp]
  add rsp,10
  movdqu xmm2,[rsp]
  add rsp,10
  movdqu xmm1,[rsp]
  add rsp,10
  movdqu xmm0,[rsp]
  add rsp,10  
  // This function has 4 parameters, each require 8 bytes. 4x8 == 20 (hex).
  ret 20
  
playerApocalypseRandomState:
  dd 0
  
logApocalypse:
  dd 0
  
apocalypseResult:
  dd 0
  
apocalypseResultUpper:
  dd #10
  
apocalypseResultLower:
  dd 1
  
teleportitisResult:
  dd 0
  
teleportitisResultUpper:
  dd #10000
  
teleportitisResultLower:
  dd 0
  
teleportitisDivisor:
  dd (float)1000.0
  
teleportitisShifter:
  dd (float)5.0

negativeVerticalDisplacementEnabled:
  dd 1
  
yIsVertical:
  dd 1
  
teleportitisDisplacementX:
  dd (float)2.0
  
negativeOne:
  dd (float)-1.0

riskOfMurderResult:
  dd 0
  
riskOfMurderResultUpper:
  dd #5
  
riskOfMurderResultLower:
  dd 1
  
extraDamageX:
  dd (float)2.0
  
sixtyNineDamageX:
  dd (float)69.0
  
maxDamageToPlayer:
  dd 0
  
lastDamageToPlayer:
  dd 0
  
totalDamageToPlayer:
  dd 0
  
playerGodMode:
  dd 0  
  
disableTeleportitis:
  dd 0
  
disableSixtyNine:
  dd 0

And next, the Enemy Apocalypse code:

Enemy Apocalypse Code – Complete

// Enemy Apocalypse System Function
// [rsp+38]: Target Health Value
// [rsp+40]: Damage Amount
alloc(executeEnemyApocalypse,$1000)
alloc(maxDamageByPlayer,8)
alloc(lastDamageByPlayer,8)
alloc(totalDamageByPlayer,8)
alloc(logKamehameha,8)
alloc(gokuResult,8)
alloc(gokuResultUpper,8)
alloc(gokuResultLower,8)
alloc(gokuDamageX,8)
alloc(playerDamageX,8)
alloc(lastEnemyHealthValue,8)
alloc(playerCritChanceResultUpper,8)
alloc(playerCritChanceResultLower,8)
alloc(playerCritChanceResult,8)
alloc(playerCritDamageResultUpper,8)
alloc(playerCritDamageResultLower,8)
alloc(playerCritDamageResult,8)
alloc(playerCritDamageDivisor,8)
alloc(logPlayerCrit,8)
alloc(enemyApocalypseRandomState,8)

registersymbol(executeEnemyApocalypse)
registersymbol(maxDamageByPlayer)
registersymbol(lastDamageByPlayer)
registersymbol(totalDamageByPlayer)
registersymbol(logKamehameha)
registersymbol(gokuDamageX)
registersymbol(gokuResultUpper)
registersymbol(playerDamageX)
registersymbol(lastEnemyHealthValue)
registersymbol(playerCritDamageResult)
registersymbol(logPlayerCrit)

executeEnemyApocalypse:
  // Backing up a few SSE registers we'll be using to
  // hold the parameters provided to this function.
  sub rsp,10
  movdqu [rsp],xmm0
  sub rsp,10
  movdqu [rsp],xmm1  
  sub rsp,10
  movdqu [rsp],xmm2
  // Load the enemy's health parameter.  
  movss xmm1,[rsp+38]
  // Load the damage amount parameter.
  movss xmm0,[rsp+40]
  // Check if the damage being done is enough to warrant Apocalypse execution.
  mov rax,damageThreshold
  ucomiss xmm0,[rax]  
  jbe exitEnemyApocalypse  
applyPlayerDamage:
  // Apply our base player damage multiplier to the damage amount.
  mulss xmm0,[playerDamageX]
  // Load the parameters for generating the critical hit check.
  push [playerCritChanceResultLower]
  push [playerCritChanceResultUpper]
  mov rax,enemyApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the 
  // "playerCritChanceResult" symbol so that the value can be displayed by the 
  // event logging display code.
  mov [playerCritChanceResult],eax
  // We can't generate random floats, only random integers. So, to have 
  // a 6.25% crit chance, we generate a number in the range of 0 to 400, and 
  // then check if the value is less than or equal to 25 (25/400 = 0.0625).
  cmp eax,25
  jg checkKamehameha  
  // Load the parameters for generating the critical hit damage.
  push [playerCritDamageResultLower]
  push [playerCritDamageResultUpper]
  mov rax,enemyApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the 
  // "playerCritDamageResult" symbol so that the value can be displayed by 
  // the event logging display code.
  mov [playerCritDamageResult],eax
  // We can't generate floating point random numbers, so we convert it to float
  // and divide it by our divisor to put it in range with one level of decimal
  // precision.
  cvtsi2ss xmm2,[playerCritDamageResult]
  divss xmm2,[playerCritDamageDivisor]
  mulss xmm0,xmm2
  // We signal to the event logging system that a crit occurred by setting
  // the "logPlayerCrit" symbol to 1.
  mov [logPlayerCrit],1  
checkKamehameha:
  // Load the parameters for generating the Kamehameha check.
  push [gokuResultLower]
  push [gokuResultUpper]
  mov rax,enemyApocalypseRandomState
  push rax
  call generateRandomNumber
  // Our random roll value is in eax -- we back it up to the "gokuResult"
  // symbol so that the value can be displayed by the event logging display code.
  mov [gokuResult],eax
  // If the roll is exactly 69, a Kamehameha has occurred! Big damage time baby.
  cmp eax,#69
  jne updatePlayerDamageStats
  // We signal to the event logging system that a Kamehameha occurred by setting
  // the "logKamehameha" symbol to 1.
  mov [logKamehameha],1
  mulss xmm0,[gokuDamageX]  
updatePlayerDamageStats:
  // Sometimes the enemy health is hidden from the player by the game. 
  // Well I like flexing my muscle and displaying it anyway on stream with the 
  // "lastEnemyHealthValue" symbol. We perform a mock damage application here and
  // store it there.
  subss xmm1,xmm0
  movss [lastEnemyHealthValue],xmm1
  // If the final damage amount is less than or equal to the current max damage 
  // from the player, it doesn't need to be updated obviously!
  ucomiss xmm0,[maxDamageByPlayer]
  jna skipMaxPlayerDamageUpdate
  movss [maxDamageByPlayer],xmm0
skipMaxPlayerDamageUpdate:
  // We save the final damage amount as the last damage to be done from the 
  // player, and add it to the running total.
  movss [lastDamageByPlayer],xmm0
  movss xmm1,xmm0
  addss xmm1,[totalDamageByPlayer]
  movss [totalDamageByPlayer],xmm1
exitEnemyApocalypse:
  // We commit our final damage amount to eax.
  movd eax,xmm0
  // We commit our final damage amount to ebx, which actually never changes. It
  // is simply used to calculate what the health will be to display with the
  // "lastEnemyHealthValue" stat, and also for purposes of polymorphism, in a 
  // manner of speaking.
  movss xmm1,[rsp+38]
  movd ebx,xmm1
  movdqu xmm2,[rsp]
  add rsp,10
  movdqu xmm1,[rsp]
  add rsp,10
  movdqu xmm0,[rsp]
  add rsp,10
  // This function has 2 parameters, each require 8 bytes. 2x8 == 10 (hex).
  ret 10

 
totalDamageByPlayer:
  dd 0

maxDamageByPlayer:
  dd 0
  
lastDamageByPlayer:
  dd 0  

logKamehameha:
  dd 0

gokuResult:
  dd 0
  
gokuResultUpper:
  dd #1000
  
gokuResultLower:
  dd 0
  
gokuDamageX:
  dd (float)10000.0
  
playerDamageX:
  dd (float)1.0
  
lastEnemyHealthValue:
  dd 0
  
playerCritChanceResult:
  dd 0
  
playerCritChanceResultUpper:
  dd #800
  
playerCritChanceResultLower:
  dd 0
  
playerCritDamageResult:
  dd 0
  
playerCritDamageResultUpper:
  dd #50
  
playerCritDamageResultLower:
  dd #20
  
playerCritDamageDivisor:
  dd (float)10.0
  
logPlayerCrit:
  dd 0
  
enemyApocalypseRandomState:
  dd 0

That’s it for this guide to the very first of my game-neutral Omnified systems. Hope this shed some light on what it is and how it works. If I was able to expand your mind a little bit at all, I am more than satisfied!

To see the insane gameplay that the Apocalypse system affords us, check me out live on my Twitch stream at: https://twitch.tv/omni

Got some questions, ask me on my Discord at: https://discord.gg/omni

Thank you for your interest, and your time. Safe travels.

~Omni