Results 1 to 11 of 11

Thread: Apparently negative unit refresh rate is possible, and works as you'd expect it

  1. #1

    Default Apparently negative unit refresh rate is possible, and works as you'd expect it

    Let's say you created a new building type called "Hellenistic Police Force" which provides law bonuses, but then provides the following "recruitment":


    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  -0.08  0  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1
    recruit_pool "hellenistic infantry hemithorakitai"  0  -0.08  0  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1
    recruit_pool "hellenistic infantry machairaphoroi"  0  -0.08  0  0  requires factions { cul_1, cul_3, f_pontos, } and event_counter ecThureosReform 1
    recruit_pool "hellenistic infantry thureophoroi"  0  -0.04  0  0  requires factions { cul_1, cul_3, f_pontos, } and event_counter ecThureosReform 1
    recruit_pool "hellenistic infantry euzonoi"  0  -0.04  0  0  requires factions { cul_1, cul_3, f_pontos, } and event_counter ecThureosReform 1

    First, this won't crash the game. Second, the game calculates the unit refresh rate by summing up all modifiers, including negative ones, and then (in order to avoid bugs?) apparently setting it to zero if the sum is less than zero. Yes, you can have the following


    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  -0.99  0  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1

    where the refresh rate is always less than zero, and the game still runs fine. When you hover your mouse over the unit card in the recruitment bar, the "Time until next unit" dialogue simply isn't there.


    As of writing this, I still haven't tested what happens when you set the unit's max to a negative number like this


    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  0  -1  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1

    but I'm 70% sure the game still runs fine and it will also work just as you'd expect.

    This should create interesting gameplay situations, like buildings that drastically increase law but decreases recruitment for certain units (since they're too busy arresting everyone)

  2. #2

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    Further testing reveals that negative unit caps work.

    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  0  -1  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1
    will reduce the cap by 1, and

    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  0  -99  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1
    will completely wipe the unit from the recruitment bar.

    In addition, the internal decimal value representing how many units are available CANNOT go below 0. This means that if you just finished a building that provides this

    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  -1  0  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1
    and wait 3 turns before demolishing it, the internal value will still be 0, NOT -3. This means you don't have to worry about negative refresh rates plunging recruitment so far down that even after destroying that building, you would be burdened with "Turns until next unit" in the hundreds. Basically, combine both negative refresh rate and unit cap to inconsequentially prevent the player from recruiting that unit from another building.

    There is one caveat though that might frustrate the bug-abusing player. In M2TW, a player can recruit a unit, wait for the replenishment to max out that unit, then disband that unit to bump the units available over the cap by next turn. As a result, the player could, in times of peace, amass huge reserves of units. If a building like

    Code:
    recruit_pool "hellenistic infantry hoplitai"  0  -1  -99  0  requires factions { cul_1, cul_3, f_pontos, } and not event_counter ecThureosReform 1
    is built, then that unit will be completely wiped out. Then again, it's that player's fault for abusing M2TW quirks.

  3. #3

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    Based on these findings and a few known M2TW quirks, we can make inferences on how M2TW handles unit recruitment internally.


    First, let's revisit some quirks. M2TW has a hard EDU cap of around 500(?) units. That seems weirdly arbitrary and unrelated, but in fact that implies that M2TW stores all unit definitions in a fixed-sized array. To illustrate, I'll type out a visual representation of this unit array if the EDU cap were 5 units.


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]


    Let's say n = 5, where n is the EDU cap. I hypothesize that, on the campaign map, M2TW stores multiple arrays of length n for each settlement. These arrays are:


    - unit_amount (a decimal representing how many of a unit is available to recruit)
    - unit_refresh (a decimal representing how much to add to unit_amount each turn)
    - unit_max (the max integer value of unit_amount before unit_refresh no longer adds to it)


    The following UI texts read from these arrays


    - "Units available to recruit" (round_down(unit_amount))
    - "Turns until next unit" (unit_amount > unit_max) ? NONE : ((unit_amount - round_down(unit_amount)) / unit_refresh)
    - "Unit shows up in the recruitment bar" (unit_max > 0)

    So to recap, each settlement stores data for a recruitable unit type in multiple arrays of length n, and updates the data in response to turn ending, clicking on a unit, or script actions. How does all of this work in practice? Say, for the EDU of n = 5 we described above


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]


    we have an existing building "Example Military Colony" in settlement "Example Town" that offers the following


    Code:
    recruit_pool "hoplitai" 1 0.04 1 0
    recruit_pool "hemithorakitai" 1 0.04 1 0

    at the start of the campaign. Inside the settlement's data, the following arrays are initialized


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,0,0,0,1] // unit_amount
    [0.04,0,0,0,0.04] // unit_refresh
    [1,0,0,0,1] // unit_max


    The player recruits a hoplitai


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [0,0,0,0,1] // unit_amount
    [0.04,0,0,0,0.04] // unit_refresh
    [1,0,0,0,1] // unit_max


    And clicks end turn. On the start of next turn, the data looks like


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [0.04,0,0,0,1] // unit_amount
    [0.04,0,0,0,0.04] // unit_refresh
    [1,0,0,0,1] // unit_max


    When the player hovers their mouse over hoplitai, it will say "Time until next unit: 25". The hemithorakitai's unit_amount won't change since it's already at unit_max. Fast forward 25 turns and "Example Town"'s data will look like


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,0,0,0,1] // unit_amount
    [0.04,0,0,0,0.04] // unit_refresh
    [1,0,0,0,1] // unit_max


    But wait! On this turn, another building called "We just lowered the draft age" was built. That building offers


    Code:
    recruit_pool "hoplitai" 1 0.04 0 0
    recruit_pool "thureophoroi" 1 0.04 0 0 and not event_counter ecBecauseISaidSo 1
    recruit_pool "thorakitai" 1 0.04 0 0 and not event_counter ecBecauseISaidSo 1
    recruit_pool "euzonoi" 1 0.04 0 0 and not event_counter ecBecauseISaidSo 1
    recruit_pool "hemithorakitai" 1 0.04 0 0

    It doesn't immediately increase unit_amount for any unit, so the settlement, having built "Example Military Colony" and "We just lowered the draft age", has this data


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,0,0,0,1] // unit_amount
    [0.08,0.04,0.04,0.04,0.08] // unit_refresh
    [2,1,1,1,2] // unit_max


    But wait! The player decides to smash "Example Military Colony". Now let's see what "Example Town"'s data looks like


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,0,0,0,1] // unit_amount
    [0.04,0.04,0.04,0.04,0.04] // unit_refresh
    [1,1,1,1,1] // unit_max


    Yes, hoplitai and hemithorakitai still show up in the recruitment bar, and still have 1 unit each to recruit. Let's wait 25 turns.


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,1,1,1,1] // unit_amount
    [0.04,0.04,0.04,0.04,0.04] // unit_refresh
    [1,1,1,1,1] // unit_max


    Lot's of units to recruit. But wait! The "I Said So Reforms" have occurred this turn, which sets ecBecauseISaidSo to 1. That means thureophoroi, thorakitai, and euzonoi are no longer available have their unit_refresh and unit_max contributing to the max! What happens to the data?


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,1,1,1,1] // unit_amount
    [0.04,0,0,0,0.04] // unit_refresh
    [1,0,0,0,1] // unit_max


    Since for thureophoroi, thorakitai, and euzonoi, their unit_maxs are zero, they won't show up in the recruitment screen at all. Pity. However, the very next turn, the player triggers the "Don't Listen To Anything I Say Reforms" which sets ecBecauseISaidSo back to 0. Let's see the data


    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [1,1,1,1,1] // unit_amount
    [0.04,0.04,0.04,0.04,0.04] // unit_refresh
    [1,1,1,1,1] // unit_max


    And suddenly, thureophoroi, thorakitai, and euzonoi are instantly available again at 1 unit each, instead of having to wait 25 turns for them to reappear!


    So what's the point of this long-winded example? Well, unit_amount is its whole separate thing from unit_refresh and unit_max, which are determined by the sum of all buildings' recruitment. Outside of the turn ending, changes to unit_refresh and unit_max won't affect unit_amount, which keeps track of how much of a unit that settlement currently has. This leads to many strange situations.


    Here's one: recall the M2TW quirk where disbanding a unit will increase the number of units that region offers by 1. However, this can also lead to the case where "Example Town" only has the "Example Military Colony" (provides only hoplitai and hemithorakitai), the player disbands a thorakitai in "Example Town", checks the recruitment bar, and doesn't see any thorakitai. Makes sense, since "We just lowered the draft age" hasn't been built yet.


    However, once the player builds "We just lowered the draft age", they will be surprised to see not one, but TWO units of thorakitai available! What happened?


    1. thorakitai's unit_amount is 0, and cannot increase since its unit_refresh and unit_max are both 0
    2. The player disbands a thorakitai. Now its unit_amount is 1. Still can't see it in the recruitment viewer since its unit_refresh and unit_max are both 0
    3. "We just lowered the draft age" is built, and its EDB entry instantly offers 1 unit (I know it's actually 0 units, but let's change it for this example). Now its unit_amount is 2.
    4. Since "We just lowered the draft age" is built, unit_max is now 1, and thorakitai is available. Since its unit_amount is 2, well, 2 are available to recruit.


    Many weird cases suddenly make sense when you start thinking in terms of unit_amount, unit_refresh, and unit_max. This brings us to the topic of this thread: negative unit_refresh and negative unit_max.


    Say "Example Town" has "We just lowered the draft age by like a ton" and I did not tell you so.


    Code:
    recruit_pool "hoplitai" 1 0.2 5 0
    recruit_pool "thureophoroi" 1 0.2 5 0 
    recruit_pool "thorakitai" 1 0.2 5 0 
    recruit_pool "euzonoi" 1 0.2 5 0 
    recruit_pool "hemithorakitai" 1 0.2 5 0

    [0,1,2,3,4]
    [hoplitai,thureophoroi,thorakitai,euzonoi,hemithorakitai]
    [0,0,0,0,0] // unit_amount
    [0.04,0.04,0.04,0.04,0.04] // unit_refresh
    [1,1,1,1,1] // unit_max


    Say "Example Town" also just finished building "Police State"


    Code:
    recruit_pool "hoplitai" 0 -0.04 0 0
    recruit_pool "thureophoroi" 0 0 -1 0

    So, hoplitai lose 0.04 unit_amount each turn, and thureophoroi has 1 less unit_max. Now it takes 7 turns for a unit of hoplites to become available instead of 5, and while you still get 1 thureophoroi every 5 turns, you can only have up to 4 now.


    Remember, unit_refresh and unit_max are calculated from the sum of all building's recruitment for certain units, and if the sum is less than zero, it gets bumped back to zero. You can do some interesting things by using this feature/bug. Happy modding!

  4. #4
    bitterhowl's Avatar Campidoctor
    Join Date
    Feb 2011
    Location
    Russian Feodality
    Posts
    1,695

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    Very interesting! Thanks for research!

    My sister, do you still recall the blue Hasan and Khalkhin-Gol?
    Russian warship is winning. Proofs needed? Go find yourself!

  5. #5

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    WARNING PLEASE READ

    My game has crashed twice on the campaign map in the past 2 hours of gameplay ever since modding my Europa Barbarorum II installation to use negative unit refresh and cap. First time was triggered by a mouse click (don't remember the exact details) and second time was clicking on the Settlement Details of a settlement that was constructing a building that provides negative recruitment. If you want to play around with negative recruitment, or even incorporate it into your mod, BE SURE TO PLAYTEST. It's still possible that those two CTDs were just random, but if they persist in their frequency, then unfortunately negative recruitment is an unstable, if still functional, feature.


  6. #6

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    There is a hard limit of 32 unit TYPES that a building can recruit in one settlement. Violating this will causing the game to crash if you try to view the settlement details WHILE THE BUILDING IS UNDER PROGRESS.
    - Once the building completes, you regain the ability to view the settlement details
    - Negative recruitment per unit type counts towards this limit! That was what was causing the CTD mentioned above

    Here's an example of building data that violates the 32 unit type per settlement limit

    Code:
    ;;; MILITARY EXEMPTIONS FOR PROFRESSIONAL HELLENES
    				recruit_pool "hellenistic infantry hoplitai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry hemithorakitai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry thureophoroi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry machairophoroi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry euzonoi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry deuteroi phalangitai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry phalangitai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry thorakitai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry hyperaspistai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry peltastai logades" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry promachoi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry hoplitai spartiatai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry hoplitai lakonikoi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic missile cretan archers" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry cretan" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry hippakontistai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry thureopherontes hippeis" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry hippeis" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry lonchophoroi hippeis" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry xystophoroi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry aspidiotai hippeis" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry lydian lancers" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry baktrioi hippeis" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry baktrioi hippotoxotai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry bosporan logades" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic infantry thureopherontes toxotai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry thureopherontes hippotoxotai" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry tarantinoi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				recruit_pool "hellenistic cavalry thessalikoi" 0 -1 -10 0 requires factions { f_pergamon, } 
    				;; Karians, Thracians, and Galatians are not exempt. Get :wub:ed.
    				
    				;;; MERCENARY IMPORTS
    				;;; ATHENS
    				recruit_pool "steppe infantry scythian archers" 1 0.09 3 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j 
    				recruit_pool "thracian cavalry prodromoi" 1 0.03 1 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j 
    				recruit_pool "thracian infantry peltastai" 1 0.06 2 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j 
    				recruit_pool "iberian infantry caetratii" 1 0.03 1 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j 
    				recruit_pool "iberian infantry caetratii spearmen" 1 0.06 2 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j 
    				recruit_pool "iberian infantry scutarii swordsman" 1 0.03 1 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j and event_counter ecThureosReform 1
    				recruit_pool "iberian infantry scutarii spearman" 1 0.03 1 0 requires factions { f_pergamon, } and hidden_resource hr_a and hidden_resource hr_g and hidden_resource hr_h and hidden_resource hr_j  and event_counter ecThureosReform 1
    This offers 29 unit types of negative recruitment across all settlements (by itself this is valid), and 5 units of positive recruitment in Athens only (since ecThureosReform was 0 in my campaign ATM). That makes 34 in total for one settlement in this building, and the game crashes if the Settlement Details is viewed while this building is in progress.

    Now, this only applies for a single building. Multiple buildings can together offer much more than 32 unit types, which makes sense since in vanilla M2TW, where (I'm guessing?) every unit can be recruited everywhere give the right infrastructure, each settlement can technically support every unit type. However, within a single building, only less than 32 unit types are probably offered.

    Someone with proper access should update https://wiki.twcenter.net/index.php?..._buildings.txt to include a 32 unit TYPE per settlement limit.

    Basically, there's nothing wrong with negative recruitment that causes CTDs. It's the hard limit of a settlement that causes this issue. Unfortunately, this means you can't have, for example, a "Garrison Duty" building that offers negative recruitment for every single heavy infantry unit in the game (probably exceeds 32). You could however spread the negative recruitment across different upgrade paths, one for each "culture".

  7. #7

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    The unit types for a single settlement is cumulative across all its buildings. So if building X offers 16 unit types for region A and 10 for region B, and building Y offers 16 unit types for region A and 30 for region B, that won't be good. While building Y, or possibly any building, is in progress, viewing the settlement details of region B will cause the game to crash

  8. #8
    bitterhowl's Avatar Campidoctor
    Join Date
    Feb 2011
    Location
    Russian Feodality
    Posts
    1,695

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    And what about "clear_pool_with_caps true" in descr_campaign_db?

    My sister, do you still recall the blue Hasan and Khalkhin-Gol?
    Russian warship is winning. Proofs needed? Go find yourself!

  9. #9

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    Quote Originally Posted by bitterhowl View Post
    And what about "clear_pool_with_caps true" in descr_campaign_db?
    I don't know what it does, but I did find it in

    Code:
    <recruitment>
          <recruitment_slots uint="1"/>
          <retraining_slots uint="0.9"/>
          <deplenish_pools_with_caps bool="false"/>
          <clear_pools_with_caps bool="false"/>
          <add_initial_with_caps bool="true"/>
          <add_disband_no_caps bool="true"/>
          <force_clamp_to_max bool="false"/>
          <deplenish_multiplier float="0.9"/>
          <deplenish_offset float="-0.2"/>
          <percentage_pool_reduction_lost uint="25"/>
          <percentage_pool_reduction_occupy uint="25"/>
          <percentage_pool_reduction_sack uint="75"/>
          <percentage_pool_reduction_exterminate uint="100"/>
          <max_agents_per_turn uint="1"/>
       </recruitment>
    Those are the settings for Europa Barbarorum II. I'm assuming that "clear_pool_with_caps true" means that unit_amount is set to zero if unit_max ever becomes zero. In EBII, "clear_pool_with_caps" is set to false, where unit_amount stays the same even if unit_max becomes zero, hence the behavior that led to my theories.

  10. #10
    bitterhowl's Avatar Campidoctor
    Join Date
    Feb 2011
    Location
    Russian Feodality
    Posts
    1,695

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    This setting set to true clears all unit_pools in settlement after capturing for new faction ones. If I understood right it removes unused pools from previous owner. I saw this explanation somewhere around TWC. Also it was told that one settlement could contain 64 pools at once. More pools cause CTD.

    My sister, do you still recall the blue Hasan and Khalkhin-Gol?
    Russian warship is winning. Proofs needed? Go find yourself!

  11. #11

    Default Re: Apparently negative unit refresh rate is possible, and works as you'd expect it

    Quote Originally Posted by bitterhowl View Post
    And what about "clear_pool_with_caps true" in descr_campaign_db?
    I thought that too but i finally read through all the recruitment pool code from the game. Its definitly the amount of lines with recruitmentpool per building in the EDB that is limited

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •