ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/alchemy.C
(Generate patch)

Comparing deliantra/server/server/alchemy.C (file contents):
Revision 1.6 by elmex, Sun Sep 3 14:33:45 2006 UTC vs.
Revision 1.18 by pippijn, Mon Jan 15 21:06:19 2007 UTC

1/* 1/*
2 * static char *rcsid_alchemy_c =
3 * "$Id: alchemy.C,v 1.6 2006/09/03 14:33:45 elmex Exp $";
4 */
5
6/*
7 CrossFire, A Multiplayer game for X-windows 2 * CrossFire, A Multiplayer game for X-windows
8 3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen 6 * Copyright (C) 1992 Frank Tore Johansen
11 7 *
12 This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version. 11 * (at your option) any later version.
16 12 *
17 This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details. 16 * GNU General Public License for more details.
21 17 *
22 You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 21 *
26 The authors can be reached via e-mail at crossfire-devel@real-time.com 22 * The authors can be reached via e-mail at <crossfire@schmorp.de>
27*/ 23 */
28 24
29/* March 96 - Laid down original code. -b.t. thomas@astro.psu.edu */ 25/* March 96 - Laid down original code. -b.t. thomas@astro.psu.edu */
30 26
31#include <global.h> 27#include <global.h>
32#include <object.h> 28#include <object.h>
33#ifndef __CEXTRACT__
34#include <sproto.h> 29#include <sproto.h>
35#endif
36#include <skills.h> 30#include <skills.h>
37#include <spells.h> 31#include <spells.h>
38 32
39/** define this for some helpful debuging information */ 33/** define this for some helpful debuging information */
40#if 0 34#if 0
41#define ALCHEMY_DEBUG 35# define ALCHEMY_DEBUG
42#endif 36#endif
43 37
44/** define this for loads of (marginal) debuging information */ 38/** define this for loads of (marginal) debuging information */
45#if 0 39#if 0
46#define EXTREME_ALCHEMY_DEBUG 40# define EXTREME_ALCHEMY_DEBUG
47#endif 41#endif
48 42
49/** Random cauldrons effects */ 43/** Random cauldrons effects */
50static const char* const cauldron_effect [] = { 44static const char *const cauldron_effect[] = {
51 "vibrates briefly", 45 "vibrates briefly",
52 "produces a cloud of steam", 46 "produces a cloud of steam",
53 "emits bright flames", 47 "emits bright flames",
54 "pours forth heavy black smoke", 48 "pours forth heavy black smoke",
55 "emits sparks", 49 "emits sparks",
56 "shoots out small flames", 50 "shoots out small flames",
57 "whines painfully", 51 "whines painfully",
58 "hiccups loudly", 52 "hiccups loudly",
59 "wheezes", 53 "wheezes",
60 "burps", 54 "burps",
61 "shakes", 55 "shakes",
62 "rattles", 56 "rattles",
63 "makes chugging sounds", 57 "makes chugging sounds",
64 "smokes heavily for a while" 58 "smokes heavily for a while"
65}; 59};
66 60
67 61
68static int is_defined_recipe(const recipe *rp, const object *cauldron, object *caster); 62static int is_defined_recipe (const recipe *rp, const object *cauldron, object *caster);
69static recipe *find_recipe(recipelist *fl, int formula, object *ingredients); 63static recipe *find_recipe (recipelist * fl, int formula, object *ingredients);
70 64
71 65
72/** Returns a random selection from cauldron_effect[] */ 66/** Returns a random selection from cauldron_effect[] */
73static const char *cauldron_sound(void) { 67static const char *
68cauldron_sound (void)
69{
74 int size=sizeof(cauldron_effect)/sizeof(char *); 70 int size = sizeof (cauldron_effect) / sizeof (char *);
75 71
76 return cauldron_effect[rndm(0, size-1)]; 72 return cauldron_effect[rndm (0, size - 1)];
77} 73}
78 74
79/** 75/**
80 * Main part of the ALCHEMY code. From this we call fctns 76 * Main part of the ALCHEMY code. From this we call fctns
81 * that take a look at the contents of the 'cauldron' and, using these ingredients, 77 * that take a look at the contents of the 'cauldron' and, using these ingredients,
97 * There is no good reason (in my mind) why alchemical processes have to be 93 * There is no good reason (in my mind) why alchemical processes have to be
98 * unique -- such a 'feature' is one reason why players might want to experiment 94 * unique -- such a 'feature' is one reason why players might want to experiment
99 * around. :) 95 * around. :)
100 * -b.t. 96 * -b.t.
101 */ 97 */
102 98
99void
103void attempt_do_alchemy(object *caster, object *cauldron) { 100attempt_do_alchemy (object *caster, object *cauldron)
101{
104 recipelist *fl; 102 recipelist *fl;
105 recipe *rp=NULL; 103 recipe *rp = NULL;
106 float success_chance; 104 float success_chance;
107 int numb, ability=1; 105 int numb, ability = 1;
108 int formula=0; 106 int formula = 0;
109 float ave_chance; 107 float ave_chance;
110 object *item, *skop; 108 object *item, *skop;
111 109
112 if (caster->type!=PLAYER) 110 if (caster->type != PLAYER)
113 return; /* only players for now */ 111 return; /* only players for now */
114 112
115 if (get_map_flags(caster->map, NULL, caster->x, caster->y, NULL, NULL) & P_SAFE) 113 if (get_map_flags (caster->map, NULL, caster->x, caster->y, NULL, NULL) & P_SAFE)
116 { 114 {
117 new_draw_info (NDI_UNIQUE, 0, caster,
118 "This is sacred ground, the gods prevent you from using this device." 115 new_draw_info (NDI_UNIQUE, 0, caster, "This is sacred ground, the gods prevent you from using this device.");
119 );
120 return; 116 return;
121 } 117 }
122 118
123 /* if no ingredients, no formula! lets forget it */ 119 /* if no ingredients, no formula! lets forget it */
124 if (!(formula=content_recipe_value(cauldron))) return; 120 if (!(formula = content_recipe_value (cauldron)))
125 121 return;
122
126 numb=numb_ob_inside(cauldron); 123 numb = numb_ob_inside (cauldron);
127 if ((fl=get_formulalist(numb))) { 124 if ((fl = get_formulalist (numb)))
125 {
128 if (QUERY_FLAG(caster, FLAG_WIZ)) { 126 if (QUERY_FLAG (caster, FLAG_WIZ))
127 {
129 rp = find_recipe(fl, formula, cauldron->inv); 128 rp = find_recipe (fl, formula, cauldron->inv);
130 if (rp != NULL) { 129 if (rp != NULL)
130 {
131#ifdef ALCHEMY_DEBUG 131#ifdef ALCHEMY_DEBUG
132 if(strcmp(rp->title, "NONE")) 132 if (strcmp (rp->title, "NONE"))
133 LOG(llevDebug, "WIZ got formula: %s of %s\n", 133 LOG (llevDebug, "WIZ got formula: %s of %s\n", rp->arch_name[0], rp->title);
134 rp->arch_name[0], rp->title);
135 else 134 else
136 LOG(llevDebug, "WIZ got formula: %s (nbatches:%d)\n", 135 LOG (llevDebug, "WIZ got formula: %s (nbatches:%d)\n", rp->arch_name[0], formula / rp->index);
137 rp->arch_name[0], formula/rp->index);
138#endif 136#endif
139 attempt_recipe(caster, cauldron, ability, rp, formula/rp->index); 137 attempt_recipe (caster, cauldron, ability, rp, formula / rp->index);
138 }
139 else
140 } else LOG(llevDebug, "WIZ couldn't find formula for ingredients.\n"); 140 LOG (llevDebug, "WIZ couldn't find formula for ingredients.\n");
141 return; 141 return;
142 } /* End of WIZ alchemy */ 142 } /* End of WIZ alchemy */
143 143
144 /* find the recipe */ 144 /* find the recipe */
145 rp = find_recipe(fl, formula, cauldron->inv); 145 rp = find_recipe (fl, formula, cauldron->inv);
146 if (rp) { 146 if (rp)
147 {
147 uint64 value_ingredients; 148 uint64 value_ingredients;
148 uint64 value_item; 149 uint64 value_item;
149 object *tmp; 150 object *tmp;
150 int attempt_shadow_alchemy; 151 int attempt_shadow_alchemy;
151 152
152 ave_chance = fl->total_chance/(float)fl->number; 153 ave_chance = fl->total_chance / (float) fl->number;
153 /* the caster gets an increase in ability based on thier skill lvl */ 154 /* the caster gets an increase in ability based on thier skill lvl */
154 if (rp->skill) { 155 if (rp->skill)
156 {
155 skop = find_skill_by_name(caster, rp->skill); 157 skop = find_skill_by_name (caster, rp->skill);
156 if (!skop) { 158 if (!skop)
157 new_draw_info(NDI_UNIQUE, 0, caster, "You do not have the proper skill for this recipe"); 159 new_draw_info (NDI_UNIQUE, 0, caster, "You do not have the proper skill for this recipe");
158 } else { 160 else
159 ability+= (int) (skop->level*((4.0 + cauldron->magic)/4.0)); 161 ability += (int) (skop->level * ((4.0 + cauldron->magic) / 4.0));
162 }
163 else
164 {
165 LOG (llevDebug, "Recipe %s has NULL skill!\n", &rp->title);
166 return;
167 }
168
169 if (!rp->cauldron)
170 {
171 LOG (llevDebug, "Recipe %s has NULL cauldron!\n", &rp->title);
172 return;
173 }
174
175 /* determine value of ingredients */
176 value_ingredients = 0;
177 for (tmp = cauldron->inv; tmp != NULL; tmp = tmp->below)
178 value_ingredients += query_cost (tmp, NULL, F_TRUE);
179
180 attempt_shadow_alchemy = !is_defined_recipe (rp, cauldron, caster);
181
182 /* create the object **FIRST**, then decide whether to keep it. */
183 if ((item = attempt_recipe (caster, cauldron, ability, rp, formula / rp->index)) != NULL)
184 {
185 /* compute base chance of recipe success */
186 success_chance = ((float) ability / (float) (rp->diff * (item->level + 2)));
187 if (ave_chance == 0)
188 ave_chance = 1;
189
190#ifdef ALCHEMY_DEBUG
191 LOG (llevDebug, "percent success chance = %f ab%d / diff%d*lev%d\n", success_chance, ability, rp->diff, item->level);
192#endif
193
194 value_item = query_cost (item, NULL, F_TRUE | F_IDENTIFIED | F_NOT_CURSED);
195 if (attempt_shadow_alchemy && value_item > value_ingredients)
196 {
197#ifdef ALCHEMY_DEBUG
198 LOG (llevDebug,
199 "Forcing failure for shadow alchemy recipe because price of ingredients (%llu) is less than price of result (%llu).\n",
200 value_ingredients, value_item);
201#endif
160 } 202 }
203 /* roll the dice */
204 else if ((float) (random_roll (0, 101, caster, PREFER_LOW)) <= 100.0 * success_chance)
161 } else { 205 {
162 LOG(llevDebug, "Recipe %s has NULL skill!\n", &rp->title); 206 change_exp (caster, rp->exp, rp->skill, SK_EXP_NONE);
207
208 // let alchemy consume some time, so that exploits are less easy
209 caster->speed_left -= 1.0;
210
163 return; 211 return;
164 }
165
166 if (rp->cauldron) {
167 LOG(llevDebug, "Recipe %s has NULL cauldron!\n", &rp->title);
168 return;
169 }
170
171 /* determine value of ingredients */
172 value_ingredients = 0;
173 for(tmp = cauldron->inv; tmp != NULL; tmp = tmp->below)
174 value_ingredients += query_cost(tmp, NULL, F_TRUE);
175
176 attempt_shadow_alchemy = !is_defined_recipe(rp, cauldron, caster);
177
178 /* create the object **FIRST**, then decide whether to keep it. */
179 if ((item=attempt_recipe(caster, cauldron, ability, rp, formula/rp->index)) != NULL) {
180 /* compute base chance of recipe success */
181 success_chance = ((float)ability /
182 (float)(rp->diff * (item->level+2)));
183 if (ave_chance == 0)
184 ave_chance = 1;
185
186#ifdef ALCHEMY_DEBUG
187 LOG(llevDebug, "percent success chance = %f ab%d / diff%d*lev%d\n",
188 success_chance, ability, rp->diff, item->level);
189#endif
190
191 value_item = query_cost(item, NULL, F_TRUE|F_IDENTIFIED|F_NOT_CURSED);
192 if(attempt_shadow_alchemy && value_item > value_ingredients) {
193#ifdef ALCHEMY_DEBUG
194#ifndef WIN32
195 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);
196#else
197 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);
198#endif
199#endif
200 } 212 }
201 /* roll the dice */
202 else if ((float)(random_roll(0, 101, caster, PREFER_LOW)) <= 100.0 * success_chance) {
203 change_exp(caster, rp->exp, rp->skill, SK_EXP_NONE);
204 return;
205 } 213 }
206 } 214 }
207 }
208 } 215 }
216
209 /* if we get here, we failed!! */ 217 /* if we get here, we failed!! */
210 alchemy_failure_effect(caster, cauldron, rp, 218 alchemy_failure_effect (caster, cauldron, rp, calc_alch_danger (caster, cauldron, rp));
211 calc_alch_danger(caster, cauldron, rp));
212} 219}
213 220
214/** 221/**
215 * Recipe value of the entire contents of a container. 222 * Recipe value of the entire contents of a container.
216 * This appears to just generate a hash value, which I guess for now works 223 * This appears to just generate a hash value, which I guess for now works
217 * ok, but the possibility of duplicate hashes is certainly possible - msw 224 * ok, but the possibility of duplicate hashes is certainly possible - msw
218 */ 225 */
219 226
227int
220int content_recipe_value (object *op) { 228content_recipe_value (object *op)
229{
221 char name[MAX_BUF]; 230 char name[MAX_BUF];
222 object *tmp=op->inv; 231 object *tmp = op->inv;
223 int tval=0, formula=0; 232 int tval = 0, formula = 0;
224 233
225 while(tmp) { 234 while (tmp)
235 {
226 tval=0; 236 tval = 0;
227 strcpy(name, tmp->name); 237 strcpy (name, tmp->name);
228 if (tmp->title) 238 if (tmp->title)
229 sprintf (name, "%s %s", &tmp->name, &tmp->title); 239 sprintf (name, "%s %s", &tmp->name, &tmp->title);
230 tval = (strtoint(name) * (tmp->nrof?tmp->nrof:1)); 240 tval = (strtoint (name) * (tmp->nrof ? tmp->nrof : 1));
231#ifdef ALCHEMY_DEBUG 241#ifdef ALCHEMY_DEBUG
232 LOG(llevDebug,"Got ingredient %d %s(%d)\n", tmp->nrof?tmp->nrof:1, 242 LOG (llevDebug, "Got ingredient %d %s(%d)\n", tmp->nrof ? tmp->nrof : 1, name, tval);
233 name, tval);
234#endif 243#endif
235 formula += tval; 244 formula += tval;
236 tmp=tmp->below; 245 tmp = tmp->below;
237 } 246 }
238#ifdef ALCHEMY_DEBUG 247#ifdef ALCHEMY_DEBUG
239 LOG(llevDebug, " Formula value=%d\n", formula); 248 LOG (llevDebug, " Formula value=%d\n", formula);
240#endif 249#endif
241 return formula; 250 return formula;
242} 251}
243 252
244/** 253/**
245 * Returns total number of items in op 254 * Returns total number of items in op
246 */ 255 */
247 256
257int
248int numb_ob_inside (object *op) { 258numb_ob_inside (object *op)
259{
249 object *tmp=op->inv; 260 object *tmp = op->inv;
250 int number=0,o_number=0; 261 int number = 0, o_number = 0;
251 262
252 while(tmp) { 263 while (tmp)
264 {
265 if (tmp->nrof)
253 if(tmp->nrof) number += tmp->nrof; 266 number += tmp->nrof;
254 else number++; 267 else
255 o_number++; 268 number++;
269 o_number++;
256 tmp=tmp->below; 270 tmp = tmp->below;
257 } 271 }
258#ifdef ALCHEMY_DEBUG 272#ifdef ALCHEMY_DEBUG
259 LOG(llevDebug,"numb_ob_inside(%s): found %d ingredients\n",op->name,o_number); 273 LOG (llevDebug, "numb_ob_inside(%s): found %d ingredients\n", op->name, o_number);
260#endif 274#endif
261 return o_number; 275 return o_number;
262} 276}
263 277
264/** 278/**
265 * Essentially a wrapper for make_item_from_recipe() and 279 * Essentially a wrapper for make_item_from_recipe() and
266 * insert_ob_in_ob. If the caster has some alchemy skill, then they might 280 * insert_ob_in_ob. If the caster has some alchemy skill, then they might
267 * gain some exp from (successfull) fabrication of the product. 281 * gain some exp from (successfull) fabrication of the product.
268 * If nbatches==-1, don't give exp for this creation (random generation/ 282 * If nbatches==-1, don't give exp for this creation (random generation/
269 * failed recipe) 283 * failed recipe)
270 */ 284 */
271 285
286object *
272object * attempt_recipe(object *caster, object *cauldron, int ability, recipe *rp, int nbatches) { 287attempt_recipe (object *caster, object *cauldron, int ability, recipe *rp, int nbatches)
288{
273 289
274 object *item=NULL, *skop; 290 object *item = NULL, *skop;
291
275 /* this should be passed to this fctn, not effiecent cpu use this way */ 292 /* this should be passed to this fctn, not effiecent cpu use this way */
276 int batches=abs(nbatches); 293 int batches = abs (nbatches);
277 294
278 295
279 LOG(llevDebug,"A %s <=> %s\n", &(rp->cauldron), &(cauldron->arch->name));
280 /* is the cauldron the right type? */ 296 /* is the cauldron the right type? */
281 if (strcmp(rp->cauldron, cauldron->arch->name) != 0) { 297 if (strcmp (rp->cauldron, cauldron->arch->name) != 0)
298 {
282 new_draw_info(NDI_UNIQUE, 0, caster, "You are not using the proper" 299 new_draw_info (NDI_UNIQUE, 0, caster, "You are not using the proper" " facilities for this formula.");
283 " facilities for this formula.");
284 return 0; 300 return 0;
285 } 301 }
286 302
287 skop = find_skill_by_name(caster, rp->skill); 303 skop = find_skill_by_name (caster, rp->skill);
288 /* does the caster have the skill? */ 304 /* does the caster have the skill? */
289 if (!skop) 305 if (!skop)
290 return 0; 306 return 0;
291 307
292 /* code required for this recipe, search the caster */ 308 /* code required for this recipe, search the caster */
293 if(rp->keycode) { 309 if (rp->keycode)
310 {
294 object *tmp; 311 object *tmp;
312
295 for(tmp=caster->inv; tmp != NULL; tmp=tmp->below) { 313 for (tmp = caster->inv; tmp; tmp = tmp->below)
296 if(tmp->type==FORCE && tmp->slaying && 314 {
297 !strcmp(rp->keycode, tmp->slaying)) 315 if (tmp->type == FORCE && tmp->slaying && !strcmp (rp->keycode, tmp->slaying))
298 break; 316 break;
299 } 317 }
300 if(tmp==NULL) { /* failure--no code found */ 318
301 new_draw_info(NDI_UNIQUE, 0, caster, "You know the ingredients," 319 if (!tmp)
302 " but not the technique. Go learn how to do this recipe."); 320 { /* failure--no code found */
321 new_draw_info (NDI_UNIQUE, 0, caster, "You know the ingredients," " but not the technique. Go learn how to do this recipe.");
303 return 0; 322 return 0;
304 } 323 }
305 } 324 }
306 325
307#ifdef EXTREME_ALCHEMY_DEBUG 326#ifdef EXTREME_ALCHEMY_DEBUG
308 LOG(llevDebug,"attempt_recipe(): got %d nbatches\n",nbatches); 327 LOG (llevDebug, "attempt_recipe(): got %d nbatches\n", nbatches);
309 LOG(llevDebug,"attempt_recipe(): using recipe %s\n", 328 LOG (llevDebug, "attempt_recipe(): using recipe %s\n", rp->title ? rp->title : "unknown");
310 rp->title?rp->title:"unknown");
311#endif 329#endif
312 330
313 if((item=make_item_from_recipe(cauldron, rp))!=NULL) { 331 if ((item = make_item_from_recipe (cauldron, rp)) != NULL)
332 {
314 remove_contents(cauldron->inv, item); 333 remove_contents (cauldron->inv, item);
315 /* Recalc carrying of the cauldron, in case recipe did not conserve mass */ 334 /* Recalc carrying of the cauldron, in case recipe did not conserve mass */
316 sum_weight(cauldron); 335 sum_weight (cauldron);
317 /* adj lvl, nrof on caster level */ 336 /* adj lvl, nrof on caster level */
318 adjust_product(item, ability, rp->yield?(rp->yield*batches):batches); 337 adjust_product (item, ability, rp->yield ? (rp->yield * batches) : batches);
319 if(!item->env && (item=insert_ob_in_ob(item,cauldron)) == NULL) { 338 if (!item->env && (item = insert_ob_in_ob (item, cauldron)) == NULL)
339 {
320 new_draw_info(NDI_UNIQUE, 0,caster,"Nothing happened."); 340 new_draw_info (NDI_UNIQUE, 0, caster, "Nothing happened.");
321 /* new_draw_info_format(NDI_UNIQUE, 0,caster, 341 /* new_draw_info_format(NDI_UNIQUE, 0,caster,
322 "Your spell causes the %s to explode!",&cauldron->name); */ 342 "Your spell causes the %s to explode!",&cauldron->name); */
323 /* kaboom_cauldron(); */ 343 /* kaboom_cauldron(); */
344 }
324 } else { 345 else
325 new_draw_info_format(NDI_UNIQUE, 0,caster, 346 new_draw_info_format (NDI_UNIQUE, 0, caster, "The %s %s.", &cauldron->name, cauldron_sound ());
326 "The %s %s.", &cauldron->name,cauldron_sound());
327 }
328 } 347 }
348
329 return item; 349 return item;
330} 350}
331 351
332 352
333 353
334/** 354/**
335 * We adjust the nrof, exp and level of the final product, based 355 * We adjust the nrof, exp and level of the final product, based
336 * on the item's default parameters, and the relevant caster skill level. 356 * on the item's default parameters, and the relevant caster skill level.
337 */ 357 */
338 358void
339void adjust_product(object *item, int lvl, int yield) { 359adjust_product (object *item, int lvl, int yield)
360{
340 int nrof=1; 361 int nrof = 1;
341 362
342 if (!yield) 363 if (!yield)
343 yield = 1; 364 yield = 1;
365
344 if (lvl<=0) 366 if (lvl <= 0)
345 lvl = 1; /* lets avoid div by zero! */ 367 lvl = 1; /* lets avoid div by zero! */
368
346 if (item->nrof) { 369 if (item->nrof)
347 nrof = (int) ( 370 {
348 (1.0 - 1.0/(lvl/10.0 + 1.0)) * 371 nrof = (int) ((1.0 - 1.0 / (lvl / 10.0 + 1.0)) * (rndm (0, yield - 1) + rndm (0, yield - 1) + rndm (0, yield - 1)) + 1);
349 (rndm(0, yield-1) + rndm(0, yield-1) + rndm(0, yield-1)) + 1 372
350 );
351 if (nrof > yield) 373 if (nrof > yield)
352 nrof = yield; 374 nrof = yield;
375
353 item->nrof=nrof; 376 item->nrof = nrof;
354 } 377 }
355} 378}
356 379
357 380
358/** 381/**
363 * @param rp the recipe to make the artifact from 386 * @param rp the recipe to make the artifact from
364 * 387 *
365 * @return the newly created object, NULL if something failed 388 * @return the newly created object, NULL if something failed
366 */ 389 */
367 390
391object *
368object * make_item_from_recipe(object *cauldron, recipe *rp) { 392make_item_from_recipe (object *cauldron, recipe *rp)
393{
369 artifact *art=NULL; 394 artifact *art = NULL;
370 object *item=NULL; 395 object *item = NULL;
371 size_t rp_arch_index; 396 size_t rp_arch_index;
372 397
398 if (rp == NULL)
373 if(rp==NULL) return (object *) NULL; 399 return (object *) NULL;
374 400
375 /* Find the appropriate object to transform...*/ 401 /* Find the appropriate object to transform... */
376 if((item=find_transmution_ob(cauldron->inv, rp, &rp_arch_index, 1))==NULL) { 402 if ((item = find_transmution_ob (cauldron->inv, rp, &rp_arch_index, 1)) == NULL)
403 {
377 LOG(llevDebug,"make_alchemy_item(): failed to create alchemical object.\n"); 404 LOG (llevDebug, "make_alchemy_item(): failed to create alchemical object.\n");
378 return (object *) NULL; 405 return (object *) NULL;
379 } 406 }
380 407
381 /* Find the appropriate artifact template...*/ 408 /* Find the appropriate artifact template... */
382 if(strcmp(rp->title,"NONE")) { 409 if (strcmp (rp->title, "NONE"))
410 {
383 if((art=locate_recipe_artifact(rp, rp_arch_index))==NULL) { 411 if ((art = locate_recipe_artifact (rp, rp_arch_index)) == NULL)
412 {
384 LOG(llevError,"make_alchemy_item(): failed to locate recipe artifact.\n"); 413 LOG (llevError, "make_alchemy_item(): failed to locate recipe artifact.\n");
385 LOG(llevDebug," --requested recipe: %s of %s.\n",rp->arch_name[0],&rp->title); 414 LOG (llevDebug, " --requested recipe: %s of %s.\n", rp->arch_name[0], &rp->title);
386 return (object *) NULL; 415 return (object *) NULL;
387 } 416 }
388 transmute_materialname(item, art->item); 417 transmute_materialname (item, art->item);
389 give_artifact_abilities(item, art->item); 418 give_artifact_abilities (item, art->item);
390 } 419 }
391 420
392 if(QUERY_FLAG(cauldron,FLAG_CURSED)) SET_FLAG(item,FLAG_CURSED); 421 if (QUERY_FLAG (cauldron, FLAG_CURSED))
393 if(QUERY_FLAG(cauldron,FLAG_DAMNED)) SET_FLAG(item,FLAG_DAMNED); 422 SET_FLAG (item, FLAG_CURSED);
394 423 if (QUERY_FLAG (cauldron, FLAG_DAMNED))
424 SET_FLAG (item, FLAG_DAMNED);
425
395 return item; 426 return item;
396} 427}
397 428
398 429
399/** 430/**
400 * Looks through the ingredient list. If we find a 431 * Looks through the ingredient list. If we find a
402 * Otherwise the code returns a 'generic' item if create_item is set. -b.t. 433 * Otherwise the code returns a 'generic' item if create_item is set. -b.t.
403 * 434 *
404 * @param rp_arch_index pointer to return value; set to arch index for recipe; 435 * @param rp_arch_index pointer to return value; set to arch index for recipe;
405 * set to zero if not using a transmution formula 436 * set to zero if not using a transmution formula
406 */ 437 */
407 438
439object *
408object * find_transmution_ob ( object *first_ingred, recipe *rp, size_t *rp_arch_index, int create_item) { 440find_transmution_ob (object *first_ingred, recipe *rp, size_t * rp_arch_index, int create_item)
441{
409 object *item=NULL; 442 object *item = NULL;
410 443
411 *rp_arch_index = 0; 444 *rp_arch_index = 0;
412 445
413 if(rp->transmute) /* look for matching ingredient/prod archs */ 446 if (rp->transmute) /* look for matching ingredient/prod archs */
414 for(item=first_ingred;item;item=item->below) { 447 for (item = first_ingred; item; item = item->below)
448 {
415 size_t i; 449 size_t i;
416 450
417 for (i = 0; i < rp->arch_names; i++) { 451 for (i = 0; i < rp->arch_names; i++)
452 {
418 if(strcmp(item->arch->name, rp->arch_name[i]) == 0) { 453 if (strcmp (item->arch->name, rp->arch_name[i]) == 0)
454 {
419 *rp_arch_index = i; 455 *rp_arch_index = i;
420 break;
421 }
422 }
423 if (i < rp->arch_names)
424 break; 456 break;
457 }
425 } 458 }
426 459 if (i < rp->arch_names)
460 break;
461 }
462
427 /* failed, create a fresh object. Note no nrof>1 because that would 463 /* failed, create a fresh object. Note no nrof>1 because that would
428 * allow players to create massive amounts of artifacts easily */ 464 * allow players to create massive amounts of artifacts easily */
429 if(create_item && (!item || item->nrof > 1)) { 465 if (create_item && (!item || item->nrof > 1))
466 {
430 *rp_arch_index = RANDOM()%rp->arch_names; 467 *rp_arch_index = RANDOM () % rp->arch_names;
431 item = get_archetype(rp->arch_name[*rp_arch_index]); 468 item = get_archetype (rp->arch_name[*rp_arch_index]);
432 } 469 }
433 470
434#ifdef ALCHEMY_DEBUG 471#ifdef ALCHEMY_DEBUG
435 LOG(llevDebug,"recipe calls for%stransmution.\n",rp->transmute?" ":" no "); 472 LOG (llevDebug, "recipe calls for%stransmution.\n", rp->transmute ? " " : " no ");
436 if (item != NULL) { 473 if (item != NULL)
437 LOG(llevDebug," find_transmutable_ob(): returns arch %s(sp:%d)\n",
438 item->arch->name,item->stats.sp);
439 } 474 {
475 LOG (llevDebug, " find_transmutable_ob(): returns arch %s(sp:%d)\n", item->arch->name, item->stats.sp);
476 }
440#endif 477#endif
441 478
442 return item; 479 return item;
443} 480}
444 481
445 482
446/** 483/**
447 * Ouch. We didnt get the formula we wanted. 484 * Ouch. We didnt get the formula we wanted.
448 * This fctn simulates the backfire effects--worse effects as the level 485 * This fctn simulates the backfire effects--worse effects as the level
449 * increases. If SPELL_FAILURE_EFFECTS is defined some really evil things 486 * increases. If SPELL_FAILURE_EFFECTS is defined some really evil things
450 * can happen to the would be alchemist. This table probably needs some 487 * can happen to the would be alchemist. This table probably needs some
451 * adjustment for playbalance. -b.t. 488 * adjustment for playbalance. -b.t.
452 */ 489 */
453 490
491void
454void alchemy_failure_effect(object *op,object *cauldron,recipe *rp,int danger) { 492alchemy_failure_effect (object *op, object *cauldron, recipe *rp, int danger)
493{
455 int level=0; 494 int level = 0;
456 495
457 if(!op || !cauldron) return; 496 if (!op || !cauldron)
497 return;
458 498
499 if (danger > 1)
459 if(danger>1) level=random_roll(1, danger, op, PREFER_LOW); 500 level = random_roll (1, danger, op, PREFER_LOW);
460 501
461#ifdef ALCHEMY_DEBUG 502#ifdef ALCHEMY_DEBUG
462 LOG(llevDebug,"Alchemy_failure_effect(): using level=%d\n",level); 503 LOG (llevDebug, "Alchemy_failure_effect(): using level=%d\n", level);
463#endif 504#endif
464 505
465 /* possible outcomes based on level */ 506 /* possible outcomes based on level */
466 if(level<25) { /* INGREDIENTS USED/SLAGGED */ 507 if (level < 25)
508 { /* INGREDIENTS USED/SLAGGED */
467 object *item=NULL; 509 object *item = NULL;
468 510
469 if(rndm(0, 2)) { /* slag created */ 511 if (rndm (0, 2))
512 { /* slag created */
470 object *tmp=cauldron->inv; 513 object *tmp = cauldron->inv;
471 int weight=0; 514 int weight = 0;
472 uint16 material=M_STONE; 515 uint16 material = M_STONE;
473 516
517 while (tmp)
474 while(tmp) { /* slag has coadded ingredient properties */ 518 { /* slag has coadded ingredient properties */
475 weight+=tmp->weight; 519 weight += tmp->weight;
476 if(!(material&tmp->material)) 520 if (!(material & tmp->material))
477 material |= tmp->material; 521 material |= tmp->material;
478 tmp=tmp->below; 522 tmp = tmp->below;
479 } 523 }
480 tmp = get_archetype("rock"); 524 tmp = get_archetype ("rock");
481 tmp->weight=weight; 525 tmp->weight = weight;
482 tmp->value=0; 526 tmp->value = 0;
483 tmp->material=material; 527 tmp->material = material;
484 tmp->materialname = "stone"; 528 tmp->materialname = "stone";
485 tmp->name="slag"; 529 tmp->name = "slag";
486 tmp->name_pl="slags"; 530 tmp->name_pl = "slags";
487 item=insert_ob_in_ob(tmp,cauldron); 531 item = insert_ob_in_ob (tmp, cauldron);
488 CLEAR_FLAG(tmp,FLAG_CAN_ROLL); 532 CLEAR_FLAG (tmp, FLAG_CAN_ROLL);
489 CLEAR_FLAG(tmp,FLAG_NO_PICK); 533 CLEAR_FLAG (tmp, FLAG_NO_PICK);
490 tmp->move_block = 0; 534 tmp->move_block = 0;
491 } 535 }
492 remove_contents(cauldron->inv,item); 536 remove_contents (cauldron->inv, item);
493 new_draw_info_format(NDI_UNIQUE,0,op, 537 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s %s.", &cauldron->name, cauldron_sound ());
494 "The %s %s.", &cauldron->name,cauldron_sound()); 538 return;
539 }
540 else if (level < 40)
541 { /* MAKE TAINTED ITEM */
542 object *tmp = NULL;
543
544 if (!rp)
545 if ((rp = get_random_recipe ((recipelist *) NULL)) == NULL)
495 return; 546 return;
496 } else if (level< 40) { /* MAKE TAINTED ITEM */
497 object *tmp=NULL;
498 547
499 if (!rp)
500 if((rp=get_random_recipe((recipelist *) NULL))==NULL)
501 return;
502
503 if((tmp=attempt_recipe(op,cauldron,1,rp,-1))) { 548 if ((tmp = attempt_recipe (op, cauldron, 1, rp, -1)))
549 {
504 if(!QUERY_FLAG(tmp,FLAG_CURSED)) /* curse it */ 550 if (!QUERY_FLAG (tmp, FLAG_CURSED)) /* curse it */
505 SET_FLAG(tmp,FLAG_CURSED); 551 SET_FLAG (tmp, FLAG_CURSED);
506 552
507 /* the apply code for potions already deals with cursed 553 /* the apply code for potions already deals with cursed
508 * potions, so any code here is basically ignored. 554 * potions, so any code here is basically ignored.
509 */ 555 */
510 if(tmp->type==FOOD) { 556 if (tmp->type == FOOD)
557 {
511 tmp->stats.hp=random_roll(0, 149, op, PREFER_LOW); 558 tmp->stats.hp = random_roll (0, 149, op, PREFER_LOW);
512 } 559 }
513 tmp->value = 0; /* unsaleable item */ 560 tmp->value = 0; /* unsaleable item */
514 561
515 /* change stats downward */ 562 /* change stats downward */
516 do { 563 do
564 {
517 change_attr_value(&tmp->stats,rndm(0, 6),-1*(rndm(1, 3))); 565 change_attr_value (&tmp->stats, rndm (0, 6), -1 * (rndm (1, 3)));
566 }
518 } while (rndm(0, 2)); 567 while (rndm (0, 2));
519 } 568 }
520 return; 569 return;
570 }
571 if (level == 40)
521 } if(level==40) { /* MAKE RANDOM RECIPE */ 572 { /* MAKE RANDOM RECIPE */
522 recipelist *fl; 573 recipelist *fl;
523 int numb=numb_ob_inside(cauldron); 574 int numb = numb_ob_inside (cauldron);
524 575
525 fl=get_formulalist(numb-1); /* take a lower recipe list */ 576 fl = get_formulalist (numb - 1); /* take a lower recipe list */
526 if(fl &&(rp=get_random_recipe(fl))) 577 if (fl && (rp = get_random_recipe (fl)))
527 /* even though random, don't grant user any EXP for it */ 578 /* even though random, don't grant user any EXP for it */
528 (void) attempt_recipe(op,cauldron,1,rp,-1); 579 (void) attempt_recipe (op, cauldron, 1, rp, -1);
529 else 580 else
530 alchemy_failure_effect(op,cauldron,rp,level-1); 581 alchemy_failure_effect (op, cauldron, rp, level - 1);
531 return; 582 return;
532 583
533 } else if (level<45) { /* INFURIATE NPC's */ 584 }
585 else if (level < 45)
586 { /* INFURIATE NPC's */
534 /* this is kind of kludgy I know...*/ 587 /* this is kind of kludgy I know... */
535 cauldron->enemy=op; 588 cauldron->enemy = op;
536 npc_call_help(cauldron); 589 npc_call_help (cauldron);
537 cauldron->enemy=NULL; 590 cauldron->enemy = NULL;
538 591
539 alchemy_failure_effect(op,cauldron,rp,level-5); 592 alchemy_failure_effect (op, cauldron, rp, level - 5);
540 return; 593 return;
541 } else if (level<50) { /* MINOR EXPLOSION/FIREBALL */ 594 }
595 else if (level < 50)
596 { /* MINOR EXPLOSION/FIREBALL */
542 object *tmp; 597 object *tmp;
598
543 remove_contents(cauldron->inv,NULL); 599 remove_contents (cauldron->inv, NULL);
544 switch(rndm(0, 2)) { 600 switch (rndm (0, 2))
601 {
545 case 0: 602 case 0:
546 tmp=get_archetype("bomb"); 603 tmp = get_archetype ("bomb");
547 tmp->stats.dam=random_roll(1, level, op, PREFER_LOW); 604 tmp->stats.dam = random_roll (1, level, op, PREFER_LOW);
548 tmp->stats.hp=random_roll(1, level, op, PREFER_LOW); 605 tmp->stats.hp = random_roll (1, level, op, PREFER_LOW);
549 new_draw_info_format(NDI_UNIQUE,0,op,"The %s creates a bomb!", 606 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s creates a bomb!", &cauldron->name);
550 &cauldron->name);
551 break; 607 break;
552 608
553 default: 609 default:
554 tmp=get_archetype("fireball"); 610 tmp = get_archetype ("fireball");
555 tmp->stats.dam=random_roll(1, level, op, PREFER_LOW)/5+1; 611 tmp->stats.dam = random_roll (1, level, op, PREFER_LOW) / 5 + 1;
556 tmp->stats.hp=random_roll(1, level, op, PREFER_LOW)/10+2; 612 tmp->stats.hp = random_roll (1, level, op, PREFER_LOW) / 10 + 2;
557 new_draw_info_format(NDI_UNIQUE,0,op,"The %s erupts in flame!", 613 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s erupts in flame!", &cauldron->name);
558 &cauldron->name);
559 break; 614 break;
560 } 615 }
561 tmp->x=cauldron->x,tmp->y=cauldron->y; 616
562 insert_ob_in_map(tmp,op->map,NULL,0); 617 op->insert_at (cauldron);
563 return; 618 return;
564 619
565 } else if (level<60) { /* CREATE MONSTER */ 620 }
566 new_draw_info_format(NDI_UNIQUE,0,op, 621 else if (level < 60)
567 "The %s %s.",&cauldron->name,cauldron_sound()); 622 { /* CREATE MONSTER */
623 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s %s.", &cauldron->name, cauldron_sound ());
568 remove_contents(cauldron->inv,NULL); 624 remove_contents (cauldron->inv, NULL);
569 return; 625 return;
570 } else if (level<80) { /* MAJOR FIRE */ 626 }
627 else if (level < 80)
628 { /* MAJOR FIRE */
571 object *fb = get_archetype(SP_MED_FIREBALL); 629 object *fb = get_archetype (SP_MED_FIREBALL);
630
572 remove_contents(cauldron->inv,NULL); 631 remove_contents (cauldron->inv, NULL);
573 fire_arch_from_position(cauldron, cauldron,cauldron->x, cauldron->y, 632 fire_arch_from_position (cauldron, cauldron, cauldron->x, cauldron->y, 0, fb);
574 0, fb); 633 fb->destroy ();
575 free_object(fb);
576 new_draw_info_format(NDI_UNIQUE,0,op,"The %s erupts in flame!", 634 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s erupts in flame!", &cauldron->name);
577 &cauldron->name);
578 return; 635 return;
579 636
580 } else if (level<100) { /* WHAMMY the CAULDRON */ 637 }
638 else if (level < 100)
639 { /* WHAMMY the CAULDRON */
581 if(!QUERY_FLAG(cauldron,FLAG_CURSED)) 640 if (!QUERY_FLAG (cauldron, FLAG_CURSED))
582 SET_FLAG(cauldron,FLAG_CURSED); 641 SET_FLAG (cauldron, FLAG_CURSED);
642 else
583 else cauldron->magic--; 643 cauldron->magic--;
584 cauldron->magic -= random_roll(0, 4, op, PREFER_LOW); 644 cauldron->magic -= random_roll (0, 4, op, PREFER_LOW);
585 if(rndm(0, 1)) { 645 if (rndm (0, 1))
646 {
586 remove_contents(cauldron->inv,NULL); 647 remove_contents (cauldron->inv, NULL);
587 new_draw_info_format(NDI_UNIQUE,0,op, 648 new_draw_info_format (NDI_UNIQUE, 0, op, "Your %s turns darker then makes a gulping sound!", &cauldron->name);
588 "Your %s turns darker then makes a gulping sound!", 649 }
589 &cauldron->name);
590 } else 650 else
591 new_draw_info_format(NDI_UNIQUE,0,op, 651 new_draw_info_format (NDI_UNIQUE, 0, op, "Your %s becomes darker.", &cauldron->name);
592 "Your %s becomes darker.",&cauldron->name);
593 return; 652 return;
594 653
595 } else if (level<110) { /* SUMMON EVIL MONSTERS */ 654 }
655 else if (level < 110)
656 { /* SUMMON EVIL MONSTERS */
596 object *tmp=get_random_mon(level/5); 657 object *tmp = get_random_mon (level / 5);
597 658
598 remove_contents(cauldron->inv,NULL); 659 remove_contents (cauldron->inv, NULL);
599 if(!tmp) 660 if (!tmp)
600 alchemy_failure_effect(op,cauldron,rp,level); 661 alchemy_failure_effect (op, cauldron, rp, level);
601 else if(summon_hostile_monsters(cauldron, random_roll(1, 10, op, PREFER_LOW), tmp->arch->name)) 662 else if (summon_hostile_monsters (cauldron, random_roll (1, 10, op, PREFER_LOW), tmp->arch->name))
602 new_draw_info_format(NDI_UNIQUE, 0,op, 663 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s %s and then pours forth monsters!", &cauldron->name, cauldron_sound ());
603 "The %s %s and then pours forth monsters!",
604 &cauldron->name,cauldron_sound());
605 return; 664 return;
606 665
607 } else if (level<150) { /* COMBO EFFECT */ 666 }
667 else if (level < 150)
668 { /* COMBO EFFECT */
608 int roll = rndm(1, 3); 669 int roll = rndm (1, 3);
670
609 while(roll) { 671 while (roll)
672 {
610 alchemy_failure_effect(op,cauldron,rp,level-39); 673 alchemy_failure_effect (op, cauldron, rp, level - 39);
611 roll--; 674 roll--;
612 } 675 }
613 return; 676 return;
614 } else if (level==151) { /* CREATE RANDOM ARTIFACT */ 677 }
678 else if (level == 151)
679 { /* CREATE RANDOM ARTIFACT */
615 object *tmp; 680 object *tmp;
681
616 /* this is meant to be better than prior possiblity, 682 /* this is meant to be better than prior possiblity,
617 * in this one, we allow *any* valid alchemy artifact 683 * in this one, we allow *any* valid alchemy artifact
618 * to be made (rather than only those on the given 684 * to be made (rather than only those on the given
619 * formulalist) */ 685 * formulalist) */
686 if (!rp)
620 if(!rp) rp=get_random_recipe((recipelist *) NULL); 687 rp = get_random_recipe ((recipelist *) NULL);
621 if(rp && (tmp=get_archetype(rp->arch_name[RANDOM()%rp->arch_names]))) { 688 if (rp && (tmp = get_archetype (rp->arch_name[RANDOM () % rp->arch_names])))
689 {
622 generate_artifact(tmp,random_roll(1, op->level/2+1, op, PREFER_HIGH)+1); 690 generate_artifact (tmp, random_roll (1, op->level / 2 + 1, op, PREFER_HIGH) + 1);
623 if((tmp=insert_ob_in_ob(tmp,cauldron))) { 691 if ((tmp = insert_ob_in_ob (tmp, cauldron)))
692 {
624 remove_contents(cauldron->inv,tmp); 693 remove_contents (cauldron->inv, tmp);
625 new_draw_info_format(NDI_UNIQUE, 0,op, 694 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s %s.", &cauldron->name, cauldron_sound ());
626 "The %s %s.",&cauldron->name,cauldron_sound());
627 }
628 } 695 }
696 }
629 return; 697 return;
698 }
699 else
630 } else { /* MANA STORM - watch out!! */ 700 { /* MANA STORM - watch out!! */
631 object *tmp = get_archetype(LOOSE_MANA); 701 object *tmp = get_archetype (LOOSE_MANA);
702
632 new_draw_info(NDI_UNIQUE,0,op,"You unwisely release potent forces!"); 703 new_draw_info (NDI_UNIQUE, 0, op, "You unwisely release potent forces!");
633 remove_contents (cauldron->inv,NULL); 704 remove_contents (cauldron->inv, NULL);
634 cast_magic_storm(op,tmp, level); 705 cast_magic_storm (op, tmp, level);
635 return; 706 return;
636 } 707 }
637} 708}
638 709
639 710
640/** 711/*
641 * All but object "save_item" are elimentated from 712 * All but object "save_item" are elimentated from
642 * the container list. Note we have to becareful to remove the inventories 713 * the container list. Note we have to becareful to remove the inventories
643 * of objects in the cauldron inventory (ex icecube has stuff in it). 714 * of objects in the cauldron inventory (ex icecube has stuff in it).
644 */ 715 */
645 716
717void
646void remove_contents (object *first_ob, object *save_item) { 718remove_contents (object *first_ob, object *save_item)
719{
647 object *next,*tmp=first_ob; 720 object *next, *tmp = first_ob;
648 721
649 while(tmp) { 722 while (tmp)
723 {
650 next = tmp->below; 724 next = tmp->below;
725
651 if(tmp==save_item) { 726 if (tmp == save_item)
652 if(!(tmp=next)) break;
653 else next=next->below;
654 } 727 {
728 if (!(tmp = next))
729 break;
730 else
731 next = next->below;
732 }
733
734 if (tmp->inv)
655 if(tmp->inv) remove_contents(tmp->inv,NULL); 735 remove_contents (tmp->inv, NULL);
656 remove_ob(tmp); 736
657 free_object(tmp); 737 tmp->destroy ();
658 tmp=next; 738 tmp = next;
659 } 739 }
660} 740}
661 741
662/** 742/**
663 *"Danger" level, will determine how bad the backfire 743 *"Danger" level, will determine how bad the backfire
667 * mixing device (aka "cauldron"). Higher values of 'danger' indicate more 747 * mixing device (aka "cauldron"). Higher values of 'danger' indicate more
668 * danger. Note that we assume that we have had the caster ready the alchemy 748 * danger. Note that we assume that we have had the caster ready the alchemy
669 * skill *before* this routine is called. (no longer auto-readies that skill) 749 * skill *before* this routine is called. (no longer auto-readies that skill)
670 * -b.t. 750 * -b.t.
671 */ 751 */
672 752
753int
673int calc_alch_danger(object *caster,object *cauldron, recipe *rp) { 754calc_alch_danger (object *caster, object *cauldron, recipe *rp)
755{
674 object *item; 756 object *item;
675 char name[MAX_BUF]; 757 char name[MAX_BUF];
676 int danger=0,nrofi=0; 758 int danger = 0, nrofi = 0;
677 759
678 /* Knowing alchemy skill reduces yer risk */ 760 /* Knowing alchemy skill reduces yer risk */
679 danger -= caster->chosen_skill?caster->chosen_skill->level:caster->level; 761 danger -= caster->chosen_skill ? caster->chosen_skill->level : caster->level;
680 762
681 /* better cauldrons reduce risk */ 763 /* better cauldrons reduce risk */
682 danger -= cauldron->magic; 764 danger -= cauldron->magic;
683 765
684 /* Higher Int, lower the risk */ 766 /* Higher Int, lower the risk */
685 danger -= 3 * (caster->stats.Int - 15); 767 danger -= 3 * (caster->stats.Int - 15);
686 768
687 /* Ingredients. Longer names usually mean rarer stuff. 769 /* Ingredients. Longer names usually mean rarer stuff.
688 * Thus the backfire is worse. Also, more ingredients 770 * Thus the backfire is worse. Also, more ingredients
689 * means we are attempting a more powerfull potion, 771 * means we are attempting a more powerfull potion,
690 * and thus the backfire will be worse. */ 772 * and thus the backfire will be worse. */
691 for(item=cauldron->inv;item;item=item->below) { 773 for (item = cauldron->inv; item; item = item->below)
774 {
692 strcpy(name,item->name); 775 strcpy (name, item->name);
776 if (item->title)
693 if(item->title) sprintf(name,"%s %s", &item->name, &item->title); 777 sprintf (name, "%s %s", &item->name, &item->title);
694 danger += (strtoint(name)/1000) + 3; 778 danger += (strtoint (name) / 1000) + 3;
695 nrofi++; 779 nrofi++;
696 } 780 }
697 if (rp == NULL) 781 if (rp == NULL)
698 danger += 110; 782 danger += 110;
699 else 783 else
700 danger += rp->diff*3; 784 danger += rp->diff * 3;
701 785
702 /* Using a bad device is *majorly* stupid */ 786 /* Using a bad device is *majorly* stupid */
703 if(QUERY_FLAG(cauldron,FLAG_CURSED)) danger +=80; 787 if (QUERY_FLAG (cauldron, FLAG_CURSED))
788 danger += 80;
704 if(QUERY_FLAG(cauldron,FLAG_DAMNED)) danger +=200; 789 if (QUERY_FLAG (cauldron, FLAG_DAMNED))
790 danger += 200;
705 791
706#ifdef ALCHEMY_DEBUG 792#ifdef ALCHEMY_DEBUG
707 LOG(llevDebug,"calc_alch_danger() returned danger=%d\n",danger); 793 LOG (llevDebug, "calc_alch_danger() returned danger=%d\n", danger);
708#endif 794#endif
709 795
710 return danger; 796 return danger;
711} 797}
712 798
713/** 799/**
714 * Determines if ingredients in a container match the 800 * Determines if ingredients in a container match the
715 * proper ingredients for a recipe. 801 * proper ingredients for a recipe.
722 * the defined recipe iff 808 * the defined recipe iff
723 * - the number of ingredients of the recipe and in the container is equal 809 * - the number of ingredients of the recipe and in the container is equal
724 * - all ingredients of the recipe are found in the container 810 * - all ingredients of the recipe are found in the container
725 * - the number of batches is the same for all ingredients 811 * - the number of batches is the same for all ingredients
726 */ 812 */
813static int
727static int is_defined_recipe(const recipe *rp, const object *cauldron, object *caster) 814is_defined_recipe (const recipe *rp, const object *cauldron, object *caster)
728{ 815{
729 uint32 batches_in_cauldron; 816 uint32 batches_in_cauldron;
730 const linked_char *ingredient; 817 const linked_char *ingredient;
731 int number; 818 int number;
732 const object *ob; 819 const object *ob;
733 820
734 /* check for matching number of ingredients */ 821 /* check for matching number of ingredients */
735 number = 0; 822 number = 0;
736 for(ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next) 823 for (ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next)
737 number++; 824 number++;
738 for(ob = cauldron->inv; ob != NULL; ob = ob->below) 825 for (ob = cauldron->inv; ob != NULL; ob = ob->below)
739 number--; 826 number--;
740 if(number != 0) 827 if (number != 0)
741 return 0; 828 return 0;
742 829
743 /* check for matching ingredients */ 830 /* check for matching ingredients */
744 batches_in_cauldron = 0; 831 batches_in_cauldron = 0;
745 for(ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next) { 832 for (ingredient = rp->ingred; ingredient != NULL; ingredient = ingredient->next)
833 {
746 uint32 nrof; 834 uint32 nrof;
747 const char *name; 835 const char *name;
748 int ok; 836 int ok;
749 837
750 /* determine and remove nrof from name */ 838 /* determine and remove nrof from name */
751 name = ingredient->name; 839 name = ingredient->name;
752 nrof = 0; 840 nrof = 0;
753 while(isdigit(*name)) { 841 while (isdigit (*name))
842 {
754 nrof = 10*nrof+(*name-'0'); 843 nrof = 10 * nrof + (*name - '0');
755 name++; 844 name++;
756 } 845 }
757 if(nrof == 0) 846 if (nrof == 0)
758 nrof = 1; 847 nrof = 1;
759 while(*name == ' ') 848 while (*name == ' ')
760 name++; 849 name++;
761 850
762 /* find the current ingredient in the cauldron */ 851 /* find the current ingredient in the cauldron */
763 ok = 0; 852 ok = 0;
764 for(ob = cauldron->inv; ob != NULL; ob = ob->below) { 853 for (ob = cauldron->inv; ob != NULL; ob = ob->below)
854 {
765 char name_ob[MAX_BUF]; 855 char name_ob[MAX_BUF];
766 const char *name2; 856 const char *name2;
767 857
768 if(ob->title == NULL) 858 if (ob->title == NULL)
769 name2 = ob->name; 859 name2 = ob->name;
770 else { 860 else
861 {
771 snprintf(name_ob, sizeof(name_ob), "%s %s", &ob->name, &ob->title); 862 snprintf (name_ob, sizeof (name_ob), "%s %s", &ob->name, &ob->title);
772 name2 = name_ob; 863 name2 = name_ob;
773 } 864 }
774 865
775 if(strcmp(name2, name) == 0) { 866 if (strcmp (name2, name) == 0)
867 {
776 if(ob->nrof%nrof == 0) { 868 if (ob->nrof % nrof == 0)
869 {
777 uint32 batches; 870 uint32 batches;
778 871
779 batches = ob->nrof/nrof; 872 batches = ob->nrof / nrof;
780 if(batches_in_cauldron == 0) { 873 if (batches_in_cauldron == 0)
874 {
781 batches_in_cauldron = batches; 875 batches_in_cauldron = batches;
782 ok = 1; 876 ok = 1;
877 }
783 } else if(batches_in_cauldron == batches) 878 else if (batches_in_cauldron == batches)
784 ok = 1; 879 ok = 1;
785 } 880 }
786 break; 881 break;
787 }
788 } 882 }
883 }
789 if(!ok) 884 if (!ok)
790 return(0); 885 return (0);
791 } 886 }
792 887
793 return(1); 888 return (1);
794} 889}
795 890
796/** 891/**
797 * Find a recipe from a recipe list that matches the given formula. If there 892 * Find a recipe from a recipe list that matches the given formula. If there
798 * is more than one matching recipe, it selects a random one. If at least one 893 * is more than one matching recipe, it selects a random one. If at least one
799 * transmuting recipe matches, it only considers matching transmuting recipes. 894 * transmuting recipe matches, it only considers matching transmuting recipes.
800 * 895 *
801 * @return one matching recipe, or NULL if no recipe matches 896 * @return one matching recipe, or NULL if no recipe matches
802 */ 897 */
898static recipe *
803static recipe *find_recipe(recipelist *fl, int formula, object *ingredients) 899find_recipe (recipelist * fl, int formula, object *ingredients)
804{ 900{
805 recipe *rp; 901 recipe *rp;
806 recipe *result; /* winning recipe, or NULL if no recipe found */ 902 recipe *result; /* winning recipe, or NULL if no recipe found */
807 int recipes_matching; /* total number of matching recipes so far */ 903 int recipes_matching; /* total number of matching recipes so far */
808 int transmute_found; /* records whether a transmuting recipe was found so far */ 904 int transmute_found; /* records whether a transmuting recipe was found so far */
809 size_t rp_arch_index; 905 size_t rp_arch_index;
810 906
811#ifdef EXTREME_ALCHEMY_DEBUG 907#ifdef EXTREME_ALCHEMY_DEBUG
812 LOG(llevDebug, "looking for formula %d:\n", formula); 908 LOG (llevDebug, "looking for formula %d:\n", formula);
813#endif 909#endif
814 result = NULL; 910 result = NULL;
815 recipes_matching = 0; 911 recipes_matching = 0;
816 transmute_found = 0; 912 transmute_found = 0;
817 for (rp = fl->items; rp != NULL; rp = rp->next) { 913 for (rp = fl->items; rp != NULL; rp = rp->next)
914 {
818 /* check if recipe matches at all */ 915 /* check if recipe matches at all */
819 if (formula%rp->index != 0) { 916 if (formula % rp->index != 0)
917 {
820#ifdef EXTREME_ALCHEMY_DEBUG 918#ifdef EXTREME_ALCHEMY_DEBUG
821 LOG(llevDebug, " formula %s of %s (%d) does not match\n", rp->arch_name[0], rp->title, rp->index); 919 LOG (llevDebug, " formula %s of %s (%d) does not match\n", rp->arch_name[0], rp->title, rp->index);
822#endif 920#endif
823 continue; 921 continue;
824 } 922 }
825 923
826 if (rp->transmute && find_transmution_ob(ingredients, rp, &rp_arch_index, 0) != NULL) { 924 if (rp->transmute && find_transmution_ob (ingredients, rp, &rp_arch_index, 0) != NULL)
925 {
827#ifdef EXTREME_ALCHEMY_DEBUG 926#ifdef EXTREME_ALCHEMY_DEBUG
828 LOG(llevDebug, " formula %s of %s (%d) is a matching transmuting formula\n", rp->arch_name[rp_arch_index], rp->title, rp->index); 927 LOG (llevDebug, " formula %s of %s (%d) is a matching transmuting formula\n", rp->arch_name[rp_arch_index], rp->title, rp->index);
829#endif 928#endif
830 /* transmution recipe with matching base ingredient */ 929 /* transmution recipe with matching base ingredient */
831 if (!transmute_found) { 930 if (!transmute_found)
931 {
832 transmute_found = 1; 932 transmute_found = 1;
833 recipes_matching = 0; 933 recipes_matching = 0;
934 }
834 } 935 }
835 } else if (transmute_found) { 936 else if (transmute_found)
937 {
836#ifdef EXTREME_ALCHEMY_DEBUG 938#ifdef EXTREME_ALCHEMY_DEBUG
837 LOG(llevDebug, " formula %s of %s (%d) matches but is not a matching transmuting formula\n", rp->arch_name[0], rp->title, rp->index); 939 LOG (llevDebug, " formula %s of %s (%d) matches but is not a matching transmuting formula\n", rp->arch_name[0], rp->title,
940 rp->index);
838#endif 941#endif
839 /* "normal" recipe found after previous transmution recipe => ignore this recipe */ 942 /* "normal" recipe found after previous transmution recipe => ignore this recipe */
840 continue; 943 continue;
841 } 944 }
842#ifdef EXTREME_ALCHEMY_DEBUG 945#ifdef EXTREME_ALCHEMY_DEBUG
843 else { 946 else
947 {
844 LOG(llevDebug, " formula %s of %s (%d) matches\n", rp->arch_name[0], rp->title, rp->index); 948 LOG (llevDebug, " formula %s of %s (%d) matches\n", rp->arch_name[0], rp->title, rp->index);
845 } 949 }
846#endif 950#endif
847 951
848 if (rndm(0, recipes_matching) == 0) 952 if (rndm (0, recipes_matching) == 0)
849 result = rp; 953 result = rp;
850 954
851 recipes_matching++; 955 recipes_matching++;
852 } 956 }
853 957
854 if (result == NULL) { 958 if (result == NULL)
959 {
855#ifdef ALCHEMY_DEBUG 960#ifdef ALCHEMY_DEBUG
856 LOG(llevDebug, "couldn't find formula for ingredients.\n"); 961 LOG (llevDebug, "couldn't find formula for ingredients.\n");
857#endif 962#endif
858 return NULL; 963 return NULL;
859 } 964 }
860 965
861#ifdef ALCHEMY_DEBUG 966#ifdef ALCHEMY_DEBUG
862 if(strcmp(result->title, "NONE") != 0) 967 if (strcmp (result->title, "NONE") != 0)
863 LOG(llevDebug, "got formula: %s of %s (nbatches:%d)\n", result->arch_name[0], result->title, formula/result->index); 968 LOG (llevDebug, "got formula: %s of %s (nbatches:%d)\n", result->arch_name[0], result->title, formula / result->index);
864 else 969 else
865 LOG(llevDebug, "got formula: %s (nbatches:%d)\n", result->arch_name[0], formula/result->index); 970 LOG (llevDebug, "got formula: %s (nbatches:%d)\n", result->arch_name[0], formula / result->index);
866#endif 971#endif
867 return result; 972 return result;
868} 973}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines