Shortcomings of the Base Game - Lua Fixes?

JPetroski

Deity
SLeague Staff
Joined
Jan 24, 2011
Messages
4,898
This thread is inspired by some discussion in the HoF thread regarding aircraft carriers. There are some elements in the base game that simply do not work as intended. Either the AI can't handle them (aircraft carriers) or they are extremely exploitable (I'd argue fortress construction right next to a city) by the humans.

We've really never had a good way to handle some of these before, but with lua, we can probably find good solutions that work for everyone. I was hoping that this thread could be a place where people discuss issues in the base game and propose solutions and hopefully we can come up with something that all agree would be much better, and then, hopefully, one of our brilliant coders takes it up to add them to the design module.

I'll start with aircraft carriers (CV). We know the AI can't handle them as it stands. They don't seem to return a/c to them consistently, or use them as designed.

My proposal (for all of you to hack away at):

-CV's pose a threat to ships especially because they can launch aircraft to attack them.
-Thus, if a CV is within range of a surface ship, aircraft are launched from that CV, their .id tracked/remembered, and they are sent towards the enemy ship.
-The aircraft either attack the ship or not - you can't really force an AI aircraft to attack.
-Either when they attack, or at the end of the turn, or at the end of their range (meaning turn 2 in most cases) the specific, tracked aircraft is deleted.

In game, CVs would basically be "empty" but would launch units near other threats, direct the units towards those threats, where hopefully the units would attack those threats. Designers might be able to tweak attack vs. defense stats of the units until they find a combo that results in an attack more often than not.

I'm not wed to this idea but throw it out there in the hopes that designers or coders have other ideas or what. It would just be nice to be able to sit here and think of what things in the base game are broken and if they can be fixed with lua now while everyone is interested in this game. These sort of "bug fixes" are prime targets for addressing, IMO.

Paging @techumseh @tootall_2012 @civ2units @Prof. Garfield @Knighttime @Dadais for a good mixture of designer / coder but feel free to tag others you've seen around.

What other things out there are "broken" or exploitable / what other things annoy you as a designer or have thwarted your plans? There may already be solutions or we might be able to come up with one together. Have at it.
 
Guess the main point is about what role one whish to gives to Carrier Aircraft in its scenario.
They after all, beeing sea air bases, displayed quite few roles with an evolution following carreed aircrafts'role one and escort sizes (or existences), people may try to depict in their proposition :

1- The recon role always was important.

Seeing submarines (or allowing to with tech and lua) ?
Seeing two square away seems a prerequisite.
Is seeing two square away enough for all scenario, considering aircraft evolutions and map scale ?

2- The Air superiority seems an ever-lasting role.

Spawning a limited number of fighters with Goto orders when spotting ennemies nearby ?
Spawning a fighter if avaible to defend wether attacked by an aircraft ?
I'd mention my AAsystem (see there and there) as a solution too, where it could be included, while it imply a total change in Air Gameplay.

3- Light strategic bombing (against ships AND land) quickly became a role too.

Spawning (with alea ?) a limited number of light bombers with Goto orders when spotting targets ?
Damage a limited amount of targets "in range" designated with alea ?

4- Scale of unit

Is the Carrier supposed to be designed as a lone ship, or as a fleet including the carrier and its escort ?
Guess that shall play a lot with its designs' choices too ?

.

Let's say we have a base there.
Truth is, I see advantages and drawbacks to all solutions, and guess choices shall be done considering the designer vision as a priority.
 
Last edited:
I found a moderately successful work around for the carrier problem in Sea Lion. The Royal Navy had a carrier with their fleet in the North Sea at Scapa Flow and one with their Western Fleet based near Glasgow. I wanted both fleets to sortie when the Germans invaded. I started by making the Swordfish torpedo bombers missile units, which have an affinity for enemy ships. Not ideal, but the planes weren't going back to the carrier anyway. It actually worked pretty well for the fleet in the North Sea. Depending on circumstances, the torpedo bombers launched effective strikes on the German fleet. It didn't work as well on the west side, where it's much narrower. The planes flew off and landed at British cities along the approach route.

