The Cold War II - Development Diary Thread

I'm working my way through China's events to start. Everything is modular now which makes it a little easier. I finished up the Korean War (including the American perspective of it) and am pleased with how it should function from both sides in single player mode. Not to give too much away, but while it doesn't "have" to go down the way it did in history, it can, and you might have a very long armistice as a result.

A **major** design goal this go around is to make it so one doesn't need to use a batch file (.isHuman is all that it takes) and also to ensure that the US and Soviets can decide to simply play as themselves and not also their minor faction (though you could still do this if you want). I'm trying to streamline things a bit from the base version in this way.
 
It has been a few years since I developed the old version but I remember this coming up in conversation somewhere and I've modified the way I did it before -- the way I *want* this to work is for the events to check down the line to see what tech the Americans have, and stop t the first if/elseif that is basically true and then not fire the rest. Not sure if I have this done correctly but this sequence is going to be allllll over the events so I'd better double check now and make sure it is right. Hopefully one of our coders can tell me if I'm boggling this up :)

Code:
if civ.hasTech(object.pAmericans, object.aJetFightersVII) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF15Eagle, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    elseif civ.hasTech(object.pAmericans, object.aJetFightersVI) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF16FightingFalcon, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    elseif civ.hasTech(object.pAmericans, object.aJetFightersV) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF14Tomcat, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    elseif civ.hasTech(object.pAmericans, object.aJetFightersIV) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF4PhantomII, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    elseif civ.hasTech(object.pAmericans, object.aJetFightersIII) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF104Starfighter, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    elseif civ.hasTech(object.pAmericans, object.aJetFightersII) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF100SuperSabre, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
            
    elseif civ.hasTech(object.pAmericans, object.aJetFightersI) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF86Sabre, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    elseif not civ.hasTech(object.pAmericans, object.aJetFightersI) then 
        local usaDefendsTaiwanTile = gen.nearbyOpenTilesForTribe({object.cTaipei.location.x,object.cTaipei.location.y,object.cTaipei.location.z},1,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},object.pAmericans)
            gen.createUnit(object.uF51Mustang, object.pAmericans, usaDefendsTaiwanTile, {count=4,randomize=true, veteran=true,scatter=true})
    
    end

Should the last one simply say "else"? instead of "elseif not"?
 
I think what you wrote will work (and "else" is an equally valid way of expressing the last section).

However, you might find this (untested) code more convenient, especially if you are making a lot of these kinds of events:

Code:
-- priorityList[i] = {techToCheck,unitTypeToCreate,numberToCreate}
--  Starting at key i = 1, WITH NO MISSING INTEGER,
--  if the tribe has the specified technology,
--  then the unit type is created in the quantity specified
--  if techToCheck is true, stop checking the list, and create the unit.
--  if numberToCreate is nil, use defaultCount supplied in function arguments
local taiwanTechPriorityList = {
    {object.aJetFightersVII,object.uF15Eagle,4},
    {object.aJetFightersVI, object.uF16FightingFalcon,4},

    {true, object.uF51Mustang,4},
}

-- createBasedOnTech(tribe,techPriorityList,location,radius,vetStatus,validPlacementTerrainTable,defaultCount)
--  tribe is the owner of units to be created
--  techPriorityList determines what unit type will be created based on the tech
--  location is the place near where the units will be created
--  radius is how many tiles away from location will be searched for a place to put units
--  vetStatus is the value of the 'veteran' option for gen.createUnit
--  validPlacementTerrainTable is a table of integers corresponding to the terrain types the created
--      units can be placed on
--  defaultCount is the default number of units to be created

local function createBasedOnTech(tribe,techPriorityList,location,radius,vetStatus,validPlacementTerrainTable,defaultCount)
    local number = nil
    local unitType = nil
    for _,data in ipairs(techPriorityList) do
        if data[1] == true then
            unitType = data[2]
            number = data[3] or defaultCount
        elseif tribe:hasTech(data[1]) then
            unitType = data[2]
            number = data[3] or defaultCount
            break
        end
    end
    local eligibleTiles = gen.nearbyOpenTilesForTribe(location,radius,validPlacementTerrainTable,tribe)
    gen.createUnit(unitType,tribe,eligibleTiles,{count = number,randomize=true,veteran=vetStatus,scatter=true})
