The Battle of Midway - Development Thread

JPetroski

Deity
SLeague Staff
Joined
Jan 24, 2011
Messages
4,801
upload_2019-10-27_0-1-48.png


I had to take a break from the 8th Air Force for a night and build something new, so I headed off to the PTO for a few hours and made excellent progress.

The Battle of Midway will be a multiplayer-only, mini-scenario.

When @McMonkey, @Grishnach and I started building this, the breakthroughs that @Prof. Garfield and @Knighttime have uncovered did not yet exist. Now that many of them (such as payload, aircraft carrier restrictions, and munitions that can't hurt certain units) have been developed, the scenario can move forward quickly.

I've made good progress so far which should be expected considering there is no tech tree to speak of, very few buildings, just a few terrain types, and less than 60 units. I will continue to primarily focus on OTR until it is done but am hoping to finish this off soon too.

A few thoughts on what it will play like:

-Each side will have two groups of units (TF16 & TF17 for the USN and First Carrier Strike Force and Second Fleet for the IJN). At the start of the scenario, each player will get to choose where their units spawn (North, Mid, South). Players could split the two groups up or consolidate them. The other side won't know which spot the other team chose, so whoever finds the carriers first will have a huge advantage.

-The scenario will feature a "points" system where the Japanese have to destroy certain units on Midway, and also sink Allied ships to win. I haven't worked this out quite yet but the goal is to necessitate that both are struck.

-The Japanese B5N has two units. One is armed with torpedos and the other with bombs. Torpedos are useless against ground targets, so the Japanese player will need to decide if they need to rearm these units with bombs. Doing so will delete the torpedo unit, replace it with a bomb-armed unit, and remove that unit's MP for the turn, leaving it vulnerable to attack. This, combined with the need to strike both naval and ground targets, will hopefully compel the Japanese player to make tough choices about what to launch, and when.

-All aircraft, including fighters, will carry a payload, so they'll all only be able to attack once.

-Each turn will represent 15 minutes. Although the battle is credited as lasting for a few days (mainly because Yorktown was sunk on the 7th), for all intents and purposes it was over within 1 day as all four Japanese carriers were damaged beyond all hope, or sunk.

-The scenario will run 12.5 hours, from 4:30 a.m. (When the Japanese first took off) to 5 p.m. (when the last U.S. attack of the day took place). Thus, there will be 50 turns.

-Each aircraft carrier has a corresponding "city" off on the edge of the map, which it will home to. This is to enable the carrier payload reload function from OTR where the planes take on the home city of the carrier unit itself. I'll be carefully managing shields to make sure that each CV can only arm the equivalent of its compliment of aircraft for any one strike.

-When a carrier is destroyed the first time, it turns into the burning carrier seen below. Any planes that were on it will be destroyed as no terrain is stackable. I'll probably forbid new units from rearming on the burning carrier, and its new function will simply be something that you want to keep alive lest you get hit with a points penalty (which will be detrimental to the Japanese chance of winning the scenario - if you lose the 4 carriers you aren't going to win, even if you knock out all of Midway's defenses).

-I'm not sure how many aircraft each unit will represent, but the Japanese player will only have 34 ships to move, and the U.S. player will only have 26 ships to move, so even if I was pretty generous with aircraft, you're looking at maybe 50-60 units to move, MAX, per turn. This should enable this scenario to be played extremely quickly.

The Units - Note that I've pretty much just kept the top row from the old version, but several of the units in the top row (such as the Japanese units and bulldozers) won't be used.

upload_2019-10-27_0-5-39.png


Unit List
2nd Combined SNLF,
28th Regiment Detachment,
11th Const. Battalion,
12th Const. Battalion,
2nd Marine Raider Bn. Company C,
2nd Marine Raider Bn. Company D,
22nd Provisional Marine Rifle Co.,
23rd Provisional Marine Rifle Co.,
Antiaircraft Artillery,
Coastal Artillery,
F4F Wildcat,
SBD-3 Dauntless,
TBD-1 Devastator,
PBY-5 Catalina,
B-17 Flying Fortress,
B-26 Marauder,
Brewster F2A Buffalo,
SB2U Vindicator,
USS Yorktown,
USS Yorktown (Damaged),
USS Enterprise,
USS Enterprise (Damaged),
USS Hornet,
USS Hornet (Damaged),
Heavy Cruiser (US),
Light Cruiser (US),
Destroyer (US),
Submarine (US),
Akagi,
Akagi (Damaged),
Kaga,
Kaga (Damaged),
Hiryu,
Hiryu (Damaged),
Soryu,
Soryu (Damaged),
Battlecruiser (JPN),
Heavy Cruiser (JPN),
Light Cruiser (JPN),
Destroyer (JPN),
Submarine (JPN),
A6M2 Zero,
B5N2 Kate (T),
B5N2 Kate (B),
D3A1 Val,
Scout Plane,
Flak Burst,
Gunfire,
Torpedo,
Dive Bomb,
Level Bomb,
5" Shell,
8" Shell,
14" Shell,
Smoke Screen,
Fuel Tanks,

Questions, comments, and emotional outbursts are all welcome!
 
Last edited:
Hi John,

This looks like a very promising battle scenario. I'm especially intrigued to know how the features such as payload, aircraft carrier restrictions, and munitions that can't hurt certain units will be implemented/coded.

I'm not certain I understand how the following works: "When a carrier is destroyed the first time, it turns into the burning carrier seen below. Any planes that were on it will be destroyed as no terrain is stackable."

In your case, I'm not certain if it is relevant, but have you considered placing your carrier 'cities' on a second map to avoid having them display on your primary map?
 
This looks like a very promising battle scenario. I'm especially intrigued to know how the features such as payload, aircraft carrier restrictions, and munitions that can't hurt certain units will be implemented/coded.

All of these are in Over the Reich, though I admit that finding the relevant code might be tricky.

Payload is achieved by only letting a unit use the 'k' attack if they have a home city, and setting the home city to NONE after they attack. My Munitions Library provides this as an "off the shelf" feature (though I didn't do automatic re-arming, or arming outside a city -- I'll put it in if/when someone asks).

Aircraft carrier restrictions are achieved with a unit activation script that only gives the carrier the 'carrier flag' when a unit eligible to land on a carrier is activated.

Search for civ.scen.onResolveCombat in OTR to see the relevant code for ineffective munitions. It is basically set attacker hp to 0 and return false.

I'm not certain I understand how the following works: "When a carrier is destroyed the first time, it turns into the burning carrier seen below. Any planes that were on it will be destroyed as no terrain is stackable."

When the carrier is destroyed, a new unit is created that is the damaged carrier, but the destroyed planes are not re-created. This is the B17 and Damaged B17 mechanic from OTR.
 
Hi John,

This looks like a very promising battle scenario. I'm especially intrigued to know how the features such as payload, aircraft carrier restrictions, and munitions that can't hurt certain units will be implemented/coded.

I'm not certain I understand how the following works: "When a carrier is destroyed the first time, it turns into the burning carrier seen below. Any planes that were on it will be destroyed as no terrain is stackable."

In your case, I'm not certain if it is relevant, but have you considered placing your carrier 'cities' on a second map to avoid having them display on your primary map?

As @Prof. Garfield pointed out, all of these are in Over the Reich and just need to be repurposed.

As for the cities, that would be "ideal," but McMonkey labored for days on the grid system you see here, and there is only one map. I have no desire to start over and replace the grid just to add a second map, so I've simply made those cities look like Japanese and American aircraft carriers. I'll just make it so that no air or naval units can go there without being deleted (also in Over the Reich). I could also make them less visible, but I dont know that it matters.

We really need to get all of you designers to jump in and play a game of OTR if only to see all the different features, so you all can start dreaming up ways to use them in your new scenarios :)
 
