forked from github/server
316 lines
7.3 KiB
C
316 lines
7.3 KiB
C
/* vi: set ts=2:
|
|
*
|
|
* Eressea PB(E)M host Copyright (C) 1998-2003
|
|
* 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"
|
|
#include "message.h"
|
|
|
|
/* kernel includes */
|
|
#include "building.h"
|
|
#include "faction.h"
|
|
#include "item.h"
|
|
#include "order.h"
|
|
#include "plane.h"
|
|
#include "region.h"
|
|
#include "unit.h"
|
|
|
|
/* util includes */
|
|
#include <util/base36.h>
|
|
#include <util/goodies.h>
|
|
#include <util/message.h>
|
|
#include <util/nrmessage.h>
|
|
#include <util/crmessage.h>
|
|
#include <util/log.h>
|
|
|
|
/* libc includes */
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
typedef struct msg_setting {
|
|
struct msg_setting *next;
|
|
const struct message_type *type;
|
|
int level;
|
|
} msg_setting;
|
|
|
|
/************ Compatibility function *************/
|
|
#define MAXSTRLEN (4*DISPLAYSIZE+3)
|
|
#include "region.h"
|
|
#include "eressea.h"
|
|
|
|
messageclass * msgclasses;
|
|
|
|
const messageclass *
|
|
mc_find(const char * name)
|
|
{
|
|
messageclass ** mcp = &msgclasses;
|
|
if (name==NULL) return NULL;
|
|
for (;*mcp;mcp=&(*mcp)->next) {
|
|
messageclass * mc = *mcp;
|
|
if (!strcmp(mc->name, name)) break;
|
|
}
|
|
return *mcp;
|
|
}
|
|
|
|
const messageclass *
|
|
mc_add(const char * name)
|
|
{
|
|
messageclass ** mcp = &msgclasses;
|
|
if (name==NULL) return NULL;
|
|
for (;*mcp;mcp=&(*mcp)->next) {
|
|
messageclass * mc = *mcp;
|
|
if (!strcmp(mc->name, name)) break;
|
|
}
|
|
if (!*mcp) {
|
|
messageclass * mc = calloc(sizeof(messageclass), 1);
|
|
mc->name = strdup(name);
|
|
*mcp = mc;
|
|
}
|
|
return *mcp;
|
|
}
|
|
|
|
static void
|
|
arg_set(variant args[], const message_type * mtype, const char * buffer, variant v)
|
|
{
|
|
int i;
|
|
for (i=0;i!=mtype->nparameters;++i) {
|
|
if (!strcmp(buffer, mtype->pnames[i])) break;
|
|
}
|
|
if (i!=mtype->nparameters) {
|
|
args[i] = v;
|
|
} else {
|
|
fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name);
|
|
assert(!"program aborted.");
|
|
}
|
|
}
|
|
|
|
struct message *
|
|
msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...)
|
|
{
|
|
va_list marker;
|
|
const message_type * mtype = mt_find(name);
|
|
char paramname[64];
|
|
const char *ic = sig;
|
|
variant args[16];
|
|
variant var;
|
|
memset(args, 0, sizeof(args));
|
|
|
|
if (ord==NULL) ord = u->thisorder;
|
|
|
|
if (!mtype) {
|
|
log_error(("trying to create message of unknown type \"%s\"\n", name));
|
|
return NULL;
|
|
}
|
|
|
|
var.v = (void*)u;
|
|
arg_set(args, mtype, "unit", var);
|
|
var.v = (void*)u->region;
|
|
arg_set(args, mtype, "region", var);
|
|
var.v = (void*)ord;
|
|
arg_set(args, mtype, "command", var);
|
|
|
|
va_start(marker, sig);
|
|
while (*ic && !isalnum(*ic)) ic++;
|
|
while (*ic) {
|
|
char * oc = paramname;
|
|
int i;
|
|
|
|
while (isalnum(*ic)) *oc++ = *ic++;
|
|
*oc = '\0';
|
|
|
|
for (i=0;i!=mtype->nparameters;++i) {
|
|
if (!strcmp(paramname, mtype->pnames[i])) break;
|
|
}
|
|
if (i!=mtype->nparameters) {
|
|
if (mtype->types[i]->vtype==VAR_VOIDPTR) {
|
|
args[i].v = va_arg(marker, void*);
|
|
} else if (mtype->types[i]->vtype==VAR_INT) {
|
|
args[i].i = va_arg(marker, int);
|
|
} else {
|
|
assert(!"unknown variant type");
|
|
}
|
|
} else {
|
|
log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name));
|
|
assert(!"program aborted.");
|
|
}
|
|
while (*ic && !isalnum(*ic)) ic++;
|
|
}
|
|
va_end(marker);
|
|
|
|
return msg_create(mtype, args);
|
|
}
|
|
|
|
message *
|
|
msg_message(const char * name, const char* sig, ...)
|
|
/* msg_message("oops_error", "unit region command", u, r, cmd) */
|
|
{
|
|
va_list marker;
|
|
const message_type * mtype = mt_find(name);
|
|
char paramname[64];
|
|
const char *ic = sig;
|
|
variant args[16];
|
|
memset(args, 0, sizeof(args));
|
|
|
|
if (!mtype) {
|
|
log_warning(("trying to create message of unknown type \"%s\"\n", name));
|
|
return NULL;
|
|
}
|
|
|
|
va_start(marker, sig);
|
|
while (*ic && !isalnum(*ic)) ic++;
|
|
while (*ic) {
|
|
char * oc = paramname;
|
|
int i;
|
|
|
|
while (isalnum(*ic)) *oc++ = *ic++;
|
|
*oc = '\0';
|
|
|
|
for (i=0;i!=mtype->nparameters;++i) {
|
|
if (!strcmp(paramname, mtype->pnames[i])) break;
|
|
}
|
|
if (i!=mtype->nparameters) {
|
|
if (mtype->types[i]->vtype==VAR_VOIDPTR) {
|
|
args[i].v = va_arg(marker, void*);
|
|
} else if (mtype->types[i]->vtype==VAR_INT) {
|
|
args[i].i = va_arg(marker, int);
|
|
} else {
|
|
assert(!"unknown variant type");
|
|
}
|
|
} else {
|
|
log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name));
|
|
assert(!"program aborted.");
|
|
}
|
|
while (*ic && !isalnum(*ic)) ic++;
|
|
}
|
|
va_end(marker);
|
|
|
|
return msg_create(mtype, args);
|
|
}
|
|
|
|
static void
|
|
caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
|
|
{
|
|
message * m = NULL;
|
|
|
|
unused(level);
|
|
switch (mtype) {
|
|
case MSG_INCOME:
|
|
assert(f);
|
|
m = add_message(&f->msgs, msg_message("msg_economy", "string", s));
|
|
break;
|
|
case MSG_BATTLE:
|
|
assert(0 || !"battle-meldungen nicht über addmessage machen");
|
|
break;
|
|
case MSG_MOVE:
|
|
assert(f);
|
|
m = add_message(&f->msgs, msg_message("msg_movement", "string", s));
|
|
break;
|
|
case MSG_COMMERCE:
|
|
assert(f);
|
|
m = add_message(&f->msgs, msg_message("msg_economy", "string", s));
|
|
break;
|
|
case MSG_PRODUCE:
|
|
assert(f);
|
|
m = add_message(&f->msgs, msg_message("msg_production", "string", s));
|
|
break;
|
|
case MSG_MAGIC:
|
|
case MSG_COMMENT:
|
|
case MSG_MESSAGE:
|
|
case MSG_ORCVERMEHRUNG:
|
|
case MSG_EVENT:
|
|
/* Botschaften an REGION oder einzelne PARTEI */
|
|
m = msg_message("msg_event", "string", s);
|
|
if (!r) {
|
|
assert(f);
|
|
m = add_message(&f->msgs, m);
|
|
} else {
|
|
if (f==NULL) add_message(&r->msgs, m);
|
|
else r_addmessage(r, f, m);
|
|
}
|
|
break;
|
|
default:
|
|
assert(!"Ungültige Msg-Klasse!");
|
|
}
|
|
if (m) msg_release(m);
|
|
}
|
|
|
|
void
|
|
addmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
|
|
{
|
|
caddmessage(r, f, s, mtype, level);
|
|
}
|
|
|
|
void
|
|
mistake(const unit * u, struct order * ord, const char *comment, int mtype)
|
|
{
|
|
if (u->faction->no != MONSTER_FACTION) {
|
|
ADDMSG(&u->faction->msgs, msg_message("mistake",
|
|
"command error unit region", ord, comment, u, u->region));
|
|
}
|
|
}
|
|
|
|
void
|
|
cmistake(const unit * u, struct order *ord, int mno, int mtype)
|
|
{
|
|
static char ebuf[20];
|
|
unused(mtype);
|
|
|
|
if (u->faction->no == MONSTER_FACTION) return;
|
|
sprintf(ebuf, "error%d", mno);
|
|
ADDMSG(&u->faction->msgs, msg_message(ebuf,
|
|
"command unit region", ord, u, u->region));
|
|
}
|
|
|
|
extern unsigned int new_hashstring(const char* s);
|
|
|
|
void
|
|
free_messagelist(message_list * msgs)
|
|
{
|
|
struct mlist ** mlistptr = &msgs->begin;
|
|
while (*mlistptr) {
|
|
struct mlist * ml = *mlistptr;
|
|
*mlistptr = ml->next;
|
|
msg_release(ml->msg);
|
|
free(ml);
|
|
}
|
|
free(msgs);
|
|
}
|
|
|
|
message *
|
|
add_message(message_list** pm, message * m)
|
|
{
|
|
if (!lomem && m!=NULL) {
|
|
struct mlist * mnew = malloc(sizeof(struct mlist));
|
|
if (*pm==NULL) {
|
|
*pm = malloc(sizeof(message_list));
|
|
(*pm)->end=&(*pm)->begin;
|
|
}
|
|
mnew->msg = msg_addref(m);
|
|
mnew->next = NULL;
|
|
*((*pm)->end) = mnew;
|
|
(*pm)->end=&mnew->next;
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|