The update simply updates each nation's nat_money as it goes. Works.
Except it doesn't update when it runs on behalf of budget. But it
still checks nat_money to determine whether the nation is solvent.
These checks are all broken. Leads to massive mispredictions when
you'd go broke or solvent during a real update.
Track money unconditionally in nat_budget[].money. Delay update of
nat_money until prod_nat(). Replace separate money[] by new
nat_budget[].start_money. Closes bug#235.
Remaining difference between budget and update in the update test:
* #1: budget mispredicts plane #100 gets built (to be fixed)
* #2: budget shows ship, plane and land unit maintenance when broke,
but update damages them instead (correct)
* #2: sector -14,0 converts, quadrupling its taxes (correct)
* #4 & #5: bank with dust and bars taken over by che (correct)
* #4: plague deaths (correct)
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
struct budg_item bm[BUDG_BLD_MAX + 1];
/* population, taxes, military payroll, bank interest */
struct budg_item civ, mil, uw, bars;
+ /* treasury */
+ int start_money; /* at beginning of update */
+ int money; /* current */
};
/* main.c */
extern struct budget nat_budget[MAXNOC];
-extern int money[MAXNOC];
extern int pops[MAXNOC];
extern int tpops[MAXNOC];
/* nat.c */
int etu = etu_per_update;
memset(nat_budget, 0, sizeof(nat_budget));
-
np = getnatp(player->cnum);
+ budget->start_money = budget->money = np->nat_money;
bp = bp_alloc();
+
for (n = 0; NULL != (sp = getsectid(n)); n++) {
bp_set_from_sect(bp, sp);
if (sp->sct_own == player->cnum) {
prod_plane(etu, player->cnum, bp, 1);
prod_land(etu, player->cnum, bp, 1);
+ if (CANT_HAPPEN(np->nat_money != budget->start_money))
+ np->nat_money = budget->start_money;
+
free(bp);
return budget;
}
* Dave Pare, 1986
* Thomas Ruschak, 1993
* Steve McClure, 1998
- * Markus Armbruster, 2004-2011
+ * Markus Armbruster, 2004-2016
*/
#include <config.h>
{
static double *import_cost;
struct sctstr *sp;
- struct natstr *np;
int n;
struct rusage rus1, rus2;
continue;
if (sp->sct_own == 0)
continue;
- np = getnatp(sp->sct_own);
- if (np->nat_money < 0)
+ if (nat_budget[sp->sct_own].money < 0)
continue;
dodeliver(sp);
}
for (n = 0; NULL != (sp = getsectid(n)); n++) {
if (!sp->sct_own)
continue;
- np = getnatp(sp->sct_own);
- if (np->nat_money < 0)
+ if (nat_budget[sp->sct_own].money < 0)
continue;
dodistribute(sp, EXPORT, import_cost[n]);
}
sp->sct_off = 0;
if (!sp->sct_own)
continue;
- np = getnatp(sp->sct_own);
- if (np->nat_money < 0)
+ if (nat_budget[sp->sct_own].money < 0)
continue;
dodistribute(sp, IMPORT, import_cost[n]);
}
#include "prototypes.h"
#include "update.h"
-static void upd_land(struct lndstr *, int, struct natstr *, struct bp *, int);
+static void upd_land(struct lndstr *, int, struct bp *, int);
static void landrepair(struct lndstr *, struct natstr *, struct bp *,
int, struct budget *);
static int feed_land(struct lndstr *, int);
{
struct lndstr *lp;
struct sctstr *sp;
- struct natstr *np;
int i;
- int start_money;
for (i = 0; (lp = getlandp(i)); i++) {
if (lp->lnd_own == 0)
sp = getsectp(lp->lnd_x, lp->lnd_y);
if (sp->sct_type == SCT_SANCT)
continue;
- np = getnatp(lp->lnd_own);
- start_money = np->nat_money;
- upd_land(lp, etus, np, bp, build);
- if (player->simulation)
- np->nat_money = start_money;
+ upd_land(lp, etus, bp, build);
}
}
static void
-upd_land(struct lndstr *lp, int etus,
- struct natstr *np, struct bp *bp, int build)
+upd_land(struct lndstr *lp, int etus, struct bp *bp, int build)
/* build = 1, maintain = 0 */
{
struct budget *budget = &nat_budget[lp->lnd_own];
- struct lchrstr *lcp;
+ struct lchrstr *lcp = &lchr[lp->lnd_type];
+ struct natstr *np = getnatp(lp->lnd_own);
int pstage, ptime;
int min = morale_base - (int)np->nat_level[NAT_HLEV];
int n, mult, cost, eff_lost;
if (lp->lnd_retreat < min)
lp->lnd_retreat = min;
- lcp = &lchr[(int)lp->lnd_type];
if (build == 1) {
- if (!lp->lnd_off && np->nat_money >= 0)
+ if (!lp->lnd_off && budget->money >= 0)
landrepair(lp, np, bp, etus, budget);
if (!player->simulation)
lp->lnd_off = 0;
mult *= 3;
budget->bm[BUDG_LND_MAINT].count++;
cost = -(mult * etus * MIN(0.0, money_land * lcp->l_cost));
- if (np->nat_money < cost && !player->simulation) {
+ if (budget->money < cost && !player->simulation) {
eff_lost = etus / 5;
if (lp->lnd_effic - eff_lost < LAND_MINEFF)
eff_lost = lp->lnd_effic - LAND_MINEFF;
}
} else {
budget->bm[BUDG_LND_MAINT].money -= cost;
- np->nat_money -= cost;
+ budget->money -= cost;
}
if (!player->simulation) {
cost = roundavg(mult * lp->l_cost * build / 100.0);
budget->bm[BUDG_LND_BUILD].count += !!build;
budget->bm[BUDG_LND_BUILD].money -= cost;
- np->nat_money -= cost;
+ budget->money -= cost;
if (!player->simulation)
land->lnd_effic += (signed char)build;
}
#include "update.h"
struct budget nat_budget[MAXNOC];
-int money[MAXNOC];
int pops[MAXNOC];
int tpops[MAXNOC];
memset(nat_budget, 0, sizeof(nat_budget));
memset(pops, 0, sizeof(pops));
for (n = 0; n < MAXNOC; n++) {
- money[n] = 0;
if (!(np = getnatp(n)))
continue;
- money[n] = np->nat_money;
+ nat_budget[n].start_money = nat_budget[n].money = np->nat_money;
tpops[n] = count_pop(n);
}
np->nat_level[NAT_RLEV] += rlev;
if (tlev != 0.0)
np->nat_level[NAT_TLEV] += tlev;
+
bm = nat_budget[n].bm;
sea_money = bm[BUDG_SHP_MAINT].money + bm[BUDG_SHP_BUILD].money;
air_money = bm[BUDG_PLN_MAINT].money + bm[BUDG_PLN_BUILD].money;
wu(0, n,
"Army delta $%d, Navy delta $%d, Air force delta $%d\n",
lnd_money, sea_money, air_money);
+ if (CANT_HAPPEN(np->nat_money != nat_budget[n].start_money))
+ nat_budget[n].money += np->nat_money - nat_budget[n].start_money;
wu(0, n, "money delta was $%d for this update\n",
- np->nat_money - money[n]);
+ nat_budget[n].money - nat_budget[n].start_money);
+ np->nat_money = nat_budget[n].money;
+
if (opt_LOSE_CONTACT) {
for (cn = 1; cn < MAXNOC; cn++) {
if ((cnp = getnatp(cn)) != NULL)
#include "ship.h"
#include "update.h"
-static void upd_plane(struct plnstr *, int, struct natstr *, struct bp *, int);
+static void upd_plane(struct plnstr *, int, struct bp *, int);
static void planerepair(struct plnstr *, struct natstr *, struct bp *,
int, struct budget *);
/* Build = 1, maintain =0 */
{
struct plnstr *pp;
- struct natstr *np;
int i;
- int start_money;
for (i = 0; (pp = getplanep(i)); i++) {
if (pp->pln_own == 0)
continue;
}
- np = getnatp(pp->pln_own);
- start_money = np->nat_money;
- upd_plane(pp, etus, np, bp, buildem);
- if (player->simulation)
- np->nat_money = start_money;
+ upd_plane(pp, etus, bp, buildem);
}
}
static void
-upd_plane(struct plnstr *pp, int etus,
- struct natstr *np, struct bp *bp, int build)
+upd_plane(struct plnstr *pp, int etus, struct bp *bp, int build)
{
struct budget *budget = &nat_budget[pp->pln_own];
- struct plchrstr *pcp = &plchr[(int)pp->pln_type];
+ struct plchrstr *pcp = &plchr[pp->pln_type];
+ struct natstr *np = getnatp(pp->pln_own);
int mult, cost, eff_lost;
if (build == 1) {
- if (!pp->pln_off && np->nat_money >= 0)
+ if (!pp->pln_off && budget->money >= 0)
planerepair(pp, np, bp, etus, budget);
if (!player->simulation)
pp->pln_off = 0;
mult = 2;
budget->bm[BUDG_PLN_MAINT].count++;
cost = -(mult * etus * MIN(0.0, pcp->pl_cost * money_plane));
- if (np->nat_money < cost && !player->simulation) {
+ if (budget->money < cost && !player->simulation) {
eff_lost = etus / 5;
if (pp->pln_effic - eff_lost < PLANE_MINEFF)
eff_lost = pp->pln_effic - PLANE_MINEFF;
}
} else {
budget->bm[BUDG_PLN_MAINT].money -= cost;
- np->nat_money -= cost;
+ budget->money -= cost;
}
/* flight pay is 5x the pay received by other military */
cost = etus * pcp->pl_mat[I_MILIT] * -money_mil * 5;
budget->bm[BUDG_PLN_MAINT].money -= cost;
- np->nat_money -= cost;
+ budget->money -= cost;
}
}
cost = roundavg(mult * build * pcp->pl_cost / 100.0);
budget->bm[BUDG_PLN_BUILD].count += !!build;
budget->bm[BUDG_PLN_BUILD].money -= cost;
- np->nat_money -= cost;
- if (!player->simulation) {
+ budget->money -= cost;
+ if (!player->simulation)
pp->pln_effic += (signed char)build;
- }
}
for (n = 0; NULL != (np = getnatp(n)); n++) {
upd_slmilcosts(etu, np->nat_cnum);
pay_reserve(np, etu);
- np->nat_money += nat_budget[n].mil.money;
- np->nat_money += nat_budget[n].civ.money;
- np->nat_money += nat_budget[n].uw.money;
- np->nat_money += nat_budget[n].bars.money;
}
}
civ_tax /= 4;
budget->civ.count += sp->sct_item[I_CIVIL];
budget->civ.money += civ_tax;
+ budget->money += civ_tax;
uw_tax = (int)(0.5 + sp->sct_item[I_UW] * sp->sct_effic *
etu * money_uw / 100);
budget->uw.count += sp->sct_item[I_UW];
budget->uw.money += uw_tax;
+ budget->money += uw_tax;
mil_pay = sp->sct_item[I_MILIT] * etu * money_mil;
budget->mil.count += sp->sct_item[I_MILIT];
budget->mil.money += mil_pay;
+ budget->money += mil_pay;
/*
* only non-captured civs add to census for nation
{
struct shpstr *sp;
struct lndstr *lp;
- int mil, i;
+ int mil, i, mil_pay;
mil = 0;
mil += lp->lnd_item[I_MILIT];
}
+ mil_pay = mil * etu * money_mil;
nat_budget[n].mil.count += mil;
- nat_budget[n].mil.money += mil * etu * money_mil;
+ nat_budget[n].mil.money += mil_pay;
+ nat_budget[n].money += mil_pay;
}
void
inc = (int)(sp->sct_item[I_BAR] * etu * bankint * sp->sct_effic / 100);
nat_budget[sp->sct_own].bars.count += sp->sct_item[I_BAR];
nat_budget[sp->sct_own].bars.money += inc;
+ nat_budget[sp->sct_own].money += inc;
}
void
pay_reserve(struct natstr *np, int etu)
{
- nat_budget[np->nat_cnum].mil.money
- += (int)(np->nat_reserve * money_res * etu);
+ int pay = (int)(np->nat_reserve * money_res * etu);
+
+ nat_budget[np->nat_cnum].mil.money += pay;
+ nat_budget[np->nat_cnum].money += pay;
}
budget->prod[sp->sct_type].count += actual;
budget->prod[sp->sct_type].money -= cost;
- if (!player->simulation)
- np->nat_money -= cost;
+ budget->money -= cost;
if (CANT_HAPPEN(p_e <= 0.0))
return;
nat_budget[np->nat_cnum].prod[SCT_ENLIST].count += enlisted;
nat_budget[np->nat_cnum].prod[SCT_ENLIST].money -= enlisted * 3;
- if (!player->simulation)
- np->nat_money -= enlisted * 3;
+ nat_budget[np->nat_cnum].money -= enlisted * 3;
}
/* Fallout is calculated here. */
do_feed(sp, np, etu, 0);
- if (sp->sct_off || np->nat_money < 0) {
+ if (sp->sct_off || budget->money < 0) {
sp->sct_avail = 0;
bp_set_from_sect(bp, sp);
continue;
cost = etu * dchr[sp->sct_type].d_maint;
budget->bm[BUDG_SCT_MAINT].count++;
budget->bm[BUDG_SCT_MAINT].money -= cost;
- if (!player->simulation)
- np->nat_money -= cost;
+ budget->money -= cost;
}
if ((sp->sct_effic < 100 || sp->sct_type != sp->sct_newtype) &&
- np->nat_money >= 0) {
+ budget->money >= 0) {
cost = roundavg(buildeff(sp));
budget->bm[BUDG_SCT_BUILD].count++;
budget->bm[BUDG_SCT_BUILD].money -= cost;
- if (!player->simulation)
- np->nat_money -= cost;
+ budget->money -= cost;
}
if (sp->sct_type == SCT_ENLIST && sp->sct_effic >= 60 &&
*/
if (sp->sct_effic >= 60) {
- if (np->nat_money >= 0 && dchr[sp->sct_type].d_prd >= 0)
+ if (budget->money >= 0 && dchr[sp->sct_type].d_prd >= 0)
produce(np, sp);
}
#include "ship.h"
#include "update.h"
-static void upd_ship(struct shpstr *, int, struct natstr *, struct bp *, int);
+static void upd_ship(struct shpstr *, int, struct bp *, int);
static void shiprepair(struct shpstr *, struct natstr *, struct bp *,
int, struct budget *);
static int feed_ship(struct shpstr *, int);
/* build = 1, maintain = 0 */
{
struct shpstr *sp;
- struct natstr *np;
int i;
- int start_money;
for (i = 0; (sp = getshipp(i)); i++) {
if (sp->shp_own == 0)
continue;
}
- np = getnatp(sp->shp_own);
- start_money = np->nat_money;
- upd_ship(sp, etus, np, bp, build);
- if (player->simulation)
- np->nat_money = start_money;
+ upd_ship(sp, etus, bp, build);
}
}
static void
-upd_ship(struct shpstr *sp, int etus,
- struct natstr *np, struct bp *bp, int build)
+upd_ship(struct shpstr *sp, int etus, struct bp *bp, int build)
/* build = 1, maintain = 0 */
{
struct budget *budget = &nat_budget[sp->shp_own];
+ struct mchrstr *mp = &mchr[sp->shp_type];
+ struct natstr *np = getnatp(sp->shp_own);
struct sctstr *sectp;
- struct mchrstr *mp;
int pstage, ptime;
int oil_gained;
int max_oil;
int dep;
int n, mult, cost, eff_lost;
- mp = &mchr[(int)sp->shp_type];
if (build == 1) {
- if (!sp->shp_off && np->nat_money >= 0)
+ if (!sp->shp_off && budget->money >= 0)
shiprepair(sp, np, bp, etus, budget);
if (!player->simulation)
sp->shp_off = 0;
mult = 2;
budget->bm[BUDG_SHP_MAINT].count++;
cost = -(mult * etus * MIN(0.0, money_ship * mp->m_cost));
- if (np->nat_money < cost && !player->simulation) {
+ if (budget->money < cost && !player->simulation) {
eff_lost = etus / 5;
if (sp->shp_effic - eff_lost < SHIP_MINEFF)
eff_lost = sp->shp_effic - SHIP_MINEFF;
}
} else {
budget->bm[BUDG_SHP_MAINT].money -= cost;
- np->nat_money -= cost;
+ budget->money -= cost;
}
if (!player->simulation) {
sectp = getsectp(sp->shp_x, sp->shp_y);
/* produce oil */
- if (np->nat_money >= 0
+ if (budget->money >= 0
&& (mp->m_flags & M_OIL) && sectp->sct_type == SCT_WATER) {
product = &pchr[dchr[SCT_OIL].d_prd];
oil_gained = roundavg(total_work(100, etus,
sp->shp_item[I_OIL] += oil_gained;
}
/* produce fish */
- if (np->nat_money >= 0
+ if (budget->money >= 0
&& (mp->m_flags & M_FOOD) && sectp->sct_type == SCT_WATER) {
sp->shp_item[I_FOOD]
+= roundavg(total_work(100, etus,
cost = roundavg(mult * mp->m_cost * build / 100.0);
budget->bm[BUDG_SHP_BUILD].count += !!build;
budget->bm[BUDG_SHP_BUILD].money -= cost;
- np->nat_money -= cost;
+ budget->money -= cost;
if (!player->simulation)
ship->shp_effic += (signed char)build;
}
budget
| BUG: military payroll slightly low
-| BUG: expenses ignore going broke
| TODO is it accurate?
production *
| Note: ignores going broke
budget
-| BUG: expenses ignore becoming solvent
| TODO is it accurate?
production *
| TODO is it accurate?
Play#2 input budget
Play#2 command budget
Play#2 output Play#2 1 Sector Type Production Cost
- Play#2 output Play#2 1 technical center 1 tech 300
- Play#2 output Play#2 1 Ship building 2 ships 450
Play#2 output Play#2 1 Ship maintenance 3 ships 90
- Play#2 output Play#2 1 Plane building 1 plane 360
Play#2 output Play#2 1 Plane maintenance 3 planes 144
- Play#2 output Play#2 1 Unit building 1 unit 450
Play#2 output Play#2 1 Unit maintenance 3 units 90
- Play#2 output Play#2 1 Sector building 26 sectors 209
- Play#2 output Play#2 1 Sector maintenance 5 sectors 300
Play#2 output Play#2 1 Military payroll 1900 mil, 1000 res 9994
- Play#2 output Play#2 1 Total expenses.....................................................12387
+ Play#2 output Play#2 1 Total expenses.....................................................10318
Play#2 output Play#2 1 Income from taxes 6800 civs, 4000 uws +1076
Play#2 output Play#2 1 Income from bars 400 bars +2865
Play#2 output Play#2 1 Total income.......................................................+3941
Play#2 output Play#2 1 Balance forward 100
- Play#2 output Play#2 1 Estimated delta -8446
- Play#2 output Play#2 1 Estimated new treasury.............................................-8346
+ Play#2 output Play#2 1 Estimated delta -6377
+ Play#2 output Play#2 1 Estimated new treasury.............................................-6277
Play#2 output Play#2 1 After processsing sectors, you will be broke!
Play#2 output Play#2 1 Sectors will not produce, distribute, or deliver!
Play#2 output Play#2 1
Play#3 input budget
Play#3 command budget
Play#3 output Play#3 1 Sector Type Production Cost
+ Play#3 output Play#3 1 uranium mine 67 rad 156
+ Play#3 output Play#3 1 Sector building 56 sectors 39
+ Play#3 output Play#3 1 Sector maintenance 1 sector 60
Play#3 output Play#3 1 Military payroll 170 mil, 0 res 848
- Play#3 output Play#3 1 Total expenses.......................................................848
+ Play#3 output Play#3 1 Total expenses......................................................1103
Play#3 output Play#3 1 Income from taxes 16549 civs, 150 uws +5540
Play#3 output Play#3 1 Total income.......................................................+5540
Play#3 output Play#3 1 Balance forward -100
- Play#3 output Play#3 1 Estimated delta +4692
- Play#3 output Play#3 1 Estimated new treasury..............................................4592
+ Play#3 output Play#3 1 Estimated delta +4437
+ Play#3 output Play#3 1 Estimated new treasury..............................................4337
Play#3 output Play#3 6 0 99
Play#3 input production *
Play#3 command production