Crossfire Server, Trunk
alchemy.cpp File Reference
#include "global.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "object.h"
#include "shop.h"
#include "skills.h"
#include "spells.h"
#include "sproto.h"
+ Include dependency graph for alchemy.cpp:

Go to the source code of this file.

Functions

static void adjust_product (object *item, int lvl, int yield)
 
static void alchemy_failure_effect (object *op, object *cauldron, const recipe *rp, int danger)
 
static void attempt_do_alchemy (object *caster, object *cauldron)
 
static objectattempt_recipe (object *caster, object *cauldron, int ability, const recipe *rp, int nbatches, int ignore_cauldron)
 
static int calc_alch_danger (object *caster, object *cauldron, const recipe *rp)
 
static const char * cauldron_sound (void)
 
static float chance_fn (int diff)
 
static int content_recipe_value (object *op)
 
static const recipefind_recipe (const recipelist *fl, int formula, object *cauldron)
 
static objectfind_transmution_ob (object *first_ingred, const recipe *rp, size_t *rp_arch_index, int create_item)
 
static int is_defined_recipe (const recipe *rp, const object *cauldron)
 
static objectmake_item_from_recipe (object *cauldron, const recipe *rp)
 
static int numb_ob_inside (const object *op)
 
static float recipe_chance (const recipe *rp, const object *skill, const object *cauldron)
 
static void remove_contents (object *first_ob, object *save_item)
 
int use_alchemy (object *op)
 

Variables

static const char *const cauldron_effect []
 

Detailed Description

This contains all alchemy-related functions.

Definition in file alchemy.cpp.

Function Documentation

◆ adjust_product()

static void adjust_product ( object item,
int  adjust,
int  yield 
)
static

We adjust the nrof of the final product, based on the item's default parameters, and the relevant caster skill level.

Parameters
itemitem to adjust.
adjustnrof adjustment parameter, the higher the better.
yieldhow many products the recipe returns at maximum.

Definition at line 406 of file alchemy.cpp.

References rndm().

Referenced by attempt_recipe().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alchemy_failure_effect()

static void alchemy_failure_effect ( object op,
object cauldron,
const recipe rp,
int  danger 
)
static

Ouch. We didnt get the formula we wanted. This fctn simulates the backfire effects–worse effects as the level increases. If SPELL_FAILURE_EFFECTS is defined some really evil things can happen to the would be alchemist. This table probably needs some adjustment for playbalance. -b.t.

Parameters
opwho tried to do alchemy.
cauldroncontainer that was used.
rprecipe that failed, can be NULL.
dangerdanger value, the higher the more evil the effect.

Recipe specifies a special failure archetype, so use it instead of evil random things.

Definition at line 550 of file alchemy.cpp.

References add_string(), recipe::arch_name, recipe::arch_names, attempt_recipe(), cast_magic_storm(), cauldron_sound(), change_attr_value(), CLEAR_FLAG, create_archetype(), draw_ext_info(), draw_ext_info_format(), recipe::failure_arch, recipe::failure_message, fire_arch_from_position(), FLAG_CAN_ROLL, FLAG_CURSED, FLAG_IDENTIFIED, FLAG_KNOWN_CURSED, FLAG_NO_PICK, FOOD, FOR_INV_FINISH, FOR_INV_PREPARE, free_string(), generate_artifact(), get_formulalist(), get_random_mon(), get_random_recipe(), commongive::inv, object::inv, llevDebug, llevError, LOG(), LOOSE_MANA, M_STONE, object::magic, monster_npc_call_help(), MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, MSG_TYPE_SKILL_SUCCESS, object::name, NDI_UNIQUE, numb_ob_inside(), object_free_drop_inventory(), object_insert_in_map_at(), object_insert_in_ob(), object_set_enemy(), give::op, PREFER_HIGH, PREFER_LOW, QUERY_FLAG, RANDOM, random_roll(), remove_contents(), rndm(), SET_FLAG, SP_MED_FIREBALL, summon_hostile_monsters(), recipe::title, Ice::tmp, nlohmann::detail::void(), object::x, and object::y.

Referenced by attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ attempt_do_alchemy()

static void attempt_do_alchemy ( object caster,
object cauldron 
)
static

