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 
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) {
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 
281  query_base_name(op, 0, name, MAX_BUF);
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 {
399  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_FLOOR|(f ? f->magicmap : 0);
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 {
457  map_mark[MAGIC_MAP_HALF+x+MAGIC_MAP_SIZE*(MAGIC_MAP_HALF+y)] = FACE_FLOOR|(f ? f->magicmap : 0);
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
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:106
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
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:105
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:219
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
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:177
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
MIN
#define MIN(x, y)
Definition: compat.h:21
MAP_LAYERS
#define MAP_LAYERS
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
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
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:359
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:427
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:116
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:182
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:112
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
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
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:245
player::listening
uint8_t listening
Which priority will be used in info_all.
Definition: player.h:133
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
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
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:334
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:97
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:264
mapstruct
This is a game-map.
Definition: map.h:315
NDI_ALL
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:267
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:474
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:4498
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
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:695
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:155
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
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:226
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:195
player_get_title
void player_get_title(const player *pl, char *buf, size_t bufsize)
Returns the player's title.
Definition: player.cpp:232