Go to the documentation of this file.
76 #define MAX_TITLE_CHECK 20
81 #define MSGTYPE_MONSTER 1
83 #define MSGTYPE_ARTIFACT 2
85 #define MSGTYPE_SPELLPATH 3
87 #define MSGTYPE_ALCHEMY 4
89 #define MSGTYPE_GODS 5
91 #define MSGTYPE_MSGFILE 6
98 #define arraysize(arrayname) (sizeof(arrayname)/sizeof(*(arrayname)))
218 {
"Missile Weapon",
BOW },
219 {
"Missile",
ARROW },
220 {
"Hand Weapon",
WEAPON },
221 {
"Artifact",
SKILL },
353 "magical manufacture",
355 "philosophical items",
607 LOG(
llevInfo,
"Warning: invalid book index %d, using 0 instead\n", i);
611 for (tl =
booklist, number = i; tl && number; tl = tl->
next, number--) {
633 int nstrtok(
const char *buf1,
const char *buf2) {
641 for (tbuf = strtok(
buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
653 while ((*
buf) ==
' ') {
675 char *
strtoktolin(
const char *buf1,
const char *buf2,
char *retbuf,
size_t size) {
676 int maxi, i =
nstrtok(buf1, buf2);
681 snprintf(retbuf, size,
" ");
682 for (tbuf = strtok(
buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
683 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
"%s",
trim(tbuf));
685 if (i == 1 && maxi > 1)
686 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
" and ");
687 else if (i > 0 && maxi > 1)
688 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
", ");
691 int end = strlen(retbuf);
692 if (retbuf[end-1] ==
'\n')
694 snprintf(retbuf+end, size-end,
".");
731 #ifdef BOOK_MSG_DEBUG
735 static int did_init_barch = 0;
745 LOG(
llevDebug,
" Reading bookarch from %s...\n", fname);
747 fp = fopen(fname,
"r");
759 for (lineno = 1; fgets(
buf,
MAX_BUF, fp) != NULL; lineno++) {
765 cp = strchr(
buf,
'\n');
767 while (cp >
buf && (cp[-1] ==
' ' || cp[-1] ==
'\t'))
772 if (strncmp(
buf,
"title ", 6) == 0) {
775 while (*cp ==
' ' || *cp ==
'\t')
778 LOG(
llevInfo,
"Warning: missing book title at %s, line %d\n", fname, lineno);
784 #ifdef BOOK_MSG_DEBUG
788 }
else if (book == NULL) {
791 LOG(
llevInfo,
"Warning: expecting 'title' at %s, line %d\n", fname, lineno);
793 }
else if (strncmp(
buf,
"authour ", 8) == 0) {
795 while (*cp ==
' ' || *cp ==
'\t')
798 LOG(
llevInfo,
"Warning: missing book authour at %s, line %d\n", fname, lineno);
802 }
else if (strncmp(
buf,
"arch ", 5) == 0) {
804 while (*cp ==
' ' || *cp ==
'\t')
807 LOG(
llevInfo,
"Warning: missing book arch at %s, line %d\n", fname, lineno);
811 }
else if (sscanf(
buf,
"level %d%n", &
value, &len) == 1 && len == (
int)strlen(
buf)) {
813 }
else if (sscanf(
buf,
"type %d%n", &
value, &len) == 1 && len == (
int)strlen(
buf)) {
815 }
else if (sscanf(
buf,
"size %d%n", &
value, &len) == 1 && len == (
int)strlen(
buf)) {
817 }
else if (sscanf(
buf,
"index %d%n", &
value, &len) == 1 && len == (
int)strlen(
buf)) {
819 }
else if (strcmp(
buf,
"end") == 0) {
824 LOG(
llevInfo,
"Warning: syntax error at %s, line %d\n", fname, lineno);
828 LOG(
llevInfo,
"Warning: missing 'end' at %s, line %d\n", fname, lineno);
838 #ifdef BOOK_MSG_DEBUG
839 LOG(
llevDebug,
"\n init_book_archive() got %d titles.\n", nroftitle);
855 LOG(
llevInfo,
"Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
878 static int did_init_mon_info = 0;
880 if (did_init_mon_info)
882 did_init_mon_info = 1;
896 static int did_this = 0;
933 return (
title *)NULL;
937 return (
title *)NULL;
939 length = strlen(book->
msg);
942 if (
t->size == length &&
t->msg_index ==
index) {
944 LOG(
llevDebug,
"Found title match (list %d): %s %s (%d)\n", msgtype,
t->name,
t->authour,
t->msg_index);
949 return (
title *)NULL;
994 if (book->
weight > 2000) {
1018 if (msgtype < 0 || strlen(
op->msg) < 5)
1091 LOG(
llevError,
"add_book_to_list can't get booklist!\n");
1098 t->size = strlen(book->
msg);
1110 #ifdef ARCHIVE_DEBUG
1134 LOG(
llevError,
"change_book_name() called w/ illegal obj type.\n");
1167 const char *old_title;
1168 const char *old_name;
1178 LOG(
llevError,
"change_book_name(): can't find title list\n");
1183 if (numb == maxnames) {
1184 #ifdef ARCHIVE_DEBUG
1185 LOG(
llevDebug,
"titles for list %d full (%d possible).\n", msgtype, maxnames);
1192 else if (!book->
title)
1210 #ifdef ARCHIVE_DEBUG
1211 LOG(
llevDebug,
"Failed to obtain unique title for %s %s (names:%d/%d)\n", book->
name, book->
title, numb, maxnames);
1228 }
else if (book->
title && strlen(book->
msg) > 5) {
1232 if (old_title != NULL)
1264 return (
object *)NULL;
1270 std::vector<object *> select;
1271 std::copy_if(
monsters.cbegin(),
monsters.cend(), std::back_inserter(select), [&] (
auto ob) { return ob->level >= level; });
1273 if (select.empty()) {
1274 LOG(
llevError,
"get_random_mon() couldn't return monster for level %d\n",
level);
1277 return select[
RANDOM() % select.size()];
1335 const char *sep =
":";
1427 else if (chance >= 10)
1429 else if (chance >= 5)
1478 if (book_entries > 5)
1492 }
while (al == NULL && i < 10);
1501 auto iart = al->
items.cbegin();
1503 if (iart == al->
items.cend())
1504 iart = al->
items.cbegin();
1515 while (book_entries > 0) {
1517 if (iart == al->
items.cend())
1518 iart = al->
items.cbegin();
1632 int chance,
count = 0;
1633 const char *op_name;
1654 for (formula = fl->
items; formula != NULL; formula = formula->
next) {
1655 chance -= formula->
chance;
1656 if (chance <= 0 && formula->chance != 0 && !formula->
is_combination)
1674 LOG(
llevError,
"formula_msg() can't find arch %s for formula.\n", op_name);
1689 if (strcmp(formula->
title,
"NONE")) {
1715 if (formula->
ingred != NULL) {
1724 snprintf(
name,
sizeof(
name),
"an unknown place");
1733 LOG(
llevError,
"formula_msg() no ingredient list for object %s of %s\n", op_name, formula->
title);
1743 snprintf(km,
sizeof(km),
"alchemy:%d:%d:%s",
count, formula->
index, formula->
title);
1764 if (
msg->identifier != NULL) {
1768 snprintf(km,
sizeof(km),
"message:%s",
msg->identifier);
1771 if (
msg->quest_code) {
1781 #ifdef BOOK_MSG_DEBUG
1815 LOG(
llevError,
"common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (
unsigned long)
booksize,
BOOK_BUF);
1849 snprintf(
buf,
sizeof(
buf),
"god:%s:%d", god->
name, what);
1878 size_t book_buf_size;
1890 book_buf_size -= strlen(
"\n");
1908 msg_type = msg_type > 0 ? msg_type : (
int)(
RANDOM()%6);
1960 title *title1, *titlenext;
1964 for (tlist =
booklist; tlist != NULL; tlist = tnext) {
1965 tnext = tlist->
next;
1966 for (title1 = tlist->
first_book; title1; title1 = titlenext) {
1967 titlenext = title1->
next;
2002 LOG(
llevDebug,
"Updating book archive: %s...\n", fname);
2011 fprintf(fp,
"title %s\n", book->
name);
2012 fprintf(fp,
"authour %s\n", book->
authour);
2013 fprintf(fp,
"arch %s\n", book->
archname);
2014 fprintf(fp,
"level %d\n", book->
level);
2015 fprintf(fp,
"type %d\n",
index);
2017 fprintf(fp,
"size %lu\n", (
unsigned long)book->
size);
2018 fprintf(fp,
"index %d\n", book->
msg_index);
2019 fprintf(fp,
"end\n");
2026 LOG(
llevError,
"Could not set permissions on '%s'\n", fname);
2040 uint8_t subtype = readable->
subtype;
void write_book_archive(void)
#define MSG_TYPE_MONUMENT_WALL_2
static const char *const formula_book_name[]
#define MSG_TYPE_BOOK_SPELL_PRAYER
static void change_book(object *book, int msgtype)
static const char *const path_book_name[]
size_t stringbuffer_length(StringBuffer *sb)
recipelist * get_formulalist(int i)
static titlelist * get_empty_booklist(void)
static void do_spellpath_msg(archetype *at)
static const char *const mon_author[]
static void init_mon_info(void)
static title * get_empty_book(void)
#define MSG_TYPE_PAPER_LETTER_OLD_2
void LOG(LogLevel logLevel, const char *format,...)
#define arraysize(arrayname)
#define MSG_TYPE_BOOK_SPELL_SUMMONER
static const char *const book_author[]
int of_close(OutputFile *of)
#define MONSTER_EXCLUDE_FROM_READABLE_KEY
void free_all_readable(void)
static std::vector< object * > monsters
FILE * of_open(OutputFile *of, const char *fname)
#define QUERY_FLAG(xyz, p)
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
void archetypes_for_each(arch_op op)
const char *const spellpathnames[NRSPELLPATHS]
static const char *const mon_book_name[]
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
static const char *const path_author[]
GeneralMessage * random()
static StringBuffer * artifact_msg(unsigned int level, size_t booksize)
#define MSG_TYPE_PAPER_LETTER_NEW_2
StringBuffer * stringbuffer_new(void)
#define MSG_TYPE_BOOK_QUARTO_1
#define MSG_TYPE_SIGN_BASIC
std::vector< artifact * > items
static const char *const gods_book_name[]
#define MSG_TYPE_PAPER_SCROLL_NEW_2
#define MSG_TYPE_PAPER_SCROLL_OLD_2
#define MSG_TYPE_PAPER_NOTE_2
#define MSG_TYPE_CARD_MONEY_2
#define MSG_TYPE_MONUMENT_STATUE_3
static StringBuffer * god_info_msg(int level, size_t booksize, object *book)
void add_abilities(object *op, const object *change)
#define MSG_TYPE_PAPER_LETTER_OLD_1
char * strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size)
#define MSG_TYPE_SIGN_DIR_RIGHT
static const char *const gods_author[]
#define MSG_TYPE_CARD_SIMPLE_2
void object_copy(const object *src_ob, object *dest_ob)
std::vector< sstring > allowed
#define MSG_TYPE_BOOK_CLASP_2
#define MSG_TYPE_BOOK_ELEGANT_1
const char * object_get_value(const object *op, const char *const key)
AssetsManager * getManager()
object * object_insert_in_ob(object *op, object *where)
static const readable_message_type readable_message_types[]
Plugin animator file specs[Config] name
static title * find_title(const object *book, int msgtype)
static object * get_next_mon(const object *tmp)
#define MSG_TYPE_PAPER_SCROLL_OLD_1
static int need_to_write_bookarchive
#define MSG_TYPE_CARD_STRANGE_1
char * stringbuffer_finish(StringBuffer *sb)
void object_free_drop_inventory(object *ob)
static void add_author(object *op, int msgtype)
const object * get_rand_god(void)
#define MSG_TYPE_MONUMENT_GRAVESTONE_1
#define MSG_TYPE_MONUMENT
#define MSG_TYPE_CARD_STRANGE_2
void query_name(const object *op, char *buf, size_t size)
#define MSG_TYPE_SIGN_DIR_BOTH
#define MSG_TYPE_MONUMENT_GRAVESTONE_2
static titlelist * get_titlelist(int i)
sstring stringbuffer_finish_shared(StringBuffer *sb)
#define MSG_TYPE_SIGN_DIR_LEFT
a copper bar weighs and has a value of
sstring add_string(const char *str)
#define MSG_TYPE_BOOK_CLASP_1
static const char *const book_descrpt[]
static void init_book_archive(void)
void tailor_readable_ob(object *book, int msg_type)
static StringBuffer * spellpath_msg(int level, size_t booksize, StringBuffer *buf)
#define FREE_AND_COPY(sv, nv)
#define MSG_TYPE_MONUMENT_STATUE_2
static void add_book_to_list(const object *book, int msgtype)
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
#define MSG_TYPE_CARD_ELEGANT_1
object * object_create_arch(archetype *at)
#define FLAG_UNAGGRESSIVE
#define MSG_TYPE_CARD_ELEGANT_3
static StringBuffer * artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator)
#define MSG_TYPE_CARD_MONEY_3
#define MSG_TYPE_BOOK_SPELL_EVOKER
#define MSG_TYPE_MONUMENT_GRAVESTONE_3
sstring get_message_body(const GeneralMessage *message)
void stringbuffer_append_string(StringBuffer *sb, const char *str)
#define MSG_TYPE_MONUMENT_STONE_3
#define MSG_TYPE_MONUMENT_WALL_3
const char * trim(const char *buf)
#define MSG_TYPE_PAPER_ENVELOPE_2
#define MSG_TYPE_CARD_ELEGANT_2
#define MSG_TYPE_PAPER_NOTE_1
#define MSG_TYPE_BOOK_SPELL_SORCERER
#define MSG_TYPE_BOOK_SPELL_PYRO
#define MSG_TYPE_SIGN_MAGIC_MOUTH
static StringBuffer * mon_desc(const object *mon)
size_t strlcpy(char *dst, const char *src, size_t size)
object * object_new(void)
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
object * create_archetype(const char *name)
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
void free_string(sstring str)
static const char *const art_book_name[]
#define MSG_TYPE_CARD_MONEY_1
void fatal(enum fatal_error err)
archetype * find_archetype_by_object_name(const char *name)
#define MSG_TYPE_PAPER_ENVELOPE_1
sstring get_message_title(const GeneralMessage *message)
#define MSG_TYPE_CARD_SIMPLE_3
static const uint32_t spellpathdef[NRSPELLPATHS]
void stringbuffer_delete(StringBuffer *sb)
static StringBuffer * msgfile_msg(object *book, size_t booksize)
const typedef char * sstring
#define MSG_TYPE_PAPER_LETTER_NEW_1
archetype * find_archetype(const char *name)
#define MSG_TYPE_BOOK_ELEGANT_2
int strtoint(const char *buf)
void object_set_msg(object *op, const char *msg)
static void do_monster(archetype *at)
static const arttypename art_name_array[]
#define MSG_TYPE_MONUMENT_STONE_2
void stringbuffer_append_stringbuffer(StringBuffer *sb, const StringBuffer *sb2)
static void new_text_name(object *book, int msgtype)
static const char *const heavy_book_name[]
#define MSGTYPE_SPELLPATH
static const char *const formula_author[]
static titlelist * booklist
#define MSG_TYPE_MONUMENT_STATUE_1
#define MSG_TYPE_MONUMENT_WALL_1
const readable_message_type * get_readable_message_type(object *readable)
static const char *const art_author[]
static const int last_readable_subtype
object * get_random_mon(int level)
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
#define MSG_TYPE_PAPER_NOTE_3
#define MSG_TYPE_BOOK_QUARTO_2
archetype * try_find_archetype(const char *name)
event
DIALOGCHECK MINARGS 1 MAXARGS 2
static StringBuffer * mon_info_msg(int level, size_t booksize, object *book)
static int unique_book(const object *book, int msgtype)
#define MSG_TYPE_CARD_SIMPLE_1
static const char *const light_book_name[]
#define MSG_TYPE_MONUMENT_STONE_1
int object_set_value(object *op, const char *key, const char *value, int add_key)
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
static void add_book(title *book, int type, const char *fname, int lineno)
#define MSG_TYPE_PAPER_SCROLL_MAGIC
static void make_formula_book(object *book, int level)
#define MSG_TYPE_PAPER_SCROLL_NEW_1
static struct @0 sp_params
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 text
static const int max_titles[6]
int nstrtok(const char *buf1, const char *buf2)
artifactlist * find_artifactlist(int type)
#define MSG_TYPE_CARD_STRANGE_3
const Face * get_message_face(const GeneralMessage *message)