move chaos to a separate module (it is an old E2 feature)

This commit is contained in:
Enno Rehling 2014-12-13 11:30:34 +01:00
parent 3d24764e08
commit 2da1d11277
10 changed files with 316 additions and 225 deletions

View File

@ -87,6 +87,7 @@ set (ERESSEA_SRC
morale.c
monster.c
randenc.c
chaos.c
report.c
spy.c
study.c

View File

@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <kernel/config.h>
#include "battle.h"
#include "alchemy.h"
#include "chaos.h"
#include "move.h"
#include "laws.h"
#include "skill.h"
@ -81,13 +82,8 @@ static FILE *bdebug;
#define CATAPULT_STRUCTURAL_DAMAGE
#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */
#ifdef NEW_COMBATSKILLS_RULE
#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */
#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */
#else
#define TDIFF_CHANGE 10
# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */
#endif
#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */
#define DEBUG_SELECT /* should be disabled if select_enemy works */
@ -2615,7 +2611,7 @@ static void battle_effects(battle * b, int dead_players)
_min(rpeasants(r), (int)(dead_players * PopulationDamage()));
if (dead_peasants) {
deathcounts(r, dead_peasants + dead_players);
chaoscounts(r, dead_peasants / 2);
add_chaoscount(r, dead_peasants / 2);
rsetpeasants(r, rpeasants(r) - dead_peasants);
}
}
@ -2899,12 +2895,11 @@ static void aftermath(battle * b)
static void battle_punit(unit * u, battle * b)
{
bfaction *bf;
strlist *S, *x;
for (bf = b->factions; bf; bf = bf->next) {
faction *f = bf->faction;
strlist *S = 0, *x;
S = 0;
spunit(&S, f, u, 4, see_battle);
for (x = S; x; x = x->next) {
fbattlerecord(b, f, x->s);

View File

@ -16,6 +16,8 @@ without prior permission by the authors of Eressea.
#include "bind_ship.h"
#include "bind_building.h"
#include "chaos.h"
#include <kernel/config.h>
#include <kernel/region.h>
#include <kernel/resources.h>
@ -370,7 +372,7 @@ static int tolua_region_get_resource(lua_State * L)
result = deathcount(r);
break;
case 4:
result = chaoscount(r);
result = get_chaoscount(r);
break;
}
} else {
@ -406,7 +408,7 @@ static int tolua_region_set_resource(lua_State * L)
deathcounts(r, value - deathcount(r));
break;
case 4:
chaoscounts(r, value - chaoscount(r));
add_chaoscount(r, value - get_chaoscount(r));
break;
}
} else {

256
src/chaos.c Normal file
View File

@ -0,0 +1,256 @@
/*
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include <kernel/config.h>
#include "chaos.h"
#include "monster.h"
#include "move.h"
#include <kernel/building.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/messages.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/save.h>
#include <kernel/ship.h>
#include <kernel/terrain.h>
#include <kernel/terrainid.h>
#include <kernel/unit.h>
#include <util/attrib.h>
#include <util/rng.h>
#include <stdlib.h>
#include <assert.h>
/*********************/
/* at_chaoscount */
/*********************/
attrib_type at_chaoscount = {
"get_chaoscount",
DEFAULT_INIT,
DEFAULT_FINALIZE,
DEFAULT_AGE,
a_writeint,
a_readint,
ATF_UNIQUE
};
int get_chaoscount(const region * r)
{
attrib *a = a_find(r->attribs, &at_chaoscount);
if (!a)
return 0;
return a->data.i;
}
void add_chaoscount(region * r, int fallen)
{
attrib *a;
if (fallen == 0)
return;
a = a_find(r->attribs, &at_chaoscount);
if (!a)
a = a_add(&r->attribs, a_new(&at_chaoscount));
a->data.i += fallen;
if (a->data.i <= 0)
a_remove(&r->attribs, a);
}
static const terrain_type *chaosterrain(void)
{
static const terrain_type **types;
static int numtypes;
if (numtypes == 0) {
const terrain_type *terrain;
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
if (fval(terrain, LAND_REGION) && terrain->herbs) {
++numtypes;
}
}
if (numtypes > 0) {
types = malloc(sizeof(terrain_type *) * numtypes);
numtypes = 0;
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
if (fval(terrain, LAND_REGION) && terrain->herbs) {
types[numtypes++] = terrain;
}
}
}
}
if (numtypes > 0) {
return types[rng_int() % numtypes];
}
return NULL;
}
static unit *random_unit(const region * r)
{
int c = 0;
int n;
unit *u;
for (u = r->units; u; u = u->next) {
if (u_race(u) != get_race(RC_SPELL)) {
c += u->number;
}
}
if (c == 0) {
return NULL;
}
n = rng_int() % c;
c = 0;
u = r->units;
while (u && c < n) {
if (u_race(u) != get_race(RC_SPELL)) {
c += u->number;
}
u = u->next;
}
return u;
}
static void chaos(region * r)
{
if (rng_int() % 100 < 8) {
switch (rng_int() % 3) {
case 0: /* Untote */
if (!fval(r->terrain, SEA_REGION)) {
unit *u = random_unit(r);
if (u && playerrace(u_race(u))) {
ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u));
u_setfaction(u, get_monsters());
u_setrace(u, get_race(RC_GHOUL));
}
}
break;
case 1: /* Drachen */
if (random_unit(r)) {
int mfac = 0;
unit *u;
switch (rng_int() % 3) {
case 0:
mfac = 100;
u =
createunit(r, get_monsters(), rng_int() % 8 + 1,
get_race(RC_FIREDRAGON));
break;
case 1:
mfac = 500;
u =
createunit(r, get_monsters(), rng_int() % 4 + 1,
get_race(RC_DRAGON));
break;
default:
mfac = 1000;
u =
createunit(r, get_monsters(), rng_int() % 2 + 1,
get_race(RC_WYRM));
break;
}
if (mfac)
set_money(u, u->number * (rng_int() % mfac));
fset(u, UFL_ISNEW | UFL_MOVED);
}
case 2: /* Terrainveränderung */
if (!fval(r->terrain, FORBIDDEN_REGION)) {
if (!fval(r->terrain, SEA_REGION)) {
direction_t dir;
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
region *rn = rconnect(r, dir);
if (rn && fval(rn->terrain, SEA_REGION))
break;
}
if (dir != MAXDIRECTIONS) {
ship *sh = r->ships;
unit **up;
while (sh) {
ship *nsh = sh->next;
float dmg =
get_param_flt(global.parameters, "rules.ship.damage.atlantis",
0.50);
damage_ship(sh, dmg);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
remove_ship(&sh->region->ships, sh);
}
sh = nsh;
}
for (up = &r->units; *up;) {
unit *u = *up;
if (u_race(u) != get_race(RC_SPELL) && u->ship == 0 && !canfly(u)) {
ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill",
"region unit", r, u));
remove_unit(up, u);
}
if (*up == u)
up = &u->next;
}
ADDMSG(&r->msgs, msg_message("tidalwave", "region", r));
while (r->buildings) {
remove_building(&r->buildings, r->buildings);
}
terraform_region(r, newterrain(T_OCEAN));
}
}
else {
direction_t dir;
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
region *rn = rconnect(r, dir);
if (rn && fval(rn->terrain, SEA_REGION))
break;
}
if (dir != MAXDIRECTIONS) {
terraform_region(r, chaosterrain());
}
}
}
}
}
}
void chaos_update(void) {
region *r;
/* Chaos */
for (r = regions; r; r = r->next) {
int i;
if (fval(r, RF_CHAOTIC)) {
chaos(r);
}
i = get_chaoscount(r);
if (i) {
add_chaoscount(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0));
}
}
}
void chaos_init(void) {
at_register(&at_chaoscount);
}

