Page 1 of 1

Repairing Units drains ManPower

Posted: Thu Aug 07, 2014 9:27 pm
by Historion
Everybody playing through a complete campaign probably has noticed the massive drain to ManPower (MP) reserves as the game advances. Building new units costs MP but it costs a lot more MP to keep units in the field by repairing them.

The function to calculate RepairCosts is located in file "game_repair.lua".

Code: Select all

gameplay.repairDiscountFactor = 0.7

function GetRepairCost(unit)

  local pointsRepaired= GetRepairPoints(unit)

  local PPcost = math.ceil(unit.prototype.costPP * (pointsRepaired) / 100 * gameplay.repairDiscountFactor)
  local MPcost = math.ceil(unit.prototype.costMP * (pointsRepaired) / 100)

  -- Repairing half supply doubles cost
  if unit.supply == 1 then
    PPcost = PPcost * 2
    MPcost = MPcost * 2
  end

  return PPcost, MPcost
end
(Note :
The game internally uses 100 hitpoints (hp) instead of the displayed 10 strength points for unit health. Repairing is done in steps of +10 hp / +20 hp respectively +1 / +2 Strength Points. GetRepairPoints(unit) returns hitpoints in range of 0..20.)

The problem is that MP costs for new units are rather small values between 1 MP and 12 MP so that effectively dividing by 10 (or more) and rounding up (ceil) has a very strong effect.

Code: Select all

Repairing from Strength 9 to 10 :

MP-cost of unit :                 unit                        : MP / 10 : Repair-Cost : Ratio (Repair-Cost / (MP/10))
----------------------------------------------------------------------------------------------------------------------------
01              : Armoured Car, Submarine                     : 0.1     : 1 MP        : 10
02              : Railroad Gun, Fighter, Airship, Cruiser     : 0.2     : 1 MP        :  5
03              : Armoured Train, Bomber                      : 0.3     : 1 MP        :  3.33
04              : Battleship                                  : 0.4     : 1 MP        :  2.5
05              : Artillery                                   : 0.5     : 1 MP        :  2
06              : Garrison, Cavalry                           : 0.6     : 1 MP        :  1.67
10              : Armour (Tank)                               : 1.0     : 1 MP        :  1
12              : Infantry                                    : 1.2     : 2 MP        :  1.67
Repairing an Armoured Car / Submarine by 1 Strength Point costs 1 MP, which is the same MP cost as for a complete new unit with 10 Strength Points. Repair costs (MP) for these units are 10 times higher than expected.

If you repair at half supply, the Repair-costs (after rounding up) are even doubled, so that repairing an Armoured Car by 1 Strength Point costs 2 MP while you get a new one for 1 MP.

If the high MP repair costs are not intended as a challenge / handicap (to increase game difficulty), an easy solution would be simply to scale MP unit costs and faction MP, MPmax by 10 or to skip the rounding and use MP as float rather than integer. (The displayed MP reserve should then be rounded to integer.)

Re: Repairing Units drains ManPower

Posted: Wed Aug 13, 2014 12:38 pm
by PrinceMiskin
Hi historion,

Accidentally I have made a similar post on steam, but from a different point of view, which I attach. You can also use this to your advantage to gain manpower. Honestly, manpower needs to start working with digits; integer makes no sense.

"When dismantling units in home territory, or home port you gain back a significant manpower and half of the production points. Theoretically one could build a unit, only to disband it and build a new one to increase manpower (MP).

One could argue that it may sound odd, or not designed properly, or can be seen as an exploit. Anyway, since it's in the game mechanics, let's try to see how it works.

The following table shows the efficiency of disbanding in terms of MP/PP and MP/PP/turn.

Code: Select all

			                         Build Cost      Scrap Gain        Net          Efficiency	
		           Build Time |   PP   MP   |   PP   MP   |   PP   MP   |   MP/PP   MP/PP/turn
