Crossfire Server, Trunk  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) {
127  } else {
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])
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 }
Settings::casting_time
uint8_t casting_time
It takes awhile to cast a spell.
Definition: global.h:271
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
PLAYER
@ PLAYER
Definition: object.h:112
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
global.h
first_player
player * first_player
First player.
Definition: init.cpp:106
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
BOW
@ BOW
Definition: object.h:123
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:229
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
range_bow
@ range_bow
Bow.
Definition: player.h:31
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
NDI_NO_TRANSLATE
#define NDI_NO_TRANSLATE
Do not attempt to translate.
Definition: newclient.h:270
player
One player.
Definition: player.h:107
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
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)
Writes to everyone on the map except *op.
Definition: info.cpp:220
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:93
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
object::x
int16_t x
Definition: object.h:335
player::ob
object * ob
The object representing the player.
Definition: player.h:179
NDI_COLOR_MASK
#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:262
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
range_none
@ range_none
No range selected.
Definition: player.h:30
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
MIN
#define MIN(x, y)
Definition: compat.h:21
MAP_LAYERS
#define MAP_LAYERS
This correspondes to the map layers in the map2 protocol.
Definition: map.h:32
NDI_ALL_DMS
#define NDI_ALL_DMS
Inform all logged in DMs.
Definition: newclient.h:268
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
blank_face
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
skills.h
range_golem
@ range_golem
Control golem.
Definition: player.h:34
buf
StringBuffer * buf
Definition: readable.cpp:1565
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
MAX
#define MAX(x, y)
Definition: compat.h:24
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
magic_mapping_mark_recursive
static void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py)
Helper for magic map creation.
Definition: info.cpp:360
range_builder
@ range_builder
Map builder.
Definition: player.h:36
MAGIC_MAP_SIZE
#define MAGIC_MAP_SIZE
Definition: map.h:24
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
object::chosen_skill
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
print_ext_msg
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
magic_mapping_mark
void magic_mapping_mark(object *pl, char *map_mark, int strength)
Creates magic map for player.
Definition: info.cpp:428
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:118
object::spell
object * spell
Spell that was being cast.
Definition: object.h:420
range_magic
@ range_magic
Spells.
Definition: player.h:32
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
object::casting_time
int16_t casting_time
Time left before spell goes off.
Definition: object.h:414
NDI_DELAYED
#define NDI_DELAYED
If set, then message is sent only after the player's tick completes.
Definition: newclient.h:273
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
MAGIC_MAP_HALF
#define MAGIC_MAP_HALF
Definition: map.h:25
object::face
const Face * face
Face with colors.
Definition: object.h:341
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:185
FACE_WALL
#define FACE_WALL
Or'd into the color value by the server right before sending.
Definition: newclient.h:308
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
message
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Definition: survival-guide.txt:34
do_print_ext
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
FACE_FLOOR
#define FACE_FLOOR
Definition: newclient.h:307
player::shoottype
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:114
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:252
sproto.h
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
SockList_Init
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
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)
Writes to everyone on the map except op1 and op2.
Definition: info.cpp:246
player::listening
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:135
SockList_Term
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
range_misc
@ range_misc
Misc items.
Definition: player.h:33
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
set_title
void set_title(const object *pl, char *buf, size_t len)
Sets player title.
Definition: info.cpp:335
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
draw_ext_info
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
get_map_flags
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
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Get player's current range attack in obuf.
Definition: info.cpp:265
mapstruct
This is a game-map.
Definition: map.h:318
NDI_ALL
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:267
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
Face::magicmap
uint8_t magicmap
Color to show this in magic map.
Definition: face.h:17
draw_magic_map
void draw_magic_map(object *pl)
Creates and sends magic map to player.
Definition: info.cpp:475
player_get_delayed_buffer
SockList * player_get_delayed_buffer(player *pl)
Get a delayed socket buffer, that will be sent after the player's tick is complete.
Definition: player.cpp:4506
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:109
query_base_name
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
range_skill
@ range_skill
Use skill.
Definition: player.h:35
TRUE
#define TRUE
Definition: compat.h:11
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,...)
Sends message to player(s).
Definition: info.cpp:156
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:685
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
i18n
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.cpp:42
ext_info_map
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
player_get_title
void player_get_title(const player *pl, char *buf, size_t bufsize)
Returns the player's title.
Definition: player.cpp:233