server/src/eressea/korrektur.c

2707 lines
60 KiB
C

/* vi: set ts=2:
*
* Eressea PB(E)M host Copyright (C) 1998-2000
* Christian Schlittchen (corwin@amber.kn-bremen.de)
* Katja Zedel (katze@felidae.kn-bremen.de)
* Henning Peters (faroul@beyond.kn-bremen.de)
* Enno Rehling (enno@eressea-pbem.de)
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
*
* based on:
*
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
* Atlantis v1.7 Copyright 1996 by Alex Schröder
*
* This program may not be used, modified or distributed without
* prior permission by the authors of Eressea.
* This program may not be sold or used commercially without prior written
* permission from the authors.
*/
#include <config.h>
#include <eressea.h>
/* misc includes */
#include <attributes/key.h>
#include <modules/xmas2000.h>
#include <modules/xmas2001.h>
#include <modules/museum.h>
/* gamecode includes */
#include <creation.h>
#include <economy.h>
/* kernel includes */
#include <border.h>
#include <building.h>
#include <ship.h>
#include <faction.h>
#include <item.h>
#include <magic.h>
#include <message.h>
#include <monster.h>
#include <movement.h>
#include <names.h>
#include <pathfinder.h>
#include <plane.h>
#include <pool.h>
#include <race.h>
#include <region.h>
#include <reports.h>
#include <resources.h>
#include <skill.h>
#include <teleport.h>
#include <unit.h>
#include <spell.h>
#include <alchemy.h>
#include <study.h>
/* util includes */
#include <attrib.h>
#include <base36.h>
#include <cvector.h>
#include <event.h>
#include <resolve.h>
#include <sql.h>
#include <vset.h>
/* libc includes */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/* attributes includes */
#include <attributes/targetregion.h>
#include <attributes/key.h>
#undef XMAS1999
#undef XMAS2000
#undef XMAS2001
extern void reorder_owners(struct region * r);
static void
verify_owners(boolean bOnce)
{
region * r;
for (r=regions;r;r=r->next) {
unit * u;
boolean bFail = false;
for (u=r->units;u;u=u->next) {
if (u->building) {
unit * bo = buildingowner(r, u->building);
if (!fval(bo, FL_OWNER)) {
log_error(("[verify_owners] %u ist Besitzer von %s, hat aber FL_OWNER nicht.\n", unitname(bo), buildingname(u->building)));
bFail = true;
if (bOnce) break;
}
if (bo!=u && fval(u, FL_OWNER)) {
log_error(("[verify_owners] %u ist NICHT Besitzer von %s, hat aber FL_OWNER.\n", unitname(u), buildingname(u->building)));
bFail = true;
if (bOnce) break;
}
}
if (u->ship) {
unit * bo = shipowner(r, u->ship);
if (!fval(bo, FL_OWNER)) {
log_error(("[verify_owners] %u ist Besitzer von %s, hat aber FL_OWNER nicht.\n", unitname(bo), shipname(u->ship)));
bFail = true;
if (bOnce) break;
}
if (bo!=u && fval(u, FL_OWNER)) {
log_error(("[verify_owners] %u ist NICHT Besitzer von %s, hat aber FL_OWNER.\n", unitname(u), shipname(u->ship)));
bFail = true;
if (bOnce) break;
}
}
}
if (bFail) reorder_owners(r);
}
}
/* make sure that this is done only once! */
#define do_once(magic, fun) \
{ \
attrib * a = find_key(global.attribs, atoi36(magic)); \
if (a) { \
log_warning(("[do_once] a unique fix %d=\"%s\" was called a second time\n", atoi36(magic), magic)); \
} else { \
if (fun == 0) a_add(&global.attribs, make_key(atoi36(magic))); \
} \
}
int
warn_items(void)
{
boolean found = 0;
region * r;
for (r=regions;r;r=r->next) {
unit * u;
for (u=r->units;u;u=u->next) {
item * itm;
for (itm=u->items;itm;itm=itm->next) {
if (itm->number>100000) {
found = 1;
log_error(("Einheit %s hat %u %s\n",
unitid(u), itm->number,
resourcename(itm->type->rtype, 0)));
}
}
}
}
return found;
}
#ifdef XMAS1999
#include "race.h"
#include "movement.h"
static void
santa_comes_to_town(void)
{
unit * santa = ufindhash(atoi36("xmas"));
unit * tans = ufindhash(atoi36("tans"));
faction * f;
region * r;
if (!tans) r = findregion(0,0);
else r = tans->region;
if (!r) return;
while (santa && santa->race!=RC_ILLUSION) {
uunhash(santa);
santa->no = newunitid();
uhash(santa);
santa = ufindhash(atoi36("xmas"));
}
if (!santa) {
santa = createunit(r, findfaction(MONSTER_FACTION), 1, new_race[RC_ILLUSION]);
uunhash(santa);
santa->no = atoi36("xmas");
uhash(santa);
}
santa->age = 2;
santa->irace = new_race[RC_DAEMON];
set_string(&santa->name, "Ein dicker Gnom mit einem Rentierschlitten");
set_string(&santa->display, "hat: 6 Rentiere, Schlitten, Sack mit Geschenken, Kekse für Khorne");
fset(santa, FL_TRAVELTHRU);
for (f=factions;f;f=f->next) {
unit * u;
runit *ru;
region * r;
item_t i = (item_t) (rand() % 4 + I_KEKS);
unit * senior = f->units;
for (u = f->units; u; u=u->nextF) {
if (senior->age < u->age) senior = u;
}
if (!senior) continue;
r = senior->region;
sprintf(buf, "%s gibt %d %s an %s.", unitname(santa), 1, itemdata[i].name[0], unitname(senior));
change_item(senior, i, 1);
addmessage(r, senior->faction, buf, MSG_COMMERCE, ML_INFO);
sprintf(buf, "von %s: 'Ho ho ho. Frohe Weihnachten, und %s für %s.'", unitname(santa), itemdata[i].name[1], unitname(senior));
addmessage(r, 0, buf, MSG_MESSAGE, ML_IMPORTANT);
for (ru = r->durchgezogen; ru ; ru=ru->next)
if (ru->unit==santa) break;
if (!ru) {
ru = calloc(1, sizeof(runit));
ru->next = r->durchgezogen;
ru->unit = santa;
r->durchgezogen = ru;
}
}
}
#endif
#if 0
static void
init_hp(void)
{
region *r;
unit *u;
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
if (u->hp == -1) {
u->hp = unit_max_hp(u) * u->number;
}
}
}
}
static void
convert(int x, int y, int *nx, int *ny)
{
*ny = -y;
*nx = x + (y + ((y>=0)?1:0))/2;
}
#endif
#if 0
static void
loesche_coasts(void)
{
region *r;
ship *sh;
for(r=regions;r;r=r->next) {
for(sh=r->ships;sh;sh=sh->next) {
sh->coast = NODIRECTION;
}
}
}
#endif
#if 0
static void
create_underworld(void)
{
int x, y;
region *r;
attrib *a;
plane * hell = create_new_plane(-1, "Hölle", 100000, 100000, 100020, 100020, PFL_NONE);
for(x=0;x<=20;x++) {
for(y=0;y<=20;y++) {
r = new_region(x+100000,y);
r->planep = hell;
if(x==0 || x == 20 || y == 0 || y == 20) {
rsetterrain(r, T_FIREWALL);
} else {
rsetterrain(r, T_HELL);
}
}
}
/* Verbindungen schaffen */
a = create_special_direction(findregion(4,4),100005,5,-1,
"Ein dunkler Schlund fuehrt in die Tiefe der Erde",
"Schlund");
a = create_special_direction(findregion(100005,5),4,4,-1,
"Ein hell erleuchteter Tunnel fuehrt nach oben",
"Tunnel");
}
#endif
#if 0
static void
bename_dracoide(void)
{
region *r;
unit *u;
for(r=regions;r;r=r->next) {
for(u=r->units;u;u=u->next) {
if(u->race == new_race[RC_DRACOID]) name_unit(u);
}
}
}
#endif
static void
fix_migrants(void) {
region * r;
for (r=regions;r;r=r->next) {
unit * u;
for (u=r->units;u;u=u->next) {
if (u->race == new_race[RC_HUMAN]) u->irace = u->race;
if (u->irace!=u->race && (u->race->flags & RCF_SHAPESHIFT)==0) {
log_warning(("[fix_migrants] %s ist ein %s, als %s getarnt\n", unitname(u), LOC(default_locale, rc_name(u->race, 0)), LOC(default_locale, rc_name(u->irace, 0))));
}
}
}
}
static boolean
kor_teure_talente(unit *u)
{
if(effskill(u, SK_TACTICS) >= 1 ||
effskill(u, SK_MAGIC) >= 1 ||
effskill(u, SK_ALCHEMY) >= 1 ||
effskill(u, SK_HERBALISM) >= 1 ||
effskill(u, SK_SPY) >= 1) {
return true;
}
return false;
}
static void
no_teurefremde(boolean convert)
{
region *r;
unit *u;
for(r=regions;r;r=r->next) {
for(u=r->units;u;u=u->next) {
if(u->faction->no != MONSTER_FACTION
&& is_migrant(u)
&& kor_teure_talente(u))
{
log_printf("* Warnung, teurer Migrant: %s %s\n",
unitname(u), factionname(u->faction));
if(convert) {
u->race = u->faction->race;
u->irace = u->faction->race;
u->faction->num_migrants -= u->number;
sprintf(buf, "Die Götter segnen %s mit der richtigen Rasse",
unitname(u));
addmessage(0, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT);
}
}
}
}
}
#if 0
static void
give_arena_gates(void)
{
faction * f;
for (f=factions;f;f=f->next) {
unit * u;
region * r;
unit * senior = f->units;
if (f->age>2) return;
for (u = f->units; u; u=u->nextF) {
if (senior->age < u->age) senior = u;
if (f->no==MONSTER_FACTION && get_item(u, I_ARENA_GATE)) return;
}
if (!senior) continue;
r = senior->region;
sprintf(buf, "Der Himmel über %s reißt auf und ein Licht aus den Wolken scheint auf %s. Ein Gesang wie von tausend Walküren ertönt, dazu Schlachtenlärm. Nach einer Weile endet die Vision, und %s hält ein %s in den Händen.", regionid(senior->region), unitname(senior), unitname(senior), itemdata[I_ARENA_GATE].name[0]);
change_item(senior, I_ARENA_GATE, 1);
addmessage(NULL, senior->faction, buf, MSG_MESSAGE, ML_IMPORTANT);
}
}
static void
remove_impossible_dragontargets(void)
{
region *r;
for (r=regions;r;r=r->next) {
unit *u;
for (u=r->units;u;u=u->next) {
attrib *a;
if(u->faction->no != MONSTER_FACTION) continue;
a = a_find(u->attribs, &at_targetregion);
if (a!=NULL) {
boolean cango = false;
region * r2 = a->data.v;
if(r2!=NULL) {
#ifdef NEW_PATH
cango = path_exists(r, r2, DRAGON_RANGE, allowed_dragon);
#else
cango = path_exists(r, r2, FLY|DRAGON_LIMIT);
#endif
}
if(!cango) {
printf("Lösche Ziel von %s\n", unitname(u));
a_remove(&u->attribs, a);
}
}
}
}
}
static void
fix_score_option(void)
{
faction * f;
for (f=factions;f;f=f->next) {
f->options &= ((1<<O_SCORE)-1);
f->options &= ~(1<<O_MERIAN);
f->options |= (1<<O_SCORE);
}
}
#endif
#if 0
static void
fix_wounds(void)
{
region *r;
unit *u;
for(r=regions; r; r=r->next) {
for(u=r->units; u; u=u->next) {
int wounds = unit_max_hp(u)*u->number - u->hp;
u->hp = max(1, u->hp - wounds);
}
}
}
#endif
#if 0
static void
fix_beached(void)
{
region * r;
for (r=regions;r;r=r->next) {
if (r->land && rterrain(r)!=T_PLAIN) {
ship * s;
building *b;
for(b=r->buildings; b; b=b->next) {
if(b->typ == BT_HAFEN) break;
}
if(b == NULL) {
for (s=r->ships;s;s=s->next) {
if (s->coast!=NODIRECTION && s->type>SH_BOAT)
{
region * r2 = rconnect(r, s->coast);
assert(rterrain(r2)==T_OCEAN || fval(r2, RF_CHAOTIC));
move_ship(s, r, r2, NULL);
}
}
}
}
}
}
#endif
#if 0
static void
fix_hungrydead(void)
{
region *r;
unit *u;
for (r=regions;r;r=r->next) {
for (u=r->units;u;u=u->next) {
if(u->hp == 0) u->hp = 1;
}
}
}
static void
name_seaserpents(void)
{
region *r;
unit *u;
for (r=regions;r;r=r->next) {
for (u=r->units;u;u=u->next) {
if(u->race == new_race[RC_SEASERPENT] && strncmp(u->name, "Nummer ", 7)) {
set_string(&u->name, "Seeschlange");
}
}
}
}
#endif
static int
old_rroad(region * r)
{
attrib * a = a_find(r->attribs, &at_road);
if (!a) return 0;
return a->data.i;
}
attrib_type at_roadfix = {
"roadfix",
DEFAULT_INIT,
DEFAULT_FINALIZE,
DEFAULT_AGE,
#if RELEASE_VERSION<DISABLE_ROADFIX
DEFAULT_WRITE,
#else
NULL, /* disable writing them so they will disappear */
#endif
DEFAULT_READ,
ATF_UNIQUE
};
static void
newroads(void)
{
region *r;
for(r=regions;r;r=r->next) if (terrain[rterrain(r)].roadreq>0) {
direction_t d;
int connections = 0;
int maxcon = MAXDIRECTIONS;
int stones = old_rroad(r);
if (stones<=0) continue;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * r2 = rconnect(r, d);
if (r2 && old_rroad(r2)) ++connections;
else if (terrain[rterrain(r2)].roadreq<=0) --maxcon;
}
if (!connections) connections=maxcon;
else maxcon=0;
for (d=0;d!=MAXDIRECTIONS && connections;++d) {
region * r2 = rconnect(r, d);
int use = stones/connections;
if (!r2 ||
terrain[rterrain(r2)].roadreq<=0 ||
(old_rroad(r2)<=0 && !maxcon))
continue;
if (use>terrain[rterrain(r)].roadreq) {
/* wenn etwas übrig bleibt (connections==1) kriegt es der regionserste */
int give = use-terrain[rterrain(r)].roadreq;
unit * u = r->units;
use = terrain[rterrain(r)].roadreq;
if (u) change_item(u, I_STONE, give);
}
rsetroad(r, d, use);
stones = stones - use;
--connections;
if (old_rroad(r)==terrain[rterrain(r)].roadreq*2 && old_rroad(r2)==terrain[rterrain(r2)].roadreq*2) {
border * b = get_borders(r, r2);
attrib * a = a_find(b->attribs, &at_roadfix);
if (a) continue;
while (b && b->type!=&bt_road) b = b->next;
assert(b);
a = a_add(&b->attribs, a_new(&at_roadfix));
}
}
}
}
/* ************************************************************ */
/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */
/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */
/* ************************************************************ */
static void
show_newspells(void)
{
region *r;
/* Alle geänderten Zauber in das array newspellids[]. mit SPL_NOSPELL
* terminieren */
spellid_t newspellids[] = {
SPL_NOSPELL };
/* die id's der neuen oder veränderten Sprüche werden in newspellids[]
* abgelegt */
for(r=regions; r; r=r->next) {
unit *u;
for(u=r->units;u;u=u->next) {
sc_mage *m = get_mage(u);
if (u->faction->no == MONSTER_FACTION) continue;
if (m != NULL) {
int i;
if (m->magietyp == M_GRAU) continue;
for (i = 0; newspellids[i] != SPL_NOSPELL; i++) {
spell *sp = find_spellbyid(newspellids[i]);
if (!sp) continue;
if (m->magietyp == sp->magietyp || getspell(u, sp->id)) {
attrib * a = a_find(u->faction->attribs, &at_reportspell);
while (a && a->data.i != sp->id) a = a->nexttype;
if (!a) {
/* spell is not being shown yet. if seen before, remove to show again */
a = a_find(u->faction->attribs, &at_seenspell);
while (a && a->data.i != sp->id) a = a->nexttype;
if (a) a_remove(&u->faction->attribs, a);
}
}
}
}
}
}
}
#if 0
static void
fix_feuerwand_orks(void)
{
unit *u;
if((u=findunitg(atoi36("1j1L"), NULL))==NULL) {
printf("Korrektur: kann Orks nicht finden!\n");
return;
}
if(u->number < 1000) {
printf("Korrektur: Orks sind schon korrigiert!\n");
return;
}
scale_number(u,170);
u->hp=2337; /* Buggy Anzahl Personen = Normale HP */
}
static void
fix_buildings(void)
{
building *burg;
unit *u, *uf = NULL;
const requirement *req;
const construction *con;
FILE *statfile;
vset done;
int s1, s2;
char buf[256];
int a,b,c,d;
int first;
if((statfile=fopen("building.txt","r"))==NULL) {
log_warning(("fix_buildings: cannot open building.txt!\n"));
return;
}
vset_init(&done);
s1=s2=-1;
while(fgets(buf, 256, statfile)!=NULL) {
if(*buf=='#')
continue;
a=b=c=d=0;
first=0;
sscanf(buf,"%d;%d;%d;%d",&a,&b,&c,&d);
if((u=findunitg(b,NULL))==NULL) {
printf("fix_buildings: Einheit %d nicht gefunden.\n",b);
continue;
}
if((burg=findbuilding(a))==NULL) {
printf("fix_buildings: Burg %d nicht gefunden.\n", a);
if((burg=u->building)==NULL) {
printf("Einheit %d steht auch in keinem Gebäude. (gebe auf)\n",u->no);
continue;
}
if(burg->type->construction->maxsize > 0 &&
burg->type->construction->reqsize > 0)
printf("Ersatz: Burg %d\n",burg->no);
else {
printf("Ersatzgebäude ist nicht vom betroffenen Typ.\n");
continue;
}
}
printf("Burg %d; Einheit %d; vorher %d; + %d\n",burg->no,u->no,c,d);
s2=vset_add(&done, (void *)a);
if(s2>s1) {
printf("ERSTER !\n");
first=1;
uf=u;
}
s1=s2;
con=burg->type->construction;
if(con->maxsize != -1 || con->reqsize == 1) continue;
for(req=con->materials; req->number!=0; req++) {
int diff=burg->size-c;
if(req->type==R_SILVER)
change_resource(uf, R_SILVER, diff*req->number-d*req->number/con->reqsize);
else {
if(first)
change_resource(uf, req->type, diff*req->number);
assert(uf!=NULL);
change_resource(uf, req->type, -d*req->number/con->reqsize);
}
}
if(first)
burg->size=c+d;
else
burg->size+=d;
}
vset_destroy(&done);
fclose(statfile);
}
#endif
extern plane * arena;
static void
fix_age(void)
{
faction * f;
for (f=factions;f;f=f->next) {
if (f->no!=MONSTER_FACTION && playerrace(f->race)) continue;
if (f->age!=turn) {
log_printf("Alter von Partei %s auf %d angepasst.\n", factionid(f), turn);
f->age = turn;
}
}
}
#if 0
static boolean
balsambug(const region *r)
{
direction_t dir;
for (dir=0; dir<MAXDIRECTIONS; dir++) {
if (landregion(rterrain(rconnect(r, dir))) && rdemand(r,0) > 0)
return false;
}
return true;
}
static void
fix_balsamfiasko(void)
{
region *r, *rc;
direction_t dir;
int i;
for (r=regions; r; r=r->next) freset(r, RF_DH);
/* Zufällig verteilen */
for (r=regions; r; r=r->next) {
if (r->x < -36 && r->y < -45 && landregion(rterrain(r))) {
if(rdemand(r,0) <= 0 && balsambug(r)) {
rsetdemand(r,0,(char)(1+rand()%5));
rsetdemand(r,rand()%7,0);
fset(r, RF_DH);
}
}
}
/* Smoothing */
for(i=0; i<3; i++) {
for (r=regions; r; r=r->next) if(fval(r, RF_DH)) {
for (dir=0; dir < MAXDIRECTIONS; dir++) {
rc = rconnect(r, dir);
if(rc && fval(rc, RF_DH) && rand()%100 < 20) {
int p1, p2;
for (p1 = 0; p1 != MAXLUXURIES; p1++)
if (rdemand(r, p1) == 0) break;
for (p2 = 0; p2 != MAXLUXURIES; p2++)
if (rdemand(rc, p2) == 0) break;
if(p1 != p2) {
rsetdemand(rc, p2, (char)(1+rand()%5));
rsetdemand(rc, p1, 0);
}
}
}
}
}
}
#endif
#if 1
static int
count_demand(const region *r)
{
struct demand *dmd;
int c = 0;
if (r->land) {
for (dmd=r->land->demands;dmd;dmd=dmd->next) c++;
}
return c;
}
#endif
static int
recurse_regions(region * r, regionlist **rlist, boolean(*fun)(const region * r))
{
if (!fun(r)) return 0;
else {
int len = 0;
direction_t d;
regionlist * rl = calloc(sizeof(regionlist), 1);
rl->next = *rlist;
rl->region = r;
(*rlist) = rl;
fset(r, FL_MARK);
for (d=0;d!=MAXDIRECTIONS;++d) {
region * nr = rconnect(r, d);
if (nr && !fval(nr, FL_MARK)) len += recurse_regions(nr, rlist, fun);
}
return len+1;
}
}
#if 1
static int maxluxuries = 0;
static boolean
f_nolux(const region * r)
{
if (r->land && count_demand(r) != maxluxuries) return true;
return false;
}
static int
fix_demand_region(region *r)
{
regionlist *rl, *rlist = NULL;
static const luxury_type **mlux = 0, ** ltypes;
const luxury_type *sale = NULL;
int maxlux = 0;
recurse_regions(r, &rlist, f_nolux);
if (mlux==0) {
int i = 0;
if (maxluxuries==0) for (sale=luxurytypes;sale;sale=sale->next) {
maxluxuries++;
}
mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *)));
ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *)));
for (sale=luxurytypes;sale;sale=sale->next) {
ltypes[i++] = sale;
}
}
else {
int i;
for (i=0;i!=maxluxuries;++i) mlux[i] = 0;
}
for (rl=rlist;rl;rl=rl->next) {
region * r = rl->region;
direction_t d;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * nr = rconnect(r, d);
if (nr && nr->land && nr->land->demands) {
struct demand * dmd;
for (dmd = nr->land->demands;dmd;dmd=dmd->next) {
if (dmd->value == 0) {
int i;
for (i=0;i!=maxluxuries;++i) {
if (mlux[i]==NULL) {
maxlux = i;
mlux[i] = dmd->type;
break;
} else if (mlux[i]==dmd->type) {
break;
}
}
break;
}
}
}
}
freset(r, FL_MARK); /* undo recursive marker */
}
if (maxlux<2) {
int i;
for (i=maxlux;i!=2;++i) {
int j;
do {
int k = rand() % maxluxuries;
mlux[i] = ltypes[k];
for (j=0;j!=i;++j) {
if (mlux[j]==mlux[i]) break;
}
} while (j!=i);
}
maxlux=2;
}
for (rl=rlist;rl;rl=rl->next) {
region * r = rl->region;
log_warning(("fixing demand in %s\n", regionname(r, NULL)));
setluxuries(r, mlux[rand() % maxlux]);
}
while (rlist) {
rl = rlist->next;
free(rlist);
rlist = rl;
}
return 0;
}
#endif
static void
fix_firewalls(void)
{
region * r = regions;
while (r) {
direction_t d;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * r2 = rconnect(r, d);
if (r2) {
border * b = get_borders(r, r2);
while (b) {
if (b->type==&bt_firewall) {
attrib * a = a_find(b->attribs, &at_countdown);
if (a==NULL || a->data.i <= 0) {
erase_border(b);
log_warning(("firewall between regions %s and %s was bugged. removed.\n",
regionid(r), regionid(r2)));
b = get_borders(r, r2);
} else {
b = b->next;
}
} else {
b = b->next;
}
}
}
}
r = r->next;
}
}
extern attrib * make_atgmcreate(const struct item_type * itype);
extern attrib * make_atpermissions(void);
extern struct attrib_type at_permissions;
extern struct attrib_type at_gmcreate;
static void
update_gms(void)
{
faction * f;
for (f=factions;f;f=f->next) {
attrib * permissions = a_find(f->attribs, &at_permissions);
if (permissions) {
const char * keys[] = { "gmgate", "gmmsgr", "gmkill", "gmmsgu", NULL };
int k;
item_t i;
for (k=0;keys[k];++k) {
add_key((attrib**)&permissions->data.v, atoi36(keys[k]));
}
for (i=I_GREATSWORD;i!=I_KEKS;++i) {
attrib * a = a_find(permissions, &at_gmcreate);
while (a && a->data.v!=(void*)olditemtype[i]) a=a->nexttype;
if (!a) a_add((attrib**)&permissions->data.v, make_atgmcreate(olditemtype[i]));
}
}
}
}
static int
fix_gms(void)
{
faction * f;
for (f=factions;f;f=f->next) {
attrib * permissions = a_find(f->attribs, &at_permissions);
if (permissions) {
const char * keys[] = { "gmgate", "gmmsgr", "gmmsgr", "gmmsgu", NULL };
int k;
item_t i;
for (k=0;keys[k];++k) {
attrib * a = find_key((attrib*)permissions->data.v, atoi36("gmgate"));
if (a) {
attrib ** ap = &a->nexttype;
while (*ap) {
attrib * an = *ap;
if (a->data.i==an->data.i) a_remove(ap, an);
else ap = &an->next;
}
}
}
for (i=I_GREATSWORD;i!=I_KEKS;++i) {
attrib * a = a_find(permissions, &at_gmcreate);
while (a && a->data.v!=(void*)olditemtype[i]) a=a->nexttype;
if (a) {
attrib ** ap = &a->nexttype;
while (*ap) {
attrib * an = *ap;
if (a->data.v==an->data.v) a_remove(ap, an);
else ap = &an->next;
}
}
}
}
}
return 0;
}
#if 1
static int
fix_demand(void)
{
region *r;
const luxury_type *sale = NULL;
if (maxluxuries==0) for (sale=luxurytypes;sale;sale=sale->next) ++maxluxuries;
for (r=regions; r; r=r->next) {
if ((r->land) && count_demand(r) != maxluxuries) {
fix_demand_region(r);
}
}
return 0;
}
#endif
#if 0
static void
read_laenrepair(boolean active)
{
FILE * f = fopen("repair.laen", "rt");
FILE * log = fopen("report.laen", "wt");
if (!f || !log) return;
while (!feof(f)) {
int n, x, y;
region * r;
fscanf(f, "%d %d %d", &x, &y, &n);
r = findregion(x, y);
if (!r) fprintf(log, "%d,%d:\tnot found\n", x, y);
else if (fval(r, RF_CHAOTIC)) continue;
else {
int laen = rlaen(r);
if (n==-1 && laen>=0) {
fprintf(log, "%d,%d:\tillegal laen (%d)\n", x, y, laen);
if (active) rsetlaen(r, n);
} else if (laen==-1 && n!=-1) {
fprintf(log, "%d,%d:\tlaen was lost (%d)\n", x, y, n);
if (active) rsetlaen(r, n);
}
}
}
fclose(f);
}
static void
write_laenrepair(void) {
FILE * f = fopen("repair.laen", "wt");
region * r;
for (r=regions;r;r=r->next) if (!fval(r, RF_CHAOTIC)) {
int laen = rlaen(r);
fprintf(f, "%d %d %d\n", r->x, r->y, laen);
}
fclose(f);
}
#endif
#include "group.h"
static void
fix_allies(void) {
faction * f;
for (f=factions;f;f=f->next) {
group * g;
for (g=f->groups;g;g=g->next) {
ally ** ap=&g->allies;
while (*ap) {
ally * an, * a = *ap;
for (an = a->next;an;an=an->next) {
if (a->faction==an->faction) {
*ap = a->next;
free(a);
break;
}
}
if (an==NULL) ap = &(*ap)->next;
}
}
}
}
#ifdef FUZZY_BASE36
extern boolean enable_fuzzy;
#endif
static void
fix_icastles(void)
{
region * r;
for (r=regions; r; r=r->next) {
building * b;
for (b=r->buildings; b; b=b->next) {
attrib * a;
const building_type * btype = &bt_castle;
icastle_data * data;
a = a_find(b->attribs, &at_icastle);
if (b->type!=&bt_illusion && !a) continue;
if (!a) {
/* attribut hat gefehle */
a = a_add(&b->attribs, a_new(&at_icastle));
}
if (b->type!=&bt_illusion) {
/* gebäudetyp war falsch */
btype = b->type;
b->type = &bt_illusion;
}
data = (icastle_data*)a->data.v;
if (data->time<=0) {
/* zeit war kaputt oder abgelaufen */
data->time = 1;
}
if (!data->type) {
/* typ muss gesetzt werden, weil er nicht geladen wurde */
data->type = btype;
}
if (data->building!=b) {
/* rückwärtszeiger auf das gebäude reparieren */
data->building=b;
}
}
}
}
#if 0
static void
fix_ponnukis(void)
/* Es kann nur einen geben! */
{
unit * ponn = findunit(atoi36("ponn"));
if (ponn) {
region * mag = ponn->region;
unit * u;
for (u=mag->units;u;u=u->next) {
if (u!=ponn && u->faction==ponn->faction && u->race==ponn->race && !strcmp(ponn->name, u->name)) {
set_number(u, 0);
}
}
}
}
#endif
#if 0
static void
fix_traveldir(void)
{
region *r;
attrib *a, *a2;
traveldir *t;
for(r=regions; r; r=r->next) {
a = a_find(r->attribs, &at_traveldir);
while (a) {
a2 = a_add(&r->attribs, a_new(&at_traveldir_new));
t = (traveldir *)(a2->data.v);
t->no = a->data.sa[0];
t->dir = a->data.ca[2];
t->age = a->data.ca[3];
a = a->nexttype;
}
}
for(r=regions; r; r=r->next) {
a = a_find(r->attribs, &at_traveldir);
while(a) {
a_remove(&r->attribs, a);
a = a->nexttype;
}
}
}
#endif
static void
stats(void)
{
FILE * F;
item * items = NULL;
char zText[MAX_PATH];
strcat(strcpy(zText, resourcepath()), "/stats");
F = fopen(zText, "wt");
if (F) {
region * r;
const item_type * itype;
for (r=regions;r;r=r->next) {
unit * u;
item * itm;
for (u=r->units;u;u=u->next) {
for (itm=u->items;itm;itm=itm->next) {
i_change(&items, itm->type, itm->number);
}
}
}
for (itype=itemtypes;itype;itype=itype->next) {
item * itm = *i_find(&items, itype);
if (itm && itm->number)
fprintf(F, "%4d %s\n", itm->number, locale_string(NULL, resourcename(itype->rtype, 0)));
else
fprintf(F, "%4d %s\n", 0, locale_string(NULL, resourcename(itype->rtype, 0)));
}
fclose(F);
} else {
perror(zText);
}
}
#if 0
static void
fix_prices(void)
{
region *r;
puts(" - Korrigiere Handelsgüterpreise");
for(r=regions; r; r=r->next) if(r->land) {
int sales = 0, buys = 0;
const luxury_type *sale = NULL, *ltype;
struct demand *dmd;
for (dmd=r->land->demands;dmd;dmd=dmd->next) {
if(dmd->value == 0) {
sales++;
sale = dmd->type;
} else {
buys++;
}
}
if(sales == 0) {
int c = 0;
for(ltype=luxurytypes; ltype; ltype=ltype->next) c++;
c = rand()%c;
for(ltype=luxurytypes; c>0; c--) ltype=ltype->next;
r_setdemand(r, ltype, 0);
sale = ltype;
}
assert(sale);
if(buys == 0) {
for(ltype=luxurytypes; ltype; ltype=ltype->next) {
if(ltype != sale) r_setdemand(r, ltype, 1 + rand() % 5);
}
}
}
}
static void
fix_options(void)
{
faction *f;
puts(" - Korrigiere Parteioptionen");
for(f=factions;f;f=f->next) {
f->options = f->options | Pow(O_REPORT);
f->options = f->options | Pow(O_ZUGVORLAGE);
}
}
static void
init_region_age(void)
{
region *r;
puts(" - Initialisiere r->age");
/* Initialisieren mit dem Alter der ältesten Partei in 2 Feldern
* Umkreis */
for(r=regions; r; r=r->next) {
regionlist *rl = all_in_range(r,2);
regionlist *rl2;
unit *u;
int maxage = 0;
for(rl2 = rl; rl2; rl2 = rl2->next) {
for(u=rl2->region->units; u; u=u->next) {
if(u->faction->age > maxage) maxage = u->faction->age;
}
}
r->age = (unsigned short)maxage;
}
}
static void
fix_herbtypes(void)
{
region * r;
for (r=regions;r!=NULL;r=r->next) if (r->land) {
const herb_type * htype = r->land->herbtype;
if (htype==NULL) {
if (terrain[r->terrain].herbs!=NULL) {
const item_type * itype;
int i=0;
while (terrain[r->terrain].herbs[i]!=NULL) ++i;
itype = finditemtype(terrain[r->terrain].herbs[rand()%i], NULL);
r->land->herbtype = resource2herb(itype->rtype);
}
} else {
if (r->terrain==T_PLAIN) {
if (r_isforest(r)) {
int i = rand()%3+3;
const char * name = terrain[T_PLAIN].herbs[i];
const item_type * itype = finditemtype(name, NULL);
r->land->herbtype = resource2herb(itype->rtype);
}
} else {
/* Das geht so nicht, wegen der Eisberg-Terrains */
/* assert(htype->terrain==r->terrain); */
}
}
}
}
#endif
#ifdef SKILLFIX_SAVE
typedef struct skillfix_data {
unit * u;
skill_t skill;
int value;
int number;
int self;
int teach;
} skillfix_data;
static void
init_skillfix(attrib * a)
{
a->data.v = calloc(sizeof(skillfix_data), 1);
}
static void
free_skillfix(attrib * a)
{
free(a->data.v);
}
attrib_type at_skillfix = { "skillfix", init_skillfix, free_skillfix };
void
skillfix(struct unit * u, skill_t skill, int from, int self, int teach)
{
attrib * a = a_add(&u->attribs, a_new(&at_skillfix));
skillfix_data * data = (skillfix_data*)a->data.v;
data->u = u;
data->skill = skill;
data->number = u->number;
data->value = from;
data->self = self;
data->teach = teach;
}
void
write_skillfix(void)
{
FILE * F = fopen("skills.fix", "w+");
region * r;
fprintf(F, "S%d\n", turn);
for (r=regions;r;r=r->next) {
unit * u;
for (u=r->units;u;u=u->next) {
attrib * a = a_find(u->attribs, &at_skillfix);
while (a) {
skillfix_data * data = (skillfix_data*)a->data.v;
fprintf(F, "%s %d %d %d %d %d\n",
itoa36(data->u->no),
data->skill,
data->number,
data->value,
data->self,
data->teach);
a = a->nexttype;
}
}
}
fclose(F);
}
#endif
#if 0
static void
init_mwarden(void)
{
unit *u = findunitg(atoi36("mwar"), NULL);
attrib *a;
if(!u) return;
a = a_add(&u->attribs, a_new(&at_warden));
a->data.i = 0;
}
#endif
#ifdef CONVERT_TRIGGER
#include "old/relation.h"
#include "old/trigger.h"
#include "old/trigger_internal.h"
#include <event.h>
#include <triggers/killunit.h>
#include <triggers/timeout.h>
#include <triggers/changerace.h>
#include <triggers/changefaction.h>
#include <triggers/createunit.h>
#include <triggers/giveitem.h>
#include <triggers/createcurse.h>
#include <triggers/shock.h>
typedef struct {
void *obj2;
typ_t typ2;
relation_t id;
spread_t spread;
} reldata;
extern timeout *all_timeouts;
static void
convert_triggers(void)
{
region * r=regions;
timeout * t;
while (r) {
unit * u = r->units;
while (u) {
attrib * a = a_find(u->attribs, &at_relation);
while (a) {
reldata *rel = (reldata *)a->data.v;
unit * u2 = (unit*)rel->obj2;
switch (rel->id) {
case REL_FAMILIAR:
if (u && u2) {
if (!playerrace(u->race) || (playerrace(u2->race) && u->race==RC_GOBLIN))
set_familiar(u2, u);
else
set_familiar(u, u2);
} else {
if (u2) fprintf(stderr, "WARNING: FAMILIAR info for %s may be broken!\n", unitname(u2));
if (u) fprintf(stderr, "WARNING: FAMILIAR info for %s may be broken!\n", unitname(u));
}
break;
case REL_CREATOR:
break;
case REL_TARGET:
fprintf(stderr, "WARNING: TARGET relation between %s and 0x%p not converted\n", unitname(u), u2);
break;
default:
fprintf(stderr, "WARNING: unknown relation %d between %s and 0x%p not converted\n", rel->id, unitname(u), u2);
break;
}
a = a->nexttype;
}
u = u->next;
}
r=r->next;
}
for (t=all_timeouts;t;t=t->next) {
actionlist * al = t->acts;
int time = t->ticks;
for (;al;al=al->next) {
action * act = al->act;
if (act) switch( act->atype ) {
case AC_DESTROY: {
/* conversion keeper */
unit * u = (unit*)act->obj;
trigger * tkill = trigger_killunit(u);
add_trigger(&u->attribs, "timer", trigger_timeout(time, tkill));
}
case AC_CHANGERACE: {
/* conversion for toads */
unit *u = (unit*)act->obj;
race_t race = (race_t)act->i[0];
race_t irace = (race_t)act->i[1];
trigger * trestore = trigger_changerace(u, race, irace);
if (rand()%10>2) t_add(&trestore, trigger_giveitem(u, olditemtype[I_TOADSLIME], 1));
add_trigger(&u->attribs, "timer", trigger_timeout(time, trestore));
break;
}
case AC_CHANGEIRACE: {
/* conversion for shapeshift */
unit *u = (unit*)act->obj;
race_t irace = (race_t)act->i[0];
trigger * trestore = trigger_changerace(u, NORACE, irace);
add_trigger(&u->attribs, "timer", trigger_timeout(time, trestore));
break;
}
case AC_CHANGEFACTION: {
/* charmingsong */
faction *f = findfaction_unique_id(act->i[0]);
unit *u = (unit*)act->obj;
trigger *trestore = trigger_changefaction(u, f);
add_trigger(&u->attribs, "timer", trigger_timeout(time, trestore));
add_trigger(&u->faction->attribs, "destroy", trigger_killunit(u));
add_trigger(&f->attribs, "destroy", trigger_killunit(u));
break;
}
case AC_CREATEUNIT: {
/* conversion summon_dragon */
faction *f = findfaction_unique_id(act->i[0]);
region *r = (region *)act->obj;
int number = act->i[1];
race_t race = (race_t)act->i[2];
trigger *tsummon = trigger_createunit(r, f, race, number);
add_trigger(&r->attribs, "timer", trigger_timeout(time, tsummon));
break;
}
case AC_CREATEMAGICBOOSTCURSE:{
/* delayed magic boost curse */
unit *mage = (unit*)act->obj;
trigger *tsummon = trigger_createcurse(mage, mage, C_AURA, 0, act->i[0], 6, 50, 1);
add_trigger(&mage->attribs, "timer", trigger_timeout(5, tsummon));
break;
}
default:
fprintf(stderr, "WARNING: timeout not converted\n");
}
}
}
}
#endif
#if 0
#include <items/lmsreward.h>
static void
lms_special(unit * u)
{
if (u) i_change(&u->items, &it_lmsreward, 1);
}
#endif
#if 0
#define LIFEEXPECTANCY (27*40)
static void
undo_deadpeasants(void)
{
region * r = regions;
while (r) {
int dead = rpeasants(r) / LIFEEXPECTANCY;
deathcounts(r, -dead);
r = r->next;
}
}
static void
fix_undead3percent(void)
{
region * r = regions;
while (r) {
int dead = deathcount(r);
deathcounts(r, -(dead/2));
r = r->next;
}
}
static void
fix_targetregion_resolve(void)
{
region *r;
unit *u;
attrib *a;
for(r=regions; r; r=r->next) {
for(u=r->units; u; u=u->next) {
a = a_find(u->attribs, &at_targetregion);
if(a) a->data.v = findregion(a->data.sa[0], a->data.sa[1]);
}
}
}
static void
fix_herbs(void)
{
const char * plain_herbs[] = {"Flachwurz", "Würziger Wagemut", "Eulenauge", "Grüner Spinnerich", "Blauer Baumringel", "Elfenlieb"};
const herb_type * htypes[6];
int herbs[6];
int hneed[6];
region *r;
int i, hsum = 0, left = 0;
for (i=0;i!=6;++i) {
htypes[i] = resource2herb(finditemtype(plain_herbs[i], NULL)->rtype);
herbs[i] = 0;
}
for (r=regions; r; r=r->next) if (rterrain(r) == T_PLAIN) {
const herb_type *htype = rherbtype(r);
if (htype==NULL) {
htype = htypes[i];
rsetherbtype(r, htype);
}
for (i=0;i!=6;++i) if (htypes[i]==htype) break;
assert(i!=6);
herbs[i]++;
hsum++;
}
for (i=0;i!=6;++i) {
int hwant = hsum / (6-i);
hneed[i] = hwant - herbs[i];
if (hneed[i]>0) left += hneed[i];
hsum -= hwant;
}
for (r=regions; r; r=r->next) if (rterrain(r) == T_PLAIN) {
const herb_type *htype = rherbtype(r);
assert(htype);
for (i=0;i!=6;++i) if (htypes[i]==htype) break;
assert(i!=6);
if (hneed[i]<0) {
int p;
int k = rand() % left;
for (p=0;p!=6;++p) if (hneed[p]>0) {
k-=hneed[p];
if (k<0) break;
}
assert(p!=6);
hneed[p]--;
hneed[i]++;
left--;
rsetherbtype(r, htypes[p]);
}
hsum++;
}
for (i=0;i!=6;++i) herbs[i] = 0;
for (r=regions; r; r=r->next) if (rterrain(r) == T_PLAIN) {
const herb_type *htype = rherbtype(r);
assert(htype);
for (i=0;i!=6;++i) if (htypes[i]==htype) break;
assert(i!=6);
herbs[i]++;
}
for (i=0;i!=6;++i) {
fprintf(stderr, "%s : %d\n", locale_string(NULL, resourcename(htypes[i]->itype->rtype, 0)), herbs[i]);
}
}
#endif
#include <event.h>
#include <triggers/timeout.h>
#include <triggers/changerace.h>
#include <triggers/changefaction.h>
#include <triggers/createcurse.h>
#include <triggers/createunit.h>
#include <triggers/killunit.h>
#include <triggers/giveitem.h>
typedef struct handler_info {
char * event;
trigger * triggers;
} handler_info;
typedef struct timeout_data {
trigger * triggers;
int timer;
variant trigger_data;
} timeout_data;
trigger *
get_timeout(trigger * td, trigger * tfind)
{
trigger * t = td;
while (t) {
if (t->type==&tt_timeout) {
timeout_data * tdata = (timeout_data *)t->data.v;
trigger * tr = tdata->triggers;
while (tr) {
if (tr==tfind) break;
tr=tr->next;
}
if (tr==tfind) break;
}
t=t->next;
}
return t;
}
#if 0
static void
fix_timeouts(void)
{
region * r;
for (r=regions;r;r=r->next) {
unit * u;
for (u=r->units;u;u=u->next) {
attrib * a = a_find(u->attribs, &at_eventhandler);
boolean toad = (u->race==RC_TOAD);
boolean keeper = (u->race==RC_IRONKEEPER);
while (a!=NULL) {
trigger * t;
handler_info * td = (handler_info *)a->data.v;
for (t=td->triggers;t;t=t->next) {
trigger ** tptr=&t->next;
while (*tptr) {
/* remove duplicates */
if ((*tptr)->type==t->type) {
*tptr = (*tptr)->next;
} else tptr = &(*tptr)->next;
}
if (t->type == &tt_changerace ||
t->type == &tt_changefaction ||
t->type == &tt_createcurse ||
t->type == &tt_createunit)
{
trigger * timer = get_timeout(td->triggers, t);
if (toad && t->type == &tt_changerace) {
toad = false;
}
if (timer==NULL) {
add_trigger(&u->attribs, "timer", trigger_timeout(1+(rand()%2), t));
}
}
else if (t->type == &tt_killunit) {
if (u->race==RC_IRONKEEPER) {
trigger * timer = get_timeout(td->triggers, t);
keeper = false;
if (timer==NULL) {
add_trigger(&u->attribs, "timer", trigger_timeout(1+(rand()%2), t));
}
}
}
}
a = a->nexttype;
}
if (keeper) {
int duration = 1+ (rand() % 2);
trigger * tkill = trigger_killunit(u);
add_trigger(&u->attribs, "timer", trigger_timeout(duration, tkill));
}
if (toad) {
/* repair toad-only mage */
int duration = 1+ (rand() % 2);
trigger * trestore = trigger_changerace(u, u->faction->race, u->faction->race);
if (rand()%10>2) t_add(&trestore, trigger_giveitem(u, olditemtype[I_TOADSLIME], 1));
add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore));
}
}
}
}
#endif
#include <modules/gmcmd.h>
static int
regatta_quest(void)
{
plane * p = gm_addplane(20, PFL_NORECRUITS, "Regatta");
region * center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2);
gm_addfaction("gregorjochmann@gmx.de", p, center);
return 0;
}
static int
secondfaction(faction * pf)
{
unit * u = findunit(atoi36("5q9w"));
if (u!=NULL) {
plane * p = rplane(u->region);
if (p!=NULL) {
region * center = findregion((p->maxx-p->minx)/2, (p->maxy-p->miny)/2);
if (center!=NULL) {
gm_addfaction(pf->email, p, center);
return 0;
}
}
}
return -1;
}
static void
update_gmquests(void)
{
/* gm04 will keine Orks */
faction * f = findfaction(atoi36("gm04"));
if (f) {
unit * u = f->units;
potion_t p;
attrib * permissions = a_find(f->attribs, &at_permissions);
do_once("et02", secondfaction(f));
if (u!=NULL) {
plane * p = rplane(u->region);
if (p!=NULL) p->flags |= PFL_NOORCGROWTH;
}
for (p=0;p!=MAX_POTIONS;++p) {
attrib * a = a_find(permissions, &at_gmcreate);
while (a && a->data.v!=(void*)oldpotiontype[p]->itype) a=a->nexttype;
if (!a) a_add((attrib**)&permissions->data.v, make_atgmcreate(oldpotiontype[p]->itype));
}
}
do_once("rq01", regatta_quest());
}
#if 0
static void
test_gmquest(void)
{
const struct faction * f;
/* enno's world */
f = gm_addquest("enno@eressea.upb.de", "GM Zone", 1, PFL_NOATTACK|PFL_NOALLIANCES|PFL_NOFEED|PFL_FRIENDLY);
log_printf("Neue Questenpartei %s\n", factionname(f));
f = gm_addquest("xandril@att.net", "Mardallas Welt", 40, 0);
log_printf("Neue Questenpartei %s\n", factionname(f));
f = gm_addquest("moritzsalinger@web.de", "Laen-Kaiser", 7, /*PFL_NORECRUITS |*/ PFL_NOMAGIC /*| PFL_NOBUILD*/);
log_printf("Neue Questenpartei %s\n", factionname(f));
f = gm_addquest("Denise.Muenstermann@home.gelsen-net.de", "Mochikas Queste", 7, PFL_NOMAGIC);
log_printf("Neue Questenpartei %s\n", factionname(f));
f = gm_addquest("feeron@aol.com", "Eternath", 11, 0);
log_printf("Neue Questenpartei %s\n", factionname(f));
f = gm_addquest("BigBear@nord-com.net", "Leonidas Vermächtnis", 15, PFL_NOMAGIC|PFL_NOSTEALTH);
log_printf("Neue Questenpartei %s\n", factionname(f));
}
#endif
#define TEST_LOCALES 0
#if TEST_LOCALES
static void
setup_locales(void)
{
locale * lang = find_locale("en");
faction * f = factions;
while (f) {
f->locale = lang;
f = f->next;
}
}
#endif
#include <triggers/shock.h>
#include <triggers/killunit.h>
#if 0
#error "this is broken, it duplicates triggers"
static void
fix_unitrefs(void)
{
region * r=regions;
while (r) {
unit * u = r->units;
while (u) {
attrib * a;
a = a_find(u->attribs, &at_familiar);
if (a) {
/* magier, hat einen familiar */
unit * ufamiliar = get_familiar(u);
if (ufamiliar) {
attrib * ae;
/* killunit attribut am magier */
ae = a_find(u->attribs, &at_eventhandler);
if (ae) {
trigger * tkillunit = NULL;
trigger ** tlist = get_triggers(u->attribs, "destroy");
if (tlist!=NULL) {
tkillunit = *tlist;
while (tkillunit) {
if (strcmp(tkillunit->type->name, "killunit")==0) break;
tkillunit = tkillunit->next;
}
if (tkillunit && !tkillunit->data.v) {
log_warning(("killunit-trigger für Magier %s und Vertrauten %s restauriert.\n",
itoa36(u->no), itoa36(ufamiliar->no)));
tkillunit->data.v = ufamiliar;
}
else ae = NULL;
}
}
if (ae==NULL) {
/* Wenn der Magier stirbt, dann auch der Vertraute */
add_trigger(&u->attribs, "destroy", trigger_killunit(ufamiliar));
}
/* killunit attribut am magier */
ae = a_find(ufamiliar->attribs, &at_eventhandler);
if (ae) {
trigger * tshockunit = NULL;
trigger ** tlist = get_triggers(ufamiliar->attribs, "destroy");
if (tlist!=NULL) {
tshockunit = *tlist;
while (tshockunit) {
if (strcmp(tshockunit->type->name, "shock")==0) break;
tshockunit = tshockunit->next;
}
if (tshockunit && !tshockunit->data.v) {
log_warning(("shockunit-trigger für Magier %s und Vertrauten %s restauriert.\n",
itoa36(u->no), itoa36(ufamiliar->no)));
tshockunit->data.v = u;
}
else ae = NULL;
}
}
if (ae==NULL) {
/* Wenn der Vertraute stirbt, schockt er den Magier */
add_trigger(&ufamiliar->attribs, "destroy", trigger_shock(u));
}
} else {
log_error(("Magier %s hat ein at_familiar, aber keinen Vertrauten.\n",
itoa36(u->no)));
}
}
u = u->next;
}
r=r->next;
}
}
#endif
static void
update_igjarjuk_quest(void)
{
unit * u;
faction *f = findfaction(atoi36("rr"));
if (!f) return;
for (u=f->units;u;u=u->nextF) {
u->race = new_race[RC_TEMPLATE];
}
}
#if RESOURCE_CONVERSION
extern struct attrib_type at_resources;
void
init_resourcefix(void)
{
at_register(&at_resources);
}
static int
read_resfix(void)
{
#if 0
FILE * F = fopen("resource.fix", "r");
if (F==NULL) return;
while (!feof(F)) {
int x, y, stone, iron, laen, age;
int lstone, liron, llaen; /* level */
region * r;
fscanf(F, "%d %d %d %d %d %d %d %d %d\n", &x, &y, &age, &stone, &iron, &laen, &lstone, &liron, &llaen);
r = findregion(x, y);
if (r) {
rawmaterial * rm = r->resources;
while (rm) {
if (rm->type==&rm_iron && liron>0) {
rm->amount = iron;
rm->level = liron;
}
else if (rm->type==&rm_laen && llaen>0) {
rm->amount = laen;
rm->level = llaen;
}
else if (rm->type==&rm_stones && lstone>0) {
rm->amount = stone;
rm->level = lstone;
}
rm = rm->next;
}
r->age = (unsigned short)age;
}
}
fclose(F);
#else
return -1;
#endif
}
static int
convert_resources(void)
{
#if 0
region *r;
for(r=regions;r;r=r->next) {
attrib *a = a_find(r->attribs, &at_resources);
r->resources = 0;
terraform_resources(r);
if (a==NULL) continue;
else {
int INIT_STONE = 20; /* skip this many weeks */
double ironmulti = 0.40;
double laenmulti = 0.50;
double stonemulti = 0.30; /* half the stones used */
rawmaterial * rmiron = rm_get(r, rm_iron.rtype);
rawmaterial * rmlaen = rm_get(r, rm_laen.rtype);
rawmaterial * rmstone = rm_get(r, rm_stones.rtype);
int oldiron;
int oldlaen = MAXLAENPERTURN * min(r->age, 100) / 2;
int oldstone = terrain[rterrain(r)].quarries * max(0, r->age - INIT_STONE);
int iron = a->data.sa[0];
int laen = a->data.sa[1];
int stone, level;
int i, base;
/** STONE **/
for (i=0;terrain[r->terrain].rawmaterials[i].type;++i) {
if (terrain[r->terrain].rawmaterials[i].type == &rm_stones) break;
}
if (terrain[r->terrain].rawmaterials[i].type) {
base = terrain[r->terrain].rawmaterials[i].base;
stone = max (0, (int)(oldstone * stonemulti));
level = 1;
base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor));
while (stone >= base) {
stone-=base;
++level;
base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor));
}
rmstone->level = level;
rmstone->amount = base - stone;
assert (rmstone->amount > 0);
log_printf("CONVERSION: %d stones @ level %d in %s\n", rmstone->amount, rmstone->level, regionname(r, NULL));
} else {
log_error(("found stones in %s of %s\n", terrain[r->terrain].name, regionname(r, NULL)));
}
/** IRON **/
if (r_isglacier(r) || r->terrain==T_ICEBERG) {
oldiron = GLIRONPERTURN * min(r->age, 100) / 2;
} else {
oldiron = IRONPERTURN * r->age;
}
for (i=0;terrain[r->terrain].rawmaterials[i].type;++i) {
if (terrain[r->terrain].rawmaterials[i].type == &rm_iron) break;
}
if (terrain[r->terrain].rawmaterials[i].type) {
base = terrain[r->terrain].rawmaterials[i].base;
iron = max(0, (int)(oldiron * ironmulti - iron ));
level = 1;
base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor));
while (iron >= base) {
iron-=base;
++level;
base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor));
}
rmiron->level = level;
rmiron->amount = base - iron;
assert (rmiron->amount > 0);
log_printf("CONVERSION: %d iron @ level %d in %s\n", rmiron->amount, rmiron->level, regionname(r, NULL));
} else {
log_error(("found iron in %s of %s\n", terrain[r->terrain].name, regionname(r, NULL)));
}
/** LAEN **/
if (laen>=0) {
if (rmlaen==NULL) {
rmlaen = calloc(sizeof(rawmaterial), 1);
rmlaen->next = r->resources;
r->resources = rmlaen;
}
for (i=0;terrain[r->terrain].rawmaterials[i].type;++i) {
if (terrain[r->terrain].rawmaterials[i].type == &rm_laen) break;
}
if (terrain[r->terrain].rawmaterials[i].type) {
laen = max(0, (int)(oldlaen * laenmulti - laen));
level = 1;
base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor));
while (laen >= base) {
laen-=base;
++level;
base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor));
}
rmlaen->level = level;
rmlaen->amount = base - laen;
assert(rmlaen->amount>0);
log_printf("CONVERSION: %d laen @ level %d in %s\n", rmlaen->amount, rmlaen->level, regionname(r, NULL));
rmlaen = NULL;
}
}
if (rmlaen) {
struct rawmaterial *res;
struct rawmaterial ** pres = &r->resources;
if (laen!=-1) log_error(("found laen in %s of %s\n", terrain[r->terrain].name, regionname(r, NULL)));
while (*pres!=rmlaen) pres = &(*pres)->next;
res = *pres;
*pres = (*pres)->next;
free(res);
}
#ifndef NDEBUG
{
rawmaterial * res = r->resources;
while (res) {
assert(res->amount>0);
assert(res->level>0);
res = res->next;
}
}
#endif
}
}
return 0;
#else
return -1;
#endif
}
#endif
#if 0
static int
convert_resources(void)
{
region *r;
attrib *a;
for(r=regions;r;r=r->next) {
/* Iron */
if(rterrain(r) == T_MOUNTAIN) {
a_add(&r->attribs, a_new(&at_iron))->data.i = 25;
} else if(rterrain(r) == T_GLACIER || rterrain(r) == T_ICEBERG_SLEEP) {
a_add(&r->attribs, a_new(&at_iron))->data.i = 2;
}
/* Laen */
if(rterrain(r) == T_MOUNTAIN) {
a = a_find(r->attribs, &at_laen);
if(a) a->data.i = 6;
}
/* Stone */
if(terrain[rterrain(r)].quarries > 0) {
a_add(&r->attribs, a_new(&at_stone))->data.i = terrain[rterrain(r)].quarries;
}
}
return 0;
}
static void
fix_negpotion(void)
{
region *r;
unit *u;
int i;
for(r=regions; r; r=r->next) {
for(u=r->units; u; u=u->next) {
i = get_effect(u, oldpotiontype[P_FAST]);
if (i < 0){
change_effect(u, oldpotiontype[P_FAST], -i);
}
}
}
}
#endif
#if GROWING_TREES
int
growing_trees(void)
{
region *r;
for(r=regions; r; r=r->next) {
if(rtrees(r, 2)) {
rsettrees(r, 1, rtrees(r, 2)/4);
rsettrees(r, 0, rtrees(r, 2)/2);
}
}
return 0;
}
#endif
#include <triggers/gate.h>
#include <triggers/unguard.h>
typedef struct gate_data {
struct building * gate;
struct region * target;
} gate_data;
static void
fix_gates(void)
{
region * r;
for (r=regions;r;r=r->next) {
unit * u;
building * b;
for (u=r->units;u;u=u->next) {
trigger ** triggers = get_triggers(u->attribs, "timer");
if (triggers) {
trigger * t = *triggers;
while (t && t->type!= &tt_gate) t=t->next;
if (t!=NULL) {
gate_data * gd = (gate_data*)t->data.v;
struct building * b = gd->gate;
struct region * rtarget = gd->target;
if (r!=b->region) {
add_trigger(&b->attribs, "timer", trigger_gate(b, rtarget));
add_trigger(&b->attribs, "create", trigger_unguard(b));
fset(b, BLD_UNGUARDED);
}
}
remove_triggers(&u->attribs, "timer", &tt_gate);
remove_triggers(&u->attribs, "create", &tt_unguard);
}
}
for (b=r->buildings;b;b=b->next) {
trigger ** triggers = get_triggers(b->attribs, "timer");
if (triggers) {
trigger * t = *triggers;
while (t && t->type!= &tt_gate) t=t->next;
if (t!=NULL) {
gate_data * gd = (gate_data*)t->data.v;
struct building * b = gd->gate;
struct region * rtarget = gd->target;
remove_triggers(&b->attribs, "timer", &tt_gate);
remove_triggers(&b->attribs, "create", &tt_unguard);
if (r!=b->region) {
add_trigger(&b->attribs, "timer", trigger_gate(b, rtarget));
add_trigger(&b->attribs, "create", trigger_unguard(b));
fset(b, BLD_UNGUARDED);
}
}
}
}
}
}
static int
dump_sql(void)
{
faction * f;
for (f=factions;f;f=f->next) {
if (f->unique_id==0) {
f->unique_id = ++max_unique_id;
}
if (f->age!=1 && f->no!=MONSTER_FACTION) {
fprintf(sqlstream, "INSERT INTO users (id, email) VALUES (%d, '%s');\n",
f->unique_id, f->email);
fprintf(sqlstream, "INSERT INTO factions (id, user, name, password, race, locale, lastorders, banner, email) "
"VALUES ('%s', %d, '%s', '%s', '%s', '%s', %u, '%s', '%s');\n",
itoa36(f->no), f->unique_id, sqlquote(f->name), sqlquote(f->passw), LOC(default_locale, rc_name(f->race, 1)),
locale_name(f->locale), f->lastorders, sqlquote(f->banner), f->email);
}
}
return 0;
}
#if NEW_RESOURCEGROWTH
static int
randomized_resources(void)
{
region *r;
for(r = regions; r; r=r->next) if(r->land) {
terrain_t ter = rterrain(r);
/* Dieses if verhindert, das Laen nocheinmal verteilt wird. */
if(ter == T_MOUNTAIN || ter == T_GLACIER || ter == T_ICEBERG || ter == T_ICEBERG_SLEEP) continue;
terraform_resources(r);
}
return 0;
}
#endif
static int
fix_idleout(void)
{
faction *f;
f = findfaction(0);
if(f){
fset(f, FL_NOIDLEOUT);
}
f = findfaction(atoi36("muse"));
if(f){
fset(f, FL_NOIDLEOUT);
}
return 0;
}
static int
set_zip(void)
{
faction *f;
for(f=factions;f;f=f->next) {
if(!(f->options & (1 << O_BZIP2)) && !(f->options & (1 << O_COMPRESS))) {
f->options = f->options | (1 << O_COMPRESS);
}
}
f = findfaction(0);
f->options = f->options & ~(1 << O_COMPRESS);
f->options = f->options | (1 << O_BZIP2);
return 0;
}
static int
heal_all(void)
{
region *r;
unit *u;
faction *f;
message *msg = msg_message("healall","");
for(f=factions; f; f=f->next) {
freset(f, FL_DH);
}
for(r=regions; r; r=r->next) {
for(u=r->units;u;u=u->next) {
int max_hp = unit_max_hp(u) * u->number;
if(u->hp < max_hp) {
u->hp = max_hp;
fset(u->faction, FL_DH);
}
}
}
for (f=factions; f; f=f->next) {
if(fval(f,FL_DH)) {
add_message(&f->msgs, msg);
freset(f, FL_DH);
}
}
msg_release(msg);
return 0;
}
#if PEASANT_ADJUSTMENT == 1
#define WEIGHT ((double)0.5)
#define PLWEIGHT ((double)0.80)
static int
peasant_adjustment(void)
{
terrain_t ter;
int sum, avg, c;
double freeall, pool; /* long long is illegal */
double s;
region *r;
s = 0;
for(r=regions; r; r=r->next) {
s += rpeasants(r);
}
log_printf("BAUERN vorher: %lld\n",s);
for(ter = 0; ter < MAXTERRAINS; ter++) {
if(terrain[ter].production_max <= 0) continue;
c = 0;
sum = 0;
pool = 0;
freeall = 0;
for(r=regions; r; r=r->next) if(rterrain(r) == ter) {
unit *u;
c++;
sum += rpeasants(r);
for(u = r->units; u; u=u->next) {
if(lifestyle(u) > 0) sum += u->number;
/* Sonderregel Bauernmob */
if (u->race == new_race[RC_PEASANT]) sum += u->number;
}
}
if (c==0) continue;
avg = sum/c;
for(r=regions; r; r=r->next) if(rterrain(r) == ter) {
unit *u;
int playerp = 0;
int p_weg;
int soll;
for(u = r->units; u; u=u->next) {
if(lifestyle(u) > 0) playerp += u->number;
/* Sonderregel Bauernmob */
if (u->race == new_race[RC_PEASANT]) playerp += u->number;
}
soll = (int)((avg + playerp + rpeasants(r)) * WEIGHT);
if(playerp * PLWEIGHT + rpeasants(r) > soll) {
p_weg = (int)(min(((playerp * PLWEIGHT) + rpeasants(r)) - soll, rpeasants(r)));
assert(p_weg >= 0);
if (p_weg > 0){
log_printf("BAUERN %s: war %d, minus %d, playerp %d\n",
regionname(r, NULL), rpeasants(r), p_weg, playerp);
}
pool += p_weg;
rsetpeasants(r, rpeasants(r) - p_weg);
assert(rpeasants(r) >= 0);
}
freeall += max(0,production(r) * MAXPEASANTS_PER_AREA
- ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE) - playerp);
}
for(r=regions; r; r=r->next) if(rterrain(r) == ter) {
unit *u;
double free;
int newp;
int playerp = 0;
for(u = r->units; u; u=u->next) {
if(lifestyle(u) > 0) playerp += u->number;
/* Sonderregel Bauernmob */
if (u->race == new_race[RC_PEASANT]) playerp += u->number;
}
free = max(0,production(r) * MAXPEASANTS_PER_AREA
- ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE) - playerp);
newp = (int)((pool * free)/freeall);
rsetpeasants(r, rpeasants(r)+newp);
assert(rpeasants(r) >= 0);
}
}
s = 0;
for(r=regions; r; r=r->next) {
s += rpeasants(r);
}
log_printf("BAUERN nachher: %lld\n",s);
return 0;
}
static int
orc_conversion2(void)
{
faction *f;
unit *u;
region *r;
for(f=factions; f; f=f->next) {
if(f->race == new_race[RC_ORC]) {
f->race = new_race[RC_URUK];
}
}
for(r=regions; r; r=r->next) {
for(u=r->units; u; u=u->next) {
if (u->race==new_race[RC_ORC] || u->race==new_race[RC_SNOTLING]) {
/* convert to either uruk or snotling */
if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY)) {
u->race = new_race[RC_URUK];
u->irace = new_race[RC_URUK];
}
}
}
}
return 0;
}
static int
orc_conversion(void)
{
faction *f;
unit *u;
region *r;
for(f=factions; f; f=f->next) {
if(f->race == new_race[RC_ORC]) {
f->race = new_race[RC_URUK];
}
}
for(r=regions; r; r=r->next) {
for(u=r->units; u; u=u->next) {
if(u->race == new_race[RC_ORC]) {
/* convert to either uruk or snotling */
if(effskill(u, SK_MAGIC) >= 1
|| effskill(u, SK_ALCHEMY) >= 1
|| get_item(u, I_CHASTITY_BELT) >= u->number) {
u->race = new_race[RC_URUK];
u->irace = new_race[RC_URUK];
} else {
u->race = new_race[RC_SNOTLING];
u->irace = new_race[RC_SNOTLING];
}
}
}
}
return 0;
}
#endif
static int
fix_astralplane(void)
{
plane * astralplane = getplanebyname("Astralraum");
if (astralplane) {
freset(astralplane, PFL_NOCOORDS);
set_ursprung(findfaction(MONSTER_FACTION), astralplane->id, 0, 0);
}
return 0;
}
static int
fix_watchers(void)
{
plane * p = getplanebyid (59034966);
if (p) {
faction * f = findfaction(atoi36("gm04"));
watcher * w = calloc(sizeof(watcher), 1);
w->faction = f;
w->mode = see_unit;
w->next = p->watchers;
p->watchers = w;
}
p = getplanebyid(1137);
if (p) {
faction * f = findfaction(atoi36("rr"));
watcher * w = calloc(sizeof(watcher), 1);
w->faction = f;
w->mode = see_unit;
w->next = p->watchers;
p->watchers = w;
}
return 0;
}
static int
fix_questcoors(void)
{
plane * p = getplanebyid (59034966);
if (p) {
faction * f;
region * eternath = findregion(-8750, 3631);
if (eternath) for (f=factions;f;f=f->next) {
ursprung * u = f->ursprung;
while (u) {
if (u->id == p->id) {
u->x = 0;
u->y = 0;
break;
}
u=u->next;
}
}
}
return 0;
}
static int
warn_password(void)
{
faction * f = factions;
while (f) {
boolean pwok = true;
const char * c = f->passw;
while (*c) {
if (!isalnum(*c)) pwok = false;
c++;
}
if (pwok == false) {
ADDMSG(&f->msgs, msg_message("msg_errors", "string",
"Dein Passwort enthält Zeichen, die bei der Nachsendung "
"von Reports Probleme bereiten können. Bitte wähle ein neues "
"Passwort, bevorzugt nur aus Buchstaben und Zahlen bestehend."));
}
f = f->next;
}
return 0;
}
static int
fix_seeds(void)
{
region *r;
for(r=regions; r; r=r->next) {
if(rtrees(r,0) > 25 && rtrees(r,0) > rtrees(r,2)/2) {
rsettrees(r,0,rtrees(r,2)/2);
}
}
return 0;
}
void
korrektur(void)
{
#if TEST_LOCALES
setup_locales();
#endif
fix_astralplane();
fix_firewalls();
fix_gates();
#ifdef TEST_GM_COMMANDS
setup_gm_faction();
#endif
update_gms();
verify_owners(false);
/* fix_herbtypes(); */
#ifdef CONVERT_TRIGGER
convert_triggers();
#endif
fix_migrants();
no_teurefremde(1);
update_igjarjuk_quest();
fix_allies();
update_gmquests(); /* test gm quests */
/* fix_unitrefs(); */
stats();
do_once("sql2", dump_sql());
do_once("fw01", fix_watchers());
#if NEW_RESOURCEGROWTH
/* do not remove do_once calls - old datafiles need them! */
do_once("rgrw", convert_resources());
do_once("rsfx", read_resfix());
#endif
/* do_once("xepl", create_xe()); */
#if GROWING_TREES
do_once("grtr", growing_trees());
#endif
do_once("fgms", fix_gms());
#if NEW_RESOURCEGROWTH
do_once("rndr", randomized_resources());
#endif
do_once("idlo", fix_idleout());
do_once("szip", set_zip());
do_once("heal", heal_all());
do_once("fquc", fix_questcoors());
do_once("fsee", fix_seeds());
do_once("orc2", orc_conversion2());
do_once("witm", warn_items());
warn_password();
/* seems something fishy is going on, do this just
* to be on the safe side:
*/
fix_demand();
/* trade_orders(); */
if (global.data_version < NEWROAD_VERSION) {
newroads();
}
/* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich
* Beschreibungen geändert haben */
show_newspells();
fix_age();
/* Immer ausführen! Erschafft neue Teleport-Regionen, wenn nötig */
create_teleport_plane();
if (global.data_version<TYPES_VERSION) fix_icastles();
#ifdef XMAS2000
santa_comes_to_town();
#endif
#ifdef FUZZY_BASE36
enable_fuzzy = true;
#endif
}
void
korrektur_end(void)
{
/* fix_balsamfiasko(); */
#ifdef XMAS2001
do_once("2001", xmas2001());
#endif
#if PEASANT_ADJUSTMENT == 1
do_once("peas", peasant_adjustment());
do_once("orcc", orc_conversion());
#endif
}
void
init_conversion(void)
{
#if defined(CONVERT_TRIGGER)
at_register(&at_relation);
at_register(&at_relbackref);
at_register(&at_trigger);
at_register(&at_action);
#endif
}