47 static void build_stringlist(
const char *str,
char ***result_list,
size_t *result_size);
102 while (fl && number > 1) {
103 if (!(fl = fl->
next))
127 if (strcmp(rp->
title,
"NONE")) {
167 char *
buf, *cp, *next;
177 if (*buf ==
'#' || *buf ==
'\0')
183 if (!strncmp(cp,
"Remove ", 7)) {
184 if (strcmp(cp + 7,
"*") == 0) {
192 if (!strncmp(cp,
"Object", 6)) {
195 }
else if (formula == NULL) {
196 LOG(
llevError,
"recipe.c: First key in formulae file %s is not \"Object\".\n", filename);
198 }
else if (!strncmp(cp,
"keycode", 7)) {
200 }
else if (sscanf(cp,
"trans %d", &value)) {
202 }
else if (sscanf(cp,
"yield %d", &value)) {
203 formula->
yield = value;
204 }
else if (sscanf(cp,
"chance %d", &value)) {
206 }
else if (sscanf(cp,
"exp %d", &value)) {
207 formula->
exp = value;
208 }
else if (sscanf(cp,
"diff %d", &value)) {
209 formula->
diff = value;
210 }
else if (!strncmp(cp,
"ingred", 6)) {
213 cp = strchr(cp,
' ')+1;
215 if ((next = strchr(cp,
',')) != NULL) {
223 while (*cp !=
'\0' && cp[strlen(cp) - 1] ==
' ')
224 cp[strlen(cp) - 1] =
'\0';
233 }
while ((cp = next) != NULL);
237 while (numb_ingred != 1) {
245 }
else if (!strncmp(cp,
"arch", 4)) {
247 }
else if (!strncmp(cp,
"skill", 5)) {
249 }
else if (!strncmp(cp,
"cauldron", 8)) {
251 }
else if (!strncmp(cp,
"failure_arch ", 13)) {
253 }
else if (!strncmp(cp,
"failure_message ", 16)) {
255 }
else if (sscanf(cp,
"min_level %d", &value)) {
257 }
else if (!strncmp(cp,
"tool ", 5)) {
259 }
else if (sscanf(cp,
"combination %d", &value)) {
262 LOG(
llevError,
"Unknown input in file %s: %s\n", filename, buf);
267 for (fl = formulalist; fl; fl = fl->
next) {
270 for (formula = fl->
items; formula; formula = formula->
next) {
295 int numb = 1, tool_match;
296 size_t tool_i,tool_j;
301 for (fl = formulalist; fl != NULL; fl = fl->
next) {
302 for (formula = fl->
items; formula != NULL; formula = formula->
next) {
303 for (check = formula->
next; check != NULL; check = check->
next)
310 for (tool_i = 0; tool_i < formula->
tool_size; ++tool_i)
312 for (tool_j = 0; tool_j < check->
tool_size; ++tool_j)
313 if (strcmp(formula->
tool[tool_i], check->
tool[tool_j]) == 0) {
324 LOG(
llevError,
"Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n",
329 for (
size_t idx = 0; idx < formula->
arch_names; idx++) {
331 LOG(
llevError,
"Formulae %s of %s (%d ingredients) references non existent archetype %s\n",
358 fprintf(stdout,
"name,index,num_ingreds,chance,skill,difficulty,exp,cauldron,yield,ingredients,ingred_price,result_price\n");
360 for (formula = fl->
items; formula != NULL; formula = formula->
next) {
367 const char *
string = formula->
arch_name[i];
371 if (!art && strcmp(formula->
title,
"NONE"))
374 if (strcmp(formula->
title,
"NONE"))
375 snprintf(buf,
sizeof(buf),
"%s of %s",
string, formula->
title);
377 strlcpy(buf,
string,
sizeof(buf));
378 fprintf(stdout,
"%s,%d,%d,%d,%s,", buf, formula->
index, num_ingred, formula->
chance, formula->
skill);
379 fprintf(stdout,
"%d,%d,", formula->
diff, formula->
exp);
380 fprintf(stdout,
"%s,%d,", formula->
cauldron, formula->
yield);
382 if (formula->
ingred != NULL) {
383 int nval = 0, tval = 0;
384 fprintf(stdout,
"\"");
385 for (next = formula->
ingred; next != NULL; next = next->
next) {
387 fprintf(stdout,
",");
392 fprintf(stdout,
"\",");
393 if (tval != formula->
index)
394 fprintf(stdout,
"WARNING:ingredient list and formula values not equal.\n");
396 fprintf(stdout,
"%d,", ingred_cost);
398 if (art != NULL && art->
item != NULL)
400 fprintf(stdout,
"%d\n", result_price);
403 LOG(
llevError,
"Can't find archetype:%s for formula %s\n",
string, formula->
title);
433 if (t->
name != NULL) {
484 while (isdigit(*name)) {
485 mult = 10*mult+(*name-
'0');
503 snprintf(part1, sizeof(part1),
"%s %s", at->clone.name, at->clone.title);
504 if (!strcasecmp(part1, name)) {
505 value = price_base(&at->clone);
511 value = price_base(&at->clone);
521 cp = strstr(name,
" of ");
524 part1[cp-name] =
'\0';
533 for (auto al = first_artifactlist; al != NULL; al = al->next) {
534 if (al->type == at->clone.type) {
535 for (const auto art : al->items) {
536 if (!strcasecmp(art->item->name, part2)) {
537 value = price_base(&at->clone) * art->item->value;
552 cp = strstr(name,
"'s ");
555 part1[cp-name] =
'\0';
563 if (at->clone.randomitems != NULL) {
564 auto at2 = find_treasure_by_name(at->clone.randomitems->items, part2, 0);
566 value = price_base(&at2->clone);
579 LOG(
llevError,
"Couldn't find cost for ingredient %s\n", name);
602 fprintf(
logfile,
"\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n", num_ingred, num_ingred > 1 ?
"s." :
".", fl->
number, fl->
total_chance);
603 for (formula = fl->
items; formula != NULL; formula = formula->
next) {
610 const char *
string = formula->
arch_name[i];
614 if (!art && strcmp(formula->
title,
"NONE"))
617 if (!strcmp(formula->
title,
"NONE"))
618 strlcpy(buf,
string,
sizeof(buf));
620 snprintf(buf,
sizeof(buf),
"%s of %s",
string, formula->
title);
621 fprintf(
logfile,
"\n%-40s bookchance %3d skill %s\n", buf, formula->
chance, formula->
skill);
622 if (formula->
ingred != NULL) {
624 for (next = formula->
ingred; next != NULL; next = next->
next) {
628 fprintf(
logfile,
"\t%-33s%5ld\n", next->
name, cost);
629 if (cost < 0 || tcost < 0)
634 if (art != NULL && art->
item != NULL)
638 fprintf(
logfile,
"\t\tBuying result costs: %5ld", cost);
639 if (formula->
yield > 1) {
640 fprintf(
logfile,
" to %ld (max %d items)\n", cost*formula->
yield, formula->
yield);
641 cost = cost*(formula->
yield+1L)/2L;
644 fprintf(
logfile,
"\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
646 fprintf(
logfile,
"Could not find some ingredients. Check the formula!\n");
647 else if (tcost > cost)
648 fprintf(
logfile,
"Ingredients are much too expensive. Useless formula.\n");
649 else if (tcost*2L > cost)
650 fprintf(
logfile,
"Ingredients are too expensive.\n");
651 else if (tcost*10L < cost)
652 fprintf(
logfile,
"Ingredients are too cheap.\n");
658 LOG(
llevError,
"Can't find archetype:%s for formula %s\n",
string, formula->
title);
666 fprintf(
logfile,
"WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
678 const char *cp = name;
681 cp = strchr(cp,
' ')+1;
696 if ((numb = atoi(buf)))
714 int val = 0, len = strlen(cp), mult =
numb_ingred(buf);
741 for (
auto art : at->
items)
756 int number = 0, roll = 0;
775 LOG(
llevError,
"get_random_recipelist(): no recipelists found!\n");
802 for (rp = fl->
items; rp; rp = rp->
next) {
816 recipe *formula = NULL, *next;
820 for (fl = formulalist; fl != NULL; fl = flnext) {
823 for (formula = fl->
items; formula != NULL; formula = next) {
824 next = formula->
next;
838 for (lchar = formula->
ingred; lchar; lchar = charnext) {
839 charnext = lchar->
next;
844 free(formula->
tool[0]);
875 for (p = strtok(dup,
","); p != NULL; p = strtok(NULL,
","))
879 *result_list =
static_cast<char **
>(malloc(
sizeof(**result_list) * size));
880 if (*result_list == NULL)
884 for (i = 0; i < size; i++) {
885 (*result_list)[i] = dup;
886 dup = dup+strlen(dup)+1;
905 if (strcmp(test->
tool[t], tool) == 0) {
936 if (strcmp(rp->
title,
"NONE") == 0) {
973 return "complicated";
977 return "challenging";
979 return "frustrating";
int diff
Alchemical dfficulty level.
FILE * logfile
Used by server/daemon.c.
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Find a recipe for a specified tool.
recipelist * next
Pointer to next recipe list.
recipe * get_random_recipe(recipelist *rpl)
Gets a random recipe from a list, based on chance.
int total_chance
Total chance of the recipes in this list.
static const char * ingred_name(const char *name)
Extracts the name from an ingredient.
New face structure - this enforces the notion that data is face by face only - you can not change the...
void dump_alchemy_costs(void)
Dumps to output all costs of recipes.
sstring name
If non null, name of list to use instead.
sstring add_string(const char *str)
Share a string.
int32_t value
How much money it is worth (or contains)
int is_combination
Whather this is an alchemy recipe, or an item transformation description.
size_t bufferreader_current_line(BufferReader *br)
Return the index of the last line returned by bufferreader_next_line().
sstring title
Distinguishing name of product.
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
linked_char * ingred
List of ingredients.
void dump_alchemy(void)
Dumps alchemy recipes to output.
recipe * items
Pointer to first recipe in this list.
artifactlist * find_artifactlist(int type)
Finds the artifact list for a certain item type.
int index
Index value derived from formula ingredients.
const char * recipe_get_difficulty_string(int difficulty)
A method to produce a difficulty adjective to describe alchemy projects.
static recipe * get_empty_formula(void)
Allocates a new recipe.
Global type definitions and header inclusions.
sstring skill
Skill name used to make this recipe.
int transmute
If defined, one of the formula ingredients is used as the basis for the product object.
archetype * try_find_archetype(const char *name)
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
AssetsManager * getManager()
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
bool check_formulae(void)
Check if formula don't have the same index.
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
sstring failure_message
Specific failure message.
int legal_artifact_combination(const object *op, const artifact *art)
Checks if op can be combined with art.
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
static long recipe_find_ingredient_cost(const char *name)
Try to find an ingredient with specified name.
std::vector< artifact * > items
Artifacts for this type.
bool check_recipes()
Ensure that all recipes have a valid artifact, and that archetypes are correct.
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
static recipelist * init_recipelist(void)
Allocates a new recipelist.
int exp
How much exp to give for this formulae.
size_t arch_names
Size of the arch_name[] array.
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given 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...
size_t tool_size
Length of tool.
void give_artifact_abilities(object *op, const object *artifact)
Fixes the given object, giving it the abilities and titles it should have due to the second artifact-...
void object_give_identified_properties(object *op)
Ensure op has all its "identified" properties set.
int strcasecmp(const char *s1, const char *s2)
sstring keycode
Optional keycode needed to use the recipe.
struct linked_char * next
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
static int check_recipe(const recipe *rp)
Makes sure we actually have the requested artifact and archetype.
List of recipes with a certain number of ingredients.
char ** tool
Tool(s) for item transformation.
Archetypes * archetypes()
Get archetypes.
int yield
Maximum number of items produced by the recipe.
const Face * face
Face with colors.
This represents all archetypes for one particular object type.
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Finds an artifact for a recipe.
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
treasure * next_no
If this item was not generated, then continue here.
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
#define MAX_BUF
Used for all kinds of things.
int strtoint(const char *buf)
Convert buf into an integer equal to the coadded sum of the (lowercase) character.
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status, and other heuristics.
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
treasurelist represents one logical group of items to be generated together.
treasure * next_yes
If this item was generated, use this link instead of ->next.
Object structure, the core of Crossfire.
treasure * next
Next treasure-item in a linked list.
int chance
Chance that recipe for this item will appear in an alchemical grimore.
sstring name
The name of the object, obviously...
sstring title
Of foo, etc.
Only for debugging purposes.
sstring failure_arch
Arch of the item to generate on failure, instead of blowing up stuff.
int min_level
Minimum level to have in the skill to be able to use the formulae.
treasure * items
Items in this list, linked.
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
archetype * find_treasure_by_name(const treasure *t, const char *name, int depth)
Find a treasure with a matching name.
treasure is one element in a linked list, which together consist of a complete treasure-list.
recipe * next
Next recipe with the same number of ingredients.
char ** arch_name
Possible archetypes of the final product made.
static void build_stringlist(const char *str, char ***result_list, size_t *result_size)
Split a comma separated string list into words.
const Face * recipe_get_face(const recipe *rp)
Return the best face associated with a recipe.
C function wrappers to interact with assets.
static recipelist * get_random_recipelist(void)
Gets a random recipe list.
char * bufferreader_next_line(BufferReader *br)
Return the next line in the buffer, as separated by a newline.
struct archetype * item
Which item this link can be.
void init_formulae(BufferReader *reader, const char *filename)
Builds up the lists of formula from the file in the libdir.
void free_all_recipes(void)
Frees all memory allocated to recipes and recipes lists.
int ingred_count
Number of items in ingred.
#define tolower(C)
Simple macro to convert a letter to lowercase.
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
This is one artifact, ie one special item.
int number
Number of recipes in this list.
object clone
An object from which to do object_copy()
static int numb_ingred(const char *buf)
Extracts the number part of an ingredient.
object * item
Special values of the artifact.
void each(std::function< void(T *)> op)
Apply a function to each asset.
static recipelist * formulalist
Pointer to first recipelist.