Crossfire Server  1.75.0
quest.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 
28 #include "global.h"
29 
30 #include <assert.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "output_file.h"
35 #include "sproto.h"
36 
37 #include "quest.h"
38 #include "assets.h"
39 
40 /* Media tags for information messages prefix. */
41 #define TAG_START "[color=#aa55ff]"
42 #define TAG_END "[/color]"
43 
45 #define QC_CAN_RESTART -1
46 
48 struct quest_state {
50  int state;
55 };
56 
58 struct quest_player {
62 };
63 
65 static quest_player *player_states = NULL;
66 
74  if (step == 0) {
75  // No error message, because 0 means not started.
76  return NULL;
77  }
78 
79  for (const auto qs : quest->steps) {
80  if (qs->step == step)
81  return qs;
82  }
83 
84  LOG(llevError, "quest %s has no required step %d\n", quest->quest_code, step);
85  return NULL;
86 }
87 
93  quest_state *qs = static_cast<quest_state *>(calloc(1, sizeof(quest_state)));
94  if (qs == NULL)
96  return qs;
97 }
98 
104  FILE *file;
105  char final[MAX_BUF], read[MAX_BUF], data[MAX_BUF];
106  quest_state *qs = NULL, *prev = NULL;
107  int warned = 0, state;
108  quest_definition *quest = NULL;
109 
110  snprintf(final, sizeof(final), "%s/%s/%s/%s.quest", settings.localdir, settings.playerdir, pq->player_name, pq->player_name);
111 
112  file = fopen(final, "r");
113  if (!file) {
114  /* no quest yet, no big deal */
115  return;
116  }
117 
118  while (fgets(read, sizeof(read), file) != NULL) {
119  if (sscanf(read, "quest %s\n", data)) {
120  qs = get_new_quest_state();
121  qs->code = add_string(data);
122  quest = quest_get_by_code(qs->code);
123  continue;
124  }
125 
126  if (!qs) {
127  if (!warned)
128  LOG(llevError, "quest: invalid file format for %s\n", final);
129  warned = 1;
130  continue;
131  }
132 
133  if (sscanf(read, "state %d\n", &state)) {
134  qs->state = state;
135  if (quest != NULL && state != -1 && state != 0) {
137  if (step == NULL) {
138  LOG(llevError, "invalid quest step %d for %s in %s\n", state, quest->quest_code, final);
139  }
140  else if (step->is_completion_step)
141  qs->is_complete = 1;
142  }
143  continue;
144  }
145  if (strcmp(read, "end_quest\n") == 0) {
146  if (quest == NULL) {
147  LOG(llevDebug, "Unknown quest %s in quest file %s\n", qs->code, final);
148  free(qs);
149  } else {
150  if (prev == NULL) {
151  pq->quests = qs;
152  } else {
153  prev->next = qs;
154  }
155  prev = qs;
156  }
157  qs = NULL;
158  continue;
159  }
160  if (sscanf(read, "completed %d\n", &state)) {
161  qs->was_completed = state ? 1 : 0;
162  continue;
163  }
164 
165  LOG(llevError, "quest: invalid line in %s: %s\n", final, read);
166  }
167 
168  if (qs)
169  LOG(llevError, "quest: missing end_quest in %s\n", final);
170 
171  fclose(file);
172 }
173 
178 static void quest_write_player_data(const quest_player *pq) {
179  FILE *file;
180  OutputFile of;
181  char fname[MAX_BUF];
182  const quest_state *state;
183 
184  snprintf(fname, sizeof(fname), "%s/%s/%s/%s.quest", settings.localdir, settings.playerdir, pq->player_name, pq->player_name);
185 
186  file = of_open(&of, fname);
187  if (file == NULL) {
188  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
189  return;
190  }
191 
192  state = pq->quests;
193 
194  while (state) {
195  fprintf(file, "quest %s\n", state->code);
196  fprintf(file, "state %d\n", state->state);
197  fprintf(file, "completed %d\n", state->was_completed);
198  fprintf(file, "end_quest\n");
199  state = state->next;
200  }
201 
202  if (!of_close(&of)) {
203  draw_ext_info(NDI_UNIQUE | NDI_ALL_DMS, 0, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "File write error on server!");
204  return;
205  }
207 }
208 
216  quest_state *qs = pq->quests;
217 
218  while (qs) {
219  if (qs->code == name)
220  return qs;
221  qs = qs->next;
222  }
223 
224  return NULL;
225 }
226 
234  quest_state *qs = get_state(pq, name);
235 
236  if (!qs) {
237  qs = static_cast<quest_state *>(calloc(1, sizeof(quest_state)));
238  if (!qs)
240  qs->code = add_refcount(name);
241  if (pq->quests != NULL) {
242  quest_state *last;
243  for (last = pq->quests ; last->next != NULL; last = last->next)
244  ;
245  last->next = qs;
246  } else {
247  pq->quests = qs;
248  }
249  }
250 
251  return qs;
252 }
253 
261 
262  while (pq) {
263  if (pq->player_name == pl->ob->name)
264  return pq;
265  pq = pq->next;
266  }
267 
268  return NULL;
269 }
270 
278  quest_player *pq = get_quest(pl);
279 
280  if (!pq) {
281  pq = static_cast<quest_player *>(calloc(1, sizeof(quest_player)));
282  if (!pq)
284  pq->player_name = add_refcount(pl->ob->name);
285  pq->next = player_states;
286  player_states = pq;
288  }
289 
290  return pq;
291 }
292 
293 /* quest_set_state can call itself through the function update_quests, so it needs to be declared here */
294 static void quest_set_state(player* dm, player *pl, sstring quest_code, int state, int started);
295 
302 static int evaluate_quest_conditions(const std::vector<quest_condition *> conditions, player *pl) {
303  int current_step;
304 
305  if (conditions.empty())
306  return 0;
307  for (const auto cond : conditions) {
308  current_step = quest_get_player_state(pl, cond->quest_code);
309  if (cond->minstep < 0 && cond->maxstep < 0) {
310  /* we are checking for the quest to have been completed. */
311  if (!quest_was_completed(pl, cond->quest_code))
312  return 0;
313  } else {
314  if (current_step < cond->minstep || current_step > cond->maxstep)
315  return 0;
316  }
317  }
318  return 1;
319 }
320 
321 static void do_update(const quest_definition *quest, void *user) {
322  player *pl = (player *)user;
323  int new_step = 0;
324  for (const quest_step_definition *step : quest->steps) {
325  if (evaluate_quest_conditions(step->conditions, pl)) {
326  new_step=new_step<step->step?step->step:new_step;
327  }
328  }
329  if (new_step > 0) {
330  int current_step = quest_get_player_state(pl, quest->quest_code);
331  if (new_step > current_step) {
332  quest_set_state(NULL, pl, quest->quest_code, new_step, 0);
333  }
334  }
335 }
336 
341 static void update_quests(player *pl) {
343 }
344 
353 static void quest_set_state(player* dm, player *pl, sstring quest_code, int state, int started) {
355  quest_state *qs = get_or_create_state(pq, quest_code);
356  quest_definition *quest = quest_find_by_code(quest_code);
357  quest_step_definition *step;
358 
359  if (!quest) {
360  if (dm) {
361  draw_ext_info_format(NDI_UNIQUE, 0, dm->ob, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_FAILURE, "Unknown quest %s!", quest_code);
362  } else {
363  LOG(llevError, "quest: asking for set_state of unknown quest %s!\n", quest_code);
364  }
365  return;
366  }
367 
368  if (!dm && state < 0) {
369  LOG(llevDebug, "quest_set_player_state: warning: called with invalid state %d for quest %s, player %s\n", state, pl->ob->name, quest_code);
370  state = 0;
371  }
372 
373  if (started && qs->state == 0) {
374  if (!dm) {
375  LOG(llevDebug, "quest_set_player_state: warning: called for player %s not having started quest %s\n", pl->ob->name, quest_code);
376  }
377  }
378 
379  qs->state = state;
380  if (state == 0) {
381  qs->is_complete = 0;
382  }
383 
384  step = quest_get_step(quest, state);
385  if (!step && state != 0) {
386  if (dm) {
387  draw_ext_info_format(NDI_UNIQUE, 0, dm->ob, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_FAILURE, "Couldn't find state definition %d for quest %s", state, quest_code);
388  } else {
389  LOG(llevError, "quest_set_player_state: couldn't find state definition %d for quest %s, player %s\n", state, quest_code, pl->ob->name);
390  }
391  }
392 
393  if (step && step->is_completion_step) {
394  /* don't send an update note if the quest was already completed, this is just to show the outcome afterwards. */
395  if (!qs->is_complete)
397  qs->was_completed = 1;
398  if (quest->quest_restart)
399  qs->state = QC_CAN_RESTART;
400  else
401  qs->is_complete = 1;
402 
403  } else if (step != 0) {
404  draw_ext_info_format(NDI_UNIQUE|NDI_DELAYED, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, "New objective for the quest '%s':", quest->quest_title);
406  }
407 
408  if (pl->socket->notifications > 0) {
410 
411  if (qs->sent_to_client) {
412  SockList_AddString(sl, "updquest ");
413  } else {
414  SockList_AddString(sl, "addquest ");
415  }
416 
417  SockList_AddInt(sl, quest->client_code);
418  if (qs->sent_to_client == 0) {
419  SockList_AddLen16Data(sl, quest->quest_title, strlen(quest->quest_title));
420  if (quest->face && !(pl->socket->faces_sent[quest->face->number]&NS_FACESENT_FACE))
421  esrv_send_face(pl->socket, quest->face, 0);
422  SockList_AddInt(sl, quest->face ? quest->face->number : 0);
423  SockList_AddChar(sl, quest->quest_restart ? 1 : 0);
424  SockList_AddInt(sl, quest->parent ? quest->parent->client_code : 0);
425  }
426 
427  SockList_AddChar(sl, (step == NULL || step->is_completion_step) ? 1 : 0);
428  if (step) {
429  SockList_AddLen16Data(sl, step->step_description, strlen(step->step_description));
430  } else {
431  const char *not_started = "Not started.";
432  SockList_AddLen16Data(sl, not_started, strlen(not_started));
433  }
434 
435  qs->sent_to_client = 1;
436  }
437 
438  if (pl->has_directory)
440  update_quests(pl);
441  LOG(llevDebug, "quest_set_player_state %s %s %d\n", pl->ob->name, quest_code, state);
442 
443 }
444 
452 static void quest_display(player *pl, quest_player *pq, int showall, const char* name) {
454  quest_definition *quest;
455  const char *restart;
456  int completed_count = 0, restart_count = 0, total_count = 0, current_count = 0;
457 
458  state = pq->quests;
459  while (state) {
460  quest = quest_find_by_code(state->code);
461  if (quest->parent == NULL) {
462  total_count++;
463  /* count up the number of completed quests first */
464  if (state->state == QC_CAN_RESTART) {
465  restart_count++;
466  completed_count++;
467  } else if (state->is_complete) {
468  completed_count++;
469  }
470  }
471  state = state->next;
472  }
473  if (completed_count > 0) {
474  if (!showall) {
475  if (restart_count > 0)
477  "%s completed %d out of %zu quests, of which %d may be restarted.", name, completed_count, quests_count(false), restart_count);
478  else
480  "%s completed %d quests", name, completed_count);
481  current_count = completed_count;
482  } else {
484  "%s completed the following quests:", name);
485  state = pq->quests;
486  while (state) {
487  quest = quest_find_by_code(state->code);
488  if (quest->parent == NULL) {
489  if (state->state == QC_CAN_RESTART || state->is_complete) {
490 
491  restart = state->state == QC_CAN_RESTART ? i18n(pl->ob, " (can be replayed)") : "";
493  "(%3d) %s%s", ++current_count, quest->quest_title, restart);
494  }
495  }
496  state = state->next;
497  }
498  }
499  }
500  if (total_count > completed_count) {
502  "%s started the following quests:", name);
503  state = pq->quests;
504  while (state) {
505  quest = quest_find_by_code(state->code);
506  if (quest->parent == NULL) {
507  if (state->state != QC_CAN_RESTART && state->is_complete == 0) {
508  quest = quest_find_by_code(state->code);
510  "(%3d) %s", ++current_count, quest->quest_title);
511  }
512  }
513  state = state->next;
514  }
515  }
516 }
517 
525 static void quest_list(player *pl, player *who, int showall, const char* name) {
526  quest_player *pq;
527 
528  /* ensure we load data if not loaded yet */
529  pq = get_or_create_quest(who);
530  if (!pq->quests) {
531  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, "%s didn't start any quest.", name);
532  return;
533  }
534 
535  quest_display(pl, pq, showall, name);
536 }
537 
545 static quest_state *get_quest_by_number(player *pl, int number) {
548  int questnum = 0;
549 
550  if (number <= 0 || !pq) {
551  return NULL;
552  }
553  /* count through completed quests first */
554  state = pq->quests;
555  while (state) {
556  /* count up the number of completed quests first */
557  if (!(quest_find_by_code(state->code)->parent) && (state->state == QC_CAN_RESTART || state->is_complete))
558  if (++questnum == number) return state;
559  state = state->next;
560  }
561  /* then active ones */
562  state = pq->quests;
563  while (state) {
564  /* count up the number of completed quests first */
565  if (!(quest_find_by_code(state->code)->parent) && state->state != QC_CAN_RESTART && state->is_complete ==0)
566  if (++questnum == number) return state;
567  state = state->next;
568  }
569  /* Ok, we didn't find our quest, return NULL*/
570  return NULL;
571 }
572 
580 static void quest_info(player *pl, player* who, quest_state *qs, int level) {
581  quest_definition *quest, *child;
584  const char *prefix;
585 
586  if (!qs) {
587  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, "Invalid quest number");
588  return;
589  }
590  quest = quest_find_by_code(qs->code);
591  if (!quest) {
592  /* already warned by quest_get */
593  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, "Quest: (internal error)");
594  return;
595  }
596 
598  if (QUERY_FLAG(pl->ob, FLAG_WIZ)) {
600  std::for_each(quest->steps.cbegin(), quest->steps.cend(), [&pl] (const auto &step) {
601  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, " " TAG_START "Step:" TAG_END " %d (%s)", step->step, step->step_description);
602  });
603  }
605 
606  quest_step_definition *step = quest_get_step(quest, qs->state);
607  if (qs->state == QC_CAN_RESTART || qs->is_complete) {
608  const char *restart = "";
609  if (quest->quest_restart)
610  restart = i18n(pl->ob, " (can be replayed)");
611  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, TAG_START "This quest has been completed%s.[/color]", restart);
612  }
613  prefix = "";
614  if (qs->state != QC_CAN_RESTART) {
615  /* ie, if we are in progress or completed for a non-restartable quest */
616  if (!step) {
617  /* already warned by quest_get_step */
619  return;
620  }
621  if (level > 0) {
622  prefix = " * ";
623  } else if (qs->is_complete)
624  prefix = "Outcome";
625  else
626  prefix = "Current Status";
627  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_QUESTS, " \n" TAG_START "%s:" TAG_END " %s", prefix, step->step_description);
628  }
629 
630  /* ok, now check all of the player's other quests for any children, and print those in order */
631  state = pq->quests;
632  while (state) {
633  child = quest_find_by_code(state->code);
634  if (child->parent == quest)
635  quest_info(pl, who, state, level+1);
636  state = state->next;
637  }
638  return;
639 }
640 
645 static void free_state(quest_player *pq) {
646  quest_state *qs = pq->quests, *next;
647 
648  while (qs) {
649  next = qs->next;
650  free_string(qs->code);
651  free(qs);
652  qs = next;
653  }
654  pq->quests = NULL;
655 }
656 
657 
658 /* public functions */
659 
666 int quest_get_player_state(player *pl, sstring quest_code) {
668  quest_state *s = get_state(q, quest_code);
669  quest_definition *quest = quest_find_by_code(quest_code);
670 
671  if (!s)
672  return 0;
673 
674  if (s->state == QC_CAN_RESTART && quest && quest->quest_restart)
675  return 0;
676 
677  return s->state;
678 }
679 
686 void quest_start(player *pl, sstring quest_code, int state) {
687  quest_player *pq;
688  quest_state *q;
689  quest_definition *quest;
690 
691  quest = quest_find_by_code(quest_code);
692  if (!quest) {
693  LOG(llevError, "quest_start: requested unknown quest %s\n", quest_code);
694  return;
695  }
696  pq = get_or_create_quest(pl);
697  q = get_or_create_state(pq, quest_code);
698 
699  if (state <= 0) {
700  state = 100;
701  LOG(llevDebug, "quest_start: negative state %d for %s quest %s\n", state, pl->ob->name, quest_code);
702  }
703 
704  /* if completed already, assume the player can redo it */
705  if (q->state > 0) {
706  LOG(llevDebug, "quest_start: warning: player %s has already started quest %s\n", pl->ob->name, quest_code);
707  }
708 
710 
711  quest_set_state(NULL, pl, quest_code, state, 0);
712 
713  /* saving state will be done in quest_set_state(). */
714 }
715 
722 void quest_set_player_state(player *pl, sstring quest_code, int state) {
723  quest_set_state(NULL, pl, quest_code, state, 1);
724 }
725 
732 int quest_was_completed(player *pl, sstring quest_code) {
734  quest_state *state = get_state(qp, quest_code);
735 
736  return (state && state->was_completed);
737 }
738 
744 void command_quest(object *op, const char *params) {
745  /* who to display information about, used when called in DM mode */
746  object *who;
747  const char *name;
748 
749  if (!op->contr) {
750  LOG(llevError, "command_quest called for a non player!\n");
751  return;
752  }
753 
754  if (!params || *params == '\0') {
755  command_help(op, "quest");
756  return;
757  }
758 
759  if (QUERY_FLAG(op, FLAG_WIZ)) {
760  char* dup = strdup(params);
761  char* space = strchr(dup, ' ');
762  player* other;
763  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_QUESTS, "Command 'quest' called in DM mode.");
764  if (space == NULL) {
765  free(dup);
766  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_FAILURE, "Please specify a player name.");
767  return;
768  }
769  params = params + (space - dup) + 1;
770  *space = '\0';
771  other = find_player_partial_name(dup);
772  if (other == NULL) {
773  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_FAILURE, "%s is not online, or ambiguous name.", dup);
774  free(dup);
775  return;
776  }
777  free(dup);
778  who = other->ob;
779  name = who->name;
780  } else {
781  who = op;
782  name = i18n(op, "You");
783  }
784 
785  if (strcmp(params, "list all") == 0) {
786  quest_list(op->contr, who->contr, 1, name);
787  return;
788  }
789 
790  if (strcmp(params, "list") == 0) {
791  quest_list(op->contr, who->contr, 0, name);
792  return;
793  }
794 
795  if (strncmp(params, "info ", 5) == 0) {
796  int number = atoi(params+5);
797  quest_info(op->contr, who->contr, get_quest_by_number(who->contr, number), 0);
798  return;
799  }
800 
801  /*
802  * Quest display for clients using the quest system, similar to 'info' above
803  * but using the (shared) quest's client_code instead of the (player unique) index.
804  */
805  if (strncmp(params, "info_c ", 7) == 0) {
806  int number = atoi(params+7);
807  quest_player *qp = get_quest(who->contr);
808  quest_state *qs = qp ? qp->quests : NULL;
809  while (qs) {
811  if (q && q->client_code == (uint32_t)number) {
812  break;
813  }
814  qs = qs->next;
815  }
816  if (qs) {
817  quest_info(op->contr, who->contr, qs, 0);
818  return;
819  }
820  draw_ext_info(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Invalid quest number");
821  return;
822  }
823 
824  if (strncmp(params, "reset ", 6) == 0) {
825  int number = atoi(params+6);
826  quest_state *q = get_quest_by_number(who->contr, number);
827  if (q == NULL) {
829  "You cannot reset a quest that you haven't started.");
830  return;
831  }
832  quest_set_state(NULL, who->contr, q->code, 0, 0);
834  "Quest progress reset.");
835  return;
836  }
837 
838  if (QUERY_FLAG(op, FLAG_WIZ) && strncmp(params, "set ", 4) == 0) {
839  char *dup = strdup(params + 4);
840  char *space = strrchr(dup, ' ');
841  int state, number;
842  quest_state* q;
843  if (space == NULL) {
844  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_FAILURE, "Syntax is: quest (player name) (quest number) (state).");
845  free(dup);
846  return;
847  }
848  *space = '\0';
849  number = atoi(dup);
850  q = get_quest_by_number(who->contr, number);
851  if (q == NULL) {
852  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN_DM, MSG_TYPE_COMMAND_FAILURE, "Invalid quest number %d.", number);
853  free(dup);
854  return;
855  }
856  state = atoi(space + 1);
857  quest_set_state(op->contr, who->contr, q->code, state, 0);
858  free(dup);
860  return;
861  }
862 
863  command_help(op, "quest");
864 }
865 
867 struct dump {
869  int level;
870 };
876 static void output_quests(const quest_definition *quest, void *user) {
877  dump *d = (dump *)user;
878  if (d->parent != quest->parent)
879  return;
880 
881  char prefix[MAX_BUF];
882  prefix[0] = '\0';
883  for (int i = 0; i < d->level; i++) {
884  strncat(prefix, "-", MAX_BUF - 1);
885  }
886  prefix[MAX_BUF - 1] = '\0';
887 
888  fprintf(logfile, "%s%s - %s - %zu steps (%srestartable)\n", prefix, quest->quest_code, quest->quest_title, quest->steps.size(), quest->quest_restart ? "" : "not ");
889 
890  dump r;
891  r.parent = quest;
892  r.level = d->level + 1;
894 }
895 
900 void dump_quests(void) {
901  dump d;
902  d.parent = NULL;
903  d.level = 0;
905  exit(0);
906 }
907 
911 void free_quest(void) {
913 
914  while (pq) {
915  next = pq->next;
916  free_state(pq);
918  free(pq);
919  pq = next;
920  }
921  player_states = NULL;
922 }
923 
930  quest_player *states = NULL;
931  quest_state *state = NULL;
932  SockList sl;
933  size_t size;
934  quest_definition *quest;
935  quest_step_definition *step;
936 
937  if (pl->socket->notifications < 1)
938  return;
939 
940  states = get_or_create_quest(pl);
941 
942  SockList_Init(&sl);
943  SockList_AddString(&sl, "addquest ");
944  for (state = states->quests; state != NULL; state = state->next) {
945 
946  quest = quest_get_by_code(state->code);
947  if (state->state == -1 || state->state == 0)
948  step = NULL;
949  else
950  step = quest_get_step(quest, state->state);
951 
952  size = 2 + (2 + strlen(quest->quest_title)) + 4 + 1 + (2 + (step != NULL ? strlen(step->step_description) : 0));
953 
954  if (SockList_Avail(&sl) < size) {
955  Send_With_Handling(pl->socket, &sl);
956  SockList_Reset(&sl);
957  SockList_AddString(&sl, "addquest ");
958  }
959 
960  SockList_AddInt(&sl, quest->client_code);
961  SockList_AddLen16Data(&sl, quest->quest_title, strlen(quest->quest_title));
962  if (quest->face && !(pl->socket->faces_sent[quest->face->number]&NS_FACESENT_FACE))
963  esrv_send_face(pl->socket, quest->face, 0);
964  SockList_AddInt(&sl, quest->face ? quest->face->number : 0);
965  SockList_AddChar(&sl, quest->quest_restart ? 1 : 0);
966  SockList_AddInt(&sl, quest->parent ? quest->parent->client_code : 0);
967  SockList_AddChar(&sl, (step == NULL || step->is_completion_step) ? 1 : 0);
968  if (step != NULL)
969  SockList_AddLen16Data(&sl, step->step_description, strlen(step->step_description));
970  else
971  SockList_AddShort(&sl, 0);
972 
973  state->sent_to_client = 1;
974  }
975 
976  Send_With_Handling(pl->socket, &sl);
977  SockList_Term(&sl);
978 }
979 
988  quest_player *qp = get_quest(pl);
989  if (qp != NULL && qp->quests != NULL) {
991  }
992 }
Error, serious thing.
Definition: logger.h:11
#define NDI_DELAYED
If set, then message is sent only after the player&#39;s tick completes.
Definition: newclient.h:280
sstring step_description
Step description to show player.
Definition: quest.h:31
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
static quest_state * get_or_create_state(quest_player *pq, sstring name)
Get the state of a quest for a player, creating it if not existing yet.
Definition: quest.cpp:233
static void free_state(quest_player *pq)
Free quests structures.
Definition: quest.cpp:645
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:141
Definition of an in-game quest.
Definition: quest.h:37
FILE * logfile
Used by server/daemon.c.
Definition: init.cpp:114
void command_quest(object *op, const char *params)
Command handler for &#39;quest&#39;.
Definition: quest.cpp:744
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
void quest_start(player *pl, sstring quest_code, int state)
Start a quest for a player.
Definition: quest.cpp:686
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
void quest_send_initial_states(player *pl)
Send the current quest states for the specified player, if the client supports those notifications...
Definition: quest.cpp:929
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:552
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
std::vector< quest_step_definition * > steps
Quest steps.
Definition: quest.h:46
static void update_quests(player *pl)
Look through all of the quests for the given player, and see if any need to be updated.
Definition: quest.cpp:341
const char * i18n(const object *who, const char *code)
Translate a message in the appropriate language.
Definition: languages.cpp:42
quest_state * next
Next quest on the list.
Definition: quest.cpp:54
int level
Definition: readable.cpp:1561
void quest_set_player_state(player *pl, sstring quest_code, int state)
Set the state of a quest for a player.
Definition: quest.cpp:722
const char * playerdir
Where the player files are.
Definition: global.h:251
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
One step of a quest.
Definition: quest.h:29
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.cpp:116
static quest_step_definition * quest_get_step(quest_definition *quest, int step)
Get a step for the specified quest.
Definition: quest.cpp:73
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 16 bit length field.
Definition: lowlevel.cpp:191
uint32_t client_code
The code used to communicate with the client, merely a unique index.
Definition: quest.h:44
void quest_for_each(quest_op op, void *user)
Iterate over all quests.
Definition: assets.cpp:543
#define MSG_TYPE_ADMIN_LOADSAVE
load/save operations
Definition: newclient.h:518
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
Structure used when dumping quests to stdout.
Definition: quest.cpp:867
sstring code
Quest internal code.
Definition: quest.cpp:49
static void quest_write_player_data(const quest_player *pq)
Write quest-data information for a player.
Definition: quest.cpp:178
int sent_to_client
Whether this state was sent to the client or not.
Definition: quest.cpp:53
Global type definitions and header inclusions.
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
static void quest_read_player_data(quest_player *pq)
Read quest-data information for a player.
Definition: quest.cpp:103
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: main.cpp:308
const quest_definition * parent
Parent to dump from.
Definition: quest.cpp:868
static quest_state * get_new_quest_state(void)
Return a new quest_state*, calling fatal() if memory shortage.
Definition: quest.cpp:92
void dump_quests(void)
Dump all of the quests, then calls exit() - useful in terms of debugging to make sure that quests are...
Definition: quest.cpp:900
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:133
#define MSG_TYPE_ADMIN_DM
DM related admin actions.
Definition: newclient.h:516
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
Information about a player.
Definition: quest.cpp:58
#define TAG_START
Definition: quest.cpp:41
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
static quest_state * get_state(quest_player *pq, sstring name)
Get the state of a quest for a player, not creating if not existing yet.
Definition: quest.cpp:215
static void do_update(const quest_definition *quest, void *user)
Definition: quest.cpp:321
int was_completed
Whether the quest was completed once or not, indepandently of the state.
Definition: quest.cpp:51
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.cpp:30
int quest_get_player_state(player *pl, sstring quest_code)
Get the quest state for a player.
Definition: quest.cpp:666
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:551
#define TAG_END
Definition: quest.cpp:42
#define NDI_ALL_DMS
Inform all logged in DMs.
Definition: newclient.h:272
static int evaluate_quest_conditions(const std::vector< quest_condition *> conditions, player *pl)
Checks whether the conditions for a given step are met.
Definition: quest.cpp:302
#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
static quest_state * get_quest_by_number(player *pl, int number)
returns the quest state which corresponds to a certain number for the given player.
Definition: quest.cpp:545
uint32_t has_directory
If 0, the player was not yet saved, its directory doesn&#39;t exist.
Definition: player.h:151
static quest_player * get_or_create_quest(player *pl)
Get quest status for a player, creating it if it doesn&#39;t exist yet.
Definition: quest.cpp:277
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
sstring quest_code
Quest internal code.
Definition: quest.h:38
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
object * ob
The object representing the player.
Definition: player.h:179
#define MSG_TYPE_COMMAND_QUESTS
Quest info.
Definition: newclient.h:548
static void output_quests(const quest_definition *quest, void *user)
Dump one quest on the logfile, then its children.
Definition: quest.cpp:876
std::vector< quest_condition * > conditions
The conditions that must be satisfied to trigger the step.
Definition: quest.h:33
static quest_player * get_quest(player *pl)
Get quest status for a player, not creating it if it doesn&#39;t exist.
Definition: quest.cpp:259
struct Settings settings
Global settings.
Definition: init.cpp:139
quest_state * quests
Quests done or in progress.
Definition: quest.cpp:60
int quest_was_completed(player *pl, sstring quest_code)
Check if a quest was completed once for a player, without taking account the current state...
Definition: quest.cpp:732
Information about a quest for a player.
Definition: quest.cpp:48
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
uint16_t number
This is the image unique identifier.
Definition: face.h:15
sstring quest_title
Quest title for player.
Definition: quest.h:39
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
quest_player * next
Next player on the list.
Definition: quest.cpp:61
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MSG_TYPE_ADMIN
Definition: newclient.h:418
sstring player_name
Player&#39;s name.
Definition: quest.cpp:59
struct quest_definition * parent
Parent for this quest, NULL if it is a &#39;top-level&#39; quest.
Definition: quest.h:47
#define QC_CAN_RESTART
Quest status that indicates a quest was completed and may be restarted.
Definition: quest.cpp:45
const Face * face
Face associated with this quest.
Definition: quest.h:43
void free_quest(void)
Free all quest status structures.
Definition: quest.cpp:911
void command_help(object *op, const char *params)
Player is asking for some help.
Definition: c_misc.cpp:1770
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
int is_completion_step
Whether this step completes the quest (1) or not (0)
Definition: quest.h:32
quest_definition * quest_get_by_code(sstring code)
Find a quest from its code if it exists.
Definition: assets.cpp:534
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.cpp:72
int is_complete
Whether the quest is complete in the current playthrough.
Definition: quest.cpp:52
static void quest_list(player *pl, player *who, int showall, const char *name)
Display current and completed player quests.
Definition: quest.cpp:525
void quest_first_player_save(player *pl)
Ensure the quest state is correctly saved for a player.
Definition: quest.cpp:987
const char * localdir
Read/write data files.
Definition: global.h:250
sstring name
The name of the object, obviously...
Definition: object.h:319
Only for debugging purposes.
Definition: logger.h:13
int of_close(OutputFile *of)
Closes an output file.
Definition: output_file.cpp:61
int quest_restart
If non zero, can be restarted.
Definition: quest.h:42
static void quest_info(player *pl, player *who, quest_state *qs, int level)
Give details about a quest.
Definition: quest.cpp:580
Functions for creating text output files.
static quest_player * player_states
Player quest state.
Definition: quest.cpp:65
static void quest_display(player *pl, quest_player *pq, int showall, const char *name)
Utility function to display a quest list.
Definition: quest.cpp:452
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
C function wrappers to interact with assets.
One player.
Definition: player.h:107
int step
Step identifier.
Definition: quest.h:30
static int quests_count
Count of quests.
Definition: mapper.cpp:945
sstring quest_description
Quest longer description.
Definition: quest.h:40
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
static void quest_set_state(player *dm, player *pl, sstring quest_code, int state, int started)
Set the state of a quest for a player.
Definition: quest.cpp:353
const char * sstring
Definition: sstring.h:2
quest_definition * quest_find_by_code(sstring code)
Find a quest from its code, logging if no matching quest.
Definition: assets.cpp:523
int level
Indentation level.
Definition: quest.cpp:869
player * find_player_partial_name(const char *plname)
Find a player by a partial name.
Definition: player.cpp:114
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
int state
State for the player.
Definition: quest.cpp:50
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447