One thing I've found is that the air defense of the fleet is hard to simulate. Carrier fighters should be the first line of defense against air attack. But given the defense factors of large ships, it is they who defend first and they are sometimes sunk before the defending fighters are even engaged. Plus fighters tend to fly off the carriers and not return. Perhaps Lua can offer some solution?

Many years ago, Captain Nemo did some research on missile units and ships. He found that there was a correlation between the attack factor of the missile and the number of shields needed to build the ship. So, the cruise missile in the vanilla game has an attack of 18 and targets naval units with a shield cost of 16, ie. battleships and carriers. Missiles with lower AFs target ships with lower build costs. He mapped out a chart with the correlations. Sadly, I never made a copy and can't find it now. It was on the Apolyton forum, probably lost with so much of our early history.
 
Sadly, I never made a copy and can't find it now. It was on the Apolyton forum, probably lost with so much of our early history.

A lot of that was mirrored. The link is in this post.

I did find a message in this thread:

It is EASY to fix. The AI will throw missile units at everything if the cost ratio is right. In Second Front the AI will attack ships and tanks and infantry with V-1s and artillery shells.

Just test it:

Make the cannonballs cost 10 and the ships 180 and the attack is guaranteed. At about 10 and 70 the attacks seem to stop... Missiles costing 30 will attack units costing over 100 but not under, but missiles costing 10 will attack units down to about 80...

For SF I made 2 types of shells (Long range/Short range) with high and low cost so the heavy coastal artillery would target only Battleships, Cruiser and Heavy transports while the smaller batteries would fire at Landing Crafts, tanks and infantry on the beaches. It worked perfectly and consistently.

BTW the units transported in a ship are also measured against the cost of the missile in the equation, not additively but comparatively. A missile will not attack a transport costing 50 and transporting 8 units costing 50 each but will attack the same transport carrying just one unit costing 120...

One thing I've found is that the air defense of the fleet is hard to simulate. Carrier fighters should be the first line of defense against air attack. But given the defense factors of large ships, it is they who defend first and they are sometimes sunk before the defending fighters are even engaged. Plus fighters tend to fly off the carriers and not return. Perhaps Lua can offer some solution?

TNO recently added the ability to use Lua to choose which unit will defend a tile. It wouldn't be difficult to make air units defend first.

1- The recon role always was important.

Seeing submarines (or allowing to with tech and lua) ?
Seeing two square away seems a prerequisite.
Is seeing two square away enough for all scenario, considering aircraft evolutions and map scale ?

Lua now gives the ability to show or hide units from tribes using unit.visibility. An onActivateUnit event could reveal all units within a certain number of squares of the carrier.
 
Thanks. That covers most of it, I think.

This may just be restating the obvious for Lua-fluent folks, but maybe it will help. I assume Lua has the equivalent to the macro "MoveUnit' event. Can it identify the location of a given unit, ie. a carrier, as well? If so, could it use that to plot new "moveto" coordinates for an air unit after it makes it's attack, bringing it back to the carrier?
 
This may just be restating the obvious for Lua-fluent folks, but maybe it will help. I assume Lua has the equivalent to the macro "MoveUnit' event. Can it identify the location of a given unit, ie. a carrier, as well? If so, could it use that to plot new "moveto" coordinates for an air unit after it makes it's attack, bringing it back to the carrier?

I know from some help Prof. Garfield gave me on a Bismarck chase event, we can find the location of one unit and direct other units to it. I'd be curious what we could do to tell if something attacked or not. If that isn't possible, perhaps checking for HP, or distance from the carrier in the first place (the idea being, a unit with less than full HP probably attacked something, and in any event, for a unit to land on the carrier it has to reach there). I don't know what would happen if there are two carriers within range though because the help I was provided was predicated on the idea that the unit to be found (Bismarck in that case) was unique. I can't remember where everyone landed on the unit ids as there as some thought that the game might recycle them, I believe.
 
So, if the carrier is at a given location, say 24,62 and carrier plane 'Dauntless' has a 2 turn endurance and a MF of 8, then simply have all Dauntlesses starting their turn within 8 squares of the carrier move to 24,62. The exception would be units at 24,62 itself, so they would be free to fly to a target without being prevented by the moveunit event. Could that work?
 
