2004-02-21 23:25:00 +01:00
|
|
|
/* vi: set ts=2:
|
|
|
|
+-------------------+
|
|
|
|
| | Christian Schlittchen <corwin@amber.kn-bremen.de>
|
|
|
|
| Eressea PBEM host | Enno Rehling <enno@eressea-pbem.de>
|
|
|
|
| (c) 1998 - 2004 | Katja Zedel <katze@felidae.kn-bremen.de>
|
|
|
|
| |
|
|
|
|
+-------------------+
|
|
|
|
|
|
|
|
This program may not be used, modified or distributed
|
|
|
|
without prior permission by the authors of Eressea.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <eressea.h>
|
|
|
|
|
|
|
|
#ifdef WORMHOLE_MODULE
|
|
|
|
#include "wormhole.h"
|
|
|
|
|
|
|
|
/* kernel includes */
|
|
|
|
#include <kernel/building.h>
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
#include <kernel/message.h>
|
2004-02-21 23:38:58 +01:00
|
|
|
#include <kernel/plane.h>
|
2004-02-21 23:25:00 +01:00
|
|
|
#include <kernel/region.h>
|
|
|
|
#include <kernel/unit.h>
|
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
#include <util/attrib.h>
|
|
|
|
|
|
|
|
/* libc includes */
|
2004-02-22 01:59:49 +01:00
|
|
|
#include <assert.h>
|
2004-02-21 23:25:00 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
good_region(const region * r)
|
|
|
|
{
|
2004-02-22 00:04:12 +01:00
|
|
|
return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL);
|
2004-02-21 23:25:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
cmp_age(const void * v1, const void *v2)
|
|
|
|
{
|
|
|
|
const region * r1 = (const region*)v1;
|
|
|
|
const region * r2 = (const region*)v2;
|
|
|
|
if (r1->age<r2->age) return -1;
|
|
|
|
if (r1->age>r2->age) return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct wormhole_data {
|
|
|
|
building * entry;
|
|
|
|
building * exit;
|
|
|
|
} wormhole_data;
|
|
|
|
|
|
|
|
static void
|
|
|
|
wormhole_init(struct attrib *a)
|
|
|
|
{
|
|
|
|
a->data.v = calloc(1, sizeof(wormhole_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wormhole_done(struct attrib * a)
|
|
|
|
{
|
|
|
|
free(a->data.v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
wormhole_age(struct attrib * a)
|
|
|
|
{
|
|
|
|
wormhole_data * data = (wormhole_data*)a->data.v;
|
2004-02-22 00:20:50 +01:00
|
|
|
int maxtransport = data->entry->size;
|
2004-02-22 01:15:13 +01:00
|
|
|
region * r = data->entry->region;
|
|
|
|
unit * u = r->units;
|
|
|
|
|
|
|
|
for (;u!=NULL && maxtransport!=0;u=u->next) {
|
|
|
|
message * m;
|
|
|
|
if (u->number>maxtransport) continue;
|
|
|
|
if (teure_talente(u)) continue;
|
|
|
|
if (u->building!=data->entry) continue;
|
|
|
|
|
2004-09-05 14:29:46 +02:00
|
|
|
if (data->exit!=NULL) {
|
|
|
|
move_unit(u, data->exit->region, NULL);
|
|
|
|
maxtransport -= u->number;
|
|
|
|
m = msg_message("wormhole_exit", "unit region", u, data->exit->region);
|
|
|
|
add_message(&data->exit->region->msgs, m);
|
|
|
|
add_message(&u->faction->msgs, m);
|
|
|
|
msg_release(m);
|
|
|
|
}
|
2004-02-21 23:37:47 +01:00
|
|
|
}
|
|
|
|
|
2004-02-22 01:59:49 +01:00
|
|
|
/* it's important that destroy_building doesn't change b->region, because
|
|
|
|
* otherwise the tunnel would no longer be bi-directional after this */
|
2004-02-22 01:15:13 +01:00
|
|
|
destroy_building(data->entry);
|
2004-03-05 23:31:37 +01:00
|
|
|
ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r));
|
2004-02-22 01:59:49 +01:00
|
|
|
assert(data->entry->region==r);
|
2004-02-22 01:15:13 +01:00
|
|
|
|
2004-02-21 23:25:00 +01:00
|
|
|
/* age returns 0 if the attribute needs to be removed, !=0 otherwise */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-07-10 14:00:21 +02:00
|
|
|
static void
|
2004-02-21 23:25:00 +01:00
|
|
|
wormhole_write(const struct attrib * a, FILE* F)
|
|
|
|
{
|
|
|
|
wormhole_data * data = (wormhole_data*)a->data.v;
|
|
|
|
write_building_reference(data->entry, F);
|
|
|
|
write_building_reference(data->exit, F);
|
|
|
|
}
|
|
|
|
|
2004-07-10 14:00:21 +02:00
|
|
|
static int
|
2004-02-21 23:25:00 +01:00
|
|
|
wormhole_read(struct attrib * a, FILE* F)
|
|
|
|
{
|
|
|
|
wormhole_data * data = (wormhole_data*)a->data.v;
|
|
|
|
|
|
|
|
read_building_reference(&data->entry, F);
|
|
|
|
read_building_reference(&data->exit, F);
|
|
|
|
/* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
|
|
|
|
return AT_READ_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static attrib_type at_wormhole = {
|
|
|
|
"wormhole",
|
|
|
|
wormhole_init,
|
|
|
|
wormhole_done,
|
|
|
|
wormhole_age,
|
|
|
|
wormhole_write,
|
|
|
|
wormhole_read,
|
|
|
|
ATF_UNIQUE
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2004-07-10 14:00:21 +02:00
|
|
|
make_wormhole(const building_type * bt_wormhole, region * r1, region * r2)
|
2004-02-21 23:25:00 +01:00
|
|
|
{
|
2004-07-10 14:00:21 +02:00
|
|
|
building * b1 = new_building(bt_wormhole, r1, NULL);
|
|
|
|
building * b2 = new_building(bt_wormhole, r2, NULL);
|
2004-02-21 23:25:00 +01:00
|
|
|
attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole));
|
|
|
|
attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole));
|
|
|
|
wormhole_data * d1 = (wormhole_data*)a1->data.v;
|
|
|
|
wormhole_data * d2 = (wormhole_data*)a2->data.v;
|
|
|
|
d1->entry = d2->exit = b1;
|
|
|
|
d2->entry = d1->exit = b2;
|
2004-07-10 14:00:21 +02:00
|
|
|
b1->size = bt_wormhole->maxsize;
|
|
|
|
b2->size = bt_wormhole->maxsize;
|
2004-02-22 00:04:12 +01:00
|
|
|
ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1));
|
|
|
|
ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2));
|
2004-02-21 23:25:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
create_wormholes(void)
|
|
|
|
{
|
|
|
|
#define WORMHOLE_CHANCE 10000
|
2004-07-10 14:00:21 +02:00
|
|
|
const building_type * bt_wormhole = bt_find("wormhole");
|
2004-02-21 23:25:00 +01:00
|
|
|
region_list *rptr, * rlist = NULL;
|
|
|
|
region * r = regions;
|
|
|
|
int i = 0, count = 0;
|
|
|
|
region ** match;
|
|
|
|
|
2004-07-10 14:00:21 +02:00
|
|
|
if (bt_wormhole==NULL) return;
|
2004-02-21 23:25:00 +01:00
|
|
|
/*
|
|
|
|
* select a list of regions. we'll sort them by age later.
|
|
|
|
*/
|
|
|
|
while (r!=NULL) {
|
|
|
|
int next = rand() % (2*WORMHOLE_CHANCE);
|
|
|
|
while (r!=NULL && (next!=0 || !good_region(r))) {
|
|
|
|
if (good_region(r)) {
|
|
|
|
--next;
|
|
|
|
}
|
|
|
|
r=r->next;
|
|
|
|
}
|
|
|
|
if (r==NULL) break;
|
|
|
|
add_regionlist(&rlist, r);
|
|
|
|
++count;
|
|
|
|
r=r->next;
|
|
|
|
}
|
|
|
|
|
2005-05-08 02:36:11 +02:00
|
|
|
if (count<2) return;
|
|
|
|
|
2004-02-21 23:25:00 +01:00
|
|
|
match = (region**)malloc(sizeof(region*) * count);
|
|
|
|
rptr = rlist;
|
|
|
|
while (i!=count) {
|
|
|
|
match[i++] = rptr->data;
|
|
|
|
rptr = rptr->next;
|
|
|
|
}
|
2004-07-06 17:11:27 +02:00
|
|
|
qsort(match, count, sizeof(region *), cmp_age);
|
2004-02-21 23:25:00 +01:00
|
|
|
free_regionlist(rlist);
|
|
|
|
|
|
|
|
count /= 2;
|
|
|
|
for (i=0;i!=count;++i) {
|
2004-07-10 14:00:21 +02:00
|
|
|
make_wormhole(bt_wormhole, match[i], match[i+count]);
|
2004-02-21 23:25:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
register_wormholes(void)
|
|
|
|
{
|
|
|
|
at_register(&at_wormhole);
|
|
|
|
}
|
|
|
|
#endif
|