Hi John and Prof Garfield,

Thanks for the high level feedback.

I have looked at the code for past iterations of OTR and I have to be honest that I have often struggled at times at understanding how the code works as I find it can be quite complex.

With Knightime's assistance, I had been doing most of the lua coding for my current Battle of Alesia project (which was placed on hold during the summer months). As I mentioned to him at the time, though I'm getting more and more comfortable at re-using code I'm already familiar with, it still remains difficult for me either at writing completely new code/functions or re-implementing more complex code (for example, I needed his assistance for using your HELP feature from OTR in my Napoleon scenario).

All part of the learning curve I know, but a fact nonetheless.

As @Prof. Garfield pointed out, all of these are in Over the Reich and just need to be repurposed.
As for the cities, that would be "ideal," but McMonkey labored for days on the grid system you see here, and there is only one map. I have no desire to start over and replace the grid just to add a second map, so I've simply made those cities look like Japanese and American aircraft carriers. I'll just make it so that no air or naval units can go there without being deleted (also in Over the Reich). I could also make them less visible, but I dont know that it matters.

As I mentioned, I wasn't certain if it was relevant for your scenario or not. I certainly undertand why at this stage you wouldn't want to make such a change.

I had noticed the grid in your screen shot but forgot to ask in my previous post what will be its purpose in the scenario?

