Crossfire Server, Trunk  1.75.0
dialog.cpp
Go to the documentation of this file.
1 
2 /*
3  * Crossfire -- cooperative multi-player graphical RPG and adventure game
4  *
5  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
6  * Copyright (c) 1992 Frank Tore Johansen
7  *
8  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
9  * welcome to redistribute it under certain conditions. For details, please
10  * see COPYING and LICENSE.
11  *
12  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
13  */
14 
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "global.h"
24 #include "define.h"
25 #include "object.h"
26 #include "dialog.h"
27 
28 const char *NPC_DIALOG_ARCH = "npc_dialog";
29 
34 void free_dialog_information(object *op) {
35  struct_dialog_message *current, *next;
36  struct_dialog_reply *currep, *nextrep;
37 
39  return;
40 
42  if (!op->dialog_information)
43  return;
44 
45  current = op->dialog_information->all_messages;
46  while (current) {
47  next = current->next;
48  free(current->match);
49  free(current->message);
50  currep = current->replies;
51  while (currep) {
52  nextrep = currep->next;
53  free(currep->reply);
54  free(currep->message);
55  currep = nextrep;
56  }
57  free(current);
58  current = next;
59  }
60 
61  currep = op->dialog_information->all_replies;
62  while (currep) {
63  nextrep = currep->next;
64  free(currep->reply);
65  free(currep->message);
66  free(currep);
67  currep = nextrep;
68  }
69 
70  free(op->dialog_information);
71  op->dialog_information = NULL;
72 }
73 
81 static int matches(const char *exp, const char *text) {
82  char *pipe, *save = NULL, *msg;
83  int match = 0;
84 
85  if (exp[0] == '*')
86  return 1;
87 
88  msg = strdup(exp);
89 
90  pipe = strtok_r(msg, "|", &save);
91  while (pipe) {
92  if (re_cmp(text, pipe)) {
93  match = 1;
94  break;
95  }
96  pipe = strtok_r(NULL, "|", &save);
97  }
98 
99  free(msg);
100  return match;
101 }
102 
106 static bool is_cfdialog(const char *msg) {
107  return msg[0] == '{';
108 }
109 
110 void dialog_preparse(object *op) {
111  // Detect inline CFDialog JSON dialogs. Make sure there's a npc_dialog.
112  if (op->msg && is_cfdialog(op->msg)) {
114  object *tmp = create_archetype(NPC_DIALOG_ARCH);
115  object_insert_in_ob(tmp, op);
116  op->event_bitmask &= ~BITMASK_VALID; // must force update to make event work
117  }
118  }
119 }
120 
127 static void parse_dialog_information(object *op) {
128  struct_dialog_message *message = NULL, *last = NULL;
129  struct_dialog_reply *reply = NULL;
130  char *current, *save = NULL, *msg, *cp;
131  int len;
132  /* Used for constructing message with */
133  char *tmp = NULL;
134  size_t tmplen = 0;
135 
137  return;
139 
141  if (op->dialog_information == NULL)
143 
144  if (!op->msg || is_cfdialog(op->msg))
145  return;
146 
147  msg = strdup(op->msg);
148  current = strtok_r(msg, "\n", &save);
149 
150  while (current) {
151  if (strncmp(current, "@match ", 7) == 0) {
152  if (message) {
153  message->message = tmp;
154  tmp = NULL;
155  tmplen = 0;
156  }
157 
158  message = (struct_dialog_message *)calloc(1, sizeof(struct_dialog_message));
159  if (last)
160  last->next = message;
161  else
163  last = message;
164 
165  message->match = strdup(current+7);
166  } else if ((strncmp(current, "@reply ", 7) == 0 && (len = 7)) || (strncmp(current, "@question ", 10) == 0 && (len = 10))) {
167  if (message) {
168  reply = (struct_dialog_reply *)calloc(1, sizeof(struct_dialog_reply));
169  reply->type = (len == 7 ? rt_reply : rt_question);
170  cp = strchr(current+len, ' ');
171  if (cp) {
172  *cp = '\0';
173  reply->reply = strdup(current+len);
174  reply->message = strdup(cp+1);
175  } else {
176  reply->reply = strdup(current+len);
177  reply->message = strdup(reply->reply);
178  LOG(llevDebug, "Warning: @reply/@question without message for %s!\n", op->name);
179  }
180  reply->next = message->replies;
181  message->replies = reply;
182 
183  reply = (struct_dialog_reply *)calloc(1, sizeof(struct_dialog_reply));
184  reply->reply = strdup(message->replies->reply);
185  reply->message = strdup(message->replies->message);
186  reply->type = message->replies->type;
187  reply->next = op->dialog_information->all_replies;
188  op->dialog_information->all_replies = reply;
189  } else
190  LOG(llevDebug, "Warning: @reply not in @match block for %s!\n", op->name);
191  } else if ((strncmp(current, "@identify", 9) == 0 && (len = 9))) {
192  if (message) {
193  message->identifies = true;
194  }
195  } else if (message) {
196  /* Needed to set initial \0 */
197  int wasnull = FALSE;
198  tmplen += strlen(current)+2;
199  if (!tmp)
200  wasnull = TRUE;
201  tmp = static_cast<char *>(realloc(tmp, tmplen*sizeof(char)));
202  if (!tmp)
204  if (wasnull)
205  tmp[0] = 0;
206  strncat(tmp, current, tmplen-strlen(tmp)-1);
207  strncat(tmp, "\n", tmplen-strlen(tmp)-1);
208  }
209  current = strtok_r(NULL, "\n", &save);
210  }
211 
212  if (message) {
213  if (!tmp)
214  message->message = strdup("");
215  else
216  message->message = tmp;
217  tmp = NULL;
218  tmplen = 0;
219  }
220 
221  free(msg);
222 }
223 
233 int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply) {
234  if (!QUERY_FLAG(op, FLAG_DIALOG_PARSED))
236 
237  for (*message = op->dialog_information->all_messages; *message; *message = (*message)->next) {
238  if (matches((*message)->match, text)) {
239  break;
240  }
241  }
242  if (!*message)
243  return 0;
244 
245  for (*reply = op->dialog_information->all_replies; *reply; *reply = (*reply)->next) {
246  if (strcmp((*reply)->reply, text) == 0)
247  break;
248  }
249 
250  return 1;
251 }
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:106
global.h
struct_dialog_reply::next
struct struct_dialog_reply * next
Next reply, NULL for last.
Definition: dialog.h:20
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
FALSE
#define FALSE
Definition: compat.h:14
struct_dialog_message::match
char * match
What the player should say, can be a regexp.
Definition: dialog.h:27
struct_dialog_message::replies
struct struct_dialog_reply * replies
Replies this message has.
Definition: dialog.h:29
is_cfdialog
static bool is_cfdialog(const char *msg)
Return true if the given message is detected as CFDialog JSON.
Definition: dialog.cpp:106
struct_dialog_message::message
char * message
What the NPC will say.
Definition: dialog.h:28
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
FLAG_DIALOG_PARSED
#define FLAG_DIALOG_PARSED
Was the object::msg field parsed? Temporary flag not saved.
Definition: define.h:243
struct_dialog_reply::message
char * message
What the player will actually say for this reply.
Definition: dialog.h:18
dialog_preparse
void dialog_preparse(object *op)
Definition: dialog.cpp:110
object::event_bitmask
uint64_t event_bitmask
Bitmask of events this object has a handler for, see events.h.
Definition: object.h:447
struct_dialog_reply
One reply a NPC can expect.
Definition: dialog.h:16
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
struct_dialog_information
Message information for a NPC.
Definition: dialog.h:37
rt_reply
@ rt_reply
Reply to something.
Definition: dialog.h:9
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
re_cmp
const char * re_cmp(const char *, const char *)
re-cmp - get regular expression match.
Definition: re-cmp.cpp:68
struct_dialog_information::all_messages
struct struct_dialog_message * all_messages
Messages the NPC can use.
Definition: dialog.h:39
BITMASK_VALID
#define BITMASK_VALID
Bit indicating if the event bitmask is valid or not.
Definition: events.h:79
struct_dialog_reply::reply
char * reply
Reply expected from the player.
Definition: dialog.h:17
dialog.h
struct_dialog_message
One message a NPC can react to.
Definition: dialog.h:26
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
get_dialog_message
int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply)
Tries to find a message matching the said text.
Definition: dialog.cpp:233
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4237
rt_question
@ rt_question
Asking a question.
Definition: dialog.h:10
struct_dialog_information::all_replies
struct struct_dialog_reply * all_replies
All replies, to quickly search things.
Definition: dialog.h:38
define.h
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
text
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended text
Definition: media-tags.txt:35
struct_dialog_message::next
struct struct_dialog_message * next
Next message, NULL if last.
Definition: dialog.h:30
TRUE
#define TRUE
Definition: compat.h:11
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
object::dialog_information
struct_dialog_information * dialog_information
Parsed dialog information for this object.
Definition: object.h:308
free_dialog_information
void free_dialog_information(object *op)
Frees obj::dialog_information.
Definition: dialog.cpp:34
matches
static int matches(const char *exp, const char *text)
Does the text match the expression?
Definition: dialog.cpp:81
NPC_DIALOG_ARCH
const char * NPC_DIALOG_ARCH
Definition: dialog.cpp:28
struct_dialog_reply::type
reply_type type
Type of message.
Definition: dialog.h:19
object.h
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
parse_dialog_information
static void parse_dialog_information(object *op)
Parse the dialog information for op, and fills in obj::dialog_information.
Definition: dialog.cpp:127