Well, you could certainly move any dauntless that is not on the CV square to the CV square, but I'm not positive if we can grab which turn of its total range the unit is on (though I suppose in this instance it wouldn't matter, because we'd say if a plane starts the turn off the carrier, it must need to return to base).

I guess the question is, what part of the base game mechanic is broken. I really haven't designed a scenario with an AI carrier so I'd ask the group, but if it's simply that planes never return to it, this should solve that.

I do think you'd need to run the check in after Production or onTurn vs. OnActivate because AI units activate every square.
 
I don't think anything is broken exactly. It's just not part of the AI's programming. 2 turn range air units almost always return to the city they left from (or sometimes a different one), but I've never seen an AI plane land on a carrier. I can see the difficulty for programmers, since the location the plane left from will usually be different than the location of the carrier one turn later.

Another issue is which type of aircraft can operate from carriers. As it stands, any plane, even a strategic bomber, can be carried. So, if a carrier starts in a port together with various kinds of planes, it will take them all with it, regardless of type. Perhaps there's a way to designate which air units can operate from carriers, and which cannot.

And that brings up a third point, the unlimited capacity of aircraft carriers. I'm pretty sure that some earlier versions of Civ2 limited the number of aircraft carried to 8. It would be better if this was somehow restored. Or even better, find a way to set the number differently for different types of carriers.
 
Just as an FYI, OTR, Cold War, and Midway all restrict what types of units can land on CVS. I can't remember if OTR also limits how many can land on one or not.
 
Code:
function discreteEvents.onActivateUnit(unit,source,repeatMove)
    if unit.type == gen.original.uBomber and unit.domainSpec >= 1 then
        for possibleCarrier in gen.nearbyUnits(unit.location,8) do
            if possibleCarrier.type == gen.original.uCarrier then
                unit.gotoTile = possibleCarrier.location
            end
        end
    end
    if unit.type == gen.original.uCarrier then
        for possibleBomber in gen.nearbyUnits(unit.location,8) do
            if possibleBomber.type == gen.original.uBomber and
                gen.distance(possibleBomber, unit) >= 6 then
                unit.moveSpent = gen.original.uCarrier.move
            end
        end
    end
end

Here's some basic code to get carriers and bombers to work together. If the bomber has already been aloft for one turn, it finds a nearby carrier to land on, and goes to it. If a carrier is activated and there is a bomber within 8 squares of it, and at least 6 squares away, the carrier's movement allowance is used up, so that it can't sail out of range for the return trip. This code doesn't take into account alternate landing places, so it is incomplete.

What I found is that this code is good at stopping bombers from flying away for no reason. However, the bomber will not return to the carrier if there is something to attack. I suspect the reason is that finding an enemy unit cancels the goto order, and the game only checks for cities for the bomber to land at, and, finding none, decides it is best to attack anyway.

Another issue is which type of aircraft can operate from carriers. As it stands, any plane, even a strategic bomber, can be carried. So, if a carrier starts in a port together with various kinds of planes, it will take them all with it, regardless of type. Perhaps there's a way to designate which air units can operate from carriers, and which cannot.

In Over the Reich, we used an onActivateUnit trigger to turn off the carry air units flag for carriers when air units that couldn't be carried were activated. Carriers could still 'push' these aircraft, but from what I remember the range was never restored. This was good enough for our purposes. It might be possible to get more fancy and set incompatible air unit types to ground domain when a carrier is activated.

And that brings up a third point, the unlimited capacity of aircraft carriers. I'm pretty sure that some earlier versions of Civ2 limited the number of aircraft carried to 8. It would be better if this was somehow restored. Or even better, find a way to set the number differently for different types of carriers.

Just as an FYI, OTR, Cold War, and Midway all restrict what types of units can land on CVS. I can't remember if OTR also limits how many can land on one or not.

I just tested "Classic" Civ II, and the carrier still takes all the air units from the city. I don't remember limiting carrier capacity for OTR.

Limited carrier capacity could probably be achieved by using an onActivateUnit event to check if the ship is within 2 squares of a city, and teleport off any excess aircraft (or, perhaps, aircraft that are not sleeping). Further out to sea, a unit could be deleted, or, since human units now have onActivate for every square, if there is no space on the nearest carrier to an air unit trying to land, the carrier flag could be removed.
 
