server/src/common/kernel/message.c
2006-01-29 01:55:36 +00:00

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;
}