end

createBasedOnTech(object.pAmericans,taiwanTechPriorityList,object.cTaipei.location,1,true,{0,1,2,3,4,5,6,7,9,10,11,12,13,14,15},4)

Something I did notice is that neither your code nor mine handles the situation where the 8 tiles around Taipei are occupied. Maybe gen.moveUnitAdjacent might be helpful. Let me know if you need more help.
 
Something I did notice is that neither your code nor mine handles the situation where the 8 tiles around Taipei are occupied. Maybe gen.moveUnitAdjacent might be helpful. Let me know if you need more help.

Will the game crash if all are occupied? If so I do probably need to do something about it. I'm not quite sure how to use gen.moveUnitAdjacent in this situation?
 
Edit - shoudl have just read your explanation twice "if numberToCreate is nil, use defaultCount supplied in function arguments"
 
Will the game crash if all are occupied? If so I do probably need to do something about it. I'm not quite sure how to use gen.moveUnitAdjacent in this situation?
If they're all occupied, gen.createUnit should just not create anything.

Here's modified code (still untested) that includes code to make a clear tile if necessary. It did turn out to be a bit more complicated than expected. Perhaps I should write a general library function with that feature.

Code:
local function createBasedOnTech(tribe,techPriorityList,location,radius,vetStatus,validPlacementTerrainTable,defaultCount)
    local number = nil
    local unitType = nil
    for _,data in ipairs(techPriorityList) do
        if data[1] == true then
            unitType = data[2]
            number = data[3] or defaultCount
        elseif tribe:hasTech(data[1]) then
            unitType = data[2]
            number = data[3] or defaultCount
            break
        end
    end
    local eligibleTiles = gen.nearbyOpenTilesForTribe(location,radius,validPlacementTerrainTable,tribe)
    local function tileCleared(tile)
        local result = false
        for unit in tile.units do
            result = gen.moveUnitAdjacent(unit)
            if not result then
                return false
            end
        end
        -- if we get here, the tile has been cleared 
        return true
    end
    if gen.isEmpty(eligibleTiles) then
        for _,tile in pairs(gen.getTilesInRadius(location,radius,1)) do
            if tileCleared(tile) then
                eligibleTiles = {tile}
                break
            end
        end
    end
    gen.createUnit(unitType,tribe,eligibleTiles,{count = number,randomize=true,veteran=vetStatus,scatter=true})
end
 
