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  return item;
394 }
395 
406 static void adjust_product(object *item, int adjust, int yield) {
407  int nrof = 1;
408 
409  if (!yield)
410  yield = 1;
411  if (adjust <= 0)
412  adjust = 1; /* lets avoid div by zero! */
413  if (item->nrof) {
414  nrof = (1.0-1.0/(adjust/10.0+1.0))*(rndm(0, yield-1)+rndm(0, yield-1)+rndm(0, yield-1))+1;
415  if (nrof > yield)
416  nrof = yield;
417  item->nrof = nrof;
418  }
419 }
420 
431 static object *make_item_from_recipe(object *cauldron, const recipe *rp) {
432  const artifact *art = NULL;
433  object *item = NULL;
434  size_t rp_arch_index;
435 
436  if (rp == NULL)
437  return (object *)NULL;
438 
439  /* Find the appropriate object to transform...*/
440  if ((item = find_transmution_ob(cauldron->inv, rp, &rp_arch_index, 1)) == NULL) {
441  LOG(llevDebug, "make_alchemy_item(): failed to create alchemical object.\n");
442  return (object *)NULL;
443  }
444 
445  /* If item is already in container, we need to remove its weight, since it can change later on. */
446  if (item->env != NULL)
447  object_sub_weight(cauldron, item->weight*NROF(item));
448 
449  /* Find the appropriate artifact template...*/
450  if (strcmp(rp->title, "NONE")) {
451  int item_power_delta = 0;
452  if ((art = locate_recipe_artifact(rp, rp_arch_index)) == NULL) {
453  LOG(llevError, "make_alchemy_item(): failed to locate recipe artifact.\n");
454  LOG(llevDebug, " --requested recipe: %s of %s.\n", rp->arch_name[0], rp->title);
455  return (object *)NULL;
456  }
457  transmute_materialname(item, art->item);
458  if (rp->transmute) {
459  /* If we change an item, then we must keep the item power.
460  * Else this allows for instance using a helmet+5 (item power 5) for a
461  * helmet of Xebinon, giving a helmet of Xebinon+5 with item power 0. */
462  item_power_delta = item->item_power - item->arch->clone.item_power;
463  }
464  give_artifact_abilities(item, art->item);
465  item->item_power += item_power_delta;
466  if (is_identified(item)) {
467  /* artifacts are generated unidentified, so if the item is identified we must give it its real properties. */
469  }
470  }
471  if (item->env != NULL)
472  object_add_weight(cauldron, item->weight*NROF(item));
473 
474  if (QUERY_FLAG(cauldron, FLAG_CURSED))
475  SET_FLAG(item, FLAG_CURSED);
476  if (QUERY_FLAG(cauldron, FLAG_DAMNED))
477  SET_FLAG(item, FLAG_DAMNED);
478 
479  return item;
480 }
481 
495 static object *find_transmution_ob(object *first_ingred, const recipe *rp, size_t *rp_arch_index, int create_item) {
496  object *item = NULL;
497 
498  *rp_arch_index = 0;
499 
500  if (rp->transmute) { /* look for matching ingredient/prod archs */
501  item = first_ingred;
503  size_t i;
504 
505  for (i = 0; i < rp->arch_names; i++) {
506  /* Items with titles are skipped to avoid shadow alchemy ability stacking. */
507  if (strcmp(item->arch->name, rp->arch_name[i]) == 0 && !(item->title)) {
508  *rp_arch_index = i;
509  break;
510  }
511  }
512  if (i < rp->arch_names)
513  break;
515  }
516 
517  /* failed, create a fresh object. Note no nrof>1 because that would
518  * allow players to create massive amounts of artifacts easily */
519  if (create_item && (!item || item->nrof > 1)) {
520  *rp_arch_index = RANDOM()%rp->arch_names;
521  item = create_archetype(rp->arch_name[*rp_arch_index]);
522  }
523 
524 #ifdef ALCHEMY_DEBUG
525  LOG(llevDebug, "recipe calls for%stransmution.\n", rp->transmute ? " " : " no ");
526  if (item != NULL) {
527  LOG(llevDebug, " find_transmutable_ob(): returns arch %s(sp:%d)\n", item->arch->name, item->stats.sp);
528  }
529 #endif
530 
531  return item;
532 }
533 
550 static void alchemy_failure_effect(object *op, object *cauldron, const recipe *rp, int danger) {
551  int level = 0;
552 
553  if (!op || !cauldron)
554  return;
555 
557  if (rp && rp->failure_arch) {
558  object *failure = create_archetype(rp->failure_arch);
559  if (!failure) {
560  LOG(llevError, "invalid failure_arch %s for recipe %s\n", rp->failure_arch, rp->title);
561  return;
562  }
563 
564  remove_contents(cauldron->inv, NULL);
565 
566  object_insert_in_ob(failure, cauldron);
567  if (rp->failure_message) {
569  }
570  return;
571  }
572 
573  if (danger > 1)
574  level = random_roll(1, danger, op, PREFER_LOW);
575 
576 #ifdef ALCHEMY_DEBUG
577  LOG(llevDebug, "Alchemy_failure_effect(): using level=%d\n", level);
578 #endif
579 
580  /* possible outcomes based on level */
581  if (level < 25) { /* INGREDIENTS USED/SLAGGED */
582  object *item = NULL;
583 
584  if (rndm(0, 2)) { /* slag created */
585  object *tmp;
586  int weight = 0;
587  uint16_t material = M_STONE;
588 
589  FOR_INV_PREPARE(cauldron, inv) { /* slag has coadded ingredient properties */
590  weight += inv->weight;
591  if (!(material&inv->material))
592  material |= inv->material;
593  } FOR_INV_FINISH();
594  tmp = create_archetype("rock");
595  tmp->weight = weight;
596  tmp->value = 0;
597  tmp->material = material;
598  tmp->materialname = add_string("stone");
599  free_string(tmp->name);
600  tmp->name = add_string("slag");
601  if (tmp->name_pl)
602  free_string(tmp->name_pl);
603  tmp->name_pl = add_string("slags");
604  item = object_insert_in_ob(tmp, cauldron);
606  CLEAR_FLAG(tmp, FLAG_NO_PICK);
607  tmp->move_block = 0;
608  }
609  remove_contents(cauldron->inv, item);
611  "The %s %s.",
612  cauldron->name, cauldron_sound());
613  return;
614  } else if (level < 40) { /* MAKE TAINTED ITEM */
615  object *tmp = NULL;
616 
617  /*
618  * Note by Nicolas Weeger 2010-09-26
619  * This is an incorrect part.
620  * Calling again attempt_recipe in case of failure will apply again the artifact
621  * combination to the item.
622  * This leads to items with eg 100% resist, or more.
623  * So use the actual item in the cauldron, don't retry the recipe.
624  * This should fix bug #2020224: buggy(?) crafting yields.
625  *
626  if (!rp)
627  if ((rp = get_random_recipe((recipelist *)NULL)) == NULL)
628  return;
629  */
630 
631  if ((tmp = cauldron->inv)) /*attempt_recipe(op, cauldron, 1, rp, -1, 0)))*/ {
632  if (!QUERY_FLAG(tmp, FLAG_CURSED)) { /* curse it */
633  SET_FLAG(tmp, FLAG_CURSED);
636  }
637 
638  /* the apply code for potions already deals with cursed
639  * potions, so any code here is basically ignored.
640  */
641  if (tmp->type == FOOD) {
642  tmp->stats.hp = random_roll(0, 149, op, PREFER_LOW);
643  }
644  tmp->value = 0; /* unsaleable item */
645 
646  /* change stats downward */
647  do {
648  change_attr_value(&tmp->stats, rndm(0, 6), -1*(rndm(1, 3)));
649  } while (rndm(0, 2));
650  }
651  return;
652  }
653 #if 0
654  /*
655  Note: this does not work as expected...
656  At this point there is only one item in the cauldron, and get_formulalist(0) will return
657  the first formula list for recipes with 1 ingredient.
658  So disable this, and just use the next case.
659  */
660 
661  if (level == 40) { /* MAKE RANDOM RECIPE */
662  recipelist *fl;
663  int numb = numb_ob_inside(cauldron);
664 
665  fl = get_formulalist(numb-1); /* take a lower recipe list */
666  if (fl && (rp = get_random_recipe(fl)))
667  /* even though random, don't grant user any EXP for it */
668  (void)attempt_recipe(op, cauldron, 1, rp, -1, 0);
669  else
670  alchemy_failure_effect(op, cauldron, rp, level-1);
671  return;
672 
673  } else
674 #endif
675  if (level < 45) { /* INFURIATE NPC's */
676  /* this is kind of kludgy I know...*/
677  object_set_enemy(cauldron, op);
678  monster_npc_call_help(cauldron);
679  object_set_enemy(cauldron, NULL);
680 
681  alchemy_failure_effect(op, cauldron, rp, level-5);
682  return;
683  } else if (level < 50) { /* MINOR EXPLOSION/FIREBALL */
684  object *tmp;
685 
686  remove_contents(cauldron->inv, NULL);
687  switch (rndm(0, 2)) {
688  case 0:
689  tmp = create_archetype("bomb");
690  tmp->stats.dam = random_roll(1, level, op, PREFER_LOW);
691  tmp->stats.hp = random_roll(1, level, op, PREFER_LOW);
693  "The %s creates a bomb!",
694  cauldron->name);
695  break;
696 
697  default:
698  tmp = create_archetype("fireball");
699  tmp->stats.dam = random_roll(1, level, op, PREFER_LOW)/5+1;
700  tmp->stats.hp = random_roll(1, level, op, PREFER_LOW)/10+2;
702  "The %s erupts in flame!",
703  cauldron->name);
704  break;
705  }
706  object_insert_in_map_at(tmp, op->map, NULL, 0, cauldron->x, cauldron->y);
707  return;
708  } else if (level < 60) { /* CREATE MONSTER */
710  "The %s %s.", cauldron->name, cauldron_sound());
711  remove_contents(cauldron->inv, NULL);
712  return;
713  } else if (level < 80) { /* MAJOR FIRE */
714  object *fb = create_archetype(SP_MED_FIREBALL);
715 
716  remove_contents(cauldron->inv, NULL);
717  fire_arch_from_position(cauldron, cauldron, cauldron->x, cauldron->y, 0, fb);
720  "The %s erupts in flame!",
721  cauldron->name);
722  return;
723  } else if (level < 100) { /* WHAMMY the CAULDRON */
724  if (!QUERY_FLAG(cauldron, FLAG_CURSED)) {
725  SET_FLAG(cauldron, FLAG_CURSED);
726  CLEAR_FLAG(cauldron, FLAG_KNOWN_CURSED);
727  CLEAR_FLAG(cauldron, FLAG_IDENTIFIED);
728  } else
729  cauldron->magic--;
730  cauldron->magic -= random_roll(0, 4, op, PREFER_LOW);
731  if (rndm(0, 1)) {
732  remove_contents(cauldron->inv, NULL);
734  "Your %s turns darker then makes a gulping sound!",
735  cauldron->name);
736  } else
738  "Your %s becomes darker.",
739  cauldron->name);
740  return;
741  } else if (level < 110) { /* SUMMON EVIL MONSTERS */
742  object *tmp = get_random_mon(level/5);
743 
744  remove_contents(cauldron->inv, NULL);
745  if (!tmp)
746  alchemy_failure_effect(op, cauldron, rp, level);
747  else if (summon_hostile_monsters(cauldron, random_roll(1, 10, op, PREFER_LOW), tmp->arch->name))
749  "The %s %s and then pours forth monsters!",
750  cauldron->name, cauldron_sound());
751  return;
752  } else if (level < 150) { /* COMBO EFFECT */
753  int roll = rndm(1, 3);
754  while (roll) {
755  alchemy_failure_effect(op, cauldron, rp, level-39);
756  roll--;
757  }
758  return;
759  } else if (level == 151) { /* CREATE RANDOM ARTIFACT */
760  object *tmp;
761 
762  /* this is meant to be better than prior possiblity,
763  * in this one, we allow *any *valid alchemy artifact
764  * to be made (rather than only those on the given
765  * formulalist) */
766  if (!rp)
767  rp = get_random_recipe((recipelist *)NULL);
768  if (rp && (tmp = create_archetype(rp->arch_name[RANDOM()%rp->arch_names]))) {
769  generate_artifact(tmp, random_roll(1, op->level/2+1, op, PREFER_HIGH)+1);
770  if ((tmp = object_insert_in_ob(tmp, cauldron))) {
771  remove_contents(cauldron->inv, tmp);
774  "The %s %s.",
775  cauldron->name, cauldron_sound());
776  }
777  }
778  return;
779  } else { /* MANA STORM - watch out!! */
780  object *tmp = create_archetype(LOOSE_MANA);
782  "You unwisely release potent forces!");
783  remove_contents(cauldron->inv, NULL);
784  cast_magic_storm(op, tmp, level);
785  return;
786  }
787 }
788 
798 static void remove_contents(object *first_ob, object *save_item) {
799  object *tmp;
800 
801  tmp = first_ob;
803  if (tmp != save_item) {
804  if (tmp->inv)
805  remove_contents(tmp->inv, NULL);
806  object_remove(tmp);
808  }
810 }
811 
830 static int calc_alch_danger(object *caster, object *cauldron, const recipe *rp) {
831  int danger = 0;
832 
833  /* Get the recipe's skill if it has one. Otherwise, use your overall level.
834  * Note that this isn't inherently your chosen skill, so we go find it.
835  */
836  object *skop = rp && rp->skill ? find_skill_by_name(caster, rp->skill) : NULL;
837  danger -= skop ? skop->level : caster->level;
838 
839  /* better cauldrons reduce risk */
840  danger -= cauldron->magic;
841 
842  /* Higher Int, lower the risk */
843  danger -= 3*(caster->stats.Int-15);
844 
845  /* Ingredients. */
846  FOR_INV_PREPARE(cauldron, item) {
847  /* Nicolas Weeger: no reason why this is the case.
848  danger += item->weight / 100;
849  */
850  danger++;
851  if (QUERY_FLAG(item, FLAG_CURSED) || QUERY_FLAG(item, FLAG_DAMNED))
852  danger += 5;
853  } FOR_INV_FINISH();
854 
855  if (rp == NULL)
856  danger += 110;
857  else
858  danger += rp->diff*3;
859 
860  /* Using a bad device is *majorly *stupid */
861  if (QUERY_FLAG(cauldron, FLAG_CURSED))
862  danger += 80;
863  if (QUERY_FLAG(cauldron, FLAG_DAMNED))
864  danger += 200;
865 
866 #ifdef ALCHEMY_DEBUG
867  LOG(llevDebug, "calc_alch_danger() returned danger=%d\n", danger);
868 #endif
869 
870  return danger;
871 }
872 
890 static int is_defined_recipe(const recipe *rp, const object *cauldron) {
891  uint32_t batches_in_cauldron;
892  const linked_char *ingredient;
893  int number;
894 
895  /* check for matching number of ingredients */
896  number = 0;
897  for (ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next)
898  number++;
899  FOR_INV_PREPARE(cauldron, ob) {
900 #ifdef ALCHEMY_DEBUG
901  LOG(llevDebug, "cauldron %s, item %s, number %d->%d\n", cauldron->name, ob->name, number, number - 1);
902 #endif
903  number--;
904  } FOR_INV_FINISH();
905  if (number != 0)
906  return 0;
907 
908  /* check for matching ingredients */
909  batches_in_cauldron = 0;
910  for (ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next) {
911  uint32_t nrof;
912  const char *name;
913  int ok;
914 
915  /* determine and remove nrof from name */
916  name = ingredient->name;
917  nrof = 0;
918  while (isdigit(*name)) {
919  nrof = 10*nrof+(*name-'0');
920  name++;
921  }
922  if (nrof == 0)
923  nrof = 1;
924  while (*name == ' ')
925  name++;
926 
927  /* find the current ingredient in the cauldron */
928  ok = 0;
929  FOR_INV_PREPARE(cauldron, ob) {
930  char name_ob[MAX_BUF];
931  const char *name2;
932 
933  if (ob->title == NULL)
934  name2 = ob->name;
935  else {
936  snprintf(name_ob, sizeof(name_ob), "%s %s", ob->name, ob->title);
937  name2 = name_ob;
938  }
939 
940  if (strcmp(name2, name) == 0) {
941  if (ob->nrof%nrof == 0) {
942  uint32_t batches;
943 
944  // Make sure we handle non-stacking ingredients such as icecubes.
945  batches = (ob->nrof ? ob->nrof : 1)/nrof;
946 #ifdef ALCHEMY_DEBUG
947  LOG(llevDebug, "batches of ingred %s: %d; batches prior: %d\n", name, batches, batches_in_cauldron);
948 #endif
949  if (batches_in_cauldron == 0) {
950  batches_in_cauldron = batches;
951  ok = 1;
952  } else if (batches_in_cauldron == batches)
953  ok = 1;
954  }
955  break;
956  }
957  } FOR_INV_FINISH();
958  if (!ok)
959  return(0);
960  }
961 
962  return(1);
963 }
964 
979 static const recipe *find_recipe(const recipelist *fl, int formula, object *cauldron) {
980  const recipe *rp;
981  const recipe *result; /* winning recipe, or NULL if no recipe found */
982  int recipes_matching; /* total number of matching recipes so far */
983  int transmute_found; /* records whether a transmuting recipe was found so far */
984  size_t rp_arch_index;
985 
986 #ifdef EXTREME_ALCHEMY_DEBUG
987  LOG(llevDebug, "looking for formula %d:\n", formula);
988 #endif
989  result = NULL;
990  recipes_matching = 0;
991  transmute_found = 0;
992  for (rp = fl->items; rp != NULL; rp = rp->next) {
993  /* check if recipe matches at all */
994  if (rp->cauldron != cauldron->arch->name || formula%rp->index != 0) {
995 #ifdef EXTREME_ALCHEMY_DEBUG
996  LOG(llevDebug, " formula %s of %s (%d) does not match\n", rp->arch_name[0], rp->title, rp->index);
997 #endif
998  continue;
999  }
1000 
1001  object *ingredients = cauldron->inv;
1002  if (rp->transmute && find_transmution_ob(ingredients, rp, &rp_arch_index, 0) != NULL) {
1003 #ifdef EXTREME_ALCHEMY_DEBUG
1004  LOG(llevDebug, " formula %s of %s (%d) is a matching transmuting formula\n", rp->arch_name[rp_arch_index], rp->title, rp->index);
1005 #endif
1006  /* transmution recipe with matching base ingredient */
1007  if (!transmute_found) {
1008  transmute_found = 1;
1009  recipes_matching = 0;
1010  }
1011  } else if (transmute_found) {
1012 #ifdef EXTREME_ALCHEMY_DEBUG
1013  LOG(llevDebug, " formula %s of %s (%d) matches but is not a matching transmuting formula\n", rp->arch_name[0], rp->title, rp->index);
1014 #endif
1015  /* "normal" recipe found after previous transmution recipe => ignore this recipe */
1016  continue;
1017  }
1018 #ifdef EXTREME_ALCHEMY_DEBUG
1019  else {
1020  LOG(llevDebug, " formula %s of %s (%d) matches\n", rp->arch_name[0], rp->title, rp->index);
1021  }
1022 #endif
1023 
1024  if (rndm(0, recipes_matching) == 0)
1025  result = rp;
1026 
1027  recipes_matching++;
1028  }
1029 
1030  if (result == NULL) {
1031 #ifdef ALCHEMY_DEBUG
1032  LOG(llevDebug, "couldn't find formula for ingredients.\n");
1033 #endif
1034  return NULL;
1035  }
1036 
1037 #ifdef ALCHEMY_DEBUG
1038  if (strcmp(result->title, "NONE") != 0)
1039  LOG(llevDebug, "got formula: %s of %s (nbatches:%d)\n", result->arch_name[0], result->title, formula/result->index);
1040  else
1041  LOG(llevDebug, "got formula: %s (nbatches:%d)\n", result->arch_name[0], formula/result->index);
1042 #endif
1043  return result;
1044 }
1045 
1057 int use_alchemy(object *op) {
1058  object *unpaid_cauldron = NULL;
1059  object *unpaid_item = NULL;
1060  int did_alchemy = 0;
1061  char name[MAX_BUF];
1062 
1063  if (QUERY_FLAG(op, FLAG_WIZ))
1064  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, "Note: alchemy in wizard-mode.\n");
1065 
1066  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
1067  if (QUERY_FLAG(tmp, FLAG_IS_CAULDRON)) {
1068  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1069  unpaid_cauldron = tmp;
1070  continue;
1071  }
1072  unpaid_item = object_find_by_flag(tmp, FLAG_UNPAID);
1073  if (unpaid_item != NULL)
1074  continue;
1075 
1076  attempt_do_alchemy(op, tmp);
1077  if (QUERY_FLAG(tmp, FLAG_APPLIED))
1078  esrv_send_inventory(op, tmp);
1079  did_alchemy = 1;
1080  }
1081  } FOR_MAP_FINISH();
1082  if (unpaid_cauldron) {
1083  query_base_name(unpaid_cauldron, 0, name, MAX_BUF);
1085  "You must pay for your %s first!",
1086  name);
1087  } else if (unpaid_item) {
1088  query_base_name(unpaid_item, 0, name, MAX_BUF);
1090  "You must pay for your %s first!",
1091  name);
1092  }
1093 
1094  return did_alchemy;
1095 }
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
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:830
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
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:224
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:410
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
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
price_base
uint64_t price_base(const object *obj)
Determine the base (intrinsic) value of an item.
Definition: shop.cpp:75
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:915
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:979
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:558
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
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
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:550
M_STONE
#define M_STONE
Stone.
Definition: material.h:20
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
recipe::exp
int exp
How much exp to give for this formulae.
Definition: recipe.h:17
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
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:2857
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:407
MAX
#define MAX(x, y)
Definition: compat.h:24
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
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
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:1560
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:557
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:495
linked_char::name
const char * name
Definition: global.h:99
recipelist
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
POTION
@ POTION
Definition: object.h:116
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:320
MSG_TYPE_COMMAND_DM
#define MSG_TYPE_COMMAND_DM
DM related commands.
Definition: newclient.h:538
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:748
use_alchemy
int use_alchemy(object *op)
Handle use_skill for alchemy-like items.
Definition: alchemy.cpp:1057
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:1353
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
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
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:4206
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:671
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:254
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Don't have the skill.
Definition: newclient.h:590
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:798
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:744
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:2100
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:211
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:280
RANDOM
#define RANDOM()
Definition: define.h:638
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:431
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:717
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:2833
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:4158
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
MSG_TYPE_SKILL_ERROR
#define MSG_TYPE_SKILL_ERROR
Doing something wrong.
Definition: newclient.h:591
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
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:593
get_random_recipe
recipe * get_random_recipe(recipelist *rpl)
Gets a random recipe from a list, based on chance.
Definition: recipe.cpp:787
locate_recipe_artifact
const artifact * locate_recipe_artifact(const recipe *rp, size_t idx)
Finds an artifact for a recipe.
Definition: recipe.cpp:730
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:2012
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:890
strtoint
int strtoint(const char *buf)
Convert buf into an integer equal to the coadded sum of the (lowercase) character.
Definition: recipe.cpp:709
recipe::diff
int diff
Alchemical dfficulty level.
Definition: recipe.h:16
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
object_give_identified_properties
void object_give_identified_properties(object *op)
Ensure op has all its "identified" properties set.
Definition: item.cpp:1361
level
int level
Definition: readable.cpp:1563
recipe::keycode
sstring keycode
Optional keycode needed to use the recipe.
Definition: recipe.h:25
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:1833
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
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
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:689
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:592
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:338
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:1807
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:406
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:316
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:664
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
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
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