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.4 by root, Tue Aug 29 08:01:37 2006 UTC vs.
Revision 1.31 by root, Mon Sep 29 10:20:48 2008 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines