2002-01-05 17:14:38 +01:00
|
|
|
|
/* vi: set ts=2:
|
|
|
|
|
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
|
|
|
|
|
| | Enno Rehling <enno@eressea-pbem.de>
|
|
|
|
|
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
|
|
|
|
|
| (c) 1998 - 2001 | Henning Peters <faroul@beyond.kn-bremen.de>
|
|
|
|
|
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
|
|
|
|
|
+-------------------+ Stefan Reich <reich@halbling.de>
|
|
|
|
|
|
|
|
|
|
This program may not be used, modified or distributed
|
|
|
|
|
without prior permission by the authors of Eressea.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <eressea.h>
|
|
|
|
|
#include "dungeon.h"
|
|
|
|
|
#include "gmcmd.h"
|
|
|
|
|
|
|
|
|
|
#include <triggers/gate.h>
|
|
|
|
|
#include <triggers/unguard.h>
|
|
|
|
|
|
|
|
|
|
/* kernel includes */
|
2002-01-09 09:20:33 +01:00
|
|
|
|
#include <building.h>
|
|
|
|
|
#include <item.h>
|
2002-01-05 17:14:38 +01:00
|
|
|
|
#include <plane.h>
|
|
|
|
|
#include <race.h>
|
|
|
|
|
#include <region.h>
|
2002-01-11 00:09:37 +01:00
|
|
|
|
#include <skill.h>
|
2002-01-09 09:20:33 +01:00
|
|
|
|
#include <unit.h>
|
2002-01-05 17:14:38 +01:00
|
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
|
#include <event.h>
|
2002-01-09 09:20:33 +01:00
|
|
|
|
#include <xml.h>
|
|
|
|
|
|
|
|
|
|
/* libc includes */
|
2002-01-13 08:59:41 +01:00
|
|
|
|
#include <stdlib.h>
|
2002-01-09 09:20:33 +01:00
|
|
|
|
#include <string.h>
|
2002-01-11 00:09:37 +01:00
|
|
|
|
#include <limits.h>
|
2002-01-05 17:14:38 +01:00
|
|
|
|
|
|
|
|
|
typedef struct treasure {
|
|
|
|
|
const struct item_type * itype;
|
|
|
|
|
int amount;
|
|
|
|
|
struct treasure * next;
|
|
|
|
|
} treasure;
|
|
|
|
|
|
|
|
|
|
typedef struct monster {
|
|
|
|
|
const struct race * race;
|
|
|
|
|
double chance;
|
|
|
|
|
int maxunits;
|
|
|
|
|
int avgsize;
|
|
|
|
|
struct treasure * treasures;
|
|
|
|
|
struct monster * next;
|
|
|
|
|
struct itemtype_list * weapons;
|
|
|
|
|
} monster;
|
|
|
|
|
|
2002-01-11 00:09:37 +01:00
|
|
|
|
typedef struct skilllimit {
|
|
|
|
|
skill_t skill;
|
|
|
|
|
int minskill;
|
|
|
|
|
int maxskill;
|
|
|
|
|
struct skilllimit * next;
|
|
|
|
|
} skilllimit;
|
|
|
|
|
|
2002-01-05 17:14:38 +01:00
|
|
|
|
typedef struct dungeon {
|
|
|
|
|
int level;
|
|
|
|
|
int radius;
|
|
|
|
|
int size;
|
2002-01-11 00:09:37 +01:00
|
|
|
|
int maxpeople;
|
|
|
|
|
struct skilllimit * limits;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
double connect;
|
|
|
|
|
struct monster * boss;
|
|
|
|
|
struct monster * monsters;
|
2002-01-09 09:20:33 +01:00
|
|
|
|
struct dungeon * next;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
} dungeon;
|
|
|
|
|
|
2002-01-09 09:20:33 +01:00
|
|
|
|
dungeon * dungeonstyles;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
|
2002-01-09 09:20:33 +01:00
|
|
|
|
region *
|
|
|
|
|
make_dungeon(const dungeon * data)
|
2002-01-05 17:14:38 +01:00
|
|
|
|
{
|
|
|
|
|
int nb[2][3][2] = {
|
|
|
|
|
{ { -1, 0 }, { 0, 1 }, { 1, -1 } },
|
|
|
|
|
{ { 1, 0 }, { -1, 1 }, { 0, -1 } }
|
|
|
|
|
};
|
2002-01-09 09:20:33 +01:00
|
|
|
|
const struct race * bossrace = data->boss->race;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
char name[128];
|
2002-01-09 09:20:33 +01:00
|
|
|
|
int size = data->size;
|
2002-01-11 00:09:37 +01:00
|
|
|
|
int iterations = size * size;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
unsigned int flags = PFL_NORECRUITS;
|
|
|
|
|
int n = 0;
|
2002-01-09 09:20:33 +01:00
|
|
|
|
struct faction * fmonsters = findfaction(MONSTER_FACTION);
|
2002-01-05 17:14:38 +01:00
|
|
|
|
plane * p;
|
|
|
|
|
region *r, *center;
|
|
|
|
|
region * rnext;
|
2002-01-09 09:20:33 +01:00
|
|
|
|
regionlist * iregion, * rlist = NULL;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
|
|
|
|
|
sprintf(name, "Die H<>hlen von %s", bossrace->generate_name(NULL));
|
2002-01-09 09:20:33 +01:00
|
|
|
|
p = gm_addplane(data->radius, flags, name);
|
2002-01-05 17:14:38 +01:00
|
|
|
|
|
|
|
|
|
center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2);
|
|
|
|
|
assert(center);
|
|
|
|
|
terraform(center, T_HELL);
|
2002-01-09 09:20:33 +01:00
|
|
|
|
add_regionlist(&rlist, center);
|
2002-01-05 17:14:38 +01:00
|
|
|
|
rnext = r = center;
|
2002-01-11 00:09:37 +01:00
|
|
|
|
while (size>0 && iterations--) {
|
2002-01-05 17:14:38 +01:00
|
|
|
|
int d, o = rand() % 3;
|
|
|
|
|
for (d=0;d!=3;++d) {
|
|
|
|
|
int index = (d+o) % 3;
|
|
|
|
|
region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]);
|
|
|
|
|
assert(r->terrain==T_HELL);
|
|
|
|
|
if (rn) {
|
|
|
|
|
switch (rn->terrain) {
|
|
|
|
|
case T_OCEAN:
|
2002-01-09 09:20:33 +01:00
|
|
|
|
if (rand() % 100 < data->connect*100) {
|
2002-01-05 17:14:38 +01:00
|
|
|
|
terraform(rn, T_HELL);
|
|
|
|
|
--size;
|
|
|
|
|
rnext = rn;
|
2002-01-09 09:20:33 +01:00
|
|
|
|
add_regionlist(&rlist, rn);
|
2002-01-05 17:14:38 +01:00
|
|
|
|
}
|
|
|
|
|
else terraform(rn, T_FIREWALL);
|
|
|
|
|
break;
|
|
|
|
|
case T_HELL:
|
|
|
|
|
rnext = rn;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (size == 0) break;
|
|
|
|
|
}
|
|
|
|
|
rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]);
|
|
|
|
|
if (rn && rn->terrain==T_OCEAN) terraform(rn, T_FIREWALL);
|
|
|
|
|
}
|
|
|
|
|
if (size==0) break;
|
2002-01-28 01:25:32 +01:00
|
|
|
|
if (r==rnext) {
|
|
|
|
|
/* error */
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-01-05 17:14:38 +01:00
|
|
|
|
r = rnext;
|
|
|
|
|
n = (n+1) % 2;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-09 09:20:33 +01:00
|
|
|
|
for (iregion=rlist;iregion;iregion=iregion->next) {
|
|
|
|
|
monster * m = data->monsters;
|
|
|
|
|
region * r = iregion->region;
|
|
|
|
|
while (m) {
|
|
|
|
|
if ((rand() % 100) < (m->chance * 100)) {
|
|
|
|
|
/* TODO: check maxunits. */
|
|
|
|
|
treasure * loot = m->treasures;
|
|
|
|
|
struct itemtype_list * weapon = m->weapons;
|
|
|
|
|
int size = 1 + (rand() % m->avgsize) + (rand() % m->avgsize);
|
|
|
|
|
unit * u = createunit(r, fmonsters, size, m->race);
|
|
|
|
|
while (weapon) {
|
|
|
|
|
i_change(&u->items, weapon->type, size);
|
|
|
|
|
weapon = weapon->next;
|
|
|
|
|
}
|
|
|
|
|
while (loot) {
|
|
|
|
|
i_change(&u->items, loot->itype, loot->amount*size);
|
|
|
|
|
loot = loot->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m = m->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return center;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2002-01-09 09:20:33 +01:00
|
|
|
|
make_dungeongate(region * source, region * target, const struct dungeon * d)
|
2002-01-05 17:14:38 +01:00
|
|
|
|
{
|
|
|
|
|
building *bsource, *btarget;
|
2002-01-28 01:25:32 +01:00
|
|
|
|
|
|
|
|
|
if (source==NULL || target==NULL || d==NULL) return;
|
2002-01-05 17:14:38 +01:00
|
|
|
|
bsource = new_building(bt_find("castle"), source, default_locale);
|
|
|
|
|
set_string(&bsource->name, "Pforte zur H<>lle");
|
|
|
|
|
bsource->size = 50;
|
|
|
|
|
add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target));
|
|
|
|
|
add_trigger(&bsource->attribs, "create", trigger_unguard(bsource));
|
|
|
|
|
fset(bsource, BLD_UNGUARDED);
|
|
|
|
|
|
|
|
|
|
btarget = new_building(bt_find("castle"), target, default_locale);
|
|
|
|
|
set_string(&btarget->name, "Pforte zur Au<41>enwelt");
|
|
|
|
|
btarget->size = 50;
|
|
|
|
|
add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source));
|
|
|
|
|
add_trigger(&btarget->attribs, "create", trigger_unguard(btarget));
|
|
|
|
|
fset(btarget, BLD_UNGUARDED);
|
|
|
|
|
}
|
2002-01-09 09:20:33 +01:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tagbegin(xml_stack *stack)
|
|
|
|
|
{
|
|
|
|
|
xml_tag * tag = stack->tag;
|
2002-01-11 00:09:37 +01:00
|
|
|
|
if (strcmp(tag->name, "dungeon")==0) {
|
|
|
|
|
dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1);
|
|
|
|
|
d->maxpeople = xml_ivalue(tag, "maxpeople");
|
|
|
|
|
if (d->maxpeople==0) d->maxpeople = INT_MAX;
|
|
|
|
|
d->level = xml_ivalue(tag, "level");
|
|
|
|
|
d->radius = xml_ivalue(tag, "radius");
|
|
|
|
|
d->connect = xml_fvalue(tag, "connect");
|
|
|
|
|
d->size = xml_ivalue(tag, "size");
|
|
|
|
|
stack->state = d;
|
2002-01-09 09:20:33 +01:00
|
|
|
|
} else {
|
|
|
|
|
dungeon * d = (dungeon*)stack->state;
|
2002-01-11 00:09:37 +01:00
|
|
|
|
if (strcmp(tag->name, "skilllimit")==0) {
|
|
|
|
|
skill_t sk = sk_find(xml_value(tag, "name"));
|
|
|
|
|
if (sk!=NOSKILL) {
|
|
|
|
|
skilllimit * skl = calloc(sizeof(skilllimit), 1);
|
|
|
|
|
skl->skill = sk;
|
|
|
|
|
if (xml_value(tag, "max")!=NULL) {
|
|
|
|
|
skl->maxskill = xml_ivalue(tag, "max");
|
|
|
|
|
} else skl->maxskill = INT_MAX;
|
|
|
|
|
if (xml_value(tag, "min")!=NULL) {
|
|
|
|
|
skl->minskill = xml_ivalue(tag, "min");
|
|
|
|
|
} else skl->maxskill = INT_MIN;
|
|
|
|
|
skl->next = d->limits;
|
|
|
|
|
d->limits = skl;
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(tag->name, "monster")==0) {
|
2002-01-09 09:20:33 +01:00
|
|
|
|
monster * m = calloc(sizeof(monster), 1);
|
|
|
|
|
m->race = rc_find(xml_value(tag, "race"));
|
|
|
|
|
m->chance = xml_fvalue(tag, "chance");
|
2002-01-11 00:09:37 +01:00
|
|
|
|
m->avgsize = max(1, xml_ivalue(tag, "size"));
|
|
|
|
|
m->maxunits = min(1, xml_ivalue(tag, "maxunits"));
|
2002-01-09 09:20:33 +01:00
|
|
|
|
|
|
|
|
|
if (m->race) {
|
|
|
|
|
if (xml_bvalue(tag, "boss")) {
|
|
|
|
|
d->boss = m;
|
|
|
|
|
} else {
|
|
|
|
|
m->next = d->monsters;
|
|
|
|
|
d->monsters = m;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-01-11 00:09:37 +01:00
|
|
|
|
} else if (strcmp(tag->name, "weapon")==0) {
|
2002-01-09 09:20:33 +01:00
|
|
|
|
monster * m = d->monsters;
|
|
|
|
|
itemtype_list * w = calloc(sizeof(itemtype_list), 1);
|
|
|
|
|
w->type = it_find(xml_value(tag, "type"));
|
|
|
|
|
if (w->type) {
|
|
|
|
|
w->next = m->weapons;
|
|
|
|
|
m->weapons = w;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return XML_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
tagend(xml_stack * stack)
|
|
|
|
|
{
|
|
|
|
|
xml_tag * tag = stack->tag;
|
|
|
|
|
if (strcmp(tag->name, "dungeon")) {
|
|
|
|
|
dungeon * d = (dungeon*)stack->state;
|
|
|
|
|
stack->state = NULL;
|
|
|
|
|
d->next = dungeonstyles;
|
|
|
|
|
dungeonstyles = d;
|
|
|
|
|
}
|
|
|
|
|
return XML_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xml_callbacks xml_dungeon = {
|
|
|
|
|
tagbegin, tagend, NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
register_dungeon(void)
|
|
|
|
|
{
|
|
|
|
|
xml_register(&xml_dungeon, "eressea dungeon", 0);
|
2002-01-13 08:59:41 +01:00
|
|
|
|
}
|