38
src/chaos.h Normal file
View File

@ -0,0 +1,38 @@
/*
Copyright (c) 1998-2014, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#ifndef H_GC_CHAOS
#define H_GC_CHAOS
#ifdef __cplusplus
extern "C" {
#endif
struct region;
extern struct attrib_type at_chaoscount;
void chaos_init(void);
void chaos_update(void);
int get_chaoscount(const struct region * r);
void add_chaoscount(struct region * r, int deaths);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -2153,7 +2153,6 @@ void attrib_init(void)
/* neue REGION-Attribute */
at_register(&at_moveblock);
at_register(&at_deathcount);
at_register(&at_chaoscount);
at_register(&at_woodcount);
/* neue UNIT-Attribute */

View File

@ -144,14 +144,6 @@ int deathcount(const region * r)
return a->data.i;
}
int chaoscount(const region * r)
{
attrib *a = a_find(r->attribs, &at_chaoscount);
if (!a)
return 0;
return a->data.i;
}
void deathcounts(region * r, int fallen)
{
attrib *a;
@ -173,22 +165,6 @@ void deathcounts(region * r, int fallen)
a_remove(&r->attribs, a);
}
void chaoscounts(region * r, int fallen)
{
attrib *a;
if (fallen == 0)
return;
a = a_find(r->attribs, &at_chaoscount);
if (!a)
a = a_add(&r->attribs, a_new(&at_chaoscount));
a->data.i += fallen;
if (a->data.i <= 0)
a_remove(&r->attribs, a);
}
/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld
r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere
Dinge gefragt werden. */
@ -237,8 +213,9 @@ static uidhashentry uidhash[MAXREGIONS];
struct region *findregionbyid(int uid)
{
int key = uid % MAXREGIONS;
while (uidhash[key].uid != 0 && uidhash[key].uid != uid)
++key;
while (uidhash[key].uid != 0 && uidhash[key].uid != uid) {
if (++key==MAXREGIONS) key = 0;
}
return uidhash[key].r;
}
@ -248,8 +225,9 @@ static void unhash_uid(region * r)
{
int key = r->uid % MAXREGIONS;
assert(r->uid);
while (uidhash[key].uid != 0 && uidhash[key].uid != r->uid)
++key;
while (uidhash[key].uid != 0 && uidhash[key].uid != r->uid) {
if (++key == MAXREGIONS) key = 0;
}
assert(uidhash[key].r == r);
uidhash[key].r = NULL;
}
@ -260,8 +238,9 @@ static void hash_uid(region * r)
for (;;) {
if (uid != 0) {
int key = uid % MAXREGIONS;
while (uidhash[key].uid != 0 && uidhash[key].uid != uid)
++key;
while (uidhash[key].uid != 0 && uidhash[key].uid != uid) {
if (++key == MAXREGIONS) key = 0;
}
if (uidhash[key].uid == 0) {
uidhash[key].uid = uid;
uidhash[key].r = r;
@ -518,19 +497,6 @@ attrib_type at_peasantluck = {
ATF_UNIQUE
};
/*********************/
/* at_chaoscount */
/*********************/
attrib_type at_chaoscount = {
"chaoscount",
DEFAULT_INIT,
DEFAULT_FINALIZE,
DEFAULT_AGE,
a_writeint,
a_readint,
ATF_UNIQUE
};
/*********************/
/* at_deathcount */
/*********************/

View File

@ -167,7 +167,6 @@ extern "C" {
extern struct attrib_type at_moveblock;
extern struct attrib_type at_peasantluck;
extern struct attrib_type at_horseluck;
extern struct attrib_type at_chaoscount;
extern struct attrib_type at_woodcount;
extern struct attrib_type at_deathcount;
extern struct attrib_type at_travelunit;

View File

@ -23,6 +23,7 @@
#include <kernel/config.h>
#include "economy.h"
#include "chaos.h"
#include "give.h"
#include "monster.h"
#include "laws.h"
@ -867,7 +868,6 @@ void plan_monsters(faction * f)
}
if (long_order) {
addlist(&u->orders, long_order);
// u->thisorder = long_order;
}
}
}
@ -876,10 +876,7 @@ void plan_monsters(faction * f)
static double chaosfactor(region * r)
{
attrib *a = a_find(r->attribs, &at_chaoscount);
if (!a)
return 0;
return ((double)a->data.i / 1000.0);
return fval(r, RF_CHAOTIC) ? ((double)(1 + get_chaoscount(r)) / 1000.0) : 0.0;
}
static int nrand(int start, int sub)

View File

@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "monster.h"
#include "move.h"
#include "alchemy.h"
#include "chaos.h"
/* kernel includes */
#include <kernel/building.h>
@ -417,159 +418,6 @@ void encounters(void)
}
}
static const terrain_type *chaosterrain(void)
{
static const terrain_type **types;
static int numtypes;
if (numtypes == 0) {
const terrain_type *terrain;
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
if (fval(terrain, LAND_REGION) && terrain->herbs) {
++numtypes;
}
}
types = malloc(sizeof(terrain_type) * numtypes);
numtypes = 0;
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
if (fval(terrain, LAND_REGION) && terrain->herbs) {
types[numtypes++] = terrain;
}
}
}
return types[rng_int() % numtypes];
}
static unit *random_unit(const region * r)
{
int c = 0;
int n;
unit *u;
for (u = r->units; u; u = u->next) {
if (u_race(u) != get_race(RC_SPELL)) {
c += u->number;
}
}
if (c == 0) {
return NULL;
}
n = rng_int() % c;
c = 0;
u = r->units;
while (u && c < n) {
if (u_race(u) != get_race(RC_SPELL)) {
c += u->number;
}
u = u->next;
}
return u;
}
void chaos(region * r)
{
if (rng_int() % 100 < 8) {
switch (rng_int() % 3) {
case 0: /* Untote */
if (!fval(r->terrain, SEA_REGION)) {
unit *u = random_unit(r);
if (u && playerrace(u_race(u))) {
ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u));
u_setfaction(u, get_monsters());
u_setrace(u, get_race(RC_GHOUL));
}
}
break;
case 1: /* Drachen */
if (random_unit(r)) {
int mfac = 0;
unit *u;
switch (rng_int() % 3) {
case 0:
mfac = 100;
u =
createunit(r, get_monsters(), rng_int() % 8 + 1,
get_race(RC_FIREDRAGON));
break;
case 1:
mfac = 500;
u =
createunit(r, get_monsters(), rng_int() % 4 + 1,
get_race(RC_DRAGON));
break;
default:
mfac = 1000;
u =
createunit(r, get_monsters(), rng_int() % 2 + 1,
get_race(RC_WYRM));
break;
}
if (mfac)
set_money(u, u->number * (rng_int() % mfac));
fset(u, UFL_ISNEW | UFL_MOVED);
}
case 2: /* Terrainveränderung */
if (!fval(r->terrain, FORBIDDEN_REGION)) {
if (!fval(r->terrain, SEA_REGION)) {
direction_t dir;
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
region *rn = rconnect(r, dir);
if (rn && fval(rn->terrain, SEA_REGION))
break;
}
if (dir != MAXDIRECTIONS) {
ship *sh = r->ships;
unit **up;
while (sh) {
ship *nsh = sh->next;
float dmg =
get_param_flt(global.parameters, "rules.ship.damage.atlantis",
0.50);
damage_ship(sh, dmg);
if (sh->damage >= sh->size * DAMAGE_SCALE) {
remove_ship(&sh->region->ships, sh);
}
sh = nsh;
}
for (up = &r->units; *up;) {
unit *u = *up;
if (u_race(u) != get_race(RC_SPELL) && u->ship == 0 && !canfly(u)) {
ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill",
"region unit", r, u));
remove_unit(up, u);
}
if (*up == u)
up = &u->next;
}
ADDMSG(&r->msgs, msg_message("tidalwave", "region", r));
while (r->buildings) {
remove_building(&r->buildings, r->buildings);
}
terraform_region(r, newterrain(T_OCEAN));
}
}
else {
direction_t dir;
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
region *rn = rconnect(r, dir);
if (rn && fval(rn->terrain, SEA_REGION))
break;
}
if (dir != MAXDIRECTIONS) {
terraform_region(r, chaosterrain());
}
}
}
}
}
}
static int nb_armor(const unit * u, int index)
{
const item *itm;
@ -611,6 +459,7 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
return 0;
}
assert(u->number > u->hp);
h = u->hp / u->number;
/* HP verteilen */
for (i = 0; i < u->number; i++)
@ -1325,18 +1174,7 @@ void randomevents(void)
}
}
/* Chaos */
for (r = regions; r; r = r->next) {
int i;
if (fval(r, RF_CHAOTIC)) {
chaos(r);
}
i = chaoscount(r);
if (i) {
chaoscounts(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0));
}
}
chaos_update();
#ifdef HERBS_ROT
rotting_herbs();
#endif