Main part of the ALCHEMY code. From this we call fctns that take a look at the contents of the 'cauldron' and, using these ingredients, we construct an integer formula value which is referenced (randomly) against a formula list (the formula list chosen is based on the # contents of the cauldron).

If we get a match between the recipe indicated in cauldron contents and a randomly chosen one, an item is created and experience awarded. Otherwise various failure effects are possible (getting worse and worse w/ # cauldron ingredients). Note that the 'item' to be made can be *anything *listed on the artifacts list in lib/artifacts which has a recipe listed in lib/formulae.

To those wondering why I am using the funky formula index method: 1) I want to match recipe to ingredients regardless of ordering. 2) I want a fast search for the 'right' recipe.

Note: it is just possible that a totally different combination of ingredients will result in a match with a given recipe. This is not a bug! There is no good reason (in my mind) why alchemical processes have to be unique – such a 'feature' is one reason why players might want to experiment around. :) -b.t.

Parameters
casterwho is doing alchemy.
cauldronthe cauldron in which alchemy should take place.

Definition at line 159 of file alchemy.cpp.

References alchemy_failure_effect(), recipe::arch_name, attempt_recipe(), calc_alch_danger(), recipe::cauldron, change_exp(), content_recipe_value(), recipe::diff, draw_ext_info(), draw_ext_info_format(), recipe::exp, find_recipe(), find_skill_by_name(), FLAG_WIZ, FOR_INV_FINISH, FOR_INV_PREPARE, get_formulalist(), recipe::index, is_defined_recipe(), say::item, object::level, llevDebug, LOG(), object::magic, recipe::min_level, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, MSG_TYPE_SKILL_MISSING, object::name, NDI_UNIQUE, numb_ob_inside(), PLAYER, PREFER_LOW, price_base(), QUERY_FLAG, random_roll(), recipe_chance(), SK_EXP_NONE, recipe::skill, recipe::title, Ice::tmp, and object::type.

Referenced by use_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ attempt_recipe()

static object * attempt_recipe ( object caster,
object cauldron,
int  ability,
const recipe rp,
int  nbatches,
int  ignore_cauldron 
)
static

Essentially a wrapper for make_item_from_recipe() and object_insert_in_ob(). If the caster has some alchemy skill, then they might gain some exp from (successfull) fabrication of the product. If nbatches==-1, don't give exp for this creation (random generation/ failed recipe) If ignore_cauldron, don't check if we are using the matching cauldron type (shadow alchemy)

Parameters
casterwho is trying to do alchemy.
cauldroncontainer used for alchemy.
ability?
rprecipe attempted.
nbatches?
ignore_cauldronif 0, checks the recipe uses the right cauldron type, else no check is done.
Returns
generated item, can be NULL if contents were destroyed.
Todo:
check meaning of ability/nbatches.

Definition at line 340 of file alchemy.cpp.

References adjust_product(), object::arch, recipe::cauldron, cauldron_sound(), draw_ext_info(), draw_ext_info_format(), find_skill_by_name(), FORCE, object::inv, say::item, recipe::keycode, llevDebug, LOG(), make_item_from_recipe(), MAX, MSG_TYPE_SKILL, MSG_TYPE_SKILL_ERROR, MSG_TYPE_SKILL_FAILURE, MSG_TYPE_SKILL_SUCCESS, object::name, archetype::name, NDI_UNIQUE, object_find_by_type_and_slaying(), object_insert_in_ob(), POTION, remove_contents(), recipe::skill, recipe::title, Ice::tmp, and recipe::yield.

Referenced by alchemy_failure_effect(), and attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ calc_alch_danger()

static int calc_alch_danger ( object caster,
object cauldron,
const recipe rp 
)
static

"Danger" level, will determine how bad the backfire could be if the user fails to concoct a recipe properly. Factors include the number of ingredients, the magical nature of ingredients, the user's effective level, the user's Int and the enchantment on the mixing device (aka "cauldron"). Higher values of 'danger' indicate more danger. -b.t.

Parameters
casterwho is trying alchemy.
cauldroncontainer used.
rprecipe attempted.
Returns
danger value.

Definition at line 830 of file alchemy.cpp.

