Crossfire Server, Trunk  1.75.0
alchemy.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 
14 /* March 96 - Laid down original code. -b.t. thomas@astro.psu.edu */
15 
21 #include "global.h"
22 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "object.h"
29 #include "shop.h"
30 #include "skills.h"
31 #include "spells.h"
32 #include "sproto.h"
33 
35 #if 0
36 #define ALCHEMY_DEBUG
37 #endif
38 
40 #if 0
41 #define EXTREME_ALCHEMY_DEBUG
42 #endif
43 
45 static const char *const cauldron_effect [] = {
46  "vibrates briefly",
47  "produces a cloud of steam",
48  "emits bright flames",
49  "pours forth heavy black smoke",
50  "emits sparks",
51  "shoots out small flames",
52  "whines painfully",
53  "hiccups loudly",
54  "wheezes",
55  "burps",
56  "shakes",
57  "rattles",
58  "makes chugging sounds",
59  "smokes heavily for a while"
60 };
61 
62 
63 static int is_defined_recipe(const recipe *rp, const object *cauldron);
64 static const recipe *find_recipe(const recipelist *fl, int formula, object *cauldron);
65 static int content_recipe_value(object *op);
66 static int numb_ob_inside(const object *op);
67 static void alchemy_failure_effect(object *op, object *cauldron, const recipe *rp, int danger);
68 static object *attempt_recipe(object *caster, object *cauldron, int ability, const recipe *rp, int nbatches, int ignore_cauldron);
69 static int calc_alch_danger(object *caster, object *cauldron, const recipe *rp);
70 static object *make_item_from_recipe(object *cauldron, const recipe *rp);
71 static void remove_contents(object *first_ob, object *save_item);
72 static void adjust_product(object *item, int lvl, int yield);
73 static object *find_transmution_ob(object *first_ingred, const recipe *rp, size_t *rp_arch_index, int create_item);
74 static void attempt_do_alchemy(object *caster, object *cauldron);
75 
77 static const char *cauldron_sound(void) {
78  int size = sizeof(cauldron_effect)/sizeof(char *);
79 
80  return cauldron_effect[rndm(0, size-1)];
81 }
82 
89 static float chance_fn(int diff) {
90  if (diff > 10)
91  return MAX(.01, .3 - (diff - 10) * .03);
92 
93  if (diff > -10)
94  return .5 + .02 * (float)(-diff);
95 
96  return MIN(.95, .70 + (-diff - 10) * .01);
97 }
98 
121 static float recipe_chance(const recipe *rp, const object *skill, const object *cauldron) {
122  assert(rp);
123  assert(skill);
124  assert(cauldron);
125 
126  const int cauldron_add_skill = (cauldron->magic + 1) / 2;
127  const int eff_skill = skill->level + cauldron_add_skill;
128  return chance_fn(rp->diff - eff_skill);
129 }
130 
159 static void attempt_do_alchemy(object *caster, object *cauldron) {
160  const recipelist *fl;
161  const recipe *rp = NULL;
162  float success_chance;
163  int numb, ability = 1;
164  int formula = 0;
165  object *item, *skop;
166 
167  if (caster->type != PLAYER)
168  return; /* only players for now */
169 
170  /* if no ingredients, no formula! lets forget it */
171  if (!(formula = content_recipe_value(cauldron))) {
173  "The %s is empty.",
174  cauldron->name);
175  return;
176  }
177 
178  numb = numb_ob_inside(cauldron);
179  if ((fl = get_formulalist(numb))) {
180  if (QUERY_FLAG(caster, FLAG_WIZ)) {
181  rp = find_recipe(fl, formula, cauldron);
182  if (rp != NULL) {
183 #ifdef ALCHEMY_DEBUG
184  if (strcmp(rp->title, "NONE"))
185  LOG(llevDebug, "WIZ got formula: %s of %s\n", rp->arch_name[0], rp->title);
186  else
187  LOG(llevDebug, "WIZ got formula: %s (nbatches:%d)\n", rp->arch_name[0], formula/rp->index);
188 #endif
189  attempt_recipe(caster, cauldron, ability, rp, formula/rp->index, !is_defined_recipe(rp, cauldron));
190  } else
191  LOG(llevDebug, "WIZ couldn't find formula for ingredients.\n");
192  return;
193  } /* End of WIZ alchemy */
194 
195  /* find the recipe */
196  rp = find_recipe(fl, formula, cauldron);
197  if (rp != NULL) {
198  uint64_t value_ingredients;
199  uint64_t value_item;
200  int attempt_shadow_alchemy;
201 
202  /* the caster gets an increase in ability based on thier skill lvl */
203  if (rp->skill != NULL) {
204  skop = find_skill_by_name(caster, rp->skill);
205  if (!skop) {
207  "You do not have the proper skill for this recipe");
208  } else {
209  ability += skop->level*((4.0+cauldron->magic)/4.0);
210  }
211  } else {
212  LOG(llevDebug, "Recipe %s has NULL skill!\n", rp->title);
213  return;
214  }
215 
216  if (rp->cauldron == NULL) {
217  LOG(llevDebug, "Recipe %s has NULL cauldron!\n", rp->title);
218  return;
219  }
220 
221  if (rp->min_level != 0 && skop->level < rp->min_level) {
223  "You aren't skilled enough to try this recipe.");
224  return;
225  }
226 
227  /* determine value of ingredients */
228  value_ingredients = 0;
229  FOR_INV_PREPARE(cauldron, tmp)
230  value_ingredients += price_base(tmp);
231  FOR_INV_FINISH();
232 
233  attempt_shadow_alchemy = !is_defined_recipe(rp, cauldron);
234 
235  /* create the object **FIRST**, then decide whether to keep it. */
236  if ((item = attempt_recipe(caster, cauldron, ability, rp, formula/rp->index, attempt_shadow_alchemy)) != NULL) {
237  /* compute base chance of recipe success */
238  success_chance = recipe_chance(rp, skop, cauldron);
239 
240 #ifdef ALCHEMY_DEBUG
241  LOG(llevDebug, "percent success chance = %f ab%d / diff%d*lev%d\n", success_chance, ability, rp->diff, item->level);
242 #endif
243 
244  value_item = price_base(item);
245  if (attempt_shadow_alchemy && value_item > value_ingredients) {
246 #ifdef ALCHEMY_DEBUG
247 #ifndef WIN32
248  LOG(llevDebug, "Forcing failure for shadow alchemy recipe because price of ingredients (%llu) is less than price of result (%llu).\n", value_ingredients, value_item);
249 #else
250  LOG(llevDebug, "Forcing failure for shadow alchemy recipe because price of ingredients (%I64d) is less than price of result (%I64d).\n", value_ingredients, value_item);
251 #endif
252 #endif
253  /* roll the dice */
254  } else if (random_roll(0, 101, caster, PREFER_LOW) <= 100.0*success_chance) {
255  change_exp(caster, rp->exp, rp->skill, SK_EXP_NONE);
256  return;
257  }
258  }
259  }
260  }
261  /* if we get here, we failed!! */
262  alchemy_failure_effect(caster, cauldron, rp, calc_alch_danger(caster, cauldron, rp));
263 }
264 
275 static int content_recipe_value(object *op) {
276  char name[MAX_BUF];
277  int tval = 0, formula = 0;
278 
279  FOR_INV_PREPARE(op, tmp) {
280  tval = 0;
281  safe_strncpy(name, tmp->name, sizeof(name));
282  if (tmp->title)
283  snprintf(name, sizeof(name), "%s %s", tmp->name, tmp->title);
284  tval = (strtoint(name)*NROF(tmp));
285 #ifdef ALCHEMY_DEBUG
286  LOG(llevDebug, "Got ingredient %d %s(%d)\n", NROF(tmp), name, tval);
287 #endif
288  formula += tval;
289  } FOR_INV_FINISH();
290 #ifdef ALCHEMY_DEBUG
291  LOG(llevDebug, " Formula value=%d\n", formula);
292 #endif
293  return formula;
294 }
295 
303 static int numb_ob_inside(const object *op) {
304  int o_number = 0;
305 
306  FOR_INV_PREPARE(op, tmp)
307  o_number++;
308  FOR_INV_FINISH();
309 #ifdef ALCHEMY_DEBUG
310  LOG(llevDebug, "numb_ob_inside(%s): found %d ingredients\n", op->name, o_number);
311 #endif
312  return o_number;
313 }
314 
340 static object *attempt_recipe(object *caster, object *cauldron, int ability, const recipe *rp, int nbatches, int ignore_cauldron) {
341  object *item = NULL, *skop;
342  /* this should be passed to this fctn, not effiecent cpu use this way */
343  int batches = abs(nbatches);
344 
345  /* is the cauldron the right type? */
346  if (!ignore_cauldron && (strcmp(rp->cauldron, cauldron->arch->name) != 0)) {
348  "You are not using the proper facilities for this formula.");
349  return NULL;
350  }
351 
352  skop = find_skill_by_name(caster, rp->skill);
353  /* does the caster have the skill? */
354  if (!skop)
355  return NULL;
356 
357  /* code required for this recipe, search the caster */
358  if (rp->keycode) {
359  object *tmp;
360 
361  tmp = object_find_by_type_and_slaying(caster, FORCE, rp->keycode);
362  if (tmp == NULL) { /* failure--no code found */
364  "You know the ingredients, but not the technique. Go learn how to do this recipe.");
365  return NULL;
366  }
367  }
368 
369 #ifdef EXTREME_ALCHEMY_DEBUG
370  LOG(llevDebug, "attempt_recipe(): got %d nbatches\n", nbatches);
371  LOG(llevDebug, "attempt_recipe(): using recipe %s\n", rp->title ? rp->title : "unknown");
372 #endif
373 
374  if ((item = make_item_from_recipe(cauldron, rp)) != NULL) {
375  remove_contents(cauldron->inv, item);
376  /* adj lvl, nrof on caster level */
377  adjust_product(item, ability, rp->yield ? (rp->yield*batches) : batches);
378 
379  if (item->type == POTION) {
380  item->level = MAX(item->level, skop->level);
381  }
382 
383  if (!item->env && (item = object_insert_in_ob(item, cauldron)) == NULL) {
385  "Nothing happened.");
386  } else {
387  draw_ext_info_format(NDI_UNIQUE, 0, caster,
389  "The %s %s.",
390  cauldron->name, cauldron_sound());
391  }
392 
393  // Give player knowledge of the recipe they just made
394  char buf[MAX_BUF];
395  formula_knowledge_code(rp, buf, sizeof(buf));
396  knowledge_give(caster->contr, buf, NULL);
397  }
398  return item;
399 }
400 
411 static void adjust_product(object *item, int adjust, int yield) {
412  int nrof = 1;
413 
414  if (!yield)
415  yield = 1;
416  if (adjust <= 0)
417  adjust = 1; /* lets avoid div by zero! */
418  if (item->nrof) {
419  nrof = (1.0-1.0/(adjust/10.0+1.0))*(rndm(0, yield-1)+rndm(0, yield-1)+rndm(0, yield-1))+1;
420  if (nrof > yield)
421  nrof = yield;
422  item->nrof = nrof;
423  }
424 }
425 
436 static object *make_item_from_recipe(object *cauldron, const recipe *rp) {
437  const artifact *art = NULL;
438  object *item = NULL;
439  size_t rp_arch_index;
440 
441  if (rp == NULL)
442  return (object *)NULL;
443 
444  /* Find the appropriate object to transform...*/
445  if ((item = find_transmution_ob(cauldron->inv, rp, &rp_arch_index, 1)) == NULL) {
446  LOG(llevDebug, "make_alchemy_item(): failed to create alchemical object.\n");
447  return (object *)NULL;
448  }
449 
450  /* If item is already in container, we need to remove its weight, since it can change later on. */
451  if (item->env != NULL)
452  object_sub_weight(cauldron, item->weight*NROF(item));
453 
454  /* Find the appropriate artifact template...*/
455  if (strcmp(rp->title, "NONE")) {
456  int item_power_delta = 0;
457  if ((art = locate_recipe_artifact(rp, rp_arch_index)) == NULL) {
458  LOG(llevError, "make_alchemy_item(): failed to locate recipe artifact.\n");
459  LOG(llevDebug, " --requested recipe: %s of %s.\n", rp->arch_name[0], rp->title);
460  return (object *)NULL;
461  }
462  transmute_materialname(item, art->item);
463  if (rp->transmute) {
464  /* If we change an item, then we must keep the item power.
465  * Else this allows for instance using a helmet+5 (item power 5) for a
466  * helmet of Xebinon, giving a helmet of Xebinon+5 with item power 0. */
467  item_power_delta = item->item_power - item->arch->clone.item_power;
468  }
469  give_artifact_abilities(item, art->item);
470  item->item_power += item_power_delta;
471  if (is_identified(item)) {
472  /* artifacts are generated unidentified, so if the item is identified we must give it its real properties. */
474  }
475  }
476  if (item->env != NULL)
477  object_add_weight(cauldron, item->weight*NROF(item));
478 
479  if (QUERY_FLAG(cauldron, FLAG_CURSED))
480  SET_FLAG(item, FLAG_CURSED);
481  if (QUERY_FLAG(cauldron, FLAG_DAMNED))
482  SET_FLAG(item, FLAG_DAMNED);
483 
484  return item;
485 }
486 
500 static object *find_transmution_ob(object *first_ingred, const recipe *rp, size_t *rp_arch_index, int create_item) {
501  object *item = NULL;
502 
503  *rp_arch_index = 0;
504 
505  if (rp->transmute) { /* look for matching ingredient/prod archs */
506  item = first_ingred;
508  size_t i;
509 
510  for (i = 0; i < rp->arch_names; i++) {
511  /* Items with titles are skipped to avoid shadow alchemy ability stacking. */
512  if (strcmp(item->arch->name, rp->arch_name[i]) == 0 && !(item->title)) {
513  *rp_arch_index = i;
514  break;
515  }
516  }
517  if (i < rp->arch_names)
518  break;
520  }
521 
522  /* failed, create a fresh object. Note no nrof>1 because that would
523  * allow players to create massive amounts of artifacts easily */
524  if (create_item && (!item || item->nrof > 1)) {
525  *rp_arch_index = RANDOM()%rp->arch_names;
526  item = create_archetype(rp->arch_name[*rp_arch_index]);
527  }
528 
529 #ifdef ALCHEMY_DEBUG
530  LOG(llevDebug, "recipe calls for%stransmution.\n", rp->transmute ? " " : " no ");
531  if (item != NULL) {
532  LOG(llevDebug, " find_transmutable_ob(): returns arch %s(sp:%d)\n", item->arch->name, item->stats.sp);
533  }
534 #endif
535 
536  return item;
537 }
538 
555 static void alchemy_failure_effect(object *op, object *cauldron, const recipe *rp, int danger) {
556  int level = 0;
557 
558  if (!op || !cauldron)
559  return;
560 
562  if (rp && rp->failure_arch) {
563  object *failure = create_archetype(rp->failure_arch);
564  if (!failure) {
565  LOG(llevError, "invalid failure_arch %s for recipe %s\n", rp->failure_arch, rp->title);
566  return;
567  }
568 
569  remove_contents(cauldron->inv, NULL);
570 
571  object_insert_in_ob(failure, cauldron);
572  if (rp->failure_message) {
574  }
575  return;
576  }
577 
578  if (danger > 1)
579  level = random_roll(1, danger, op, PREFER_LOW);
580 
581 #ifdef ALCHEMY_DEBUG
582  LOG(llevDebug, "Alchemy_failure_effect(): using level=%d\n", level);
583 #endif
584 
585  /* possible outcomes based on level */
586  if (level < 25) { /* INGREDIENTS USED/SLAGGED */
587  object *item = NULL;
588 
589  if (rndm(0, 2)) { /* slag created */
590  object *tmp;
591  int weight = 0;
592  uint16_t material = M_STONE;
593 
594  FOR_INV_PREPARE(cauldron, inv) { /* slag has coadded ingredient properties */
595  weight += inv->weight;
596  if (!(material&inv->material))
597  material |= inv->material;
598  } FOR_INV_FINISH();
599  tmp = create_archetype("rock");
600  tmp->weight = weight;
601  tmp->value = 0;
602  tmp->material = material;
603  tmp->materialname = add_string("stone");
604  free_string(tmp->name);
605  tmp->name = add_string("slag");
606  if (tmp->name_pl)
607  free_string(tmp->name_pl);
608  tmp->name_pl = add_string("slags");
609  item = object_insert_in_ob(tmp, cauldron);
611  CLEAR_FLAG(tmp, FLAG_NO_PICK);
612  tmp->move_block = 0;
613  }
614  remove_contents(cauldron->inv, item);
616  "The %s %s.",
617  cauldron->name, cauldron_sound());
618  return;
619  } else if (level < 40) { /* MAKE TAINTED ITEM */
620  object *tmp = NULL;
621 
622  /*
623  * Note by Nicolas Weeger 2010-09-26
624  * This is an incorrect part.
625  * Calling again attempt_recipe in case of failure will apply again the artifact
626  * combination to the item.
627  * This leads to items with eg 100% resist, or more.
628  * So use the actual item in the cauldron, don't retry the recipe.
629  * This should fix bug #2020224: buggy(?) crafting yields.
630  *
631  if (!rp)
632  if ((rp = get_random_recipe((recipelist *)NULL)) == NULL)
633  return;
634  */
635 
636  if ((tmp = cauldron->inv)) /*attempt_recipe(op, cauldron, 1, rp, -1, 0)))*/ {
637  if (!QUERY_FLAG(tmp, FLAG_CURSED)) { /* curse it */
638  SET_FLAG(tmp, FLAG_CURSED);
641  }
642 
643  /* the apply code for potions already deals with cursed
644  * potions, so any code here is basically ignored.
645  */
646  if (tmp->type == FOOD) {
647  tmp->stats.hp = random_roll(0, 149, op, PREFER_LOW);
648  }
649  tmp->value = 0; /* unsaleable item */
650 
651  /* change stats downward */
652  do {
653  change_attr_value(&tmp->stats, rndm(0, 6), -1*(rndm(1, 3)));
654  } while (rndm(0, 2));
655  }
656  return;
657  }
658 #if 0
659  /*
660  Note: this does not work as expected...
661  At this point there is only one item in the cauldron, and get_formulalist(0) will return
662  the first formula list for recipes with 1 ingredient.
663  So disable this, and just use the next case.
664  */
665 
666  if (level == 40) { /* MAKE RANDOM RECIPE */
667  recipelist *fl;
668  int numb = numb_ob_inside(cauldron);
669 
670  fl = get_formulalist(numb-1); /* take a lower recipe list */
671  if (fl && (rp = get_random_recipe(fl)))
672  /* even though random, don't grant user any EXP for it */
673  (void)attempt_recipe(op, cauldron, 1, rp, -1, 0);
674  else
675  alchemy_failure_effect(op, cauldron, rp, level-1);
676  return;
677 
678  } else
679 #endif
680  if (level < 45) { /* INFURIATE NPC's */
681  /* this is kind of kludgy I know...*/
682  object_set_enemy(cauldron, op);
683  monster_npc_call_help(cauldron);
684  object_set_enemy(cauldron, NULL);
685 
686  alchemy_failure_effect(op, cauldron, rp, level-5);
687  return;
688  } else if (level < 50) { /* MINOR EXPLOSION/FIREBALL */
689  object *tmp;
690 
691  remove_contents(cauldron->inv, NULL);
692  switch (rndm(0, 2)) {
693  case 0:
694  tmp = create_archetype("bomb");
695  tmp->stats.dam = random_roll(1, level, op, PREFER_LOW);
696  tmp->stats.hp = random_roll(1, level, op, PREFER_LOW);
698  "The %s creates a bomb!",
699  cauldron->name);
700  break;
701 
702  default:
703  tmp = create_archetype("fireball");
704  tmp->stats.dam = random_roll(1, level, op, PREFER_LOW)/5+1;
705  tmp->stats.hp = random_roll(1, level, op, PREFER_LOW)/10+2;
707  "The %s erupts in flame!",
708  cauldron->name);
709  break;
710  }
711  object_insert_in_map_at(tmp, op->map, NULL, 0, cauldron->x, cauldron->y);
712  return;
713  } else if (level < 60) { /* CREATE MONSTER */
715  "The %s %s.", cauldron->name, cauldron_sound());
716  remove_contents(cauldron->inv, NULL);
717  return;
718  } else if (level < 80) { /* MAJOR FIRE */
719  object *fb = create_archetype(SP_MED_FIREBALL);
720 
721  remove_contents(cauldron->inv, NULL);
722  fire_arch_from_position(cauldron, cauldron, cauldron->x, cauldron->y, 0, fb);
725  "The %s erupts in flame!",
726  cauldron->name);
727  return;
728  } else if (level < 100) { /* WHAMMY the CAULDRON */
729  if (!QUERY_FLAG(cauldron, FLAG_CURSED)) {
730  SET_FLAG(cauldron, FLAG_CURSED);
731  CLEAR_FLAG(cauldron, FLAG_KNOWN_CURSED);
732  CLEAR_FLAG(cauldron, FLAG_IDENTIFIED);
733  } else
734  cauldron->magic--;
735  cauldron->magic -= random_roll(0, 4, op, PREFER_LOW);
736  if (rndm(0, 1)) {
737  remove_contents(cauldron->inv, NULL);
739  "Your %s turns darker then makes a gulping sound!",
740  cauldron->name);
741  } else
743  "Your %s becomes darker.",
744  cauldron->name);
745  return;
746  } else if (level < 110) { /* SUMMON EVIL MONSTERS */
747  object *tmp = get_random_mon(level/5);
748 
749  remove_contents(cauldron->inv, NULL);
750  if (!tmp)
751  alchemy_failure_effect(op, cauldron, rp, level);
752  else if (summon_hostile_monsters(cauldron, random_roll(1, 10, op, PREFER_LOW), tmp->arch->name))
754  "The %s %s and then pours forth monsters!",
755  cauldron->name, cauldron_sound());
756  return;
757  } else if (level < 150) { /* COMBO EFFECT */
758  int roll = rndm(1, 3);
759  while (roll) {
760  alchemy_failure_effect(op, cauldron, rp, level-39);
761  roll--;
762  }
763  return;
764  } else if (level == 151) { /* CREATE RANDOM ARTIFACT */
765  object *tmp;
766 
767  /* this is meant to be better than prior possiblity,
768  * in this one, we allow *any *valid alchemy artifact
769  * to be made (rather than only those on the given
770  * formulalist) */
771  if (!rp)
772  rp = get_random_recipe((recipelist *)NULL);
773  if (rp && (tmp = create_archetype(rp->arch_name[RANDOM()%rp->arch_names]))) {
774  generate_artifact(tmp, random_roll(1, op->level/2+1, op, PREFER_HIGH)+1);
775  if ((tmp = object_insert_in_ob(tmp, cauldron))) {
776  remove_contents(cauldron->inv, tmp);
779  "The %s %s.",
780  cauldron->name, cauldron_sound());
781  }
782  }
783  return;
784  } else { /* MANA STORM - watch out!! */
785  object *tmp = create_archetype(LOOSE_MANA);
787  "You unwisely release potent forces!");
788  remove_contents(cauldron->inv, NULL);
789  cast_magic_storm(op, tmp, level);
790  return;
791  }
792 }
793 
803 static void remove_contents(object *first_ob, object *save_item) {
804  object *tmp;
805 
806  tmp = first_ob;
808  if (tmp != save_item) {
809  if (tmp->inv)
810  remove_contents(tmp->inv, NULL);
811  object_remove(tmp);
813  }
815 }
816 
835 static int calc_alch_danger(object *caster, object *cauldron, const recipe *rp) {
836  int danger = 0;
837 
838  /* Get the recipe's skill if it has one. Otherwise, use your overall level.
839  * Note that this isn't inherently your chosen skill, so we go find it.
840  */
841  object *skop = rp && rp->skill ? find_skill_by_name(caster, rp->skill) : NULL;
842  danger -= skop ? skop->level : caster->level;
843 
844  /* better cauldrons reduce risk */
845  danger -= cauldron->magic;
846 
847  /* Higher Int, lower the risk */
848  danger -= 3*(caster->stats.Int-15);
849 
850  /* Ingredients. */
851  FOR_INV_PREPARE(cauldron, item) {
852  /* Nicolas Weeger: no reason why this is the case.
853  danger += item->weight / 100;
854  */
855  danger++;
856  if (QUERY_FLAG(item, FLAG_CURSED) || QUERY_FLAG(item, FLAG_DAMNED))
857  danger += 5;
858  } FOR_INV_FINISH();
859 
860  if (rp == NULL)
861  danger += 110;
862  else
863  danger += rp->diff*3;
864 
865  /* Using a bad device is *majorly *stupid */
866  if (QUERY_FLAG(cauldron, FLAG_CURSED))
867  danger += 80;
868  if (QUERY_FLAG(cauldron, FLAG_DAMNED))
869  danger += 200;
870 
871 #ifdef ALCHEMY_DEBUG
872  LOG(llevDebug, "calc_alch_danger() returned danger=%d\n", danger);
873 #endif
874 
875  return danger;
876 }
877 
895 static int is_defined_recipe(const recipe *rp, const object *cauldron) {
896  uint32_t batches_in_cauldron;
897  const linked_char *ingredient;
898  int number;
899 
900  /* check for matching number of ingredients */
901  number = 0;
902  for (ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next)
903  number++;
904  FOR_INV_PREPARE(cauldron, ob) {
905 #ifdef ALCHEMY_DEBUG
906  LOG(llevDebug, "cauldron %s, item %s, number %d->%d\n", cauldron->name, ob->name, number, number - 1);
907 #endif
908  number--;
909  } FOR_INV_FINISH();
910  if (number != 0)
911  return 0;
912 
913  /* check for matching ingredients */
914  batches_in_cauldron = 0;
915  for (ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next) {
916  uint32_t nrof;
917  const char *name;
918  int ok;
919 
920  /* determine and remove nrof from name */
921  name = ingredient->name;
922  nrof = 0;
923  while (isdigit(*name)) {
924  nrof = 10*nrof+(*name-'0');
925  name++;
926  }
927  if (nrof == 0)
928  nrof = 1;
929  while (*name == ' ')
930  name++;
931 
932  /* find the current ingredient in the cauldron */
933  ok = 0;
934  FOR_INV_PREPARE(cauldron, ob) {
935  char name_ob[MAX_BUF];
936  const char *name2;
937 
938  if (ob->title == NULL)
939  name2 = ob->name;
940  else {
941  snprintf(name_ob, sizeof(name_ob), "%s %s", ob->name, ob->title);
942  name2 = name_ob;
943  }
944 
945  if (strcmp(name2, name) == 0) {
946  if (ob->nrof%nrof == 0) {
947  uint32_t batches;
948 
949  // Make sure we handle non-stacking ingredients such as icecubes.
950  batches = (ob->nrof ? ob->nrof : 1)/nrof;
951 #ifdef ALCHEMY_DEBUG
952  LOG(llevDebug, "batches of ingred %s: %d; batches prior: %d\n", name, batches, batches_in_cauldron);
953 #endif
954  if (batches_in_cauldron == 0) {
955  batches_in_cauldron = batches;
956  ok = 1;
957  } else if (batches_in_cauldron == batches)
958  ok = 1;
959  }
960  break;
961  }
962  } FOR_INV_FINISH();
963  if (!ok)
964  return(0);
965  }
966 
967  return(1);
968 }
969 
984 static const recipe *find_recipe(const recipelist *fl, int formula, object *cauldron) {
985  const recipe *rp;
986  const recipe *result; /* winning recipe, or NULL if no recipe found */
987  int recipes_matching; /* total number of matching recipes so far */
988  int transmute_found; /* records whether a transmuting recipe was found so far */
989  size_t rp_arch_index;
990 
991 #ifdef EXTREME_ALCHEMY_DEBUG
992  LOG(llevDebug, "looking for formula %d:\n", formula);
993 #endif
994  result = NULL;
995  recipes_matching = 0;
996  transmute_found = 0;
997  for (rp = fl->items; rp != NULL; rp = rp->next) {
998  /* check if recipe matches at all */
999  if (rp->cauldron != cauldron->arch->name || formula%rp->index != 0) {
1000 #ifdef EXTREME_ALCHEMY_DEBUG
1001  LOG(llevDebug, " formula %s of %s (%d) does not match\n", rp->arch_name[0], rp->title, rp->index);
1002 #endif
1003  continue;
1004  }
1005 
1006  object *ingredients = cauldron->inv;
1007  if (rp->transmute && find_transmution_ob(ingredients, rp, &rp_arch_index, 0) != NULL) {
1008 #ifdef EXTREME_ALCHEMY_DEBUG
1009  LOG(llevDebug, " formula %s of %s (%d) is a matching transmuting formula\n", rp->arch_name[rp_arch_index], rp->title, rp->index);
1010 #endif
1011  /* transmution recipe with matching base ingredient */
1012  if (!transmute_found) {
1013  transmute_found = 1;
1014  recipes_matching = 0;
1015  }
1016  } else if (transmute_found) {
1017 #ifdef EXTREME_ALCHEMY_DEBUG
1018  LOG(llevDebug, " formula %s of %s (%d) matches but is not a matching transmuting formula\n", rp->arch_name[0], rp->title, rp->index);
1019 #endif
1020  /* "normal" recipe found after previous transmution recipe => ignore this recipe */
1021  continue;
1022  }
1023 #ifdef EXTREME_ALCHEMY_DEBUG
1024  else {
1025  LOG(llevDebug, " formula %s of %s (%d) matches\n", rp->arch_name[0], rp->title, rp->index);
1026  }
1027 #endif
1028 
1029  if (rndm(0, recipes_matching) == 0)
1030  result = rp;
1031 
1032  recipes_matching++;
1033  }
1034 
1035  if (result == NULL) {
1036 #ifdef ALCHEMY_DEBUG
1037  LOG(llevDebug, "couldn't find formula for ingredients.\n");
1038 #endif
1039  return NULL;
1040  }
1041 
1042 #ifdef ALCHEMY_DEBUG
1043  if (strcmp(result->title, "NONE") != 0)
1044  LOG(llevDebug, "got formula: %s of %s (nbatches:%d)\n", result->arch_name[0], result->title, formula/result->index);
1045  else
1046  LOG(llevDebug, "got formula: %s (nbatches:%d)\n", result->arch_name[0], formula/result->index);
1047 #endif
1048  return result;
1049 }
1050 
1062 int use_alchemy(object *op) {
1063  object *unpaid_cauldron = NULL;
1064  object *unpaid_item = NULL;
1065  int did_alchemy = 0;
1066  char name[MAX_BUF];
1067 
1068  if (QUERY_FLAG(op, FLAG_WIZ))
1069  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, "Note: alchemy in wizard-mode.\n");
1070 
1071  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
1072  if (QUERY_FLAG(tmp, FLAG_IS_CAULDRON)) {
1073  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1074  unpaid_cauldron = tmp;
1075  continue;
1076  }
1077  unpaid_item = object_find_by_flag(tmp, FLAG_UNPAID);
1078  if (unpaid_item != NULL)
1079  continue;
1080 
1081  attempt_do_alchemy(op, tmp);
1082  if (QUERY_FLAG(tmp, FLAG_APPLIED))
1083  esrv_send_inventory(op, tmp);
1084  did_alchemy = 1;
1085  }
1086  } FOR_MAP_FINISH();
1087  if (unpaid_cauldron) {
1088  query_base_name(unpaid_cauldron, 0, name, MAX_BUF);
1090  "You must pay for your %s first!",
1091  name);
1092  } else if (unpaid_item) {
1093  query_base_name(unpaid_item, 0, name, MAX_BUF);
1095  "You must pay for your %s first!",
1096  name);
1097  }
1098 
1099  return did_alchemy;
1100 }
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
M_STONE
#define M_STONE
Stone.
Definition: material.h:20
PLAYER
@ PLAYER
Definition: object.h:112
global.h
calc_alch_danger
static int calc_alch_danger(object *caster, object *cauldron, const recipe *rp)
"Danger" level, will determine how bad the backfire could be if the user fails to concoct a recipe pr...
Definition: alchemy.cpp:835
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:714
get_formulalist
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
Definition: recipe.cpp:98
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
cauldron_sound
static const char * cauldron_sound(void)
Returns a random selection from cauldron_effect[].
Definition: alchemy.cpp:77
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:411
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
recipe::arch_names
size_t arch_names
Size of the arch_name[] array.
Definition: recipe.h:12
recipe::yield
int yield
Maximum number of items produced by the recipe.
Definition: recipe.h:21
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.cpp:316
object::item_power
int8_t item_power
Power rating of the object.
Definition: object.h:372
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
find_recipe
static const recipe * find_recipe(const recipelist *fl, int formula, object *cauldron)
Find a recipe from a recipe list that matches the given formula.
Definition: alchemy.cpp:984
object::x
int16_t x
Definition: object.h:335
recipe::failure_arch
sstring failure_arch
Arch of the item to generate on failure, instead of blowing up stuff.
Definition: recipe.h:28
give_artifact_abilities
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-...
Definition: artifact.cpp:230
PREFER_LOW
#define PREFER_LOW
Definition: define.h:548
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
LOOSE_MANA
#define LOOSE_MANA
Definition: spells.h:162
cauldron_effect
static const char *const cauldron_effect[]
define this for some helpful debuging information
Definition: alchemy.cpp:45
artifact::item
object * item
Special values of the artifact.
Definition: artifact.h:15
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:325
recipelist::items
recipe * items
Pointer to first recipe in this list.
Definition: recipe.h:40
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
MIN
#define MIN(x, y)
Definition: compat.h:21
alchemy_failure_effect
static void alchemy_failure_effect(object *op, object *cauldron, const recipe *rp, int danger)
Ouch.
Definition: alchemy.cpp:555
recipe::failure_message
sstring failure_message
Specific failure message.
Definition: recipe.h:29
recipe::arch_name
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
attempt_recipe
static object * attempt_recipe(object *caster, object *cauldron, int ability, const recipe *rp, int nbatches, int ignore_cauldron)
Essentially a wrapper for make_item_from_recipe() and object_insert_in_ob().
Definition: alchemy.cpp:340
recipe::transmute
int transmute
If defined, one of the formula ingredients is used as the basis for the product object.
Definition: recipe.h:19
rndm
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
skills.h
fire_arch_from_position
int fire_arch_from_position(object *op, object *caster, int16_t x, int16_t y, int dir, object *spell)
Fires an archetype.
Definition: spell_util.cpp:629
object::title
sstring title
Of foo, etc.
Definition: object.h:325
SK_EXP_NONE
#define SK_EXP_NONE
Player gets nothing.
Definition: skills.h:80
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:303
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:241
recipe::exp
int exp
How much exp to give for this formulae.
Definition: recipe.h:17
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
buf
StringBuffer * buf
Definition: readable.cpp:1565
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:408
MAX
#define MAX(x, y)
Definition: compat.h:24
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
cast_magic_storm
void cast_magic_storm(object *op, object *tmp, int lvl)
This is really used mostly for spell fumbles and the like.
Definition: spell_effect.cpp:49
linked_char
Definition: global.h:98
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:307
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1545
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
NROF
static uint32_t NROF(const object *const ob)
Returns ob->nrof, unless it is 0, in which case return 1.
Definition: object.h:625
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:547
find_transmution_ob
static object * find_transmution_ob(object *first_ingred, const recipe *rp, size_t *rp_arch_index, int create_item)
Looks through the ingredient list.
Definition: alchemy.cpp:500
linked_char::name
const char * name
Definition: global.h:99
recipelist
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
POTION
@ POTION
Definition: object.h:116
MSG_TYPE_COMMAND_DM
#define MSG_TYPE_COMMAND_DM
DM related commands.
Definition: newclient.h:539
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
price_base
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status,...
Definition: item.cpp:1507
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:738
use_alchemy
int use_alchemy(object *op)
Handle use_skill for alchemy-like items.
Definition: alchemy.cpp:1062
numb_ob_inside
static int numb_ob_inside(const object *op)
Returns the total number of items in op, excluding ones in item's items.
Definition: alchemy.cpp:303
SP_MED_FIREBALL
#define SP_MED_FIREBALL
These are some hard coded values that are used within the code for spell failure effects or pieces of...
Definition: spells.h:161
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
is_identified
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn't ever need identifi...
Definition: item.cpp:1357
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
recipe::index
int index
Index value derived from formula ingredients.
Definition: recipe.h:18
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
content_recipe_value
static int content_recipe_value(object *op)
Recipe value of the entire contents of a container.
Definition: alchemy.cpp:275
object_find_by_flag
object * object_find_by_flag(const object *who, int flag)
Find object in inventory by flag.
Definition: object.cpp:4191
linked_char::next
struct linked_char * next
Definition: global.h:100
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:226
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Don't have the skill.
Definition: newclient.h:591
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
remove_contents
static void remove_contents(object *first_ob, object *save_item)
All but object "save_item" are elimentated from the container list.
Definition: alchemy.cpp:803
sproto.h
living::sp
int16_t sp
Spell points.
Definition: living.h:42
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:734
living::Int
int8_t Int
Definition: living.h:36
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
weight
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 and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked but be for you could fall down into a pit full of ghosts or dragons and not be able to get back out Break away sometimes it may be worth a player s time to test the walls of a map for secret doors Fire such as missile weapons and spells you will notice them going up in smoke ! So be careful not to destroy valuable items Spellbooks sometimes a player can learn the other times they cannot There are many different types of books and scrolls out there Improve item have lower weight
Definition: survival-guide.txt:100
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level,...
Definition: skill_util.cpp:209
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
create_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...
Definition: arch.cpp:276
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
attempt_do_alchemy
static void attempt_do_alchemy(object *caster, object *cauldron)
Main part of the ALCHEMY code.
Definition: alchemy.cpp:159
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
RANDOM
#define RANDOM()
Definition: define.h:628
make_item_from_recipe
static object * make_item_from_recipe(object *cauldron, const recipe *rp)
Using a list of items and a recipe to make an artifact.
Definition: alchemy.cpp:436
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:304
recipe
One alchemy recipe.
Definition: recipe.h:10
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:707
object_add_weight
void object_add_weight(object *op, signed long weight)
object_add_weight(object, weight) adds the specified weight to an object, and also updates how much t...
Definition: object.cpp:2818
formula_knowledge_code
void formula_knowledge_code(const recipe *r, char *buf, size_t len)
Store the textual knowledge marker code for recipe R in BUF.
Definition: readable.cpp:1638
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Find object in inventory by type and slaying.
Definition: object.cpp:4143
MSG_TYPE_SKILL_ERROR
#define MSG_TYPE_SKILL_ERROR
Doing something wrong.
Definition: newclient.h:592
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
spells.h
transmute_materialname
void transmute_materialname(object *op, const object *change)
When doing transmutation of objects, we have to recheck the resistances, as some that did not apply p...
Definition: utils.cpp:263
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:594
get_random_recipe
recipe * get_random_recipe(recipelist *rpl)
Gets a random recipe from a list, based on chance.
Definition: recipe.cpp:790
locate_recipe_artifact
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Finds an artifact for a recipe.
Definition: recipe.cpp:733
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Like set_attr_value(), but instead the value (which can be negative) is added to the specified stat.
Definition: living.cpp:264
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
monster_npc_call_help
void monster_npc_call_help(object *op)
A monster calls for help against its enemy.
Definition: monster.cpp:2014
shop.h
summon_hostile_monsters
int summon_hostile_monsters(object *op, int n, const char *monstername)
Summons hostile monsters and places them in nearby squares.
Definition: spell_util.cpp:1005
is_defined_recipe
static int is_defined_recipe(const recipe *rp, const object *cauldron)
Determines if ingredients in a container match the proper ingredients for a recipe.
Definition: alchemy.cpp:895
strtoint
int strtoint(const char *buf)
Convert buf into an integer equal to the coadded sum of the (lowercase) character.
Definition: recipe.cpp:712
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
recipe::diff
int diff
Alchemical dfficulty level.
Definition: recipe.h:16
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
object_give_identified_properties
void object_give_identified_properties(object *op)
Ensure op has all its "identified" properties set.
Definition: item.cpp:1365
level
int level
Definition: readable.cpp:1563
recipe::keycode
sstring keycode
Optional keycode needed to use the recipe.
Definition: recipe.h:25
knowledge_give
void knowledge_give(player *pl, const char *marker, const object *book)
Give a knowledge item from its code.
Definition: knowledge.cpp:996
recipe::min_level
int min_level
Minimum level to have in the skill to be able to use the formulae.
Definition: recipe.h:30
get_random_mon
object * get_random_mon(int level)
Returns a random monster selected from linked list of all monsters in the current game.
Definition: readable.cpp:1269
FOOD
@ FOOD
Definition: object.h:117
skill
skill
Definition: arch-handbook.txt:585
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1818
recipe::ingred
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
chance_fn
static float chance_fn(int diff)
Compute a success probability, between .01 and .95, based on the level difference.
Definition: alchemy.cpp:89
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
recipe::next
recipe * next
Next recipe with the same number of ingredients.
Definition: recipe.h:24
recipe::skill
sstring skill
Skill name used to make this recipe.
Definition: recipe.h:26
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:692
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
artifact
This is one artifact, ie one special item.
Definition: artifact.h:14
MSG_TYPE_SKILL_SUCCESS
#define MSG_TYPE_SKILL_SUCCESS
Successfully used skill.
Definition: newclient.h:593
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
object_sub_weight
void object_sub_weight(object *op, signed long weight)
Recursively (outwards) subtracts a number from the weight of an object (and what is carried by it's e...
Definition: object.cpp:1792
recipe_chance
static float recipe_chance(const recipe *rp, const object *skill, const object *cauldron)
Compute the success probability of a recipe.
Definition: alchemy.cpp:121
adjust_product
static void adjust_product(object *item, int lvl, int yield)
We adjust the nrof of the final product, based on the item's default parameters, and the relevant cas...
Definition: alchemy.cpp:411
generate_artifact
void generate_artifact(object *op, int difficulty)
Decides randomly which artifact the object should be turned into.
Definition: artifact.cpp:177
object::material
uint16_t material
What materials this object consist of.
Definition: object.h:357
object::move_block
MoveType move_block
What movement types this blocks.
Definition: object.h:437
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:654
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
object.h
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
recipe::cauldron
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
Definition: recipe.h:27
recipe::title
sstring title
Distinguishing name of product.
Definition: recipe.h:11