So this is probably a dumb question, but this code you wrote is magnificent because it really will streamline these events (and in a scenario spanning 50+ years, they'll be all over creation). My question though... The below (eventually multiplied 3-5 times for the different civs) screams, "put me in my own file and reference me elsewhere." For example, it's currently in a module I'm calling "chinaEvents" but really, I'd rather put it into a file I'm calling "grandEvents" which basically is almost like another object file that stores stuff for everywhere. I guess my question is how would I accomplish sticking these in one place so they don't have to be copied and pasted into 5 different places? I've noticed that it's easy enough to have different files have their own stuff like "onTurn" just by referencing "chinaEvents.onTurn" for example but I'm not sure how it would work since these are all just groups that start with a 'local'.

Hopefully this question makes sense? Also, if it's a big pain in the butt I certainly have enough "locals" to spare so it's not a huge deal to just copy and paste it. I'm using "nil" for the numbers so I can tweak how many show up for different events anyway, so it's not like I'd have to go and change 5 files once they're copy and pasted in.

(I haven't finished this so for example I need to edit the advances in a few spots, but you get the point)

Spoiler :

Code:
local usaFighterTechPriorityList = {
    {object.aJetFightersVII,object.uF15Eagle,nil},
    {object.aJetFightersVI, object.uF16FightingFalcon,nil},
    {object.aJetFightersV, object.uF14Tomcat ,nil},
    {object.aJetFightersIV, object.uF4PhantomII,nil},
    {object.aJetFightersIII, object.uF104Starfighter,nil},
    {object.aJetFightersII, object.uF100SuperSabre,nil},
    {object.aJetFightersI, object.uF86Sabre,nil},
    {true, object.uF51Mustang,nil},
}

local usaBomberTechPriorityList = {
    {object.aJetFightersIII, object.uB1Lancer,nil},
    {object.aJetFightersII, object.uB52Stratofortress,nil},
    {object.aJetFightersI, object.uB47Stratojet,nil},
    {true, object.uStrategicBomber,nil},
}

local usaAttackTechPriorityList = {
    {object.aAttackAircraftIV, object.uF111Aardvark,nil},
    {object.aAttackAircraftIII, object.uF105Thunderchief,nil},
    {object.aAttackAircraftII, object.uB57Canberra,nil},
    {true, object.uF4UCorsair,nil},
}

local usaHelicopterTechPriorityList = {
    {object.aAttackHelicopterII, object.uAH64Apache,nil},
    {object.aAttackHelicopterI, object.uUH1Huey,nil},
    {true, object.uUSInfantry,nil},
}

local usaTankTechPriorityList = {
    {object.aMainBattleTankIV, object.uM1A1Abrams,nil},
    {object.aMainBattleTankIII, object.uM60A3Patton,nil},
    {object.aMainBattleTankII, object.uM60A1Patton,nil},
    {object.aMainBattleTankI, object.uM48Patton,nil},
    {true, object.uM26Pershing,nil},
}

local usaArtilleryTechPriorityList = {
    {object.aMobileArtillery, object.uSPArtillery,nil},
    {true, object.uArtillery,nil},
}

local usaIFVTechPriorityList = {
    {object.aIFV, object.uBradleyIFV,nil},
    {true, object.uUSInfantry,nil},
}

local usaNukeTechPriorityList = {
    {object.aICBM, object.uICBM,nil},
    {object.aMRBM, object.uMRBM,nil},
    {true, object.uStrategicBomber,nil},
}

local usaNavalTech1PriorityList = {
    {object.aTiconderogaClassCGN, object.uTiconderogaCGN,nil},
    {object.aNPMissileCruisers, object.uCGN,nil},
    {true, object.uCA,nil},
}

local usaNavalTech2PriorityList = {
    {object.aMissileDestroyers, object.uDDG,nil},
    {object.aMissileFrigates, object.uFFG,nil},
    {true, object.uDD,nil},
}

local usaNavalTech3PriorityList = {
    {object.aNuclearPoweredNavy, object.uCVN,nil},
    {true, object.uCV,nil},
}

local usaAttackSubPriorityList = {
    {object.aAdvancedSSN, object.uLosAngelesClassSSN,nil},
    {object.aImprovedSSN, object.uSturgeonClassSSN,nil},
    {object.aNuclearPoweredNavy, object.uSkipjackClassSSN,nil},
    {true, object.uSSK,nil},
}

local usaMissileSubPriorityList = {
    {object.aLateSSBN, object.uOhioClassSSBN,nil},
    {object.aEarlySSBN, object.uLafayetteClassSSBN,nil},
    {true, object.uSSK,nil},
}
 
If you want put values in a file to reference elsewhere, you add those values to a table, and return that table. For example

priorities.lua
Code:
local priorities = {}

priorities.usaFighterTechPriorityList = {
    {object.aJetFightersVII,object.uF15Eagle,nil},
    {object.aJetFightersVI, object.uF16FightingFalcon,nil},
    {object.aJetFightersV, object.uF14Tomcat ,nil},
    {object.aJetFightersIV, object.uF4PhantomII,nil},
    {object.aJetFightersIII, object.uF104Starfighter,nil},
    {object.aJetFightersII, object.uF100SuperSabre,nil},
    {object.aJetFightersI, object.uF86Sabre,nil},
    {true, object.uF51Mustang,nil},
}

priorities.usaBomberTechPriorityList = {
    {object.aJetFightersIII, object.uB1Lancer,nil},
    {object.aJetFightersII, object.uB52Stratofortress,nil},
    {object.aJetFightersI, object.uB47Stratojet,nil},
    {true, object.uStrategicBomber,nil},
}

priorities.usaAttackTechPriorityList = {
    {object.aAttackAircraftIV, object.uF111Aardvark,nil},
    {object.aAttackAircraftIII, object.uF105Thunderchief,nil},
    {object.aAttackAircraftII, object.uB57Canberra,nil},
    {true, object.uF4UCorsair,nil},
}

priorities.usaHelicopterTechPriorityList = {
    {object.aAttackHelicopterII, object.uAH64Apache,nil},
    {object.aAttackHelicopterI, object.uUH1Huey,nil},
    {true, object.uUSInfantry,nil},
}

priorities.usaTankTechPriorityList = {
    {object.aMainBattleTankIV, object.uM1A1Abrams,nil},
    {object.aMainBattleTankIII, object.uM60A3Patton,nil},
    {object.aMainBattleTankII, object.uM60A1Patton,nil},
    {object.aMainBattleTankI, object.uM48Patton,nil},
    {true, object.uM26Pershing,nil},
}

priorities.usaArtilleryTechPriorityList = {
    {object.aMobileArtillery, object.uSPArtillery,nil},
    {true, object.uArtillery,nil},
}

priorities.usaIFVTechPriorityList = {
    {object.aIFV, object.uBradleyIFV,nil},
    {true, object.uUSInfantry,nil},
}

priorities.usaNukeTechPriorityList = {
    {object.aICBM, object.uICBM,nil},
    {object.aMRBM, object.uMRBM,nil},
    {true, object.uStrategicBomber,nil},
}

priorities.usaNavalTech1PriorityList = {
    {object.aTiconderogaClassCGN, object.uTiconderogaCGN,nil},
    {object.aNPMissileCruisers, object.uCGN,nil},
    {true, object.uCA,nil},
}

priorities.usaNavalTech2PriorityList = {
    {object.aMissileDestroyers, object.uDDG,nil},
    {object.aMissileFrigates, object.uFFG,nil},
    {true, object.uDD,nil},
}

priorities.usaNavalTech3PriorityList = {
    {object.aNuclearPoweredNavy, object.uCVN,nil},
    {true, object.uCV,nil},
}

priorities.usaAttackSubPriorityList = {
    {object.aAdvancedSSN, object.uLosAngelesClassSSN,nil},
    {object.aImprovedSSN, object.uSturgeonClassSSN,nil},
    {object.aNuclearPoweredNavy, object.uSkipjackClassSSN,nil},
    {true, object.uSSK,nil},
}

priorities.usaMissileSubPriorityList = {
    {object.aLateSSBN, object.uOhioClassSSBN,nil},
    {object.aEarlySSBN, object.uLafayetteClassSSBN,nil},
    {true, object.uSSK,nil},
}
return priorities

someOtherFile.lua
Code:
local priorities = require("priorities")
someFunction(priorities)

If I've misunderstood what you're asking, let me know.
 
Just plugging away at the Chinese events. Right now I have a delayed U.S./European response (if the U.S. or Europeans aren't human players) triggered for Hong Kong, Japan, Taiwan, and Australia based on if units are attacked by China in these areas. I just can't see China conducting a bombing run on Australia without the U.S. getting involved, so I don't have the trigger for cities. We will see how that goes in eventual playtesting.

--MAJOR EVENTS FOR CHINA AND COMPLETION STATUS
--CAN SEARCH FOR THESE PHRASES
--1. Chinese Civil War (COMPLETE)
--2. Chinese Annexation of Tibet (COMPLETE)
--3. Korean War (COMPLETE)
--4. Taiwan Strait Crisis (COMPLETE)
--5. Tibetan Uprising (COMPLETE)

--6. China-Burma Border Campaign
--7. Sino-Indian War (1962)
--8. Vietnam War
--9. Sino-Vietnamese War
--10. Theoretical China invades Japan (COMPLETE)
--11. Theoretical China invades Taiwan (COMPLETE)

--12. Theoretical China expands influence in Africa
--13. Theoretical China expands influence in Southeast Asia
--14. Theoretical Chinese War with Soviet Union
--15. Sino-Soviet Split
--16. Theoretical Chinese invasion of Australia (COMPLETE)
--17. Theoretical Chinese invasion of Western U.S.A.
--18. Theoretical Chinese expansion into India
--19. Theoretical Chinese expansion into Middle East
--20. Theoretical China invades Hong Kong (COMPLETE)
--21. The Death of Mao Tse Tung (COMPLETE) *Note this is complete in "grandEvents"
--22. The first use of home grown weapons (COMPLETE)

--23. Chinese expansion into man-made islands in South China Sea
 
A question for all on how to handle trade in both SP (where the AI will be hopeless anyway) and MP (where there's probably an opportunity to be different than most games that are just about trade).

Option 1: Standard game - all (or some) civs can build and produce freight.

Option 2: Go to a "resource" module. Get rid of the ASW aircraft as it's not that useful. Replace with "resources" that populates for the barbarian(?) civ. Depending on where on the map they pop they convert to the freight unit with a specific commodity set when killed. Might also tie it into ownership of a city region to make sure some players can't really "steal" the resource - so for example, if Brazil is "Pro-West," then the "resource" would show up as "Pro-East" non-disbandable, non-moveable that the US Civ can destroy but others can't. Some civs (China for example) might have access to true "barbarian" ones to make the mechanism work, but USA/Soviets wouldn't be able to attack this via lua.

The AI will be terrible at either or and I'm thinking #2 would be much more fun. There are certainly scenarios that have taken this approach before but with lua we can change commodities and such for the caravans and I think this can be further explored.
 
Perhaps instead of freight, you can use Lua events to create and remove trade routes between cities based on alignment, policy choices, etc. This way the player doesn't have to micromanage civilian traffic. I can help if you want/need it.
 
A small update while I try to get back some Civ2 mojo. I've decided to add in the SOund SUrveillance System (SOSUS) that the U.S. employed from the 50's onward. These were/are a series of hydrophones arranged in a semi circle in the Atlantic and at strategic spots in the Pacific to detect Soviet submarines.

All five major civs will be able to create their own system on the underwater map. For a hefty set price, a submarine can press a button while on the underwater map and it will bring up a menu that allows you to place a hydrophone, or decide against it. If you place it, you lose the price, a distinct hydrophone tile for each of the five civs replaces the ocean floor, and your submarine is moved a few spaces away (to prevent it from hanging out, impervious, on a new "land" tile).

So far this part works. The next job is to take a look at how far radar in lua has come since I last did anything with it but the idea will be that this system will allow detection of naval assets. Ideally it would detect all surface ships as well as almost all older subs, most mid-tier subs, and a few late tier subs based on a random chance it's found each turn (because, I mean, they're subs - we don't want them all seen). I was thinking maybe 90% of the older subs, 60% of the mid-tier subs and 30% of the late tier subs would probably be good. Thus, a nation that invests heavily in late tier submarines can expect that most won't be detected.

The goal will be for the SOSUS system to do a scan unprompted at the start of each human player's turn and return a marker (probably pollution) for every naval asset found, which will then be wiped after the end of the turn.

This should give the civ that creates a decent ring of this a considerable advantage in that they don't have to scour the oceans to track enemy movement, but it also won't be foolproof.

I might disable the system in the single player game (so the human can't get an unfair advantage) or try and figure out a way to give the AI some benefit to this -- perhaps by somewhat randomly placing them by events and then if they're at war with a civ that gets an asset too nearby, maybe simulating a strike on those enemy assets by reducing their hitpoints or some such).

1694518382559.png


1694518411578.png
 
Top Bottom