The Halo Random Shotgun
So the video above is my random shotgun, it's a Halo 2 shotgun that shoots one of 19 random projectiles that range from pistol bullets to tank shells, it's totally unpredictable and there's probably a chance that when you shoot it you'll die. It's pretty cool right! But did you know doing this actually took me all day and uses some of the most ingenious hacks I've ever done? Let me explain!
The mod Cursed Halo created by InfernoPlus is a Halo mod that I am inspired by and I wanted to make a mod for it in Halo 2. One of my favourite weapons in cursed halo is the D20 grenade, a grenade that fires a random chaotic effect. I had always wondered how he was able to do this, as I don't see any other mods that involve random effects, so I decided to make a d20 shotgun, a shotgun that shoots random projectiles.
Harder than expected...
So to understand the problem you first must understand how Halo modding works. Halo mod tools does not have access to the actual Halo engine, instead we have access to "tags". Tags are the configuration of objects, there are many different tag types (weapons, vehicles, effects, etc) and they govern the objects behaviour. Having only the configuration to modify may seem limiting, but the good news is Halo was designed as a very open sandbox game so actually changing the configuration gives us a huge amount of freedom. Not only can you change the fire rate or how much damage bullets do, but you can also change the physics of the bullets, which bullet a weapon fires, the model a weapon uses, the animations, and even import your own stuff.
So there's a lot you can do but the limitation is that you have to obey the engine's rules. Anything that's hardcoded in the engine you cannot change yourself, for example the engine hardcodes that 7 needles from the needler causes an explosion, so this is something you can not change. So if we want to create a custom weapon, we have to do so by utilizing behaviours that already exist in the game, mixing and matching them to make our custom weapon, but we cannot add new purely novel behaviours or change existing behaviours.
With that in mind I have some unfortunate news, randomness is not a behaviour that exists natively. There's no "random" function you can call in a tag to get a tag to do something random. Instead, the fields already have to support some randomness behaviour to begin with, otherwise you can't use this. And, unfortunately for us, what projectile a weapon fires is NOT a random behaviour, it will always be deterministic. So, then how did I do this?
Firing Effects
What projectile a weapon fires is deterministic and not something you can change, but I did notice an interesting flag that said "randomize firing effects". When you fire a gun in Halo it makes a noise, has some muzzle flashes and what-not, these are known as firing effects. A weapon can have multiple firing effects and then cycle through those firing effects to add a little diversity in the animation. Instead of cycling through the firing effects sequentially, by enabling this flag you can cycle through the firing effects randomly. Ok but how does this help us? We want to fire projectiles, not show fancy lights!
Well the key is that a fire effect uses the tag type effect and effect, luckily for us, is the most abstract and general tag type. An effect, which controls everything from sounds, to particle effects to explosions, is basically a container. It contains a set of effect events that each have a series of parts, each part can spawn an object which can be anything from a sound, a weapon or... a projectile. You see where I'm going with this? Instead of spawning projectiles the usual way through the gun, instead I can spawn a fire effect that then spawns the projectile, I can then add many fire effects each with different projectiles and have them randomly cycle through!
So I did this but it took a while, fire effects are not guns they don't have the same information as a gun. For example when you fire a projectile you cannot just say fire inside the retical, you have to say fire from a certain point in the 3D model itself. Alas though I figured it out (mostly, you obviously see some bugs in the video but I'll talk about that later) and in no time I had a shotgun that shot out a rocket or a needler randomly, not using any actual projectiles.
I ran into a problem when I started using weapons like the beam rifle. When I fired rockets I could fire them with a random spread of velocities (something already inbuilt within the effect) and they would spread out like a shotgun. But when I tried to do it with the beam rifle, it was all in one line. I eventually figured out that the beam rifle is not a point-scan weapon, rather it actually DOES have a projectile that just fires EXTREMELY quickly, and the velocity I was firing it out of the beam rifle added to the velocity innate in the projectile and thus was not able to deflect it. So I just increased the effect velocity a tonne and boom, it worked!
So then I ended up adding 19 different effects with different projectiles, all was looking good, I was very excited. Then I went to finally make my shotgun! I added the first fire effect, then the second fire effect, then the third one and then the- wait, what do you mean there's a cap of 3 fire effects? You mean I can't add a fourth fire effect? But I have 19 effects! And the d20 grenade had at least 60 different effects! What do you mean I can only add 3!? This is... this is terrible!
A stumbling stone
So what I was doing was evidently not the right way to do it, but it felt really close! So I thought I could still keep doing it! I decided that the effect object itself might have some randomness, remember an effect is made up of some effect events and each effect event is made up of parts, surely there was something I could do. So I asked the modding discord on thoughts and not many people knew what to do, so I just had to set out and do some experimenting.
So first thing is that in order to spawn multiple projectiles I was using an effect events parts, each part would spawn a single projectile, and so I would add maybe 12 parts each spawning one projectile, but this couldn't be a source of randomness because the parts would all spawn at the same time. No place for randomness. But what about the effect events? Can they be used to add randomness?
Yes! Kinda... The effect event has a flag called "skip fraction". Basically how effect events work is you have a chain of events and the game runs through each event sequentially when the effect is triggered, however an event with a non-zero skip fraction has a chance to be skipped, thus not being played in the chain. This is very promising because we could have to effect events, one that fires needlers and one that fires rockets, and have the effects have a skip fraction so that the needlers would get skipped and the gun would fire rockets instead.
Unfortunately, this isn't how it works, each skip fraction is calculated independently. So for example, if both your needles and rocket effect had a skip ratio of 50%, then you'd have a 25% chance of both effects firing and a 25% chance of no effects firing. Alas I couldn't figure out any way to make only one effect occur, and I was kinda upset because I worked all day on this! So, I decided to pull the trigger and do something I was avoiding doing.
I downloaded the Cursed Halo files
So I went onto Inferno's patreon and downloaded the files for the d20 grenade to figure how he managed to create these random effects. And oh my god, the thing he did was absolute genius.
So first off, props to me because I was ALMOST right, the thoughts I had were almost completely correct, I just missed one step. And it's a really cursed step coming from the cursed halo mod. So remember how I said effect events happen sequentially in the chain? Well, the new event in the chain will only trigger if the current event finishes playing. So, what if you just have that event play for like... an hour? Well then if that event gets hit, then no other events will play for an HOUR or until the event chain is reset (by firing the weapon or switching weapons).
So that's the key insight I got from the d20 grenade. To recap, you have two effect events in an effect, something that shoots needles and something that shoots rockets. You say the needles has a 50% chance of being skipped. If the needles is skipped, you fire rockets and the event chain ends. If the needles is not skipped you fire needles and then only move onto firing rockets once the needle event finishes, which it does after one hour of sleeping. So yes this means there is a kinda subtle bug where if you just stand idly for an hour after firing the shotgun then the shotgun will randomly fire all on it's own, but that's a pretty minor bug I can deal with.
Conclusion
Halo modding is crazy and I'm actually having so much fun! But work on the weapon is not over, there is the obvious bug of the weapons not always firing straight. My THEORY is that this is because the model marker that the weapon fires from, called primary_trigger, which is always at the end of the 3D model, is sorta all over the place. So if that's the case I may be able to solve it by adding a new marker that's a little more static. But that's an adventure for another day!