Crossfire Server, Trunk
info.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
24 #include "global.h"
25 
26 #include <stdarg.h>
27 #include <string.h>
28 
29 #include "skills.h"
30 #include "spells.h"
31 #include "sproto.h"
32 
41 static void do_print_ext(SockList *sl, int color, uint8_t type, uint8_t subtype, const char *message) {
42  SockList_Init(sl);
43  SockList_AddPrintf(sl, "drawextinfo %d %hhu %hhu %s", color, type, subtype, message);
44 }
45 
62 void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message) {
63  SockList sl;
64  do_print_ext(&sl, color, type, subtype, message);
65  Send_With_Handling(ns, &sl);
66  SockList_Term(&sl);
67 }
68 
98  int flags, int pri, const object *pl, uint8_t type,
99  uint8_t subtype, const char *message) {
100 
101  if ((flags&NDI_ALL) || (flags&NDI_ALL_DMS)) {
102  player *tmppl;
103 
104  for (tmppl = first_player; tmppl != NULL; tmppl = tmppl->next) {
105  if ((flags&NDI_ALL_DMS) && !QUERY_FLAG(tmppl->ob, FLAG_WIZ))
106  continue;
107  draw_ext_info((flags&~NDI_ALL&~NDI_ALL_DMS), pri, tmppl->ob, type, subtype, message);
108  }
109  // If NDI_NO_TRANSLATE is set, we assume the message was already printed to the log.
110  // So we skip it in that case. Otherwise we print it.
111  if ((~flags)&NDI_NO_TRANSLATE)
112  LOG(llevInfo, "-- %s\n", message);
113  return;
114  }
115 
116  if (!pl || (pl->type == PLAYER && pl->contr == NULL))
117  return;
118  if (pl->type != PLAYER)
119  return;
120  if (pri >= pl->contr->listening)
121  return;
122 
123  if (flags & NDI_DELAYED) {
124  SockList *sl = player_get_delayed_buffer(pl->contr);
126  } else {
128  }
129 }
130 
155 void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format, ...) {
156  char buf[HUGE_BUF];
157  va_list ap;
158 
159  // Make sure the buf starts with \0.
160  // We will check for this when we attempt to print the translated string to buffer.
161  *buf = '\0';
162 
163  va_start(ap, format);
164  // If NDI_ALL or NDI_ALL_DM, first do the buffer for the untranslated message to the log file,
165  if ((flags&NDI_ALL) || (flags&NDI_ALL_DMS)) {
166  vsnprintf(buf, HUGE_BUF, format, ap);
167  LOG(llevInfo, "-- %s\n", buf);
168  va_end(ap);
169  va_start(ap, format);
170  }
171  // Then, if we need to translate, attempt to do so.
172  if ((~flags)&NDI_NO_TRANSLATE)
173  vsnprintf(buf, HUGE_BUF, i18n(pl, format), ap);
174  // Otherwise, print only to an empty string, because we already did if it is not empty.
175  else if (*buf == '\0')
176  vsnprintf(buf, HUGE_BUF, format, ap);
177  va_end(ap);
178  // Since we already translated, we do not need to do so again.
179  draw_ext_info(flags|NDI_NO_TRANSLATE, pri, pl, type, subtype, buf);
180 }
181 
195 void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1) {
196  player *pl;
197 
198  for (pl = first_player; pl != NULL; pl = pl->next)
199  if (pl->ob != NULL && pl->ob->map == map) {
200  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
201  }
202 }
203 
219 void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1) {
220  player *pl;
221 
222  for (pl = first_player; pl != NULL; pl = pl->next)
223  if (pl->ob != NULL && pl->ob->map == map && pl->ob != op) {
224  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
225  }
226 }
227 
245 void ext_info_map_except2(int color, const mapstruct *map, const object *op1, const object *op2, int type, int subtype, const char *str1) {
246  player *pl;
247 
248  for (pl = first_player; pl != NULL; pl = pl->next)
249  if (pl->ob != NULL && pl->ob->map == map
250  && pl->ob != op1 && pl->ob != op2) {
251  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
252  }
253 }
254 
264 void rangetostring(const object *pl, char *obuf, size_t len) {
265  char name[MAX_BUF];
266 
267  switch (pl->contr->shoottype) {
268  case range_none:
269  strncpy(obuf, "Range: nothing", len);
270  break;
271 
272  case range_bow: {
273  object *op;
274 
275  for (op = pl->inv; op; op = op->below)
276  if (op->type == BOW && QUERY_FLAG(op, FLAG_APPLIED))
277  break;
278  if (op == NULL)
279  break;
280 
282  snprintf(obuf, len, "Range: %s (%s)", name, op->race ? op->race : "nothing");
283  }
284  break;
285 
286  case range_magic:
287  if (settings.casting_time == TRUE && pl->casting_time > -1) {
288  if (pl->casting_time == 0)
289  snprintf(obuf, len, "Range: Holding spell (%s)", pl->spell->name);
290  else
291  snprintf(obuf, len, "Range: Casting spell (%s)", pl->spell->name);
292  }
293  else
294  snprintf(obuf, len, "Range: spell (%s)", pl->contr->ranges[range_magic]->name);
295  break;
296 
297  case range_misc:
298  if (pl->contr->ranges[range_misc])
300  else
301  strncpy(name, "none", MAX_BUF);
302  snprintf(obuf, len, "Range: %s", name);
303  break;
304 
305  /* range_scroll is only used for controlling golems. If the
306  * the player does not have a golem, reset some things.
307  */
308  case range_golem:
309  if (pl->contr->ranges[range_golem] != NULL)
310  snprintf(obuf, len, "Range: golem (%s)", pl->contr->ranges[range_golem]->name);
311  else {
312  pl->contr->shoottype = range_none;
313  strncpy(obuf, "Range: nothing", len);
314  }
315  break;
316 
317  case range_skill:
318  snprintf(obuf, len, "Skill: %s", pl->chosen_skill != NULL ? pl->chosen_skill->name : "none");
319  break;
320 
321  case range_builder:
323  snprintf(obuf, len, "Builder: %s", name);
324  break;
325 
326  default:
327  strncpy(obuf, "Range: illegal", len);
328  }
329 }
330 
334 void set_title(const object *pl, char *buf, size_t len) {
335  char *p;
336 
337  snprintf(buf, len, "Player: %s ", pl->name);
338  p = strchr(buf, '\0');
339  player_get_title(pl->contr, p, (buf+len)-p);
340 }
341 
359 static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py) {
360  int x, y, dx, dy, mflags, l;
361  int16_t nx, ny;
362  mapstruct *mp;
363  const Face *f;
364  object *ob;
365 
366  for (dx = -1; dx <= 1; dx++) {
367  for (dy = -1; dy <= 1; dy++) {
368  x = px+dx;
369  y = py+dy;
370 
371  if (FABS(x) >= MAGIC_MAP_HALF || FABS(y) >= MAGIC_MAP_HALF)
372  continue;
373 
374  mp = pl->map;
375  nx = pl->x+x;
376  ny = pl->y+y;
377 
378  mflags = get_map_flags(pl->map, &mp, nx, ny, &nx, &ny);
379  if (mflags&P_OUT_OF_MAP)
380  continue;
381 
382  if (map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] == 0) {
383  for (l = 0; l < MAP_LAYERS; l++) {
384  ob = GET_MAP_FACE_OBJ(mp, nx, ny, l);
385  if (ob && !ob->invisible && ob->face != blank_face)
386  break;
387  }
388  if (ob)
389  f = ob->face;
390  else
391  f = blank_face;
392 
393  /* Should probably have P_NO_MAGIC here also, but then shops don't
394  * work.
395  */
396  if (mflags&P_BLOCKSVIEW)
397  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_WALL|(f ? f->magicmap : 0);
398  else {
400  magic_mapping_mark_recursive(pl, map_mark, x, y);
401  }
402  }
403  }
404  }
405 }
406 
427 void magic_mapping_mark(object *pl, char *map_mark, int strength) {
428  int x, y, mflags, l;
429  int16_t nx, ny;
430  mapstruct *mp;
431  const Face *f;
432  object *ob;
433 
434  for (x = -strength; x < strength; x++) {
435  for (y = -strength; y < strength; y++) {
436  mp = pl->map;
437  nx = pl->x+x;
438  ny = pl->y+y;
439  mflags = get_map_flags(pl->map, &mp, nx, ny, &nx, &ny);
440  if (mflags&P_OUT_OF_MAP)
441  continue;
442  else {
443  for (l = 0; l < MAP_LAYERS; l++) {
444  ob = GET_MAP_FACE_OBJ(mp, nx, ny, l);
445  if (ob && !ob->invisible && ob->face != blank_face)
446  break;
447  }
448  if (ob)
449  f = ob->face;
450  else
451  f = blank_face;
452  }
453 
454  if (mflags&P_BLOCKSVIEW)
455  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_WALL|(f ? f->magicmap : 0);
456  else {
458  magic_mapping_mark_recursive(pl, map_mark, x, y);
459  }
460  }
461  }
462 }
463 
474 void draw_magic_map(object *pl) {
475  int x, y;
476  char map_mark[MAGIC_MAP_SIZE*MAGIC_MAP_SIZE];
477  int xmin, xmax, ymin, ymax;
478  SockList sl;
479 
480  if (pl->type != PLAYER) {
481  LOG(llevError, "Non player object called draw_map.\n");
482  return;
483  }
484 
485  /* First, we figure out what spaces are 'reachable' by the player */
486  memset(map_mark, 0, MAGIC_MAP_SIZE*MAGIC_MAP_SIZE);
487  magic_mapping_mark(pl, map_mark, 3);
488 
489  /* We now go through and figure out what spaces have been
490  * marked, and thus figure out rectangular region we send
491  * to the client (eg, if only a 10x10 area is visible, we only
492  * want to send those 100 spaces.)
493  */
494  xmin = MAGIC_MAP_SIZE;
495  ymin = MAGIC_MAP_SIZE;
496  xmax = 0;
497  ymax = 0;
498  for (x = 0; x < MAGIC_MAP_SIZE; x++) {
499  for (y = 0; y < MAGIC_MAP_SIZE; y++) {
500  if (map_mark[x+MAGIC_MAP_SIZE*y]&~FACE_FLOOR) {
501  xmin = MIN(x, xmin);
502  xmax = MAX(x, xmax);
503  ymin = MIN(y, ymin);
504  ymax = MAX(y, ymax);
505  }
506  }
507  }
508 
509  SockList_Init(&sl);
510  SockList_AddPrintf(&sl, "magicmap %d %d %d %d ", xmin <= xmax ? xmax-xmin+1 : 0, ymin <= ymax ? ymax-ymin+1 : 0, MAGIC_MAP_HALF-xmin, MAGIC_MAP_HALF-ymin);
511 
512  for (y = ymin; y <= ymax; y++) {
513  for (x = xmin; x <= xmax; x++) {
514  SockList_AddChar(&sl, map_mark[x+MAGIC_MAP_SIZE*y]&~FACE_FLOOR);
515  } /* x loop */
516  } /* y loop */
517 
518  Send_With_Handling(&pl->contr->socket, &sl);
519  SockList_Term(&sl);
520 }
Settings::casting_time
uint8_t casting_time
Definition: global.h:265
Face
Definition: face.h:14
PLAYER
@ PLAYER
Definition: object.h:107
global.h
banquet.l
l
Definition: banquet.py:164
BOW
@ BOW
Definition: object.h:118
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
ext_info_map_except
void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1)
Definition: info.c:219
range_bow
@ range_bow
Definition: player.h:31
NDI_NO_TRANSLATE
#define NDI_NO_TRANSLATE
Definition: newclient.h:266
diamondslots.x
x
Definition: diamondslots.py:15
obj::map
struct mapdef * map
Definition: object.h:300
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
socket_struct
Definition: newserver.h:89
pl::socket
socket_struct socket
Definition: player.h:107
set_title
void set_title(const object *pl, char *buf, size_t len)
Definition: info.c:334
pl::shoottype
rangetype shoottype
Definition: player.h:112
pl
Definition: player.h:105
NDI_COLOR_MASK
#define NDI_COLOR_MASK
Definition: newclient.h:258
guildjoin.ob
ob
Definition: guildjoin.py:42
range_none
@ range_none
Definition: player.h:30
blank_face
const Face * blank_face
Definition: image.c:35
MIN
#define MIN(x, y)
Definition: compat.h:21
pl::ob
object * ob
Definition: player.h:176
MAP_LAYERS
#define MAP_LAYERS
Definition: map.h:32
NDI_ALL_DMS
#define NDI_ALL_DMS
Definition: newclient.h:264
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.c:101
skills.h
range_golem
@ range_golem
Definition: player.h:34
smoking_pipe.color
color
Definition: smoking_pipe.py:5
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MAX
#define MAX(x, y)
Definition: compat.h:24
settings
struct Settings settings
Definition: init.c:39
range_builder
@ range_builder
Definition: player.h:36
MAGIC_MAP_SIZE
#define MAGIC_MAP_SIZE
Definition: map.h:24
pl::next
struct pl * next
Definition: player.h:106
disinfect.map
map
Definition: disinfect.py:4
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Definition: info.c:264
obj::name
sstring name
Definition: object.h:314
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: info.c:97
range_magic
@ range_magic
Definition: player.h:32
NDI_DELAYED
#define NDI_DELAYED
Definition: newclient.h:269
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:103
MAGIC_MAP_HALF
#define MAGIC_MAP_HALF
Definition: map.h:25
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Definition: map.h:185
FACE_WALL
#define FACE_WALL
Definition: newclient.h:304
first_player
EXTERN player * first_player
Definition: global.h:115
FACE_FLOOR
#define FACE_FLOOR
Definition: newclient.h:303
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: info.c:155
sproto.h
mapdef
Definition: map.h:317
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.c:52
pl::listening
uint8_t listening
Definition: player.h:133
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
MAX_BUF
#define MAX_BUF
Definition: define.h:35
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.c:62
range_misc
@ range_misc
Definition: player.h:33
diamondslots.message
string message
Definition: diamondslots.py:57
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
llevInfo
@ llevInfo
Definition: logger.h:12
spells.h
ext_info_map_except2
void ext_info_map_except2(int color, const mapstruct *map, const object *op1, const object *op2, int type, int subtype, const char *str1)
Definition: info.c:245
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:263
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:686
diamondslots.y
y
Definition: diamondslots.py:16
Face::magicmap
uint8_t magicmap
Definition: face.h:17
print_ext_msg
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Definition: info.c:62
buf
StringBuffer * buf
Definition: readable.c:1610
draw_magic_map
void draw_magic_map(object *pl)
Definition: info.c:474
pl::ranges
object * ranges[range_size]
Definition: player.h:116
do_print_ext
static void do_print_ext(SockList *sl, int color, uint8_t type, uint8_t subtype, const char *message)
Definition: info.c:41
i18n
const char * i18n(const object *who, const char *code)
Definition: languages.c:55
player_get_delayed_buffer
SockList * player_get_delayed_buffer(player *pl)
Definition: player.c:4452
ext_info_map
void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Definition: info.c:195
magic_mapping_mark
void magic_mapping_mark(object *pl, char *map_mark, int strength)
Definition: info.c:427
magic_mapping_mark_recursive
static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py)
Definition: info.c:359
range_skill
@ range_skill
Definition: player.h:35
TRUE
#define TRUE
Definition: compat.h:11
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:301
player_get_title
void player_get_title(const struct pl *pl, char *buf, size_t bufsize)
Definition: player.c:232
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:440
SockList
Definition: newclient.h:681
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:199
P_BLOCKSVIEW
#define P_BLOCKSVIEW
Definition: map.h:227
give.name
name
Definition: give.py:27