The Hinge of Fate - Development Thread

I made good progress tonight but with 12 rules files it's going to take a bit. I'm opting for generic names of the 62 new units so I can speed things a bit. This is probably more manageable on the player than having to figure out what specific equipment names are/do as the game progresses, anyway.

Summer '40 units so far... I still have some slots to fill. There's nothing pressing so I might leave them until I come up with ideas later.

upload_2022-1-12_0-17-38.png
 
John, what are the changes you're making to take advantage of v18.0?

All the units from the line right above 136-144 above on down are either new, or at least are available (assuming they're researched) "from the start." I was (and still am, for the Allies) using lua to recycle some slots which meant, for example, that the Panzer II eventually turned into the SP artillery and now that is no longer required.

To be honest, the game was playing pretty well in playtests so much of this is just to make it more interesting, to give the minor Axis nations especially some depth (rather than using Italian stuff for everyone) and to flesh out Yugoslavia. I intend to more thoroughly explore that element of the war now that I can build out Tito's forces to a greater extent. I also intend to flesh out the Turkish and Spanish campaigns more now. Since they never happened, I have to invent what would have occurred.

I had enough tech slots to incorporate these already so I didn't need to take advantage of the extra ones. I haven't really explored the additional commands in lua available now but taking a quick look there wasn't anything that caught my eye as being critical.

Basically, the periphery of the game is enhanced at this point. I had 127 units and pushed it to over 150 with the unit swap events so many "nice to have" units were added. I'm hoping to get the rules/unit art in place and perhaps finish the events this weekend to start other playtests.
 
So mostly extra units? I've also added some slots in my 1937 project to Give each Japanese industrial city its own factory units. Otherwise, I'm happy with the compromises I've already made. Some limits on units and techs imposes a certain discipline that I appreciate. It helps keep it from being an open-ended project that never gets finished.
 
Well I hear you on that. Luckily 80% of the changes are just copy and paste for the different minors. Our artists work so hard that it's great to be able to get more of their stuff into the game.

Just as an FYI the way the Knighttime's module works (and presumably the way Prof. Garfield will work as well) - one "factory" unit can work for every city, so if there's no real reason for each one to have an individual type you can save the slots/some work. HoF has strategic bombing where I'm only using a factory, oil refinery, and urban unit for each city that can build them (Germany and the Axis Minors). You link it with coordinates

There's a table where each city is defined. Here's one (Berlin, or city 0 meaning the first one I placed. [15] is for my factory improvement, which in the second section of code further below is linked to unitTypeID 126 meaning the 127th unit (because it starts at 0).

strat.cityCoordinates = {
-- Outer key is a city ID
-- All nested (inner) keys are improvement IDs

--GERMAN INDUSTRIAL CITIES (includes Prague, Pilsen, and Austria)

--[[ Berlin ]] [0] = {[15] = {{128,62}}, [5] = {{128,66}}, [4] = {{130,62}, {129,63}, {131,65}}, [14] = {{129,65}, {131,67}, {132,64}, {131,63}} },

}

This below looks like goblygook but is named well enough that I think you can follow. Basically the building of a city improvement changes the terrain type to a high-yield industrial or trade tile. Destroying the unit not only takes away the improvement, but also changes the terrain.

strat.improvementUnitTerrainLinks = {
-- Key is an improvement ID
--[[ Factory ]] [15] = {unitTypeId=126, buildTerrainTypeMap0=13, buildTerrainTypeMap1=13, buildTerrainTypeMap2=13, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=14},
--[[ Fuel Refinery ]] [5] = {unitTypeId=123, buildTerrainTypeMap0=12, buildTerrainTypeMap1=12, buildTerrainTypeMap2=12, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=14},
--[[ Civilian Population ]] [4] = {unitTypeId=124, buildTerrainTypeMap0=5, buildTerrainTypeMap1=5, buildTerrainTypeMap2=5, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=15},
--[[ Housing District ]] [14] = {unitTypeId=39, buildTerrainTypeMap0=5, buildTerrainTypeMap1=5, buildTerrainTypeMap2=5, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=15},

}

I'd really encourage you to load up Over the Reich and play a turn against yourself to see it in action. You can get immediate results with Bomber Command's attack on Cologne. I imagine when @Prof. Garfield releases the strat bombing module it'll be a little different but it will likely have the same idea. I think he was considering making it so you don't even need to define (and potentially mistype) coordinates for each city.
 
Our artists work so hard that it's great to be able to get more of their stuff into the game.

:yup: Yes, and I am especially astonished about the very good quality of the major ships in such a small place. :thumbsup: The only one that has not the quality of the other ships, is the pocket battleship of the Deutschland Class.
 
Well I hear you on that. Luckily 80% of the changes are just copy and paste for the different minors. Our artists work so hard that it's great to be able to get more of their stuff into the game.

Just as an FYI the way the Knighttime's module works (and presumably the way Prof. Garfield will work as well) - one "factory" unit can work for every city, so if there's no real reason for each one to have an individual type you can save the slots/some work. HoF has strategic bombing where I'm only using a factory, oil refinery, and urban unit for each city that can build them (Germany and the Axis Minors). You link it with coordinates

There's a table where each city is defined. Here's one (Berlin, or city 0 meaning the first one I placed. [15] is for my factory improvement, which in the second section of code further below is linked to unitTypeID 126 meaning the 127th unit (because it starts at 0).

strat.cityCoordinates = {
-- Outer key is a city ID
-- All nested (inner) keys are improvement IDs

--GERMAN INDUSTRIAL CITIES (includes Prague, Pilsen, and Austria)

--[[ Berlin ]] [0] = {[15] = {{128,62}}, [5] = {{128,66}}, [4] = {{130,62}, {129,63}, {131,65}}, [14] = {{129,65}, {131,67}, {132,64}, {131,63}} },

}

This below looks like goblygook but is named well enough that I think you can follow. Basically the building of a city improvement changes the terrain type to a high-yield industrial or trade tile. Destroying the unit not only takes away the improvement, but also changes the terrain.

strat.improvementUnitTerrainLinks = {
-- Key is an improvement ID
--[[ Factory ]] [15] = {unitTypeId=126, buildTerrainTypeMap0=13, buildTerrainTypeMap1=13, buildTerrainTypeMap2=13, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=14},
--[[ Fuel Refinery ]] [5] = {unitTypeId=123, buildTerrainTypeMap0=12, buildTerrainTypeMap1=12, buildTerrainTypeMap2=12, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=14},
--[[ Civilian Population ]] [4] = {unitTypeId=124, buildTerrainTypeMap0=5, buildTerrainTypeMap1=5, buildTerrainTypeMap2=5, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=15},
--[[ Housing District ]] [14] = {unitTypeId=39, buildTerrainTypeMap0=5, buildTerrainTypeMap1=5, buildTerrainTypeMap2=5, destroyTerrainTypeMap0=14, destroyTerrainTypeMap1=14, destroyTerrainTypeMap2=15},

}

I'd really encourage you to load up Over the Reich and play a turn against yourself to see it in action. You can get immediate results with Bomber Command's attack on Cologne. I imagine when @Prof. Garfield releases the strat bombing module it'll be a little different but it will likely have the same idea. I think he was considering making it so you don't even need to define (and potentially mistype) coordinates for each city.
So mostly extra units? I've also added some slots in my 1937 project to Give each Japanese industrial city its own factory units. Otherwise, I'm happy with the compromises I've already made. Some limits on units and techs imposes a certain discipline that I appreciate. It helps keep it from being an open-ended project that never gets finished.

The units I plan to add to EotRS are also things I had considered and toyed with in the past, and that appeared, in many cases, on past working versions of my units files, but I ended up cutting after griping, groaning, and bellyaching, as well.
 
Thanks for that. I will try to get it working well with Macro events first, then store them as Legacy events with Lua, then add some bits that reduce the need for a bunch of house rules. I really hope I can get some guidance on setting up the Legacy events part when the time comes. For me, learning a few bits at first and then gradually broadening my understanding really seems to be the way to go. One step at a time.

One question: Would it be possible to limit the ability of a trade unit to only be able to trade into a city which had a specific improvement? For example, a market?
 
I think since 0.17 there has been the ability to remove a trade route, at least, so I would guess (but am not sure) that you could at least get rid of it after the fact. We have some new options for when an event fires, including at the end of a turn, so maybe you could run the check at that point and fix things. I'd have to defer to one of the masters but at the very least you should be able to see of a city without a market has a trade route, and remove it if it does. I'm not sure if you could prevent it from being established in the first place. Restoration of the unit is likely possible by having a condition where if the route is removed, a unit is reestablished next to the city, but I don't know how you'd get around picking what the original units home city or commodity was (though I think both can be set).
 
One question: Would it be possible to limit the ability of a trade unit to only be able to trade into a city which had a specific improvement? For example, a market?

Not easily. The only thing I can think of (other than @JPetroski 's suggestion to delete the route after the fact) is to use onActivateUnit to change the trade unit's type role if it is beside a city without the requisite improvement. That is, change the unit type's role from trade to diplomacy or something when it is activated beside an incompatible city. Or, I suppose, use a key press event to simulate a delivery.

You may want to let @TheNamelessOne know that this is something you could use. Since at least v17, there has been an 'onCaravanArrives' registration function in civ.scen (reveal with console command: for key,val in pairs(civ.scen) do print(key) end) so presumably this sort of thing has been thought of, but got delayed in favour of other features (or is harder than anticipated).
 
Thanks PG, I will let him know. The gist of it is this: Units may only be built in the 10 cities that have an industry or naval shipyard unit. There are 6 in the southern portion of Japan shown on the map, 2 in Manchuria, and one each in Korea and Formosa. The only units that can be built in captured Chinese cities are 'resource' (trade) units. They can be disbanded anywhere, but I only want them to trade into cities in Japan proper. That forces the player to transport them by sea to get gold or to build combat units. And there they must pass the gauntlet of the USN's very effective submarine campaign. So limiting resource units to trading into cities with a specific trade improvement means I can dispense with another house rule. (Sorry for the hijack John - I promise I'll start my own thread shortly.)
 
The gist of it is this: Units may only be built in the 10 cities that have an industry or naval shipyard unit. There are 6 in the southern portion of Japan shown on the map, 2 in Manchuria, and one each in Korea and Formosa. The only units that can be built in captured Chinese cities are 'resource' (trade) units. They can be disbanded anywhere, but I only want them to trade into cities in Japan proper. That forces the player to transport them by sea to get gold or to build combat units. And there they must pass the gauntlet of the USN's very effective submarine campaign. So limiting resource units to trading into cities with a specific trade improvement means I can dispense with another house rule.

Oh, it would be very easy to do a key press event to just give gold/science/whatever to the Japanese when the unit reaches Japan. In Over the Reich, we gave the player units and gold when a convoy reached a port and the player pressed k with the convoy active, but only if the city had a port facility and hadn't unloaded too many convoys in that town already that turn.
 
8/12 unit art done and the "mechanics" Lua modules adjusted. I hope to finish the rules and unit art over the weekend, build out a few last campaign events, and hopefully start another playtest shortly.
 
I've attached a modified transport file. It provides the opportunity to either unload the truck when the enemy attacks (default version), or kill the units. @SorFox may be interested in this as well.

I don't think you're using civ.scen.onChooseDefender elsewhere, but if you are, you will want to move that part out of this file.

Code:
--transport.onChooseDefender by Prof. Garfield
function transport.onChooseDefender(defaultFunction,tile,attacker,isCombat)
    for unit in tile.units do
        -- max of two units on truck, so unload twice
        transport.unloadUnitsOffTruck(unit)
        transport.unloadUnitsOffTruck(unit)
    end
end
civ.scen.onChooseDefender(function(defaultFunction,tile,attacker,isCombat)
    transport.onChooseDefender(defaultFunction,tile,attacker,isCombat)
    return defaultFunction(tile,attacker)
end)
A couple lines of transport.unloadUnitsOffTruck were also changed, to allow for unloading a truck that is not the active unit

You can also comment out the above lines, and uncomment out the lines below if you want units to be killed when the truck is defeated.
Code:
-- transport.onUnitKilled by Prof Garfield
-- if using this effect, add this line to the unitDefeated event
--    transport.onUnitKilled(loser,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
--local transportVehicleType = {}
--transportVehicleType[26]=true
--transportVehicleType[118]=true
--
--function transport.onUnitKilled(loser,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
--    if state.loadedTrucks[loser.id] and transportVehicleType[loser.type.id] then
--        -- truck is killed, get cargo, and kill it on the loser's square
--        for _,cargoId in pairs(state.loadedTrucks[loser.id]) do
--            if type(cargoId) == "number" then
--                local cargoUnit = civ.getUnit(cargoId)
--                if cargoUnit.owner == loser.owner and cargoUnit.location == storageTile then
--                    -- this is to double check the unit is still on the truck
--                    cargoUnit:teleport(loserLocation)
--                    gen.defeatUnit(cargoUnit,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
--                end
--            end
--        end
--       
--        -- remove truck loaded status from table
--        state.loadedTrucks[loser.id] = nil
--        return
--    elseif state.loadedTrucks[loser.id] then
--        -- A unit with the id of a former truck is killed, but that unit isn't a truck
--        -- clear the state table of that unit
--        state.loadedTrucks[loser.id] = nil
--        return
--    else
--        -- some other unit was killed, return with no action
--        return
--    end
--end
You will also have to add the line specified to the unitDefeated event (and, perhaps, move some unitKilledInCombat events to unit defeated if you want them to apply to truck cargo.
 

Attachments

Thank you. I have a "local function chooseDefender(defaultFunction,tile,attacker,isCombat)" but there's a separate function right above it for civ.scen.onChooseDefender - so I'm good as these are different?
 
I've attached a modified transport file. It provides the opportunity to either unload the truck when the enemy attacks (default version),

I tried testing this by loading up a truck, switching civs, and destroying the truck and the units don't unload (I left everything at default) - so maybe I do need to move these lines to the "chooseDefender?"
 
I tried testing this by loading up a truck, switching civs, and destroying the truck and the units don't unload (I left everything at default) - so maybe I do need to move these lines to the "chooseDefender?"
Yes, put this line at the beginning of your chooseDefender function.
Code:
transport.onChooseDefender(defaultFunction,tile,attacker,isCombat)
Either you didn't have a chooseDefender event in the version I have, or this file got loaded later in my version for some reason. Remember to comment out the civ.scen.onChooseDefender stuff in the transport module.
 
Thank you. I have a "local function chooseDefender(defaultFunction,tile,attacker,isCombat)" but there's a separate function right above it for civ.scen.onChooseDefender - so I'm good as these are different?

civ.scen.onChooseDefender registers a function for the onChooseDefender execution point. It is probably registering the local chooseDefender function. You might be confused because frequently a function is defined within the onChooseDefender call.

It's the same idea as
Code:
civ.ui.text("My message")
and
Code:
local message = "My message"
civ.ui.text(message)
 
I was trying to swap over to the unitKilled one and got one of these errors:

...cenario\Hinge of Fate\LuaTriggerEvents\triggerEvents.lua:295: attempt to call a nil value (field 'onChooseDefender')
stack traceback:
...cenario\Hinge of Fate\LuaTriggerEvents\triggerEvents.lua:295: in function <...cenario\Hinge of Fate\LuaTriggerEvents\triggerEvents.lua:294>

error: bad return value #-1 from 'onChooseDefender' (civ.unit expected, got nil)

I did add this to the function:

function triggerEvents.unitDefeated(loser,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
transport.onUnitKilled(loser,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
context[getContext()]["unitDefeated"](loser,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
universal["unitDefeated"](loser,winner,aggressor,victim,loserLocation,winnerVetStatus,loserVetStatus)
legacy.doUnitKilledEvents(loser,winner)

log.onUnitKilled(winner,loser)

end

Did I comment out things appropriately in the attached file?
 

Attachments

Back
Top Bottom