References recipe::diff, find_skill_by_name(), FLAG_CURSED, FLAG_DAMNED, FOR_INV_FINISH, FOR_INV_PREPARE, living::Int, object::level, llevDebug, LOG(), object::magic, QUERY_FLAG, recipe::skill, and object::stats.

Referenced by attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cauldron_sound()

static const char* cauldron_sound ( void  )
static

Returns a random selection from cauldron_effect[]

Definition at line 77 of file alchemy.cpp.

References cauldron_effect, and rndm().

Referenced by alchemy_failure_effect(), and attempt_recipe().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ chance_fn()

static float chance_fn ( int  diff)
static

Compute a success probability, between .01 and .95, based on the level difference.

Parameters
difflevel difference.
Returns
success probability.

Definition at line 89 of file alchemy.cpp.

References MAX, and MIN.

Referenced by recipe_chance().

+ Here is the caller graph for this function:

◆ content_recipe_value()

static int content_recipe_value ( object op)
static

Recipe value of the entire contents of a container. This appears to just generate a hash value, which I guess for now works ok, but the possibility of duplicate hashes is certainly possible - msw

Parameters
opcontained for which to generate a hash.
Returns
hash value.

Definition at line 275 of file alchemy.cpp.

References FOR_INV_FINISH, FOR_INV_PREPARE, llevDebug, LOG(), MAX_BUF, give::name, NROF(), give::op, safe_strncpy, strtoint(), and Ice::tmp.

Referenced by attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_recipe()

static const recipe * find_recipe ( const recipelist fl,
int  formula,
object cauldron 
)
static

Find a recipe from a recipe list that matches the given formula. If there is more than one matching recipe, it selects a random one. If at least one transmuting recipe matches, it only considers matching transmuting recipes.

Parameters
fllist containing the potential formulae based on the number of ingredients.
formulahash of the ingredients.
ingredientsingredients, linked through the 'below' field.
Returns
one matching recipe, or NULL if no recipe matches

Definition at line 979 of file alchemy.cpp.

References object::arch, recipe::arch_name, recipe::cauldron, find_transmution_ob(), recipe::index, object::inv, recipelist::items, llevDebug, LOG(), archetype::name, recipe::next, rotate-tower::result, rndm(), recipe::title, and recipe::transmute.

Referenced by attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_transmution_ob()

static object * find_transmution_ob ( object first_ingred,
const recipe rp,
size_t *  rp_arch_index,
int  create_item 
)
static

Looks through the ingredient list. If we find a suitable object in it - we will use that to make the requested artifact. Otherwise the code returns a 'generic' item if create_item is set. -b.t.

Parameters
first_ingredpointer to first item to check
rprecipe the player is trying
rp_arch_indexpointer to return value; set to arch index for recipe; set to zero if not using a transmution formula
create_itemif set, will create a generic item if no suitable item is found.
Returns
NULL if no suitable item was found and create_item is 0, existing or new item else.

Definition at line 495 of file alchemy.cpp.

References recipe::arch_name, recipe::arch_names, create_archetype(), FOR_OB_AND_BELOW_FINISH, FOR_OB_AND_BELOW_PREPARE, say::item, llevDebug, LOG(), RANDOM, and recipe::transmute.

Referenced by find_recipe(), and make_item_from_recipe().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_defined_recipe()

static int is_defined_recipe ( const recipe rp,
const object cauldron 
)
static

Determines if ingredients in a container match the proper ingredients for a recipe.

This functions tries to find each defined ingredient in the container. It is the defined recipe iff

  • the number of ingredients of the recipe and in the container is equal
  • all ingredients of the recipe are found in the container
  • the number of batches is the same for all ingredients
Parameters
rprecipe to check.
cauldroncontainer that holds the ingredients.
Returns
1 if the ingredients match the recipe, 0 if not.

Definition at line 890 of file alchemy.cpp.

References FOR_INV_FINISH, FOR_INV_PREPARE, recipe::ingred, llevDebug, LOG(), MAX_BUF, give::name, linked_char::name, object::name, linked_char::next, and guildjoin::ob.

Referenced by attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ make_item_from_recipe()

static object * make_item_from_recipe ( object cauldron,
const recipe rp 
)
static

