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

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines