forked from github/server
506 lines
16 KiB
C
506 lines
16 KiB
C
/*
|
||
Copyright (c) 1998-2015, 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>
|
||
|
||
#if MUSEUM_MODULE
|
||
#include "museum.h"
|
||
|
||
/* kernel includes */
|
||
#include <kernel/building.h>
|
||
#include <kernel/connection.h>
|
||
#include <kernel/faction.h>
|
||
#include <kernel/item.h>
|
||
#include <kernel/messages.h>
|
||
#include <kernel/order.h>
|
||
#include <kernel/plane.h>
|
||
#include <kernel/region.h>
|
||
#include <kernel/save.h>
|
||
#include <kernel/terrain.h>
|
||
#include <kernel/unit.h>
|
||
#include <kernel/faction.h>
|
||
|
||
#include <move.h>
|
||
|
||
/* util includes */
|
||
#include <util/attrib.h>
|
||
#include <util/base36.h>
|
||
#include <util/functions.h>
|
||
#include <util/gamedata.h>
|
||
#include <util/strings.h>
|
||
#include <util/language.h>
|
||
|
||
#include <storage.h>
|
||
|
||
/* libc includes */
|
||
#include <limits.h>
|
||
#include <stdlib.h>
|
||
#include <assert.h>
|
||
|
||
#define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED
|
||
|
||
attrib_type at_museumexit = {
|
||
"museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts
|
||
};
|
||
|
||
static void a_initmuseumgivebackcookie(attrib * a)
|
||
{
|
||
a->data.v = calloc(1, sizeof(museumgivebackcookie));
|
||
}
|
||
|
||
static void a_finalizemuseumgivebackcookie(attrib * a)
|
||
{
|
||
free(a->data.v);
|
||
}
|
||
|
||
static void
|
||
a_writemuseumgivebackcookie(const attrib * a, const void *owner,
|
||
struct storage *store)
|
||
{
|
||
museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v;
|
||
WRITE_INT(store, gbc->warden_no);
|
||
WRITE_INT(store, gbc->cookie);
|
||
}
|
||
|
||
static int
|
||
a_readmuseumgivebackcookie(attrib * a, void *owner, gamedata *data)
|
||
{
|
||
museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v;
|
||
READ_INT(data->store, &gbc->warden_no);
|
||
READ_INT(data->store, &gbc->cookie);
|
||
return AT_READ_OK;
|
||
}
|
||
|
||
attrib_type at_museumgivebackcookie = {
|
||
"museumgivebackcookie",
|
||
a_initmuseumgivebackcookie,
|
||
a_finalizemuseumgivebackcookie,
|
||
NULL,
|
||
a_writemuseumgivebackcookie,
|
||
a_readmuseumgivebackcookie
|
||
};
|
||
|
||
attrib_type at_warden = {
|
||
"itemwarden", NULL, NULL, NULL, a_writeint, a_readint
|
||
};
|
||
|
||
static void a_initmuseumgiveback(attrib * a)
|
||
{
|
||
a->data.v = calloc(1, sizeof(museumgiveback));
|
||
}
|
||
|
||
static void a_finalizemuseumgiveback(attrib * a)
|
||
{
|
||
museumgiveback *gb = (museumgiveback *)a->data.v;
|
||
i_freeall(&gb->items);
|
||
free(a->data.v);
|
||
}
|
||
|
||
static void
|
||
a_writemuseumgiveback(const attrib * a, const void *owner,
|
||
struct storage *store)
|
||
{
|
||
museumgiveback *gb = (museumgiveback *)a->data.v;
|
||
WRITE_INT(store, gb->cookie);
|
||
write_items(store, gb->items);
|
||
}
|
||
|
||
static int a_readmuseumgiveback(attrib * a, void *owner, struct gamedata *data)
|
||
{
|
||
museumgiveback *gb = (museumgiveback *)a->data.v;
|
||
READ_INT(data->store, &gb->cookie);
|
||
read_items(data->store, &gb->items);
|
||
return AT_READ_OK;
|
||
}
|
||
|
||
attrib_type at_museumgiveback = {
|
||
"museumgiveback",
|
||
a_initmuseumgiveback,
|
||
a_finalizemuseumgiveback,
|
||
NULL,
|
||
a_writemuseumgiveback,
|
||
a_readmuseumgiveback
|
||
};
|
||
|
||
void warden_add_give(unit * src, unit * u, const item_type * itype, int n)
|
||
{
|
||
attrib *aw = a_find(u->attribs, &at_warden);
|
||
museumgiveback *gb = NULL;
|
||
museumgivebackcookie *gbc;
|
||
attrib *a;
|
||
|
||
/* has the giver a cookie corresponding to the warden */
|
||
for (a = a_find(src->attribs, &at_museumgivebackcookie);
|
||
a && a->type == &at_museumgivebackcookie; a = a->next) {
|
||
if (((museumgivebackcookie *)(a->data.v))->warden_no == u->no)
|
||
break;
|
||
}
|
||
|
||
/* if not give it one */
|
||
if (a == NULL || a->type != &at_museumgivebackcookie) {
|
||
a = a_add(&src->attribs, a_new(&at_museumgivebackcookie));
|
||
gbc = (museumgivebackcookie *)a->data.v;
|
||
gbc->warden_no = u->no;
|
||
gbc->cookie = aw->data.i;
|
||
assert(aw->data.i < INT_MAX);
|
||
aw->data.i++;
|
||
}
|
||
else {
|
||
gbc = (museumgivebackcookie *)(a->data.v);
|
||
}
|
||
|
||
/* now we search for the warden's corresponding item list */
|
||
for (a = a_find(u->attribs, &at_museumgiveback);
|
||
a && a->type == &at_museumgiveback; a = a->next) {
|
||
gb = (museumgiveback *)a->data.v;
|
||
if (gb->cookie == gbc->cookie) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* if there's none, give it one */
|
||
if (!gb) {
|
||
a = a_add(&u->attribs, a_new(&at_museumgiveback));
|
||
gb = (museumgiveback *)a->data.v;
|
||
gb->cookie = gbc->cookie;
|
||
}
|
||
|
||
/* now register the items */
|
||
i_change(&gb->items, itype, n);
|
||
|
||
/* done */
|
||
|
||
/* this has a caveat: If the src-unit is destroyed while inside
|
||
* the museum, the corresponding itemlist of the warden will never
|
||
* be removed. to circumvent that in a generic way will be extremly
|
||
* difficult. */
|
||
}
|
||
|
||
void create_museum(void)
|
||
{
|
||
#if 0 /* TODO: move this to Lua. It should be possible. */
|
||
unsigned int museum_id = hashstring("museum");
|
||
plane *museum = getplanebyid(museum_id);
|
||
region *r;
|
||
building *b;
|
||
const terrain_type *terrain_hall = get_terrain("hall1");
|
||
const terrain_type *terrain_corridor = get_terrain("corridor1");
|
||
|
||
assert(terrain_corridor && terrain_hall);
|
||
|
||
if (!museum) {
|
||
museum = create_new_plane(museum_id, "Museum", 9500, 9550,
|
||
9500, 9550, PFL_MUSEUM);
|
||
}
|
||
|
||
if (findregion(9525, 9525) == NULL) {
|
||
/* Eingangshalle */
|
||
r = new_region(9525, 9525, 0);
|
||
terraform_region(r, terrain_hall);
|
||
r->planep = museum;
|
||
rsetname(r, "Eingangshalle");
|
||
rsethorses(r, 0);
|
||
rsetmoney(r, 0);
|
||
rsetpeasants(r, 0);
|
||
set_string(&r->display,
|
||
"Die Eingangshalle des Gro<72>en Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht er<65>ffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein gro<72>er Kompass eingelassen, der den Besuchern bei Orientierung helfen soll.");
|
||
}
|
||
|
||
r = findregion(9526, 9525);
|
||
if (!r) {
|
||
/* Lounge */
|
||
r = new_region(9526, 9525, 0);
|
||
terraform_region(r, terrain_hall);
|
||
r->planep = museum;
|
||
rsetname(r, "Lounge");
|
||
rsethorses(r, 0);
|
||
rsetmoney(r, 0);
|
||
rsetpeasants(r, 0);
|
||
set_string(&r->display,
|
||
"Die Lounge des gro<72>en Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindr<64>cke, die sie gewonnen haben, zu verarbeiten. Gem<65>tliche Sitzgruppen laden zum Verweilen ein.");
|
||
}
|
||
|
||
r = findregion(9526, 9525);
|
||
if (!r->buildings) {
|
||
const building_type *bt_generic = bt_find("generic");
|
||
b = new_building(bt_generic, r, NULL);
|
||
set_string(&b->name, "S<>par<61>e im d<>monischen Stil");
|
||
set_string(&b->display,
|
||
"Diese ganz im d<>monischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarzt<7A>nen gehalten. Muster fremdartiger Runen bedecken das merkw<6B>rdig geformte Mobiliar, das unangenehm lebendig wirkt.");
|
||
|
||
b = new_building(bt_generic, r, NULL);
|
||
set_string(&b->name, "S<>par<61>e im elfischen Stil");
|
||
set_string(&b->display,
|
||
"Ganz in Gr<47>n- und Braunt<6E>nen gehalten wirkt die Sitzgruppe fast lebendig. Bei n<>herer Betrachtung erschlie<69>t sich dem Betrachter, da<64> sie tats<74>chlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wundersch<63>n gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden.");
|
||
|
||
b = new_building(bt_generic, r, NULL);
|
||
set_string(&b->name, "S<>par<61>e im halblingschen Stil");
|
||
set_string(&b->display,
|
||
"Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben flei<65>ige Halblinge der L<>nge nach gevierteilt und aus den vier langen Viertelst<73>mmen die Sitzb<7A>nke geschnitzt, w<>hrend der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Ger<65>che der K<>stlichkeiten entgegen, die auf dem Tisch stapeln.");
|
||
|
||
b = new_building(bt_generic, r, NULL);
|
||
set_string(&b->name, "S<>par<61>e im orkischen Stil");
|
||
set_string(&b->display,
|
||
"Grobgeschreinerte, elfenhautbespannte St<53>hle und ein Tisch aus Knochen, <20>ber deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. <20>berall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt.");
|
||
|
||
b = new_building(bt_generic, r, NULL);
|
||
set_string(&b->name, "S<>par<61>e im Meermenschenstil");
|
||
set_string(&b->display,
|
||
"Ganz in Blau- und Gr<47>nt<6E>nen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten St<53>hle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte.");
|
||
|
||
b = new_building(bt_generic, r, NULL);
|
||
set_string(&b->name, "S<>par<61>e im Katzenstil");
|
||
set_string(&b->display,
|
||
"Die W<>nde dieses S<>par<61>e sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei n<>herer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der K<>nstler M<>he gegeben wirklich jedes Katzenvolk Eresseas zu portr<74>tieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gem<65>tlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein gro<72>er Korb mit roten Wollkn<6B>ulen und grauen und braunen Spielm<6C>usen.");
|
||
} else {
|
||
for (b = r->buildings; b; b = b->next) {
|
||
b->size = b->type->maxsize;
|
||
}
|
||
}
|
||
|
||
r = findregion(9524, 9526);
|
||
if (!r) {
|
||
r = new_region(9524, 9526, 0);
|
||
terraform_region(r, terrain_corridor);
|
||
r->planep = museum;
|
||
rsetname(r, "N<>rdliche Promenade");
|
||
rsethorses(r, 0);
|
||
rsetmoney(r, 0);
|
||
rsetpeasants(r, 0);
|
||
set_string(&r->display,
|
||
"Die N<>rdliche Promenade f<>hrt direkt in den naturgeschichtlichen Teil des Museums.");
|
||
}
|
||
r = findregion(9525, 9524);
|
||
if (!r) {
|
||
r = new_region(9525, 9524, 0);
|
||
terraform_region(r, terrain_corridor);
|
||
r->planep = museum;
|
||
rsetname(r, "S<>dliche Promenade");
|
||
rsethorses(r, 0);
|
||
rsetmoney(r, 0);
|
||
rsetpeasants(r, 0);
|
||
set_string(&r->display,
|
||
"Die S<>dliche Promenade f<>hrt den Besucher in den kulturgeschichtlichen Teil des Museums.");
|
||
}
|
||
#endif
|
||
}
|
||
|
||
static int
|
||
use_museumexitticket(unit * u, const struct item_type *itype, int amount,
|
||
order * ord)
|
||
{
|
||
attrib *a;
|
||
region *r;
|
||
unit *warden = findunit(atoi36("mwar"));
|
||
int unit_cookie;
|
||
|
||
unused_arg(amount);
|
||
|
||
/* Pr<50>fen ob in Eingangshalle */
|
||
if (u->region->x != 9525 || u->region->y != 9525) {
|
||
cmistake(u, ord, 266, MSG_MAGIC);
|
||
return 0;
|
||
}
|
||
|
||
a = a_find(u->attribs, &at_museumexit);
|
||
assert(a);
|
||
r = findregion(a->data.sa[0], a->data.sa[1]);
|
||
assert(r);
|
||
a_remove(&u->attribs, a);
|
||
/* <20>bergebene Gegenst<73>nde zur<75>ckgeben */
|
||
|
||
a = a_find(u->attribs, &at_museumgivebackcookie);
|
||
if (a) {
|
||
unit_cookie = a->data.i;
|
||
a_remove(&u->attribs, a);
|
||
|
||
for (a = a_find(warden->attribs, &at_museumgiveback);
|
||
a && a->type == &at_museumgiveback; a = a->next) {
|
||
if (((museumgiveback *)(a->data.v))->cookie == unit_cookie)
|
||
break;
|
||
}
|
||
if (a && a->type == &at_museumgiveback) {
|
||
museumgiveback *gb = (museumgiveback *)(a->data.v);
|
||
item *it;
|
||
|
||
for (it = gb->items; it; it = it->next) {
|
||
i_change(&u->items, it->type, it->number);
|
||
}
|
||
ADDMSG(&u->faction->msgs, msg_message("museumgiveback",
|
||
"region unit sender items", r, u, warden, gb->items));
|
||
a_remove(&warden->attribs, a);
|
||
}
|
||
}
|
||
|
||
/* Benutzer zur<75>ck teleportieren */
|
||
move_unit(u, r, NULL);
|
||
|
||
/* Exitticket abziehen */
|
||
i_change(&u->items, itype, -1);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int
|
||
use_museumticket(unit * u, const struct item_type *itype, int amount,
|
||
order * ord)
|
||
{
|
||
attrib *a;
|
||
region *r = u->region;
|
||
plane *pl = rplane(r);
|
||
|
||
unused_arg(amount);
|
||
|
||
/* Pruefen ob in normaler Plane und nur eine Person */
|
||
if (pl != get_homeplane()) {
|
||
cmistake(u, ord, 265, MSG_MAGIC);
|
||
return 0;
|
||
}
|
||
if (u->number != 1) {
|
||
cmistake(u, ord, 267, MSG_MAGIC);
|
||
return 0;
|
||
}
|
||
if (has_horses(u)) {
|
||
cmistake(u, ord, 272, MSG_MAGIC);
|
||
return 0;
|
||
}
|
||
|
||
/* In diesem Attribut merken wir uns, wohin die Einheit zur<75>ckgesetzt
|
||
* wird, wenn sie das Museum verl<72><6C>t. */
|
||
|
||
a = a_add(&u->attribs, a_new(&at_museumexit));
|
||
a->data.sa[0] = (short)r->x;
|
||
a->data.sa[1] = (short)r->y;
|
||
|
||
/* Benutzer in die Halle teleportieren */
|
||
move_unit(u, findregion(9525, 9525), NULL);
|
||
|
||
/* Ticket abziehen */
|
||
i_change(&u->items, itype, -1);
|
||
|
||
/* Benutzer ein Exitticket geben */
|
||
i_change(&u->items, itype, 1);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/***
|
||
* special quest door
|
||
***/
|
||
|
||
bool b_blockquestportal(const connection * b, const unit * u,
|
||
const region * r)
|
||
{
|
||
if (b->data.i > 0)
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
static const char *b_namequestportal(const connection * b, const region * r,
|
||
const struct faction *f, int gflags)
|
||
{
|
||
const char *bname;
|
||
int lock = b->data.i;
|
||
unused_arg(b);
|
||
unused_arg(r);
|
||
|
||
if (gflags & GF_ARTICLE) {
|
||
if (lock > 0) {
|
||
bname = "a_gate_locked";
|
||
}
|
||
else {
|
||
bname = "a_gate_open";
|
||
}
|
||
}
|
||
else {
|
||
if (lock > 0) {
|
||
bname = "gate_locked";
|
||
}
|
||
else {
|
||
bname = "gate_open";
|
||
}
|
||
}
|
||
if (gflags & GF_PURE)
|
||
return bname;
|
||
return LOC(f->locale, mkname("border", bname));
|
||
}
|
||
|
||
border_type bt_questportal = {
|
||
"questportal", VAR_INT,
|
||
b_opaque,
|
||
NULL, /* init */
|
||
NULL, /* destroy */
|
||
b_read, /* read */
|
||
b_write, /* write */
|
||
b_blockquestportal, /* block */
|
||
b_namequestportal, /* name */
|
||
b_rvisible, /* rvisible */
|
||
b_fvisible, /* fvisible */
|
||
b_uvisible, /* uvisible */
|
||
};
|
||
|
||
static void use_key1(connection *b, void *data) {
|
||
unit * u = (unit *)data;
|
||
if (b->type == &bt_questportal) {
|
||
const struct item_type *itype = it_find("questkey1");
|
||
ADDMSG(&u->faction->msgs,
|
||
msg_message("use_item", "unit item", u, itype->rtype));
|
||
b->data.i &= 0xFE;
|
||
}
|
||
}
|
||
|
||
static void use_key2(connection *b, void *data) {
|
||
unit * u = (unit *)data;
|
||
if (b->type == &bt_questportal) {
|
||
const struct item_type *itype = it_find("questkey2");
|
||
ADDMSG(&u->faction->msgs,
|
||
msg_message("use_item", "unit item", u, itype->rtype));
|
||
b->data.i &= 0xFD;
|
||
}
|
||
}
|
||
|
||
static int
|
||
use_museumkey(unit * u, const struct item_type *itype, int amount,
|
||
order * ord)
|
||
{
|
||
const struct item_type *ikey = it_find("questkey1");
|
||
assert(u);
|
||
assert(itype && ikey);
|
||
assert(amount >= 1);
|
||
|
||
walk_connections(u->region, itype == ikey ? use_key1 : use_key2, u);
|
||
return 0;
|
||
}
|
||
|
||
void register_museum(void)
|
||
{
|
||
register_bordertype(&bt_questportal);
|
||
|
||
at_register(&at_warden);
|
||
at_register(&at_museumexit);
|
||
at_register(&at_museumgivebackcookie);
|
||
at_register(&at_museumgiveback);
|
||
|
||
register_item_use(use_museumticket, "use_museumticket");
|
||
register_item_use(use_museumkey, "use_museumkey");
|
||
register_item_use(use_museumexitticket, "use_museumexitticket");
|
||
}
|
||
|
||
#endif
|