Damage due to lack of maintenance is now limited by the unit's minimum efficiency. Before, units could die. Unfortunately, the update left any embarked units on their dead carrier. Should have seen this when I fixed a related bug in commitc2c0d1ff
, v4.3.22. Broken for ships and land units when Empire 2 added their maintenance cost, and for planes when commit2e40a4bb
(v4.3.4) replaced nuclear stockpiles by nuke units. The common root cause of these bugs is the update bypassing pre-write functions (bug#1010856). If another unit with the same number got built, it picked up the stuck cargo, triggering the oops from commit6fb5caf6
, which see. In "stuck on dead carrier" state, units pretty much behave as if their carrier was still alive, with additional protection from the fact that a dead carrier can't be damaged or boarded. The server detects this state on startup since commit7da9aab5
, and refuses to start. Only a deity can take units off a dead carrier.
214 lines
5.5 KiB
C
214 lines
5.5 KiB
C
/*
|
|
* Empire - A multi-player, client/server Internet based war game.
|
|
* Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
|
* Ken Stevens, Steve McClure, Markus Armbruster
|
|
*
|
|
* Empire is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* ---
|
|
*
|
|
* See files README, COPYING and CREDITS in the root of the source
|
|
* tree for related information and legal notices. It is expected
|
|
* that future projects/authors will amend these files as needed.
|
|
*
|
|
* ---
|
|
*
|
|
* plane.c: Do production for planes
|
|
*
|
|
* Known contributors to this file:
|
|
* Dave Pare, 1986
|
|
* Steve McClure, 1998
|
|
* Markus Armbruster, 2006-2011
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "budg.h"
|
|
#include "lost.h"
|
|
#include "plane.h"
|
|
#include "player.h"
|
|
#include "ship.h"
|
|
#include "update.h"
|
|
|
|
static void planerepair(struct plnstr *, struct natstr *, struct bp *, int);
|
|
static void upd_plane(struct plnstr *, int, struct natstr *, struct bp *, int);
|
|
|
|
int
|
|
prod_plane(int etus, int natnum, struct bp *bp, int buildem)
|
|
/* Build = 1, maintain =0 */
|
|
{
|
|
struct plnstr *pp;
|
|
struct natstr *np;
|
|
int n, k = 0;
|
|
int start_money;
|
|
|
|
for (n = 0; NULL != (pp = getplanep(n)); n++) {
|
|
if (pp->pln_own == 0)
|
|
continue;
|
|
if (pp->pln_own != natnum)
|
|
continue;
|
|
if (pp->pln_effic < PLANE_MINEFF) {
|
|
makelost(EF_PLANE, pp->pln_own, pp->pln_uid,
|
|
pp->pln_x, pp->pln_y);
|
|
pp->pln_own = 0;
|
|
continue;
|
|
}
|
|
|
|
if (pln_is_in_orbit(pp)) {
|
|
if (!player->simulation && buildem == 0
|
|
&& !(pp->pln_flags & PLN_SYNCHRONOUS))
|
|
move_sat(pp);
|
|
continue;
|
|
}
|
|
|
|
np = getnatp(pp->pln_own);
|
|
start_money = np->nat_money;
|
|
upd_plane(pp, etus, np, bp, buildem);
|
|
air_money[pp->pln_own] += np->nat_money - start_money;
|
|
if (buildem == 0 || np->nat_money != start_money)
|
|
k++;
|
|
if (player->simulation)
|
|
np->nat_money = start_money;
|
|
}
|
|
|
|
return k;
|
|
}
|
|
|
|
static void
|
|
upd_plane(struct plnstr *pp, int etus,
|
|
struct natstr *np, struct bp *bp, int build)
|
|
{
|
|
struct plchrstr *pcp = &plchr[(int)pp->pln_type];
|
|
int mult, cost, eff_lost;
|
|
|
|
if (build == 1) {
|
|
if (!pp->pln_off && np->nat_money >= 0)
|
|
planerepair(pp, np, bp, etus);
|
|
if (!player->simulation)
|
|
pp->pln_off = 0;
|
|
} else {
|
|
mult = 1;
|
|
if (np->nat_level[NAT_TLEV] < pp->pln_tech * 0.85)
|
|
mult = 2;
|
|
cost = -(mult * etus * MIN(0.0, pcp->pl_cost * money_plane));
|
|
if (np->nat_money < cost && !player->simulation) {
|
|
eff_lost = etus / 5;
|
|
if (pp->pln_effic - eff_lost < PLANE_MINEFF)
|
|
eff_lost = pp->pln_effic - PLANE_MINEFF;
|
|
if (eff_lost > 0) {
|
|
wu(0, pp->pln_own, "%s lost %d%% to lack of maintenance\n",
|
|
prplane(pp), eff_lost);
|
|
pp->pln_effic -= eff_lost;
|
|
}
|
|
} else {
|
|
np->nat_money -= cost;
|
|
}
|
|
/* flight pay is 5x the pay received by other military */
|
|
np->nat_money += etus * pcp->pl_crew * money_mil * 5;
|
|
}
|
|
}
|
|
|
|
static void
|
|
planerepair(struct plnstr *pp, struct natstr *np, struct bp *bp, int etus)
|
|
{
|
|
int build;
|
|
int mvec[I_MAX + 1];
|
|
struct shpstr *carrier;
|
|
struct plchrstr *pcp = &plchr[(int)pp->pln_type];
|
|
struct sctstr *sp = getsectp(pp->pln_x, pp->pln_y);
|
|
int delta;
|
|
int mult;
|
|
int avail;
|
|
int w_p_eff;
|
|
int used;
|
|
|
|
carrier = NULL;
|
|
if (pp->pln_ship >= 0) {
|
|
if (pp->pln_effic >= 80)
|
|
return;
|
|
carrier = getshipp(pp->pln_ship);
|
|
if (CANT_HAPPEN(!carrier))
|
|
return;
|
|
if (carrier->shp_off)
|
|
return;
|
|
if (relations_with(carrier->shp_own, pp->pln_own) != ALLIED)
|
|
return;
|
|
} else {
|
|
if (relations_with(sp->sct_own, pp->pln_own) != ALLIED)
|
|
return;
|
|
}
|
|
|
|
if (sp->sct_off)
|
|
return;
|
|
mult = 1;
|
|
if (np->nat_level[NAT_TLEV] < pp->pln_tech * 0.85)
|
|
mult = 2;
|
|
|
|
if (pp->pln_effic == 100)
|
|
return;
|
|
|
|
if (!player->simulation)
|
|
avail = sp->sct_avail * 100;
|
|
else
|
|
avail = bp_get_avail(bp, sp) * 100;
|
|
if (carrier)
|
|
avail += etus * carrier->shp_item[I_MILIT] / 2;
|
|
|
|
w_p_eff = PLN_BLD_WORK(pcp->pl_lcm, pcp->pl_hcm);
|
|
delta = roundavg((double)avail / w_p_eff);
|
|
if (delta <= 0)
|
|
return;
|
|
if (delta > (int)((float)etus * plane_grow_scale))
|
|
delta = (int)((float)etus * plane_grow_scale);
|
|
if (delta > 100 - pp->pln_effic)
|
|
delta = 100 - pp->pln_effic;
|
|
|
|
memset(mvec, 0, sizeof(mvec));
|
|
mvec[I_MILIT] = pcp->pl_crew;
|
|
mvec[I_LCM] = pcp->pl_lcm;
|
|
mvec[I_HCM] = pcp->pl_hcm;
|
|
build = get_materials(sp, bp, mvec, delta);
|
|
|
|
if (carrier)
|
|
build = delta;
|
|
|
|
used = build * w_p_eff;
|
|
/*
|
|
* I didn't use roundavg here, because I want to
|
|
* penalize the player with a large number of planes.
|
|
*/
|
|
if (!player->simulation)
|
|
avail = (sp->sct_avail * 100 - used) / 100;
|
|
else
|
|
avail = (bp_get_avail(bp, sp) * 100 - used) / 100;
|
|
|
|
if (avail < 0)
|
|
avail = 0;
|
|
if (!player->simulation)
|
|
sp->sct_avail = avail;
|
|
else
|
|
bp_put_avail(bp, sp, avail);
|
|
|
|
if (sp->sct_type != SCT_AIRPT)
|
|
build /= 3;
|
|
if (carrier) {
|
|
if ((pp->pln_effic + build) > 80)
|
|
build = 80 - pp->pln_effic;
|
|
}
|
|
|
|
np->nat_money -= mult * build * pcp->pl_cost / 100.0;
|
|
|
|
if (!player->simulation)
|
|
pp->pln_effic += (signed char)build;
|
|
}
|