Crossfire Server  1.75.0
info.cpp
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 
99  int flags, int pri, const object *pl, uint8_t type,
100  uint8_t subtype, const char *message) {
101 
102  if ((flags&NDI_ALL) || (flags&NDI_ALL_DMS)) {
103  player *tmppl;
104 
105  for (tmppl = first_player; tmppl != NULL; tmppl = tmppl->next) {
106  if ((flags&NDI_ALL_DMS) && !QUERY_FLAG(tmppl->ob, FLAG_WIZ))
107  continue;
108  draw_ext_info((flags&~NDI_ALL&~NDI_ALL_DMS), pri, tmppl->ob, type, subtype, message);
109  }
110  // If NDI_NO_TRANSLATE is set, we assume the message was already printed to the log.
111  // So we skip it in that case. Otherwise we print it.
112  if ((~flags)&NDI_NO_TRANSLATE && pri < 10)
113  LOG(llevInfo, "-- %s\n", message);
114  return;
115  }
116 
117  if (!pl || (pl->type == PLAYER && pl->contr == NULL))
118  return;
119  if (pl->type != PLAYER)
120  return;
121  if (pri >= pl->contr->listening)
122  return;
123 
124  if (flags & NDI_DELAYED) {
126  do_print_ext(sl, flags & NDI_COLOR_MASK, type, subtype, flags&NDI_NO_TRANSLATE ? message : i18n(pl, message));
127  } else {
128  print_ext_msg(pl->contr->socket, flags&NDI_COLOR_MASK, type, subtype, flags&NDI_NO_TRANSLATE ? message : i18n(pl, message));
129  }
130 }
131 
156 void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format, ...) {
157  char buf[HUGE_BUF];
158  va_list ap;
159 
160  // Make sure the buf starts with \0.
161  // We will check for this when we attempt to print the translated string to buffer.
162  *buf = '\0';
163 
164  va_start(ap, format);
165  // If NDI_ALL or NDI_ALL_DM, first do the buffer for the untranslated message to the log file,
166  if ((flags&NDI_ALL) || (flags&NDI_ALL_DMS)) {
167  vsnprintf(buf, HUGE_BUF, format, ap);
168  LOG(llevInfo, "-- %s\n", buf);
169  va_end(ap);
170  va_start(ap, format);
171  }
172  // Then, if we need to translate, attempt to do so.
173  if ((~flags)&NDI_NO_TRANSLATE)
174  vsnprintf(buf, HUGE_BUF, i18n(pl, format), ap);
175  // Otherwise, print only to an empty string, because we already did if it is not empty.
176  else if (*buf == '\0')
177  vsnprintf(buf, HUGE_BUF, format, ap);
178  va_end(ap);
179  // Since we already translated, we do not need to do so again.
180  draw_ext_info(flags|NDI_NO_TRANSLATE, pri, pl, type, subtype, buf);
181 }
182 
196 void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1) {
197  player *pl;
198 
199  for (pl = first_player; pl != NULL; pl = pl->next)
200  if (pl->ob != NULL && pl->ob->map == map) {
201  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
202  }
203 }
204 
220 void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1) {
221  player *pl;
222 
223  for (pl = first_player; pl != NULL; pl = pl->next)
224  if (pl->ob != NULL && pl->ob->map == map && pl->ob != op) {
225  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
226  }
227 }
228 
246 void ext_info_map_except2(int color, const mapstruct *map, const object *op1, const object *op2, int type, int subtype, const char *str1) {
247  player *pl;
248 
249  for (pl = first_player; pl != NULL; pl = pl->next)
250  if (pl->ob != NULL && pl->ob->map == map
251  && pl->ob != op1 && pl->ob != op2) {
252  draw_ext_info(color, 0, pl->ob, type, subtype, str1);
253  }
254 }
255 
265 void rangetostring(const object *pl, char *obuf, size_t len) {
266  char name[MAX_BUF];
267 
268  switch (pl->contr->shoottype) {
269  case range_none:
270  strncpy(obuf, "Range: nothing", len);
271  break;
272 
273  case range_bow: {
274  object *op;
275 
276  for (op = pl->inv; op; op = op->below)
277  if (op->type == BOW && QUERY_FLAG(op, FLAG_APPLIED))
278  break;
279  if (op == NULL)
280  break;
281 
282  query_base_name(op, 0, name, MAX_BUF);
283  snprintf(obuf, len, "Range: %s (%s)", name, op->race ? op->race : "nothing");
284  }
285  break;
286 
287  case range_magic:
288  if (settings.casting_time == TRUE && pl->casting_time > -1) {
289  if (pl->casting_time == 0)
290  snprintf(obuf, len, "Range: Holding spell (%s)", pl->spell->name);
291  else
292  snprintf(obuf, len, "Range: Casting spell (%s)", pl->spell->name);
293  }
294  else
295  snprintf(obuf, len, "Range: spell (%s)", pl->contr->ranges[range_magic]->name);
296  break;
297 
298  case range_misc:
299  if (pl->contr->ranges[range_misc])
300  query_base_name(pl->contr->ranges[range_misc], 0, name, MAX_BUF);
301  else
302  strncpy(name, "none", MAX_BUF);
303  snprintf(obuf, len, "Range: %s", name);
304  break;
305 
306  /* range_scroll is only used for controlling golems. If the
307  * the player does not have a golem, reset some things.
308  */
309  case range_golem:
310  if (pl->contr->ranges[range_golem] != NULL)
311  snprintf(obuf, len, "Range: golem (%s)", pl->contr->ranges[range_golem]->name);
312  else {
313  pl->contr->shoottype = range_none;
314  strncpy(obuf, "Range: nothing", len);
315  }
316  break;
317 
318  case range_skill:
319  snprintf(obuf, len, "Skill: %s", pl->chosen_skill != NULL ? pl->chosen_skill->name : "none");
320  break;
321 
322  case range_builder:
324  snprintf(obuf, len, "Builder: %s", name);
325  break;
326 
327  default:
328  strncpy(obuf, "Range: illegal", len);
329  }
330 }
331 
335 void set_title(const object *pl, char *buf, size_t len) {
336  char *p;
337 
338  snprintf(buf, len, "Player: %s ", pl->name);
339  p = strchr(buf, '\0');
340  player_get_title(pl->contr, p, (buf+len)-p);
341 }
342 
360 static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py) {
361  int x, y, dx, dy, mflags, l;
362  int16_t nx, ny;
363  mapstruct *mp;
364  const Face *f;
365  object *ob;
366 
367  for (dx = -1; dx <= 1; dx++) {
368  for (dy = -1; dy <= 1; dy++) {
369  x = px+dx;
370  y = py+dy;
371 
372  if (FABS(x) >= MAGIC_MAP_HALF || FABS(y) >= MAGIC_MAP_HALF)
373  continue;
374 
375  mp = pl->map;
376  nx = pl->x+x;
377  ny = pl->y+y;
378 
379  mflags = get_map_flags(pl->map, &mp, nx, ny, &nx, &ny);
380  if (mflags&P_OUT_OF_MAP)
381  continue;
382 
383  if (map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] == 0) {
384  for (l = 0; l < MAP_LAYERS; l++) {
385  ob = GET_MAP_FACE_OBJ(mp, nx, ny, l);
386  if (ob && !ob->invisible && ob->face != blank_face)
387  break;
388  }
389  if (ob)
390  f = ob->face;
391  else
392  f = blank_face;
393 
394  /* Should probably have P_NO_MAGIC here also, but then shops don't
395  * work.
396  */
397  if (mflags&P_BLOCKSVIEW)
398  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_WALL|(f ? f->magicmap : 0);
399  else {
400  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_FLOOR|(f ? f->magicmap : 0);
401  magic_mapping_mark_recursive(pl, map_mark, x, y);
402  }
403  }
404  }
405  }
406 }
407 
428 void magic_mapping_mark(object *pl, char *map_mark, int strength) {
429  int x, y, mflags, l;
430  int16_t nx, ny;
431  mapstruct *mp;
432  const Face *f;
433  object *ob;
434 
435  for (x = -strength; x < strength; x++) {
436  for (y = -strength; y < strength; y++) {
437  mp = pl->map;
438  nx = pl->x+x;
439  ny = pl->y+y;
440  mflags = get_map_flags(pl->map, &mp, nx, ny, &nx, &ny);
441  if (mflags&P_OUT_OF_MAP)
442  continue;
443  else {
444  for (l = 0; l < MAP_LAYERS; l++) {
445  ob = GET_MAP_FACE_OBJ(mp, nx, ny, l);
446  if (ob && !ob->invisible && ob->face != blank_face)
447  break;
448  }
449  if (ob)
450  f = ob->face;
451  else
452  f = blank_face;
453  }
454 
455  if (mflags&P_BLOCKSVIEW)
456  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_WALL|(f ? f->magicmap : 0);
457  else {
458  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_FLOOR|(f ? f->magicmap : 0);
459  magic_mapping_mark_recursive(pl, map_mark, x, y);
460  }
461  }
462  }
463 }
464 
475 void draw_magic_map(object *pl) {
476  int x, y;
477  char map_mark[MAGIC_MAP_SIZE*MAGIC_MAP_SIZE];
478  int xmin, xmax, ymin, ymax;
479  SockList sl;
480 
481  if (pl->type != PLAYER) {
482  LOG(llevError, "Non player object called draw_map.\n");
483  return;
484  }
485 
486  /* First, we figure out what spaces are 'reachable' by the player */
487  memset(map_mark, 0, MAGIC_MAP_SIZE*MAGIC_MAP_SIZE);
488  magic_mapping_mark(pl, map_mark, 3);
489 
490  /* We now go through and figure out what spaces have been
491  * marked, and thus figure out rectangular region we send
492  * to the client (eg, if only a 10x10 area is visible, we only
493  * want to send those 100 spaces.)
494  */
495  xmin = MAGIC_MAP_SIZE;
496  ymin = MAGIC_MAP_SIZE;
497  xmax = 0;
498  ymax = 0;
499  for (x = 0; x < MAGIC_MAP_SIZE; x++) {
500  for (y = 0; y < MAGIC_MAP_SIZE; y++) {
501  if (map_mark[x+MAGIC_MAP_SIZE*y]&~FACE_FLOOR) {
502  xmin = MIN(x, xmin);
503  xmax = MAX(x, xmax);
504  ymin = MIN(y, ymin);
505  ymax = MAX(y, ymax);
506  }
507  }
508  }
509 
510  SockList_Init(&sl);
511  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);
512 
513  for (y = ymin; y <= ymax; y++) {
514  for (x = xmin; x <= xmax; x++) {
515  SockList_AddChar(&sl, map_mark[x+MAGIC_MAP_SIZE*y]&~FACE_FLOOR);
516  } /* x loop */
517  } /* y loop */
518 
519  Send_With_Handling(pl->contr->socket, &sl);
520  SockList_Term(&sl);
521 }
Error, serious thing.
Definition: logger.h:11
Use skill.
Definition: player.h:35
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
#define NDI_DELAYED
If set, then message is sent only after the player&#39;s tick completes.
Definition: newclient.h:280
object * ranges[range_size]
Object for each range.
Definition: player.h:118
Spell-related defines: spellpath, subtypes, ...
Information.
Definition: logger.h:12
void draw_magic_map(object *pl)
Creates and sends magic map to player.
Definition: info.cpp:475
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:271
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.cpp:42
No range selected.
Definition: player.h:30
player * first_player
First player.
Definition: init.cpp:106
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
#define FACE_WALL
Or&#39;d into the color value by the server right before sending.
Definition: newclient.h:319
Socket structure, represents a client-server connection.
Definition: newserver.h:93
#define NDI_NO_TRANSLATE
Do not attempt to translate.
Definition: newclient.h:275
int16_t y
Position in the map for this object.
Definition: object.h:335
Misc items.
Definition: player.h:33
#define TRUE
Definition: compat.h:11
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
#define FACE_FLOOR
Definition: newclient.h:318
#define MAX(x, y)
Definition: compat.h:24
int16_t x
Definition: object.h:335
void rangetostring(const object *pl, char *obuf, size_t len)
Get player&#39;s current range attack in obuf.
Definition: info.cpp:265
Global type definitions and header inclusions.
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
void set_title(const object *pl, char *buf, size_t len)
Sets player title.
Definition: info.cpp:335
uint8_t casting_time
It takes awhile to cast a spell.
Definition: global.h:271
#define MIN(x, y)
Definition: compat.h:21
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:114
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
object * spell
Spell that was being cast.
Definition: object.h:420
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
int16_t casting_time
Time left before spell goes off.
Definition: object.h:414
See Shooting Weapon.
Definition: object.h:123
#define NDI_ALL_DMS
Inform all logged in DMs.
Definition: newclient.h:272
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
void player_get_title(const player *pl, char *buf, size_t bufsize)
Returns the player&#39;s title.
Definition: player.cpp:233
Map builder.
Definition: player.h:36
Control golem.
Definition: player.h:34
socket_struct * socket
Socket information for this player.
Definition: player.h:109
SockList * player_get_delayed_buffer(player *pl)
Get a delayed socket buffer, that will be sent after the player&#39;s tick is complete.
Definition: player.cpp:4506
#define MAP_LAYERS
This correspondes to the map layers in the map2 protocol.
Definition: map.h:32
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
This is a game-map.
Definition: map.h:320
object * ob
The object representing the player.
Definition: player.h:179
const Face * face
Face with colors.
Definition: object.h:341
#define NDI_COLOR_MASK
Gives lots of room for expansion - we are using an int anyways, so we have the space to still do all ...
Definition: newclient.h:263
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
struct Settings settings
Global settings.
Definition: init.cpp:139
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: info.cpp:156
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:135
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: info.cpp:98
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
Skill-related defines, including subtypes.
static const flag_definition flags[]
Flag mapping.
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
#define MAGIC_MAP_HALF
Definition: map.h:25
See Player.
Definition: object.h:112
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:185
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:692
void magic_mapping_mark(object *pl, char *map_mark, int strength)
Creates magic map for player.
Definition: info.cpp:428
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Draws an extended message on the client.
Definition: info.cpp:62
sstring name
The name of the object, obviously...
Definition: object.h:319
static void do_print_ext(SockList *sl, int color, uint8_t type, uint8_t subtype, const char *message)
Fill a socket buffer with an extended message.
Definition: info.cpp:41
#define MAGIC_MAP_SIZE
Definition: map.h:24
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.cpp:300
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
Bow.
Definition: player.h:31
Spells.
Definition: player.h:32
One player.
Definition: player.h:107
void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1)
Writes to everyone on the map except *op.
Definition: info.cpp:220
StringBuffer * buf
Definition: readable.cpp:1563
#define P_BLOCKSVIEW
This spot blocks the player&#39;s view.
Definition: map.h:229
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
void ext_info_map_except2(int color, const mapstruct *map, const object *op1, const object *op2, int type, int subtype, const char *str1)
Writes to everyone on the map except op1 and op2.
Definition: info.cpp:246
uint8_t magicmap
Color to show this in magic map.
Definition: face.h:17
static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py)
Helper for magic map creation.
Definition: info.cpp:360
void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Writes to everyone on the specified map.
Definition: info.cpp:196
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447