Go to the documentation of this file.
41 #define TAG_START "[color=#aa55ff]"
42 #define TAG_END "[/color]"
45 #define QC_CAN_RESTART -1
74 for (
const auto qs :
quest->steps) {
102 int warned = 0,
state;
107 file = fopen(
final,
"r");
113 while (fgets(read,
sizeof(read),
file) != NULL) {
114 if (sscanf(read,
"quest %s\n",
data)) {
123 LOG(
llevError,
"quest: invalid file format for %s\n",
final);
128 if (sscanf(read,
"state %d\n", &
state)) {
135 else if (
step->is_completion_step)
140 if (strcmp(read,
"end_quest\n") == 0) {
155 if (sscanf(read,
"completed %d\n", &
state)) {
160 LOG(
llevError,
"quest: invalid line in %s: %s\n",
final, read);
164 LOG(
llevError,
"quest: missing end_quest in %s\n",
final);
190 fprintf(
file,
"quest %s\n",
state->code);
191 fprintf(
file,
"state %d\n",
state->state);
192 fprintf(
file,
"completed %d\n",
state->was_completed);
193 fprintf(
file,
"end_quest\n");
300 if (conditions.empty())
302 for (
const auto cond : conditions) {
304 if (cond->minstep < 0 && cond->maxstep < 0) {
309 if (current_step < cond->minstep || current_step > cond->maxstep)
321 new_step=new_step<
step->step?
step->step:new_step;
326 if (new_step > current_step) {
358 LOG(
llevError,
"quest: asking for set_state of unknown quest %s!\n", quest_code);
363 if (!dm &&
state <= 0) {
364 LOG(
llevDebug,
"quest_set_player_state: warning: called with invalid state %d for quest %s, player %s\n",
state,
pl->ob->name, quest_code);
368 if (started && qs->
state == 0) {
370 LOG(
llevDebug,
"quest_set_player_state: warning: called for player %s not having started quest %s\n",
pl->ob->name, quest_code);
385 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 if (
step->is_completion_step) {
395 if (
quest->quest_restart)
405 if (
pl->socket->notifications > 0) {
425 assert(
step != NULL);
427 strlen(
step->step_description));
432 if (
pl->has_directory)
450 int completed_count = 0, restart_count = 0, total_count = 0, current_count = 0;
455 if (
quest->parent == NULL) {
461 }
else if(
state->is_complete) {
467 if (completed_count > 0) {
469 if (restart_count > 0)
471 "%s completed %d out of %zu quests, of which %d may be restarted.",
name, completed_count,
quests_count(
false), restart_count);
474 "%s completed %d quests",
name, completed_count);
475 current_count = completed_count;
478 "%s completed the following quests:",
name);
482 if (
quest->parent == NULL) {
487 "(%3d) %s%s", ++current_count,
quest->quest_title, restart);
494 if (total_count > completed_count) {
496 "%s started the following quests:",
name);
500 if (
quest->parent == NULL) {
504 "(%3d) %s", ++current_count,
quest->quest_title);
544 if (number <= 0 || !pq) {
552 if (++questnum == number)
return state;
560 if (++questnum == number)
return state;
594 std::for_each(
quest->steps.cbegin(),
quest->steps.cend(), [&
pl] (
const auto &
step) {
595 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 const char *restart =
"";
603 if (
quest->quest_restart)
604 restart =
i18n(
pl->ob,
" (can be replayed)");
620 prefix =
"Current Status";
687 LOG(
llevError,
"quest_start: requested unknown quest %s\n", quest_code);
695 LOG(
llevDebug,
"quest_start: negative state %d for %s quest %s\n",
state,
pl->ob->name, quest_code);
700 LOG(
llevDebug,
"quest_start: warning: player %s has already started quest %s\n",
pl->ob->name, quest_code);
744 LOG(
llevError,
"command_quest called for a non player!\n");
754 char* dup = strdup(
params);
755 char*
space = strchr(dup,
' ');
779 if (strcmp(
params,
"list all") == 0) {
784 if (strcmp(
params,
"list") == 0) {
789 if (strncmp(
params,
"info ", 5) == 0) {
790 int number = atoi(
params+5);
799 if (strncmp(
params,
"info_c ", 7) == 0) {
800 int number = atoi(
params+7);
805 if (
q &&
q->client_code == (uint32_t)number) {
819 char *dup = strdup(
params + 4);
820 char *
space = strrchr(dup,
' ');
858 if (
d->parent !=
quest->parent)
863 for (
int i = 0; i <
d->level; i++) {
868 fprintf(
logfile,
"%s%s - %s - %zu steps (%srestartable)\n",
prefix,
quest->quest_code,
quest->quest_title,
quest->steps.size(),
quest->quest_restart ?
"" :
"not ");
872 r.level =
d->level + 1;
917 if (
pl->socket->notifications < 1)
927 if (
state->state == -1)
932 size = 2 + (2 + strlen(
quest->quest_title)) + 4 + 1 + (2 + (
step != NULL ? strlen(
step->step_description) : 0));
953 state->sent_to_client = 1;
969 if (qp != NULL && qp->
quests != NULL) {
void SockList_AddInt(SockList *sl, uint32_t data)
static void output_quests(const quest_definition *quest, void *user)
#define MSG_TYPE_COMMAND_SUCCESS
void quest_for_each(quest_op op, void *user)
void LOG(LogLevel logLevel, const char *format,...)
int of_close(OutputFile *of)
FILE * of_open(OutputFile *of, const char *fname)
static quest_player * get_or_create_quest(player *pl)
#define QUERY_FLAG(xyz, p)
static void quest_write_player_data(const quest_player *pq)
static quest_state * get_new_quest_state(void)
void quest_first_player_save(player *pl)
void SockList_AddString(SockList *sl, const char *data)
static void quest_set_state(player *dm, player *pl, sstring quest_code, int state, int started)
static void quest_info(player *pl, player *who, quest_state *qs, int level)
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
#define MSG_TYPE_COMMAND_QUESTS
static quest_player * get_quest(player *pl)
const quest_definition * parent
static quest_state * get_quest_by_number(player *pl, int number)
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
void SockList_Reset(SockList *sl)
static void free_state(quest_player *pq)
Plugin animator file specs[Config] name
size_t SockList_Avail(const SockList *sl)
#define MSG_TYPE_ADMIN_DM
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For most everything that is sent is text This is more or less how things worked under except it packed the ints into bytes in a known order In some we handle ints as in they are sent as binary information How any command handles it is detailed below in the command description The S and C represent the direction of the we use MSB as well as any ints or shorts that get sent inside the packets All packets are defined to have at least one word of followed by a space
sstring add_refcount(sstring str)
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
a copper bar weighs and has a value of
static void do_update(const quest_definition *quest, void *user)
sstring add_string(const char *str)
void SockList_AddShort(SockList *sl, uint16_t data)
void SockList_AddChar(SockList *sl, unsigned char c)
static quest_step_definition * quest_get_step(quest_definition *quest, int step)
struct quest_definition * parent
static void update_quests(player *pl)
static void quest_list(player *pl, player *who, int showall, const char *name)
void command_help(object *op, const char *params)
quest_definition * quest_get_by_code(sstring code)
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for but you habe then to change the pathes in the VC settings Go in Settings C and Settings Link and change the optional include and libs path to the new python installation path o step
void SockList_Init(SockList *sl)
static void quest_display(player *pl, quest_player *pq, int showall, const char *name)
static quest_state * get_or_create_state(quest_player *pq, sstring name)
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for d
void quest_set_player_state(player *pl, sstring quest_code, int state)
#define MSG_TYPE_ADMIN_LOADSAVE
void free_string(sstring str)
void quest_send_initial_states(player *pl)
void SockList_Term(SockList *sl)
int quest_get_player_state(player *pl, sstring quest_code)
#define MSG_TYPE_COMMAND_FAILURE
quest_definition * quest_find_by_code(sstring code)
void fatal(enum fatal_error err)
void quest_start(player *pl, sstring quest_code, int state)
static void quest_read_player_data(quest_player *pq)
const typedef char * sstring
static quest_state * get_state(quest_player *pq, sstring name)
int quest_was_completed(player *pl, sstring quest_code)
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
player * find_player_partial_name(const char *plname)
void command_quest(object *op, const char *params)
SockList * player_get_delayed_buffer(player *pl)
void Send_With_Handling(socket_struct *ns, SockList *sl)
static quest_player * player_states
static int evaluate_quest_conditions(const std::vector< quest_condition * > conditions, player *pl)
const char * i18n(const object *who, const char *code)