We really need to get all of you designers to jump in and play a game of OTR if only to see all the different features, so you all can start dreaming up ways to use them in your new scenarios :)

I was reluctant to reply when you posted your request for play testers for OTR because I know from reading posts in most multiplayer games in the past how challenging and time consuming a process it can be to get everyones schedules to align. Most MP games can takes weeks if not months to play out.

I don't mind playtesting other designers single player scenarios when they ask me because I control the entire process and play on my own schedule.

I'm not closing the door but I also might be more willing to help play test Midway because as you mentioned it's a smaller and shorter scenario.

Let me know your thoughts.
 
Last edited:
I had noticed the grid in your screen shot but forgot to ask in my previous post what will be its purpose in the scenario?

The grid is basically a "quality of life" enhancement. McMonkey observed that our map is 99.9% water with no real landmarks to speak of, and he thought it would be difficult for players to judge how far away they were from their aircraft carriers or targets, especially if the carriers were expected to move each turn. To the fullest extent possible, I plan to scale movement to a multiple of each grid (so if they're 5 squares planes might move 20, 25, 30 spaces per turn), to help players with this.

Also, having some form of coordinate will be much easier to keep track of in a MP game (fleet spotted in B-8 is a lot easier and intuitive to jot down and immediately search than 356,24,0 or whatever.

He thought it would be helpful and if he ever returns, I won't rob him of seeing his carpal-tunnel-inducing work in all its glory :)

With Knightime's assistance, I had been doing most of the lua coding for my current Battle of Alesia project (which was placed on hold during the summer months). As I mentioned to him at the time, though I'm getting more and more comfortable at re-using code I'm already familiar with, it still remains difficult for me either at writing completely new code/functions or re-implementing more complex code (for example, I needed his assistance for using your HELP feature from OTR in my Napoleon scenario).

I certainly hear you with that. It is good to see that you're at least comfortable patching stuff together. I am (for the most part) there as well and like you I would struggle with implementing something completely new. On the other hand, between OTR and Napoleon and all the modules and libraries that have come out since then, any designer has a pretty good basis to start. I could see this developing almost like the art does. No one asks the artists for planes they've already drawn but they do ask for help with a tweak or two or something completely new. I think when a few of us start getting the hang of what is already out there, it will be less of an ask for a bit of help on a particular issue we can't figure out. Right now, Prof. Garfield, Knighttime, and Grishnach deserve a place in the HoF if we still had one active.

I was reluctant to reply when you posted your request for play testers for OTR because I know from reading posts in most multiplayer games in the past how challenging and time consuming a processs it can be to get everyones schedules to align. Most MP games can takes weeks if not months to play out.

I don't mind playtesting other designers single player scenarios when they ask me because I control the entire process and play on my own schedule.

I'm not closing the door but I also might be more willing to help play test Midway because as you mentioned it's a smaller and shorter scenario.

Well, it's not so much a playtest at this point. I think Garfield and I have each played our own private games a few times and I've been able to square off against two good players to help me get the balance where I mostly want it. Right now, when the "formal" release comes in a short while, I'm just really hoping that some of you will try it out and enjoy it for yourselves, because otherwise what is the point of creation! That's not to say I wouldn't be open to suggestions or changes, but I feel like the scenario is about where it needs to be to give the kind of experience I envision.

One thing that would be helpful, however, would be if people who did play were vocal about any confusion they had, or anything they found tedious, as we've tried to reduce both the learning curve, and "quartermaster duties" as much as possible, but the former especially is difficult to judge on your own work.
 
I have looked at the code for past iterations of OTR and I have to be honest that I have often struggled at times at understanding how the code works as I find it can be quite complex.

With Knightime's assistance, I had been doing most of the lua coding for my current Battle of Alesia project (which was placed on hold during the summer months). As I mentioned to him at the time, though I'm getting more and more comfortable at re-using code I'm already familiar with, it still remains difficult for me either at writing completely new code/functions or re-implementing more complex code (for example, I needed his assistance for using your HELP feature from OTR in my Napoleon scenario).

I don't recommend using the code I've written in Over the Reich as 'example code' if you're not comfortable with programming. A lot of it is a mess and inconsistent in style, and I worry about making changes to it, lest something break. If you're reasonably comfortable with programming, then the OTR code might be useful for revealing the 'trick' for certain things. I suggested searching for the civ.scen.onResolveCombat, since that code is more recent, not as complex, and I'm concerned that putting that code in a 'library' format might make it slow (I don't know for sure, but that code is supposed to be run for each round of combat).

Let me know if you want features from Over the Reich. I'll put them into a module that will be easier to re-use. I have a year of extra programming experience over most of what I wrote for OTR, and should be able to write you something that you can 'just use' (maybe after filling in a parameter table or something). My goal when I write 'library' code is that you should be able to use it the same way that you use something like civ.createUnit(unittype, tribe, tile) -> unit. You don't have to know how it works, just what it does. If the documentation I provide isn't clear enough, let me know.
 
One thing that would be helpful, however, would be if people who did play were vocal about any confusion they had, or anything they found tedious, as we've tried to reduce both the learning curve, and "quartermaster duties" as much as possible, but the former especially is difficult to judge on your own work.

So even though it is designed for multiplayer, you are indicating it can still be played/tested solo. Is that correct?

As such, I imagine it still needs to be played in Hot Seat Mode, where you need to play both sides?

Let me know if you want features from Over the Reich. I'll put them into a module that will be easier to re-use. I have a year of extra programming experience over most of what I wrote for OTR, and should be able to write you something that you can 'just use' (maybe after filling in a parameter table or something). My goal when I write 'library' code is that you should be able to use it the same way that you use something like civ.createUnit(unittype, tribe, tile) -> unit. You don't have to know how it works, just what it does. If the documentation I provide isn't clear enough, let me know.

There are certainly features/concepts from OTR I would want to re-implement or use in some of my future projects and as such when the time comes I would undoudtedly reach out to you, so thank you for the offer.

In the meantime, one of the reasons I selected the Battle of Alesia as my next project was because it is a simple tactical battle scenario and as such I felt it was an ideal candidate as my first, mostly, solo lua coding attempt. Only covering the final three days of that historical battle, it didn't require, for example, any of the more complex diplomatic/production type of events found in Napoleon or OTR and thus made it a much more manageable coding project and thereby a useful learning excercise.
 
Last edited:
So even though it is designed for multiplayer, you are indicating it can still be played/tested solo. Is that correct?

As such, I imagine it still needs to be played in Hot Seat Mode, where you need to play both sides?

Yes, I've played several games against myself in hot seat mode. It's actually fun, surprisingly, though you naturally don't get the full effect of playing a cunning opponent with a fog of war. The reactive defense system and ranged units make combat unpredictable enough that you don't know how things will shake out. It has the same issue as all scenarios a designer self-tests, as I usually make it 20-30 turns before compiling a punch list of items to fix, which usually would so dramatically alter the experience that I start over, which is no small feat for a scenario of this size. As quick as turns 3-125 can go, turns 1-3 still require a lot of moving units around where you want them.
 
I've completed the text files for the game, meaning the rules file (I just need to add unit sounds). This is going to be a stripped-down project--a true mini-scenario. I am not going to bother with describe.txt for the pedia, etc. I also am not bothering to "tidy up" the rules file and make sure everything looks pretty. As long as things function, I will be happy. Right now, I'm reusing unit stats from OTR as they are fairly tested.

The "only" thing that remains to be done is the events file. Assuming things go smoothly with OTR (and I can break away from Imperialism 3) I will start compiling that over the weekend.

I think the biggest challenge is going to be getting the range of aircraft right from a playability standard. Right now I'm having the slow dive bombers and torpedo bombers each move 15 spaces per turn, but we'll see how that works out in practice.
 
I made some progress at events today but made them such a garbled mess I couldn't get the afterProduction working, so I decided to start over and methodically add OTR code line by line as needed.

I dont really need that many events so I'm hoping this approach will work. My first try involves patching events together from a few different scenarios which confused the process.

If I get some time later where I can concentrate, I'll continue the process.
 
I made some progress at events today but made them such a garbled mess I couldn't get the afterProduction working, so I decided to start over and methodically add OTR code line by line as needed.

I dont really need that many events so I'm hoping this approach will work. My first try involves patching events together from a few different scenarios which confused the process.

If I get some time later where I can concentrate, I'll continue the process.

I show how to achieve after production in my lessons. A much better way to learn than trying to make sense of OTR code.

http://sleague.civfanatics.com/inde...ta_in_the_State_Table#After_Production_Events

Incidentally, I was planning to produce a 'template' events.lua file at some point. I could move that project up if it would be helpful.
 
Thanks for reminding me about that! There's so much to learn, and so much info out there, that it's really hard to remember where it all is!
 
I was able to get the after production working, but I'll admit I just pushed forward with simply copy/paste/adopt OTR's code line by line.

I'm definitely not "learning" anything with this approach and at some point I really need to just go through your lessons (maybe as part of Boudicca next) so I better understand what is going on, but I am pretty pleased that I'm at least able to reverse engineer and trouble shoot some of the stuff. I really just want to publish this thing so that at least 1 of 3 2019 projects other than OTR is complete...

In any event, I've managed to successfully create a dialogue box for Japan where they get to choose which way their fleet approaches. I need to do the same for the U.S.

There aren't that many events I need to work through though I have a ton of tables to fill.

-The deployment event seems to be working but needs to be built out
-I'm confident that the ranged attacks and reactive attacks will work but I haven't tested them yet.
-I need to test the event for the carriers being replaced by dead carriers
-I need to test payload
-I need to add a point counter and eventual victory message for the Japanese

-One quality of life that I am probably going to try on my own, but am not sure I'll succeed with is that I need the aircraft to know where the nearest carrier unit is (like we tell players where the nearest city is). I think it's a matter of changing a few things but we'll see. It might be a good test to see if I can take a feature, slightly change it, and get a desired result.

We'll see how it goes! Just happy to get the first hurdle done as it took a few days but I was able to work through it.
 
In any event, I've managed to successfully create a dialogue box for Japan where they get to choose which way their fleet approaches. I need to do the same for the U.S.

My text library has text.menu which should automate the menu creating process for you.

-I'm confident that the ranged attacks and reactive attacks will work but I haven't tested them yet.

I really don't recommend trying to copy the reactive attack code from Over the Reich. Give me a chance to re-implement it as a module. I think others have asked about reactive attacks before, so I wouldn't be building the module just for you. This would also give it a convenient testing framework.
 
I think reactive attacks are a great module to have. They're the only way that ranged units can sustain damage on the offensive, which is desirable for a large number of reasons.

At the pace I'm going, you'll have time :)
 