Noobie question there.
Have someone studied how carriers, missiles and aircrafts are handle by AI function of their AI role ?
 
It is EASY to fix. The AI will throw missile units at everything if the cost ratio is right. In Second Front the AI will attack ships and tanks and infantry with V-1s and artillery shells.

Just test it:

Make the cannonballs cost 10 and the ships 180 and the attack is guaranteed. At about 10 and 70 the attacks seem to stop... Missiles costing 30 will attack units costing over 100 but not under, but missiles costing 10 will attack units down to about 80...

For SF I made 2 types of shells (Long range/Short range) with high and low cost so the heavy coastal artillery would target only Battleships, Cruiser and Heavy transports while the smaller batteries would fire at Landing Crafts, tanks and infantry on the beaches. It worked perfectly and consistently.

BTW the units transported in a ship are also measured against the cost of the missile in the equation, not additively but comparatively. A missile will not attack a transport costing 50 and transporting 8 units costing 50 each but will attack the same transport carrying just one unit costing 120...

This function sounds very interesting. I would like to use this in the AWI scenario as I have some coastal cities defended by a fortress unit. If I can ammunition these units with cannonballs and the AI automatically attacks nearby vessels, this would make the scenario more challenging for playing.
 
This function sounds very interesting. I would like to use this in the AWI scenario as I have some coastal cities defended by a fortress unit. If I can ammunition these units with cannonballs and the AI automatically attacks nearby vessels, this would make the scenario more challenging for playing.

That's "natural" behaviour, that Captain Nemo described in the thread I linked, if it wasn't clear. I didn't put it in a regular quote box for some reason. It doesn't have anything to do with Lua. Of course, you could use Lua to check if a ship is adjacent to a fortress, and generate cannon balls only in that case, but the AI might choose to use all of them to attack the same ship (since the AI can launch missiles from any location, not just the city they are actually in).
 
By teleporting the bomber to a square adjacent to the carrier, the bomber won't be distracted by units to attack. Since AI missiles are teleported to the target, this seems like a reasonable solution. This code works pretty well (I think there was one instance of a bomber not returning to its carrier).

Code:
-- returns a tile adjacent to the carrier that is 
-- nearest to the starting bomber
local function nearestAdjacentTile(bomber,carrier)
    local bestDistSoFar = math.huge
    local bestTileSoFar = nil
    for key,tile in pairs(gen.getAdjacentTiles(carrier.location)) do
        if (tile.defender == nil or tile.defender == bomber.owner) and 
            gen.distance(bomber.location,tile) < bestDistSoFar then
            bestTileSoFar = tile
            bestDistSoFar = gen.distance(bomber.location,tile)
        end
    end
    return bestTileSoFar
end
function discreteEvents.onActivateUnit(unit,source,repeatMove)
    if unit.type == gen.original.uBomber and unit.domainSpec >= 1 then
        for possibleCarrier in gen.nearbyUnits(unit.location,8) do
            if possibleCarrier.type == gen.original.uCarrier then
                local adjTile = nearestAdjacentTile(unit,possibleCarrier)
                if (gen.distance(unit,adjTile)+1)*totpp.movementMultipliers.aggregate <= unit.type.move-unit.moveSpent then
                    unit.moveSpent = unit.moveSpent + gen.distance(unit,adjTile)*totpp.movementMultipliers.aggregate
                    unit:teleport(adjTile)
                    unit.gotoTile = possibleCarrier.location
                    break
                end
            end
        end
    end
    if unit.type == gen.original.uCarrier then
        for possibleBomber in gen.nearbyUnits(unit.location,8) do
            if possibleBomber.type == gen.original.uBomber and
                gen.distance(possibleBomber, unit) >= 6 then
                unit.moveSpent = gen.original.uCarrier.move
            end
        end
    end
end
 
Teleportation is unrealistic. A tactic I sometimes use is to block the return route of an AI-controlled aircraft so that it's lost. In that case, the enemy air unit would just jump over my blocking units and get safely home.