------------------------------------------------------------------------------------
Garrison              2	10	6	5	10	-5	4	0.80	0.40
Infantry              4	20	12	10	20	-10	8	0.80	0.20
Cavarly               5	20	6	10	20	-10	14	1.40	0.28
Artillery             7	50	5	25	50	-25	45	1.80	0.26
Armoured Car          3	8	1	4	8	-4	7	1.75	0.58
Armoured Train        7	35	3	8	17	-27	14	0.52	0.07
Armor                 9	60	10	30	60	-30	50	1.67	0.19
Fighter               7	30	2	15	30	-15	28	1.87	0.27
Airship               4	30	2	15	30	-15	28	1.87	0.47
Bomber                8	50	3	25	50	-25	47	1.88	0.24
Submarine             4	22	1	11	22	-11	21	1.91	0.48
Cruiser		         12 50	2	25	50	-25	48	1.92	0.16
Battleship*		     26 124	4	62	124	-62	120	1.94	0.07
*= Dismantling also comes with significant loss of National Morale (NM).

The matrix shows that the most efficient unit to gain manpower is the cruiser -in fact it is the battleship, but it also comes with a signifcant drop in NM, hence it's not an option.

The most efficient unit to dismantle in terms of production points and production time is the armored car, since you gain 0.58 per PP per turn of build time.

Overall one of the most cost effective units to disband is the submarine, which combines both MP/MPP and MP/MPP/turn efficiency.

I hope this guide helps you handle shortages in MP better."

Re: Repairing Units drains ManPower

Posted: Wed Aug 13, 2014 1:48 pm
by Historion
Gaining additional ManPower from building and disbanding units is exploiting a well known bug which should have been fixed for a long time ...

It looks like a simple copy and paste bug where the developer just forgot to change the unit.prototype.costPP to unit.prototype.costMP in those 3 lines where MPrefund is calculated, e.g. :

Code: Select all

 MPrefund = math.floor(unit.prototype.costPP * unit.hp * 100 / 10000)
It takes only a moment to fix it ... and I expect/hope it to be fixed with the new patch ...

see game_deployment.lua

code with bug :

Code: Select all

function GetDisbandRefund(unit)
  local PPrefund
  local MPrefund
  if unit.type  ~= Unit.NAVAL then
    if unit.hex.originalFaction.alliance.id == unit.faction.alliance.id then
      if unit.hex.originalFaction.id == unit.faction.id then
        PPrefund = math.floor(unit.prototype.costPP * unit.hp * 50 / 10000)
      else
        PPrefund = math.floor(unit.prototype.costPP * unit.hp * 25 / 10000)
      end
    else
      PPrefund = 0
    end
    if unit.hex.originalFaction.alliance.id == unit.faction.alliance.id then
      if unit.hex.originalFaction.id == unit.faction.id then
        MPrefund = math.floor(unit.prototype.costPP * unit.hp * 100 / 10000)
      else
        MPrefund = math.floor(unit.prototype.costPP * unit.hp * 50 / 10000)
      end
    else
      MPrefund = 0
    end
  else
    PPrefund = math.floor(unit.prototype.costPP * unit.hp * 50 / 10000)
    MPrefund = math.floor(unit.prototype.costPP * unit.hp * 100 / 10000)
  end
  return PPrefund, MPrefund
end
fixed code :

Code: Select all

function GetDisbandRefund(unit)
  local PPrefund
  local MPrefund
  if unit.type  ~= Unit.NAVAL then
    if unit.hex.originalFaction.alliance.id == unit.faction.alliance.id then
      if unit.hex.originalFaction.id == unit.faction.id then
        PPrefund = math.floor(unit.prototype.costPP * unit.hp * 50 / 10000)
      else
        PPrefund = math.floor(unit.prototype.costPP * unit.hp * 25 / 10000)
      end
    else
      PPrefund = 0
    end
    if unit.hex.originalFaction.alliance.id == unit.faction.alliance.id then
      if unit.hex.originalFaction.id == unit.faction.id then
        MPrefund = math.floor(unit.prototype.costMP * unit.hp * 100 / 10000)
      else
        MPrefund = math.floor(unit.prototype.costMP * unit.hp * 50 / 10000)
      end
    else
      MPrefund = 0
    end
  else
    PPrefund = math.floor(unit.prototype.costPP * unit.hp * 50 / 10000)
    MPrefund = math.floor(unit.prototype.costMP * unit.hp * 100 / 10000)
  end
  return PPrefund, MPrefund
