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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines