1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

[TOT] New Supply Lines module for Lua events

Discussion in 'Civ2 - Scenario Creation' started by Knighttime, Dec 23, 2018.

  1. Knighttime

    Knighttime Chieftain

    Joined:
    Sep 20, 2002
    Messages:
    60
    More than a few scenario developers have probably wished there was a way to implement supply lines into a scenario, in an abstract way -- that is, without the micromanagement of moving dozens of supply train units across the map each turn. This concept is now possible and can be integrated into a TOT scenario using Lua events and TOTPP, and the attached module provides a working implementation.

    This is a separate supplyLines.lua file that would be stored within a scenario directory and referenced from the scenario's main events.lua file. It allows the scenario designer to first customize the definition of a valid supply link -- that is, what criteria determine whether or not a supply line can pass through a given tile. Then you can customize the definition of a valid supply depot, from which supplies would originate to reach units in the field. The remainder of the code in the module contains the pathfinding logic that searches for a connection between the unit and depot that meets all of the criteria. Each time a unit is activated, the main events.lua file runs this module to immediately determine whether or not that unit is supplied.

    As an aid to the designer, the module also contains a "review" feature that will highlight the shortest valid path connecting the active unit to the nearest valid supply depot. (If there are multiple paths of equal length, the first one found by the pathfinding logic is the one which will be highlighted.) If no such depot could be found, the highlighting can be used to reveal the area of the map from which the active unit *could* be supplied, if a depot was located there.

    More details, including a working example, are available within the attachment. Here are a series of screen shots to illustrate the behavior:

    SupplyLines1.jpg
    In this first screen shot, the Warrior cannot be supplied from the city of Rome, because it is not a port city. (This example defined supply lines that are permitted to cross ocean tiles, but only to reach port cities -- they may not proceed further inland.) Therefore the closest depot is the city of Antium, so the supply line ignores Rome and connects Antium to the Warrior.

    SupplyLines2.jpg
    In this second screen shot, a barbarian Trireme has now blockaded the north side of the city of Antium, which was previously part of the supply line. However, the pathfinding logic determined that it is still possible for supplies from Antium to reach the Warrior, by a longer southern route.

    SupplyLines3.jpg
    In this third screen shot, another barbarian Trireme has now occupied a narrow channel that was previously part of the southern supply line to Antium. The pathfinding logic correctly identified that now Antium is no longer reachable at all, so the shortest valid supply line extends all the way to Cumae.

    LuaConsole.jpg
    The Lua console, which provides information to the scenario designer, reveals the actions taken by the module in the above examples. As you can see, Lua is pretty quick! The pathfinding logic analyzed 1731 tiles in order to find the supply line between the Warrior and Cumae, which was 65 tiles long, and it did so in less than 1/10 of a second. It should be possible to support supply lines of just about any length, even on large maps, with no discernible lag in performance. However, it's very easy to configure a maximum supply line length, which may be more realistic for scenarios anyway. This would limit the number of tiles the module would need to analyze, and would also ensure that performance remains acceptable even on extremely large maps.

    If this feature would be useful in a scenario you are designing, you're welcome to incorporate it and customize it as you wish. I'll do my best to answer any qustions you may have as you do so. Please let me know if you have any feedback, including requests for new features.

    As with all Lua features for TOT, a big round of applause for TheNamelessOne who created TOTPP and made it possible for Lua events to interact with the game, at a level far surpassing what was possible with the original macro language.

    Happy Civing!
     

    Attached Files:

    Last edited: Dec 23, 2018
    Prof. Garfield and JPetroski like this.
  2. tootall_2012

    tootall_2012 Chieftain

    Joined:
    Feb 11, 2012
    Messages:
    449
    Hi Knighttime,

    This is a very interesting indeed and I’m certain many designers will want to implement this in their scenarios at one point or another. I did take the opportunity to take a preliminary look at the event file itself and, if you don’t mind, had few starting questions.

    Looking at the code, it’s a little unclear to me. Can a supply source only be a city tile or could it also be a unit (say an HQ or Supply Depot)?

    Could one limit the number of units a supply source could support, say either based on a hardcoded number or the size of a city for example?

    It looks like the supply for each unit is determined at the moment of its activation (civ.scen.onActivateUnit). Does the out supply status apply for the remainder of the turn? Or can a unit move within that same turn to a tile that would put it back in supply? Personally I would prefer the former but since the event appears to be related to the onActivateunit I suspect it might be the latter.

    In the events.lua file you made the effect of being out of supply to reduce the attack factor to zero. Could one also reduce its movement factor, for example to one or zero MP’s, or apply attrition to the unit or any combination of all three at the same time?

    Does an enemy unit’s ZOC (i.e. the 8 tiles surrounding the unit) block a supply line or just the tile the unit physically occupies count?

    I noticed in the supplyLines.lua that the code appears to apply only for land units. Could a similar kind of feature be designed for naval units? I’ve always found it somewhat unrealistic that once your naval units left a port that they could essentially remain at sea for the remainder of the scenario without ever needing to come back to port. Would it be possible, for example, to reduce the movement factor of a naval unit that was at sea by half if it didn’t begin the turn say stacked with a supply/tanker ship?
     
  3. JPetroski

    JPetroski Chieftain

    Joined:
    Jan 24, 2011
    Messages:
    1,233
    This is an awesome tool that I think is going to make a world of difference in new scenarios, and possibly refresh some older ones.

    Knighttime had asked me about ZOC when developing this and I asked that he not include that at the time because I was looking at this from the perspective of trying to replicate Stalingrad, with the 6th Army desperately trying to keep a small corridor open for supplies and so I was trying to go for a total encirclement to cut off supplies.

    With that said I at least got the impression from our conversation that ZOC would be possible.

    One question I have is if it would be possible to perhaps use a terrain "improvement" like pollution, an airbase or fortress to show the supply chain (rather than a unit) which the player could then press a key to "see" briefly before it "disappears" (perhaps onActivate of the next unit). All this to help people understand what they need to do to break the siege or to effect one.
     
  4. Knighttime

    Knighttime Chieftain

    Joined:
    Sep 20, 2002
    Messages:
    60
    All good questions! I will start a list of possible enhancements for version 2.0. :)

    Yes, it could certainly be a unit. Really it can be any object or attribute that is associated with a specific location on the map. The isValidSupplyDepot() function takes a tile and a tribe as parameters, and needs to contain logic to answer the question, "Can this tile serve as a supply depot for this tribe?" I could add another commented-out example in that function, showing how to test that location for the presence of a particular unit type.

    However, remember that due to an apparent bug, if a unit is activated directly from the city screen, the onActivateUnit() trigger doesn't fire. If all cities are supply depots, and your suppliedUnitEffects() function is written to assume that units are supplied by default and to apply a penalty if they are not, this isn't really an issue. But if some/all cities are not supply depots, you could run into a situation where a unit activated in such a city wouldn't search for a supply line. So... just something to keep in mind as the designer, and weigh pros and cons.

    The only other thing I'll add is that a key advantage of this module is that it allows you to abstract supply lines away from needing to move supply train units around on the map, thus reducing micromanagement. Using a unit as a depot is certainly possible, but if you take that idea too far, you may end up losing much of the benefit.

    How would you envision that the game would identify which units are supplied by that source, if the number of possibilities exceeded that limit? Simply order of unit activation on a given turn? That seems a little arbitrary and could force the player back into micromanagement, by very carefully activating units manually in a particular order. From a code perspective, this would require the use of the state table to track history, so it would add quite a bit of complexity. I'm not sure I see a clear path forward for this one yet.

    Correct, it's the latter at this point: a unit which begins its turn "out of supply" does not necessarily have that status for its entire turn. A change in status could be achieved by moving the unit (so that it's in range of a supply depot) or by killing an enemy unit that was blocking a depot (thereby opening up a valid supply line) or even by adding/moving a supply depot (building a new city, moving a supply "storehouse" unit, building a new tile improvement such as an airbase, etc.).

    Calculating the supplied status for each unit at the beginning of your turn, and having that status apply for the entire turn, would definitely be possible, but this would again require the use of the state table. Because units can be both killed and created during a turn, and unit IDs get reused by the game :(, the complexity goes up quickly. Would this be a huge benefit to you? If so I can add it to the list of version 2.0 ideas. Personally I prefer the current behavior, and it was definitely simpler to write, so that's why it works this way in version 1.0. :)

    Absolutely, all of those are possible. The example provided in events.lua was recommended by @JPetroski to illustrate the power of this feature, but it's just one example and not intended to limit you from introducing new or different effects.

    This is definitely something I considered, but based on John's feedback it didn't seem like a critical feature, at least for version 1.0. This would add some complexity to the code, but my biggest concern is performance: this would mean that every tile the code analyzes, to see if it's a valid supply link, would require it to find up to 7 other tiles, and look for enemy units on them. That could be a pretty severe hit and might mean that there would need to be a much lower cap on the maximum supply line length, to avoid a noticeable lag each time a unit is activated. I haven't tried to write or test this yet, though, so it's all speculation at this point.

    Yes, a similar kind of feature would be possible, but it seems to me that you might want different rules for valid supply lines, or depots, than you would use for land units. So this might necessitate adding additional constants at the top of the file, splitting isValidSupplyDepot() into separate isValidLandUnitSupplyDepot() and isValidNavalUnitSupplyDepot() functions, possibly doing the same to isValidSupplyLink(), and then adjusting the core logic in hasSupplyLine() to branch based upon unit domain.
    This actually wouldn't require a supplyLines module at all, since the primary purpose of it is pathfinding -- detecting an open route between a unit and a depot located elsewhere. If all you want is to detect the presence of a supply unit on the same tile, for either land or naval units, this could be done directly within the onActivateUnit() section of your events.lua.

    Sure, that would be possible and not too difficult. I picked a unit because it seemed more likely that a scenario could spare one unit slot, than that the scenario would have no pollution/fortresses/airbases thus leaving one of those icons available. I could add some commented-out examples of how to implement those other options though.
     
  5. JPetroski

    JPetroski Chieftain

    Joined:
    Jan 24, 2011
    Messages:
    1,233
    I'm trying to envision how to use this for naval supply routes, specifically convoy routes going to Britain (or any other island in any scenario). In this case, it would be preferable for the city to be reliant on supplies more so than the unit. From Garfield's work on OTR, I know that it is possible to change the production of a city each turn (or probably each "other trigger") to 0 shields, or likely to reset its food supplies, etc.

    If a designer were so inclined, rather than requiring the game to check for every possible route, could a route be predefined? Imagine a straight (or curved) line of coordinates in a table that a designer goes through the trouble of writing into a large table. If any such tile has an enemy unit on it, the city it supplies is effectively cut off.

    Perhaps I would then draw several lines across the map that feed into Britain - if these are cut, then perhaps one city goes dark per line, or perhaps each city has a reduced production by some percentage depending on how many lines are cut.

    I'm especially interested in this because Hinge of Fate will have multiple maps. The east coast of North America will be one map and Europe will be another. I imagine that a system like this would work across multiple maps, because it would simply be a matter of the game checking different coordinates on different maps in a table - I suspect that wouldn't cause major issues.

    I think that this would be very useful for my scenario as well as @Prof. Garfield 's planned Imperialism remake. This would cut down on micromanagement in that a player wouldn't need to scour the entire ocean looking for supply ships to sink, or U-Boats to defend against. They'd have a set line to patrol, which I imagine would be fairly true to real life anyway (most sea lanes are well known and utilized). Importantly, I can get the AI to defend these sea lanes with unit creation and moveunit commands.

    I know there is the issue with onActivate for the units but if the goal is to simply starve the cities by cutting them off (so they can't produce anything else and perhaps actually start starving) would this system work for a naval supply mechanism?
     
  6. tootall_2012

    tootall_2012 Chieftain

    Joined:
    Feb 11, 2012
    Messages:
    449
    Hi Kighttime,

    Thank you for the feedback. For now, I’m simply trying to understand what the feature is capable of doing and what are its potentials and limitations, so I’m not ready to request any enhancements or changes.

    One of the future projects I’m envisioning working on is my companion to my Battle of France scenario, which is the Battle of Italy (from Sicily to the end of the war). I can definitely see supply playing an important role in that design.

    In my vision, one of the advantages of using HQ or Supply type units, would be to limit the supply range, in order to represent the danger of armies running too far ahead of their supply sources.

    Understood.

    Understood. This allows me to understand the potential pitfalls to avoid.

    Though I prefer the former, I think the fact that one of the effects you could apply is to reduce the MP of an unsupplied unit to zero, would resolve my personal dilemma. In this manner, the isolated unit would require a friendly unit to come to its aid to redress its supply situations and if you added attrition to the mix would make things even more interesting.

    That sound great!

    As long as the conditions are clear, I think most designers could live with the simpler solution.

    I don’t see any harm in giving designers the extra flexibility.

    In this instance, I was thinking of my next version of my Total War scenario whereby naval task forces would be required to move around with tanker/supply ships to be able to move effectively at sea. If this can be accomplished with the onActivateUnit() function, all the better.


    I'm nowhere near selecting my next major project (though its not the options that are missing) but it's good to know some of the new lua features that will be there when I'm ready to move forward.

    Short term, I'm hoping to complete the changes to version 1.1 of Napoléon once I've received feedback from the players. After that, I would probably like to finalize my Battle of Alesia scenario. Since it is relatively short and simple in concept, it would be an ideal candidate for me to try to write the core of the lua for it (though I'm certain I would probably need help along the way).
     
  7. McMonkey

    McMonkey ----Evertonian---- SLeague Staff

    Joined:
    May 9, 2005
    Messages:
    2,769
    Location:
    Cardiff
    Well my mind is blown! This is a hell of a development. The Train Militaire/Attrition in Napoleon worked perfectly for the particular historical situation in that scenario. Having to build them & then ensure they are in the right place at the right time. This will just add another dimension, especially in modern scenarios where foraging is not really a viable option for mechanized armies.

    I'm so impressed. Thanks for all the effort you're putting in here Knighttime!
     
  8. Knighttime

    Knighttime Chieftain

    Joined:
    Sep 20, 2002
    Messages:
    60
    So, just to avoid any confusion, I think the term "naval supply" is best used to refer to supplies reaching naval units. What you're describing is a concept I would refer to as "city supply" -- with specific supply line criteria that (only? primarily?) involve the use of ocean tiles.

    Yes, it's possible to set the number of food stored in the food box, and/or the number of shields stored in the shield box. It is not possible, at present, to change what the city is building. It's also not possible to directly set the quantity of food or shields generated each turn, since that's derived from the tiles worked and then adjusted by city improvements and wonders.

    Well... as I mentioned above, the key breakthrough with this module is pathfinding -- that is, finding a valid route through any portion of the map based on a set of criteria that need to be continually re-evaluated because they could change based on player actions. If you have a set of predefined coordinates in a table, and you want to know whether any of them are blocked by an enemy unit, I'd do that by looping through the table, not by using this supplyLines module:
    Code:
    local supplyLineOpen = true
    for _, supplyTile in pairs(supplyLineTable) do
       for unit in supplyTile.units do
           if unit.tribe ~= thisTribe then
               supplyLineOpen = false
               break
           end
       end
       if supplyLineOpen == false then
           break
       end
    end
    Using the supplyLines module could potentially work, but it feels a little like using pliers to pound in a nail. :)

    So depending on how these lines are laid out, whether or not they crisscross, and whether there are multiple branching paths through them, it might mean that the supplyLines module is more appropriate after all. If an enemy unit blocking a tile on a predefined supply line automatically invalidates that supply line, you probably don't need the module; but if that situation means that supplies could potentially reroute along a different path to still reach the destination successfully, that seems more like a situation where the module may come in handy.

    Actually, the core logic of the module relies very heavily on the concept of adjacent tiles on a single map. I think supply lines that stretch across different maps (especially where the "connection" has a different X,Y coordinate, not just a different Z coordinate) would mean that you could not use this supplyLines module -- at least, not without a substantial rewrite (version 2.0 at least).

    I can see why this concept of sea lanes for supplying cities might be well-suited to some scenarios, but to be quite honest it seems different enough from the way supply lines are conceptualized for units in this module, that I think you would be better off building a different solution from scratch. Perhaps I should start work on a "seaLanes.lua" module? ;)

    I think land unit supply and naval unit supply are best triggered by onActivateUnit(), but city supply (which is what you're discussing) would probably belong in the onTurn() trigger. In summary, I think your vision is definitely possible, it's just pretty different from what this was written to do.

    That makes sense. I think this supplyLines module would work well in connection with supply units as long as you want supply units to benefit other units within the surrounding area. If a supply unit should only provide supplies to units on its own tile, you don't need this module.

    Yep -- again, the distinction is whether supply units have a supply radius reaching to multiple tiles, or if they only affect the single tile on which they're located.

    Thank you sir! :D It's great to hear that this seems like a useful feature.
     
    Last edited: Dec 28, 2018

Share This Page