1 /**
2 * @file items.cpp
3 *
4 * Implementation of item functionality.
5 */
6 #include <algorithm>
7 #include "all.h"
8 #include "options.h"
9
10 DEVILUTION_BEGIN_NAMESPACE
11
12 int itemactive[MAXITEMS];
13 BOOL uitemflag;
14 int itemavail[MAXITEMS];
15 ItemStruct curruitem;
16 ItemGetRecordStruct itemrecord[MAXITEMS];
17 /** Contains the items on ground in the current game. */
18 ItemStruct item[MAXITEMS + 1];
19 BOOL itemhold[3][3];
20 CornerStoneStruct CornerStone;
21 BYTE *itemanims[ITEMTYPES];
22 BOOL UniqueItemFlag[128];
23 int numitems;
24 int gnNumGetRecords;
25
26 /* data */
27
28 int OilLevels[] = { 1, 10, 1, 10, 4, 1, 5, 17, 1, 10 };
29 int OilValues[] = { 500, 2500, 500, 2500, 1500, 100, 2500, 15000, 500, 2500 };
30 enum item_misc_id OilMagic[] = {
31 IMISC_OILACC,
32 IMISC_OILMAST,
33 IMISC_OILSHARP,
34 IMISC_OILDEATH,
35 IMISC_OILSKILL,
36 IMISC_OILBSMTH,
37 IMISC_OILFORT,
38 IMISC_OILPERM,
39 IMISC_OILHARD,
40 IMISC_OILIMP,
41 };
42 char OilNames[10][25] = {
43 "Oil of Accuracy",
44 "Oil of Mastery",
45 "Oil of Sharpness",
46 "Oil of Death",
47 "Oil of Skill",
48 "Blacksmith Oil",
49 "Oil of Fortitude",
50 "Oil of Permanence",
51 "Oil of Hardening",
52 "Oil of Imperviousness"
53 };
54 int MaxGold = GOLD_MAX_LIMIT;
55
56 /** Maps from item_cursor_graphic to in-memory item type. */
57 BYTE ItemCAnimTbl[] = {
58 20, 16, 16, 16, 4, 4, 4, 12, 12, 12,
59 12, 12, 12, 12, 12, 21, 21, 25, 12, 28,
60 28, 28, 38, 38, 38, 32, 38, 38, 38, 24,
61 24, 26, 2, 25, 22, 23, 24, 25, 27, 27,
62 29, 0, 0, 0, 12, 12, 12, 12, 12, 0,
63 8, 8, 0, 8, 8, 8, 8, 8, 8, 6,
64 8, 8, 8, 6, 8, 8, 6, 8, 8, 6,
65 6, 6, 8, 8, 8, 5, 9, 13, 13, 13,
66 5, 5, 5, 15, 5, 5, 18, 18, 18, 30,
67 5, 5, 14, 5, 14, 13, 16, 18, 5, 5,
68 7, 1, 3, 17, 1, 15, 10, 14, 3, 11,
69 8, 0, 1, 7, 0, 7, 15, 7, 3, 3,
70 3, 6, 6, 11, 11, 11, 31, 14, 14, 14,
71 6, 6, 7, 3, 8, 14, 0, 14, 14, 0,
72 33, 1, 1, 1, 1, 1, 7, 7, 7, 14,
73 14, 17, 17, 17, 0, 34, 1, 0, 3, 17,
74 8, 8, 6, 1, 3, 3, 11, 3, 12, 12,
75 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
76 12, 12, 12, 12, 12, 12, 12, 35, 39, 36,
77 36, 36, 37, 38, 38, 38, 38, 38, 41, 42,
78 8, 8, 8, 17, 0, 6, 8, 11, 11, 3,
79 3, 1, 6, 6, 6, 1, 8, 6, 11, 3,
80 6, 8, 1, 6, 6, 17, 40, 0, 0
81 };
82 /** Map of item type .cel file names. */
83 const char *const ItemDropNames[] = {
84 "Armor2",
85 "Axe",
86 "FBttle",
87 "Bow",
88 "GoldFlip",
89 "Helmut",
90 "Mace",
91 "Shield",
92 "SwrdFlip",
93 "Rock",
94 "Cleaver",
95 "Staff",
96 "Ring",
97 "CrownF",
98 "LArmor",
99 "WShield",
100 "Scroll",
101 "FPlateAr",
102 "FBook",
103 "Food",
104 "FBttleBB",
105 "FBttleDY",
106 "FBttleOR",
107 "FBttleBR",
108 "FBttleBL",
109 "FBttleBY",
110 "FBttleWH",
111 "FBttleDB",
112 "FEar",
113 "FBrain",
114 "FMush",
115 "Innsign",
116 "Bldstn",
117 "Fanvil",
118 "FLazStaf",
119 "bombs1",
120 "halfps1",
121 "wholeps1",
122 "runes1",
123 "teddys1",
124 "cows1",
125 "donkys1",
126 "mooses1",
127 };
128 /** Maps of item drop animation length. */
129 BYTE ItemAnimLs[] = {
130 15,
131 13,
132 16,
133 13,
134 10,
135 13,
136 13,
137 13,
138 13,
139 10,
140 13,
141 13,
142 13,
143 13,
144 13,
145 13,
146 13,
147 13,
148 13,
149 1,
150 16,
151 16,
152 16,
153 16,
154 16,
155 16,
156 16,
157 16,
158 13,
159 12,
160 12,
161 13,
162 13,
163 13,
164 8,
165 10,
166 16,
167 16,
168 10,
169 10,
170 15,
171 15,
172 15,
173 };
174 /** Maps of drop sounds effect of dropping the item on ground. */
175 int ItemDropSnds[] = {
176 IS_FHARM,
177 IS_FAXE,
178 IS_FPOT,
179 IS_FBOW,
180 IS_GOLD,
181 IS_FCAP,
182 IS_FSWOR,
183 IS_FSHLD,
184 IS_FSWOR,
185 IS_FROCK,
186 IS_FAXE,
187 IS_FSTAF,
188 IS_FRING,
189 IS_FCAP,
190 IS_FLARM,
191 IS_FSHLD,
192 IS_FSCRL,
193 IS_FHARM,
194 IS_FBOOK,
195 IS_FLARM,
196 IS_FPOT,
197 IS_FPOT,
198 IS_FPOT,
199 IS_FPOT,
200 IS_FPOT,
201 IS_FPOT,
202 IS_FPOT,
203 IS_FPOT,
204 IS_FBODY,
205 IS_FBODY,
206 IS_FMUSH,
207 IS_ISIGN,
208 IS_FBLST,
209 IS_FANVL,
210 IS_FSTAF,
211 IS_FROCK,
212 IS_FSCRL,
213 IS_FSCRL,
214 IS_FROCK,
215 IS_FMUSH,
216 IS_FHARM,
217 IS_FLARM,
218 IS_FLARM,
219 };
220 /** Maps of drop sounds effect of placing the item in the inventory. */
221 int ItemInvSnds[] = {
222 IS_IHARM,
223 IS_IAXE,
224 IS_IPOT,
225 IS_IBOW,
226 IS_GOLD,
227 IS_ICAP,
228 IS_ISWORD,
229 IS_ISHIEL,
230 IS_ISWORD,
231 IS_IROCK,
232 IS_IAXE,
233 IS_ISTAF,
234 IS_IRING,
235 IS_ICAP,
236 IS_ILARM,
237 IS_ISHIEL,
238 IS_ISCROL,
239 IS_IHARM,
240 IS_IBOOK,
241 IS_IHARM,
242 IS_IPOT,
243 IS_IPOT,
244 IS_IPOT,
245 IS_IPOT,
246 IS_IPOT,
247 IS_IPOT,
248 IS_IPOT,
249 IS_IPOT,
250 IS_IBODY,
251 IS_IBODY,
252 IS_IMUSH,
253 IS_ISIGN,
254 IS_IBLST,
255 IS_IANVL,
256 IS_ISTAF,
257 IS_IROCK,
258 IS_ISCROL,
259 IS_ISCROL,
260 IS_IROCK,
261 IS_IMUSH,
262 IS_IHARM,
263 IS_ILARM,
264 IS_ILARM,
265 };
266 /** Specifies the current Y-coordinate used for validation of items on ground. */
267 int idoppely = 16;
268 /** Maps from Griswold premium item number to a quality level delta as added to the base quality level. */
269 int premiumlvladd[] = {
270 // clang-format off
271 -1,
272 -1,
273 0,
274 0,
275 1,
276 2,
277 // clang-format on
278 };
279 /** Maps from Griswold premium item number to a quality level delta as added to the base quality level. */
280 int premiumLvlAddHellfire[] = {
281 // clang-format off
282 -1,
283 -1,
284 -1,
285 0,
286 0,
287 0,
288 0,
289 1,
290 1,
291 1,
292 1,
293 2,
294 2,
295 3,
296 3,
297 // clang-format on
298 };
299
IsItemAvailable(int i)300 bool IsItemAvailable(int i)
301 {
302 if (gbIsHellfire)
303 return true;
304 return (
305 i != IDI_MAPOFDOOM // Cathedral Map
306 && i != IDI_LGTFORGE // Bovine Plate
307 && (i < IDI_OIL || i > IDI_GREYSUIT) // Hellfire exclusive items
308 && (i < 83 || i > 86) // Oils
309 && i != 92 // Scroll of Search
310 && (i < 161 || i > 165) // Runes
311 && i != IDI_SORCERER // Short Staff of Mana
312 )
313 || (
314 // Bard items are technically Hellfire-exclusive
315 // but are just normal items with adjusted stats.
316 sgOptions.Gameplay.bTestBard && (i == IDI_BARDSWORD || i == IDI_BARDDAGGER));
317 }
318
IsUniqueAvailable(int i)319 bool IsUniqueAvailable(int i)
320 {
321 return gbIsHellfire || i <= 89;
322 }
323
IsPrefixValidForItemType(int i,int flgs)324 static bool IsPrefixValidForItemType(int i, int flgs)
325 {
326 int PLIType = PL_Prefix[i].PLIType;
327
328 if (!gbIsHellfire) {
329 if (i > 82)
330 return false;
331
332 if (i >= 12 && i <= 20)
333 PLIType &= ~PLT_STAFF;
334 }
335
336 return (flgs & PLIType) != 0;
337 }
338
IsSuffixValidForItemType(int i,int flgs)339 static bool IsSuffixValidForItemType(int i, int flgs)
340 {
341 int PLIType = PL_Suffix[i].PLIType;
342
343 if (!gbIsHellfire) {
344 if (i > 94)
345 return false;
346
347 if ((i >= 0 && i <= 1)
348 || (i >= 14 && i <= 15)
349 || (i >= 21 && i <= 22)
350 || (i >= 34 && i <= 36)
351 || (i >= 41 && i <= 44)
352 || (i >= 60 && i <= 63))
353 PLIType &= ~PLT_STAFF;
354 }
355
356 return (flgs & PLIType) != 0;
357 }
358
get_ring_max_value(int i)359 int get_ring_max_value(int i)
360 {
361 int j, res;
362
363 res = 0;
364 for (j = 0; j < NUM_INVLOC; j++) {
365 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_RING && res < plr[i].InvBody[j]._iIvalue)
366 res = plr[i].InvBody[j]._iIvalue;
367 }
368 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
369 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_RING && res < plr[i].InvList[j]._iIvalue)
370 res = plr[i].InvList[j]._iIvalue;
371 }
372
373 return res;
374 }
375
get_bow_max_value(int i)376 int get_bow_max_value(int i)
377 {
378 int j, res;
379
380 res = 0;
381 for (j = 0; j < NUM_INVLOC; j++) {
382 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_BOW && res < plr[i].InvBody[j]._iIvalue)
383 res = plr[i].InvBody[j]._iIvalue;
384 }
385 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
386 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_BOW && res < plr[i].InvList[j]._iIvalue)
387 res = plr[i].InvList[j]._iIvalue;
388 }
389
390 return res;
391 }
392
get_staff_max_value(int i)393 int get_staff_max_value(int i)
394 {
395 int j, res;
396
397 res = 0;
398 for (j = 0; j < NUM_INVLOC; j++) {
399 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_STAFF && res < plr[i].InvBody[j]._iIvalue)
400 res = plr[i].InvBody[j]._iIvalue;
401 }
402 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
403 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_STAFF && res < plr[i].InvList[j]._iIvalue)
404 res = plr[i].InvList[j]._iIvalue;
405 }
406
407 return res;
408 }
409
get_sword_max_value(int i)410 int get_sword_max_value(int i)
411 {
412 int j, res;
413
414 res = 0;
415 for (j = 0; j < NUM_INVLOC; j++) {
416 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_SWORD && res < plr[i].InvBody[j]._iIvalue)
417 res = plr[i].InvBody[j]._iIvalue;
418 }
419 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
420 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_SWORD && res < plr[i].InvList[j]._iIvalue)
421 res = plr[i].InvList[j]._iIvalue;
422 }
423
424 return res;
425 }
426
get_helm_max_value(int i)427 int get_helm_max_value(int i)
428 {
429 int j, res;
430
431 res = 0;
432 for (j = 0; j < NUM_INVLOC; j++) {
433 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_HELM && res < plr[i].InvBody[j]._iIvalue)
434 res = plr[i].InvBody[j]._iIvalue;
435 }
436 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
437 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_HELM && res < plr[i].InvList[j]._iIvalue)
438 res = plr[i].InvList[j]._iIvalue;
439 }
440
441 return res;
442 }
443
get_shield_max_value(int i)444 int get_shield_max_value(int i)
445 {
446 int j, res;
447
448 res = 0;
449 for (j = 0; j < NUM_INVLOC; j++) {
450 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_SHIELD && res < plr[i].InvBody[j]._iIvalue)
451 res = plr[i].InvBody[j]._iIvalue;
452 }
453 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
454 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_SHIELD && res < plr[i].InvList[j]._iIvalue)
455 res = plr[i].InvList[j]._iIvalue;
456 }
457
458 return res;
459 }
460
get_armor_max_value(int i)461 int get_armor_max_value(int i)
462 {
463 int j, res;
464
465 res = 0;
466 for (j = 0; j < NUM_INVLOC; j++) {
467 if (plr[i].InvBody[j]._iClass != ICLASS_NONE
468 && (plr[i].InvBody[j]._itype == ITYPE_LARMOR || plr[i].InvBody[j]._itype == ITYPE_MARMOR || plr[i].InvBody[j]._itype == ITYPE_HARMOR)
469 && res < plr[i].InvBody[j]._iIvalue)
470 res = plr[i].InvBody[j]._iIvalue;
471 }
472 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
473 if (plr[i].InvList[j]._iClass != ICLASS_NONE
474 && (plr[i].InvList[j]._itype == ITYPE_LARMOR || plr[i].InvList[j]._itype == ITYPE_MARMOR || plr[i].InvList[j]._itype == ITYPE_HARMOR)
475 && res < plr[i].InvList[j]._iIvalue)
476 res = plr[i].InvList[j]._iIvalue;
477 }
478
479 return res;
480 }
481
get_mace_max_value(int i)482 int get_mace_max_value(int i)
483 {
484 int j, res;
485
486 res = 0;
487 for (j = 0; j < NUM_INVLOC; j++) {
488 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_MACE && res < plr[i].InvBody[j]._iIvalue)
489 res = plr[i].InvBody[j]._iIvalue;
490 }
491 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
492 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_MACE && res < plr[i].InvList[j]._iIvalue)
493 res = plr[i].InvList[j]._iIvalue;
494 }
495
496 return res;
497 }
498
get_amulet_max_value(int i)499 int get_amulet_max_value(int i)
500 {
501 int j, res;
502
503 res = 0;
504 for (j = 0; j < NUM_INVLOC; j++) {
505 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_AMULET && res < plr[i].InvBody[j]._iIvalue)
506 res = plr[i].InvBody[j]._iIvalue;
507 }
508 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
509 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_AMULET && res < plr[i].InvList[j]._iIvalue)
510 res = plr[i].InvList[j]._iIvalue;
511 }
512
513 return res;
514 }
515
get_axe_max_value(int i)516 int get_axe_max_value(int i)
517 {
518 int j, res;
519
520 res = 0;
521 for (j = 0; j < NUM_INVLOC; j++) {
522 if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_AXE && res < plr[i].InvBody[j]._iIvalue)
523 res = plr[i].InvBody[j]._iIvalue;
524 }
525 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
526 if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_AXE && res < plr[i].InvList[j]._iIvalue)
527 res = plr[i].InvList[j]._iIvalue;
528 }
529
530 return res;
531 }
532
items_get_currlevel()533 int items_get_currlevel()
534 {
535 int lvl;
536
537 lvl = currlevel;
538 if (currlevel >= 17 && currlevel <= 20)
539 lvl = currlevel - 8;
540 if (currlevel >= 21 && currlevel <= 24)
541 lvl = currlevel - 7;
542
543 return lvl;
544 }
545
InitItemGFX()546 void InitItemGFX()
547 {
548 char arglist[64];
549
550 int itemTypes = gbIsHellfire ? ITEMTYPES : 35;
551 for (int i = 0; i < itemTypes; i++) {
552 sprintf(arglist, "Items\\%s.CEL", ItemDropNames[i]);
553 itemanims[i] = LoadFileInMem(arglist, NULL);
554 }
555 memset(UniqueItemFlag, 0, sizeof(UniqueItemFlag));
556 }
557
ItemPlace(int xp,int yp)558 BOOL ItemPlace(int xp, int yp)
559 {
560 if (dMonster[xp][yp] != 0)
561 return FALSE;
562 if (dPlayer[xp][yp] != 0)
563 return FALSE;
564 if (dItem[xp][yp] != 0)
565 return FALSE;
566 if (dObject[xp][yp] != 0)
567 return FALSE;
568 if (dFlags[xp][yp] & BFLAG_POPULATED)
569 return FALSE;
570 if (nSolidTable[dPiece[xp][yp]])
571 return FALSE;
572
573 return TRUE;
574 }
575
AddInitItems()576 void AddInitItems()
577 {
578 int x, y, j, rnd;
579
580 int curlv = items_get_currlevel();
581 rnd = random_(11, 3) + 3;
582 for (j = 0; j < rnd; j++) {
583 int ii = AllocateItem();
584
585 x = random_(12, 80) + 16;
586 y = random_(12, 80) + 16;
587 while (!ItemPlace(x, y)) {
588 x = random_(12, 80) + 16;
589 y = random_(12, 80) + 16;
590 }
591 item[ii]._ix = x;
592 item[ii]._iy = y;
593
594 dItem[x][y] = ii + 1;
595
596 item[ii]._iSeed = AdvanceRndSeed();
597 SetRndSeed(item[ii]._iSeed);
598
599 if (random_(12, 2) != 0)
600 GetItemAttrs(ii, IDI_HEAL, curlv);
601 else
602 GetItemAttrs(ii, IDI_MANA, curlv);
603
604 item[ii]._iCreateInfo = curlv | CF_PREGEN;
605 SetupItem(ii);
606 item[ii]._iAnimFrame = item[ii]._iAnimLen;
607 item[ii]._iAnimFlag = FALSE;
608 item[ii]._iSelFlag = 1;
609 DeltaAddItem(ii);
610 }
611 }
612
items_42390F()613 static void items_42390F()
614 {
615 int x, y, id;
616
617 x = random_(12, 80) + 16;
618 y = random_(12, 80) + 16;
619 while (!ItemPlace(x, y)) {
620 x = random_(12, 80) + 16;
621 y = random_(12, 80) + 16;
622 }
623 switch (currlevel) {
624 case 22:
625 id = IDI_NOTE2;
626 break;
627 case 23:
628 id = IDI_NOTE3;
629 break;
630 default:
631 id = IDI_NOTE1;
632 break;
633 }
634 SpawnQuestItem(id, x, y, 0, 1);
635 }
636
InitItems()637 void InitItems()
638 {
639 int i;
640
641 memset(&item[0], 0, sizeof(*item));
642 GetItemAttrs(0, IDI_GOLD, 1);
643 golditem = item[0];
644 golditem._iStatFlag = TRUE;
645 numitems = 0;
646
647 for (i = 0; i < MAXITEMS; i++) {
648 item[i]._itype = ITYPE_NONE;
649 item[i]._ix = 0;
650 item[i]._iy = 0;
651 item[i]._iAnimFlag = FALSE;
652 item[i]._iSelFlag = 0;
653 item[i]._iIdentified = FALSE;
654 item[i]._iPostDraw = FALSE;
655 }
656
657 for (i = 0; i < MAXITEMS; i++) {
658 itemavail[i] = i;
659 itemactive[i] = 0;
660 }
661
662 if (!setlevel) {
663 AdvanceRndSeed(); /* unused */
664 if (QuestStatus(Q_ROCK))
665 SpawnRock();
666 if (QuestStatus(Q_ANVIL))
667 SpawnQuestItem(IDI_ANVIL, 2 * setpc_x + 27, 2 * setpc_y + 27, 0, 1);
668 if (gbCowQuest && currlevel == 20)
669 SpawnQuestItem(IDI_BROWNSUIT, 25, 25, 3, 1);
670 if (gbCowQuest && currlevel == 19)
671 SpawnQuestItem(IDI_GREYSUIT, 25, 25, 3, 1);
672 if (currlevel > 0 && currlevel < 16)
673 AddInitItems();
674 if (currlevel >= 21 && currlevel <= 23)
675 items_42390F();
676 }
677
678 uitemflag = FALSE;
679 }
680
CalcPlrItemVals(int p,BOOL Loadgfx)681 void CalcPlrItemVals(int p, BOOL Loadgfx)
682 {
683 int pvid, d;
684
685 int mind = 0; // min damage
686 int maxd = 0; // max damage
687 int tac = 0; // accuracy
688
689 int g;
690 int i;
691 int mi;
692
693 int bdam = 0; // bonus damage
694 int btohit = 0; // bonus chance to hit
695 int bac = 0; // bonus accuracy
696
697 int iflgs = ISPL_NONE; // item_special_effect flags
698
699 int pDamAcFlags = 0;
700
701 int sadd = 0; // added strength
702 int madd = 0; // added magic
703 int dadd = 0; // added dexterity
704 int vadd = 0; // added vitality
705
706 Uint64 spl = 0; // bitarray for all enabled/active spells
707
708 int fr = 0; // fire resistance
709 int lr = 0; // lightning resistance
710 int mr = 0; // magic resistance
711
712 int dmod = 0; // bonus damage mod?
713 int ghit = 0; // increased damage from enemies
714
715 int lrad = 10; // light radius
716
717 int ihp = 0; // increased HP
718 int imana = 0; // increased mana
719
720 int spllvladd = 0; // increased spell level
721 int enac = 0; // enhanced accuracy
722
723 int fmin = 0; // minimum fire damage
724 int fmax = 0; // maximum fire damage
725 int lmin = 0; // minimum lightning damage
726 int lmax = 0; // maximum lightning damage
727
728 for (i = 0; i < NUM_INVLOC; i++) {
729 ItemStruct *itm = &plr[p].InvBody[i];
730 if (!itm->isEmpty() && itm->_iStatFlag) {
731
732 mind += itm->_iMinDam;
733 maxd += itm->_iMaxDam;
734 tac += itm->_iAC;
735
736 if (itm->_iSpell != SPL_NULL) {
737 spl |= GetSpellBitmask(itm->_iSpell);
738 }
739
740 if (itm->_iMagical == ITEM_QUALITY_NORMAL || itm->_iIdentified) {
741 bdam += itm->_iPLDam;
742 btohit += itm->_iPLToHit;
743 if (itm->_iPLAC) {
744 int tmpac = itm->_iAC;
745 tmpac *= itm->_iPLAC;
746 tmpac /= 100;
747 if (tmpac == 0)
748 tmpac = 1;
749 bac += tmpac;
750 }
751 iflgs |= itm->_iFlags;
752 pDamAcFlags |= itm->_iDamAcFlags;
753 sadd += itm->_iPLStr;
754 madd += itm->_iPLMag;
755 dadd += itm->_iPLDex;
756 vadd += itm->_iPLVit;
757 fr += itm->_iPLFR;
758 lr += itm->_iPLLR;
759 mr += itm->_iPLMR;
760 dmod += itm->_iPLDamMod;
761 ghit += itm->_iPLGetHit;
762 lrad += itm->_iPLLight;
763 ihp += itm->_iPLHP;
764 imana += itm->_iPLMana;
765 spllvladd += itm->_iSplLvlAdd;
766 enac += itm->_iPLEnAc;
767 fmin += itm->_iFMinDam;
768 fmax += itm->_iFMaxDam;
769 lmin += itm->_iLMinDam;
770 lmax += itm->_iLMaxDam;
771 }
772 }
773 }
774
775 if (mind == 0 && maxd == 0) {
776 mind = 1;
777 maxd = 1;
778
779 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
780 maxd = 3;
781 }
782
783 if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
784 maxd = 3;
785 }
786
787 if (plr[p]._pClass == PC_MONK) {
788 mind = std::max(mind, plr[p]._pLevel >> 1);
789 maxd = std::max(maxd, (int)plr[p]._pLevel);
790 }
791 }
792
793 if ((plr[p]._pSpellFlags & 2) == 2) {
794 sadd += 2 * plr[p]._pLevel;
795 dadd += plr[p]._pLevel + plr[p]._pLevel / 2;
796 vadd += 2 * plr[p]._pLevel;
797 }
798 if ((plr[p]._pSpellFlags & 4) == 4) {
799 sadd -= 2 * plr[p]._pLevel;
800 dadd -= plr[p]._pLevel + plr[p]._pLevel / 2;
801 vadd -= 2 * plr[p]._pLevel;
802 }
803
804 plr[p]._pIMinDam = mind;
805 plr[p]._pIMaxDam = maxd;
806 plr[p]._pIAC = tac;
807 plr[p]._pIBonusDam = bdam;
808 plr[p]._pIBonusToHit = btohit;
809 plr[p]._pIBonusAC = bac;
810 plr[p]._pIFlags = iflgs;
811 plr[p].pDamAcFlags = pDamAcFlags;
812 plr[p]._pIBonusDamMod = dmod;
813 plr[p]._pIGetHit = ghit;
814
815 if (lrad < 2) {
816 lrad = 2;
817 }
818 if (lrad > 15) {
819 lrad = 15;
820 }
821
822 if (plr[p]._pLightRad != lrad && p == myplr) {
823 ChangeLightRadius(plr[p]._plid, lrad);
824 ChangeVisionRadius(plr[p]._pvid, lrad);
825 plr[p]._pLightRad = lrad;
826 }
827
828 plr[p]._pStrength = sadd + plr[p]._pBaseStr;
829 if (plr[p]._pStrength < 0) {
830 plr[p]._pStrength = 0;
831 }
832
833 plr[p]._pMagic = madd + plr[p]._pBaseMag;
834 if (plr[p]._pMagic < 0) {
835 plr[p]._pMagic = 0;
836 }
837
838 plr[p]._pDexterity = dadd + plr[p]._pBaseDex;
839 if (plr[p]._pDexterity < 0) {
840 plr[p]._pDexterity = 0;
841 }
842
843 plr[p]._pVitality = vadd + plr[p]._pBaseVit;
844 if (plr[p]._pVitality < 0) {
845 plr[p]._pVitality = 0;
846 }
847
848 if (plr[p]._pClass == PC_ROGUE) {
849 plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 200;
850 } else if (plr[p]._pClass == PC_MONK) {
851 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_STAFF) {
852 if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_STAFF && (!plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty() || !plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty())) {
853 plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 300;
854 } else {
855 plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150;
856 }
857 } else {
858 plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150;
859 }
860 } else if (plr[p]._pClass == PC_BARD) {
861 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD)
862 plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150;
863 else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_BOW) {
864 plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 250;
865 } else {
866 plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100;
867 }
868 } else if (plr[p]._pClass == PC_BARBARIAN) {
869
870 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_AXE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_AXE) {
871 plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 75;
872 } else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_MACE) {
873 plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 75;
874 } else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_BOW) {
875 plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 300;
876 } else {
877 plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100;
878 }
879
880 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) {
881 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD)
882 plr[p]._pIAC -= plr[p].InvBody[INVLOC_HAND_LEFT]._iAC / 2;
883 else if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD)
884 plr[p]._pIAC -= plr[p].InvBody[INVLOC_HAND_RIGHT]._iAC / 2;
885 } else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_BOW && plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_BOW) {
886 plr[p]._pDamageMod += plr[p]._pLevel * plr[p]._pVitality / 100;
887 }
888 plr[p]._pIAC += plr[p]._pLevel / 4;
889 } else {
890 plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100;
891 }
892
893 plr[p]._pISpells = spl;
894
895 EnsureValidReadiedSpell(plr[p]);
896
897 plr[p]._pISplLvlAdd = spllvladd;
898 plr[p]._pIEnAc = enac;
899
900 if (plr[p]._pClass == PC_BARBARIAN) {
901 mr += plr[p]._pLevel;
902 fr += plr[p]._pLevel;
903 lr += plr[p]._pLevel;
904 }
905
906 if ((plr[p]._pSpellFlags & 4) == 4) {
907 mr -= plr[p]._pLevel;
908 fr -= plr[p]._pLevel;
909 lr -= plr[p]._pLevel;
910 }
911
912 if (iflgs & ISPL_ALLRESZERO) {
913 // reset resistances to zero if the respective special effect is active
914 mr = 0;
915 fr = 0;
916 lr = 0;
917 }
918
919 if (mr > MAXRESIST)
920 mr = MAXRESIST;
921 else if (mr < 0)
922 mr = 0;
923 plr[p]._pMagResist = mr;
924
925 if (fr > MAXRESIST)
926 fr = MAXRESIST;
927 else if (fr < 0)
928 fr = 0;
929 plr[p]._pFireResist = fr;
930
931 if (lr > MAXRESIST)
932 lr = MAXRESIST;
933 else if (lr < 0)
934 lr = 0;
935 plr[p]._pLghtResist = lr;
936
937 if (plr[p]._pClass == PC_WARRIOR) {
938 vadd <<= 1;
939 } else if (plr[p]._pClass == PC_BARBARIAN) {
940 vadd += vadd;
941 vadd += (vadd >> 2);
942 } else if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD) {
943 vadd += vadd >> 1;
944 }
945 ihp += (vadd << 6); // BUGFIX: blood boil can cause negative shifts here (see line 757)
946
947 if (plr[p]._pClass == PC_SORCERER) {
948 madd <<= 1;
949 }
950 if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK) {
951 madd += madd >> 1;
952 } else if (plr[p]._pClass == PC_BARD) {
953 madd += (madd >> 2) + (madd >> 1);
954 }
955 imana += (madd << 6);
956
957 plr[p]._pHitPoints = ihp + plr[p]._pHPBase;
958 plr[p]._pMaxHP = ihp + plr[p]._pMaxHPBase;
959 if (plr[p]._pHitPoints > plr[p]._pMaxHP)
960 plr[p]._pHitPoints = plr[p]._pMaxHP;
961
962 if (p == myplr && (plr[p]._pHitPoints >> 6) <= 0) {
963 SetPlayerHitPoints(p, 0);
964 }
965
966 plr[p]._pMana = imana + plr[p]._pManaBase;
967 plr[p]._pMaxMana = imana + plr[p]._pMaxManaBase;
968 if (plr[p]._pMana > plr[p]._pMaxMana)
969 plr[p]._pMana = plr[p]._pMaxMana;
970
971 plr[p]._pIFMinDam = fmin;
972 plr[p]._pIFMaxDam = fmax;
973 plr[p]._pILMinDam = lmin;
974 plr[p]._pILMaxDam = lmax;
975
976 if (iflgs & ISPL_INFRAVISION) {
977 plr[p]._pInfraFlag = TRUE;
978 } else {
979 plr[p]._pInfraFlag = FALSE;
980 }
981
982 plr[p]._pBlockFlag = FALSE;
983 if (plr[p]._pClass == PC_MONK) {
984 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
985 plr[p]._pBlockFlag = TRUE;
986 plr[p]._pIFlags |= ISPL_FASTBLOCK;
987 }
988 if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
989 plr[p]._pBlockFlag = TRUE;
990 plr[p]._pIFlags |= ISPL_FASTBLOCK;
991 }
992 if (plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty())
993 plr[p]._pBlockFlag = TRUE;
994 if (plr[p].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[p].InvBody[INVLOC_HAND_LEFT]._iLoc != ILOC_TWOHAND && plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty())
995 plr[p]._pBlockFlag = TRUE;
996 if (plr[p].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[p].InvBody[INVLOC_HAND_RIGHT]._iLoc != ILOC_TWOHAND && plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty())
997 plr[p]._pBlockFlag = TRUE;
998 }
999 plr[p]._pwtype = WT_MELEE;
1000
1001 g = 0;
1002
1003 if (!plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty()
1004 && plr[p].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON
1005 && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
1006 g = plr[p].InvBody[INVLOC_HAND_LEFT]._itype;
1007 }
1008
1009 if (!plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty()
1010 && plr[p].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON
1011 && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
1012 g = plr[p].InvBody[INVLOC_HAND_RIGHT]._itype;
1013 }
1014
1015 switch (g) {
1016 case ITYPE_SWORD:
1017 g = ANIM_ID_SWORD;
1018 break;
1019 case ITYPE_AXE:
1020 g = ANIM_ID_AXE;
1021 break;
1022 case ITYPE_BOW:
1023 plr[p]._pwtype = WT_RANGED;
1024 g = ANIM_ID_BOW;
1025 break;
1026 case ITYPE_MACE:
1027 g = ANIM_ID_MACE;
1028 break;
1029 case ITYPE_STAFF:
1030 g = ANIM_ID_STAFF;
1031 break;
1032 }
1033
1034 if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
1035 plr[p]._pBlockFlag = TRUE;
1036 g++;
1037 }
1038 if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
1039 plr[p]._pBlockFlag = TRUE;
1040 g++;
1041 }
1042
1043 if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_HARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) {
1044 if (plr[p]._pClass == PC_MONK && plr[p].InvBody[INVLOC_CHEST]._iMagical == ITEM_QUALITY_UNIQUE)
1045 plr[p]._pIAC += plr[p]._pLevel >> 1;
1046 g += ANIM_ID_HEAVY_ARMOR;
1047 } else if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_MARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) {
1048 if (plr[p]._pClass == PC_MONK) {
1049 if (plr[p].InvBody[INVLOC_CHEST]._iMagical == ITEM_QUALITY_UNIQUE)
1050 plr[p]._pIAC += plr[p]._pLevel << 1;
1051 else
1052 plr[p]._pIAC += plr[p]._pLevel >> 1;
1053 }
1054 g += ANIM_ID_MEDIUM_ARMOR;
1055 } else if (plr[p]._pClass == PC_MONK) {
1056 plr[p]._pIAC += plr[p]._pLevel << 1;
1057 }
1058
1059 if (plr[p]._pgfxnum != g && Loadgfx) {
1060 plr[p]._pgfxnum = g;
1061 plr[p]._pGFXLoad = 0;
1062 LoadPlrGFX(p, PFILE_STAND);
1063 SetPlrAnims(p);
1064
1065 d = plr[p]._pdir;
1066
1067 assert(plr[p]._pNAnim[d]);
1068 plr[p]._pAnimData = plr[p]._pNAnim[d];
1069
1070 plr[p]._pAnimLen = plr[p]._pNFrames;
1071 plr[p]._pAnimFrame = 1;
1072 plr[p]._pAnimCnt = 0;
1073 plr[p]._pAnimDelay = 3;
1074 plr[p]._pAnimWidth = plr[p]._pNWidth;
1075 plr[p]._pAnimWidth2 = (plr[p]._pNWidth - 64) >> 1;
1076 } else {
1077 plr[p]._pgfxnum = g;
1078 }
1079
1080 for (i = 0; i < nummissiles; i++) {
1081 mi = missileactive[i];
1082 if (missile[mi]._mitype == MIS_MANASHIELD && missile[mi]._misource == p) {
1083 missile[mi]._miVar1 = plr[p]._pHitPoints;
1084 missile[mi]._miVar2 = plr[p]._pHPBase;
1085 break;
1086 }
1087 }
1088 if (plr[p].InvBody[INVLOC_AMULET].isEmpty() || plr[p].InvBody[INVLOC_AMULET].IDidx != IDI_AURIC) {
1089 int half = MaxGold;
1090 MaxGold = GOLD_MAX_LIMIT;
1091
1092 if (half != MaxGold)
1093 StripTopGold(p);
1094 } else {
1095 MaxGold = GOLD_MAX_LIMIT * 2;
1096 }
1097
1098 drawmanaflag = TRUE;
1099 drawhpflag = TRUE;
1100 }
1101
CalcPlrScrolls(int p)1102 void CalcPlrScrolls(int p)
1103 {
1104 int i, j;
1105
1106 plr[p]._pScrlSpells = 0;
1107 for (i = 0; i < plr[p]._pNumInv; i++) {
1108 if (!plr[p].InvList[i].isEmpty() && (plr[p].InvList[i]._iMiscId == IMISC_SCROLL || plr[p].InvList[i]._iMiscId == IMISC_SCROLLT)) {
1109 if (plr[p].InvList[i]._iStatFlag)
1110 plr[p]._pScrlSpells |= GetSpellBitmask(plr[p].InvList[i]._iSpell);
1111 }
1112 }
1113
1114 for (j = 0; j < MAXBELTITEMS; j++) {
1115 if (!plr[p].SpdList[j].isEmpty() && (plr[p].SpdList[j]._iMiscId == IMISC_SCROLL || plr[p].SpdList[j]._iMiscId == IMISC_SCROLLT)) {
1116 if (plr[p].SpdList[j]._iStatFlag)
1117 plr[p]._pScrlSpells |= GetSpellBitmask(plr[p].SpdList[j]._iSpell);
1118 }
1119 }
1120 EnsureValidReadiedSpell(plr[p]);
1121 }
1122
CalcPlrStaff(int p)1123 void CalcPlrStaff(int p)
1124 {
1125 plr[p]._pISpells = 0;
1126 if (!plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty()
1127 && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag
1128 && plr[p].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) {
1129 plr[p]._pISpells |= GetSpellBitmask(plr[p].InvBody[INVLOC_HAND_LEFT]._iSpell);
1130 }
1131 }
1132
CalcSelfItems(int pnum)1133 void CalcSelfItems(int pnum)
1134 {
1135 int i;
1136 PlayerStruct *p;
1137 ItemStruct *pi;
1138 BOOL sf, changeflag;
1139 int sa, ma, da;
1140
1141 p = &plr[pnum];
1142
1143 sa = 0;
1144 ma = 0;
1145 da = 0;
1146 pi = p->InvBody;
1147 for (i = 0; i < NUM_INVLOC; i++, pi++) {
1148 if (!pi->isEmpty()) {
1149 pi->_iStatFlag = TRUE;
1150 if (pi->_iIdentified) {
1151 sa += pi->_iPLStr;
1152 ma += pi->_iPLMag;
1153 da += pi->_iPLDex;
1154 }
1155 }
1156 }
1157 do {
1158 changeflag = FALSE;
1159 pi = p->InvBody;
1160 for (i = 0; i < NUM_INVLOC; i++, pi++) {
1161 if (!pi->isEmpty() && pi->_iStatFlag) {
1162 sf = TRUE;
1163 if (sa + p->_pBaseStr < pi->_iMinStr)
1164 sf = FALSE;
1165 if (ma + p->_pBaseMag < pi->_iMinMag)
1166 sf = FALSE;
1167 if (da + p->_pBaseDex < pi->_iMinDex)
1168 sf = FALSE;
1169 if (!sf) {
1170 changeflag = TRUE;
1171 pi->_iStatFlag = FALSE;
1172 if (pi->_iIdentified) {
1173 sa -= pi->_iPLStr;
1174 ma -= pi->_iPLMag;
1175 da -= pi->_iPLDex;
1176 }
1177 }
1178 }
1179 }
1180 } while (changeflag);
1181 }
1182
ItemMinStats(PlayerStruct * p,ItemStruct * x)1183 static BOOL ItemMinStats(PlayerStruct *p, ItemStruct *x)
1184 {
1185 if (p->_pMagic < x->_iMinMag)
1186 return FALSE;
1187
1188 if (p->_pStrength < x->_iMinStr)
1189 return FALSE;
1190
1191 if (p->_pDexterity < x->_iMinDex)
1192 return FALSE;
1193
1194 return TRUE;
1195 }
1196
CalcPlrItemMin(int pnum)1197 void CalcPlrItemMin(int pnum)
1198 {
1199 PlayerStruct *p;
1200 ItemStruct *pi;
1201 int i;
1202
1203 p = &plr[pnum];
1204 pi = p->InvList;
1205 i = p->_pNumInv;
1206
1207 while (i--) {
1208 pi->_iStatFlag = ItemMinStats(p, pi);
1209 pi++;
1210 }
1211
1212 pi = p->SpdList;
1213 for (i = MAXBELTITEMS; i != 0; i--) {
1214 if (!pi->isEmpty()) {
1215 pi->_iStatFlag = ItemMinStats(p, pi);
1216 }
1217 pi++;
1218 }
1219 }
1220
CalcPlrBookVals(int p)1221 void CalcPlrBookVals(int p)
1222 {
1223 int i, slvl;
1224
1225 if (currlevel == 0) {
1226 for (i = 1; !witchitem[i].isEmpty(); i++) {
1227 WitchBookLevel(i);
1228 witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]);
1229 }
1230 }
1231
1232 for (i = 0; i < plr[p]._pNumInv; i++) {
1233 if (plr[p].InvList[i]._itype == ITYPE_MISC && plr[p].InvList[i]._iMiscId == IMISC_BOOK) {
1234 plr[p].InvList[i]._iMinMag = spelldata[plr[p].InvList[i]._iSpell].sMinInt;
1235 slvl = plr[p]._pSplLvl[plr[p].InvList[i]._iSpell];
1236
1237 while (slvl != 0) {
1238 plr[p].InvList[i]._iMinMag += 20 * plr[p].InvList[i]._iMinMag / 100;
1239 slvl--;
1240 if (plr[p].InvList[i]._iMinMag + 20 * plr[p].InvList[i]._iMinMag / 100 > 255) {
1241 plr[p].InvList[i]._iMinMag = 255;
1242 slvl = 0;
1243 }
1244 }
1245 plr[p].InvList[i]._iStatFlag = ItemMinStats(&plr[p], &plr[p].InvList[i]);
1246 }
1247 }
1248 }
1249
CalcPlrInv(int p,BOOL Loadgfx)1250 void CalcPlrInv(int p, BOOL Loadgfx)
1251 {
1252 CalcPlrItemMin(p);
1253 CalcSelfItems(p);
1254 CalcPlrItemVals(p, Loadgfx);
1255 CalcPlrItemMin(p);
1256 if (p == myplr) {
1257 CalcPlrBookVals(p);
1258 CalcPlrScrolls(p);
1259 CalcPlrStaff(p);
1260 if (p == myplr && currlevel == 0)
1261 RecalcStoreStats();
1262 }
1263 }
1264
SetPlrHandItem(ItemStruct * h,int idata)1265 void SetPlrHandItem(ItemStruct *h, int idata)
1266 {
1267 ItemDataStruct *pAllItem;
1268
1269 pAllItem = &AllItemsList[idata];
1270
1271 // zero-initialize struct
1272 memset(h, 0, sizeof(*h));
1273
1274 h->_itype = pAllItem->itype;
1275 h->_iCurs = pAllItem->iCurs;
1276 strcpy(h->_iName, pAllItem->iName);
1277 strcpy(h->_iIName, pAllItem->iName);
1278 h->_iLoc = pAllItem->iLoc;
1279 h->_iClass = pAllItem->iClass;
1280 h->_iMinDam = pAllItem->iMinDam;
1281 h->_iMaxDam = pAllItem->iMaxDam;
1282 h->_iAC = pAllItem->iMinAC;
1283 h->_iMiscId = pAllItem->iMiscId;
1284 h->_iSpell = pAllItem->iSpell;
1285
1286 if (pAllItem->iMiscId == IMISC_STAFF) {
1287 h->_iCharges = gbIsHellfire ? 18 : 40;
1288 }
1289
1290 h->_iMaxCharges = h->_iCharges;
1291 h->_iDurability = pAllItem->iDurability;
1292 h->_iMaxDur = pAllItem->iDurability;
1293 h->_iMinStr = pAllItem->iMinStr;
1294 h->_iMinMag = pAllItem->iMinMag;
1295 h->_iMinDex = pAllItem->iMinDex;
1296 h->_ivalue = pAllItem->iValue;
1297 h->_iIvalue = pAllItem->iValue;
1298 h->_iPrePower = IPL_INVALID;
1299 h->_iSufPower = IPL_INVALID;
1300 h->_iMagical = ITEM_QUALITY_NORMAL;
1301 h->IDidx = idata;
1302 if (gbIsHellfire)
1303 h->dwBuff |= CF_HELLFIRE;
1304 }
1305
GetPlrHandSeed(ItemStruct * h)1306 void GetPlrHandSeed(ItemStruct *h)
1307 {
1308 h->_iSeed = AdvanceRndSeed();
1309 }
1310
1311 /**
1312 * @brief Set a new unique seed value on the given item
1313 * @param pnum Player id
1314 * @param h Item to update
1315 */
GetGoldSeed(int pnum,ItemStruct * h)1316 void GetGoldSeed(int pnum, ItemStruct *h)
1317 {
1318 int i, ii, s;
1319 BOOL doneflag;
1320
1321 do {
1322 doneflag = TRUE;
1323 s = AdvanceRndSeed();
1324 for (i = 0; i < numitems; i++) {
1325 ii = itemactive[i];
1326 if (item[ii]._iSeed == s)
1327 doneflag = FALSE;
1328 }
1329 if (pnum == myplr) {
1330 for (i = 0; i < plr[pnum]._pNumInv; i++) {
1331 if (plr[pnum].InvList[i]._iSeed == s)
1332 doneflag = FALSE;
1333 }
1334 }
1335 } while (!doneflag);
1336
1337 h->_iSeed = s;
1338 }
1339
SetPlrHandSeed(ItemStruct * h,int iseed)1340 void SetPlrHandSeed(ItemStruct *h, int iseed)
1341 {
1342 h->_iSeed = iseed;
1343 }
1344
GetGoldCursor(int value)1345 int GetGoldCursor(int value)
1346 {
1347 if (value >= GOLD_MEDIUM_LIMIT)
1348 return ICURS_GOLD_LARGE;
1349
1350 if (value <= GOLD_SMALL_LIMIT)
1351 return ICURS_GOLD_SMALL;
1352
1353 return ICURS_GOLD_MEDIUM;
1354 }
1355
1356 /**
1357 * @brief Update the gold cursor on the given gold item
1358 * @param h The item to update
1359 */
SetPlrHandGoldCurs(ItemStruct * h)1360 void SetPlrHandGoldCurs(ItemStruct *h)
1361 {
1362 h->_iCurs = GetGoldCursor(h->_ivalue);
1363 }
1364
CreatePlrItems(int p)1365 void CreatePlrItems(int p)
1366 {
1367 int i;
1368 ItemStruct *pi = plr[p].InvBody;
1369
1370 for (i = NUM_INVLOC; i != 0; i--) {
1371 pi->_itype = ITYPE_NONE;
1372 pi++;
1373 }
1374
1375 // converting this to a for loop creates a `rep stosd` instruction,
1376 // so this probably actually was a memset
1377 memset(&plr[p].InvGrid, 0, sizeof(plr[p].InvGrid));
1378
1379 pi = plr[p].InvList;
1380 for (i = NUM_INV_GRID_ELEM; i != 0; i--) {
1381 pi->_itype = ITYPE_NONE;
1382 pi++;
1383 }
1384
1385 plr[p]._pNumInv = 0;
1386
1387 pi = &plr[p].SpdList[0];
1388 for (i = MAXBELTITEMS; i != 0; i--) {
1389 pi->_itype = ITYPE_NONE;
1390 pi++;
1391 }
1392
1393 switch (plr[p]._pClass) {
1394 case PC_WARRIOR:
1395 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_WARRIOR);
1396 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
1397
1398 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_WARRSHLD);
1399 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]);
1400
1401 #ifdef _DEBUG
1402 if (!debug_mode_key_w)
1403 #endif
1404 {
1405 SetPlrHandItem(&plr[p].HoldItem, IDI_WARRCLUB);
1406 GetPlrHandSeed(&plr[p].HoldItem);
1407 AutoPlace(p, 0, 1, 3, TRUE);
1408 }
1409
1410 SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
1411 GetPlrHandSeed(&plr[p].SpdList[0]);
1412
1413 SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
1414 GetPlrHandSeed(&plr[p].SpdList[1]);
1415 break;
1416 case PC_ROGUE:
1417 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_ROGUE);
1418 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
1419
1420 SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
1421 GetPlrHandSeed(&plr[p].SpdList[0]);
1422
1423 SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
1424 GetPlrHandSeed(&plr[p].SpdList[1]);
1425 break;
1426 case PC_SORCERER:
1427 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], gbIsHellfire ? IDI_SORCERER : 166);
1428 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
1429
1430 SetPlrHandItem(&plr[p].SpdList[0], gbIsHellfire ? IDI_HEAL : IDI_MANA);
1431 GetPlrHandSeed(&plr[p].SpdList[0]);
1432
1433 SetPlrHandItem(&plr[p].SpdList[1], gbIsHellfire ? IDI_HEAL : IDI_MANA);
1434 GetPlrHandSeed(&plr[p].SpdList[1]);
1435 break;
1436
1437 case PC_MONK:
1438 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_SHORTSTAFF);
1439 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
1440 SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
1441 GetPlrHandSeed(&plr[p].SpdList[0]);
1442
1443 SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
1444 GetPlrHandSeed(&plr[p].SpdList[1]);
1445 break;
1446 case PC_BARD:
1447 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_BARDSWORD);
1448 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
1449
1450 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_BARDDAGGER);
1451 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]);
1452 SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
1453 GetPlrHandSeed(&plr[p].SpdList[0]);
1454
1455 SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
1456 GetPlrHandSeed(&plr[p].SpdList[1]);
1457 break;
1458 case PC_BARBARIAN:
1459 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], 139); // TODO: add more enums to items
1460 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
1461
1462 SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_WARRSHLD);
1463 GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]);
1464 SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
1465 GetPlrHandSeed(&plr[p].SpdList[0]);
1466
1467 SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
1468 GetPlrHandSeed(&plr[p].SpdList[1]);
1469 break;
1470 case NUM_CLASSES:
1471 break;
1472 }
1473
1474 SetPlrHandItem(&plr[p].HoldItem, IDI_GOLD);
1475 GetPlrHandSeed(&plr[p].HoldItem);
1476
1477 #ifdef _DEBUG
1478 if (!debug_mode_key_w) {
1479 #endif
1480 plr[p].HoldItem._ivalue = 100;
1481 plr[p].HoldItem._iCurs = ICURS_GOLD_SMALL;
1482 plr[p]._pGold = plr[p].HoldItem._ivalue;
1483 plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem;
1484 plr[p].InvGrid[30] = plr[p]._pNumInv;
1485 #ifdef _DEBUG
1486 } else {
1487 plr[p].HoldItem._ivalue = GOLD_MAX_LIMIT;
1488 plr[p].HoldItem._iCurs = ICURS_GOLD_LARGE;
1489 plr[p]._pGold = plr[p].HoldItem._ivalue * 40;
1490 for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
1491 GetPlrHandSeed(&plr[p].HoldItem);
1492 plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem;
1493 plr[p].InvGrid[i] = plr[p]._pNumInv;
1494 }
1495 }
1496 #endif
1497
1498 CalcPlrItemVals(p, FALSE);
1499 }
1500
ItemSpaceOk(int i,int j)1501 BOOL ItemSpaceOk(int i, int j)
1502 {
1503 int oi;
1504
1505 // BUGFIX: Check `i + 1 >= MAXDUNX` and `j + 1 >= MAXDUNY` (applied)
1506 if (i < 0 || i + 1 >= MAXDUNX || j < 0 || j + 1 >= MAXDUNY)
1507 return FALSE;
1508
1509 if (dMonster[i][j] != 0)
1510 return FALSE;
1511
1512 if (dPlayer[i][j] != 0)
1513 return FALSE;
1514
1515 if (dItem[i][j] != 0)
1516 return FALSE;
1517
1518 if (dObject[i][j] != 0) {
1519 oi = dObject[i][j] > 0 ? dObject[i][j] - 1 : -(dObject[i][j] + 1);
1520 if (object[oi]._oSolidFlag)
1521 return FALSE;
1522 }
1523
1524 if (dObject[i + 1][j + 1] > 0 && object[dObject[i + 1][j + 1] - 1]._oSelFlag != 0)
1525 return FALSE;
1526
1527 if (dObject[i + 1][j + 1] < 0 && object[-(dObject[i + 1][j + 1] + 1)]._oSelFlag != 0)
1528 return FALSE;
1529
1530 if (dObject[i + 1][j] > 0
1531 && dObject[i][j + 1] > 0
1532 && object[dObject[i + 1][j] - 1]._oSelFlag != 0
1533 && object[dObject[i][j + 1] - 1]._oSelFlag != 0) {
1534 return FALSE;
1535 }
1536
1537 return !nSolidTable[dPiece[i][j]];
1538 }
1539
GetItemSpace(int x,int y,char inum)1540 static bool GetItemSpace(int x, int y, char inum)
1541 {
1542 int i, j, rs;
1543 int xx, yy;
1544 BOOL savail;
1545
1546 yy = 0;
1547 for (j = y - 1; j <= y + 1; j++) {
1548 xx = 0;
1549 for (i = x - 1; i <= x + 1; i++) {
1550 itemhold[xx][yy] = ItemSpaceOk(i, j);
1551 xx++;
1552 }
1553 yy++;
1554 }
1555
1556 savail = FALSE;
1557 for (j = 0; j < 3; j++) {
1558 for (i = 0; i < 3; i++) {
1559 if (itemhold[i][j])
1560 savail = TRUE;
1561 }
1562 }
1563
1564 rs = random_(13, 15) + 1;
1565
1566 if (!savail)
1567 return false;
1568
1569 xx = 0;
1570 yy = 0;
1571 while (rs > 0) {
1572 if (itemhold[xx][yy])
1573 rs--;
1574 if (rs > 0) {
1575 xx++;
1576 if (xx == 3) {
1577 xx = 0;
1578 yy++;
1579 if (yy == 3)
1580 yy = 0;
1581 }
1582 }
1583 }
1584
1585 xx += x - 1;
1586 yy += y - 1;
1587 item[inum]._ix = xx;
1588 item[inum]._iy = yy;
1589 dItem[xx][yy] = inum + 1;
1590
1591 return true;
1592 }
1593
AllocateItem()1594 int AllocateItem()
1595 {
1596 int inum = itemavail[0];
1597 itemavail[0] = itemavail[MAXITEMS - numitems - 1];
1598 itemactive[numitems] = inum;
1599 numitems++;
1600
1601 memset(&item[inum], 0, sizeof(*item));
1602
1603 return inum;
1604 }
1605
GetSuperItemSpace(int x,int y,char inum)1606 static void GetSuperItemSpace(int x, int y, char inum)
1607 {
1608 if (!GetItemSpace(x, y, inum)) {
1609 for (int k = 2; k < 50; k++) {
1610 for (int j = -k; j <= k; j++) {
1611 int yy = y + j;
1612 for (int i = -k; i <= k; i++) {
1613 int xx = i + x;
1614 if (ItemSpaceOk(xx, yy)) {
1615 item[inum]._ix = xx;
1616 item[inum]._iy = yy;
1617 dItem[xx][yy] = inum + 1;
1618 return;
1619 }
1620 }
1621 }
1622 }
1623 }
1624 }
1625
GetSuperItemLoc(int x,int y,int * xx,int * yy)1626 void GetSuperItemLoc(int x, int y, int *xx, int *yy)
1627 {
1628 int i, j, k;
1629
1630 for (k = 1; k < 50; k++) {
1631 for (j = -k; j <= k; j++) {
1632 *yy = y + j;
1633 for (i = -k; i <= k; i++) {
1634 *xx = i + x;
1635 if (ItemSpaceOk(*xx, *yy)) {
1636 return;
1637 }
1638 }
1639 }
1640 }
1641 }
1642
CalcItemValue(int i)1643 void CalcItemValue(int i)
1644 {
1645 int v;
1646
1647 v = item[i]._iVMult1 + item[i]._iVMult2;
1648 if (v > 0) {
1649 v *= item[i]._ivalue;
1650 }
1651 if (v < 0) {
1652 v = item[i]._ivalue / v;
1653 }
1654 v = item[i]._iVAdd1 + item[i]._iVAdd2 + v;
1655 if (v <= 0) {
1656 v = 1;
1657 }
1658 item[i]._iIvalue = v;
1659 }
1660
GetBookSpell(int i,int lvl)1661 void GetBookSpell(int i, int lvl)
1662 {
1663 int rv;
1664
1665 if (lvl == 0)
1666 lvl = 1;
1667
1668 int maxSpells = gbIsHellfire ? MAX_SPELLS : 37;
1669
1670 rv = random_(14, maxSpells) + 1;
1671
1672 if (gbIsSpawn && lvl > 5)
1673 lvl = 5;
1674
1675 int s = SPL_FIREBOLT;
1676 enum spell_id bs = SPL_FIREBOLT;
1677 while (rv > 0) {
1678 int sLevel = GetSpellBookLevel(static_cast<spell_id>(s));
1679 if (sLevel != -1 && lvl >= sLevel) {
1680 rv--;
1681 bs = static_cast<spell_id>(s);
1682 }
1683 s++;
1684 if (!gbIsMultiplayer) {
1685 if (s == SPL_RESURRECT)
1686 s = SPL_TELEKINESIS;
1687 }
1688 if (!gbIsMultiplayer) {
1689 if (s == SPL_HEALOTHER)
1690 s = SPL_FLARE;
1691 }
1692 if (s == maxSpells)
1693 s = 1;
1694 }
1695 strcat(item[i]._iName, spelldata[bs].sNameText);
1696 strcat(item[i]._iIName, spelldata[bs].sNameText);
1697 item[i]._iSpell = bs;
1698 item[i]._iMinMag = spelldata[bs].sMinInt;
1699 item[i]._ivalue += spelldata[bs].sBookCost;
1700 item[i]._iIvalue += spelldata[bs].sBookCost;
1701 if (spelldata[bs].sType == STYPE_FIRE)
1702 item[i]._iCurs = ICURS_BOOK_RED;
1703 else if (spelldata[bs].sType == STYPE_LIGHTNING)
1704 item[i]._iCurs = ICURS_BOOK_BLUE;
1705 else if (spelldata[bs].sType == STYPE_MAGIC)
1706 item[i]._iCurs = ICURS_BOOK_GREY;
1707 }
1708
GetStaffPower(int i,int lvl,int bs,BOOL onlygood)1709 void GetStaffPower(int i, int lvl, int bs, BOOL onlygood)
1710 {
1711 int l[256];
1712 char istr[128];
1713 int nl, j, preidx;
1714 BOOL addok;
1715 int tmp;
1716
1717 tmp = random_(15, 10);
1718 preidx = -1;
1719 if (tmp == 0 || onlygood) {
1720 nl = 0;
1721 for (j = 0; PL_Prefix[j].PLPower != IPL_INVALID; j++) {
1722 if (IsPrefixValidForItemType(j, PLT_STAFF) && PL_Prefix[j].PLMinLvl <= lvl) {
1723 addok = TRUE;
1724 if (onlygood && !PL_Prefix[j].PLOk)
1725 addok = FALSE;
1726 if (addok) {
1727 l[nl] = j;
1728 nl++;
1729 if (PL_Prefix[j].PLDouble) {
1730 l[nl] = j;
1731 nl++;
1732 }
1733 }
1734 }
1735 }
1736 if (nl != 0) {
1737 preidx = l[random_(16, nl)];
1738 sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName);
1739 strcpy(item[i]._iIName, istr);
1740 item[i]._iMagical = ITEM_QUALITY_MAGIC;
1741 SaveItemPower(
1742 i,
1743 PL_Prefix[preidx].PLPower,
1744 PL_Prefix[preidx].PLParam1,
1745 PL_Prefix[preidx].PLParam2,
1746 PL_Prefix[preidx].PLMinVal,
1747 PL_Prefix[preidx].PLMaxVal,
1748 PL_Prefix[preidx].PLMultVal);
1749 item[i]._iPrePower = PL_Prefix[preidx].PLPower;
1750 }
1751 }
1752 if (!control_WriteStringToBuffer((BYTE *)item[i]._iIName)) {
1753 strcpy(item[i]._iIName, AllItemsList[item[i].IDidx].iSName);
1754 if (preidx != -1) {
1755 sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName);
1756 strcpy(item[i]._iIName, istr);
1757 }
1758 sprintf(istr, "%s of %s", item[i]._iIName, spelldata[bs].sNameText);
1759 strcpy(item[i]._iIName, istr);
1760 if (item[i]._iMagical == ITEM_QUALITY_NORMAL)
1761 strcpy(item[i]._iName, item[i]._iIName);
1762 }
1763 CalcItemValue(i);
1764 }
1765
GetStaffSpell(int i,int lvl,BOOL onlygood)1766 void GetStaffSpell(int i, int lvl, BOOL onlygood)
1767 {
1768 int l, rv, minc, maxc, v;
1769 char istr[68];
1770
1771 if (!gbIsHellfire && random_(17, 4) == 0) {
1772 GetItemPower(i, lvl >> 1, lvl, PLT_STAFF, onlygood);
1773 } else {
1774 int maxSpells = gbIsHellfire ? MAX_SPELLS : 37;
1775 l = lvl >> 1;
1776 if (l == 0)
1777 l = 1;
1778 rv = random_(18, maxSpells) + 1;
1779
1780 if (gbIsSpawn && lvl > 10)
1781 lvl = 10;
1782
1783 int s = SPL_FIREBOLT;
1784 enum spell_id bs = SPL_NULL;
1785 while (rv > 0) {
1786 int sLevel = GetSpellStaffLevel(static_cast<spell_id>(s));
1787 if (sLevel != -1 && l >= sLevel) {
1788 rv--;
1789 bs = static_cast<spell_id>(s);
1790 }
1791 s++;
1792 if (!gbIsMultiplayer && s == SPL_RESURRECT)
1793 s = SPL_TELEKINESIS;
1794 if (!gbIsMultiplayer && s == SPL_HEALOTHER)
1795 s = SPL_FLARE;
1796 if (s == maxSpells)
1797 s = SPL_FIREBOLT;
1798 }
1799 sprintf(istr, "%s of %s", item[i]._iName, spelldata[bs].sNameText);
1800 if (!control_WriteStringToBuffer((BYTE *)istr))
1801 sprintf(istr, "Staff of %s", spelldata[bs].sNameText);
1802 strcpy(item[i]._iName, istr);
1803 strcpy(item[i]._iIName, istr);
1804
1805 minc = spelldata[bs].sStaffMin;
1806 maxc = spelldata[bs].sStaffMax - minc + 1;
1807 item[i]._iSpell = bs;
1808 item[i]._iCharges = minc + random_(19, maxc);
1809 item[i]._iMaxCharges = item[i]._iCharges;
1810
1811 item[i]._iMinMag = spelldata[bs].sMinInt;
1812 v = item[i]._iCharges * spelldata[bs].sStaffCost / 5;
1813 item[i]._ivalue += v;
1814 item[i]._iIvalue += v;
1815 GetStaffPower(i, lvl, bs, onlygood);
1816 }
1817 }
1818
GetOilType(int i,int max_lvl)1819 void GetOilType(int i, int max_lvl)
1820 {
1821 int cnt, t, j, r;
1822 char rnd[32];
1823
1824 if (!gbIsMultiplayer) {
1825 if (max_lvl == 0)
1826 max_lvl = 1;
1827 cnt = 0;
1828
1829 for (j = 0; j < (int)(sizeof(OilLevels) / sizeof(OilLevels[0])); j++) {
1830 if (OilLevels[j] <= max_lvl) {
1831 rnd[cnt] = j;
1832 cnt++;
1833 }
1834 }
1835 r = random_(165, cnt);
1836 t = rnd[r];
1837 } else {
1838 r = random_(165, 2);
1839 t = (r != 0 ? 6 : 5);
1840 }
1841 strcpy(item[i]._iName, OilNames[t]);
1842 strcpy(item[i]._iIName, OilNames[t]);
1843 item[i]._iMiscId = OilMagic[t];
1844 item[i]._ivalue = OilValues[t];
1845 item[i]._iIvalue = OilValues[t];
1846 }
1847
GetItemAttrs(int i,int idata,int lvl)1848 void GetItemAttrs(int i, int idata, int lvl)
1849 {
1850 item[i]._itype = AllItemsList[idata].itype;
1851 item[i]._iCurs = AllItemsList[idata].iCurs;
1852 strcpy(item[i]._iName, AllItemsList[idata].iName);
1853 strcpy(item[i]._iIName, AllItemsList[idata].iName);
1854 item[i]._iLoc = AllItemsList[idata].iLoc;
1855 item[i]._iClass = AllItemsList[idata].iClass;
1856 item[i]._iMinDam = AllItemsList[idata].iMinDam;
1857 item[i]._iMaxDam = AllItemsList[idata].iMaxDam;
1858 item[i]._iAC = AllItemsList[idata].iMinAC + random_(20, AllItemsList[idata].iMaxAC - AllItemsList[idata].iMinAC + 1);
1859 item[i]._iFlags = AllItemsList[idata].iFlags;
1860 item[i]._iMiscId = AllItemsList[idata].iMiscId;
1861 item[i]._iSpell = AllItemsList[idata].iSpell;
1862 item[i]._iMagical = ITEM_QUALITY_NORMAL;
1863 item[i]._ivalue = AllItemsList[idata].iValue;
1864 item[i]._iIvalue = AllItemsList[idata].iValue;
1865 item[i]._iDurability = AllItemsList[idata].iDurability;
1866 item[i]._iMaxDur = AllItemsList[idata].iDurability;
1867 item[i]._iMinStr = AllItemsList[idata].iMinStr;
1868 item[i]._iMinMag = AllItemsList[idata].iMinMag;
1869 item[i]._iMinDex = AllItemsList[idata].iMinDex;
1870 item[i].IDidx = idata;
1871 if (gbIsHellfire)
1872 item[i].dwBuff |= CF_HELLFIRE;
1873 item[i]._iPrePower = IPL_INVALID;
1874 item[i]._iSufPower = IPL_INVALID;
1875
1876 if (item[i]._iMiscId == IMISC_BOOK)
1877 GetBookSpell(i, lvl);
1878
1879 if (gbIsHellfire && item[i]._iMiscId == IMISC_OILOF)
1880 GetOilType(i, lvl);
1881
1882 if (item[i]._itype != ITYPE_GOLD)
1883 return;
1884
1885 int rndv;
1886 int itemlevel = items_get_currlevel();
1887 if (gnDifficulty == DIFF_NORMAL)
1888 rndv = 5 * itemlevel + random_(21, 10 * itemlevel);
1889 else if (gnDifficulty == DIFF_NIGHTMARE)
1890 rndv = 5 * (itemlevel + 16) + random_(21, 10 * (itemlevel + 16));
1891 else if (gnDifficulty == DIFF_HELL)
1892 rndv = 5 * (itemlevel + 32) + random_(21, 10 * (itemlevel + 32));
1893 if (leveltype == DTYPE_HELL)
1894 rndv += rndv >> 3;
1895 if (rndv > GOLD_MAX_LIMIT)
1896 rndv = GOLD_MAX_LIMIT;
1897
1898 item[i]._ivalue = rndv;
1899 SetPlrHandGoldCurs(&item[i]);
1900 }
1901
RndPL(int param1,int param2)1902 int RndPL(int param1, int param2)
1903 {
1904 return param1 + random_(22, param2 - param1 + 1);
1905 }
1906
PLVal(int pv,int p1,int p2,int minv,int maxv)1907 int PLVal(int pv, int p1, int p2, int minv, int maxv)
1908 {
1909 if (p1 == p2)
1910 return minv;
1911 if (minv == maxv)
1912 return minv;
1913 return minv + (maxv - minv) * (100 * (pv - p1) / (p2 - p1)) / 100;
1914 }
1915
SaveItemPower(int i,item_effect_type power,int param1,int param2,int minval,int maxval,int multval)1916 void SaveItemPower(int i, item_effect_type power, int param1, int param2, int minval, int maxval, int multval)
1917 {
1918 int r, r2;
1919
1920 r = RndPL(param1, param2);
1921 switch (power) {
1922 case IPL_TOHIT:
1923 item[i]._iPLToHit += r;
1924 break;
1925 case IPL_TOHIT_CURSE:
1926 item[i]._iPLToHit -= r;
1927 break;
1928 case IPL_DAMP:
1929 item[i]._iPLDam += r;
1930 break;
1931 case IPL_DAMP_CURSE:
1932 item[i]._iPLDam -= r;
1933 break;
1934 case IPL_DOPPELGANGER:
1935 item[i]._iDamAcFlags |= 16;
1936 // no break
1937 case IPL_TOHIT_DAMP:
1938 r = RndPL(param1, param2);
1939 item[i]._iPLDam += r;
1940 if (param1 == 20)
1941 r2 = RndPL(1, 5);
1942 if (param1 == 36)
1943 r2 = RndPL(6, 10);
1944 if (param1 == 51)
1945 r2 = RndPL(11, 15);
1946 if (param1 == 66)
1947 r2 = RndPL(16, 20);
1948 if (param1 == 81)
1949 r2 = RndPL(21, 30);
1950 if (param1 == 96)
1951 r2 = RndPL(31, 40);
1952 if (param1 == 111)
1953 r2 = RndPL(41, 50);
1954 if (param1 == 126)
1955 r2 = RndPL(51, 75);
1956 if (param1 == 151)
1957 r2 = RndPL(76, 100);
1958 item[i]._iPLToHit += r2;
1959 break;
1960 case IPL_TOHIT_DAMP_CURSE:
1961 item[i]._iPLDam -= r;
1962 if (param1 == 25)
1963 r2 = RndPL(1, 5);
1964 if (param1 == 50)
1965 r2 = RndPL(6, 10);
1966 item[i]._iPLToHit -= r2;
1967 break;
1968 case IPL_ACP:
1969 item[i]._iPLAC += r;
1970 break;
1971 case IPL_ACP_CURSE:
1972 item[i]._iPLAC -= r;
1973 break;
1974 case IPL_SETAC:
1975 item[i]._iAC = r;
1976 break;
1977 case IPL_AC_CURSE:
1978 item[i]._iAC -= r;
1979 break;
1980 case IPL_FIRERES:
1981 item[i]._iPLFR += r;
1982 break;
1983 case IPL_LIGHTRES:
1984 item[i]._iPLLR += r;
1985 break;
1986 case IPL_MAGICRES:
1987 item[i]._iPLMR += r;
1988 break;
1989 case IPL_ALLRES:
1990 item[i]._iPLFR += r;
1991 item[i]._iPLLR += r;
1992 item[i]._iPLMR += r;
1993 if (item[i]._iPLFR < 0)
1994 item[i]._iPLFR = 0;
1995 if (item[i]._iPLLR < 0)
1996 item[i]._iPLLR = 0;
1997 if (item[i]._iPLMR < 0)
1998 item[i]._iPLMR = 0;
1999 break;
2000 case IPL_SPLLVLADD:
2001 item[i]._iSplLvlAdd = r;
2002 break;
2003 case IPL_CHARGES:
2004 item[i]._iCharges *= param1;
2005 item[i]._iMaxCharges = item[i]._iCharges;
2006 break;
2007 case IPL_SPELL:
2008 item[i]._iSpell = static_cast<spell_id>(param1);
2009 item[i]._iCharges = param2;
2010 item[i]._iMaxCharges = param2;
2011 break;
2012 case IPL_FIREDAM:
2013 item[i]._iFlags |= ISPL_FIREDAM;
2014 item[i]._iFlags &= ~ISPL_LIGHTDAM;
2015 item[i]._iFMinDam = param1;
2016 item[i]._iFMaxDam = param2;
2017 item[i]._iLMinDam = 0;
2018 item[i]._iLMaxDam = 0;
2019 break;
2020 case IPL_LIGHTDAM:
2021 item[i]._iFlags |= ISPL_LIGHTDAM;
2022 item[i]._iFlags &= ~ISPL_FIREDAM;
2023 item[i]._iLMinDam = param1;
2024 item[i]._iLMaxDam = param2;
2025 item[i]._iFMinDam = 0;
2026 item[i]._iFMaxDam = 0;
2027 break;
2028 case IPL_STR:
2029 item[i]._iPLStr += r;
2030 break;
2031 case IPL_STR_CURSE:
2032 item[i]._iPLStr -= r;
2033 break;
2034 case IPL_MAG:
2035 item[i]._iPLMag += r;
2036 break;
2037 case IPL_MAG_CURSE:
2038 item[i]._iPLMag -= r;
2039 break;
2040 case IPL_DEX:
2041 item[i]._iPLDex += r;
2042 break;
2043 case IPL_DEX_CURSE:
2044 item[i]._iPLDex -= r;
2045 break;
2046 case IPL_VIT:
2047 item[i]._iPLVit += r;
2048 break;
2049 case IPL_VIT_CURSE:
2050 item[i]._iPLVit -= r;
2051 break;
2052 case IPL_ATTRIBS:
2053 item[i]._iPLStr += r;
2054 item[i]._iPLMag += r;
2055 item[i]._iPLDex += r;
2056 item[i]._iPLVit += r;
2057 break;
2058 case IPL_ATTRIBS_CURSE:
2059 item[i]._iPLStr -= r;
2060 item[i]._iPLMag -= r;
2061 item[i]._iPLDex -= r;
2062 item[i]._iPLVit -= r;
2063 break;
2064 case IPL_GETHIT_CURSE:
2065 item[i]._iPLGetHit += r;
2066 break;
2067 case IPL_GETHIT:
2068 item[i]._iPLGetHit -= r;
2069 break;
2070 case IPL_LIFE:
2071 item[i]._iPLHP += r << 6;
2072 break;
2073 case IPL_LIFE_CURSE:
2074 item[i]._iPLHP -= r << 6;
2075 break;
2076 case IPL_MANA:
2077 item[i]._iPLMana += r << 6;
2078 drawmanaflag = TRUE;
2079 break;
2080 case IPL_MANA_CURSE:
2081 item[i]._iPLMana -= r << 6;
2082 drawmanaflag = TRUE;
2083 break;
2084 case IPL_DUR:
2085 r2 = r * item[i]._iMaxDur / 100;
2086 item[i]._iMaxDur += r2;
2087 item[i]._iDurability += r2;
2088 break;
2089 case IPL_CRYSTALLINE:
2090 item[i]._iPLDam += 140 + r * 2;
2091 // no break
2092 case IPL_DUR_CURSE:
2093 item[i]._iMaxDur -= r * item[i]._iMaxDur / 100;
2094 if (item[i]._iMaxDur < 1)
2095 item[i]._iMaxDur = 1;
2096 item[i]._iDurability = item[i]._iMaxDur;
2097 break;
2098 case IPL_INDESTRUCTIBLE:
2099 item[i]._iDurability = DUR_INDESTRUCTIBLE;
2100 item[i]._iMaxDur = DUR_INDESTRUCTIBLE;
2101 break;
2102 case IPL_LIGHT:
2103 item[i]._iPLLight += param1;
2104 break;
2105 case IPL_LIGHT_CURSE:
2106 item[i]._iPLLight -= param1;
2107 break;
2108 case IPL_MULT_ARROWS:
2109 item[i]._iFlags |= ISPL_MULT_ARROWS;
2110 break;
2111 case IPL_FIRE_ARROWS:
2112 item[i]._iFlags |= ISPL_FIRE_ARROWS;
2113 item[i]._iFlags &= ~ISPL_LIGHT_ARROWS;
2114 item[i]._iFMinDam = param1;
2115 item[i]._iFMaxDam = param2;
2116 item[i]._iLMinDam = 0;
2117 item[i]._iLMaxDam = 0;
2118 break;
2119 case IPL_LIGHT_ARROWS:
2120 item[i]._iFlags |= ISPL_LIGHT_ARROWS;
2121 item[i]._iFlags &= ~ISPL_FIRE_ARROWS;
2122 item[i]._iLMinDam = param1;
2123 item[i]._iLMaxDam = param2;
2124 item[i]._iFMinDam = 0;
2125 item[i]._iFMaxDam = 0;
2126 break;
2127 case IPL_FIREBALL:
2128 item[i]._iFlags |= (ISPL_LIGHT_ARROWS | ISPL_FIRE_ARROWS);
2129 item[i]._iFMinDam = param1;
2130 item[i]._iFMaxDam = param2;
2131 item[i]._iLMinDam = 0;
2132 item[i]._iLMaxDam = 0;
2133 break;
2134 case IPL_THORNS:
2135 item[i]._iFlags |= ISPL_THORNS;
2136 break;
2137 case IPL_NOMANA:
2138 item[i]._iFlags |= ISPL_NOMANA;
2139 drawmanaflag = TRUE;
2140 break;
2141 case IPL_NOHEALPLR:
2142 item[i]._iFlags |= ISPL_NOHEALPLR;
2143 break;
2144 case IPL_ABSHALFTRAP:
2145 item[i]._iFlags |= ISPL_ABSHALFTRAP;
2146 break;
2147 case IPL_KNOCKBACK:
2148 item[i]._iFlags |= ISPL_KNOCKBACK;
2149 break;
2150 case IPL_3XDAMVDEM:
2151 item[i]._iFlags |= ISPL_3XDAMVDEM;
2152 break;
2153 case IPL_ALLRESZERO:
2154 item[i]._iFlags |= ISPL_ALLRESZERO;
2155 break;
2156 case IPL_NOHEALMON:
2157 item[i]._iFlags |= ISPL_NOHEALMON;
2158 break;
2159 case IPL_STEALMANA:
2160 if (param1 == 3)
2161 item[i]._iFlags |= ISPL_STEALMANA_3;
2162 if (param1 == 5)
2163 item[i]._iFlags |= ISPL_STEALMANA_5;
2164 drawmanaflag = TRUE;
2165 break;
2166 case IPL_STEALLIFE:
2167 if (param1 == 3)
2168 item[i]._iFlags |= ISPL_STEALLIFE_3;
2169 if (param1 == 5)
2170 item[i]._iFlags |= ISPL_STEALLIFE_5;
2171 drawhpflag = TRUE;
2172 break;
2173 case IPL_TARGAC:
2174 if (gbIsHellfire)
2175 item[i]._iPLEnAc = param1;
2176 else
2177 item[i]._iPLEnAc += r;
2178 break;
2179 case IPL_FASTATTACK:
2180 if (param1 == 1)
2181 item[i]._iFlags |= ISPL_QUICKATTACK;
2182 if (param1 == 2)
2183 item[i]._iFlags |= ISPL_FASTATTACK;
2184 if (param1 == 3)
2185 item[i]._iFlags |= ISPL_FASTERATTACK;
2186 if (param1 == 4)
2187 item[i]._iFlags |= ISPL_FASTESTATTACK;
2188 break;
2189 case IPL_FASTRECOVER:
2190 if (param1 == 1)
2191 item[i]._iFlags |= ISPL_FASTRECOVER;
2192 if (param1 == 2)
2193 item[i]._iFlags |= ISPL_FASTERRECOVER;
2194 if (param1 == 3)
2195 item[i]._iFlags |= ISPL_FASTESTRECOVER;
2196 break;
2197 case IPL_FASTBLOCK:
2198 item[i]._iFlags |= ISPL_FASTBLOCK;
2199 break;
2200 case IPL_DAMMOD:
2201 item[i]._iPLDamMod += r;
2202 break;
2203 case IPL_RNDARROWVEL:
2204 item[i]._iFlags |= ISPL_RNDARROWVEL;
2205 break;
2206 case IPL_SETDAM:
2207 item[i]._iMinDam = param1;
2208 item[i]._iMaxDam = param2;
2209 break;
2210 case IPL_SETDUR:
2211 item[i]._iDurability = param1;
2212 item[i]._iMaxDur = param1;
2213 break;
2214 case IPL_FASTSWING:
2215 item[i]._iFlags |= ISPL_FASTERATTACK;
2216 break;
2217 case IPL_ONEHAND:
2218 item[i]._iLoc = ILOC_ONEHAND;
2219 break;
2220 case IPL_DRAINLIFE:
2221 item[i]._iFlags |= ISPL_DRAINLIFE;
2222 break;
2223 case IPL_RNDSTEALLIFE:
2224 item[i]._iFlags |= ISPL_RNDSTEALLIFE;
2225 break;
2226 case IPL_INFRAVISION:
2227 item[i]._iFlags |= ISPL_INFRAVISION;
2228 break;
2229 case IPL_NOMINSTR:
2230 item[i]._iMinStr = 0;
2231 break;
2232 case IPL_INVCURS:
2233 item[i]._iCurs = param1;
2234 break;
2235 case IPL_ADDACLIFE:
2236 item[i]._iFlags |= (ISPL_LIGHT_ARROWS | ISPL_FIRE_ARROWS);
2237 item[i]._iFMinDam = param1;
2238 item[i]._iFMaxDam = param2;
2239 item[i]._iLMinDam = 1;
2240 item[i]._iLMaxDam = 0;
2241 break;
2242 case IPL_ADDMANAAC:
2243 item[i]._iFlags |= (ISPL_LIGHTDAM | ISPL_FIREDAM);
2244 item[i]._iFMinDam = param1;
2245 item[i]._iFMaxDam = param2;
2246 item[i]._iLMinDam = 2;
2247 item[i]._iLMaxDam = 0;
2248 break;
2249 case IPL_FIRERESCLVL:
2250 item[i]._iPLFR = 30 - plr[myplr]._pLevel;
2251 if (item[i]._iPLFR < 0)
2252 item[i]._iPLFR = 0;
2253 break;
2254 case IPL_FIRERES_CURSE:
2255 item[i]._iPLFR -= r;
2256 break;
2257 case IPL_LIGHTRES_CURSE:
2258 item[i]._iPLLR -= r;
2259 break;
2260 case IPL_MAGICRES_CURSE:
2261 item[i]._iPLMR -= r;
2262 break;
2263 case IPL_ALLRES_CURSE:
2264 item[i]._iPLFR -= r;
2265 item[i]._iPLLR -= r;
2266 item[i]._iPLMR -= r;
2267 break;
2268 case IPL_DEVASTATION:
2269 item[i]._iDamAcFlags |= 0x01;
2270 break;
2271 case IPL_DECAY:
2272 item[i]._iDamAcFlags |= 0x02;
2273 item[i]._iPLDam += r;
2274 break;
2275 case IPL_PERIL:
2276 item[i]._iDamAcFlags |= 0x04;
2277 break;
2278 case IPL_JESTERS:
2279 item[i]._iDamAcFlags |= 0x08;
2280 break;
2281 case IPL_ACDEMON:
2282 item[i]._iDamAcFlags |= 0x20;
2283 break;
2284 case IPL_ACUNDEAD:
2285 item[i]._iDamAcFlags |= 0x40;
2286 break;
2287 case IPL_MANATOLIFE:
2288 r2 = ((plr[myplr]._pMaxManaBase >> 6) * 50 / 100);
2289 item[i]._iPLMana -= (r2 << 6);
2290 item[i]._iPLHP += (r2 << 6);
2291 break;
2292 case IPL_LIFETOMANA:
2293 r2 = ((plr[myplr]._pMaxHPBase >> 6) * 40 / 100);
2294 item[i]._iPLHP -= (r2 << 6);
2295 item[i]._iPLMana += (r2 << 6);
2296 break;
2297 }
2298 if (item[i]._iVAdd1 || item[i]._iVMult1) {
2299 item[i]._iVAdd2 = PLVal(r, param1, param2, minval, maxval);
2300 item[i]._iVMult2 = multval;
2301 } else {
2302 item[i]._iVAdd1 = PLVal(r, param1, param2, minval, maxval);
2303 item[i]._iVMult1 = multval;
2304 }
2305 }
2306
SaveItemSuffix(int i,int sufidx)2307 static void SaveItemSuffix(int i, int sufidx)
2308 {
2309 int param1 = PL_Suffix[sufidx].PLParam1;
2310 int param2 = PL_Suffix[sufidx].PLParam2;
2311
2312 if (!gbIsHellfire) {
2313 if (sufidx >= 84 && sufidx <= 86) {
2314 param1 = 2 << param1;
2315 param2 = 6 << param2;
2316 }
2317 }
2318
2319 SaveItemPower(
2320 i,
2321 PL_Suffix[sufidx].PLPower,
2322 param1,
2323 param2,
2324 PL_Suffix[sufidx].PLMinVal,
2325 PL_Suffix[sufidx].PLMaxVal,
2326 PL_Suffix[sufidx].PLMultVal);
2327 }
2328
GetItemPower(int i,int minlvl,int maxlvl,int flgs,BOOL onlygood)2329 void GetItemPower(int i, int minlvl, int maxlvl, int flgs, BOOL onlygood)
2330 {
2331 int pre, post, nt, nl, j, preidx, sufidx;
2332 int l[256];
2333 char istr[128];
2334 goodorevil goe;
2335
2336 pre = random_(23, 4);
2337 post = random_(23, 3);
2338 if (pre != 0 && post == 0) {
2339 if (random_(23, 2) != 0)
2340 post = 1;
2341 else
2342 pre = 0;
2343 }
2344 preidx = -1;
2345 sufidx = -1;
2346 goe = GOE_ANY;
2347 if (!onlygood && random_(0, 3) != 0)
2348 onlygood = TRUE;
2349 if (pre == 0) {
2350 nt = 0;
2351 for (j = 0; PL_Prefix[j].PLPower != IPL_INVALID; j++) {
2352 if (IsPrefixValidForItemType(j, flgs)) {
2353 if (PL_Prefix[j].PLMinLvl >= minlvl && PL_Prefix[j].PLMinLvl <= maxlvl && (!onlygood || PL_Prefix[j].PLOk) && (flgs != PLT_STAFF || PL_Prefix[j].PLPower != IPL_CHARGES)) {
2354 l[nt] = j;
2355 nt++;
2356 if (PL_Prefix[j].PLDouble) {
2357 l[nt] = j;
2358 nt++;
2359 }
2360 }
2361 }
2362 }
2363 if (nt != 0) {
2364 preidx = l[random_(23, nt)];
2365 sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName);
2366 strcpy(item[i]._iIName, istr);
2367 item[i]._iMagical = ITEM_QUALITY_MAGIC;
2368 SaveItemPower(
2369 i,
2370 PL_Prefix[preidx].PLPower,
2371 PL_Prefix[preidx].PLParam1,
2372 PL_Prefix[preidx].PLParam2,
2373 PL_Prefix[preidx].PLMinVal,
2374 PL_Prefix[preidx].PLMaxVal,
2375 PL_Prefix[preidx].PLMultVal);
2376 item[i]._iPrePower = PL_Prefix[preidx].PLPower;
2377 goe = PL_Prefix[preidx].PLGOE;
2378 }
2379 }
2380 if (post != 0) {
2381 nl = 0;
2382 for (j = 0; PL_Suffix[j].PLPower != IPL_INVALID; j++) {
2383 if (IsSuffixValidForItemType(j, flgs)
2384 && PL_Suffix[j].PLMinLvl >= minlvl && PL_Suffix[j].PLMinLvl <= maxlvl
2385 && !((goe == GOE_GOOD && PL_Suffix[j].PLGOE == GOE_EVIL) || (goe == GOE_EVIL && PL_Suffix[j].PLGOE == GOE_GOOD))
2386 && (!onlygood || PL_Suffix[j].PLOk)) {
2387 l[nl] = j;
2388 nl++;
2389 }
2390 }
2391 if (nl != 0) {
2392 sufidx = l[random_(23, nl)];
2393 sprintf(istr, "%s of %s", item[i]._iIName, PL_Suffix[sufidx].PLName);
2394 strcpy(item[i]._iIName, istr);
2395 item[i]._iMagical = ITEM_QUALITY_MAGIC;
2396 SaveItemSuffix(i, sufidx);
2397 item[i]._iSufPower = PL_Suffix[sufidx].PLPower;
2398 }
2399 }
2400 if (!control_WriteStringToBuffer((BYTE *)item[i]._iIName)) {
2401 int aii = item[i].IDidx;
2402 if (AllItemsList[aii].iSName)
2403 strcpy(item[i]._iIName, AllItemsList[aii].iSName);
2404 else
2405 item[i]._iName[0] = 0;
2406
2407 if (preidx != -1) {
2408 sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, item[i]._iIName);
2409 strcpy(item[i]._iIName, istr);
2410 }
2411 if (sufidx != -1) {
2412 sprintf(istr, "%s of %s", item[i]._iIName, PL_Suffix[sufidx].PLName);
2413 strcpy(item[i]._iIName, istr);
2414 }
2415 }
2416 if (preidx != -1 || sufidx != -1)
2417 CalcItemValue(i);
2418 }
2419
GetItemBonus(int i,int idata,int minlvl,int maxlvl,BOOL onlygood,BOOLEAN allowspells)2420 void GetItemBonus(int i, int idata, int minlvl, int maxlvl, BOOL onlygood, BOOLEAN allowspells)
2421 {
2422 if (minlvl > 25)
2423 minlvl = 25;
2424
2425 switch (item[i]._itype) {
2426 case ITYPE_SWORD:
2427 case ITYPE_AXE:
2428 case ITYPE_MACE:
2429 GetItemPower(i, minlvl, maxlvl, PLT_WEAP, onlygood);
2430 break;
2431 case ITYPE_BOW:
2432 GetItemPower(i, minlvl, maxlvl, PLT_BOW, onlygood);
2433 break;
2434 case ITYPE_SHIELD:
2435 GetItemPower(i, minlvl, maxlvl, PLT_SHLD, onlygood);
2436 break;
2437 case ITYPE_LARMOR:
2438 case ITYPE_HELM:
2439 case ITYPE_MARMOR:
2440 case ITYPE_HARMOR:
2441 GetItemPower(i, minlvl, maxlvl, PLT_ARMO, onlygood);
2442 break;
2443 case ITYPE_STAFF:
2444 if (allowspells)
2445 GetStaffSpell(i, maxlvl, onlygood);
2446 else
2447 GetItemPower(i, minlvl, maxlvl, PLT_STAFF, onlygood);
2448 break;
2449 case ITYPE_RING:
2450 case ITYPE_AMULET:
2451 GetItemPower(i, minlvl, maxlvl, PLT_MISC, onlygood);
2452 break;
2453 case ITYPE_NONE:
2454 case ITYPE_MISC:
2455 case ITYPE_GOLD:
2456 break;
2457 }
2458 }
2459
SetupItem(int i)2460 void SetupItem(int i)
2461 {
2462 int it;
2463
2464 it = ItemCAnimTbl[item[i]._iCurs];
2465 item[i]._iAnimData = itemanims[it];
2466 item[i]._iAnimLen = ItemAnimLs[it];
2467 item[i]._iAnimWidth = 96;
2468 item[i]._iAnimWidth2 = 16;
2469 item[i]._iIdentified = FALSE;
2470 item[i]._iPostDraw = FALSE;
2471
2472 if (!plr[myplr].pLvlLoad) {
2473 item[i]._iAnimFrame = 1;
2474 item[i]._iAnimFlag = TRUE;
2475 item[i]._iSelFlag = 0;
2476 } else {
2477 item[i]._iAnimFrame = item[i]._iAnimLen;
2478 item[i]._iAnimFlag = FALSE;
2479 item[i]._iSelFlag = 1;
2480 }
2481 }
2482
RndItem(int m)2483 int RndItem(int m)
2484 {
2485 int i, ri, r;
2486 int ril[512];
2487
2488 if ((monster[m].MData->mTreasure & 0x8000) != 0)
2489 return -((monster[m].MData->mTreasure & 0xFFF) + 1);
2490
2491 if (monster[m].MData->mTreasure & 0x4000)
2492 return 0;
2493
2494 if (random_(24, 100) > 40)
2495 return 0;
2496
2497 if (random_(24, 100) > 25)
2498 return IDI_GOLD + 1;
2499
2500 ri = 0;
2501 for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
2502 if (!IsItemAvailable(i))
2503 continue;
2504
2505 if (AllItemsList[i].iRnd == IDROP_DOUBLE && monster[m].mLevel >= AllItemsList[i].iMinMLvl
2506 && ri < 512) {
2507 ril[ri] = i;
2508 ri++;
2509 }
2510 if (AllItemsList[i].iRnd != IDROP_NEVER && monster[m].mLevel >= AllItemsList[i].iMinMLvl
2511 && ri < 512) {
2512 ril[ri] = i;
2513 ri++;
2514 }
2515 if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
2516 ri--;
2517 if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
2518 ri--;
2519 }
2520
2521 r = random_(24, ri);
2522 return ril[r] + 1;
2523 }
2524
RndUItem(int m)2525 int RndUItem(int m)
2526 {
2527 int i, ri;
2528 int ril[512];
2529 BOOL okflag;
2530
2531 if (m != -1 && (monster[m].MData->mTreasure & 0x8000) != 0 && !gbIsMultiplayer)
2532 return -((monster[m].MData->mTreasure & 0xFFF) + 1);
2533
2534 int curlv = items_get_currlevel();
2535 ri = 0;
2536 for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
2537 if (!IsItemAvailable(i))
2538 continue;
2539
2540 okflag = TRUE;
2541 if (AllItemsList[i].iRnd == IDROP_NEVER)
2542 okflag = FALSE;
2543 if (m != -1) {
2544 if (monster[m].mLevel < AllItemsList[i].iMinMLvl)
2545 okflag = FALSE;
2546 } else {
2547 if (2 * curlv < AllItemsList[i].iMinMLvl)
2548 okflag = FALSE;
2549 }
2550 if (AllItemsList[i].itype == ITYPE_MISC)
2551 okflag = FALSE;
2552 if (AllItemsList[i].itype == ITYPE_GOLD)
2553 okflag = FALSE;
2554 if (AllItemsList[i].iMiscId == IMISC_BOOK)
2555 okflag = TRUE;
2556 if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
2557 okflag = FALSE;
2558 if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
2559 okflag = FALSE;
2560 if (okflag && ri < 512) {
2561 ril[ri] = i;
2562 ri++;
2563 }
2564 }
2565
2566 return ril[random_(25, ri)];
2567 }
2568
RndAllItems()2569 int RndAllItems()
2570 {
2571 int i, ri;
2572 int ril[512];
2573
2574 if (random_(26, 100) > 25)
2575 return 0;
2576
2577 int curlv = items_get_currlevel();
2578 ri = 0;
2579 for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
2580 if (!IsItemAvailable(i))
2581 continue;
2582
2583 if (AllItemsList[i].iRnd != IDROP_NEVER && 2 * curlv >= AllItemsList[i].iMinMLvl && ri < 512) {
2584 ril[ri] = i;
2585 ri++;
2586 }
2587 if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
2588 ri--;
2589 if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
2590 ri--;
2591 }
2592
2593 return ril[random_(26, ri)];
2594 }
2595
RndTypeItems(int itype,int imid,int lvl)2596 int RndTypeItems(int itype, int imid, int lvl)
2597 {
2598 int i, ri;
2599 BOOL okflag;
2600 int ril[512];
2601
2602 ri = 0;
2603 for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
2604 if (!IsItemAvailable(i))
2605 continue;
2606
2607 okflag = TRUE;
2608 if (AllItemsList[i].iRnd == IDROP_NEVER)
2609 okflag = FALSE;
2610 if (lvl << 1 < AllItemsList[i].iMinMLvl)
2611 okflag = FALSE;
2612 if (AllItemsList[i].itype != itype)
2613 okflag = FALSE;
2614 if (imid != -1 && AllItemsList[i].iMiscId != imid)
2615 okflag = FALSE;
2616 if (okflag && ri < 512) {
2617 ril[ri] = i;
2618 ri++;
2619 }
2620 }
2621
2622 return ril[random_(27, ri)];
2623 }
2624
CheckUnique(int i,int lvl,int uper,BOOL recreate)2625 int CheckUnique(int i, int lvl, int uper, BOOL recreate)
2626 {
2627 int j, idata, numu;
2628 BOOLEAN uok[128];
2629
2630 if (random_(28, 100) > uper)
2631 return UITYPE_INVALID;
2632
2633 numu = 0;
2634 memset(uok, 0, sizeof(uok));
2635 for (j = 0; UniqueItemList[j].UIItemId != UITYPE_INVALID; j++) {
2636 if (!IsUniqueAvailable(j))
2637 break;
2638 if (UniqueItemList[j].UIItemId == AllItemsList[item[i].IDidx].iItemId
2639 && lvl >= UniqueItemList[j].UIMinLvl
2640 && (recreate || !UniqueItemFlag[j] || gbIsMultiplayer)) {
2641 uok[j] = TRUE;
2642 numu++;
2643 }
2644 }
2645
2646 if (numu == 0)
2647 return UITYPE_INVALID;
2648
2649 random_(29, 10); /// BUGFIX: unused, last unique in array always gets chosen
2650 idata = 0;
2651 while (numu > 0) {
2652 if (uok[idata])
2653 numu--;
2654 if (numu > 0) {
2655 idata++;
2656 if (idata == 128)
2657 idata = 0;
2658 }
2659 }
2660
2661 return idata;
2662 }
2663
GetUniqueItem(int i,int uid)2664 void GetUniqueItem(int i, int uid)
2665 {
2666 UniqueItemFlag[uid] = TRUE;
2667 SaveItemPower(i, UniqueItemList[uid].UIPower1, UniqueItemList[uid].UIParam1, UniqueItemList[uid].UIParam2, 0, 0, 1);
2668
2669 if (UniqueItemList[uid].UINumPL > 1)
2670 SaveItemPower(i, UniqueItemList[uid].UIPower2, UniqueItemList[uid].UIParam3, UniqueItemList[uid].UIParam4, 0, 0, 1);
2671 if (UniqueItemList[uid].UINumPL > 2)
2672 SaveItemPower(i, UniqueItemList[uid].UIPower3, UniqueItemList[uid].UIParam5, UniqueItemList[uid].UIParam6, 0, 0, 1);
2673 if (UniqueItemList[uid].UINumPL > 3)
2674 SaveItemPower(i, UniqueItemList[uid].UIPower4, UniqueItemList[uid].UIParam7, UniqueItemList[uid].UIParam8, 0, 0, 1);
2675 if (UniqueItemList[uid].UINumPL > 4)
2676 SaveItemPower(i, UniqueItemList[uid].UIPower5, UniqueItemList[uid].UIParam9, UniqueItemList[uid].UIParam10, 0, 0, 1);
2677 if (UniqueItemList[uid].UINumPL > 5)
2678 SaveItemPower(i, UniqueItemList[uid].UIPower6, UniqueItemList[uid].UIParam11, UniqueItemList[uid].UIParam12, 0, 0, 1);
2679
2680 strcpy(item[i]._iIName, UniqueItemList[uid].UIName);
2681 item[i]._iIvalue = UniqueItemList[uid].UIValue;
2682
2683 if (item[i]._iMiscId == IMISC_UNIQUE)
2684 item[i]._iSeed = uid;
2685
2686 item[i]._iUid = uid;
2687 item[i]._iMagical = ITEM_QUALITY_UNIQUE;
2688 item[i]._iCreateInfo |= CF_UNIQUE;
2689 }
2690
SpawnUnique(int uid,int x,int y)2691 void SpawnUnique(int uid, int x, int y)
2692 {
2693 if (numitems >= MAXITEMS)
2694 return;
2695
2696 int ii = AllocateItem();
2697 GetSuperItemSpace(x, y, ii);
2698 int curlv = items_get_currlevel();
2699
2700 int idx = 0;
2701 while (AllItemsList[idx].iItemId != UniqueItemList[uid].UIItemId)
2702 idx++;
2703
2704 GetItemAttrs(ii, idx, curlv);
2705 GetUniqueItem(ii, uid);
2706 SetupItem(ii);
2707
2708 return;
2709 }
2710
ItemRndDur(int ii)2711 void ItemRndDur(int ii)
2712 {
2713 if (item[ii]._iDurability && item[ii]._iDurability != DUR_INDESTRUCTIBLE)
2714 item[ii]._iDurability = random_(0, item[ii]._iMaxDur >> 1) + (item[ii]._iMaxDur >> 2) + 1;
2715 }
2716
SetupAllItems(int ii,int idx,int iseed,int lvl,int uper,BOOL onlygood,BOOL recreate,BOOL pregen)2717 void SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, BOOL onlygood, BOOL recreate, BOOL pregen)
2718 {
2719 int iblvl, uid;
2720
2721 item[ii]._iSeed = iseed;
2722 SetRndSeed(iseed);
2723 GetItemAttrs(ii, idx, lvl >> 1);
2724 item[ii]._iCreateInfo = lvl;
2725
2726 if (pregen)
2727 item[ii]._iCreateInfo |= CF_PREGEN;
2728 if (onlygood)
2729 item[ii]._iCreateInfo |= CF_ONLYGOOD;
2730
2731 if (uper == 15)
2732 item[ii]._iCreateInfo |= CF_UPER15;
2733 else if (uper == 1)
2734 item[ii]._iCreateInfo |= CF_UPER1;
2735
2736 if (item[ii]._iMiscId != IMISC_UNIQUE) {
2737 iblvl = -1;
2738 if (random_(32, 100) <= 10 || random_(33, 100) <= lvl) {
2739 iblvl = lvl;
2740 }
2741 if (iblvl == -1 && item[ii]._iMiscId == IMISC_STAFF) {
2742 iblvl = lvl;
2743 }
2744 if (iblvl == -1 && item[ii]._iMiscId == IMISC_RING) {
2745 iblvl = lvl;
2746 }
2747 if (iblvl == -1 && item[ii]._iMiscId == IMISC_AMULET) {
2748 iblvl = lvl;
2749 }
2750 if (onlygood)
2751 iblvl = lvl;
2752 if (uper == 15)
2753 iblvl = lvl + 4;
2754 if (iblvl != -1) {
2755 uid = CheckUnique(ii, iblvl, uper, recreate);
2756 if (uid == UITYPE_INVALID) {
2757 GetItemBonus(ii, idx, iblvl >> 1, iblvl, onlygood, TRUE);
2758 } else {
2759 GetUniqueItem(ii, uid);
2760 }
2761 }
2762 if (item[ii]._iMagical != ITEM_QUALITY_UNIQUE)
2763 ItemRndDur(ii);
2764 } else {
2765 if (item[ii]._iLoc != ILOC_UNEQUIPABLE) {
2766 GetUniqueItem(ii, iseed); // uid is stored in iseed for uniques
2767 }
2768 }
2769 SetupItem(ii);
2770 }
2771
SpawnItem(int m,int x,int y,BOOL sendmsg)2772 void SpawnItem(int m, int x, int y, BOOL sendmsg)
2773 {
2774 int idx;
2775 BOOL onlygood;
2776
2777 if (monster[m]._uniqtype || ((monster[m].MData->mTreasure & 0x8000) && gbIsMultiplayer)) {
2778 idx = RndUItem(m);
2779 if (idx < 0) {
2780 SpawnUnique(-(idx + 1), x, y);
2781 return;
2782 }
2783 onlygood = TRUE;
2784 } else if (quests[Q_MUSHROOM]._qactive != QUEST_ACTIVE || quests[Q_MUSHROOM]._qvar1 != QS_MUSHGIVEN) {
2785 idx = RndItem(m);
2786 if (!idx)
2787 return;
2788 if (idx > 0) {
2789 idx--;
2790 onlygood = FALSE;
2791 } else {
2792 SpawnUnique(-(idx + 1), x, y);
2793 return;
2794 }
2795 } else {
2796 idx = IDI_BRAIN;
2797 quests[Q_MUSHROOM]._qvar1 = QS_BRAINSPAWNED;
2798 }
2799
2800 if (numitems >= MAXITEMS)
2801 return;
2802
2803 int ii = AllocateItem();
2804 GetSuperItemSpace(x, y, ii);
2805 int upper = monster[m]._uniqtype ? 15 : 1;
2806
2807 int mLevel = monster[m].MData->mLevel;
2808 if (!gbIsHellfire && monster[m].MType->mtype == MT_DIABLO)
2809 mLevel -= 15;
2810
2811 SetupAllItems(ii, idx, AdvanceRndSeed(), mLevel, upper, onlygood, FALSE, FALSE);
2812
2813 if (sendmsg)
2814 NetSendCmdDItem(FALSE, ii);
2815 }
2816
SetupBaseItem(Sint32 x,Sint32 y,Sint32 idx,bool onlygood,bool sendmsg,bool delta)2817 static void SetupBaseItem(Sint32 x, Sint32 y, Sint32 idx, bool onlygood, bool sendmsg, bool delta)
2818 {
2819 if (numitems >= MAXITEMS)
2820 return;
2821
2822 int ii = AllocateItem();
2823 GetSuperItemSpace(x, y, ii);
2824 int curlv = items_get_currlevel();
2825
2826 SetupAllItems(ii, idx, AdvanceRndSeed(), 2 * curlv, 1, onlygood, FALSE, delta);
2827
2828 if (sendmsg)
2829 NetSendCmdDItem(FALSE, ii);
2830 if (delta)
2831 DeltaAddItem(ii);
2832 }
2833
CreateRndItem(int x,int y,BOOL onlygood,BOOL sendmsg,BOOL delta)2834 void CreateRndItem(int x, int y, BOOL onlygood, BOOL sendmsg, BOOL delta)
2835 {
2836 int idx = onlygood ? RndUItem(-1) : RndAllItems();
2837
2838 SetupBaseItem(x, y, idx, onlygood, sendmsg, delta);
2839 }
2840
SetupAllUseful(int ii,int iseed,int lvl)2841 void SetupAllUseful(int ii, int iseed, int lvl)
2842 {
2843 int idx;
2844
2845 item[ii]._iSeed = iseed;
2846 SetRndSeed(iseed);
2847
2848 if (gbIsHellfire) {
2849 idx = random_(34, 7);
2850 switch (idx) {
2851 case 0:
2852 idx = IDI_PORTAL;
2853 if ((lvl <= 1))
2854 idx = IDI_HEAL;
2855 break;
2856 case 1:
2857 case 2:
2858 idx = IDI_HEAL;
2859 break;
2860 case 3:
2861 idx = IDI_PORTAL;
2862 if ((lvl <= 1))
2863 idx = IDI_MANA;
2864 break;
2865 case 4:
2866 case 5:
2867 idx = IDI_MANA;
2868 break;
2869 default:
2870 idx = IDI_OIL;
2871 break;
2872 }
2873 } else {
2874 if (random_(34, 2) != 0)
2875 idx = IDI_HEAL;
2876 else
2877 idx = IDI_MANA;
2878
2879 if (lvl > 1 && random_(34, 3) == 0)
2880 idx = IDI_PORTAL;
2881 }
2882
2883 GetItemAttrs(ii, idx, lvl);
2884 item[ii]._iCreateInfo = lvl | CF_USEFUL;
2885 SetupItem(ii);
2886 }
2887
CreateRndUseful(int pnum,int x,int y,BOOL sendmsg)2888 void CreateRndUseful(int pnum, int x, int y, BOOL sendmsg)
2889 {
2890 if (numitems >= MAXITEMS)
2891 return;
2892
2893 int ii = AllocateItem();
2894 GetSuperItemSpace(x, y, ii);
2895 int curlv = items_get_currlevel();
2896
2897 SetupAllUseful(ii, AdvanceRndSeed(), curlv);
2898 if (sendmsg)
2899 NetSendCmdDItem(FALSE, ii);
2900 }
2901
CreateTypeItem(int x,int y,BOOL onlygood,int itype,int imisc,BOOL sendmsg,BOOL delta)2902 void CreateTypeItem(int x, int y, BOOL onlygood, int itype, int imisc, BOOL sendmsg, BOOL delta)
2903 {
2904 int idx;
2905
2906 int curlv = items_get_currlevel();
2907 if (itype != ITYPE_GOLD)
2908 idx = RndTypeItems(itype, imisc, curlv);
2909 else
2910 idx = IDI_GOLD;
2911
2912 SetupBaseItem(x, y, idx, onlygood, sendmsg, delta);
2913 }
2914
RecreateItem(int ii,int idx,WORD icreateinfo,int iseed,int ivalue,bool isHellfire)2915 void RecreateItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue, bool isHellfire)
2916 {
2917 bool _gbIsHellfire = gbIsHellfire;
2918 gbIsHellfire = isHellfire;
2919
2920 if (idx == IDI_GOLD) {
2921 SetPlrHandItem(&item[ii], IDI_GOLD);
2922 item[ii]._iSeed = iseed;
2923 item[ii]._iCreateInfo = icreateinfo;
2924 item[ii]._ivalue = ivalue;
2925 SetPlrHandGoldCurs(&item[ii]);
2926 gbIsHellfire = _gbIsHellfire;
2927 return;
2928 }
2929
2930 if (icreateinfo == 0) {
2931 SetPlrHandItem(&item[ii], idx);
2932 SetPlrHandSeed(&item[ii], iseed);
2933 gbIsHellfire = _gbIsHellfire;
2934 return;
2935 }
2936
2937 if ((icreateinfo & CF_UNIQUE) == 0) {
2938 if (icreateinfo & CF_TOWN) {
2939 RecreateTownItem(ii, idx, icreateinfo, iseed, ivalue);
2940 gbIsHellfire = _gbIsHellfire;
2941 return;
2942 }
2943
2944 if ((icreateinfo & CF_USEFUL) == CF_USEFUL) {
2945 SetupAllUseful(ii, iseed, icreateinfo & CF_LEVEL);
2946 gbIsHellfire = _gbIsHellfire;
2947 return;
2948 }
2949 }
2950
2951 int level = icreateinfo & CF_LEVEL;
2952
2953 int uper = 0;
2954 if (icreateinfo & CF_UPER1)
2955 uper = 1;
2956 if (icreateinfo & CF_UPER15)
2957 uper = 15;
2958
2959 bool onlygood = (icreateinfo & CF_ONLYGOOD) != 0;
2960 bool recreate = (icreateinfo & CF_UNIQUE) != 0;
2961 bool pregen = (icreateinfo & CF_PREGEN) != 0;
2962
2963 SetupAllItems(ii, idx, iseed, level, uper, onlygood, recreate, pregen);
2964 gbIsHellfire = _gbIsHellfire;
2965 }
2966
RecreateEar(int ii,WORD ic,int iseed,int Id,int dur,int mdur,int ch,int mch,int ivalue,int ibuff)2967 void RecreateEar(int ii, WORD ic, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, int ibuff)
2968 {
2969 SetPlrHandItem(&item[ii], IDI_EAR);
2970 tempstr[0] = (ic >> 8) & 0x7F;
2971 tempstr[1] = ic & 0x7F;
2972 tempstr[2] = (iseed >> 24) & 0x7F;
2973 tempstr[3] = (iseed >> 16) & 0x7F;
2974 tempstr[4] = (iseed >> 8) & 0x7F;
2975 tempstr[5] = iseed & 0x7F;
2976 tempstr[6] = Id & 0x7F;
2977 tempstr[7] = dur & 0x7F;
2978 tempstr[8] = mdur & 0x7F;
2979 tempstr[9] = ch & 0x7F;
2980 tempstr[10] = mch & 0x7F;
2981 tempstr[11] = (ivalue >> 8) & 0x7F;
2982 tempstr[12] = (ibuff >> 24) & 0x7F;
2983 tempstr[13] = (ibuff >> 16) & 0x7F;
2984 tempstr[14] = (ibuff >> 8) & 0x7F;
2985 tempstr[15] = ibuff & 0x7F;
2986 tempstr[16] = '\0';
2987 sprintf(item[ii]._iName, "Ear of %s", tempstr);
2988 item[ii]._iCurs = ((ivalue >> 6) & 3) + ICURS_EAR_SORCERER;
2989 item[ii]._ivalue = ivalue & 0x3F;
2990 item[ii]._iCreateInfo = ic;
2991 item[ii]._iSeed = iseed;
2992 }
2993
items_427A72()2994 void items_427A72()
2995 {
2996 PkItemStruct id;
2997 BYTE *buffer;
2998
2999 if (CornerStone.activated) {
3000 if (!CornerStone.item.isEmpty()) {
3001 PackItem(&id, &CornerStone.item);
3002 buffer = (BYTE *)&id;
3003 for (int i = 0; i < sizeof(PkItemStruct); i++) {
3004 sprintf(&sgOptions.Hellfire.szItem[i * 2], "%02X", buffer[i]);
3005 }
3006 } else {
3007 sgOptions.Hellfire.szItem[0] = '\0';
3008 }
3009 }
3010 }
3011
char2int(char input)3012 int char2int(char input)
3013 {
3014 if (input >= '0' && input <= '9')
3015 return input - '0';
3016 if (input >= 'A' && input <= 'F')
3017 return input - 'A' + 10;
3018 return 0;
3019 }
3020
hex2bin(const char * src,int bytes,char * target)3021 void hex2bin(const char *src, int bytes, char *target)
3022 {
3023 for (int i = 0; i < bytes; i++, src += 2) {
3024 target[i] = (char2int(*src) << 4) | char2int(src[1]);
3025 }
3026 }
3027
items_427ABA(int x,int y)3028 void items_427ABA(int x, int y)
3029 {
3030 PkItemStruct PkSItem;
3031
3032 if (CornerStone.activated || x == 0 || y == 0) {
3033 return;
3034 }
3035
3036 CornerStone.item._itype = ITYPE_NONE;
3037 CornerStone.activated = TRUE;
3038 if (dItem[x][y]) {
3039 int ii = dItem[x][y] - 1;
3040 for (int i = 0; i < numitems; i++) {
3041 if (itemactive[i] == ii) {
3042 DeleteItem(ii, i);
3043 break;
3044 }
3045 }
3046 dItem[x][y] = 0;
3047 }
3048
3049 if (strlen(sgOptions.Hellfire.szItem) < sizeof(PkItemStruct) * 2)
3050 return;
3051
3052 hex2bin(sgOptions.Hellfire.szItem, sizeof(PkItemStruct), (char *)&PkSItem);
3053
3054 int ii = AllocateItem();
3055
3056 dItem[x][y] = ii + 1;
3057
3058 UnPackItem(&PkSItem, &item[ii], (PkSItem.dwBuff & CF_HELLFIRE) != 0);
3059 item[ii]._ix = x;
3060 item[ii]._iy = y;
3061 RespawnItem(ii, FALSE);
3062 CornerStone.item = item[ii];
3063 }
3064
SpawnQuestItem(int itemid,int x,int y,int randarea,int selflag)3065 void SpawnQuestItem(int itemid, int x, int y, int randarea, int selflag)
3066 {
3067 if (randarea) {
3068 int tries = 0;
3069 while (1) {
3070 tries++;
3071 if (tries > 1000 && randarea > 1)
3072 randarea--;
3073
3074 x = random_(0, MAXDUNX);
3075 y = random_(0, MAXDUNY);
3076
3077 bool failed = false;
3078 for (int i = 0; i < randarea && !failed; i++) {
3079 for (int j = 0; j < randarea && !failed; j++) {
3080 failed = !ItemSpaceOk(i + x, j + y);
3081 }
3082 }
3083 if (!failed)
3084 break;
3085 }
3086 }
3087
3088 if (numitems >= MAXITEMS)
3089 return;
3090
3091 int ii = AllocateItem();
3092
3093 item[ii]._ix = x;
3094 item[ii]._iy = y;
3095
3096 dItem[x][y] = ii + 1;
3097
3098 int curlv = items_get_currlevel();
3099 GetItemAttrs(ii, itemid, curlv);
3100
3101 SetupItem(ii);
3102 item[ii]._iPostDraw = TRUE;
3103 if (selflag) {
3104 item[ii]._iSelFlag = selflag;
3105 item[ii]._iAnimFrame = item[ii]._iAnimLen;
3106 item[ii]._iAnimFlag = FALSE;
3107 }
3108 }
3109
SpawnRock()3110 void SpawnRock()
3111 {
3112 if (numitems >= MAXITEMS)
3113 return;
3114
3115 int oi;
3116 bool ostand = false;
3117 for (int i = 0; i < nobjects && !ostand; i++) {
3118 oi = objectactive[i];
3119 ostand = object[oi]._otype == OBJ_STAND;
3120 }
3121
3122 if (!ostand)
3123 return;
3124
3125 int ii = AllocateItem();
3126
3127 int xx = object[oi]._ox;
3128 int yy = object[oi]._oy;
3129 item[ii]._ix = xx;
3130 item[ii]._iy = yy;
3131 dItem[xx][item[ii]._iy] = ii + 1;
3132 int curlv = items_get_currlevel();
3133 GetItemAttrs(ii, IDI_ROCK, curlv);
3134 SetupItem(ii);
3135 item[ii]._iSelFlag = 2;
3136 item[ii]._iPostDraw = TRUE;
3137 item[ii]._iAnimFrame = 11;
3138 }
3139
SpawnRewardItem(int itemid,int xx,int yy)3140 void SpawnRewardItem(int itemid, int xx, int yy)
3141 {
3142 if (numitems >= MAXITEMS)
3143 return;
3144
3145 int ii = AllocateItem();
3146
3147 item[ii]._ix = xx;
3148 item[ii]._iy = yy;
3149 dItem[xx][yy] = ii + 1;
3150 int curlv = items_get_currlevel();
3151 GetItemAttrs(ii, itemid, curlv);
3152 SetupItem(ii);
3153 item[ii]._iSelFlag = 2;
3154 item[ii]._iPostDraw = TRUE;
3155 item[ii]._iAnimFrame = 1;
3156 item[ii]._iAnimFlag = TRUE;
3157 item[ii]._iIdentified = TRUE;
3158 }
3159
SpawnMapOfDoom(int xx,int yy)3160 void SpawnMapOfDoom(int xx, int yy)
3161 {
3162 SpawnRewardItem(IDI_MAPOFDOOM, xx, yy);
3163 }
3164
SpawnRuneBomb(int xx,int yy)3165 void SpawnRuneBomb(int xx, int yy)
3166 {
3167 SpawnRewardItem(IDI_RUNEBOMB, xx, yy);
3168 }
3169
SpawnTheodore(int xx,int yy)3170 void SpawnTheodore(int xx, int yy)
3171 {
3172 SpawnRewardItem(IDI_THEODORE, xx, yy);
3173 }
3174
RespawnItem(int i,BOOL FlipFlag)3175 void RespawnItem(int i, BOOL FlipFlag)
3176 {
3177 int it;
3178
3179 it = ItemCAnimTbl[item[i]._iCurs];
3180 item[i]._iAnimData = itemanims[it];
3181 item[i]._iAnimLen = ItemAnimLs[it];
3182 item[i]._iAnimWidth = 96;
3183 item[i]._iAnimWidth2 = 16;
3184 item[i]._iPostDraw = FALSE;
3185 item[i]._iRequest = FALSE;
3186 if (FlipFlag) {
3187 item[i]._iAnimFrame = 1;
3188 item[i]._iAnimFlag = TRUE;
3189 item[i]._iSelFlag = 0;
3190 } else {
3191 item[i]._iAnimFrame = item[i]._iAnimLen;
3192 item[i]._iAnimFlag = FALSE;
3193 item[i]._iSelFlag = 1;
3194 }
3195
3196 if (item[i]._iCurs == ICURS_MAGIC_ROCK) {
3197 item[i]._iSelFlag = 1;
3198 PlaySfxLoc(ItemDropSnds[it], item[i]._ix, item[i]._iy);
3199 }
3200 if (item[i]._iCurs == ICURS_TAVERN_SIGN)
3201 item[i]._iSelFlag = 1;
3202 if (item[i]._iCurs == ICURS_ANVIL_OF_FURY)
3203 item[i]._iSelFlag = 1;
3204 }
3205
DeleteItem(int ii,int i)3206 void DeleteItem(int ii, int i)
3207 {
3208 itemavail[MAXITEMS - numitems] = ii;
3209 numitems--;
3210 if (numitems > 0 && i != numitems)
3211 itemactive[i] = itemactive[numitems];
3212 }
3213
ItemDoppel()3214 void ItemDoppel()
3215 {
3216 int idoppelx;
3217 ItemStruct *i;
3218
3219 if (gbIsMultiplayer) {
3220 for (idoppelx = 16; idoppelx < 96; idoppelx++) {
3221 if (dItem[idoppelx][idoppely]) {
3222 i = &item[dItem[idoppelx][idoppely] - 1];
3223 if (i->_ix != idoppelx || i->_iy != idoppely)
3224 dItem[idoppelx][idoppely] = 0;
3225 }
3226 }
3227 idoppely++;
3228 if (idoppely == 96)
3229 idoppely = 16;
3230 }
3231 }
3232
ProcessItems()3233 void ProcessItems()
3234 {
3235 int i, ii;
3236
3237 for (i = 0; i < numitems; i++) {
3238 ii = itemactive[i];
3239 if (item[ii]._iAnimFlag) {
3240 item[ii]._iAnimFrame++;
3241 if (item[ii]._iCurs == ICURS_MAGIC_ROCK) {
3242 if (item[ii]._iSelFlag == 1 && item[ii]._iAnimFrame == 11)
3243 item[ii]._iAnimFrame = 1;
3244 if (item[ii]._iSelFlag == 2 && item[ii]._iAnimFrame == 21)
3245 item[ii]._iAnimFrame = 11;
3246 } else {
3247 if (item[ii]._iAnimFrame == item[ii]._iAnimLen >> 1)
3248 PlaySfxLoc(ItemDropSnds[ItemCAnimTbl[item[ii]._iCurs]], item[ii]._ix, item[ii]._iy);
3249
3250 if (item[ii]._iAnimFrame >= item[ii]._iAnimLen) {
3251 item[ii]._iAnimFrame = item[ii]._iAnimLen;
3252 item[ii]._iAnimFlag = FALSE;
3253 item[ii]._iSelFlag = 1;
3254 }
3255 }
3256 }
3257 }
3258 ItemDoppel();
3259 }
3260
FreeItemGFX()3261 void FreeItemGFX()
3262 {
3263 for (int i = 0; i < ITEMTYPES; i++) {
3264 MemFreeDbg(itemanims[i]);
3265 }
3266 }
3267
GetItemFrm(int i)3268 void GetItemFrm(int i)
3269 {
3270 item[i]._iAnimData = itemanims[ItemCAnimTbl[item[i]._iCurs]];
3271 }
3272
GetItemStr(int i)3273 void GetItemStr(int i)
3274 {
3275 int nGold;
3276
3277 if (item[i]._itype != ITYPE_GOLD) {
3278 if (item[i]._iIdentified)
3279 strcpy(infostr, item[i]._iIName);
3280 else
3281 strcpy(infostr, item[i]._iName);
3282
3283 if (item[i]._iMagical == ITEM_QUALITY_MAGIC)
3284 infoclr = COL_BLUE;
3285 if (item[i]._iMagical == ITEM_QUALITY_UNIQUE)
3286 infoclr = COL_GOLD;
3287 } else {
3288 nGold = item[i]._ivalue;
3289 sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold));
3290 }
3291 }
3292
CheckIdentify(int pnum,int cii)3293 void CheckIdentify(int pnum, int cii)
3294 {
3295 ItemStruct *pi;
3296
3297 if (cii >= NUM_INVLOC)
3298 pi = &plr[pnum].InvList[cii - NUM_INVLOC];
3299 else
3300 pi = &plr[pnum].InvBody[cii];
3301
3302 pi->_iIdentified = TRUE;
3303 CalcPlrInv(pnum, TRUE);
3304
3305 if (pnum == myplr)
3306 SetCursor_(CURSOR_HAND);
3307 }
3308
RepairItem(ItemStruct * i,int lvl)3309 static void RepairItem(ItemStruct *i, int lvl)
3310 {
3311 int rep, d;
3312
3313 if (i->_iDurability == i->_iMaxDur) {
3314 return;
3315 }
3316
3317 if (i->_iMaxDur <= 0) {
3318 i->_itype = ITYPE_NONE;
3319 return;
3320 }
3321
3322 rep = 0;
3323 do {
3324 rep += lvl + random_(37, lvl);
3325 d = i->_iMaxDur / (lvl + 9);
3326 if (d < 1)
3327 d = 1;
3328 i->_iMaxDur = i->_iMaxDur - d;
3329 if (!i->_iMaxDur) {
3330 i->_itype = ITYPE_NONE;
3331 return;
3332 }
3333 } while (rep + i->_iDurability < i->_iMaxDur);
3334
3335 i->_iDurability += rep;
3336 if (i->_iDurability > i->_iMaxDur)
3337 i->_iDurability = i->_iMaxDur;
3338 }
3339
DoRepair(int pnum,int cii)3340 void DoRepair(int pnum, int cii)
3341 {
3342 PlayerStruct *p;
3343 ItemStruct *pi;
3344
3345 p = &plr[pnum];
3346 PlaySfxLoc(IS_REPAIR, p->_px, p->_py);
3347
3348 if (cii >= NUM_INVLOC) {
3349 pi = &p->InvList[cii - NUM_INVLOC];
3350 } else {
3351 pi = &p->InvBody[cii];
3352 }
3353
3354 RepairItem(pi, p->_pLevel);
3355 CalcPlrInv(pnum, TRUE);
3356
3357 if (pnum == myplr)
3358 SetCursor_(CURSOR_HAND);
3359 }
3360
RechargeItem(ItemStruct * i,int r)3361 static void RechargeItem(ItemStruct *i, int r)
3362 {
3363 if (i->_iCharges != i->_iMaxCharges) {
3364 do {
3365 i->_iMaxCharges--;
3366 if (i->_iMaxCharges == 0) {
3367 return;
3368 }
3369 i->_iCharges += r;
3370 } while (i->_iCharges < i->_iMaxCharges);
3371 if (i->_iCharges > i->_iMaxCharges)
3372 i->_iCharges = i->_iMaxCharges;
3373 }
3374 }
3375
DoRecharge(int pnum,int cii)3376 void DoRecharge(int pnum, int cii)
3377 {
3378 PlayerStruct *p;
3379 ItemStruct *pi;
3380 int r;
3381
3382 p = &plr[pnum];
3383 if (cii >= NUM_INVLOC) {
3384 pi = &p->InvList[cii - NUM_INVLOC];
3385 } else {
3386 pi = &p->InvBody[cii];
3387 }
3388 if (pi->_itype == ITYPE_STAFF && pi->_iSpell != SPL_NULL) {
3389 r = GetSpellBookLevel(pi->_iSpell);
3390 r = random_(38, p->_pLevel / r) + 1;
3391 RechargeItem(pi, r);
3392 CalcPlrInv(pnum, TRUE);
3393 }
3394
3395 if (pnum == myplr)
3396 SetCursor_(CURSOR_HAND);
3397 }
3398
OilItem(ItemStruct * x,PlayerStruct * p)3399 static BOOL OilItem(ItemStruct *x, PlayerStruct *p)
3400 {
3401 int dur, r;
3402
3403 if (x->_iClass == ICLASS_MISC) {
3404 return FALSE;
3405 }
3406 if (x->_iClass == ICLASS_GOLD) {
3407 return FALSE;
3408 }
3409 if (x->_iClass == ICLASS_QUEST) {
3410 return FALSE;
3411 }
3412
3413 switch (p->_pOilType) {
3414 case IMISC_OILACC:
3415 case IMISC_OILMAST:
3416 case IMISC_OILSHARP:
3417 if (x->_iClass == ICLASS_ARMOR) {
3418 return FALSE;
3419 }
3420 break;
3421 case IMISC_OILDEATH:
3422 if (x->_iClass == ICLASS_ARMOR) {
3423 return FALSE;
3424 }
3425 if (x->_itype == ITYPE_BOW) {
3426 return FALSE;
3427 }
3428 break;
3429 case IMISC_OILHARD:
3430 case IMISC_OILIMP:
3431 if (x->_iClass == ICLASS_WEAPON) {
3432 return FALSE;
3433 }
3434 break;
3435 default:
3436 break;
3437 }
3438
3439 switch (p->_pOilType) {
3440 case IMISC_OILACC:
3441 if (x->_iPLToHit < 50) {
3442 x->_iPLToHit += random_(68, 2) + 1;
3443 }
3444 break;
3445 case IMISC_OILMAST:
3446 if (x->_iPLToHit < 100) {
3447 x->_iPLToHit += random_(68, 3) + 3;
3448 }
3449 break;
3450 case IMISC_OILSHARP:
3451 if (x->_iMaxDam - x->_iMinDam < 30) {
3452 x->_iMaxDam = x->_iMaxDam + 1;
3453 }
3454 break;
3455 case IMISC_OILDEATH:
3456 if (x->_iMaxDam - x->_iMinDam < 30) {
3457 x->_iMinDam = x->_iMinDam + 1;
3458 x->_iMaxDam = x->_iMaxDam + 2;
3459 }
3460 break;
3461 case IMISC_OILSKILL:
3462 r = random_(68, 6) + 5;
3463 if (x->_iMinStr > r) {
3464 x->_iMinStr = x->_iMinStr - r;
3465 } else {
3466 x->_iMinStr = 0;
3467 }
3468 if (x->_iMinMag > r) {
3469 x->_iMinMag = x->_iMinMag - r;
3470 } else {
3471 x->_iMinMag = 0;
3472 }
3473 if (x->_iMinDex > r) {
3474 x->_iMinDex = x->_iMinDex - r;
3475 } else {
3476 x->_iMinDex = 0;
3477 }
3478 break;
3479 case IMISC_OILBSMTH:
3480 if (x->_iMaxDur != 255) {
3481 if (x->_iDurability < x->_iMaxDur) {
3482 dur = (x->_iMaxDur + 4) / 5 + x->_iDurability;
3483 if (dur > x->_iMaxDur) {
3484 dur = x->_iMaxDur;
3485 }
3486 } else {
3487 if (x->_iMaxDur >= 100) {
3488 return TRUE;
3489 }
3490 dur = x->_iMaxDur + 1;
3491 x->_iMaxDur = dur;
3492 }
3493 x->_iDurability = dur;
3494 }
3495 break;
3496 case IMISC_OILFORT:
3497 if (x->_iMaxDur != 255 && x->_iMaxDur < 200) {
3498 r = random_(68, 41) + 10;
3499 x->_iMaxDur += r;
3500 x->_iDurability += r;
3501 }
3502 break;
3503 case IMISC_OILPERM:
3504 x->_iDurability = 255;
3505 x->_iMaxDur = 255;
3506 break;
3507 case IMISC_OILHARD:
3508 if (x->_iAC < 60) {
3509 x->_iAC += random_(68, 2) + 1;
3510 }
3511 break;
3512 case IMISC_OILIMP:
3513 if (x->_iAC < 120) {
3514 x->_iAC += random_(68, 3) + 3;
3515 }
3516 break;
3517 default:
3518 return FALSE;
3519 }
3520 return TRUE;
3521 }
3522
DoOil(int pnum,int cii)3523 void DoOil(int pnum, int cii)
3524 {
3525 PlayerStruct *p = &plr[pnum];
3526
3527 if (cii >= NUM_INVLOC || cii == INVLOC_HEAD || (cii > INVLOC_AMULET && cii <= INVLOC_CHEST)) {
3528 if (OilItem(&p->InvBody[cii], p)) {
3529 CalcPlrInv(pnum, TRUE);
3530 if (pnum == myplr) {
3531 SetCursor_(CURSOR_HAND);
3532 }
3533 }
3534 }
3535 }
3536
PrintItemOil(char IDidx)3537 void PrintItemOil(char IDidx)
3538 {
3539 switch (IDidx) {
3540 case IMISC_OILACC:
3541 strcpy(tempstr, "increases a weapon's");
3542 AddPanelString(tempstr, TRUE);
3543 strcpy(tempstr, "chance to hit");
3544 AddPanelString(tempstr, TRUE);
3545 break;
3546 case IMISC_OILMAST:
3547 strcpy(tempstr, "greatly increases a");
3548 AddPanelString(tempstr, TRUE);
3549 strcpy(tempstr, "weapon's chance to hit");
3550 AddPanelString(tempstr, TRUE);
3551 break;
3552 case IMISC_OILSHARP:
3553 strcpy(tempstr, "increases a weapon's");
3554 AddPanelString(tempstr, TRUE);
3555 strcpy(tempstr, "damage potential");
3556 AddPanelString(tempstr, TRUE);
3557 break;
3558 case IMISC_OILDEATH:
3559 strcpy(tempstr, "greatly increases a weapon's");
3560 AddPanelString(tempstr, TRUE);
3561 strcpy(tempstr, "damage potential - not bows");
3562 AddPanelString(tempstr, TRUE);
3563 break;
3564 case IMISC_OILSKILL:
3565 strcpy(tempstr, "reduces attributes needed");
3566 AddPanelString(tempstr, TRUE);
3567 strcpy(tempstr, "to use armor or weapons");
3568 AddPanelString(tempstr, TRUE);
3569 break;
3570 case IMISC_OILBSMTH:
3571 strcpy(tempstr, "restores 20% of an");
3572 AddPanelString(tempstr, TRUE);
3573 strcpy(tempstr, "item's durability");
3574 AddPanelString(tempstr, TRUE);
3575 break;
3576 case IMISC_OILFORT:
3577 strcpy(tempstr, "increases an item's");
3578 AddPanelString(tempstr, TRUE);
3579 strcpy(tempstr, "current and max durability");
3580 AddPanelString(tempstr, TRUE);
3581 break;
3582 case IMISC_OILPERM:
3583 strcpy(tempstr, "makes an item indestructible");
3584 AddPanelString(tempstr, TRUE);
3585 break;
3586 case IMISC_OILHARD:
3587 strcpy(tempstr, "increases the armor class");
3588 AddPanelString(tempstr, TRUE);
3589 strcpy(tempstr, "of armor and shields");
3590 AddPanelString(tempstr, TRUE);
3591 break;
3592 case IMISC_OILIMP:
3593 strcpy(tempstr, "greatly increases the armor");
3594 AddPanelString(tempstr, TRUE);
3595 strcpy(tempstr, "class of armor and shields");
3596 AddPanelString(tempstr, TRUE);
3597 break;
3598 case IMISC_RUNEF:
3599 strcpy(tempstr, "sets fire trap");
3600 AddPanelString(tempstr, TRUE);
3601 break;
3602 case IMISC_RUNEL:
3603 strcpy(tempstr, "sets lightning trap");
3604 AddPanelString(tempstr, TRUE);
3605 break;
3606 case IMISC_GR_RUNEL:
3607 strcpy(tempstr, "sets lightning trap");
3608 AddPanelString(tempstr, TRUE);
3609 break;
3610 case IMISC_GR_RUNEF:
3611 strcpy(tempstr, "sets fire trap");
3612 AddPanelString(tempstr, TRUE);
3613 break;
3614 case IMISC_RUNES:
3615 strcpy(tempstr, "sets petrification trap");
3616 AddPanelString(tempstr, TRUE);
3617 break;
3618 case IMISC_FULLHEAL:
3619 strcpy(tempstr, "fully recover life");
3620 AddPanelString(tempstr, TRUE);
3621 break;
3622 case IMISC_HEAL:
3623 strcpy(tempstr, "recover partial life");
3624 AddPanelString(tempstr, TRUE);
3625 break;
3626 case IMISC_OLDHEAL:
3627 strcpy(tempstr, "recover life");
3628 AddPanelString(tempstr, TRUE);
3629 break;
3630 case IMISC_DEADHEAL:
3631 strcpy(tempstr, "deadly heal");
3632 AddPanelString(tempstr, TRUE);
3633 break;
3634 case IMISC_MANA:
3635 strcpy(tempstr, "recover mana");
3636 AddPanelString(tempstr, TRUE);
3637 break;
3638 case IMISC_FULLMANA:
3639 strcpy(tempstr, "fully recover mana");
3640 AddPanelString(tempstr, TRUE);
3641 break;
3642 case IMISC_ELIXSTR:
3643 strcpy(tempstr, "increase strength");
3644 AddPanelString(tempstr, TRUE);
3645 break;
3646 case IMISC_ELIXMAG:
3647 strcpy(tempstr, "increase magic");
3648 AddPanelString(tempstr, TRUE);
3649 break;
3650 case IMISC_ELIXDEX:
3651 strcpy(tempstr, "increase dexterity");
3652 AddPanelString(tempstr, TRUE);
3653 break;
3654 case IMISC_ELIXVIT:
3655 strcpy(tempstr, "increase vitality");
3656 AddPanelString(tempstr, TRUE);
3657 break;
3658 case IMISC_ELIXWEAK:
3659 strcpy(tempstr, "decrease strength");
3660 AddPanelString(tempstr, TRUE);
3661 break;
3662 case IMISC_ELIXDIS:
3663 strcpy(tempstr, "decrease strength");
3664 AddPanelString(tempstr, TRUE);
3665 break;
3666 case IMISC_ELIXCLUM:
3667 strcpy(tempstr, "decrease dexterity");
3668 AddPanelString(tempstr, TRUE);
3669 break;
3670 case IMISC_ELIXSICK:
3671 strcpy(tempstr, "decrease vitality");
3672 AddPanelString(tempstr, TRUE);
3673 break;
3674 case IMISC_REJUV:
3675 strcpy(tempstr, "recover life and mana");
3676 AddPanelString(tempstr, TRUE);
3677 break;
3678 case IMISC_FULLREJUV:
3679 strcpy(tempstr, "fully recover life and mana");
3680 AddPanelString(tempstr, TRUE);
3681 break;
3682 }
3683 }
3684
PrintItemPower(char plidx,ItemStruct * x)3685 void PrintItemPower(char plidx, ItemStruct *x)
3686 {
3687 switch (plidx) {
3688 case IPL_TOHIT:
3689 case IPL_TOHIT_CURSE:
3690 sprintf(tempstr, "chance to hit: %+i%%", x->_iPLToHit);
3691 break;
3692 case IPL_DAMP:
3693 case IPL_DAMP_CURSE:
3694 sprintf(tempstr, "%+i%% damage", x->_iPLDam);
3695 break;
3696 case IPL_TOHIT_DAMP:
3697 case IPL_TOHIT_DAMP_CURSE:
3698 sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam);
3699 break;
3700 case IPL_ACP:
3701 case IPL_ACP_CURSE:
3702 sprintf(tempstr, "%+i%% armor", x->_iPLAC);
3703 break;
3704 case IPL_SETAC:
3705 sprintf(tempstr, "armor class: %i", x->_iAC);
3706 break;
3707 case IPL_AC_CURSE:
3708 sprintf(tempstr, "armor class: %i", x->_iAC);
3709 break;
3710 case IPL_FIRERES:
3711 case IPL_FIRERES_CURSE:
3712 if (x->_iPLFR < 75)
3713 sprintf(tempstr, "Resist Fire: %+i%%", x->_iPLFR);
3714 else
3715 sprintf(tempstr, "Resist Fire: 75%% MAX");
3716 break;
3717 case IPL_LIGHTRES:
3718 case IPL_LIGHTRES_CURSE:
3719 if (x->_iPLLR < 75)
3720 sprintf(tempstr, "Resist Lightning: %+i%%", x->_iPLLR);
3721 else
3722 sprintf(tempstr, "Resist Lightning: 75%% MAX");
3723 break;
3724 case IPL_MAGICRES:
3725 case IPL_MAGICRES_CURSE:
3726 if (x->_iPLMR < 75)
3727 sprintf(tempstr, "Resist Magic: %+i%%", x->_iPLMR);
3728 else
3729 sprintf(tempstr, "Resist Magic: 75%% MAX");
3730 break;
3731 case IPL_ALLRES:
3732 case IPL_ALLRES_CURSE:
3733 if (x->_iPLFR < 75)
3734 sprintf(tempstr, "Resist All: %+i%%", x->_iPLFR);
3735 if (x->_iPLFR >= 75)
3736 sprintf(tempstr, "Resist All: 75%% MAX");
3737 break;
3738 case IPL_SPLLVLADD:
3739 if (x->_iSplLvlAdd == 1)
3740 strcpy(tempstr, "spells are increased 1 level");
3741 else if (x->_iSplLvlAdd > 1)
3742 sprintf(tempstr, "spells are increased %i levels", x->_iSplLvlAdd);
3743 else if (x->_iSplLvlAdd == -1)
3744 strcpy(tempstr, "spells are decreased 1 level");
3745 else if (x->_iSplLvlAdd < -1)
3746 sprintf(tempstr, "spells are decreased %i levels", -x->_iSplLvlAdd);
3747 else if (x->_iSplLvlAdd == 0)
3748 strcpy(tempstr, "spell levels unchanged (?)");
3749 break;
3750 case IPL_CHARGES:
3751 strcpy(tempstr, "Extra charges");
3752 break;
3753 case IPL_SPELL:
3754 sprintf(tempstr, "%i %s charges", x->_iMaxCharges, spelldata[x->_iSpell].sNameText);
3755 break;
3756 case IPL_FIREDAM:
3757 if (x->_iFMinDam == x->_iFMaxDam)
3758 sprintf(tempstr, "Fire hit damage: %i", x->_iFMinDam);
3759 else
3760 sprintf(tempstr, "Fire hit damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
3761 break;
3762 case IPL_LIGHTDAM:
3763 if (x->_iLMinDam == x->_iLMaxDam)
3764 sprintf(tempstr, "Lightning hit damage: %i", x->_iLMinDam);
3765 else
3766 sprintf(tempstr, "Lightning hit damage: %i-%i", x->_iLMinDam, x->_iLMaxDam);
3767 break;
3768 case IPL_STR:
3769 case IPL_STR_CURSE:
3770 sprintf(tempstr, "%+i to strength", x->_iPLStr);
3771 break;
3772 case IPL_MAG:
3773 case IPL_MAG_CURSE:
3774 sprintf(tempstr, "%+i to magic", x->_iPLMag);
3775 break;
3776 case IPL_DEX:
3777 case IPL_DEX_CURSE:
3778 sprintf(tempstr, "%+i to dexterity", x->_iPLDex);
3779 break;
3780 case IPL_VIT:
3781 case IPL_VIT_CURSE:
3782 sprintf(tempstr, "%+i to vitality", x->_iPLVit);
3783 break;
3784 case IPL_ATTRIBS:
3785 case IPL_ATTRIBS_CURSE:
3786 sprintf(tempstr, "%+i to all attributes", x->_iPLStr);
3787 break;
3788 case IPL_GETHIT_CURSE:
3789 case IPL_GETHIT:
3790 sprintf(tempstr, "%+i damage from enemies", x->_iPLGetHit);
3791 break;
3792 case IPL_LIFE:
3793 case IPL_LIFE_CURSE:
3794 sprintf(tempstr, "Hit Points: %+i", x->_iPLHP >> 6);
3795 break;
3796 case IPL_MANA:
3797 case IPL_MANA_CURSE:
3798 sprintf(tempstr, "Mana: %+i", x->_iPLMana >> 6);
3799 break;
3800 case IPL_DUR:
3801 strcpy(tempstr, "high durability");
3802 break;
3803 case IPL_DUR_CURSE:
3804 strcpy(tempstr, "decreased durability");
3805 break;
3806 case IPL_INDESTRUCTIBLE:
3807 strcpy(tempstr, "indestructible");
3808 break;
3809 case IPL_LIGHT:
3810 sprintf(tempstr, "+%i%% light radius", 10 * x->_iPLLight);
3811 break;
3812 case IPL_LIGHT_CURSE:
3813 sprintf(tempstr, "-%i%% light radius", -10 * x->_iPLLight);
3814 break;
3815 case IPL_MULT_ARROWS:
3816 sprintf(tempstr, "multiple arrows per shot");
3817 break;
3818 case IPL_FIRE_ARROWS:
3819 if (x->_iFMinDam == x->_iFMaxDam)
3820 sprintf(tempstr, "fire arrows damage: %i", x->_iFMinDam);
3821 else
3822 sprintf(tempstr, "fire arrows damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
3823 break;
3824 case IPL_LIGHT_ARROWS:
3825 if (x->_iLMinDam == x->_iLMaxDam)
3826 sprintf(tempstr, "lightning arrows damage %i", x->_iLMinDam);
3827 else
3828 sprintf(tempstr, "lightning arrows damage %i-%i", x->_iLMinDam, x->_iLMaxDam);
3829 break;
3830 case IPL_FIREBALL:
3831 if (x->_iFMinDam == x->_iFMaxDam)
3832 sprintf(tempstr, "fireball damage: %i", x->_iFMinDam);
3833 else
3834 sprintf(tempstr, "fireball damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
3835 break;
3836 case IPL_THORNS:
3837 strcpy(tempstr, "attacker takes 1-3 damage");
3838 break;
3839 case IPL_NOMANA:
3840 strcpy(tempstr, "user loses all mana");
3841 break;
3842 case IPL_NOHEALPLR:
3843 strcpy(tempstr, "you can't heal");
3844 break;
3845 case IPL_ABSHALFTRAP:
3846 strcpy(tempstr, "absorbs half of trap damage");
3847 break;
3848 case IPL_KNOCKBACK:
3849 strcpy(tempstr, "knocks target back");
3850 break;
3851 case IPL_3XDAMVDEM:
3852 strcpy(tempstr, "+200% damage vs. demons");
3853 break;
3854 case IPL_ALLRESZERO:
3855 strcpy(tempstr, "All Resistance equals 0");
3856 break;
3857 case IPL_NOHEALMON:
3858 strcpy(tempstr, "hit monster doesn't heal");
3859 break;
3860 case IPL_STEALMANA:
3861 if (x->_iFlags & ISPL_STEALMANA_3)
3862 strcpy(tempstr, "hit steals 3% mana");
3863 if (x->_iFlags & ISPL_STEALMANA_5)
3864 strcpy(tempstr, "hit steals 5% mana");
3865 break;
3866 case IPL_STEALLIFE:
3867 if (x->_iFlags & ISPL_STEALLIFE_3)
3868 strcpy(tempstr, "hit steals 3% life");
3869 if (x->_iFlags & ISPL_STEALLIFE_5)
3870 strcpy(tempstr, "hit steals 5% life");
3871 break;
3872 case IPL_TARGAC:
3873 strcpy(tempstr, "penetrates target's armor");
3874 break;
3875 case IPL_FASTATTACK:
3876 if (x->_iFlags & ISPL_QUICKATTACK)
3877 strcpy(tempstr, "quick attack");
3878 if (x->_iFlags & ISPL_FASTATTACK)
3879 strcpy(tempstr, "fast attack");
3880 if (x->_iFlags & ISPL_FASTERATTACK)
3881 strcpy(tempstr, "faster attack");
3882 if (x->_iFlags & ISPL_FASTESTATTACK)
3883 strcpy(tempstr, "fastest attack");
3884 break;
3885 case IPL_FASTRECOVER:
3886 if (x->_iFlags & ISPL_FASTRECOVER)
3887 strcpy(tempstr, "fast hit recovery");
3888 if (x->_iFlags & ISPL_FASTERRECOVER)
3889 strcpy(tempstr, "faster hit recovery");
3890 if (x->_iFlags & ISPL_FASTESTRECOVER)
3891 strcpy(tempstr, "fastest hit recovery");
3892 break;
3893 case IPL_FASTBLOCK:
3894 strcpy(tempstr, "fast block");
3895 break;
3896 case IPL_DAMMOD:
3897 sprintf(tempstr, "adds %i points to damage", x->_iPLDamMod);
3898 break;
3899 case IPL_RNDARROWVEL:
3900 strcpy(tempstr, "fires random speed arrows");
3901 break;
3902 case IPL_SETDAM:
3903 sprintf(tempstr, "unusual item damage");
3904 break;
3905 case IPL_SETDUR:
3906 strcpy(tempstr, "altered durability");
3907 break;
3908 case IPL_FASTSWING:
3909 strcpy(tempstr, "Faster attack swing");
3910 break;
3911 case IPL_ONEHAND:
3912 strcpy(tempstr, "one handed sword");
3913 break;
3914 case IPL_DRAINLIFE:
3915 strcpy(tempstr, "constantly lose hit points");
3916 break;
3917 case IPL_RNDSTEALLIFE:
3918 strcpy(tempstr, "life stealing");
3919 break;
3920 case IPL_NOMINSTR:
3921 strcpy(tempstr, "no strength requirement");
3922 break;
3923 case IPL_INFRAVISION:
3924 strcpy(tempstr, "see with infravision");
3925 break;
3926 case IPL_INVCURS:
3927 strcpy(tempstr, " ");
3928 break;
3929 case IPL_ADDACLIFE:
3930 if (x->_iFMinDam == x->_iFMaxDam)
3931 sprintf(tempstr, "lightning damage: %i", x->_iFMinDam);
3932 else
3933 sprintf(tempstr, "lightning damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
3934 break;
3935 case IPL_ADDMANAAC:
3936 strcpy(tempstr, "charged bolts on hits");
3937 break;
3938 case IPL_FIRERESCLVL:
3939 if (x->_iPLFR <= 0)
3940 sprintf(tempstr, " ");
3941 else if (x->_iPLFR >= 1)
3942 sprintf(tempstr, "Resist Fire: %+i%%", x->_iPLFR);
3943 break;
3944 case IPL_DEVASTATION:
3945 strcpy(tempstr, "occasional triple damage");
3946 break;
3947 case IPL_DECAY:
3948 sprintf(tempstr, "decaying %+i%% damage", x->_iPLDam);
3949 break;
3950 case IPL_PERIL:
3951 strcpy(tempstr, "2x dmg to monst, 1x to you");
3952 break;
3953 case IPL_JESTERS:
3954 strcpy(tempstr, "Random 0 - 500% damage");
3955 break;
3956 case IPL_CRYSTALLINE:
3957 sprintf(tempstr, "low dur, %+i%% damage", x->_iPLDam);
3958 break;
3959 case IPL_DOPPELGANGER:
3960 sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam);
3961 break;
3962 case IPL_ACDEMON:
3963 sprintf(tempstr, "extra AC vs demons");
3964 break;
3965 case IPL_ACUNDEAD:
3966 sprintf(tempstr, "extra AC vs undead");
3967 break;
3968 case IPL_MANATOLIFE:
3969 sprintf(tempstr, "50%% Mana moved to Health");
3970 break;
3971 case IPL_LIFETOMANA:
3972 sprintf(tempstr, "40%% Health moved to Mana");
3973 break;
3974 default:
3975 strcpy(tempstr, "Another ability (NW)");
3976 break;
3977 }
3978 }
3979
DrawUTextBack(CelOutputBuffer out)3980 static void DrawUTextBack(CelOutputBuffer out)
3981 {
3982 CelDrawTo(out, RIGHT_PANEL_X - SPANEL_WIDTH + 24, 327, pSTextBoxCels, 1, 271);
3983 DrawHalfTransparentRectTo(out, RIGHT_PANEL_X - SPANEL_WIDTH + 27, 28, 265, 297);
3984 }
3985
PrintUString(CelOutputBuffer out,int x,int y,BOOL cjustflag,const char * str,text_color col)3986 void PrintUString(CelOutputBuffer out, int x, int y, BOOL cjustflag, const char *str, text_color col)
3987 {
3988 int len, width, sx, sy, i, k;
3989 BYTE c;
3990
3991 sx = x + 32;
3992 sy = y * 12 + 44;
3993 len = strlen(str);
3994 k = 0;
3995 if (cjustflag) {
3996 width = 0;
3997 for (i = 0; i < len; i++)
3998 width += fontkern[fontframe[gbFontTransTbl[(BYTE)str[i]]]] + 1;
3999 if (width < 257)
4000 k = (257 - width) >> 1;
4001 sx += k;
4002 }
4003
4004 for (i = 0; i < len; i++) {
4005 c = fontframe[gbFontTransTbl[(BYTE)str[i]]];
4006 k += fontkern[c] + 1;
4007 if (c && k <= 257) {
4008 PrintChar(out, sx, sy, c, col);
4009 }
4010 sx += fontkern[c] + 1;
4011 }
4012 }
4013
DrawULine(CelOutputBuffer out,int y)4014 static void DrawULine(CelOutputBuffer out, int y)
4015 {
4016 BYTE *src = out.at(26 + RIGHT_PANEL - SPANEL_WIDTH, 25);
4017 BYTE *dst = out.at(26 + RIGHT_PANEL_X - SPANEL_WIDTH, y * 12 + 38);
4018
4019 for (int i = 0; i < 3; i++, src += out.pitch(), dst += out.pitch())
4020 memcpy(dst, src, 267); // BUGFIX: should be 267 (fixed)
4021 }
4022
DrawUniqueInfo(CelOutputBuffer out)4023 void DrawUniqueInfo(CelOutputBuffer out)
4024 {
4025 int uid, y;
4026
4027 if ((!chrflag && !questlog) || gnScreenWidth >= SPANEL_WIDTH * 3) {
4028 uid = curruitem._iUid;
4029 DrawUTextBack(GlobalBackBuffer());
4030 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, 2, TRUE, UniqueItemList[uid].UIName, COL_GOLD);
4031 DrawULine(out, 5);
4032 PrintItemPower(UniqueItemList[uid].UIPower1, &curruitem);
4033 y = 6 - UniqueItemList[uid].UINumPL + 8;
4034 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y, TRUE, tempstr, COL_WHITE);
4035 if (UniqueItemList[uid].UINumPL > 1) {
4036 PrintItemPower(UniqueItemList[uid].UIPower2, &curruitem);
4037 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 2, TRUE, tempstr, COL_WHITE);
4038 }
4039 if (UniqueItemList[uid].UINumPL > 2) {
4040 PrintItemPower(UniqueItemList[uid].UIPower3, &curruitem);
4041 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 4, TRUE, tempstr, COL_WHITE);
4042 }
4043 if (UniqueItemList[uid].UINumPL > 3) {
4044 PrintItemPower(UniqueItemList[uid].UIPower4, &curruitem);
4045 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 6, TRUE, tempstr, COL_WHITE);
4046 }
4047 if (UniqueItemList[uid].UINumPL > 4) {
4048 PrintItemPower(UniqueItemList[uid].UIPower5, &curruitem);
4049 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 8, TRUE, tempstr, COL_WHITE);
4050 }
4051 if (UniqueItemList[uid].UINumPL > 5) {
4052 PrintItemPower(UniqueItemList[uid].UIPower6, &curruitem);
4053 PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 10, TRUE, tempstr, COL_WHITE);
4054 }
4055 }
4056 }
4057
PrintItemMisc(ItemStruct * x)4058 void PrintItemMisc(ItemStruct *x)
4059 {
4060 if (x->_iMiscId == IMISC_SCROLL) {
4061 strcpy(tempstr, "Right-click to read");
4062 AddPanelString(tempstr, TRUE);
4063 }
4064 if (x->_iMiscId == IMISC_SCROLLT) {
4065 strcpy(tempstr, "Right-click to read, then");
4066 AddPanelString(tempstr, TRUE);
4067 strcpy(tempstr, "left-click to target");
4068 AddPanelString(tempstr, TRUE);
4069 }
4070 if (x->_iMiscId >= IMISC_USEFIRST && x->_iMiscId <= IMISC_USELAST) {
4071 PrintItemOil(x->_iMiscId);
4072 strcpy(tempstr, "Right-click to use");
4073 AddPanelString(tempstr, TRUE);
4074 }
4075 if (x->_iMiscId > IMISC_OILFIRST && x->_iMiscId < IMISC_OILLAST) {
4076 PrintItemOil(x->_iMiscId);
4077 strcpy(tempstr, "Right click to use");
4078 AddPanelString(tempstr, TRUE);
4079 }
4080 if (x->_iMiscId > IMISC_RUNEFIRST && x->_iMiscId < IMISC_RUNELAST) {
4081 PrintItemOil(x->_iMiscId);
4082 strcpy(tempstr, "Right click to use");
4083 AddPanelString(tempstr, TRUE);
4084 }
4085 if (x->_iMiscId == IMISC_BOOK) {
4086 strcpy(tempstr, "Right-click to read");
4087 AddPanelString(tempstr, TRUE);
4088 }
4089 if (x->_iMiscId == IMISC_NOTE) {
4090 strcpy(tempstr, "Right click to read");
4091 AddPanelString(tempstr, TRUE);
4092 }
4093 if (x->_iMiscId == IMISC_MAPOFDOOM) {
4094 strcpy(tempstr, "Right-click to view");
4095 AddPanelString(tempstr, TRUE);
4096 }
4097 if (x->_iMiscId == IMISC_EAR) {
4098 sprintf(tempstr, "Level: %i", x->_ivalue);
4099 AddPanelString(tempstr, TRUE);
4100 }
4101 if (x->_iMiscId == IMISC_AURIC) {
4102 sprintf(tempstr, "Doubles gold capacity");
4103 AddPanelString(tempstr, TRUE);
4104 }
4105 }
4106
PrintItemInfo(ItemStruct * x)4107 static void PrintItemInfo(ItemStruct *x)
4108 {
4109 PrintItemMisc(x);
4110 Uint8 str = x->_iMinStr;
4111 Uint8 dex = x->_iMinDex;
4112 Uint8 mag = x->_iMinMag;
4113 if (str != 0 || mag != 0 || dex != 0) {
4114 strcpy(tempstr, "Required:");
4115 if (str)
4116 sprintf(tempstr + strlen(tempstr), " %i Str", str);
4117 if (mag)
4118 sprintf(tempstr + strlen(tempstr), " %i Mag", mag);
4119 if (dex)
4120 sprintf(tempstr + strlen(tempstr), " %i Dex", dex);
4121 AddPanelString(tempstr, TRUE);
4122 }
4123 pinfoflag = TRUE;
4124 }
4125
PrintItemDetails(ItemStruct * x)4126 void PrintItemDetails(ItemStruct *x)
4127 {
4128 if (x->_iClass == ICLASS_WEAPON) {
4129 if (x->_iMinDam == x->_iMaxDam) {
4130 if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
4131 sprintf(tempstr, "damage: %i Indestructible", x->_iMinDam);
4132 else
4133 sprintf(tempstr, "damage: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur);
4134 } else {
4135 if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
4136 sprintf(tempstr, "damage: %i-%i Indestructible", x->_iMinDam, x->_iMaxDam);
4137 else
4138 sprintf(tempstr, "damage: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur);
4139 }
4140 AddPanelString(tempstr, TRUE);
4141 }
4142 if (x->_iClass == ICLASS_ARMOR) {
4143 if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
4144 sprintf(tempstr, "armor: %i Indestructible", x->_iAC);
4145 else
4146 sprintf(tempstr, "armor: %i Dur: %i/%i", x->_iAC, x->_iDurability, x->_iMaxDur);
4147 AddPanelString(tempstr, TRUE);
4148 }
4149 if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
4150 if (x->_iMinDam == x->_iMaxDam)
4151 sprintf(tempstr, "dam: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur);
4152 else
4153 sprintf(tempstr, "dam: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur);
4154 sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
4155 AddPanelString(tempstr, TRUE);
4156 }
4157 if (x->_iPrePower != -1) {
4158 PrintItemPower(x->_iPrePower, x);
4159 AddPanelString(tempstr, TRUE);
4160 }
4161 if (x->_iSufPower != -1) {
4162 PrintItemPower(x->_iSufPower, x);
4163 AddPanelString(tempstr, TRUE);
4164 }
4165 if (x->_iMagical == ITEM_QUALITY_UNIQUE) {
4166 AddPanelString("unique item", TRUE);
4167 uitemflag = TRUE;
4168 curruitem = *x;
4169 }
4170 PrintItemInfo(x);
4171 }
4172
PrintItemDur(ItemStruct * x)4173 void PrintItemDur(ItemStruct *x)
4174 {
4175 if (x->_iClass == ICLASS_WEAPON) {
4176 if (x->_iMinDam == x->_iMaxDam) {
4177 if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
4178 sprintf(tempstr, "damage: %i Indestructible", x->_iMinDam);
4179 else
4180 sprintf(tempstr, "damage: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur);
4181 } else {
4182 if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
4183 sprintf(tempstr, "damage: %i-%i Indestructible", x->_iMinDam, x->_iMaxDam);
4184 else
4185 sprintf(tempstr, "damage: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur);
4186 }
4187 AddPanelString(tempstr, TRUE);
4188 if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
4189 sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
4190 AddPanelString(tempstr, TRUE);
4191 }
4192 if (x->_iMagical != ITEM_QUALITY_NORMAL)
4193 AddPanelString("Not Identified", TRUE);
4194 }
4195 if (x->_iClass == ICLASS_ARMOR) {
4196 if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
4197 sprintf(tempstr, "armor: %i Indestructible", x->_iAC);
4198 else
4199 sprintf(tempstr, "armor: %i Dur: %i/%i", x->_iAC, x->_iDurability, x->_iMaxDur);
4200 AddPanelString(tempstr, TRUE);
4201 if (x->_iMagical != ITEM_QUALITY_NORMAL)
4202 AddPanelString("Not Identified", TRUE);
4203 if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
4204 sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
4205 AddPanelString(tempstr, TRUE);
4206 }
4207 }
4208 if (x->_itype == ITYPE_RING || x->_itype == ITYPE_AMULET)
4209 AddPanelString("Not Identified", TRUE);
4210 PrintItemInfo(x);
4211 }
4212
UseItem(int p,item_misc_id Mid,spell_id spl)4213 void UseItem(int p, item_misc_id Mid, spell_id spl)
4214 {
4215 int l, j;
4216
4217 switch (Mid) {
4218 case IMISC_HEAL:
4219 case IMISC_FOOD:
4220 j = plr[p]._pMaxHP >> 8;
4221 l = ((j >> 1) + random_(39, j)) << 6;
4222 if (plr[p]._pClass == PC_WARRIOR || plr[p]._pClass == PC_BARBARIAN)
4223 l <<= 1;
4224 if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD)
4225 l += l >> 1;
4226 plr[p]._pHitPoints += l;
4227 if (plr[p]._pHitPoints > plr[p]._pMaxHP)
4228 plr[p]._pHitPoints = plr[p]._pMaxHP;
4229 plr[p]._pHPBase += l;
4230 if (plr[p]._pHPBase > plr[p]._pMaxHPBase)
4231 plr[p]._pHPBase = plr[p]._pMaxHPBase;
4232 drawhpflag = TRUE;
4233 break;
4234 case IMISC_FULLHEAL:
4235 plr[p]._pHitPoints = plr[p]._pMaxHP;
4236 plr[p]._pHPBase = plr[p]._pMaxHPBase;
4237 drawhpflag = TRUE;
4238 break;
4239 case IMISC_MANA:
4240 j = plr[p]._pMaxMana >> 8;
4241 l = ((j >> 1) + random_(40, j)) << 6;
4242 if (plr[p]._pClass == PC_SORCERER)
4243 l <<= 1;
4244 if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD)
4245 l += l >> 1;
4246 if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
4247 plr[p]._pMana += l;
4248 if (plr[p]._pMana > plr[p]._pMaxMana)
4249 plr[p]._pMana = plr[p]._pMaxMana;
4250 plr[p]._pManaBase += l;
4251 if (plr[p]._pManaBase > plr[p]._pMaxManaBase)
4252 plr[p]._pManaBase = plr[p]._pMaxManaBase;
4253 drawmanaflag = TRUE;
4254 }
4255 break;
4256 case IMISC_FULLMANA:
4257 if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
4258 plr[p]._pMana = plr[p]._pMaxMana;
4259 plr[p]._pManaBase = plr[p]._pMaxManaBase;
4260 drawmanaflag = TRUE;
4261 }
4262 break;
4263 case IMISC_ELIXSTR:
4264 ModifyPlrStr(p, 1);
4265 break;
4266 case IMISC_ELIXMAG:
4267 ModifyPlrMag(p, 1);
4268 if (gbIsHellfire) {
4269 plr[p]._pMana = plr[p]._pMaxMana;
4270 plr[p]._pManaBase = plr[p]._pMaxManaBase;
4271 drawmanaflag = TRUE;
4272 }
4273 break;
4274 case IMISC_ELIXDEX:
4275 ModifyPlrDex(p, 1);
4276 break;
4277 case IMISC_ELIXVIT:
4278 ModifyPlrVit(p, 1);
4279 if (gbIsHellfire) {
4280 plr[p]._pHitPoints = plr[p]._pMaxHP;
4281 plr[p]._pHPBase = plr[p]._pMaxHPBase;
4282 drawhpflag = TRUE;
4283 }
4284 break;
4285 case IMISC_REJUV:
4286 j = plr[p]._pMaxHP >> 8;
4287 l = ((j >> 1) + random_(39, j)) << 6;
4288 if (plr[p]._pClass == PC_WARRIOR || plr[p]._pClass == PC_BARBARIAN)
4289 l <<= 1;
4290 if (plr[p]._pClass == PC_ROGUE)
4291 l += l >> 1;
4292 plr[p]._pHitPoints += l;
4293 if (plr[p]._pHitPoints > plr[p]._pMaxHP)
4294 plr[p]._pHitPoints = plr[p]._pMaxHP;
4295 plr[p]._pHPBase += l;
4296 if (plr[p]._pHPBase > plr[p]._pMaxHPBase)
4297 plr[p]._pHPBase = plr[p]._pMaxHPBase;
4298 drawhpflag = TRUE;
4299 j = plr[p]._pMaxMana >> 8;
4300 l = ((j >> 1) + random_(40, j)) << 6;
4301 if (plr[p]._pClass == PC_SORCERER)
4302 l <<= 1;
4303 if (plr[p]._pClass == PC_ROGUE)
4304 l += l >> 1;
4305 if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
4306 plr[p]._pMana += l;
4307 if (plr[p]._pMana > plr[p]._pMaxMana)
4308 plr[p]._pMana = plr[p]._pMaxMana;
4309 plr[p]._pManaBase += l;
4310 if (plr[p]._pManaBase > plr[p]._pMaxManaBase)
4311 plr[p]._pManaBase = plr[p]._pMaxManaBase;
4312 drawmanaflag = TRUE;
4313 }
4314 break;
4315 case IMISC_FULLREJUV:
4316 plr[p]._pHitPoints = plr[p]._pMaxHP;
4317 plr[p]._pHPBase = plr[p]._pMaxHPBase;
4318 drawhpflag = TRUE;
4319 if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
4320 plr[p]._pMana = plr[p]._pMaxMana;
4321 plr[p]._pManaBase = plr[p]._pMaxManaBase;
4322 drawmanaflag = TRUE;
4323 }
4324 break;
4325 case IMISC_SCROLL:
4326 if (spelldata[spl].sTargeted) {
4327 plr[p]._pTSpell = spl;
4328 plr[p]._pTSplType = RSPLTYPE_INVALID;
4329 if (p == myplr)
4330 NewCursor(CURSOR_TELEPORT);
4331 } else {
4332 ClrPlrPath(p);
4333 plr[p]._pSpell = spl;
4334 plr[p]._pSplType = RSPLTYPE_INVALID;
4335 plr[p]._pSplFrom = 3;
4336 plr[p].destAction = ACTION_SPELL;
4337 plr[p].destParam1 = cursmx;
4338 plr[p].destParam2 = cursmy;
4339 if (p == myplr && spl == SPL_NOVA)
4340 NetSendCmdLoc(TRUE, CMD_NOVA, cursmx, cursmy);
4341 }
4342 break;
4343 case IMISC_SCROLLT:
4344 if (spelldata[spl].sTargeted) {
4345 plr[p]._pTSpell = spl;
4346 plr[p]._pTSplType = RSPLTYPE_INVALID;
4347 if (p == myplr)
4348 NewCursor(CURSOR_TELEPORT);
4349 } else {
4350 ClrPlrPath(p);
4351 plr[p]._pSpell = spl;
4352 plr[p]._pSplType = RSPLTYPE_INVALID;
4353 plr[p]._pSplFrom = 3;
4354 plr[p].destAction = ACTION_SPELL;
4355 plr[p].destParam1 = cursmx;
4356 plr[p].destParam2 = cursmy;
4357 }
4358 break;
4359 case IMISC_BOOK:
4360 plr[p]._pMemSpells |= GetSpellBitmask(spl);
4361 if (plr[p]._pSplLvl[spl] < MAX_SPELL_LEVEL)
4362 plr[p]._pSplLvl[spl]++;
4363 if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
4364 plr[p]._pMana += spelldata[spl].sManaCost << 6;
4365 if (plr[p]._pMana > plr[p]._pMaxMana)
4366 plr[p]._pMana = plr[p]._pMaxMana;
4367 plr[p]._pManaBase += spelldata[spl].sManaCost << 6;
4368 if (plr[p]._pManaBase > plr[p]._pMaxManaBase)
4369 plr[p]._pManaBase = plr[p]._pMaxManaBase;
4370 }
4371 if (p == myplr)
4372 CalcPlrBookVals(p);
4373 drawmanaflag = TRUE;
4374 break;
4375 case IMISC_MAPOFDOOM:
4376 doom_init();
4377 break;
4378 case IMISC_OILACC:
4379 case IMISC_OILMAST:
4380 case IMISC_OILSHARP:
4381 case IMISC_OILDEATH:
4382 case IMISC_OILSKILL:
4383 case IMISC_OILBSMTH:
4384 case IMISC_OILFORT:
4385 case IMISC_OILPERM:
4386 case IMISC_OILHARD:
4387 case IMISC_OILIMP:
4388 plr[p]._pOilType = Mid;
4389 if (p != myplr) {
4390 return;
4391 }
4392 if (sbookflag) {
4393 sbookflag = FALSE;
4394 }
4395 if (!invflag) {
4396 invflag = TRUE;
4397 }
4398 NewCursor(CURSOR_OIL);
4399 break;
4400 case IMISC_SPECELIX:
4401 ModifyPlrStr(p, 3);
4402 ModifyPlrMag(p, 3);
4403 ModifyPlrDex(p, 3);
4404 ModifyPlrVit(p, 3);
4405 break;
4406 case IMISC_RUNEF:
4407 plr[p]._pTSpell = SPL_RUNEFIRE;
4408 plr[p]._pTSplType = RSPLTYPE_INVALID;
4409 if (p == myplr)
4410 NewCursor(CURSOR_TELEPORT);
4411 break;
4412 case IMISC_RUNEL:
4413 plr[p]._pTSpell = SPL_RUNELIGHT;
4414 plr[p]._pTSplType = RSPLTYPE_INVALID;
4415 if (p == myplr)
4416 NewCursor(CURSOR_TELEPORT);
4417 break;
4418 case IMISC_GR_RUNEL:
4419 plr[p]._pTSpell = SPL_RUNENOVA;
4420 plr[p]._pTSplType = RSPLTYPE_INVALID;
4421 if (p == myplr)
4422 NewCursor(CURSOR_TELEPORT);
4423 break;
4424 case IMISC_GR_RUNEF:
4425 plr[p]._pTSpell = SPL_RUNEIMMOLAT;
4426 plr[p]._pTSplType = RSPLTYPE_INVALID;
4427 if (p == myplr)
4428 NewCursor(CURSOR_TELEPORT);
4429 break;
4430 case IMISC_RUNES:
4431 plr[p]._pTSpell = SPL_RUNESTONE;
4432 plr[p]._pTSplType = RSPLTYPE_INVALID;
4433 if (p == myplr)
4434 NewCursor(CURSOR_TELEPORT);
4435 break;
4436 default:
4437 break;
4438 }
4439 }
4440
StoreStatOk(ItemStruct * h)4441 BOOL StoreStatOk(ItemStruct *h)
4442 {
4443 BOOL sf;
4444
4445 sf = TRUE;
4446 if (plr[myplr]._pStrength < h->_iMinStr)
4447 sf = FALSE;
4448 if (plr[myplr]._pMagic < h->_iMinMag)
4449 sf = FALSE;
4450 if (plr[myplr]._pDexterity < h->_iMinDex)
4451 sf = FALSE;
4452
4453 return sf;
4454 }
4455
SmithItemOk(int i)4456 BOOL SmithItemOk(int i)
4457 {
4458 BOOL rv;
4459
4460 rv = TRUE;
4461 if (AllItemsList[i].itype == ITYPE_MISC)
4462 rv = FALSE;
4463 if (AllItemsList[i].itype == ITYPE_GOLD)
4464 rv = FALSE;
4465 if (AllItemsList[i].itype == ITYPE_STAFF && (!gbIsHellfire || AllItemsList[i].iSpell))
4466 rv = FALSE;
4467 if (AllItemsList[i].itype == ITYPE_RING)
4468 rv = FALSE;
4469 if (AllItemsList[i].itype == ITYPE_AMULET)
4470 rv = FALSE;
4471
4472 return rv;
4473 }
4474
RndSmithItem(int lvl)4475 int RndSmithItem(int lvl)
4476 {
4477 int i, ri;
4478 int ril[512];
4479
4480 ri = 0;
4481 for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
4482 if (!IsItemAvailable(i))
4483 continue;
4484
4485 if (AllItemsList[i].iRnd != IDROP_NEVER && SmithItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
4486 && ri < 512) {
4487 ril[ri] = i;
4488 ri++;
4489 if (AllItemsList[i].iRnd == IDROP_DOUBLE
4490 && ri < 512) {
4491 ril[ri] = i;
4492 ri++;
4493 }
4494 }
4495 }
4496
4497 return ril[random_(50, ri)] + 1;
4498 }
4499
BubbleSwapItem(ItemStruct * a,ItemStruct * b)4500 void BubbleSwapItem(ItemStruct *a, ItemStruct *b)
4501 {
4502 ItemStruct h;
4503
4504 h = *a;
4505 *a = *b;
4506 *b = h;
4507 }
4508
SortSmith()4509 void SortSmith()
4510 {
4511 int j, k;
4512 BOOL sorted;
4513
4514 j = 0;
4515 while (!smithitem[j + 1].isEmpty()) {
4516 j++;
4517 }
4518
4519 sorted = FALSE;
4520 while (j > 0 && !sorted) {
4521 sorted = TRUE;
4522 for (k = 0; k < j; k++) {
4523 if (smithitem[k].IDidx > smithitem[k + 1].IDidx) {
4524 BubbleSwapItem(&smithitem[k], &smithitem[k + 1]);
4525 sorted = FALSE;
4526 }
4527 }
4528 j--;
4529 }
4530 }
4531
SpawnSmith(int lvl)4532 void SpawnSmith(int lvl)
4533 {
4534 int i, iCnt, idata;
4535 int maxValue, maxItems;
4536
4537 ItemStruct holditem;
4538 holditem = item[0];
4539
4540 if (gbIsHellfire) {
4541 maxValue = 200000;
4542 maxItems = 25;
4543 } else {
4544 maxValue = 140000;
4545 maxItems = 20;
4546 }
4547
4548 iCnt = random_(50, maxItems - 10) + 10;
4549 for (i = 0; i < iCnt; i++) {
4550 do {
4551 memset(&item[0], 0, sizeof(*item));
4552 item[0]._iSeed = AdvanceRndSeed();
4553 SetRndSeed(item[0]._iSeed);
4554 idata = RndSmithItem(lvl) - 1;
4555 GetItemAttrs(0, idata, lvl);
4556 } while (item[0]._iIvalue > maxValue);
4557 smithitem[i] = item[0];
4558 smithitem[i]._iCreateInfo = lvl | CF_SMITH;
4559 smithitem[i]._iIdentified = TRUE;
4560 smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]);
4561 }
4562 for (i = iCnt; i < SMITH_ITEMS; i++)
4563 smithitem[i]._itype = ITYPE_NONE;
4564
4565 SortSmith();
4566 item[0] = holditem;
4567 }
4568
PremiumItemOk(int i)4569 BOOL PremiumItemOk(int i)
4570 {
4571 BOOL rv;
4572
4573 rv = TRUE;
4574 if (AllItemsList[i].itype == ITYPE_MISC)
4575 rv = FALSE;
4576 if (AllItemsList[i].itype == ITYPE_GOLD)
4577 rv = FALSE;
4578 if (!gbIsHellfire && AllItemsList[i].itype == ITYPE_STAFF)
4579 rv = FALSE;
4580
4581 if (gbIsMultiplayer) {
4582 if (AllItemsList[i].iMiscId == IMISC_OILOF)
4583 rv = FALSE;
4584 if (AllItemsList[i].itype == ITYPE_RING)
4585 rv = FALSE;
4586 if (AllItemsList[i].itype == ITYPE_AMULET)
4587 rv = FALSE;
4588 }
4589
4590 return rv;
4591 }
4592
RndPremiumItem(int minlvl,int maxlvl)4593 int RndPremiumItem(int minlvl, int maxlvl)
4594 {
4595 int i, ri;
4596 int ril[512];
4597
4598 ri = 0;
4599 for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
4600 if (!IsItemAvailable(i))
4601 continue;
4602
4603 if (AllItemsList[i].iRnd != IDROP_NEVER) {
4604 if (PremiumItemOk(i)) {
4605 if (AllItemsList[i].iMinMLvl >= minlvl && AllItemsList[i].iMinMLvl <= maxlvl && ri < 512) {
4606 ril[ri] = i;
4607 ri++;
4608 }
4609 }
4610 }
4611 }
4612
4613 return ril[random_(50, ri)] + 1;
4614 }
4615
SpawnOnePremium(int i,int plvl,int myplr)4616 static void SpawnOnePremium(int i, int plvl, int myplr)
4617 {
4618 int ivalue;
4619 bool keepgoing = false;
4620 ItemStruct holditem = item[0];
4621
4622 int strength = get_max_strength(plr[myplr]._pClass);
4623 if (strength < plr[myplr]._pStrength) {
4624 strength = plr[myplr]._pStrength;
4625 }
4626 strength *= 1.2;
4627
4628 int dexterity = get_max_dexterity(plr[myplr]._pClass);
4629 if (dexterity < plr[myplr]._pDexterity) {
4630 dexterity = plr[myplr]._pDexterity;
4631 }
4632 dexterity *= 1.2;
4633
4634 int magic = get_max_magic(plr[myplr]._pClass);
4635 if (magic < plr[myplr]._pMagic) {
4636 magic = plr[myplr]._pMagic;
4637 }
4638 magic *= 1.2;
4639
4640 if (plvl > 30)
4641 plvl = 30;
4642 if (plvl < 1)
4643 plvl = 1;
4644
4645 int count = 0;
4646
4647 do {
4648 keepgoing = false;
4649 memset(&item[0], 0, sizeof(*item));
4650 item[0]._iSeed = AdvanceRndSeed();
4651 SetRndSeed(item[0]._iSeed);
4652 int itype = RndPremiumItem(plvl >> 2, plvl) - 1;
4653 GetItemAttrs(0, itype, plvl);
4654 GetItemBonus(0, itype, plvl >> 1, plvl, TRUE, !gbIsHellfire);
4655
4656 if (!gbIsHellfire) {
4657 if (item[0]._iIvalue > 140000) {
4658 keepgoing = true; // prevent breaking the do/while loop too early by failing hellfire's condition in while
4659 continue;
4660 }
4661 break;
4662 }
4663
4664 switch (item[0]._itype) {
4665 case ITYPE_LARMOR:
4666 case ITYPE_MARMOR:
4667 case ITYPE_HARMOR:
4668 ivalue = get_armor_max_value(myplr);
4669 break;
4670 case ITYPE_SHIELD:
4671 ivalue = get_shield_max_value(myplr);
4672 break;
4673 case ITYPE_AXE:
4674 ivalue = get_axe_max_value(myplr);
4675 break;
4676 case ITYPE_BOW:
4677 ivalue = get_bow_max_value(myplr);
4678 break;
4679 case ITYPE_MACE:
4680 ivalue = get_mace_max_value(myplr);
4681 break;
4682 case ITYPE_SWORD:
4683 ivalue = get_sword_max_value(myplr);
4684 break;
4685 case ITYPE_HELM:
4686 ivalue = get_helm_max_value(myplr);
4687 break;
4688 case ITYPE_STAFF:
4689 ivalue = get_staff_max_value(myplr);
4690 break;
4691 case ITYPE_RING:
4692 ivalue = get_ring_max_value(myplr);
4693 break;
4694 case ITYPE_AMULET:
4695 ivalue = get_amulet_max_value(myplr);
4696 break;
4697 default:
4698 ivalue = 0;
4699 break;
4700 }
4701 ivalue *= 0.8;
4702
4703 count++;
4704 } while (keepgoing || ((item[0]._iIvalue > 200000
4705 || item[0]._iMinStr > strength
4706 || item[0]._iMinMag > magic
4707 || item[0]._iMinDex > dexterity
4708 || item[0]._iIvalue < ivalue)
4709 && count < 150));
4710 premiumitem[i] = item[0];
4711 premiumitem[i]._iCreateInfo = plvl | CF_SMITHPREMIUM;
4712 premiumitem[i]._iIdentified = TRUE;
4713 premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]);
4714 item[0] = holditem;
4715 }
4716
SpawnPremium(int pnum)4717 void SpawnPremium(int pnum)
4718 {
4719 int i;
4720
4721 int lvl = plr[pnum]._pLevel;
4722 int maxItems = gbIsHellfire ? SMITH_PREMIUM_ITEMS : 6;
4723 if (numpremium < maxItems) {
4724 for (i = 0; i < maxItems; i++) {
4725 if (premiumitem[i].isEmpty()) {
4726 int plvl = premiumlevel + (gbIsHellfire ? premiumLvlAddHellfire[i] : premiumlvladd[i]);
4727 SpawnOnePremium(i, plvl, pnum);
4728 }
4729 }
4730 numpremium = maxItems;
4731 }
4732 while (premiumlevel < lvl) {
4733 premiumlevel++;
4734 if (gbIsHellfire) {
4735 premiumitem[0] = premiumitem[3];
4736 premiumitem[1] = premiumitem[4];
4737 premiumitem[2] = premiumitem[5];
4738 premiumitem[3] = premiumitem[6];
4739 premiumitem[4] = premiumitem[7];
4740 premiumitem[5] = premiumitem[8];
4741 premiumitem[6] = premiumitem[9];
4742 premiumitem[7] = premiumitem[10];
4743 premiumitem[8] = premiumitem[11];
4744 premiumitem[9] = premiumitem[12];
4745 SpawnOnePremium(10, premiumlevel + premiumLvlAddHellfire[10], pnum);
4746 premiumitem[11] = premiumitem[13];
4747 SpawnOnePremium(12, premiumlevel + premiumLvlAddHellfire[12], pnum);
4748 premiumitem[13] = premiumitem[14];
4749 SpawnOnePremium(14, premiumlevel + premiumLvlAddHellfire[14], pnum);
4750 } else {
4751 premiumitem[0] = premiumitem[2];
4752 premiumitem[1] = premiumitem[3];
4753 premiumitem[2] = premiumitem[4];
4754 SpawnOnePremium(3, premiumlevel + premiumlvladd[3], pnum);
4755 premiumitem[4] = premiumitem[5];
4756 SpawnOnePremium(5, premiumlevel + premiumlvladd[5], pnum);
4757 }
4758 }
4759 }
4760
WitchItemOk(int i)4761 BOOL WitchItemOk(int i)
4762 {
4763 BOOL rv;
4764
4765 rv = FALSE;
4766 if (AllItemsList[i].itype == ITYPE_MISC)
4767 rv = TRUE;
4768 if (AllItemsList[i].itype == ITYPE_STAFF)
4769 rv = TRUE;
4770 if (AllItemsList[i].iMiscId == IMISC_MANA)
4771 rv = FALSE;
4772 if (AllItemsList[i].iMiscId == IMISC_FULLMANA)
4773 rv = FALSE;
4774 if (AllItemsList[i].iSpell == SPL_TOWN)
4775 rv = FALSE;
4776 if (AllItemsList[i].iMiscId == IMISC_FULLHEAL)
4777 rv = FALSE;
4778 if (AllItemsList[i].iMiscId == IMISC_HEAL)
4779 rv = FALSE;
4780 if (AllItemsList[i].iMiscId > IMISC_OILFIRST && AllItemsList[i].iMiscId < IMISC_OILLAST)
4781 rv = FALSE;
4782 if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
4783 rv = FALSE;
4784 if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
4785 rv = FALSE;
4786
4787 return rv;
4788 }
4789
RndWitchItem(int lvl)4790 int RndWitchItem(int lvl)
4791 {
4792 int i, ri;
4793 int ril[512];
4794
4795 ri = 0;
4796 for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
4797 if (!IsItemAvailable(i))
4798 continue;
4799
4800 if (AllItemsList[i].iRnd != IDROP_NEVER && WitchItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
4801 && ri < 512) {
4802
4803 ril[ri] = i;
4804 ri++;
4805 }
4806 }
4807
4808 return ril[random_(51, ri)] + 1;
4809 }
4810
SortWitch()4811 void SortWitch()
4812 {
4813 int j, k;
4814 BOOL sorted;
4815
4816 j = 3;
4817 while (!witchitem[j + 1].isEmpty()) {
4818 j++;
4819 }
4820
4821 sorted = FALSE;
4822 while (j > 3 && !sorted) {
4823 sorted = TRUE;
4824 for (k = 3; k < j; k++) {
4825 if (witchitem[k].IDidx > witchitem[k + 1].IDidx) {
4826 BubbleSwapItem(&witchitem[k], &witchitem[k + 1]);
4827 sorted = FALSE;
4828 }
4829 }
4830 j--;
4831 }
4832 }
4833
WitchBookLevel(int ii)4834 void WitchBookLevel(int ii)
4835 {
4836 int slvl;
4837
4838 if (witchitem[ii]._iMiscId == IMISC_BOOK) {
4839 witchitem[ii]._iMinMag = spelldata[witchitem[ii]._iSpell].sMinInt;
4840 slvl = plr[myplr]._pSplLvl[witchitem[ii]._iSpell];
4841 while (slvl) {
4842 witchitem[ii]._iMinMag += 20 * witchitem[ii]._iMinMag / 100;
4843 slvl--;
4844 if (witchitem[ii]._iMinMag + 20 * witchitem[ii]._iMinMag / 100 > 255) {
4845 witchitem[ii]._iMinMag = 255;
4846 slvl = 0;
4847 }
4848 }
4849 }
4850 }
4851
SpawnWitch(int lvl)4852 void SpawnWitch(int lvl)
4853 {
4854 int i, j, iCnt;
4855 int idata, maxlvl, maxValue;
4856
4857 j = 3;
4858
4859 memset(&item[0], 0, sizeof(*item));
4860 GetItemAttrs(0, IDI_MANA, 1);
4861 witchitem[0] = item[0];
4862 witchitem[0]._iCreateInfo = lvl;
4863 witchitem[0]._iStatFlag = TRUE;
4864 memset(&item[0], 0, sizeof(*item));
4865 GetItemAttrs(0, IDI_FULLMANA, 1);
4866 witchitem[1] = item[0];
4867 witchitem[1]._iCreateInfo = lvl;
4868 witchitem[1]._iStatFlag = TRUE;
4869 memset(&item[0], 0, sizeof(*item));
4870 GetItemAttrs(0, IDI_PORTAL, 1);
4871 witchitem[2] = item[0];
4872 witchitem[2]._iCreateInfo = lvl;
4873 witchitem[2]._iStatFlag = TRUE;
4874
4875 if (gbIsHellfire) {
4876 iCnt = random_(51, WITCH_ITEMS - 10) + 10;
4877 maxValue = 200000;
4878
4879 int bCnt;
4880 int books = random_(3, 4);
4881 for (i = 114, bCnt = 0; i <= 117 && bCnt < books; ++i) {
4882 if (WitchItemOk(i)
4883 && lvl >= AllItemsList[i].iMinMLvl) {
4884 memset(&item[0], 0, sizeof(*item));
4885 item[0]._iSeed = AdvanceRndSeed();
4886 SetRndSeed(item[0]._iSeed);
4887 random_(0, 1);
4888
4889 GetItemAttrs(0, i, lvl);
4890 witchitem[j] = item[0];
4891 witchitem[j]._iCreateInfo = lvl | CF_WITCH;
4892 witchitem[j]._iIdentified = TRUE;
4893 WitchBookLevel(j);
4894 witchitem[j]._iStatFlag = StoreStatOk(&witchitem[j]);
4895 j++;
4896 bCnt++;
4897 }
4898 }
4899 } else {
4900 iCnt = random_(51, WITCH_ITEMS - 12) + 10;
4901 maxValue = 140000;
4902 }
4903
4904 for (i = j; i < iCnt; i++) {
4905 do {
4906 memset(&item[0], 0, sizeof(*item));
4907 item[0]._iSeed = AdvanceRndSeed();
4908 SetRndSeed(item[0]._iSeed);
4909 idata = RndWitchItem(lvl) - 1;
4910 GetItemAttrs(0, idata, lvl);
4911 maxlvl = -1;
4912 if (random_(51, 100) <= 5)
4913 maxlvl = 2 * lvl;
4914 if (maxlvl == -1 && item[0]._iMiscId == IMISC_STAFF)
4915 maxlvl = 2 * lvl;
4916 if (maxlvl != -1)
4917 GetItemBonus(0, idata, maxlvl >> 1, maxlvl, TRUE, TRUE);
4918 } while (item[0]._iIvalue > maxValue);
4919 witchitem[i] = item[0];
4920 witchitem[i]._iCreateInfo = lvl | CF_WITCH;
4921 witchitem[i]._iIdentified = TRUE;
4922 WitchBookLevel(i);
4923 witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]);
4924 }
4925
4926 for (i = iCnt; i < WITCH_ITEMS; i++)
4927 witchitem[i]._itype = ITYPE_NONE;
4928
4929 SortWitch();
4930 }
4931
RndBoyItem(int lvl)4932 int RndBoyItem(int lvl)
4933 {
4934 int i, ri;
4935 int ril[512];
4936
4937 ri = 0;
4938 for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
4939 if (!IsItemAvailable(i))
4940 continue;
4941
4942 if (AllItemsList[i].iRnd != IDROP_NEVER && PremiumItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
4943 && ri < 512) {
4944 ril[ri] = i;
4945 ri++;
4946 }
4947 }
4948
4949 return ril[random_(49, ri)] + 1;
4950 }
4951
SpawnBoy(int lvl)4952 void SpawnBoy(int lvl)
4953 {
4954 int itype;
4955
4956 int ivalue;
4957 bool keepgoing = false;
4958 int count = 0;
4959
4960 int strength = get_max_strength(plr[myplr]._pClass);
4961 int dexterity = get_max_dexterity(plr[myplr]._pClass);
4962 int magic = get_max_magic(plr[myplr]._pClass);
4963 plr_class pc = plr[myplr]._pClass;
4964
4965 if (strength < plr[myplr]._pStrength) {
4966 strength = plr[myplr]._pStrength;
4967 }
4968 strength *= 1.2;
4969
4970 if (dexterity < plr[myplr]._pDexterity) {
4971 dexterity = plr[myplr]._pDexterity;
4972 }
4973 dexterity *= 1.2;
4974
4975 if (magic < plr[myplr]._pMagic) {
4976 magic = plr[myplr]._pMagic;
4977 }
4978 magic *= 1.2;
4979
4980 if (boylevel < (lvl >> 1) || boyitem.isEmpty()) {
4981 do {
4982 keepgoing = false;
4983 memset(&item[0], 0, sizeof(*item));
4984 item[0]._iSeed = AdvanceRndSeed();
4985 SetRndSeed(item[0]._iSeed);
4986 itype = RndBoyItem(lvl) - 1;
4987 GetItemAttrs(0, itype, lvl);
4988 GetItemBonus(0, itype, lvl, 2 * lvl, TRUE, TRUE);
4989
4990 if (!gbIsHellfire) {
4991 if (item[0]._iIvalue > 90000) {
4992 keepgoing = true; // prevent breaking the do/while loop too early by failing hellfire's condition in while
4993 continue;
4994 }
4995 break;
4996 }
4997
4998 ivalue = 0;
4999
5000 int itemType = item[0]._itype;
5001
5002 switch (itemType) {
5003 case ITYPE_LARMOR:
5004 case ITYPE_MARMOR:
5005 case ITYPE_HARMOR:
5006 ivalue = get_armor_max_value(myplr);
5007 break;
5008 case ITYPE_SHIELD:
5009 ivalue = get_shield_max_value(myplr);
5010 break;
5011 case ITYPE_AXE:
5012 ivalue = get_axe_max_value(myplr);
5013 break;
5014 case ITYPE_BOW:
5015 ivalue = get_bow_max_value(myplr);
5016 break;
5017 case ITYPE_MACE:
5018 ivalue = get_mace_max_value(myplr);
5019 break;
5020 case ITYPE_SWORD:
5021 ivalue = get_sword_max_value(myplr);
5022 break;
5023 case ITYPE_HELM:
5024 ivalue = get_helm_max_value(myplr);
5025 break;
5026 case ITYPE_STAFF:
5027 ivalue = get_staff_max_value(myplr);
5028 break;
5029 case ITYPE_RING:
5030 ivalue = get_ring_max_value(myplr);
5031 break;
5032 case ITYPE_AMULET:
5033 ivalue = get_amulet_max_value(myplr);
5034 break;
5035 }
5036 ivalue *= 0.8;
5037
5038 count++;
5039
5040 if (count < 200) {
5041 switch (pc) {
5042 case PC_WARRIOR:
5043 if (itemType == ITYPE_BOW || itemType == ITYPE_STAFF)
5044 ivalue = INT_MAX;
5045 break;
5046 case PC_ROGUE:
5047 if (itemType == ITYPE_SWORD || itemType == ITYPE_STAFF || itemType == ITYPE_AXE || itemType == ITYPE_MACE || itemType == ITYPE_SHIELD)
5048 ivalue = INT_MAX;
5049 break;
5050 case PC_SORCERER:
5051 if (itemType == ITYPE_STAFF || itemType == ITYPE_AXE || itemType == ITYPE_BOW || itemType == ITYPE_MACE)
5052 ivalue = INT_MAX;
5053 break;
5054 case PC_MONK:
5055 if (itemType == ITYPE_BOW || itemType == ITYPE_MARMOR || itemType == ITYPE_SHIELD || itemType == ITYPE_MACE)
5056 ivalue = INT_MAX;
5057 break;
5058 case PC_BARD:
5059 if (itemType == ITYPE_AXE || itemType == ITYPE_MACE || itemType == ITYPE_STAFF)
5060 ivalue = INT_MAX;
5061 break;
5062 case PC_BARBARIAN:
5063 if (itemType == ITYPE_BOW || itemType == ITYPE_STAFF)
5064 ivalue = INT_MAX;
5065 break;
5066 case NUM_CLASSES:
5067 break;
5068 }
5069 }
5070 } while (keepgoing || ((item[0]._iIvalue > 200000
5071 || item[0]._iMinStr > strength
5072 || item[0]._iMinMag > magic
5073 || item[0]._iMinDex > dexterity
5074 || item[0]._iIvalue < ivalue)
5075 && count < 250));
5076 boyitem = item[0];
5077 boyitem._iCreateInfo = lvl | CF_BOY;
5078 boyitem._iIdentified = TRUE;
5079 boyitem._iStatFlag = StoreStatOk(&boyitem);
5080 boylevel = lvl >> 1;
5081 }
5082 }
5083
HealerItemOk(int i)5084 BOOL HealerItemOk(int i)
5085 {
5086 if (AllItemsList[i].itype != ITYPE_MISC)
5087 return FALSE;
5088
5089 if (AllItemsList[i].iMiscId == IMISC_SCROLL)
5090 return AllItemsList[i].iSpell == SPL_HEAL;
5091 if (AllItemsList[i].iMiscId == IMISC_SCROLLT)
5092 return AllItemsList[i].iSpell == SPL_HEALOTHER && gbIsMultiplayer;
5093
5094 if (!gbIsMultiplayer) {
5095 if (AllItemsList[i].iMiscId == IMISC_ELIXSTR)
5096 return !gbIsHellfire || plr[myplr]._pBaseStr < MaxStats[plr[myplr]._pClass][ATTRIB_STR];
5097 if (AllItemsList[i].iMiscId == IMISC_ELIXMAG)
5098 return !gbIsHellfire || plr[myplr]._pBaseMag < MaxStats[plr[myplr]._pClass][ATTRIB_MAG];
5099 if (AllItemsList[i].iMiscId == IMISC_ELIXDEX)
5100 return !gbIsHellfire || plr[myplr]._pBaseDex < MaxStats[plr[myplr]._pClass][ATTRIB_DEX];
5101 if (AllItemsList[i].iMiscId == IMISC_ELIXVIT)
5102 return !gbIsHellfire || plr[myplr]._pBaseVit < MaxStats[plr[myplr]._pClass][ATTRIB_VIT];
5103 }
5104
5105 if (AllItemsList[i].iMiscId == IMISC_REJUV)
5106 return TRUE;
5107 if (AllItemsList[i].iMiscId == IMISC_FULLREJUV)
5108 return TRUE;
5109
5110 return FALSE;
5111 }
5112
RndHealerItem(int lvl)5113 int RndHealerItem(int lvl)
5114 {
5115 int i, ri;
5116 int ril[512];
5117
5118 ri = 0;
5119 for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
5120 if (!IsItemAvailable(i))
5121 continue;
5122
5123 if (AllItemsList[i].iRnd != IDROP_NEVER && HealerItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
5124 && ri < 512) {
5125 ril[ri] = i;
5126 ri++;
5127 }
5128 }
5129
5130 return ril[random_(50, ri)] + 1;
5131 }
5132
SortHealer()5133 void SortHealer()
5134 {
5135 int j, k;
5136 BOOL sorted;
5137
5138 j = 2;
5139 while (!healitem[j + 1].isEmpty()) {
5140 j++;
5141 }
5142
5143 sorted = FALSE;
5144 while (j > 2 && !sorted) {
5145 sorted = TRUE;
5146 for (k = 2; k < j; k++) {
5147 if (healitem[k].IDidx > healitem[k + 1].IDidx) {
5148 BubbleSwapItem(&healitem[k], &healitem[k + 1]);
5149 sorted = FALSE;
5150 }
5151 }
5152 j--;
5153 }
5154 }
5155
SpawnHealer(int lvl)5156 void SpawnHealer(int lvl)
5157 {
5158 int i, nsi, srnd, itype;
5159
5160 memset(&item[0], 0, sizeof(*item));
5161 GetItemAttrs(0, IDI_HEAL, 1);
5162 healitem[0] = item[0];
5163 healitem[0]._iCreateInfo = lvl;
5164 healitem[0]._iStatFlag = TRUE;
5165
5166 memset(&item[0], 0, sizeof(*item));
5167 GetItemAttrs(0, IDI_FULLHEAL, 1);
5168 healitem[1] = item[0];
5169 healitem[1]._iCreateInfo = lvl;
5170 healitem[1]._iStatFlag = TRUE;
5171
5172 if (gbIsMultiplayer) {
5173 memset(&item[0], 0, sizeof(*item));
5174 GetItemAttrs(0, IDI_RESURRECT, 1);
5175 healitem[2] = item[0];
5176 healitem[2]._iCreateInfo = lvl;
5177 healitem[2]._iStatFlag = TRUE;
5178
5179 srnd = 3;
5180 } else {
5181 srnd = 2;
5182 }
5183 nsi = random_(50, gbIsHellfire ? 10 : 8) + 10;
5184 for (i = srnd; i < nsi; i++) {
5185 memset(&item[0], 0, sizeof(*item));
5186 item[0]._iSeed = AdvanceRndSeed();
5187 SetRndSeed(item[0]._iSeed);
5188 itype = RndHealerItem(lvl) - 1;
5189 GetItemAttrs(0, itype, lvl);
5190 healitem[i] = item[0];
5191 healitem[i]._iCreateInfo = lvl | CF_HEALER;
5192 healitem[i]._iIdentified = TRUE;
5193 healitem[i]._iStatFlag = StoreStatOk(&healitem[i]);
5194 }
5195 for (i = nsi; i < 20; i++) {
5196 healitem[i]._itype = ITYPE_NONE;
5197 }
5198 SortHealer();
5199 }
5200
SpawnStoreGold()5201 void SpawnStoreGold()
5202 {
5203 memset(&item[0], 0, sizeof(*item));
5204 GetItemAttrs(0, IDI_GOLD, 1);
5205 golditem = item[0];
5206 golditem._iStatFlag = TRUE;
5207 }
5208
RecreateSmithItem(int ii,int idx,int lvl,int iseed)5209 void RecreateSmithItem(int ii, int idx, int lvl, int iseed)
5210 {
5211 SetRndSeed(iseed);
5212 int itype = RndSmithItem(lvl) - 1;
5213 GetItemAttrs(ii, itype, lvl);
5214
5215 item[ii]._iSeed = iseed;
5216 item[ii]._iCreateInfo = lvl | CF_SMITH;
5217 item[ii]._iIdentified = TRUE;
5218 }
5219
RecreatePremiumItem(int ii,int idx,int plvl,int iseed)5220 void RecreatePremiumItem(int ii, int idx, int plvl, int iseed)
5221 {
5222 SetRndSeed(iseed);
5223 int itype = RndPremiumItem(plvl >> 2, plvl) - 1;
5224 GetItemAttrs(ii, itype, plvl);
5225 GetItemBonus(ii, itype, plvl >> 1, plvl, TRUE, !gbIsHellfire);
5226
5227 item[ii]._iSeed = iseed;
5228 item[ii]._iCreateInfo = plvl | CF_SMITHPREMIUM;
5229 item[ii]._iIdentified = TRUE;
5230 }
5231
RecreateBoyItem(int ii,int idx,int lvl,int iseed)5232 void RecreateBoyItem(int ii, int idx, int lvl, int iseed)
5233 {
5234 SetRndSeed(iseed);
5235 int itype = RndBoyItem(lvl) - 1;
5236 GetItemAttrs(ii, itype, lvl);
5237 GetItemBonus(ii, itype, lvl, 2 * lvl, TRUE, TRUE);
5238
5239 item[ii]._iSeed = iseed;
5240 item[ii]._iCreateInfo = lvl | CF_BOY;
5241 item[ii]._iIdentified = TRUE;
5242 }
5243
RecreateWitchItem(int ii,int idx,int lvl,int iseed)5244 void RecreateWitchItem(int ii, int idx, int lvl, int iseed)
5245 {
5246 if (idx == IDI_MANA || idx == IDI_FULLMANA || idx == IDI_PORTAL) {
5247 GetItemAttrs(ii, idx, lvl);
5248 } else if (gbIsHellfire && idx >= 114 && idx <= 117) {
5249 SetRndSeed(iseed);
5250 random_(0, 1);
5251 GetItemAttrs(ii, idx, lvl);
5252 } else {
5253 SetRndSeed(iseed);
5254 int itype = RndWitchItem(lvl) - 1;
5255 GetItemAttrs(ii, itype, lvl);
5256 int iblvl = -1;
5257 if (random_(51, 100) <= 5)
5258 iblvl = 2 * lvl;
5259 if (iblvl == -1 && item[ii]._iMiscId == IMISC_STAFF)
5260 iblvl = 2 * lvl;
5261 if (iblvl != -1)
5262 GetItemBonus(ii, itype, iblvl >> 1, iblvl, TRUE, TRUE);
5263 }
5264
5265 item[ii]._iSeed = iseed;
5266 item[ii]._iCreateInfo = lvl | CF_WITCH;
5267 item[ii]._iIdentified = TRUE;
5268 }
5269
RecreateHealerItem(int ii,int idx,int lvl,int iseed)5270 void RecreateHealerItem(int ii, int idx, int lvl, int iseed)
5271 {
5272 int itype;
5273
5274 if (idx == IDI_HEAL || idx == IDI_FULLHEAL || idx == IDI_RESURRECT) {
5275 GetItemAttrs(ii, idx, lvl);
5276 } else {
5277 SetRndSeed(iseed);
5278 itype = RndHealerItem(lvl) - 1;
5279 GetItemAttrs(ii, itype, lvl);
5280 }
5281
5282 item[ii]._iSeed = iseed;
5283 item[ii]._iCreateInfo = lvl | CF_HEALER;
5284 item[ii]._iIdentified = TRUE;
5285 }
5286
RecreateTownItem(int ii,int idx,WORD icreateinfo,int iseed,int ivalue)5287 void RecreateTownItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue)
5288 {
5289 if (icreateinfo & CF_SMITH)
5290 RecreateSmithItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
5291 else if (icreateinfo & CF_SMITHPREMIUM)
5292 RecreatePremiumItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
5293 else if (icreateinfo & CF_BOY)
5294 RecreateBoyItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
5295 else if (icreateinfo & CF_WITCH)
5296 RecreateWitchItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
5297 else if (icreateinfo & CF_HEALER)
5298 RecreateHealerItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
5299 }
5300
RecalcStoreStats()5301 void RecalcStoreStats()
5302 {
5303 int i;
5304
5305 for (i = 0; i < SMITH_ITEMS; i++) {
5306 if (!smithitem[i].isEmpty()) {
5307 smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]);
5308 }
5309 }
5310 for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) {
5311 if (!premiumitem[i].isEmpty()) {
5312 premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]);
5313 }
5314 }
5315 for (i = 0; i < 20; i++) {
5316 if (!witchitem[i].isEmpty()) {
5317 witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]);
5318 }
5319 }
5320 for (i = 0; i < 20; i++) {
5321 if (!healitem[i].isEmpty()) {
5322 healitem[i]._iStatFlag = StoreStatOk(&healitem[i]);
5323 }
5324 }
5325 boyitem._iStatFlag = StoreStatOk(&boyitem);
5326 }
5327
ItemNoFlippy()5328 int ItemNoFlippy()
5329 {
5330 int r = itemactive[numitems - 1];
5331 item[r]._iAnimFrame = item[r]._iAnimLen;
5332 item[r]._iAnimFlag = FALSE;
5333 item[r]._iSelFlag = 1;
5334
5335 return r;
5336 }
5337
CreateSpellBook(int x,int y,spell_id ispell,BOOL sendmsg,BOOL delta)5338 void CreateSpellBook(int x, int y, spell_id ispell, BOOL sendmsg, BOOL delta)
5339 {
5340 int lvl = currlevel;
5341
5342 if (gbIsHellfire) {
5343 lvl = GetSpellBookLevel(ispell) + 1;
5344 if (lvl < 1) {
5345 return;
5346 }
5347 }
5348
5349 int idx = RndTypeItems(ITYPE_MISC, IMISC_BOOK, lvl);
5350 if (numitems >= MAXITEMS)
5351 return;
5352
5353 int ii = AllocateItem();
5354
5355 while (true) {
5356 memset(&item[ii], 0, sizeof(*item));
5357 SetupAllItems(ii, idx, AdvanceRndSeed(), 2 * lvl, 1, TRUE, FALSE, delta);
5358 if (item[ii]._iMiscId == IMISC_BOOK && item[ii]._iSpell == ispell)
5359 break;
5360 }
5361 GetSuperItemSpace(x, y, ii);
5362
5363 if (sendmsg)
5364 NetSendCmdDItem(FALSE, ii);
5365 if (delta)
5366 DeltaAddItem(ii);
5367 }
5368
CreateMagicItem(int x,int y,int lvl,int imisc,int imid,int icurs,BOOL sendmsg,BOOL delta)5369 static void CreateMagicItem(int x, int y, int lvl, int imisc, int imid, int icurs, BOOL sendmsg, BOOL delta)
5370 {
5371 if (numitems >= MAXITEMS)
5372 return;
5373
5374 int ii = AllocateItem();
5375 int idx = RndTypeItems(imisc, imid, lvl);
5376
5377 while (true) {
5378 memset(&item[ii], 0, sizeof(*item));
5379 SetupAllItems(ii, idx, AdvanceRndSeed(), 2 * lvl, 1, TRUE, FALSE, delta);
5380 if (item[ii]._iCurs == icurs)
5381 break;
5382
5383 idx = RndTypeItems(imisc, imid, lvl);
5384 }
5385 GetSuperItemSpace(x, y, ii);
5386
5387 if (sendmsg)
5388 NetSendCmdDItem(FALSE, ii);
5389 if (delta)
5390 DeltaAddItem(ii);
5391 }
5392
CreateMagicArmor(int x,int y,int imisc,int icurs,BOOL sendmsg,BOOL delta)5393 void CreateMagicArmor(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta)
5394 {
5395 int lvl = items_get_currlevel();
5396 CreateMagicItem(x, y, lvl, imisc, IMISC_NONE, icurs, sendmsg, delta);
5397 }
5398
CreateAmulet(int x,int y,int lvl,BOOL sendmsg,BOOL delta)5399 void CreateAmulet(int x, int y, int lvl, BOOL sendmsg, BOOL delta)
5400 {
5401 CreateMagicItem(x, y, lvl, ITYPE_AMULET, IMISC_AMULET, ICURS_AMULET, sendmsg, delta);
5402 }
5403
CreateMagicWeapon(int x,int y,int imisc,int icurs,BOOL sendmsg,BOOL delta)5404 void CreateMagicWeapon(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta)
5405 {
5406 int imid = IMISC_NONE;
5407 if (imisc == ITYPE_STAFF)
5408 imid = IMISC_STAFF;
5409
5410 int curlv = items_get_currlevel();
5411
5412 CreateMagicItem(x, y, curlv, imisc, imid, icurs, sendmsg, delta);
5413 }
5414
NextItemRecord(int i)5415 static void NextItemRecord(int i)
5416 {
5417 gnNumGetRecords--;
5418
5419 if (gnNumGetRecords == 0) {
5420 return;
5421 }
5422
5423 itemrecord[i].dwTimestamp = itemrecord[gnNumGetRecords].dwTimestamp;
5424 itemrecord[i].nSeed = itemrecord[gnNumGetRecords].nSeed;
5425 itemrecord[i].wCI = itemrecord[gnNumGetRecords].wCI;
5426 itemrecord[i].nIndex = itemrecord[gnNumGetRecords].nIndex;
5427 }
5428
GetItemRecord(int nSeed,WORD wCI,int nIndex)5429 BOOL GetItemRecord(int nSeed, WORD wCI, int nIndex)
5430 {
5431 int i;
5432 DWORD dwTicks;
5433
5434 dwTicks = SDL_GetTicks();
5435
5436 for (i = 0; i < gnNumGetRecords; i++) {
5437 if (dwTicks - itemrecord[i].dwTimestamp > 6000) {
5438 NextItemRecord(i);
5439 i--;
5440 } else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) {
5441 return FALSE;
5442 }
5443 }
5444
5445 return TRUE;
5446 }
5447
SetItemRecord(int nSeed,WORD wCI,int nIndex)5448 void SetItemRecord(int nSeed, WORD wCI, int nIndex)
5449 {
5450 DWORD dwTicks;
5451
5452 dwTicks = SDL_GetTicks();
5453
5454 if (gnNumGetRecords == MAXITEMS) {
5455 return;
5456 }
5457
5458 itemrecord[gnNumGetRecords].dwTimestamp = dwTicks;
5459 itemrecord[gnNumGetRecords].nSeed = nSeed;
5460 itemrecord[gnNumGetRecords].wCI = wCI;
5461 itemrecord[gnNumGetRecords].nIndex = nIndex;
5462 gnNumGetRecords++;
5463 }
5464
PutItemRecord(int nSeed,WORD wCI,int nIndex)5465 void PutItemRecord(int nSeed, WORD wCI, int nIndex)
5466 {
5467 int i;
5468 DWORD dwTicks;
5469
5470 dwTicks = SDL_GetTicks();
5471
5472 for (i = 0; i < gnNumGetRecords; i++) {
5473 if (dwTicks - itemrecord[i].dwTimestamp > 6000) {
5474 NextItemRecord(i);
5475 i--;
5476 } else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) {
5477 NextItemRecord(i);
5478 break;
5479 }
5480 }
5481 }
5482
5483 DEVILUTION_END_NAMESPACE
5484