Just a little update...

I've managed to get formations working, carriers being "sunk" working, munitions working, and all the initial unit spawns working. I'm pretty pleased with myself that I'm able to create a timed delay for the Japanese reinforcements (but still require the player to choose which direction they're going to approach from on turn 1). I need to test to see if units will rearm on carriers or not but assume it will work.

I just need to do these two now and I think I'm pretty much ready to roll... Both seem to be things that there are examples or libraries for so I'm hopeful I can pull it off without much fuss, but I do think they're best tackled with some quiet time guaranteed so I can focus.

-The scenario will feature a "points" system where the Japanese have to destroy certain units on Midway, and also sink Allied ships to win. I haven't worked this out quite yet but the goal is to necessitate that both are struck.

-The Japanese B5N has two units. One is armed with torpedos and the other with bombs. Torpedos are useless against ground targets, so the Japanese player will need to decide if they need to rearm these units with bombs. Doing so will delete the torpedo unit, replace it with a bomb-armed unit, and remove that unit's MP for the turn, leaving it vulnerable to attack. This, combined with the need to strike both naval and ground targets, will hopefully compel the Japanese player to make tough choices about what to launch, and when.

Again, this is not the scenario I will want to be known for but it is a quick little one that should be fun and more importantly is giving me a little bit of confidence with lua. So far, I've been successful in troubleshooting the (many) bugs I've created.