What would happen if an AI aircraft was returning to a city on its own? I think it goes around the unit if it can, if not, it's lost. I haven't observed a 2 range air unit ever attacking another unit on its return journey. I know that when you manually use moveunit, the moving unit stops in a ZOC, but if you hold down the right mouse button again, it moves to the next tile and so on. Can the moveunit command be repeated in this way so that your air unit keeps working its way around the obstacle?
 
On the topic of the "more robust transport module" that @tootall_2012 had requested - I'd throw in my 2 cents as well as we wait for his.

-The module at present works well but the following opportunities were identified:

1. Either not sending the units to a different map/out of the way tile and in stead storing them elsewhere, or at least recalling them back to the scene of the transporter's death with less HP (or perhaps killing them outright).
2. Ensuring that the name of the unit rather than the id is shown when a transport unit is activated, to make sure people can tell what they're working with.

I'd also like this functionality (I put it in for Cold War but if this were built from scratch I'd argue it should be included):

1. An ability to not allow units to disembark on certain terrain tiles. This should be linked to the transporter itself. The way I used it in Cold War was to prevent cargo aircraft from dropping paratroops into a forest - they had to find a clearing.
2. An ability to decide if the transported unit (example, artillery) should have its movespent when it disembarks. The designer may or may not want that.
3. Perhaps a cost to load a unit?
4. Perhaps a tech advance required to load certain units?

Ideally I'd think this would wind up looking something like the munitions module where you can basically identify these requirements on a unit by unit basis.

Code:
primaryAttackTable[object.u88mmFlak.id] = {goldCost = 0, moveCost = 1,
        payload = false, 
        generatedUnitType = object.u88mmShells, copyVeteranStatus = true, numberToGenerate = 1, activate = true,}

But instead:

Code:
transportSettingsTable[object.u88mmFlak.id] = {transporterUnitUsed = object.uSdkfz, goldCost = 2, moveCostToUnload = 1,
        destroyedWithTransporterDeath = false, forbiddenTerrain = {0,1,2}, techRequirement = object.aBlitzkrieg, activate = true,}

Something like that, if you follow.
 
On the topic of the "more robust transport module" that @tootall_2012 had requested - I'd throw in my 2 cents as well as we wait for his.

-The module at present works well but the following opportunities were identified:

1. Either not sending the units to a different map/out of the way tile and in stead storing them elsewhere, or at least recalling them back to the scene of the transporter's death with less HP (or perhaps killing them outright).
2. Ensuring that the name of the unit rather than the id is shown when a transport unit is activated, to make sure people can tell what they're working with.

Yes, John has done a very good job to describe some of the enhancements that would be welcome. These two points are key for certain.
  • Currently, sending the units to a different map to 'temporarily' store them has two distinct disadvantages:
    • It requires the designer to reserve an entire physical map to do this, thereby reducing the total available maps by one. Granted in the majority of scenarios this won't be a problem as most design only use one map, but in the case of Hinge of Fate, for example, if John had also wanted to simulate the Atlantic war at sea by including an ocean map he would have had to make a choice between the transport mechanism or war at sea.
    • The other issue, is if a designer wants to be able to keep track of killed units to trigger certain events.
      • If the transport unit itself gets eliminated, the transported units still remain on the temporary map, and thereof wouldn't be added to the units killed count. Basically, we need to be able to keep track of units that are killed, whether they are being transported or not.
      • This could also cause a problem say if you wanted to keep track of a maximum number of units allowed on the map or on a specific area. In Napoleon for example, if France had more than 15 units in Spain it would lose the ability to renew the Franco-Spanish alliance. What if you wanted to allow only a maximum number of a specific unit to be constructed and exist at any specific time and couldn't build others if you had reached that maximum limit. In either case, how would you keep track of units being transported?
  • Being able to determine what unit is being transported by what transporter is very important otherwise it can quickly become difficult to keep track if you only have the unit ID's and have many transport units.

3. Perhaps a cost to load a unit?

Or unload as well.
 
Yes agreed with Tootall - also one more thing - I gave an example of the way it might look for a transportable unit but we also might want modifiers for the transporter itself so that certain units could only carry certain other units, or have more or less number to transport. Perhaps a C130 can carry some tanks across the ocean, but a Chinook helicopter could only take a Humvee. That sort of thing.
 
Back
Top Bottom