/*
* Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2014, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Copyright (C) 1986-2017, Dave Pare, Jeff Bailey, Thomas Ruschak,
* Ken Stevens, Steve McClure, Markus Armbruster
*
* Empire is free software: you can redistribute it and/or modify
* Known contributors to this file:
* Dave Pare, 1986
* Steve McClure, 1997-2000
- * Markus Armbruster, 2004-2012
+ * Markus Armbruster, 2004-2016
*/
#include <config.h>
#include "chance.h"
#include "land.h"
#include "lost.h"
+#include "nat.h"
#include "news.h"
#include "nsc.h"
#include "nuke.h"
#include "path.h"
#include "plane.h"
+#include "prototypes.h"
+#include "sect.h"
#include "update.h"
-static void take_casualties(struct sctstr *, int);
+static int take_casualties(struct sctstr *, int);
+static int take_casualties_from_lands(struct sctstr *, int, int, int);
static void lnd_dies_fighting_che(struct lndstr *);
void
struct sctstr *nsp;
int recruit;
int move;
- int ratio;
+ double ratio;
int che;
int mil;
+ double security_bonus;
int cc, mc;
double odds;
int civ;
actor = sp->sct_oldown;
che = sp->sct_che;
mil = sp->sct_item[I_MILIT];
+ security_bonus = 0;
snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY) {
int che_kill, r;
- mil += lp->lnd_item[I_MILIT];
+ security_bonus += 3 * lp->lnd_item[I_MILIT] * lp->lnd_effic / 100.0;
r = (lp->lnd_item[I_MILIT] * lp->lnd_effic) / 500;
che_kill = r < 1 ? 0 : roll(r);
if (che_kill > che)
return;
tnat = getnatp(target);
if (tnat->nat_stat == STAT_UNUSED) {
- /* target nation has dissolved: che's retire. */
+ /* target nation has dissolved: che's retire. */
logerror("%d Che targeted at country %d retiring", che, target);
sp->sct_che = 0;
sp->sct_che_target = 0;
goto domove;
}
- ratio = mil / che;
- odds = (double)che / (mil + che);
+ ratio = (mil + security_bonus) / che;
+ odds = (double)che / (mil + security_bonus + che);
odds /= hap_fact(tnat, getnatp(sp->sct_oldown));
if (mil == 0) {
wu(0, sp->sct_own, "Revolutionary subversion reported in %s!\n",
* If loyalty bad enough, then take the sector over,
* and enlist 5% of civ as military force.
*/
- while (che > 0 && mil > 0) {
- if (chance(odds)) {
+ while (che > cc && mil > mc) {
+ if (chance(odds))
mc++;
- mil--;
- } else {
+ else
cc++;
- che--;
- }
}
- if (mil > 0) {
+ if (mil > mc) {
/* military won. */
n = sp->sct_loyal - roll0(15);
if (n < 0)
convert++;
recruit++;
}
- take_casualties(sp, mc);
+ mc = take_casualties(sp, mc);
+ che -= cc;
+ mil -= mc;
} else if (ratio < 5) {
/*
* guerrillas have to resort to blowing things up.
*/
if (chance(ratio * 0.10)) {
n = (mil / 5) + 1;
- odds = (double)che / (n + che);
+ odds = (double)che / (n + security_bonus / 5 + che);
odds /= hap_fact(tnat, getnatp(sp->sct_oldown));
- while (che > 0 && n > 0) {
- if (chance(odds)) {
+ while (che > cc && n > mc) {
+ if (chance(odds))
mc++;
- n--;
- } else {
+ else
cc++;
- che--;
- }
}
- take_casualties(sp, mc);
+ mc = take_casualties(sp, mc);
+ che -= cc;
+ mil -= mc;
recruit = 0;
}
}
/* che won, and sector converts. */
if (sp->sct_own == sp->sct_oldown)
sp->sct_oldown = 0;
- else {
- lost_and_found(EF_SECTOR, sp->sct_own, sp->sct_oldown,
- 0, sp->sct_x, sp->sct_y);
- takeover(sp, sp->sct_oldown);
- }
+ lost_and_found(EF_SECTOR, sp->sct_own, sp->sct_oldown,
+ 0, sp->sct_x, sp->sct_y);
+ takeover(sp, sp->sct_oldown);
sp->sct_mobil = oldmob;
civ += uw;
uw = 0;
else
min_mil = mil;
/* search adjacent sectors for a nice one */
+ /* TODO consider land units in addition to mil */
for (n = 1; n <= 6; n++) {
nsp = getsectp(sp->sct_x + diroff[n][0],
sp->sct_y + diroff[n][1]);
xyas(sp->sct_x, sp->sct_y, victim));
}
-static void
+static int
take_casualties(struct sctstr *sp, int mc)
{
- int orig_mil;
- int cantake;
- int nunits = 0, each, deq;
+ int orig_mil, taken;
+ int nunits = 0, each;
struct lndstr *lp;
struct nstr_item ni;
if (mc <= orig_mil) {
sp->sct_item[I_MILIT] = orig_mil - mc;
- return;
+ return mc;
}
sp->sct_item[I_MILIT] = 0;
- /* remaining casualites */
- mc -= orig_mil;
-
/*
* Need to take total_casualties and divide
* them amongst the land units in the sector
* Do security troops first, then others.
* Try not to kill any unit.
+ * TODO Spread proportionally to mil instead of evenly
*/
snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
while (NULL != (lp = nxtitemp(&ni))) {
continue;
if (lp->lnd_ship >= 0)
continue;
+ if (!lp->lnd_item[I_MILIT])
+ continue;
nunits++;
- if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY)
- nunits++;
}
- if (nunits == 0)
- return;
+ if (CANT_HAPPEN(!nunits))
+ return orig_mil;
- each = (mc / nunits) + 2;
+ taken = orig_mil;
+ each = (mc - taken) / nunits + 2;
/* kill some security troops */
- snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
- while (NULL != (lp = nxtitemp(&ni))) {
- if (lp->lnd_own != sp->sct_own)
- continue;
- if (lp->lnd_ship >= 0)
- continue;
- if (!(lchr[(int)lp->lnd_type].l_flags & L_SECURITY))
- continue;
-
- cantake = ((lp->lnd_effic - 40) / 100.0) * lp->lnd_item[I_MILIT];
+ taken += take_casualties_from_lands(sp, MIN(each, mc - taken), 1, 0);
- if (cantake >= each) {
- deq = ((double)each / lp->lnd_item[I_MILIT]) * 100.0;
- mc -= 2 * each;
- } else if (cantake > 0) {
- deq = ((double)cantake / lp->lnd_item[I_MILIT]) * 100.0;
- mc -= 2 * cantake;
- } else
- deq = 0;
-
- lp->lnd_effic -= deq;
- lp->lnd_mobil -= deq / 2;
- deq = lchr[(int)lp->lnd_type].l_item[I_MILIT] * (deq / 100.0);
- lnd_submil(lp, deq);
- if (mc <= 0)
- return;
- }
+ /* kill some normal troops */
+ taken += take_casualties_from_lands(sp, MIN(each, mc - taken), 0, 0);
+ /* Hmm.. still some left.. kill off units now */
/* kill some normal troops */
- snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
- while (NULL != (lp = nxtitemp(&ni))) {
- if (lp->lnd_own != sp->sct_own)
- continue;
- if (lp->lnd_ship >= 0)
- continue;
- if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY)
- continue;
+ taken += take_casualties_from_lands(sp, MIN(each, mc - taken), 0, 1);
- cantake = ((lp->lnd_effic - 40) / 100.0) * lp->lnd_item[I_MILIT];
+ /* Hmm.. still some left.. kill off units now */
+ /* kill some security troops */
+ taken += take_casualties_from_lands(sp, MIN(each, mc - taken), 1, 1);
- if (cantake >= each) {
- deq = ((double)each / lp->lnd_item[I_MILIT]) * 100.0;
- mc -= each;
- } else if (cantake > 0) {
- deq = ((double)cantake / lp->lnd_item[I_MILIT]) * 100.0;
- mc -= cantake;
- } else
- deq = 0;
+ CANT_HAPPEN(taken < mc);
+ return taken;
+}
- lp->lnd_effic -= deq;
- lp->lnd_mobil -= deq / 2;
- deq = lchr[(int)lp->lnd_type].l_item[I_MILIT] * (deq / 100.0);
- lnd_submil(lp, deq);
- if (mc <= 0)
- return;
- }
+int
+take_casualties_from_lands(struct sctstr *sp, int cas,
+ int security, int may_kill)
+{
+ struct nstr_item ni;
+ struct lndstr *lp;
+ double eff_per_cas;
+ int cantake, deq, taken;
- /* Hmm.. still some left.. kill off units now */
- /* kill some normal troops */
+ taken = 0;
snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
- while (NULL != (lp = nxtitemp(&ni))) {
+ while (taken < cas && (lp = nxtitemp(&ni))) {
if (lp->lnd_own != sp->sct_own)
continue;
if (lp->lnd_ship >= 0)
continue;
- if (lchr[(int)lp->lnd_type].l_flags & L_SECURITY)
+ if (!lp->lnd_item[I_MILIT])
continue;
-
- mc -= (lp->lnd_effic / 100.0) * lp->lnd_item[I_MILIT];
- lnd_dies_fighting_che(lp);
- if (mc <= 0)
- return;
- }
-
- /* Hmm.. still some left.. kill off units now */
- /* kill some security troops */
- snxtitem_xy(&ni, EF_LAND, sp->sct_x, sp->sct_y);
- while (NULL != (lp = nxtitemp(&ni))) {
- if (lp->lnd_own != sp->sct_own)
- continue;
- if (lp->lnd_ship >= 0)
+ if (!(lchr[(int)lp->lnd_type].l_flags & L_SECURITY) == !!security)
continue;
- if (!(lchr[(int)lp->lnd_type].l_flags & L_SECURITY))
+
+ eff_per_cas = 100.0 / lchr[lp->lnd_type].l_item[I_MILIT];
+ cantake = lp->lnd_item[I_MILIT];
+ if (!may_kill)
+ cantake = MIN(cantake,
+ (int)((lp->lnd_effic - 40) / eff_per_cas));
+ deq = MIN(cantake, cas - taken);
+ if (deq <= 0)
continue;
- mc -= (lp->lnd_effic / 100.0) * lp->lnd_item[I_MILIT] * 2.0;
- lnd_dies_fighting_che(lp);
- if (mc <= 0)
- return;
+ taken += deq;
+ lp->lnd_effic -= deq * eff_per_cas;
+ lp->lnd_mobil -= deq * eff_per_cas / 2;
+ lnd_submil(lp, deq);
+ if (lp->lnd_effic < LAND_MINEFF) {
+ CANT_HAPPEN(!may_kill);
+ taken += lp->lnd_item[I_MILIT];
+ lnd_dies_fighting_che(lp);
+ }
}
- /* Hmm.. everyone dead.. too bad */
+ return taken;
}
static void