Using a list of items and a recipe to make an artifact.

Parameters
cauldronthe cauldron (including the ingredients) used to make the item
rpthe recipe to make the artifact from
Returns
the newly created object, NULL if something failed

Definition at line 431 of file alchemy.cpp.

References recipe::arch_name, find_transmution_ob(), FLAG_CURSED, FLAG_DAMNED, give_artifact_abilities(), object::inv, is_identified(), artifact::item, say::item, llevDebug, llevError, locate_recipe_artifact(), LOG(), NROF(), object_add_weight(), object_give_identified_properties(), object_sub_weight(), QUERY_FLAG, SET_FLAG, recipe::title, recipe::transmute, and transmute_materialname().

Referenced by attempt_recipe().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ numb_ob_inside()

static int numb_ob_inside ( const object op)
static

Returns the total number of items in op, excluding ones in item's items.

Parameters
opcontainer.
Returns
total item count.

Definition at line 303 of file alchemy.cpp.

References FOR_INV_FINISH, FOR_INV_PREPARE, llevDebug, LOG(), give::op, and Ice::tmp.

Referenced by alchemy_failure_effect(), and attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ recipe_chance()

static float recipe_chance ( const recipe rp,
const object skill,
const object cauldron 
)
static

Compute the success probability of a recipe.

Probability of success is a function of the difference between the recipe difficulty and the player's skill level, adjusted by the cauldron bonus.

The shape is roughly 1.5-exp(x/50): ---------—+----------— Difference | Probability ---------—+----------— 10 | 0.31 0 | 0.51 -10 | 0.71 -30 | 0.91 <= -35 | 0.95 ---------—+----------—

Parameters
rprecipe to attempt.
skillskill being used.
cauldronprovides the magic of the used device.
Returns
chance between 0.01 and .95.

Definition at line 121 of file alchemy.cpp.

References chance_fn(), recipe::diff, object::level, and object::magic.

Referenced by attempt_do_alchemy().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_contents()

static void remove_contents ( object first_ob,
object save_item 
)
static

All but object "save_item" are elimentated from the container list. Note we have to becareful to remove the inventories of objects in the cauldron inventory (ex icecube has stuff in it).

Parameters
first_obcontainer from which to remove.
save_itemwhat item to not remove. Can be NULL.

Definition at line 798 of file alchemy.cpp.

References FOR_OB_AND_BELOW_FINISH, FOR_OB_AND_BELOW_PREPARE, object_free_drop_inventory(), object_remove(), and Ice::tmp.

Referenced by alchemy_failure_effect(), and attempt_recipe().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ use_alchemy()

int use_alchemy ( object op)

Handle use_skill for alchemy-like items.

Parameters
opplayer trying to do alchemy.
Returns
1 if any recipe was attempted, 0 else.
Note
Will inform player if attempting to use unpaid cauldron or ingredient.
Todo:
check if no superflous message when 2 cauldrons on same spot, one unpaid? (shouldn't happen, but well).

Definition at line 1057 of file alchemy.cpp.

References attempt_do_alchemy(), draw_ext_info(), draw_ext_info_format(), esrv_send_inventory(), FLAG_APPLIED, FLAG_IS_CAULDRON, FLAG_UNPAID, FLAG_WIZ, FOR_MAP_FINISH, FOR_MAP_PREPARE, MAX_BUF, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, MSG_TYPE_SKILL, MSG_TYPE_SKILL_ERROR, give::name, NDI_UNIQUE, object_find_by_flag(), give::op, query_base_name(), QUERY_FLAG, and Ice::tmp.

Referenced by do_skill(), and knowledge_alchemy_attempt().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ cauldron_effect

const char* const cauldron_effect[]
static
Initial value:
= {
"vibrates briefly",
"produces a cloud of steam",
"emits bright flames",
"pours forth heavy black smoke",
"emits sparks",
"shoots out small flames",
"whines painfully",
"hiccups loudly",
"wheezes",
"burps",
"shakes",
"rattles",
"makes chugging sounds",
"smokes heavily for a while"
}

define this for some helpful debuging information define this for loads of (marginal) debuging information Random cauldrons effects

Definition at line 45 of file alchemy.cpp.

Referenced by cauldron_sound().