2010-08-08 10:06:34 +02:00
|
|
|
/* vi: set ts=2:
|
|
|
|
+-------------------+
|
|
|
|
| | Christian Schlittchen <corwin@amber.kn-bremen.de>
|
|
|
|
| Eressea PBEM host | Enno Rehling <enno@eressea.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 <platform.h>
|
|
|
|
#include <kernel/config.h>
|
|
|
|
#include "order.h"
|
|
|
|
|
|
|
|
#include "skill.h"
|
|
|
|
|
|
|
|
#include <util/base36.h>
|
|
|
|
#include <util/bsdstring.h>
|
|
|
|
#include <util/language.h>
|
|
|
|
#include <util/log.h>
|
|
|
|
#include <util/parser.h>
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
# define ORD_KEYWORD(ord) (ord)->data->_keyword
|
|
|
|
# define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang
|
|
|
|
# define ORD_STRING(ord) (ord)->data->_str
|
|
|
|
|
|
|
|
typedef struct locale_data {
|
2011-03-07 08:02:35 +01:00
|
|
|
struct order_data *short_orders[MAXKEYWORDS];
|
|
|
|
struct order_data *study_orders[MAXSKILLS];
|
|
|
|
const struct locale *lang;
|
2010-08-08 10:06:34 +02:00
|
|
|
} locale_data;
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static struct locale_data *locale_array[16];
|
2010-08-08 10:06:34 +02:00
|
|
|
static int nlocales = 0;
|
|
|
|
|
|
|
|
typedef struct order_data {
|
2011-03-07 08:02:35 +01:00
|
|
|
char *_str;
|
|
|
|
int _refcount:20;
|
|
|
|
int _lindex:4;
|
2010-08-08 10:06:34 +02:00
|
|
|
keyword_t _keyword;
|
|
|
|
} order_data;
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static void release_data(order_data * data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
if (data) {
|
|
|
|
if (--data->_refcount == 0) {
|
2011-03-07 08:02:35 +01:00
|
|
|
if (data->_str)
|
|
|
|
free(data->_str);
|
2010-08-08 10:06:34 +02:00
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void replace_order(order ** dlist, order * orig, const order * src)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
while (*dlist != NULL) {
|
|
|
|
order *dst = *dlist;
|
|
|
|
if (dst->data == orig->data) {
|
|
|
|
order *cpy = copy_order(src);
|
2010-08-08 10:06:34 +02:00
|
|
|
*dlist = cpy;
|
|
|
|
cpy->next = dst->next;
|
|
|
|
dst->next = 0;
|
|
|
|
free_order(dst);
|
|
|
|
}
|
|
|
|
dlist = &(*dlist)->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
keyword_t get_keyword(const order * ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
if (ord == NULL) {
|
2010-08-08 10:06:34 +02:00
|
|
|
return NOKEYWORD;
|
|
|
|
}
|
|
|
|
return ORD_KEYWORD(ord);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** returns a plain-text representation of the order.
|
|
|
|
* This is the inverse function to the parse_order command. Note that
|
|
|
|
* keywords are expanded to their full length.
|
|
|
|
*/
|
2011-03-07 08:02:35 +01:00
|
|
|
static char *get_command(const order * ord, char *sbuffer, size_t size)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
char *bufp = sbuffer;
|
|
|
|
const char *text = ORD_STRING(ord);
|
2010-08-08 10:06:34 +02:00
|
|
|
keyword_t kwd = ORD_KEYWORD(ord);
|
|
|
|
int bytes;
|
|
|
|
|
|
|
|
if (ord->_persistent) {
|
2011-03-07 08:02:35 +01:00
|
|
|
if (size > 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
*bufp++ = '@';
|
|
|
|
--size;
|
|
|
|
} else {
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
}
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (kwd != NOKEYWORD) {
|
|
|
|
const struct locale *lang = ORD_LOCALE(ord);
|
|
|
|
if (size > 0) {
|
|
|
|
if (text)
|
|
|
|
--size;
|
|
|
|
bytes = (int)strlcpy(bufp, (const char *)LOC(lang, keywords[kwd]), size);
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
if (text)
|
|
|
|
*bufp++ = ' ';
|
2012-05-09 22:06:16 +02:00
|
|
|
} else {
|
2011-03-07 08:02:35 +01:00
|
|
|
WARN_STATIC_BUFFER();
|
2012-05-09 22:06:16 +02:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
if (text) {
|
|
|
|
bytes = (int)strlcpy(bufp, (const char *)text, size);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (wrptr(&bufp, &size, bytes) != 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
WARN_STATIC_BUFFER();
|
2011-03-07 08:02:35 +01:00
|
|
|
if (bufp - sbuffer >= 6) {
|
2010-08-08 10:06:34 +02:00
|
|
|
bufp -= 6;
|
2011-03-07 08:02:35 +01:00
|
|
|
while (bufp > sbuffer && (*bufp & 0x80) != 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
++size;
|
|
|
|
--bufp;
|
|
|
|
}
|
2011-08-28 06:51:21 +02:00
|
|
|
memcpy(bufp, "[...]", 6); /* TODO: make sure this only happens in eval_command */
|
2010-08-08 10:06:34 +02:00
|
|
|
bufp += 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (size > 0)
|
|
|
|
*bufp = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
return sbuffer;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
char *getcommand(const order * ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
char sbuffer[DISPLAYSIZE * 2];
|
2010-08-08 10:06:34 +02:00
|
|
|
return strdup(get_command(ord, sbuffer, sizeof(sbuffer)));
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void free_order(order * ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
if (ord != NULL) {
|
|
|
|
assert(ord->next == 0);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
release_data(ord->data);
|
|
|
|
free(ord);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
order *copy_order(const order * src)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
if (src != NULL) {
|
|
|
|
order *ord = (order *) malloc(sizeof(order));
|
2010-08-08 10:06:34 +02:00
|
|
|
ord->next = NULL;
|
|
|
|
ord->_persistent = src->_persistent;
|
|
|
|
ord->data = src->data;
|
|
|
|
++ord->data->_refcount;
|
|
|
|
return ord;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void set_order(struct order **destp, struct order *src)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
if (*destp == src)
|
|
|
|
return;
|
2010-08-08 10:06:34 +02:00
|
|
|
free_order(*destp);
|
|
|
|
*destp = src;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void free_orders(order ** olist)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
while (*olist) {
|
|
|
|
order *ord = *olist;
|
|
|
|
*olist = ord->next;
|
2010-08-08 10:06:34 +02:00
|
|
|
ord->next = NULL;
|
2011-03-07 08:02:35 +01:00
|
|
|
free_order(ord);
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *s = sptr;
|
|
|
|
order_data *data;
|
|
|
|
const struct locale *lang = locale_array[lindex]->lang;
|
|
|
|
|
|
|
|
if (kwd != NOKEYWORD)
|
|
|
|
s = (*sptr) ? sptr : NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/* learning, only one order_data per skill required */
|
2011-03-07 08:02:35 +01:00
|
|
|
if (kwd == K_STUDY) {
|
2010-08-08 10:06:34 +02:00
|
|
|
skill_t sk = findskill(parse_token(&sptr), lang);
|
|
|
|
switch (sk) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case NOSKILL: /* fehler */
|
|
|
|
break;
|
|
|
|
case SK_MAGIC: /* kann parameter haben */
|
|
|
|
if (*sptr != 0)
|
2010-08-08 10:06:34 +02:00
|
|
|
break;
|
2011-03-08 08:44:20 +01:00
|
|
|
default: /* nur skill als Parameter, keine extras */
|
|
|
|
data = locale_array[lindex]->study_orders[sk];
|
|
|
|
if (data == NULL) {
|
|
|
|
const char *skname = skillname(sk, lang);
|
|
|
|
data = (order_data *) malloc(sizeof(order_data));
|
|
|
|
locale_array[lindex]->study_orders[sk] = data;
|
|
|
|
data->_keyword = kwd;
|
|
|
|
data->_lindex = lindex;
|
|
|
|
if (strchr(skname, ' ') != NULL) {
|
|
|
|
size_t len = strlen(skname);
|
|
|
|
data->_str = malloc(len + 3);
|
|
|
|
data->_str[0] = '\"';
|
|
|
|
memcpy(data->_str + 1, skname, len);
|
|
|
|
data->_str[len + 1] = '\"';
|
|
|
|
data->_str[len + 2] = '\0';
|
|
|
|
} else {
|
|
|
|
data->_str = strdup(skname);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2011-03-08 08:44:20 +01:00
|
|
|
data->_refcount = 1;
|
|
|
|
}
|
|
|
|
++data->_refcount;
|
|
|
|
return data;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* orders with no parameter, only one order_data per order required */
|
2011-03-07 08:02:35 +01:00
|
|
|
else if (kwd != NOKEYWORD && *sptr == 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
data = locale_array[lindex]->short_orders[kwd];
|
|
|
|
if (data == NULL) {
|
2011-03-07 08:02:35 +01:00
|
|
|
data = (order_data *) malloc(sizeof(order_data));
|
2010-08-08 10:06:34 +02:00
|
|
|
locale_array[lindex]->short_orders[kwd] = data;
|
|
|
|
data->_keyword = kwd;
|
|
|
|
data->_lindex = lindex;
|
|
|
|
data->_str = NULL;
|
|
|
|
data->_refcount = 1;
|
|
|
|
}
|
|
|
|
++data->_refcount;
|
|
|
|
return data;
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
data = (order_data *) malloc(sizeof(order_data));
|
2010-08-08 10:06:34 +02:00
|
|
|
data->_keyword = kwd;
|
|
|
|
data->_lindex = lindex;
|
2011-03-07 08:02:35 +01:00
|
|
|
data->_str = s ? strdup(s) : NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
data->_refcount = 1;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static order *create_order_i(keyword_t kwd, const char *sptr, int persistent,
|
|
|
|
const struct locale *lang)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
order *ord = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
int lindex;
|
|
|
|
|
|
|
|
/* if this is just nonsense, then we skip it. */
|
|
|
|
if (lomem) {
|
|
|
|
switch (kwd) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case K_KOMMENTAR:
|
|
|
|
case NOKEYWORD:
|
|
|
|
return NULL;
|
|
|
|
case K_LIEFERE:
|
|
|
|
kwd = K_GIVE;
|
|
|
|
persistent = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
for (lindex = 0; lindex != nlocales; ++lindex) {
|
|
|
|
if (locale_array[lindex]->lang == lang)
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (lindex == nlocales) {
|
|
|
|
locale_array[nlocales] = (locale_data *) calloc(1, sizeof(locale_data));
|
2010-08-08 10:06:34 +02:00
|
|
|
locale_array[nlocales]->lang = lang;
|
|
|
|
++nlocales;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
ord = (order *) malloc(sizeof(order));
|
2010-08-08 10:06:34 +02:00
|
|
|
ord->_persistent = persistent;
|
|
|
|
ord->next = NULL;
|
|
|
|
|
|
|
|
ord->data = create_data(kwd, sptr, lindex);
|
|
|
|
|
|
|
|
return ord;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
order *create_order(keyword_t kwd, const struct locale * lang,
|
|
|
|
const char *params, ...)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
char zBuffer[DISPLAYSIZE];
|
|
|
|
if (params) {
|
2011-03-07 08:02:35 +01:00
|
|
|
char *bufp = zBuffer;
|
2010-08-08 10:06:34 +02:00
|
|
|
int bytes;
|
|
|
|
size_t size = sizeof(zBuffer) - 1;
|
|
|
|
va_list marker;
|
|
|
|
|
|
|
|
va_start(marker, params);
|
|
|
|
while (*params) {
|
2011-03-07 08:02:35 +01:00
|
|
|
if (*params == '%') {
|
2010-08-08 10:06:34 +02:00
|
|
|
int i;
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *s;
|
2010-08-08 10:06:34 +02:00
|
|
|
++params;
|
|
|
|
switch (*params) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case 's':
|
|
|
|
s = va_arg(marker, const char *);
|
|
|
|
bytes = (int)strlcpy(bufp, s, size);
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
i = va_arg(marker, int);
|
|
|
|
bytes = (int)strlcpy(bufp, itoa10(i), size);
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
i = va_arg(marker, int);
|
|
|
|
bytes = (int)strlcpy(bufp, itoa36(i), size);
|
|
|
|
if (wrptr(&bufp, &size, bytes) != 0)
|
|
|
|
WARN_STATIC_BUFFER();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(!"unknown format-character in create_order");
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
} else if (size > 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
*bufp++ = *params;
|
|
|
|
--size;
|
|
|
|
}
|
|
|
|
++params;
|
|
|
|
}
|
|
|
|
va_end(marker);
|
|
|
|
*bufp = 0;
|
|
|
|
} else {
|
|
|
|
zBuffer[0] = 0;
|
|
|
|
}
|
|
|
|
return create_order_i(kwd, zBuffer, 0, lang);
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
order *parse_order(const char *s, const struct locale * lang)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
while (*s && !isalnum(*(unsigned char *)s) && !ispunct(*(unsigned char *)s))
|
|
|
|
++s;
|
|
|
|
if (*s != 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
keyword_t kwd;
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *sptr;
|
2010-08-08 10:06:34 +02:00
|
|
|
int persistent = 0;
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
while (*s == '@') {
|
2010-08-08 10:06:34 +02:00
|
|
|
persistent = 1;
|
|
|
|
++s;
|
|
|
|
}
|
|
|
|
sptr = s;
|
|
|
|
kwd = findkeyword(parse_token(&sptr), lang);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (kwd != NOKEYWORD) {
|
|
|
|
while (isxspace(*(unsigned char *)sptr))
|
|
|
|
++sptr;
|
2010-08-08 10:06:34 +02:00
|
|
|
s = sptr;
|
|
|
|
}
|
|
|
|
return create_order_i(kwd, s, persistent, lang);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-11-12 05:11:19 +01:00
|
|
|
/**
|
|
|
|
* Returns true if the order qualifies as "repeated". An order is repeated if it will overwrite the
|
|
|
|
* old default order. K_BUY is in this category, but not K_MOVE.
|
|
|
|
*
|
|
|
|
* \param ord An order.
|
|
|
|
* \return true if the order is long
|
|
|
|
* \sa is_exclusive(), is_repeated(), is_persistent()
|
|
|
|
*/
|
2011-03-07 08:02:35 +01:00
|
|
|
boolean is_repeated(const order * ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
keyword_t kwd = ORD_KEYWORD(ord);
|
2011-03-07 08:02:35 +01:00
|
|
|
const struct locale *lang = ORD_LOCALE(ord);
|
2010-08-08 10:06:34 +02:00
|
|
|
param_t param;
|
|
|
|
|
|
|
|
switch (kwd) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case K_CAST:
|
|
|
|
case K_BUY:
|
|
|
|
case K_SELL:
|
|
|
|
case K_ROUTE:
|
|
|
|
case K_DRIVE:
|
|
|
|
case K_WORK:
|
|
|
|
case K_BESIEGE:
|
|
|
|
case K_ENTERTAIN:
|
|
|
|
case K_TAX:
|
|
|
|
case K_RESEARCH:
|
|
|
|
case K_SPY:
|
|
|
|
case K_STEAL:
|
|
|
|
case K_SABOTAGE:
|
|
|
|
case K_STUDY:
|
|
|
|
case K_TEACH:
|
|
|
|
case K_BREED:
|
|
|
|
case K_PIRACY:
|
|
|
|
case K_PLANT:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case K_FOLLOW:
|
|
|
|
/* FOLLOW is only a long order if we are following a ship. */
|
|
|
|
parser_pushstate();
|
|
|
|
init_tokens(ord);
|
|
|
|
skip_token();
|
|
|
|
param = getparam(lang);
|
|
|
|
parser_popstate();
|
|
|
|
|
|
|
|
if (param == P_SHIP)
|
2010-08-08 10:06:34 +02:00
|
|
|
return true;
|
2011-03-08 08:44:20 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case K_MAKE:
|
|
|
|
/* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen
|
|
|
|
* Arten von MACHE zaehlen aber als neue defaults und werden
|
|
|
|
* behandelt wie die anderen (deswegen kein break nach case
|
|
|
|
* K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl)
|
|
|
|
* abgespeichert). */
|
|
|
|
parser_pushstate();
|
|
|
|
init_tokens(ord); /* initialize token-parser */
|
|
|
|
skip_token();
|
|
|
|
param = getparam(lang);
|
|
|
|
parser_popstate();
|
|
|
|
|
|
|
|
if (param != P_TEMP)
|
2010-08-08 10:06:34 +02:00
|
|
|
return true;
|
2011-03-08 08:44:20 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-12 05:11:19 +01:00
|
|
|
/**
|
|
|
|
* Returns true if the order qualifies as "exclusive". An order is exclusive if it makes all other
|
|
|
|
* long orders illegal. K_MOVE is in this category, but not K_BUY.
|
|
|
|
*
|
|
|
|
* \param ord An order.
|
|
|
|
* \return true if the order is long
|
|
|
|
* \sa is_exclusive(), is_repeated(), is_persistent()
|
|
|
|
*/
|
2011-03-07 08:02:35 +01:00
|
|
|
boolean is_exclusive(const order * ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
keyword_t kwd = ORD_KEYWORD(ord);
|
2011-03-07 08:02:35 +01:00
|
|
|
const struct locale *lang = ORD_LOCALE(ord);
|
2010-08-08 10:06:34 +02:00
|
|
|
param_t param;
|
|
|
|
|
|
|
|
switch (kwd) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case K_MOVE:
|
|
|
|
case K_WEREWOLF:
|
|
|
|
/* these should not become persistent */
|
|
|
|
case K_ROUTE:
|
|
|
|
case K_DRIVE:
|
|
|
|
case K_WORK:
|
|
|
|
case K_BESIEGE:
|
|
|
|
case K_ENTERTAIN:
|
|
|
|
case K_TAX:
|
|
|
|
case K_RESEARCH:
|
|
|
|
case K_SPY:
|
|
|
|
case K_STEAL:
|
|
|
|
case K_SABOTAGE:
|
|
|
|
case K_STUDY:
|
|
|
|
case K_TEACH:
|
|
|
|
case K_BREED:
|
|
|
|
case K_PIRACY:
|
|
|
|
case K_PLANT:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case K_FOLLOW:
|
|
|
|
/* FOLLOW is only a long order if we are following a ship. */
|
|
|
|
parser_pushstate();
|
|
|
|
init_tokens(ord);
|
|
|
|
skip_token();
|
|
|
|
param = getparam(lang);
|
|
|
|
parser_popstate();
|
|
|
|
|
|
|
|
if (param == P_SHIP)
|
2010-08-08 10:06:34 +02:00
|
|
|
return true;
|
2011-03-08 08:44:20 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case K_MAKE:
|
|
|
|
/* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen
|
|
|
|
* Arten von MACHE zaehlen aber als neue defaults und werden
|
|
|
|
* behandelt wie die anderen (deswegen kein break nach case
|
|
|
|
* K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl)
|
|
|
|
* abgespeichert). */
|
|
|
|
parser_pushstate();
|
|
|
|
init_tokens(ord); /* initialize token-parser */
|
|
|
|
skip_token();
|
|
|
|
param = getparam(lang);
|
|
|
|
parser_popstate();
|
|
|
|
|
|
|
|
if (param != P_TEMP)
|
2010-08-08 10:06:34 +02:00
|
|
|
return true;
|
2011-03-08 08:44:20 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-12 05:11:19 +01:00
|
|
|
/**
|
|
|
|
* Returns true if the order qualifies as "long". An order is long if it excludes most other long
|
|
|
|
* orders.
|
|
|
|
*
|
|
|
|
* \param ord An order.
|
|
|
|
* \return true if the order is long
|
|
|
|
* \sa is_exclusive(), is_repeated(), is_persistent()
|
|
|
|
*/
|
2011-03-07 08:02:35 +01:00
|
|
|
boolean is_long(const order * ord)
|
2010-11-12 05:11:19 +01:00
|
|
|
{
|
|
|
|
keyword_t kwd = ORD_KEYWORD(ord);
|
2011-03-07 08:02:35 +01:00
|
|
|
const struct locale *lang = ORD_LOCALE(ord);
|
2010-11-12 05:11:19 +01:00
|
|
|
param_t param;
|
|
|
|
|
|
|
|
switch (kwd) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case K_CAST:
|
|
|
|
case K_BUY:
|
|
|
|
case K_SELL:
|
|
|
|
case K_MOVE:
|
|
|
|
case K_WEREWOLF:
|
|
|
|
case K_ROUTE:
|
|
|
|
case K_DRIVE:
|
|
|
|
case K_WORK:
|
|
|
|
case K_BESIEGE:
|
|
|
|
case K_ENTERTAIN:
|
|
|
|
case K_TAX:
|
|
|
|
case K_RESEARCH:
|
|
|
|
case K_SPY:
|
|
|
|
case K_STEAL:
|
|
|
|
case K_SABOTAGE:
|
|
|
|
case K_STUDY:
|
|
|
|
case K_TEACH:
|
|
|
|
case K_BREED:
|
|
|
|
case K_PIRACY:
|
|
|
|
case K_PLANT:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case K_FOLLOW:
|
|
|
|
/* FOLLOW is only a long order if we are following a ship. */
|
|
|
|
parser_pushstate();
|
|
|
|
init_tokens(ord);
|
|
|
|
skip_token();
|
|
|
|
param = getparam(lang);
|
|
|
|
parser_popstate();
|
|
|
|
|
|
|
|
if (param == P_SHIP)
|
2010-11-12 05:11:19 +01:00
|
|
|
return true;
|
2011-03-08 08:44:20 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case K_MAKE:
|
|
|
|
/* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen
|
|
|
|
* Arten von MACHE zaehlen aber als neue defaults und werden
|
|
|
|
* behandelt wie die anderen (deswegen kein break nach case
|
|
|
|
* K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl)
|
|
|
|
* abgespeichert). */
|
|
|
|
parser_pushstate();
|
|
|
|
init_tokens(ord); /* initialize token-parser */
|
|
|
|
skip_token();
|
|
|
|
param = getparam(lang);
|
|
|
|
parser_popstate();
|
|
|
|
|
|
|
|
if (param != P_TEMP)
|
2010-11-12 05:11:19 +01:00
|
|
|
return true;
|
2011-03-08 08:44:20 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
2010-11-12 05:11:19 +01:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if the order qualifies as "persistent". An order is persistent if it will be
|
|
|
|
* included in the template orders. @-orders, comments and most long orders are in this category,
|
|
|
|
* but not K_MOVE.
|
|
|
|
*
|
|
|
|
* \param ord An order.
|
|
|
|
* \return true if the order is persistent
|
|
|
|
* \sa is_exclusive(), is_repeated(), is_persistent()
|
|
|
|
*/
|
2011-03-07 08:02:35 +01:00
|
|
|
boolean is_persistent(const order * ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
keyword_t kwd = ORD_KEYWORD(ord);
|
2011-03-07 08:02:35 +01:00
|
|
|
boolean persist = ord->_persistent != 0;
|
|
|
|
switch (kwd) {
|
2011-03-08 08:44:20 +01:00
|
|
|
case K_MOVE:
|
|
|
|
case K_WEREWOLF:
|
|
|
|
case NOKEYWORD:
|
|
|
|
/* lang, aber niemals persistent! */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case K_KOMMENTAR:
|
|
|
|
case K_LIEFERE:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return persist || is_repeated(ord);
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
char *write_order(const order * ord, char *buffer, size_t size)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
if (ord == 0) {
|
|
|
|
buffer[0] = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
} else {
|
|
|
|
keyword_t kwd = ORD_KEYWORD(ord);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (kwd == NOKEYWORD) {
|
|
|
|
const char *text = ORD_STRING(ord);
|
2010-08-08 10:06:34 +02:00
|
|
|
strlcpy(buffer, (const char *)text, size);
|
|
|
|
} else {
|
|
|
|
get_command(ord, buffer, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
2011-02-22 07:00:03 +01:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void push_order(order ** ordp, order * ord)
|
|
|
|
{
|
|
|
|
while (*ordp)
|
|
|
|
ordp = &(*ordp)->next;
|
2011-02-22 07:00:03 +01:00
|
|
|
*ordp = ord;
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|