Crossfire Server, Trunk  R20513
dialog.c
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 
32 void free_dialog_information(object *op) {
33  struct_dialog_message *current, *next;
34  struct_dialog_reply *currep, *nextrep;
35 
37  return;
38 
40  if (!op->dialog_information)
41  return;
42 
43  current = op->dialog_information->all_messages;
44  while (current) {
45  next = current->next;
46  free(current->match);
47  free(current->message);
48  currep = current->replies;
49  while (currep) {
50  nextrep = currep->next;
51  free(currep->reply);
52  free(currep->message);
53  currep = nextrep;
54  }
55  free(current);
56  current = next;
57  }
58 
59  currep = op->dialog_information->all_replies;
60  while (currep) {
61  nextrep = currep->next;
62  free(currep->reply);
63  free(currep->message);
64  free(currep);
65  currep = nextrep;
66  }
67 
68  free(op->dialog_information);
69  op->dialog_information = NULL;
70 }
71 
79 static int matches(const char *exp, const char *text) {
80  char *pipe, *save, *msg;
81  int match = 0;
82 
83  if (exp[0] == '*')
84  return 1;
85 
86  msg = strdup(exp);
87 
88  pipe = strtok_r(msg, "|", &save);
89  while (pipe) {
90  if (re_cmp(text, pipe)) {
91  match = 1;
92  break;
93  }
94  pipe = strtok_r(NULL, "|", &save);
95  }
96 
97  free(msg);
98  return match;
99 }
100 
107 static void parse_dialog_information(object *op) {
108  struct_dialog_message *message = NULL, *last = NULL;
109  struct_dialog_reply *reply = NULL;
110  char *current, *save, *msg, *cp;
111  int len;
112  /* Used for constructing message with */
113  char *tmp = NULL;
114  size_t tmplen = 0;
115 
117  return;
119 
121  if (op->dialog_information == NULL)
123 
124  if (!op->msg)
125  return;
126 
127  msg = strdup(op->msg);
128  current = strtok_r(msg, "\n", &save);
129 
130  while (current) {
131  if (strncmp(current, "@match ", 7) == 0) {
132  if (message) {
133  message->message = tmp;
134  tmp = NULL;
135  tmplen = 0;
136  }
137 
138  message = (struct_dialog_message *)calloc(1, sizeof(struct_dialog_message));
139  if (last)
140  last->next = message;
141  else
142  op->dialog_information->all_messages = message;
143  last = message;
144 
145  message->match = strdup(current+7);
146  } else if ((strncmp(current, "@reply ", 7) == 0 && (len = 7)) || (strncmp(current, "@question ", 10) == 0 && (len = 10))) {
147  if (message) {
148  reply = (struct_dialog_reply *)calloc(1, sizeof(struct_dialog_reply));
149  reply->type = (len == 7 ? rt_reply : rt_question);
150  cp = strchr(current+len, ' ');
151  if (cp) {
152  *cp = '\0';
153  reply->reply = strdup(current+len);
154  reply->message = strdup(cp+1);
155  } else {
156  reply->reply = strdup(current+len);
157  reply->message = strdup(reply->reply);
158  LOG(llevDebug, "Warning: @reply/@question without message for %s!\n", op->name);
159  }
160  reply->next = message->replies;
161  message->replies = reply;
162 
163  reply = (struct_dialog_reply *)calloc(1, sizeof(struct_dialog_reply));
164  reply->reply = strdup(message->replies->reply);
165  reply->message = strdup(message->replies->message);
166  reply->type = message->replies->type;
167  reply->next = op->dialog_information->all_replies;
168  op->dialog_information->all_replies = reply;
169  } else
170  LOG(llevDebug, "Warning: @reply not in @match block for %s!\n", op->name);
171  } else if (message) {
172  /* Needed to set initial \0 */
173  int wasnull = FALSE;
174  tmplen += strlen(current)+2;
175  if (!tmp)
176  wasnull = TRUE;
177  tmp = realloc(tmp, tmplen*sizeof(char));
178  if (!tmp)
180  if (wasnull)
181  tmp[0] = 0;
182  strncat(tmp, current, tmplen-strlen(tmp)-1);
183  strncat(tmp, "\n", tmplen-strlen(tmp)-1);
184  }
185  current = strtok_r(NULL, "\n", &save);
186  }
187 
188  if (message) {
189  if (!tmp)
190  message->message = strdup("");
191  else
192  message->message = tmp;
193  tmp = NULL;
194  tmplen = 0;
195  }
196 
197  free(msg);
198 }
199 
209 int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply) {
210  if (!QUERY_FLAG(op, FLAG_DIALOG_PARSED))
212 
213  for (*message = op->dialog_information->all_messages; *message; *message = (*message)->next) {
214  if (matches((*message)->match, text)) {
215  break;
216  }
217  }
218  if (!*message)
219  return 0;
220 
221  for (*reply = op->dialog_information->all_replies; *reply; *reply = (*reply)->next) {
222  if (strcmp((*reply)->reply, text) == 0)
223  break;
224  }
225 
226  return 1;
227 }
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.c:209
#define SET_FLAG(xyz, p)
Definition: define.h:223
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
static void parse_dialog_information(object *op)
Parse the dialog information for op, and fills in obj::dialog_information.
Definition: dialog.c:107
char * message
What the player will actually say for this reply.
Definition: dialog.h:20
#define TRUE
Definition: compat.h:10
#define FALSE
Definition: compat.h:11
Global type definitions and header inclusions.
void free_dialog_information(object *op)
Frees obj::dialog_information.
Definition: dialog.c:32
struct struct_dialog_message * next
Next message, NULL if last.
Definition: dialog.h:32
One reply a NPC can expect.
Definition: dialog.h:18
struct struct_dialog_reply * all_replies
All replies, to quickly search things.
Definition: dialog.h:39
#define strtok_r(x, y, z)
Definition: win32.h:62
Asking a question.
Definition: dialog.h:12
char * match
What the player should say, can be a regexp.
Definition: dialog.h:29
static int matches(const char *exp, const char *text)
Does the text match the expression?
Definition: dialog.c:79
Reply to something.
Definition: dialog.h:11
const char * name
The name of the object, obviously...
Definition: object.h:311
char * reply
Reply expected from the player.
Definition: dialog.h:19
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
const char * re_cmp(const char *, const char *)
re-cmp - get regular expression match.
Definition: re-cmp.c:69
struct struct_dialog_information * dialog_information
Parsed dialog information for this object.
Definition: object.h:300
Message information for a NPC.
Definition: dialog.h:38
Object structure, the core of Crossfire.
Only for debugging purposes.
Definition: logger.h:13
One message a NPC can react to.
Definition: dialog.h:28
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
struct struct_dialog_reply * replies
Replies this message has.
Definition: dialog.h:31
char * message
What the NPC will say.
Definition: dialog.h:30
char * strdup(const char *str)
Portable implementation of strdup(3).
Definition: porting.c:200
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
struct struct_dialog_message * all_messages
Messages the NPC can use.
Definition: dialog.h:40
#define FLAG_DIALOG_PARSED
Was the object::msg field parsed? Temporary flag not saved.
Definition: define.h:243
struct struct_dialog_reply * next
Next reply, NULL for last.
Definition: dialog.h:22
reply_type type
Type of message.
Definition: dialog.h:21
Core defines: object types, flags, etc.