2014-12-13 11:30:34 +01:00
|
|
|
|
/*
|
2015-01-30 22:10:29 +01:00
|
|
|
|
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
|
2014-12-13 11:30:34 +01:00
|
|
|
|
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"
|
2016-12-23 18:05:38 +01:00
|
|
|
|
#include "monsters.h"
|
2014-12-13 11:30:34 +01:00
|
|
|
|
#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/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 = {
|
2014-12-13 17:31:55 +01:00
|
|
|
|
"chaoscount",
|
2014-12-13 11:30:34 +01:00
|
|
|
|
DEFAULT_INIT,
|
|
|
|
|
DEFAULT_FINALIZE,
|
|
|
|
|
DEFAULT_AGE,
|
|
|
|
|
a_writeint,
|
|
|
|
|
a_readint,
|
2016-02-09 06:43:19 +01:00
|
|
|
|
NULL,
|
2014-12-13 11:30:34 +01:00
|
|
|
|
ATF_UNIQUE
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-07 18:38:10 +02:00
|
|
|
|
void set_chaoscount(struct region *r, int deaths)
|
|
|
|
|
{
|
|
|
|
|
if (deaths==0) {
|
|
|
|
|
a_removeall(&r->attribs, &at_chaoscount);
|
|
|
|
|
} else {
|
|
|
|
|
attrib *a = a_find(r->attribs, &at_chaoscount);
|
|
|
|
|
if (!a) {
|
|
|
|
|
a = a_add(&r->attribs, a_new(&at_chaoscount));
|
|
|
|
|
}
|
|
|
|
|
a->data.i = deaths;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-13 11:30:34 +01:00
|
|
|
|
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) {
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if ((terrain->flags & LAND_REGION) && terrain->herbs) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
++numtypes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (numtypes > 0) {
|
|
|
|
|
types = malloc(sizeof(terrain_type *) * numtypes);
|
|
|
|
|
numtypes = 0;
|
|
|
|
|
for (terrain = terrains(); terrain != NULL; terrain = terrain->next) {
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if ((terrain->flags & LAND_REGION) && terrain->herbs) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
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) {
|
2017-05-24 08:52:19 +02:00
|
|
|
|
c += u->number;
|
2014-12-13 11:30:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == 0) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
n = rng_int() % c;
|
|
|
|
|
c = 0;
|
|
|
|
|
u = r->units;
|
|
|
|
|
|
|
|
|
|
while (u && c < n) {
|
2017-05-24 08:52:19 +02:00
|
|
|
|
c += u->number;
|
2014-12-13 11:30:34 +01:00
|
|
|
|
u = u->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void chaos(region * r)
|
|
|
|
|
{
|
|
|
|
|
if (rng_int() % 100 < 8) {
|
|
|
|
|
switch (rng_int() % 3) {
|
|
|
|
|
case 0: /* Untote */
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if (!(r->terrain->flags & SEA_REGION)) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
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 =
|
2014-12-25 18:40:46 +01:00
|
|
|
|
create_unit(r, get_monsters(), rng_int() % 8 + 1,
|
|
|
|
|
get_race(RC_FIREDRAGON), 0, NULL, NULL);
|
2014-12-13 11:30:34 +01:00
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
mfac = 500;
|
2016-11-17 10:38:09 +01:00
|
|
|
|
u = create_unit(r, get_monsters(), rng_int() % 4 + 1,
|
2014-12-25 18:40:46 +01:00
|
|
|
|
get_race(RC_DRAGON), 0, NULL, NULL);
|
2014-12-13 11:30:34 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
mfac = 1000;
|
2016-11-17 10:38:09 +01:00
|
|
|
|
u = create_unit(r, get_monsters(), rng_int() % 2 + 1,
|
2014-12-25 18:40:46 +01:00
|
|
|
|
get_race(RC_WYRM), 0, NULL, NULL);
|
2014-12-13 11:30:34 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if (mfac) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
set_money(u, u->number * (rng_int() % mfac));
|
2016-11-17 10:38:09 +01:00
|
|
|
|
}
|
|
|
|
|
u->flags |= (UFL_ISNEW | UFL_MOVED);
|
2014-12-13 11:30:34 +01:00
|
|
|
|
}
|
2015-11-05 11:18:39 +01:00
|
|
|
|
break;
|
2016-11-17 10:38:09 +01:00
|
|
|
|
case 2: /* Terrainver<65>nderung */
|
|
|
|
|
if (!(r->terrain->flags & FORBIDDEN_REGION)) {
|
|
|
|
|
if (!(r->terrain->flags & SEA_REGION)) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
direction_t dir;
|
|
|
|
|
for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
|
|
|
|
|
region *rn = rconnect(r, dir);
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if (rn && (rn->terrain->flags & SEA_REGION))
|
2014-12-13 11:30:34 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (dir != MAXDIRECTIONS) {
|
|
|
|
|
ship *sh = r->ships;
|
|
|
|
|
unit **up;
|
|
|
|
|
|
|
|
|
|
while (sh) {
|
|
|
|
|
ship *nsh = sh->next;
|
2015-09-12 16:38:39 +02:00
|
|
|
|
double dmg =
|
2015-11-22 10:44:46 +01:00
|
|
|
|
config_get_flt("rules.ship.damage.atlantis",
|
2014-12-13 11:30:34 +01:00
|
|
|
|
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;
|
2017-05-24 08:52:19 +02:00
|
|
|
|
if (u->ship == 0 && !canfly(u)) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
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);
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if (rn && (rn->terrain->flags & SEA_REGION))
|
2014-12-13 11:30:34 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (dir != MAXDIRECTIONS) {
|
|
|
|
|
terraform_region(r, chaosterrain());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void chaos_update(void) {
|
|
|
|
|
region *r;
|
|
|
|
|
/* Chaos */
|
|
|
|
|
for (r = regions; r; r = r->next) {
|
|
|
|
|
int i;
|
|
|
|
|
|
2016-11-17 10:38:09 +01:00
|
|
|
|
if ((r->flags & RF_CHAOTIC)) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
chaos(r);
|
|
|
|
|
}
|
|
|
|
|
i = get_chaoscount(r);
|
|
|
|
|
if (i) {
|
|
|
|
|
add_chaoscount(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-13 17:31:55 +01:00
|
|
|
|
void chaos_register(void) {
|
2014-12-13 11:30:34 +01:00
|
|
|
|
at_register(&at_chaoscount);
|
|
|
|
|
}
|