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_start(ap, format);
169  }
170  // Then, if we need to translate, attempt to do so.
171  if ((~flags)&NDI_NO_TRANSLATE)
172  vsnprintf(buf, HUGE_BUF, i18n(pl, format), ap);
173  // Otherwise, print only to an empty string, because we already did if it is not empty.
174  else if (*buf == '\0')
175  vsnprintf(buf, HUGE_BUF, format, ap);
176  va_end(ap);
177  // Since we already translated, we do not need to do so again.
178  draw_ext_info(flags|NDI_NO_TRANSLATE, pri, pl, type, subtype, buf);
179 }
180 
194 void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1) {
195  player *pl;
196 
197  for (pl = first_player; pl != NULL; pl = pl->next)
198  if (pl->ob != NULL && pl->ob->map == map) {
199  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
200  }
201 }
202 
218 void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1) {
219  player *pl;
220 
221  for (pl = first_player; pl != NULL; pl = pl->next)
222  if (pl->ob != NULL && pl->ob->map == map && pl->ob != op) {
223  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
224  }
225 }
226 
244 void ext_info_map_except2(int color, const mapstruct *map, const object *op1, const object *op2, int type, int subtype, const char *str1) {
245  player *pl;
246 
247  for (pl = first_player; pl != NULL; pl = pl->next)
248  if (pl->ob != NULL && pl->ob->map == map
249  && pl->ob != op1 && pl->ob != op2) {
250  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
251  }
252 }
253 
263 void rangetostring(const object *pl, char *obuf, size_t len) {
264  char name[MAX_BUF];
265 
266  switch (pl->contr->shoottype) {
267  case range_none:
268  strncpy(obuf, "Range: nothing", len);
269  break;
270 
271  case range_bow: {
272  object *op;
273 
274  for (op = pl->inv; op; op = op->below)
275  if (op->type == BOW && QUERY_FLAG(op, FLAG_APPLIED))
276  break;
277  if (op == NULL)
278  break;
279 
281  snprintf(obuf, len, "Range: %s (%s)", name, op->race ? op->race : "nothing");
282  }
283  break;
284 
285  case range_magic:
286  if (settings.casting_time == TRUE && pl->casting_time > -1) {
287  if (pl->casting_time == 0)
288  snprintf(obuf, len, "Range: Holding spell (%s)", pl->spell->name);
289  else
290  snprintf(obuf, len, "Range: Casting spell (%s)", pl->spell->name);
291  }
292  else
293  snprintf(obuf, len, "Range: spell (%s)", pl->contr->ranges[range_magic]->name);
294  break;
295 
296  case range_misc:
297  if (pl->contr->ranges[range_misc])
299  else
300  strncpy(name, "none", MAX_BUF);
301  snprintf(obuf, len, "Range: %s", name);
302  break;
303 
304  /* range_scroll is only used for controlling golems. If the
305  * the player does not have a golem, reset some things.
306  */
307  case range_golem:
308  if (pl->contr->ranges[range_golem] != NULL)
309  snprintf(obuf, len, "Range: golem (%s)", pl->contr->ranges[range_golem]->name);
310  else {
311  pl->contr->shoottype = range_none;
312  strncpy(obuf, "Range: nothing", len);
313  }
314  break;
315 
316  case range_skill:
317  snprintf(obuf, len, "Skill: %s", pl->chosen_skill != NULL ? pl->chosen_skill->name : "none");
318  break;
319 
320  case range_builder:
322  snprintf(obuf, len, "Builder: %s", name);
323  break;
324 
325  default:
326  strncpy(obuf, "Range: illegal", len);
327  }
328 }
329 
333 void set_title(const object *pl, char *buf, size_t len) {
334  char *p;
335 
336  snprintf(buf, len, "Player: %s ", pl->name);
337  p = strchr(buf, '\0');
338  player_get_title(pl->contr, p, (buf+len)-p);
339 }
340 
358 static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py) {
359  int x, y, dx, dy, mflags, l;
360  int16_t nx, ny;
361  mapstruct *mp;
362  const Face *f;
363  object *ob;
364 
365  for (dx = -1; dx <= 1; dx++) {
366  for (dy = -1; dy <= 1; dy++) {
367  x = px+dx;
368  y = py+dy;
369 
370  if (FABS(x) >= MAGIC_MAP_HALF || FABS(y) >= MAGIC_MAP_HALF)
371  continue;
372 
373  mp = pl->map;
374  nx = pl->x+x;
375  ny = pl->y+y;
376 
377  mflags = get_map_flags(pl->map, &mp, nx, ny, &nx, &ny);
378  if (mflags&P_OUT_OF_MAP)
379  continue;
380 
381  if (map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] == 0) {
382  for (l = 0; l < MAP_LAYERS; l++) {
383  ob = GET_MAP_FACE_OBJ(mp, nx, ny, l);
384  if (ob && !ob->invisible && ob->face != blank_face)
385  break;
386  }
387  if (ob)
388  f = ob->face;
389  else
390  f = blank_face;
391 
392  /* Should probably have P_NO_MAGIC here also, but then shops don't
393  * work.
394  */
395  if (mflags&P_BLOCKSVIEW)
396  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_WALL|(f ? f->magicmap : 0);
397  else {
399  magic_mapping_mark_recursive(pl, map_mark, x, y);
400  }
401  }
402  }
403  }
404 }
405 
426 void magic_mapping_mark(object *pl, char *map_mark, int strength) {
427  int x, y, mflags, l;
428  int16_t nx, ny;
429  mapstruct *mp;
430  const Face *f;
431  object *ob;
432 
433  for (x = -strength; x < strength; x++) {
434  for (y = -strength; y < strength; y++) {
435  mp = pl->map;
436  nx = pl->x+x;
437  ny = pl->y+y;
438  mflags = get_map_flags(pl->map, &mp, nx, ny, &nx, &ny);
439  if (mflags&P_OUT_OF_MAP)
440  continue;
441  else {
442  for (l = 0; l < MAP_LAYERS; l++) {
443  ob = GET_MAP_FACE_OBJ(mp, nx, ny, l);
444  if (ob && !ob->invisible && ob->face != blank_face)
445  break;
446  }
447  if (ob)
448  f = ob->face;
449  else
450  f = blank_face;
451  }
452 
453  if (mflags&P_BLOCKSVIEW)
454  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_WALL|(f ? f->magicmap : 0);
455  else {
457  magic_mapping_mark_recursive(pl, map_mark, x, y);
458  }
459  }
460  }
461 }
462 
473 void draw_magic_map(object *pl) {
474  int x, y;
475  char map_mark[MAGIC_MAP_SIZE*MAGIC_MAP_SIZE];
476  int xmin, xmax, ymin, ymax;
477  SockList sl;
478 
479  if (pl->type != PLAYER) {
480  LOG(llevError, "Non player object called draw_map.\n");
481  return;
482  }
483 
484  /* First, we figure out what spaces are 'reachable' by the player */
485  memset(map_mark, 0, MAGIC_MAP_SIZE*MAGIC_MAP_SIZE);
486  magic_mapping_mark(pl, map_mark, 3);
487 
488  /* We now go through and figure out what spaces have been
489  * marked, and thus figure out rectangular region we send
490  * to the client (eg, if only a 10x10 area is visible, we only
491  * want to send those 100 spaces.)
492  */
493  xmin = MAGIC_MAP_SIZE;
494  ymin = MAGIC_MAP_SIZE;
495  xmax = 0;
496  ymax = 0;
497  for (x = 0; x < MAGIC_MAP_SIZE; x++) {
498  for (y = 0; y < MAGIC_MAP_SIZE; y++) {
499  if (map_mark[x+MAGIC_MAP_SIZE*y]&~FACE_FLOOR) {
500  xmin = MIN(x, xmin);
501  xmax = MAX(x, xmax);
502  ymin = MIN(y, ymin);
503  ymax = MAX(y, ymax);
504  }
505  }
506  }
507 
508  SockList_Init(&sl);
509  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);
510 
511  for (y = ymin; y <= ymax; y++) {
512  for (x = xmin; x <= xmax; x++) {
513  SockList_AddChar(&sl, map_mark[x+MAGIC_MAP_SIZE*y]&~FACE_FLOOR);
514  } /* x loop */
515  } /* y loop */
516 
517  Send_With_Handling(&pl->contr->socket, &sl);
518  SockList_Term(&sl);
519 }
Settings::casting_time
uint8_t casting_time
Definition: global.h:266
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:218
range_bow
@ range_bow
Definition: player.h:18
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:298
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:94
set_title
void set_title(const object *pl, char *buf, size_t len)
Definition: info.c:333
pl::shoottype
rangetype shoottype
Definition: player.h:99
pl
Definition: player.h:92
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:17
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:162
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:21
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:23
MAGIC_MAP_SIZE
#define MAGIC_MAP_SIZE
Definition: map.h:24
pl::next
struct pl * next
Definition: player.h:93
disinfect.map
map
Definition: disinfect.py:4
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Definition: info.c:263
obj::name
sstring name
Definition: object.h:312
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:19
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:324
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.c:52
pl::listening
uint8_t listening
Definition: player.h:120
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:20
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:244
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:685
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:1606
draw_magic_map
void draw_magic_map(object *pl)
Definition: info.c:473
pl::ranges
object * ranges[range_size]
Definition: player.h:103
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:4441
ext_info_map
void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Definition: info.c:194
magic_mapping_mark
void magic_mapping_mark(object *pl, char *map_mark, int strength)
Definition: info.c:426
magic_mapping_mark_recursive
static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py)
Definition: info.c:358
range_skill
@ range_skill
Definition: player.h:22
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:311
player_get_title
void player_get_title(const struct pl *pl, char *buf, size_t bufsize)
Definition: player.c:235
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