After this though I think my focus will be on single player scenarios as there doesn't seem to be much demand for MP ones. Boudicca, Rise of Macedon, or Hinge of Fate... Oh the options...
 
Anyone willing to take a peek at this and see why my counters aren't working? There's a test save that is ready to have the USS Yorktown blown up, which "should" grant the Japanese 50 points. You can press 1 to see the point pop up box, but they don't actually earn the 50 points. I am unsure why this is.

Code:
local function killFunction(deadUnit,reactingUnit)
    if deadUnit.type == unitAliases.Akagi or deadUnit.type == unitAliases.Yorktown then
        state.reactionWarning["CarrierDamaged"] = (state.reactionWarning["CarrierDamaged"] or 0) + 1
    else
        state.reactionWarning["CarrierLosses"] = (state.reactionWarning["CarrierLosses"] or 0) + 1
    end
    local replacementUnit = false
    local loser = deadUnit
    local winner = reactingUnit   
    -- Code for units to "survive" destruction by being re-created as a different unit
    if civ.getTile(loser.location.x,loser.location.y,loser.location.z) ~= nil then
        local tile = loser.location
        for __, unitSurvivalInfo in pairs(survivingUnitTypes) do
            if loser.type == unitSurvivalInfo.unitType then
                local quantityToProduce = unitSurvivalInfo.replacingQuantity or 1
                if math.random() <= (quantityToProduce - math.floor(quantityToProduce)) then
                    quantityToProduce = math.ceil(quantityToProduce)
                else
                    quantityToProduce = math.floor(quantityToProduce)
                end
                local replacingHome = nil
                if unitSurvivalInfo.preserveHome then
                    replacingHome = loser.homeCity
                end
                local replacingVetStatus = unitSurvivalInfo.replacementVetStatus or false
                if unitSurvivalInfo.preserveVetStatus then
                    replacingVetStatus = loser.veteran
                end
                for i=1,quantityToProduce do
                    local newUnit = civ.createUnit(unitSurvivalInfo.replacingUnit,loser.owner,loser.location)
                    newUnit.homeCity = replacingHome
                    newUnit.veteran = replacingVetStatus
                    replacementUnit = newUnit
                end --1st instance for i=1,quantityToProduce
                if unitSurvivalInfo.bonusUnit then
                    quantityToProduce = unitSurvivalInfo.bonusUnitQuantity or 1
                    if math.random() <= (quantityToProduce - math.floor(quantityToProduce)) then
                        quantityToProduce = math.ceil(quantityToProduce)
                    else
                        quantityToProduce = math.floor(quantityToProduce)
                    end       
                    for i=1,quantityToProduce do
                        local newUnit = civ.createUnit(unitSurvivalInfo.bonusUnit,loser.owner,loser.location)
                        newUnit.homeCity = nil
                        newUnit.veteran = false
                    end --2nd instance for i=1,quantityToProduce   
                end -- end if unitSurvivalInfo.bonusUnit       
            end -- loser.type == unitSurvivalInfo.unitType
        end -- for unitSurvivalInfo in pairs(survivingUnitTypes)
    end--civ.getTile(...
    
    if loser.owner == tribeAliases.USN then
        
        if loser.type == unitAliases.BurningYorktown or unitAliases.BurningHornet or unitAliases.BurningEnterprise then
        incrementCounter("JapanScore",specialNumbers.japanScoreIncrementSinkCarrier)
        elseif loser.type == unitAliases.RaiderC or loser.type == unitAliases.RaiderD or loser.type == unitAliases.MarineRifle22
        or loser.type == unitAliases.MarineRifle23 or loser.type == unitAliases.FuelTanks then
        incrementCounter("JapanScore",specialNumbers.japanScoreDamageMidway)
        end
    end
    if loser.owner == tribeAliases.IJN then
        if loser.type == unitAliases.BurningAkagi or unitAliases.BurningKaga or unitAliases.BurningSoryu or unitAliases.BurningHiryu then
        incrementCounter("AlliedScore",specialNumbers.usaScoreIncrementSinkCarrier)
        end
    end
    
    
    civ.deleteUnit(deadUnit)
    return replacementUnit
end --function killFunction(deadUnit,reactingUnit)
 

Attachments

  • Midway.zip
    1.1 MB · Views: 333
Hi John, I think lines 54 and 62 of the code you posted are incorrect -- you need to repeat loser.type == before each of the unitAliases.* references, not just the first one. Compare those lines to lines 56 and 57, which are written correctly.
 
Top Bottom