end

Re: Repairing Units drains ManPower

Posted: Wed Aug 13, 2014 2:06 pm
by PrinceMiskin
Did you read my mind?

I have also changed:

Code: Select all

 MPrefund = math.floor(unit.prototype.costPP * unit.hp * 100 / 10000)
to:

Code: Select all

 MPrefund = math.floor(unit.prototype.costMP * unit.hp * 100 / 10000)
I have also rescaled all MP costs, and now works like a charm!

Re: Repairing Units drains ManPower

Posted: Wed Aug 13, 2014 3:06 pm
by PrinceMiskin
If we rescale MP by a factor of 10, we should also update the "convoy.lua" file, so allied MP from convoys gets count correctly.

Code: Select all

  -- Manage existing convoys
  gameplay.convoys = {}
  for faction in alliance.factions do
    for unit in faction.units do
      if unit.alive and unit.prototype.name == "convoy" then
        -- If convoy is in national port
        local arrived = false
        local hexes = game.map:GetHexesInRange(unit.hex, 1)
        for _, hex in pairs(hexes) do
          if hex.construction ~= nil and hex.construction.isPort and hex.construction.city.hex.faction.id == faction.id and hex.construction.city.hex.originalFaction.id == faction.id and hex.y < 45 then
            arrived = true
            if alliance.id == playerAlliance.id then
              --PopupInfoDialog("convoy_finished", unit.hex.x, unit.hex.y)
              ui.resourcesPanel:Refresh()
            end
            faction:ConsumeProductionPoints(-unit.hp)
            faction:ConsumeManpower(-unit.hp / 10)
            unit:Kill()
            break
          end
        end
        if not arrived then
          -- Move convoy automatically
          -- For player only! AI should do the same in AI scripts
          if alliance.id == playerAlliance.id then
            table.insert(gameplay.convoys, unit)
          end
        end
      end
    end
  end
Specifically the line:

Code: Select all

faction:ConsumeManpower(-unit.hp / 10)
should be updated to:

Code: Select all

faction:ConsumeManpower(-unit.hp)

Re: Repairing Units drains ManPower

Posted: Thu Aug 14, 2014 2:30 pm
by lordzimoa
Thanks guys, this is already fixed and will be in the upcoming Beta patch 1.6 that is coming soon.

Cheers,

Tim

Re: Repairing Units drains ManPower

Posted: Sat Aug 16, 2014 5:16 am
by PrinceMiskin
Cheers

Code: Select all

function GetMPOutput(faction)
  local minimum = 50
  return minimum + math.min(minimum, math.ceil(faction.mp * minimum / data.factions[faction.id+1].manpowerMax))
end
Could someone explain to me what is the meaning of: [faction.id+1]

I am having some issues understanding if the "+1" is intended or not.

Re: Repairing Units drains ManPower

Posted: Sat Aug 16, 2014 5:38 pm
by Historion
I'm not a LUA-expert but it seems that in LUA the index of a table / array starts with '1' (while in C and most other languages it starts with '0').

data.factions is a table/array defined in "factions.lua". Each faction has an attribute "id" and these ids start with value '0', e.g.
France is the 1st faction (data.factions[1]) and has id = 0.

Code: Select all

data.factions =
{
  {
    name= "france",
    id = 0,
    manpowerMax = 1100,
    morale = 110,
    territory = 2,
    research = { ground = 1, artillery = 1, naval = 1, air = 1, armour = 1 },
    color = {34, 92, 136},
  },
...
So the table-index of a faction is "faction.id + 1" .

Re: Repairing Units drains ManPower

Posted: Sun Aug 17, 2014 1:47 am
by PrinceMiskin
This is great! Thanks!

You know, I have rescaled everything to x10 MP to avoid rounding issues. The problem now is the quality drop, when we MP falls below 90%, does not occur.

And yes, I have edited both manpowerMax in factions.lua and mp in 1914.lua.

I am struggling to see what could have gone wrong...