You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5475 lines
134 KiB

/**
* @file items.cpp
*
* Implementation of item functionality.
*/
#include <algorithm>
#include "all.h"
#include "options.h"
namespace devilution {
int itemactive[MAXITEMS];
BOOL uitemflag;
int itemavail[MAXITEMS];
ItemStruct curruitem;
ItemGetRecordStruct itemrecord[MAXITEMS];
/** Contains the items on ground in the current game. */
ItemStruct items[MAXITEMS + 1];
BOOL itemhold[3][3];
CornerStoneStruct CornerStone;
BYTE *itemanims[ITEMTYPES];
BOOL UniqueItemFlag[128];
int numitems;
int gnNumGetRecords;
/* data */
int OilLevels[] = { 1, 10, 1, 10, 4, 1, 5, 17, 1, 10 };
int OilValues[] = { 500, 2500, 500, 2500, 1500, 100, 2500, 15000, 500, 2500 };
enum item_misc_id OilMagic[] = {
IMISC_OILACC,
IMISC_OILMAST,
IMISC_OILSHARP,
IMISC_OILDEATH,
IMISC_OILSKILL,
IMISC_OILBSMTH,
IMISC_OILFORT,
IMISC_OILPERM,
IMISC_OILHARD,
IMISC_OILIMP,
};
char OilNames[10][25] = {
"Oil of Accuracy",
"Oil of Mastery",
"Oil of Sharpness",
"Oil of Death",
"Oil of Skill",
"Blacksmith Oil",
"Oil of Fortitude",
"Oil of Permanence",
"Oil of Hardening",
"Oil of Imperviousness"
};
int MaxGold = GOLD_MAX_LIMIT;
/** Maps from item_cursor_graphic to in-memory item type. */
BYTE ItemCAnimTbl[] = {
20, 16, 16, 16, 4, 4, 4, 12, 12, 12,
12, 12, 12, 12, 12, 21, 21, 25, 12, 28,
28, 28, 38, 38, 38, 32, 38, 38, 38, 24,
24, 26, 2, 25, 22, 23, 24, 25, 27, 27,
29, 0, 0, 0, 12, 12, 12, 12, 12, 0,
8, 8, 0, 8, 8, 8, 8, 8, 8, 6,
8, 8, 8, 6, 8, 8, 6, 8, 8, 6,
6, 6, 8, 8, 8, 5, 9, 13, 13, 13,
5, 5, 5, 15, 5, 5, 18, 18, 18, 30,
5, 5, 14, 5, 14, 13, 16, 18, 5, 5,
7, 1, 3, 17, 1, 15, 10, 14, 3, 11,
8, 0, 1, 7, 0, 7, 15, 7, 3, 3,
3, 6, 6, 11, 11, 11, 31, 14, 14, 14,
6, 6, 7, 3, 8, 14, 0, 14, 14, 0,
33, 1, 1, 1, 1, 1, 7, 7, 7, 14,
14, 17, 17, 17, 0, 34, 1, 0, 3, 17,
8, 8, 6, 1, 3, 3, 11, 3, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 35, 39, 36,
36, 36, 37, 38, 38, 38, 38, 38, 41, 42,
8, 8, 8, 17, 0, 6, 8, 11, 11, 3,
3, 1, 6, 6, 6, 1, 8, 6, 11, 3,
6, 8, 1, 6, 6, 17, 40, 0, 0
};
/** Map of item type .cel file names. */
const char *const ItemDropNames[] = {
"Armor2",
"Axe",
"FBttle",
"Bow",
"GoldFlip",
"Helmut",
"Mace",
"Shield",
"SwrdFlip",
"Rock",
"Cleaver",
"Staff",
"Ring",
"CrownF",
"LArmor",
"WShield",
"Scroll",
"FPlateAr",
"FBook",
"Food",
"FBttleBB",
"FBttleDY",
"FBttleOR",
"FBttleBR",
"FBttleBL",
"FBttleBY",
"FBttleWH",
"FBttleDB",
"FEar",
"FBrain",
"FMush",
"Innsign",
"Bldstn",
"Fanvil",
"FLazStaf",
"bombs1",
"halfps1",
"wholeps1",
"runes1",
"teddys1",
"cows1",
"donkys1",
"mooses1",
};
/** Maps of item drop animation length. */
BYTE ItemAnimLs[] = {
15,
13,
16,
13,
10,
13,
13,
13,
13,
10,
13,
13,
13,
13,
13,
13,
13,
13,
13,
1,
16,
16,
16,
16,
16,
16,
16,
16,
13,
12,
12,
13,
13,
13,
8,
10,
16,
16,
10,
10,
15,
15,
15,
};
/** Maps of drop sounds effect of dropping the item on ground. */
int ItemDropSnds[] = {
IS_FHARM,
IS_FAXE,
IS_FPOT,
IS_FBOW,
IS_GOLD,
IS_FCAP,
IS_FSWOR,
IS_FSHLD,
IS_FSWOR,
IS_FROCK,
IS_FAXE,
IS_FSTAF,
IS_FRING,
IS_FCAP,
IS_FLARM,
IS_FSHLD,
IS_FSCRL,
IS_FHARM,
IS_FBOOK,
IS_FLARM,
IS_FPOT,
IS_FPOT,
IS_FPOT,
IS_FPOT,
IS_FPOT,
IS_FPOT,
IS_FPOT,
IS_FPOT,
IS_FBODY,
IS_FBODY,
IS_FMUSH,
IS_ISIGN,
IS_FBLST,
IS_FANVL,
IS_FSTAF,
IS_FROCK,
IS_FSCRL,
IS_FSCRL,
IS_FROCK,
IS_FMUSH,
IS_FHARM,
IS_FLARM,
IS_FLARM,
};
/** Maps of drop sounds effect of placing the item in the inventory. */
int ItemInvSnds[] = {
IS_IHARM,
IS_IAXE,
IS_IPOT,
IS_IBOW,
IS_GOLD,
IS_ICAP,
IS_ISWORD,
IS_ISHIEL,
IS_ISWORD,
IS_IROCK,
IS_IAXE,
IS_ISTAF,
IS_IRING,
IS_ICAP,
IS_ILARM,
IS_ISHIEL,
IS_ISCROL,
IS_IHARM,
IS_IBOOK,
IS_IHARM,
IS_IPOT,
IS_IPOT,
IS_IPOT,
IS_IPOT,
IS_IPOT,
IS_IPOT,
IS_IPOT,
IS_IPOT,
IS_IBODY,
IS_IBODY,
IS_IMUSH,
IS_ISIGN,
IS_IBLST,
IS_IANVL,
IS_ISTAF,
IS_IROCK,
IS_ISCROL,
IS_ISCROL,
IS_IROCK,
IS_IMUSH,
IS_IHARM,
IS_ILARM,
IS_ILARM,
};
/** Specifies the current Y-coordinate used for validation of items on ground. */
int idoppely = 16;
/** Maps from Griswold premium item number to a quality level delta as added to the base quality level. */
int premiumlvladd[] = {
// clang-format off
-1,
-1,
0,
0,
1,
2,
// clang-format on
};
/** Maps from Griswold premium item number to a quality level delta as added to the base quality level. */
int premiumLvlAddHellfire[] = {
// clang-format off
-1,
-1,
-1,
0,
0,
0,
0,
1,
1,
1,
1,
2,
2,
3,
3,
// clang-format on
};
bool IsItemAvailable(int i)
{
if (gbIsHellfire)
return true;
return (
i != IDI_MAPOFDOOM // Cathedral Map
&& i != IDI_LGTFORGE // Bovine Plate
&& (i < IDI_OIL || i > IDI_GREYSUIT) // Hellfire exclusive items
&& (i < 83 || i > 86) // Oils
&& i != 92 // Scroll of Search
&& (i < 161 || i > 165) // Runes
&& i != IDI_SORCERER // Short Staff of Mana
)
|| (
// Bard items are technically Hellfire-exclusive
// but are just normal items with adjusted stats.
sgOptions.Gameplay.bTestBard && (i == IDI_BARDSWORD || i == IDI_BARDDAGGER));
}
bool IsUniqueAvailable(int i)
{
return gbIsHellfire || i <= 89;
}
static bool IsPrefixValidForItemType(int i, int flgs)
{
int PLIType = PL_Prefix[i].PLIType;
if (!gbIsHellfire) {
if (i > 82)
return false;
if (i >= 12 && i <= 20)
PLIType &= ~PLT_STAFF;
}
return (flgs & PLIType) != 0;
}
static bool IsSuffixValidForItemType(int i, int flgs)
{
int PLIType = PL_Suffix[i].PLIType;
if (!gbIsHellfire) {
if (i > 94)
return false;
if ((i >= 0 && i <= 1)
|| (i >= 14 && i <= 15)
|| (i >= 21 && i <= 22)
|| (i >= 34 && i <= 36)
|| (i >= 41 && i <= 44)
|| (i >= 60 && i <= 63))
PLIType &= ~PLT_STAFF;
}
return (flgs & PLIType) != 0;
}
int get_ring_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_RING && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_RING && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_bow_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_BOW && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_BOW && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_staff_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_STAFF && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_STAFF && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_sword_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_SWORD && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_SWORD && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_helm_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_HELM && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_HELM && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_shield_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_SHIELD && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_SHIELD && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_armor_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE
&& (plr[i].InvBody[j]._itype == ITYPE_LARMOR || plr[i].InvBody[j]._itype == ITYPE_MARMOR || plr[i].InvBody[j]._itype == ITYPE_HARMOR)
&& res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE
&& (plr[i].InvList[j]._itype == ITYPE_LARMOR || plr[i].InvList[j]._itype == ITYPE_MARMOR || plr[i].InvList[j]._itype == ITYPE_HARMOR)
&& res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_mace_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_MACE && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_MACE && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_amulet_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_AMULET && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_AMULET && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int get_axe_max_value(int i)
{
int j, res;
res = 0;
for (j = 0; j < NUM_INVLOC; j++) {
if (plr[i].InvBody[j]._iClass != ICLASS_NONE && plr[i].InvBody[j]._itype == ITYPE_AXE && res < plr[i].InvBody[j]._iIvalue)
res = plr[i].InvBody[j]._iIvalue;
}
for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
if (plr[i].InvList[j]._iClass != ICLASS_NONE && plr[i].InvList[j]._itype == ITYPE_AXE && res < plr[i].InvList[j]._iIvalue)
res = plr[i].InvList[j]._iIvalue;
}
return res;
}
int items_get_currlevel()
{
int lvl;
lvl = currlevel;
if (currlevel >= 17 && currlevel <= 20)
lvl = currlevel - 8;
if (currlevel >= 21 && currlevel <= 24)
lvl = currlevel - 7;
return lvl;
}
void InitItemGFX()
{
char arglist[64];
int itemTypes = gbIsHellfire ? ITEMTYPES : 35;
for (int i = 0; i < itemTypes; i++) {
sprintf(arglist, "Items\\%s.CEL", ItemDropNames[i]);
itemanims[i] = LoadFileInMem(arglist, NULL);
}
memset(UniqueItemFlag, 0, sizeof(UniqueItemFlag));
}
BOOL ItemPlace(int xp, int yp)
{
if (dMonster[xp][yp] != 0)
return FALSE;
if (dPlayer[xp][yp] != 0)
return FALSE;
if (dItem[xp][yp] != 0)
return FALSE;
if (dObject[xp][yp] != 0)
return FALSE;
if (dFlags[xp][yp] & BFLAG_POPULATED)
return FALSE;
if (nSolidTable[dPiece[xp][yp]])
return FALSE;
return TRUE;
}
void AddInitItems()
{
int x, y, j, rnd;
int curlv = items_get_currlevel();
rnd = random_(11, 3) + 3;
for (j = 0; j < rnd; j++) {
int ii = AllocateItem();
x = random_(12, 80) + 16;
y = random_(12, 80) + 16;
while (!ItemPlace(x, y)) {
x = random_(12, 80) + 16;
y = random_(12, 80) + 16;
}
items[ii]._ix = x;
items[ii]._iy = y;
dItem[x][y] = ii + 1;
items[ii]._iSeed = AdvanceRndSeed();
SetRndSeed(items[ii]._iSeed);
if (random_(12, 2) != 0)
GetItemAttrs(ii, IDI_HEAL, curlv);
else
GetItemAttrs(ii, IDI_MANA, curlv);
items[ii]._iCreateInfo = curlv | CF_PREGEN;
SetupItem(ii);
items[ii]._iAnimFrame = items[ii]._iAnimLen;
items[ii]._iAnimFlag = FALSE;
items[ii]._iSelFlag = 1;
DeltaAddItem(ii);
}
}
static void items_42390F()
{
int x, y, id;
x = random_(12, 80) + 16;
y = random_(12, 80) + 16;
while (!ItemPlace(x, y)) {
x = random_(12, 80) + 16;
y = random_(12, 80) + 16;
}
switch (currlevel) {
case 22:
id = IDI_NOTE2;
break;
case 23:
id = IDI_NOTE3;
break;
default:
id = IDI_NOTE1;
break;
}
SpawnQuestItem(id, x, y, 0, 1);
}
void InitItems()
{
int i;
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_GOLD, 1);
golditem = items[0];
golditem._iStatFlag = TRUE;
numitems = 0;
for (i = 0; i < MAXITEMS; i++) {
items[i]._itype = ITYPE_NONE;
items[i]._ix = 0;
items[i]._iy = 0;
items[i]._iAnimFlag = FALSE;
items[i]._iSelFlag = 0;
items[i]._iIdentified = FALSE;
items[i]._iPostDraw = FALSE;
}
for (i = 0; i < MAXITEMS; i++) {
itemavail[i] = i;
itemactive[i] = 0;
}
if (!setlevel) {
AdvanceRndSeed(); /* unused */
if (QuestStatus(Q_ROCK))
SpawnRock();
if (QuestStatus(Q_ANVIL))
SpawnQuestItem(IDI_ANVIL, 2 * setpc_x + 27, 2 * setpc_y + 27, 0, 1);
if (gbCowQuest && currlevel == 20)
SpawnQuestItem(IDI_BROWNSUIT, 25, 25, 3, 1);
if (gbCowQuest && currlevel == 19)
SpawnQuestItem(IDI_GREYSUIT, 25, 25, 3, 1);
if (currlevel > 0 && currlevel < 16)
AddInitItems();
if (currlevel >= 21 && currlevel <= 23)
items_42390F();
}
uitemflag = FALSE;
}
void CalcPlrItemVals(int p, BOOL Loadgfx)
{
int pvid, d;
int mind = 0; // min damage
int maxd = 0; // max damage
int tac = 0; // accuracy
int g;
int i;
int mi;
int bdam = 0; // bonus damage
int btohit = 0; // bonus chance to hit
int bac = 0; // bonus accuracy
int iflgs = ISPL_NONE; // item_special_effect flags
int pDamAcFlags = 0;
int sadd = 0; // added strength
int madd = 0; // added magic
int dadd = 0; // added dexterity
int vadd = 0; // added vitality
Uint64 spl = 0; // bitarray for all enabled/active spells
int fr = 0; // fire resistance
int lr = 0; // lightning resistance
int mr = 0; // magic resistance
int dmod = 0; // bonus damage mod?
int ghit = 0; // increased damage from enemies
int lrad = 10; // light radius
int ihp = 0; // increased HP
int imana = 0; // increased mana
int spllvladd = 0; // increased spell level
int enac = 0; // enhanced accuracy
int fmin = 0; // minimum fire damage
int fmax = 0; // maximum fire damage
int lmin = 0; // minimum lightning damage
int lmax = 0; // maximum lightning damage
for (i = 0; i < NUM_INVLOC; i++) {
ItemStruct *itm = &plr[p].InvBody[i];
if (!itm->isEmpty() && itm->_iStatFlag) {
mind += itm->_iMinDam;
maxd += itm->_iMaxDam;
tac += itm->_iAC;
if (itm->_iSpell != SPL_NULL) {
spl |= GetSpellBitmask(itm->_iSpell);
}
if (itm->_iMagical == ITEM_QUALITY_NORMAL || itm->_iIdentified) {
bdam += itm->_iPLDam;
btohit += itm->_iPLToHit;
if (itm->_iPLAC) {
int tmpac = itm->_iAC;
tmpac *= itm->_iPLAC;
tmpac /= 100;
if (tmpac == 0)
tmpac = 1;
bac += tmpac;
}
iflgs |= itm->_iFlags;
pDamAcFlags |= itm->_iDamAcFlags;
sadd += itm->_iPLStr;
madd += itm->_iPLMag;
dadd += itm->_iPLDex;
vadd += itm->_iPLVit;
fr += itm->_iPLFR;
lr += itm->_iPLLR;
mr += itm->_iPLMR;
dmod += itm->_iPLDamMod;
ghit += itm->_iPLGetHit;
lrad += itm->_iPLLight;
ihp += itm->_iPLHP;
imana += itm->_iPLMana;
spllvladd += itm->_iSplLvlAdd;
enac += itm->_iPLEnAc;
fmin += itm->_iFMinDam;
fmax += itm->_iFMaxDam;
lmin += itm->_iLMinDam;
lmax += itm->_iLMaxDam;
}
}
}
if (mind == 0 && maxd == 0) {
mind = 1;
maxd = 1;
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
maxd = 3;
}
if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
maxd = 3;
}
if (plr[p]._pClass == PC_MONK) {
mind = std::max(mind, plr[p]._pLevel >> 1);
maxd = std::max(maxd, (int)plr[p]._pLevel);
}
}
if ((plr[p]._pSpellFlags & 2) == 2) {
sadd += 2 * plr[p]._pLevel;
dadd += plr[p]._pLevel + plr[p]._pLevel / 2;
vadd += 2 * plr[p]._pLevel;
}
if ((plr[p]._pSpellFlags & 4) == 4) {
sadd -= 2 * plr[p]._pLevel;
dadd -= plr[p]._pLevel + plr[p]._pLevel / 2;
vadd -= 2 * plr[p]._pLevel;
}
plr[p]._pIMinDam = mind;
plr[p]._pIMaxDam = maxd;
plr[p]._pIAC = tac;
plr[p]._pIBonusDam = bdam;
plr[p]._pIBonusToHit = btohit;
plr[p]._pIBonusAC = bac;
plr[p]._pIFlags = iflgs;
plr[p].pDamAcFlags = pDamAcFlags;
plr[p]._pIBonusDamMod = dmod;
plr[p]._pIGetHit = ghit;
if (lrad < 2) {
lrad = 2;
}
if (lrad > 15) {
lrad = 15;
}
if (plr[p]._pLightRad != lrad && p == myplr) {
ChangeLightRadius(plr[p]._plid, lrad);
ChangeVisionRadius(plr[p]._pvid, lrad);
plr[p]._pLightRad = lrad;
}
plr[p]._pStrength = sadd + plr[p]._pBaseStr;
if (plr[p]._pStrength < 0) {
plr[p]._pStrength = 0;
}
plr[p]._pMagic = madd + plr[p]._pBaseMag;
if (plr[p]._pMagic < 0) {
plr[p]._pMagic = 0;
}
plr[p]._pDexterity = dadd + plr[p]._pBaseDex;
if (plr[p]._pDexterity < 0) {
plr[p]._pDexterity = 0;
}
plr[p]._pVitality = vadd + plr[p]._pBaseVit;
if (plr[p]._pVitality < 0) {
plr[p]._pVitality = 0;
}
if (plr[p]._pClass == PC_ROGUE) {
plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 200;
} else if (plr[p]._pClass == PC_MONK) {
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_STAFF) {
if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_STAFF && (!plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty() || !plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty())) {
plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 300;
} else {
plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150;
}
} else {
plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150;
}
} else if (plr[p]._pClass == PC_BARD) {
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SWORD)
plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 150;
else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_BOW) {
plr[p]._pDamageMod = plr[p]._pLevel * (plr[p]._pStrength + plr[p]._pDexterity) / 250;
} else {
plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100;
}
} else if (plr[p]._pClass == PC_BARBARIAN) {
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_AXE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_AXE) {
plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 75;
} else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_MACE) {
plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 75;
} else if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_BOW || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_BOW) {
plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 300;
} else {
plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100;
}
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD || plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) {
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD)
plr[p]._pIAC -= plr[p].InvBody[INVLOC_HAND_LEFT]._iAC / 2;
else if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD)
plr[p]._pIAC -= plr[p].InvBody[INVLOC_HAND_RIGHT]._iAC / 2;
} 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) {
plr[p]._pDamageMod += plr[p]._pLevel * plr[p]._pVitality / 100;
}
plr[p]._pIAC += plr[p]._pLevel / 4;
} else {
plr[p]._pDamageMod = plr[p]._pLevel * plr[p]._pStrength / 100;
}
plr[p]._pISpells = spl;
EnsureValidReadiedSpell(plr[p]);
plr[p]._pISplLvlAdd = spllvladd;
plr[p]._pIEnAc = enac;
if (plr[p]._pClass == PC_BARBARIAN) {
mr += plr[p]._pLevel;
fr += plr[p]._pLevel;
lr += plr[p]._pLevel;
}
if ((plr[p]._pSpellFlags & 4) == 4) {
mr -= plr[p]._pLevel;
fr -= plr[p]._pLevel;
lr -= plr[p]._pLevel;
}
if (iflgs & ISPL_ALLRESZERO) {
// reset resistances to zero if the respective special effect is active
mr = 0;
fr = 0;
lr = 0;
}
if (mr > MAXRESIST)
mr = MAXRESIST;
else if (mr < 0)
mr = 0;
plr[p]._pMagResist = mr;
if (fr > MAXRESIST)
fr = MAXRESIST;
else if (fr < 0)
fr = 0;
plr[p]._pFireResist = fr;
if (lr > MAXRESIST)
lr = MAXRESIST;
else if (lr < 0)
lr = 0;
plr[p]._pLghtResist = lr;
if (plr[p]._pClass == PC_WARRIOR) {
vadd <<= 1;
} else if (plr[p]._pClass == PC_BARBARIAN) {
vadd += vadd;
vadd += (vadd >> 2);
} else if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD) {
vadd += vadd >> 1;
}
ihp += (vadd << 6); // BUGFIX: blood boil can cause negative shifts here (see line 757)
if (plr[p]._pClass == PC_SORCERER) {
madd <<= 1;
}
if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK) {
madd += madd >> 1;
} else if (plr[p]._pClass == PC_BARD) {
madd += (madd >> 2) + (madd >> 1);
}
imana += (madd << 6);
plr[p]._pHitPoints = ihp + plr[p]._pHPBase;
plr[p]._pMaxHP = ihp + plr[p]._pMaxHPBase;
if (plr[p]._pHitPoints > plr[p]._pMaxHP)
plr[p]._pHitPoints = plr[p]._pMaxHP;
if (p == myplr && (plr[p]._pHitPoints >> 6) <= 0) {
SetPlayerHitPoints(p, 0);
}
plr[p]._pMana = imana + plr[p]._pManaBase;
plr[p]._pMaxMana = imana + plr[p]._pMaxManaBase;
if (plr[p]._pMana > plr[p]._pMaxMana)
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pIFMinDam = fmin;
plr[p]._pIFMaxDam = fmax;
plr[p]._pILMinDam = lmin;
plr[p]._pILMaxDam = lmax;
if (iflgs & ISPL_INFRAVISION) {
plr[p]._pInfraFlag = TRUE;
} else {
plr[p]._pInfraFlag = FALSE;
}
plr[p]._pBlockFlag = FALSE;
if (plr[p]._pClass == PC_MONK) {
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
plr[p]._pBlockFlag = TRUE;
plr[p]._pIFlags |= ISPL_FASTBLOCK;
}
if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_STAFF && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
plr[p]._pBlockFlag = TRUE;
plr[p]._pIFlags |= ISPL_FASTBLOCK;
}
if (plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty())
plr[p]._pBlockFlag = TRUE;
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())
plr[p]._pBlockFlag = TRUE;
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())
plr[p]._pBlockFlag = TRUE;
}
plr[p]._pwtype = WT_MELEE;
g = 0;
if (!plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty()
&& plr[p].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON
&& plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
g = plr[p].InvBody[INVLOC_HAND_LEFT]._itype;
}
if (!plr[p].InvBody[INVLOC_HAND_RIGHT].isEmpty()
&& plr[p].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON
&& plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
g = plr[p].InvBody[INVLOC_HAND_RIGHT]._itype;
}
switch (g) {
case ITYPE_SWORD:
g = ANIM_ID_SWORD;
break;
case ITYPE_AXE:
g = ANIM_ID_AXE;
break;
case ITYPE_BOW:
plr[p]._pwtype = WT_RANGED;
g = ANIM_ID_BOW;
break;
case ITYPE_MACE:
g = ANIM_ID_MACE;
break;
case ITYPE_STAFF:
g = ANIM_ID_STAFF;
break;
}
if (plr[p].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
plr[p]._pBlockFlag = TRUE;
g++;
}
if (plr[p].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD && plr[p].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
plr[p]._pBlockFlag = TRUE;
g++;
}
if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_HARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) {
if (plr[p]._pClass == PC_MONK && plr[p].InvBody[INVLOC_CHEST]._iMagical == ITEM_QUALITY_UNIQUE)
plr[p]._pIAC += plr[p]._pLevel >> 1;
g += ANIM_ID_HEAVY_ARMOR;
} else if (plr[p].InvBody[INVLOC_CHEST]._itype == ITYPE_MARMOR && plr[p].InvBody[INVLOC_CHEST]._iStatFlag) {
if (plr[p]._pClass == PC_MONK) {
if (plr[p].InvBody[INVLOC_CHEST]._iMagical == ITEM_QUALITY_UNIQUE)
plr[p]._pIAC += plr[p]._pLevel << 1;
else
plr[p]._pIAC += plr[p]._pLevel >> 1;
}
g += ANIM_ID_MEDIUM_ARMOR;
} else if (plr[p]._pClass == PC_MONK) {
plr[p]._pIAC += plr[p]._pLevel << 1;
}
if (plr[p]._pgfxnum != g && Loadgfx) {
plr[p]._pgfxnum = g;
plr[p]._pGFXLoad = 0;
LoadPlrGFX(p, PFILE_STAND);
SetPlrAnims(p);
d = plr[p]._pdir;
assert(plr[p]._pNAnim[d]);
plr[p]._pAnimData = plr[p]._pNAnim[d];
plr[p]._pAnimLen = plr[p]._pNFrames;
plr[p]._pAnimFrame = 1;
plr[p]._pAnimCnt = 0;
plr[p]._pAnimDelay = 3;
plr[p]._pAnimWidth = plr[p]._pNWidth;
plr[p]._pAnimWidth2 = (plr[p]._pNWidth - 64) >> 1;
} else {
plr[p]._pgfxnum = g;
}
for (i = 0; i < nummissiles; i++) {
mi = missileactive[i];
if (missile[mi]._mitype == MIS_MANASHIELD && missile[mi]._misource == p) {
missile[mi]._miVar1 = plr[p]._pHitPoints;
missile[mi]._miVar2 = plr[p]._pHPBase;
break;
}
}
if (plr[p].InvBody[INVLOC_AMULET].isEmpty() || plr[p].InvBody[INVLOC_AMULET].IDidx != IDI_AURIC) {
int half = MaxGold;
MaxGold = GOLD_MAX_LIMIT;
if (half != MaxGold)
StripTopGold(p);
} else {
MaxGold = GOLD_MAX_LIMIT * 2;
}
drawmanaflag = TRUE;
drawhpflag = TRUE;
}
void CalcPlrScrolls(int p)
{
int i, j;
plr[p]._pScrlSpells = 0;
for (i = 0; i < plr[p]._pNumInv; i++) {
if (!plr[p].InvList[i].isEmpty() && (plr[p].InvList[i]._iMiscId == IMISC_SCROLL || plr[p].InvList[i]._iMiscId == IMISC_SCROLLT)) {
if (plr[p].InvList[i]._iStatFlag)
plr[p]._pScrlSpells |= GetSpellBitmask(plr[p].InvList[i]._iSpell);
}
}
for (j = 0; j < MAXBELTITEMS; j++) {
if (!plr[p].SpdList[j].isEmpty() && (plr[p].SpdList[j]._iMiscId == IMISC_SCROLL || plr[p].SpdList[j]._iMiscId == IMISC_SCROLLT)) {
if (plr[p].SpdList[j]._iStatFlag)
plr[p]._pScrlSpells |= GetSpellBitmask(plr[p].SpdList[j]._iSpell);
}
}
EnsureValidReadiedSpell(plr[p]);
}
void CalcPlrStaff(int p)
{
plr[p]._pISpells = 0;
if (!plr[p].InvBody[INVLOC_HAND_LEFT].isEmpty()
&& plr[p].InvBody[INVLOC_HAND_LEFT]._iStatFlag
&& plr[p].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) {
plr[p]._pISpells |= GetSpellBitmask(plr[p].InvBody[INVLOC_HAND_LEFT]._iSpell);
}
}
void CalcSelfItems(int pnum)
{
int i;
PlayerStruct *p;
ItemStruct *pi;
BOOL sf, changeflag;
int sa, ma, da;
p = &plr[pnum];
sa = 0;
ma = 0;
da = 0;
pi = p->InvBody;
for (i = 0; i < NUM_INVLOC; i++, pi++) {
if (!pi->isEmpty()) {
pi->_iStatFlag = TRUE;
if (pi->_iIdentified) {
sa += pi->_iPLStr;
ma += pi->_iPLMag;
da += pi->_iPLDex;
}
}
}
do {
changeflag = FALSE;
pi = p->InvBody;
for (i = 0; i < NUM_INVLOC; i++, pi++) {
if (!pi->isEmpty() && pi->_iStatFlag) {
sf = TRUE;
if (sa + p->_pBaseStr < pi->_iMinStr)
sf = FALSE;
if (ma + p->_pBaseMag < pi->_iMinMag)
sf = FALSE;
if (da + p->_pBaseDex < pi->_iMinDex)
sf = FALSE;
if (!sf) {
changeflag = TRUE;
pi->_iStatFlag = FALSE;
if (pi->_iIdentified) {
sa -= pi->_iPLStr;
ma -= pi->_iPLMag;
da -= pi->_iPLDex;
}
}
}
}
} while (changeflag);
}
static BOOL ItemMinStats(PlayerStruct *p, ItemStruct *x)
{
if (p->_pMagic < x->_iMinMag)
return FALSE;
if (p->_pStrength < x->_iMinStr)
return FALSE;
if (p->_pDexterity < x->_iMinDex)
return FALSE;
return TRUE;
}
void CalcPlrItemMin(int pnum)
{
PlayerStruct *p;
ItemStruct *pi;
int i;
p = &plr[pnum];
pi = p->InvList;
i = p->_pNumInv;
while (i--) {
pi->_iStatFlag = ItemMinStats(p, pi);
pi++;
}
pi = p->SpdList;
for (i = MAXBELTITEMS; i != 0; i--) {
if (!pi->isEmpty()) {
pi->_iStatFlag = ItemMinStats(p, pi);
}
pi++;
}
}
void CalcPlrBookVals(int p)
{
int i, slvl;
if (currlevel == 0) {
for (i = 1; !witchitem[i].isEmpty(); i++) {
WitchBookLevel(i);
witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]);
}
}
for (i = 0; i < plr[p]._pNumInv; i++) {
if (plr[p].InvList[i]._itype == ITYPE_MISC && plr[p].InvList[i]._iMiscId == IMISC_BOOK) {
plr[p].InvList[i]._iMinMag = spelldata[plr[p].InvList[i]._iSpell].sMinInt;
slvl = plr[p]._pSplLvl[plr[p].InvList[i]._iSpell];
while (slvl != 0) {
plr[p].InvList[i]._iMinMag += 20 * plr[p].InvList[i]._iMinMag / 100;
slvl--;
if (plr[p].InvList[i]._iMinMag + 20 * plr[p].InvList[i]._iMinMag / 100 > 255) {
plr[p].InvList[i]._iMinMag = 255;
slvl = 0;
}
}
plr[p].InvList[i]._iStatFlag = ItemMinStats(&plr[p], &plr[p].InvList[i]);
}
}
}
void CalcPlrInv(int p, BOOL Loadgfx)
{
CalcPlrItemMin(p);
CalcSelfItems(p);
CalcPlrItemVals(p, Loadgfx);
CalcPlrItemMin(p);
if (p == myplr) {
CalcPlrBookVals(p);
CalcPlrScrolls(p);
CalcPlrStaff(p);
if (p == myplr && currlevel == 0)
RecalcStoreStats();
}
}
void SetPlrHandItem(ItemStruct *h, int idata)
{
ItemDataStruct *pAllItem;
pAllItem = &AllItemsList[idata];
// zero-initialize struct
memset(h, 0, sizeof(*h));
h->_itype = pAllItem->itype;
h->_iCurs = pAllItem->iCurs;
strcpy(h->_iName, pAllItem->iName);
strcpy(h->_iIName, pAllItem->iName);
h->_iLoc = pAllItem->iLoc;
h->_iClass = pAllItem->iClass;
h->_iMinDam = pAllItem->iMinDam;
h->_iMaxDam = pAllItem->iMaxDam;
h->_iAC = pAllItem->iMinAC;
h->_iMiscId = pAllItem->iMiscId;
h->_iSpell = pAllItem->iSpell;
if (pAllItem->iMiscId == IMISC_STAFF) {
h->_iCharges = gbIsHellfire ? 18 : 40;
}
h->_iMaxCharges = h->_iCharges;
h->_iDurability = pAllItem->iDurability;
h->_iMaxDur = pAllItem->iDurability;
h->_iMinStr = pAllItem->iMinStr;
h->_iMinMag = pAllItem->iMinMag;
h->_iMinDex = pAllItem->iMinDex;
h->_ivalue = pAllItem->iValue;
h->_iIvalue = pAllItem->iValue;
h->_iPrePower = IPL_INVALID;
h->_iSufPower = IPL_INVALID;
h->_iMagical = ITEM_QUALITY_NORMAL;
h->IDidx = idata;
if (gbIsHellfire)
h->dwBuff |= CF_HELLFIRE;
}
void GetPlrHandSeed(ItemStruct *h)
{
h->_iSeed = AdvanceRndSeed();
}
/**
* @brief Set a new unique seed value on the given item
* @param pnum Player id
* @param h Item to update
*/
void GetGoldSeed(int pnum, ItemStruct *h)
{
int i, ii, s;
BOOL doneflag;
do {
doneflag = TRUE;
s = AdvanceRndSeed();
for (i = 0; i < numitems; i++) {
ii = itemactive[i];
if (items[ii]._iSeed == s)
doneflag = FALSE;
}
if (pnum == myplr) {
for (i = 0; i < plr[pnum]._pNumInv; i++) {
if (plr[pnum].InvList[i]._iSeed == s)
doneflag = FALSE;
}
}
} while (!doneflag);
h->_iSeed = s;
}
void SetPlrHandSeed(ItemStruct *h, int iseed)
{
h->_iSeed = iseed;
}
int GetGoldCursor(int value)
{
if (value >= GOLD_MEDIUM_LIMIT)
return ICURS_GOLD_LARGE;
if (value <= GOLD_SMALL_LIMIT)
return ICURS_GOLD_SMALL;
return ICURS_GOLD_MEDIUM;
}
/**
* @brief Update the gold cursor on the given gold item
* @param h The item to update
*/
void SetPlrHandGoldCurs(ItemStruct *h)
{
h->_iCurs = GetGoldCursor(h->_ivalue);
}
void CreatePlrItems(int p)
{
int i;
ItemStruct *pi = plr[p].InvBody;
for (i = NUM_INVLOC; i != 0; i--) {
pi->_itype = ITYPE_NONE;
pi++;
}
// converting this to a for loop creates a `rep stosd` instruction,
// so this probably actually was a memset
memset(&plr[p].InvGrid, 0, sizeof(plr[p].InvGrid));
pi = plr[p].InvList;
for (i = NUM_INV_GRID_ELEM; i != 0; i--) {
pi->_itype = ITYPE_NONE;
pi++;
}
plr[p]._pNumInv = 0;
pi = &plr[p].SpdList[0];
for (i = MAXBELTITEMS; i != 0; i--) {
pi->_itype = ITYPE_NONE;
pi++;
}
switch (plr[p]._pClass) {
case PC_WARRIOR:
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_WARRIOR);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_WARRSHLD);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]);
#ifdef _DEBUG
if (!debug_mode_key_w)
#endif
{
SetPlrHandItem(&plr[p].HoldItem, IDI_WARRCLUB);
GetPlrHandSeed(&plr[p].HoldItem);
AutoPlaceItemInInventory(p, plr[p].HoldItem, true);
}
SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[0]);
SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[1]);
break;
case PC_ROGUE:
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_ROGUE);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[0]);
SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[1]);
break;
case PC_SORCERER:
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], gbIsHellfire ? IDI_SORCERER : 166);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
SetPlrHandItem(&plr[p].SpdList[0], gbIsHellfire ? IDI_HEAL : IDI_MANA);
GetPlrHandSeed(&plr[p].SpdList[0]);
SetPlrHandItem(&plr[p].SpdList[1], gbIsHellfire ? IDI_HEAL : IDI_MANA);
GetPlrHandSeed(&plr[p].SpdList[1]);
break;
case PC_MONK:
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_SHORTSTAFF);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[0]);
SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[1]);
break;
case PC_BARD:
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_BARDSWORD);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_BARDDAGGER);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]);
SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[0]);
SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[1]);
break;
case PC_BARBARIAN:
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], 139); // TODO: add more enums to items
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]);
SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_RIGHT], IDI_WARRSHLD);
GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]);
SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[0]);
SetPlrHandItem(&plr[p].SpdList[1], IDI_HEAL);
GetPlrHandSeed(&plr[p].SpdList[1]);
break;
case NUM_CLASSES:
break;
}
SetPlrHandItem(&plr[p].HoldItem, IDI_GOLD);
GetPlrHandSeed(&plr[p].HoldItem);
#ifdef _DEBUG
if (!debug_mode_key_w) {
#endif
plr[p].HoldItem._ivalue = 100;
plr[p].HoldItem._iCurs = ICURS_GOLD_SMALL;
plr[p]._pGold = plr[p].HoldItem._ivalue;
plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem;
plr[p].InvGrid[30] = plr[p]._pNumInv;
#ifdef _DEBUG
} else {
plr[p].HoldItem._ivalue = GOLD_MAX_LIMIT;
plr[p].HoldItem._iCurs = ICURS_GOLD_LARGE;
plr[p]._pGold = plr[p].HoldItem._ivalue * 40;
for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
GetPlrHandSeed(&plr[p].HoldItem);
plr[p].InvList[plr[p]._pNumInv++] = plr[p].HoldItem;
plr[p].InvGrid[i] = plr[p]._pNumInv;
}
}
#endif
CalcPlrItemVals(p, FALSE);
}
BOOL ItemSpaceOk(int i, int j)
{
int oi;
// BUGFIX: Check `i + 1 >= MAXDUNX` and `j + 1 >= MAXDUNY` (applied)
if (i < 0 || i + 1 >= MAXDUNX || j < 0 || j + 1 >= MAXDUNY)
return FALSE;
if (dMonster[i][j] != 0)
return FALSE;
if (dPlayer[i][j] != 0)
return FALSE;
if (dItem[i][j] != 0)
return FALSE;
if (dObject[i][j] != 0) {
oi = dObject[i][j] > 0 ? dObject[i][j] - 1 : -(dObject[i][j] + 1);
if (object[oi]._oSolidFlag)
return FALSE;
}
if (dObject[i + 1][j + 1] > 0 && object[dObject[i + 1][j + 1] - 1]._oSelFlag != 0)
return FALSE;
if (dObject[i + 1][j + 1] < 0 && object[-(dObject[i + 1][j + 1] + 1)]._oSelFlag != 0)
return FALSE;
if (dObject[i + 1][j] > 0
&& dObject[i][j + 1] > 0
&& object[dObject[i + 1][j] - 1]._oSelFlag != 0
&& object[dObject[i][j + 1] - 1]._oSelFlag != 0) {
return FALSE;
}
return !nSolidTable[dPiece[i][j]];
}
static bool GetItemSpace(int x, int y, char inum)
{
int i, j, rs;
int xx, yy;
BOOL savail;
yy = 0;
for (j = y - 1; j <= y + 1; j++) {
xx = 0;
for (i = x - 1; i <= x + 1; i++) {
itemhold[xx][yy] = ItemSpaceOk(i, j);
xx++;
}
yy++;
}
savail = FALSE;
for (j = 0; j < 3; j++) {
for (i = 0; i < 3; i++) {
if (itemhold[i][j])
savail = TRUE;
}
}
rs = random_(13, 15) + 1;
if (!savail)
return false;
xx = 0;
yy = 0;
while (rs > 0) {
if (itemhold[xx][yy])
rs--;
if (rs > 0) {
xx++;
if (xx == 3) {
xx = 0;
yy++;
if (yy == 3)
yy = 0;
}
}
}
xx += x - 1;
yy += y - 1;
items[inum]._ix = xx;
items[inum]._iy = yy;
dItem[xx][yy] = inum + 1;
return true;
}
int AllocateItem()
{
int inum = itemavail[0];
itemavail[0] = itemavail[MAXITEMS - numitems - 1];
itemactive[numitems] = inum;
numitems++;
memset(&items[inum], 0, sizeof(*items));
return inum;
}
static void GetSuperItemSpace(int x, int y, char inum)
{
if (!GetItemSpace(x, y, inum)) {
for (int k = 2; k < 50; k++) {
for (int j = -k; j <= k; j++) {
int yy = y + j;
for (int i = -k; i <= k; i++) {
int xx = i + x;
if (ItemSpaceOk(xx, yy)) {
items[inum]._ix = xx;
items[inum]._iy = yy;
dItem[xx][yy] = inum + 1;
return;
}
}
}
}
}
}
void GetSuperItemLoc(int x, int y, int *xx, int *yy)
{
int i, j, k;
for (k = 1; k < 50; k++) {
for (j = -k; j <= k; j++) {
*yy = y + j;
for (i = -k; i <= k; i++) {
*xx = i + x;
if (ItemSpaceOk(*xx, *yy)) {
return;
}
}
}
}
}
void CalcItemValue(int i)
{
int v;
v = items[i]._iVMult1 + items[i]._iVMult2;
if (v > 0) {
v *= items[i]._ivalue;
}
if (v < 0) {
v = items[i]._ivalue / v;
}
v = items[i]._iVAdd1 + items[i]._iVAdd2 + v;
if (v <= 0) {
v = 1;
}
items[i]._iIvalue = v;
}
void GetBookSpell(int i, int lvl)
{
int rv;
if (lvl == 0)
lvl = 1;
int maxSpells = gbIsHellfire ? MAX_SPELLS : 37;
rv = random_(14, maxSpells) + 1;
if (gbIsSpawn && lvl > 5)
lvl = 5;
int s = SPL_FIREBOLT;
enum spell_id bs = SPL_FIREBOLT;
while (rv > 0) {
int sLevel = GetSpellBookLevel(static_cast<spell_id>(s));
if (sLevel != -1 && lvl >= sLevel) {
rv--;
bs = static_cast<spell_id>(s);
}
s++;
if (!gbIsMultiplayer) {
if (s == SPL_RESURRECT)
s = SPL_TELEKINESIS;
}
if (!gbIsMultiplayer) {
if (s == SPL_HEALOTHER)
s = SPL_FLARE;
}
if (s == maxSpells)
s = 1;
}
strcat(items[i]._iName, spelldata[bs].sNameText);
strcat(items[i]._iIName, spelldata[bs].sNameText);
items[i]._iSpell = bs;
items[i]._iMinMag = spelldata[bs].sMinInt;
items[i]._ivalue += spelldata[bs].sBookCost;
items[i]._iIvalue += spelldata[bs].sBookCost;
if (spelldata[bs].sType == STYPE_FIRE)
items[i]._iCurs = ICURS_BOOK_RED;
else if (spelldata[bs].sType == STYPE_LIGHTNING)
items[i]._iCurs = ICURS_BOOK_BLUE;
else if (spelldata[bs].sType == STYPE_MAGIC)
items[i]._iCurs = ICURS_BOOK_GREY;
}
void GetStaffPower(int i, int lvl, int bs, BOOL onlygood)
{
int l[256];
char istr[128];
int nl, j, preidx;
BOOL addok;
int tmp;
tmp = random_(15, 10);
preidx = -1;
if (tmp == 0 || onlygood) {
nl = 0;
for (j = 0; PL_Prefix[j].PLPower != IPL_INVALID; j++) {
if (IsPrefixValidForItemType(j, PLT_STAFF) && PL_Prefix[j].PLMinLvl <= lvl) {
addok = TRUE;
if (onlygood && !PL_Prefix[j].PLOk)
addok = FALSE;
if (addok) {
l[nl] = j;
nl++;
if (PL_Prefix[j].PLDouble) {
l[nl] = j;
nl++;
}
}
}
}
if (nl != 0) {
preidx = l[random_(16, nl)];
sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, items[i]._iIName);
strcpy(items[i]._iIName, istr);
items[i]._iMagical = ITEM_QUALITY_MAGIC;
SaveItemPower(
i,
PL_Prefix[preidx].PLPower,
PL_Prefix[preidx].PLParam1,
PL_Prefix[preidx].PLParam2,
PL_Prefix[preidx].PLMinVal,
PL_Prefix[preidx].PLMaxVal,
PL_Prefix[preidx].PLMultVal);
items[i]._iPrePower = PL_Prefix[preidx].PLPower;
}
}
if (!control_WriteStringToBuffer((BYTE *)items[i]._iIName)) {
strcpy(items[i]._iIName, AllItemsList[items[i].IDidx].iSName);
if (preidx != -1) {
sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, items[i]._iIName);
strcpy(items[i]._iIName, istr);
}
sprintf(istr, "%s of %s", items[i]._iIName, spelldata[bs].sNameText);
strcpy(items[i]._iIName, istr);
if (items[i]._iMagical == ITEM_QUALITY_NORMAL)
strcpy(items[i]._iName, items[i]._iIName);
}
CalcItemValue(i);
}
void GetStaffSpell(int i, int lvl, BOOL onlygood)
{
int l, rv, minc, maxc, v;
char istr[68];
if (!gbIsHellfire && random_(17, 4) == 0) {
GetItemPower(i, lvl >> 1, lvl, PLT_STAFF, onlygood);
} else {
int maxSpells = gbIsHellfire ? MAX_SPELLS : 37;
l = lvl >> 1;
if (l == 0)
l = 1;
rv = random_(18, maxSpells) + 1;
if (gbIsSpawn && lvl > 10)
lvl = 10;
int s = SPL_FIREBOLT;
enum spell_id bs = SPL_NULL;
while (rv > 0) {
int sLevel = GetSpellStaffLevel(static_cast<spell_id>(s));
if (sLevel != -1 && l >= sLevel) {
rv--;
bs = static_cast<spell_id>(s);
}
s++;
if (!gbIsMultiplayer && s == SPL_RESURRECT)
s = SPL_TELEKINESIS;
if (!gbIsMultiplayer && s == SPL_HEALOTHER)
s = SPL_FLARE;
if (s == maxSpells)
s = SPL_FIREBOLT;
}
sprintf(istr, "%s of %s", items[i]._iName, spelldata[bs].sNameText);
if (!control_WriteStringToBuffer((BYTE *)istr))
sprintf(istr, "Staff of %s", spelldata[bs].sNameText);
strcpy(items[i]._iName, istr);
strcpy(items[i]._iIName, istr);
minc = spelldata[bs].sStaffMin;
maxc = spelldata[bs].sStaffMax - minc + 1;
items[i]._iSpell = bs;
items[i]._iCharges = minc + random_(19, maxc);
items[i]._iMaxCharges = items[i]._iCharges;
items[i]._iMinMag = spelldata[bs].sMinInt;
v = items[i]._iCharges * spelldata[bs].sStaffCost / 5;
items[i]._ivalue += v;
items[i]._iIvalue += v;
GetStaffPower(i, lvl, bs, onlygood);
}
}
void GetOilType(int i, int max_lvl)
{
int cnt, t, j, r;
char rnd[32];
if (!gbIsMultiplayer) {
if (max_lvl == 0)
max_lvl = 1;
cnt = 0;
for (j = 0; j < (int)(sizeof(OilLevels) / sizeof(OilLevels[0])); j++) {
if (OilLevels[j] <= max_lvl) {
rnd[cnt] = j;
cnt++;
}
}
r = random_(165, cnt);
t = rnd[r];
} else {
r = random_(165, 2);
t = (r != 0 ? 6 : 5);
}
strcpy(items[i]._iName, OilNames[t]);
strcpy(items[i]._iIName, OilNames[t]);
items[i]._iMiscId = OilMagic[t];
items[i]._ivalue = OilValues[t];
items[i]._iIvalue = OilValues[t];
}
void GetItemAttrs(int i, int idata, int lvl)
{
items[i]._itype = AllItemsList[idata].itype;
items[i]._iCurs = AllItemsList[idata].iCurs;
strcpy(items[i]._iName, AllItemsList[idata].iName);
strcpy(items[i]._iIName, AllItemsList[idata].iName);
items[i]._iLoc = AllItemsList[idata].iLoc;
items[i]._iClass = AllItemsList[idata].iClass;
items[i]._iMinDam = AllItemsList[idata].iMinDam;
items[i]._iMaxDam = AllItemsList[idata].iMaxDam;
items[i]._iAC = AllItemsList[idata].iMinAC + random_(20, AllItemsList[idata].iMaxAC - AllItemsList[idata].iMinAC + 1);
items[i]._iFlags = AllItemsList[idata].iFlags;
items[i]._iMiscId = AllItemsList[idata].iMiscId;
items[i]._iSpell = AllItemsList[idata].iSpell;
items[i]._iMagical = ITEM_QUALITY_NORMAL;
items[i]._ivalue = AllItemsList[idata].iValue;
items[i]._iIvalue = AllItemsList[idata].iValue;
items[i]._iDurability = AllItemsList[idata].iDurability;
items[i]._iMaxDur = AllItemsList[idata].iDurability;
items[i]._iMinStr = AllItemsList[idata].iMinStr;
items[i]._iMinMag = AllItemsList[idata].iMinMag;
items[i]._iMinDex = AllItemsList[idata].iMinDex;
items[i].IDidx = idata;
if (gbIsHellfire)
items[i].dwBuff |= CF_HELLFIRE;
items[i]._iPrePower = IPL_INVALID;
items[i]._iSufPower = IPL_INVALID;
if (items[i]._iMiscId == IMISC_BOOK)
GetBookSpell(i, lvl);
if (gbIsHellfire && items[i]._iMiscId == IMISC_OILOF)
GetOilType(i, lvl);
if (items[i]._itype != ITYPE_GOLD)
return;
int rndv;
int itemlevel = items_get_currlevel();
if (gnDifficulty == DIFF_NORMAL)
rndv = 5 * itemlevel + random_(21, 10 * itemlevel);
else if (gnDifficulty == DIFF_NIGHTMARE)
rndv = 5 * (itemlevel + 16) + random_(21, 10 * (itemlevel + 16));
else if (gnDifficulty == DIFF_HELL)
rndv = 5 * (itemlevel + 32) + random_(21, 10 * (itemlevel + 32));
if (leveltype == DTYPE_HELL)
rndv += rndv >> 3;
if (rndv > GOLD_MAX_LIMIT)
rndv = GOLD_MAX_LIMIT;
items[i]._ivalue = rndv;
SetPlrHandGoldCurs(&items[i]);
}
int RndPL(int param1, int param2)
{
return param1 + random_(22, param2 - param1 + 1);
}
int PLVal(int pv, int p1, int p2, int minv, int maxv)
{
if (p1 == p2)
return minv;
if (minv == maxv)
return minv;
return minv + (maxv - minv) * (100 * (pv - p1) / (p2 - p1)) / 100;
}
void SaveItemPower(int i, item_effect_type power, int param1, int param2, int minval, int maxval, int multval)
{
int r, r2;
r = RndPL(param1, param2);
switch (power) {
case IPL_TOHIT:
items[i]._iPLToHit += r;
break;
case IPL_TOHIT_CURSE:
items[i]._iPLToHit -= r;
break;
case IPL_DAMP:
items[i]._iPLDam += r;
break;
case IPL_DAMP_CURSE:
items[i]._iPLDam -= r;
break;
case IPL_DOPPELGANGER:
items[i]._iDamAcFlags |= 16;
// no break
case IPL_TOHIT_DAMP:
r = RndPL(param1, param2);
items[i]._iPLDam += r;
if (param1 == 20)
r2 = RndPL(1, 5);
if (param1 == 36)
r2 = RndPL(6, 10);
if (param1 == 51)
r2 = RndPL(11, 15);
if (param1 == 66)
r2 = RndPL(16, 20);
if (param1 == 81)
r2 = RndPL(21, 30);
if (param1 == 96)
r2 = RndPL(31, 40);
if (param1 == 111)
r2 = RndPL(41, 50);
if (param1 == 126)
r2 = RndPL(51, 75);
if (param1 == 151)
r2 = RndPL(76, 100);
items[i]._iPLToHit += r2;
break;
case IPL_TOHIT_DAMP_CURSE:
items[i]._iPLDam -= r;
if (param1 == 25)
r2 = RndPL(1, 5);
if (param1 == 50)
r2 = RndPL(6, 10);
items[i]._iPLToHit -= r2;
break;
case IPL_ACP:
items[i]._iPLAC += r;
break;
case IPL_ACP_CURSE:
items[i]._iPLAC -= r;
break;
case IPL_SETAC:
items[i]._iAC = r;
break;
case IPL_AC_CURSE:
items[i]._iAC -= r;
break;
case IPL_FIRERES:
items[i]._iPLFR += r;
break;
case IPL_LIGHTRES:
items[i]._iPLLR += r;
break;
case IPL_MAGICRES:
items[i]._iPLMR += r;
break;
case IPL_ALLRES:
items[i]._iPLFR += r;
items[i]._iPLLR += r;
items[i]._iPLMR += r;
if (items[i]._iPLFR < 0)
items[i]._iPLFR = 0;
if (items[i]._iPLLR < 0)
items[i]._iPLLR = 0;
if (items[i]._iPLMR < 0)
items[i]._iPLMR = 0;
break;
case IPL_SPLLVLADD:
items[i]._iSplLvlAdd = r;
break;
case IPL_CHARGES:
items[i]._iCharges *= param1;
items[i]._iMaxCharges = items[i]._iCharges;
break;
case IPL_SPELL:
items[i]._iSpell = static_cast<spell_id>(param1);
items[i]._iCharges = param2;
items[i]._iMaxCharges = param2;
break;
case IPL_FIREDAM:
items[i]._iFlags |= ISPL_FIREDAM;
items[i]._iFlags &= ~ISPL_LIGHTDAM;
items[i]._iFMinDam = param1;
items[i]._iFMaxDam = param2;
items[i]._iLMinDam = 0;
items[i]._iLMaxDam = 0;
break;
case IPL_LIGHTDAM:
items[i]._iFlags |= ISPL_LIGHTDAM;
items[i]._iFlags &= ~ISPL_FIREDAM;
items[i]._iLMinDam = param1;
items[i]._iLMaxDam = param2;
items[i]._iFMinDam = 0;
items[i]._iFMaxDam = 0;
break;
case IPL_STR:
items[i]._iPLStr += r;
break;
case IPL_STR_CURSE:
items[i]._iPLStr -= r;
break;
case IPL_MAG:
items[i]._iPLMag += r;
break;
case IPL_MAG_CURSE:
items[i]._iPLMag -= r;
break;
case IPL_DEX:
items[i]._iPLDex += r;
break;
case IPL_DEX_CURSE:
items[i]._iPLDex -= r;
break;
case IPL_VIT:
items[i]._iPLVit += r;
break;
case IPL_VIT_CURSE:
items[i]._iPLVit -= r;
break;
case IPL_ATTRIBS:
items[i]._iPLStr += r;
items[i]._iPLMag += r;
items[i]._iPLDex += r;
items[i]._iPLVit += r;
break;
case IPL_ATTRIBS_CURSE:
items[i]._iPLStr -= r;
items[i]._iPLMag -= r;
items[i]._iPLDex -= r;
items[i]._iPLVit -= r;
break;
case IPL_GETHIT_CURSE:
items[i]._iPLGetHit += r;
break;
case IPL_GETHIT:
items[i]._iPLGetHit -= r;
break;
case IPL_LIFE:
items[i]._iPLHP += r << 6;
break;
case IPL_LIFE_CURSE:
items[i]._iPLHP -= r << 6;
break;
case IPL_MANA:
items[i]._iPLMana += r << 6;
drawmanaflag = TRUE;
break;
case IPL_MANA_CURSE:
items[i]._iPLMana -= r << 6;
drawmanaflag = TRUE;
break;
case IPL_DUR:
r2 = r * items[i]._iMaxDur / 100;
items[i]._iMaxDur += r2;
items[i]._iDurability += r2;
break;
case IPL_CRYSTALLINE:
items[i]._iPLDam += 140 + r * 2;
// no break
case IPL_DUR_CURSE:
items[i]._iMaxDur -= r * items[i]._iMaxDur / 100;
if (items[i]._iMaxDur < 1)
items[i]._iMaxDur = 1;
items[i]._iDurability = items[i]._iMaxDur;
break;
case IPL_INDESTRUCTIBLE:
items[i]._iDurability = DUR_INDESTRUCTIBLE;
items[i]._iMaxDur = DUR_INDESTRUCTIBLE;
break;
case IPL_LIGHT:
items[i]._iPLLight += param1;
break;
case IPL_LIGHT_CURSE:
items[i]._iPLLight -= param1;
break;
case IPL_MULT_ARROWS:
items[i]._iFlags |= ISPL_MULT_ARROWS;
break;
case IPL_FIRE_ARROWS:
items[i]._iFlags |= ISPL_FIRE_ARROWS;
items[i]._iFlags &= ~ISPL_LIGHT_ARROWS;
items[i]._iFMinDam = param1;
items[i]._iFMaxDam = param2;
items[i]._iLMinDam = 0;
items[i]._iLMaxDam = 0;
break;
case IPL_LIGHT_ARROWS:
items[i]._iFlags |= ISPL_LIGHT_ARROWS;
items[i]._iFlags &= ~ISPL_FIRE_ARROWS;
items[i]._iLMinDam = param1;
items[i]._iLMaxDam = param2;
items[i]._iFMinDam = 0;
items[i]._iFMaxDam = 0;
break;
case IPL_FIREBALL:
items[i]._iFlags |= (ISPL_LIGHT_ARROWS | ISPL_FIRE_ARROWS);
items[i]._iFMinDam = param1;
items[i]._iFMaxDam = param2;
items[i]._iLMinDam = 0;
items[i]._iLMaxDam = 0;
break;
case IPL_THORNS:
items[i]._iFlags |= ISPL_THORNS;
break;
case IPL_NOMANA:
items[i]._iFlags |= ISPL_NOMANA;
drawmanaflag = TRUE;
break;
case IPL_NOHEALPLR:
items[i]._iFlags |= ISPL_NOHEALPLR;
break;
case IPL_ABSHALFTRAP:
items[i]._iFlags |= ISPL_ABSHALFTRAP;
break;
case IPL_KNOCKBACK:
items[i]._iFlags |= ISPL_KNOCKBACK;
break;
case IPL_3XDAMVDEM:
items[i]._iFlags |= ISPL_3XDAMVDEM;
break;
case IPL_ALLRESZERO:
items[i]._iFlags |= ISPL_ALLRESZERO;
break;
case IPL_NOHEALMON:
items[i]._iFlags |= ISPL_NOHEALMON;
break;
case IPL_STEALMANA:
if (param1 == 3)
items[i]._iFlags |= ISPL_STEALMANA_3;
if (param1 == 5)
items[i]._iFlags |= ISPL_STEALMANA_5;
drawmanaflag = TRUE;
break;
case IPL_STEALLIFE:
if (param1 == 3)
items[i]._iFlags |= ISPL_STEALLIFE_3;
if (param1 == 5)
items[i]._iFlags |= ISPL_STEALLIFE_5;
drawhpflag = TRUE;
break;
case IPL_TARGAC:
if (gbIsHellfire)
items[i]._iPLEnAc = param1;
else
items[i]._iPLEnAc += r;
break;
case IPL_FASTATTACK:
if (param1 == 1)
items[i]._iFlags |= ISPL_QUICKATTACK;
if (param1 == 2)
items[i]._iFlags |= ISPL_FASTATTACK;
if (param1 == 3)
items[i]._iFlags |= ISPL_FASTERATTACK;
if (param1 == 4)
items[i]._iFlags |= ISPL_FASTESTATTACK;
break;
case IPL_FASTRECOVER:
if (param1 == 1)
items[i]._iFlags |= ISPL_FASTRECOVER;
if (param1 == 2)
items[i]._iFlags |= ISPL_FASTERRECOVER;
if (param1 == 3)
items[i]._iFlags |= ISPL_FASTESTRECOVER;
break;
case IPL_FASTBLOCK:
items[i]._iFlags |= ISPL_FASTBLOCK;
break;
case IPL_DAMMOD:
items[i]._iPLDamMod += r;
break;
case IPL_RNDARROWVEL:
items[i]._iFlags |= ISPL_RNDARROWVEL;
break;
case IPL_SETDAM:
items[i]._iMinDam = param1;
items[i]._iMaxDam = param2;
break;
case IPL_SETDUR:
items[i]._iDurability = param1;
items[i]._iMaxDur = param1;
break;
case IPL_FASTSWING:
items[i]._iFlags |= ISPL_FASTERATTACK;
break;
case IPL_ONEHAND:
items[i]._iLoc = ILOC_ONEHAND;
break;
case IPL_DRAINLIFE:
items[i]._iFlags |= ISPL_DRAINLIFE;
break;
case IPL_RNDSTEALLIFE:
items[i]._iFlags |= ISPL_RNDSTEALLIFE;
break;
case IPL_INFRAVISION:
items[i]._iFlags |= ISPL_INFRAVISION;
break;
case IPL_NOMINSTR:
items[i]._iMinStr = 0;
break;
case IPL_INVCURS:
items[i]._iCurs = param1;
break;
case IPL_ADDACLIFE:
items[i]._iFlags |= (ISPL_LIGHT_ARROWS | ISPL_FIRE_ARROWS);
items[i]._iFMinDam = param1;
items[i]._iFMaxDam = param2;
items[i]._iLMinDam = 1;
items[i]._iLMaxDam = 0;
break;
case IPL_ADDMANAAC:
items[i]._iFlags |= (ISPL_LIGHTDAM | ISPL_FIREDAM);
items[i]._iFMinDam = param1;
items[i]._iFMaxDam = param2;
items[i]._iLMinDam = 2;
items[i]._iLMaxDam = 0;
break;
case IPL_FIRERESCLVL:
items[i]._iPLFR = 30 - plr[myplr]._pLevel;
if (items[i]._iPLFR < 0)
items[i]._iPLFR = 0;
break;
case IPL_FIRERES_CURSE:
items[i]._iPLFR -= r;
break;
case IPL_LIGHTRES_CURSE:
items[i]._iPLLR -= r;
break;
case IPL_MAGICRES_CURSE:
items[i]._iPLMR -= r;
break;
case IPL_ALLRES_CURSE:
items[i]._iPLFR -= r;
items[i]._iPLLR -= r;
items[i]._iPLMR -= r;
break;
case IPL_DEVASTATION:
items[i]._iDamAcFlags |= 0x01;
break;
case IPL_DECAY:
items[i]._iDamAcFlags |= 0x02;
items[i]._iPLDam += r;
break;
case IPL_PERIL:
items[i]._iDamAcFlags |= 0x04;
break;
case IPL_JESTERS:
items[i]._iDamAcFlags |= 0x08;
break;
case IPL_ACDEMON:
items[i]._iDamAcFlags |= 0x20;
break;
case IPL_ACUNDEAD:
items[i]._iDamAcFlags |= 0x40;
break;
case IPL_MANATOLIFE:
r2 = ((plr[myplr]._pMaxManaBase >> 6) * 50 / 100);
items[i]._iPLMana -= (r2 << 6);
items[i]._iPLHP += (r2 << 6);
break;
case IPL_LIFETOMANA:
r2 = ((plr[myplr]._pMaxHPBase >> 6) * 40 / 100);
items[i]._iPLHP -= (r2 << 6);
items[i]._iPLMana += (r2 << 6);
break;
}
if (items[i]._iVAdd1 || items[i]._iVMult1) {
items[i]._iVAdd2 = PLVal(r, param1, param2, minval, maxval);
items[i]._iVMult2 = multval;
} else {
items[i]._iVAdd1 = PLVal(r, param1, param2, minval, maxval);
items[i]._iVMult1 = multval;
}
}
static void SaveItemSuffix(int i, int sufidx)
{
int param1 = PL_Suffix[sufidx].PLParam1;
int param2 = PL_Suffix[sufidx].PLParam2;
if (!gbIsHellfire) {
if (sufidx >= 84 && sufidx <= 86) {
param1 = 2 << param1;
param2 = 6 << param2;
}
}
SaveItemPower(
i,
PL_Suffix[sufidx].PLPower,
param1,
param2,
PL_Suffix[sufidx].PLMinVal,
PL_Suffix[sufidx].PLMaxVal,
PL_Suffix[sufidx].PLMultVal);
}
void GetItemPower(int i, int minlvl, int maxlvl, int flgs, BOOL onlygood)
{
int pre, post, nt, nl, j, preidx, sufidx;
int l[256];
char istr[128];
goodorevil goe;
pre = random_(23, 4);
post = random_(23, 3);
if (pre != 0 && post == 0) {
if (random_(23, 2) != 0)
post = 1;
else
pre = 0;
}
preidx = -1;
sufidx = -1;
goe = GOE_ANY;
if (!onlygood && random_(0, 3) != 0)
onlygood = TRUE;
if (pre == 0) {
nt = 0;
for (j = 0; PL_Prefix[j].PLPower != IPL_INVALID; j++) {
if (IsPrefixValidForItemType(j, flgs)) {
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)) {
l[nt] = j;
nt++;
if (PL_Prefix[j].PLDouble) {
l[nt] = j;
nt++;
}
}
}
}
if (nt != 0) {
preidx = l[random_(23, nt)];
sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, items[i]._iIName);
strcpy(items[i]._iIName, istr);
items[i]._iMagical = ITEM_QUALITY_MAGIC;
SaveItemPower(
i,
PL_Prefix[preidx].PLPower,
PL_Prefix[preidx].PLParam1,
PL_Prefix[preidx].PLParam2,
PL_Prefix[preidx].PLMinVal,
PL_Prefix[preidx].PLMaxVal,
PL_Prefix[preidx].PLMultVal);
items[i]._iPrePower = PL_Prefix[preidx].PLPower;
goe = PL_Prefix[preidx].PLGOE;
}
}
if (post != 0) {
nl = 0;
for (j = 0; PL_Suffix[j].PLPower != IPL_INVALID; j++) {
if (IsSuffixValidForItemType(j, flgs)
&& PL_Suffix[j].PLMinLvl >= minlvl && PL_Suffix[j].PLMinLvl <= maxlvl
&& !((goe == GOE_GOOD && PL_Suffix[j].PLGOE == GOE_EVIL) || (goe == GOE_EVIL && PL_Suffix[j].PLGOE == GOE_GOOD))
&& (!onlygood || PL_Suffix[j].PLOk)) {
l[nl] = j;
nl++;
}
}
if (nl != 0) {
sufidx = l[random_(23, nl)];
sprintf(istr, "%s of %s", items[i]._iIName, PL_Suffix[sufidx].PLName);
strcpy(items[i]._iIName, istr);
items[i]._iMagical = ITEM_QUALITY_MAGIC;
SaveItemSuffix(i, sufidx);
items[i]._iSufPower = PL_Suffix[sufidx].PLPower;
}
}
if (!control_WriteStringToBuffer((BYTE *)items[i]._iIName)) {
int aii = items[i].IDidx;
if (AllItemsList[aii].iSName)
strcpy(items[i]._iIName, AllItemsList[aii].iSName);
else
items[i]._iName[0] = 0;
if (preidx != -1) {
sprintf(istr, "%s %s", PL_Prefix[preidx].PLName, items[i]._iIName);
strcpy(items[i]._iIName, istr);
}
if (sufidx != -1) {
sprintf(istr, "%s of %s", items[i]._iIName, PL_Suffix[sufidx].PLName);
strcpy(items[i]._iIName, istr);
}
}
if (preidx != -1 || sufidx != -1)
CalcItemValue(i);
}
void GetItemBonus(int i, int idata, int minlvl, int maxlvl, BOOL onlygood, BOOLEAN allowspells)
{
if (minlvl > 25)
minlvl = 25;
switch (items[i]._itype) {
case ITYPE_SWORD:
case ITYPE_AXE:
case ITYPE_MACE:
GetItemPower(i, minlvl, maxlvl, PLT_WEAP, onlygood);
break;
case ITYPE_BOW:
GetItemPower(i, minlvl, maxlvl, PLT_BOW, onlygood);
break;
case ITYPE_SHIELD:
GetItemPower(i, minlvl, maxlvl, PLT_SHLD, onlygood);
break;
case ITYPE_LARMOR:
case ITYPE_HELM:
case ITYPE_MARMOR:
case ITYPE_HARMOR:
GetItemPower(i, minlvl, maxlvl, PLT_ARMO, onlygood);
break;
case ITYPE_STAFF:
if (allowspells)
GetStaffSpell(i, maxlvl, onlygood);
else
GetItemPower(i, minlvl, maxlvl, PLT_STAFF, onlygood);
break;
case ITYPE_RING:
case ITYPE_AMULET:
GetItemPower(i, minlvl, maxlvl, PLT_MISC, onlygood);
break;
case ITYPE_NONE:
case ITYPE_MISC:
case ITYPE_GOLD:
break;
}
}
void SetupItem(int i)
{
int it;
it = ItemCAnimTbl[items[i]._iCurs];
items[i]._iAnimData = itemanims[it];
items[i]._iAnimLen = ItemAnimLs[it];
items[i]._iAnimWidth = 96;
items[i]._iAnimWidth2 = 16;
items[i]._iIdentified = FALSE;
items[i]._iPostDraw = FALSE;
if (!plr[myplr].pLvlLoad) {
items[i]._iAnimFrame = 1;
items[i]._iAnimFlag = TRUE;
items[i]._iSelFlag = 0;
} else {
items[i]._iAnimFrame = items[i]._iAnimLen;
items[i]._iAnimFlag = FALSE;
items[i]._iSelFlag = 1;
}
}
int RndItem(int m)
{
int i, ri, r;
int ril[512];
if ((monster[m].MData->mTreasure & 0x8000) != 0)
return -((monster[m].MData->mTreasure & 0xFFF) + 1);
if (monster[m].MData->mTreasure & 0x4000)
return 0;
if (random_(24, 100) > 40)
return 0;
if (random_(24, 100) > 25)
return IDI_GOLD + 1;
ri = 0;
for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd == IDROP_DOUBLE && monster[m].mLevel >= AllItemsList[i].iMinMLvl
&& ri < 512) {
ril[ri] = i;
ri++;
}
if (AllItemsList[i].iRnd != IDROP_NEVER && monster[m].mLevel >= AllItemsList[i].iMinMLvl
&& ri < 512) {
ril[ri] = i;
ri++;
}
if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
ri--;
if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
ri--;
}
r = random_(24, ri);
return ril[r] + 1;
}
int RndUItem(int m)
{
int i, ri;
int ril[512];
BOOL okflag;
if (m != -1 && (monster[m].MData->mTreasure & 0x8000) != 0 && !gbIsMultiplayer)
return -((monster[m].MData->mTreasure & 0xFFF) + 1);
int curlv = items_get_currlevel();
ri = 0;
for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
okflag = TRUE;
if (AllItemsList[i].iRnd == IDROP_NEVER)
okflag = FALSE;
if (m != -1) {
if (monster[m].mLevel < AllItemsList[i].iMinMLvl)
okflag = FALSE;
} else {
if (2 * curlv < AllItemsList[i].iMinMLvl)
okflag = FALSE;
}
if (AllItemsList[i].itype == ITYPE_MISC)
okflag = FALSE;
if (AllItemsList[i].itype == ITYPE_GOLD)
okflag = FALSE;
if (AllItemsList[i].iMiscId == IMISC_BOOK)
okflag = TRUE;
if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
okflag = FALSE;
if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
okflag = FALSE;
if (okflag && ri < 512) {
ril[ri] = i;
ri++;
}
}
return ril[random_(25, ri)];
}
int RndAllItems()
{
int i, ri;
int ril[512];
if (random_(26, 100) > 25)
return 0;
int curlv = items_get_currlevel();
ri = 0;
for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd != IDROP_NEVER && 2 * curlv >= AllItemsList[i].iMinMLvl && ri < 512) {
ril[ri] = i;
ri++;
}
if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
ri--;
if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
ri--;
}
return ril[random_(26, ri)];
}
int RndTypeItems(int itype, int imid, int lvl)
{
int i, ri;
BOOL okflag;
int ril[512];
ri = 0;
for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
okflag = TRUE;
if (AllItemsList[i].iRnd == IDROP_NEVER)
okflag = FALSE;
if (lvl << 1 < AllItemsList[i].iMinMLvl)
okflag = FALSE;
if (AllItemsList[i].itype != itype)
okflag = FALSE;
if (imid != -1 && AllItemsList[i].iMiscId != imid)
okflag = FALSE;
if (okflag && ri < 512) {
ril[ri] = i;
ri++;
}
}
return ril[random_(27, ri)];
}
int CheckUnique(int i, int lvl, int uper, BOOL recreate)
{
int j, idata, numu;
BOOLEAN uok[128];
if (random_(28, 100) > uper)
return UITYPE_INVALID;
numu = 0;
memset(uok, 0, sizeof(uok));
for (j = 0; UniqueItemList[j].UIItemId != UITYPE_INVALID; j++) {
if (!IsUniqueAvailable(j))
break;
if (UniqueItemList[j].UIItemId == AllItemsList[items[i].IDidx].iItemId
&& lvl >= UniqueItemList[j].UIMinLvl
&& (recreate || !UniqueItemFlag[j] || gbIsMultiplayer)) {
uok[j] = TRUE;
numu++;
}
}
if (numu == 0)
return UITYPE_INVALID;
random_(29, 10); /// BUGFIX: unused, last unique in array always gets chosen
idata = 0;
while (numu > 0) {
if (uok[idata])
numu--;
if (numu > 0) {
idata++;
if (idata == 128)
idata = 0;
}
}
return idata;
}
void GetUniqueItem(int i, int uid)
{
UniqueItemFlag[uid] = TRUE;
SaveItemPower(i, UniqueItemList[uid].UIPower1, UniqueItemList[uid].UIParam1, UniqueItemList[uid].UIParam2, 0, 0, 1);
if (UniqueItemList[uid].UINumPL > 1)
SaveItemPower(i, UniqueItemList[uid].UIPower2, UniqueItemList[uid].UIParam3, UniqueItemList[uid].UIParam4, 0, 0, 1);
if (UniqueItemList[uid].UINumPL > 2)
SaveItemPower(i, UniqueItemList[uid].UIPower3, UniqueItemList[uid].UIParam5, UniqueItemList[uid].UIParam6, 0, 0, 1);
if (UniqueItemList[uid].UINumPL > 3)
SaveItemPower(i, UniqueItemList[uid].UIPower4, UniqueItemList[uid].UIParam7, UniqueItemList[uid].UIParam8, 0, 0, 1);
if (UniqueItemList[uid].UINumPL > 4)
SaveItemPower(i, UniqueItemList[uid].UIPower5, UniqueItemList[uid].UIParam9, UniqueItemList[uid].UIParam10, 0, 0, 1);
if (UniqueItemList[uid].UINumPL > 5)
SaveItemPower(i, UniqueItemList[uid].UIPower6, UniqueItemList[uid].UIParam11, UniqueItemList[uid].UIParam12, 0, 0, 1);
strcpy(items[i]._iIName, UniqueItemList[uid].UIName);
items[i]._iIvalue = UniqueItemList[uid].UIValue;
if (items[i]._iMiscId == IMISC_UNIQUE)
items[i]._iSeed = uid;
items[i]._iUid = uid;
items[i]._iMagical = ITEM_QUALITY_UNIQUE;
items[i]._iCreateInfo |= CF_UNIQUE;
}
void SpawnUnique(int uid, int x, int y)
{
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
GetSuperItemSpace(x, y, ii);
int curlv = items_get_currlevel();
int idx = 0;
while (AllItemsList[idx].iItemId != UniqueItemList[uid].UIItemId)
idx++;
GetItemAttrs(ii, idx, curlv);
GetUniqueItem(ii, uid);
SetupItem(ii);
return;
}
void ItemRndDur(int ii)
{
if (items[ii]._iDurability && items[ii]._iDurability != DUR_INDESTRUCTIBLE)
items[ii]._iDurability = random_(0, items[ii]._iMaxDur >> 1) + (items[ii]._iMaxDur >> 2) + 1;
}
void SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, BOOL onlygood, BOOL recreate, BOOL pregen)
{
int iblvl, uid;
items[ii]._iSeed = iseed;
SetRndSeed(iseed);
GetItemAttrs(ii, idx, lvl >> 1);
items[ii]._iCreateInfo = lvl;
if (pregen)
items[ii]._iCreateInfo |= CF_PREGEN;
if (onlygood)
items[ii]._iCreateInfo |= CF_ONLYGOOD;
if (uper == 15)
items[ii]._iCreateInfo |= CF_UPER15;
else if (uper == 1)
items[ii]._iCreateInfo |= CF_UPER1;
if (items[ii]._iMiscId != IMISC_UNIQUE) {
iblvl = -1;
if (random_(32, 100) <= 10 || random_(33, 100) <= lvl) {
iblvl = lvl;
}
if (iblvl == -1 && items[ii]._iMiscId == IMISC_STAFF) {
iblvl = lvl;
}
if (iblvl == -1 && items[ii]._iMiscId == IMISC_RING) {
iblvl = lvl;
}
if (iblvl == -1 && items[ii]._iMiscId == IMISC_AMULET) {
iblvl = lvl;
}
if (onlygood)
iblvl = lvl;
if (uper == 15)
iblvl = lvl + 4;
if (iblvl != -1) {
uid = CheckUnique(ii, iblvl, uper, recreate);
if (uid == UITYPE_INVALID) {
GetItemBonus(ii, idx, iblvl >> 1, iblvl, onlygood, TRUE);
} else {
GetUniqueItem(ii, uid);
}
}
if (items[ii]._iMagical != ITEM_QUALITY_UNIQUE)
ItemRndDur(ii);
} else {
if (items[ii]._iLoc != ILOC_UNEQUIPABLE) {
GetUniqueItem(ii, iseed); // uid is stored in iseed for uniques
}
}
SetupItem(ii);
}
void SpawnItem(int m, int x, int y, BOOL sendmsg)
{
int idx;
BOOL onlygood;
if (monster[m]._uniqtype || ((monster[m].MData->mTreasure & 0x8000) && gbIsMultiplayer)) {
idx = RndUItem(m);
if (idx < 0) {
SpawnUnique(-(idx + 1), x, y);
return;
}
onlygood = TRUE;
} else if (quests[Q_MUSHROOM]._qactive != QUEST_ACTIVE || quests[Q_MUSHROOM]._qvar1 != QS_MUSHGIVEN) {
idx = RndItem(m);
if (!idx)
return;
if (idx > 0) {
idx--;
onlygood = FALSE;
} else {
SpawnUnique(-(idx + 1), x, y);
return;
}
} else {
idx = IDI_BRAIN;
quests[Q_MUSHROOM]._qvar1 = QS_BRAINSPAWNED;
}
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
GetSuperItemSpace(x, y, ii);
int upper = monster[m]._uniqtype ? 15 : 1;
int mLevel = monster[m].MData->mLevel;
if (!gbIsHellfire && monster[m].MType->mtype == MT_DIABLO)
mLevel -= 15;
SetupAllItems(ii, idx, AdvanceRndSeed(), mLevel, upper, onlygood, FALSE, FALSE);
if (sendmsg)
NetSendCmdDItem(FALSE, ii);
}
static void SetupBaseItem(Sint32 x, Sint32 y, Sint32 idx, bool onlygood, bool sendmsg, bool delta)
{
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
GetSuperItemSpace(x, y, ii);
int curlv = items_get_currlevel();
SetupAllItems(ii, idx, AdvanceRndSeed(), 2 * curlv, 1, onlygood, FALSE, delta);
if (sendmsg)
NetSendCmdDItem(FALSE, ii);
if (delta)
DeltaAddItem(ii);
}
void CreateRndItem(int x, int y, BOOL onlygood, BOOL sendmsg, BOOL delta)
{
int idx = onlygood ? RndUItem(-1) : RndAllItems();
SetupBaseItem(x, y, idx, onlygood, sendmsg, delta);
}
void SetupAllUseful(int ii, int iseed, int lvl)
{
int idx;
items[ii]._iSeed = iseed;
SetRndSeed(iseed);
if (gbIsHellfire) {
idx = random_(34, 7);
switch (idx) {
case 0:
idx = IDI_PORTAL;
if ((lvl <= 1))
idx = IDI_HEAL;
break;
case 1:
case 2:
idx = IDI_HEAL;
break;
case 3:
idx = IDI_PORTAL;
if ((lvl <= 1))
idx = IDI_MANA;
break;
case 4:
case 5:
idx = IDI_MANA;
break;
default:
idx = IDI_OIL;
break;
}
} else {
if (random_(34, 2) != 0)
idx = IDI_HEAL;
else
idx = IDI_MANA;
if (lvl > 1 && random_(34, 3) == 0)
idx = IDI_PORTAL;
}
GetItemAttrs(ii, idx, lvl);
items[ii]._iCreateInfo = lvl | CF_USEFUL;
SetupItem(ii);
}
void CreateRndUseful(int pnum, int x, int y, BOOL sendmsg)
{
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
GetSuperItemSpace(x, y, ii);
int curlv = items_get_currlevel();
SetupAllUseful(ii, AdvanceRndSeed(), curlv);
if (sendmsg)
NetSendCmdDItem(FALSE, ii);
}
void CreateTypeItem(int x, int y, BOOL onlygood, int itype, int imisc, BOOL sendmsg, BOOL delta)
{
int idx;
int curlv = items_get_currlevel();
if (itype != ITYPE_GOLD)
idx = RndTypeItems(itype, imisc, curlv);
else
idx = IDI_GOLD;
SetupBaseItem(x, y, idx, onlygood, sendmsg, delta);
}
void RecreateItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue, bool isHellfire)
{
bool _gbIsHellfire = gbIsHellfire;
gbIsHellfire = isHellfire;
if (idx == IDI_GOLD) {
SetPlrHandItem(&items[ii], IDI_GOLD);
items[ii]._iSeed = iseed;
items[ii]._iCreateInfo = icreateinfo;
items[ii]._ivalue = ivalue;
SetPlrHandGoldCurs(&items[ii]);
gbIsHellfire = _gbIsHellfire;
return;
}
if (icreateinfo == 0) {
SetPlrHandItem(&items[ii], idx);
SetPlrHandSeed(&items[ii], iseed);
gbIsHellfire = _gbIsHellfire;
return;
}
if ((icreateinfo & CF_UNIQUE) == 0) {
if (icreateinfo & CF_TOWN) {
RecreateTownItem(ii, idx, icreateinfo, iseed, ivalue);
gbIsHellfire = _gbIsHellfire;
return;
}
if ((icreateinfo & CF_USEFUL) == CF_USEFUL) {
SetupAllUseful(ii, iseed, icreateinfo & CF_LEVEL);
gbIsHellfire = _gbIsHellfire;
return;
}
}
int level = icreateinfo & CF_LEVEL;
int uper = 0;
if (icreateinfo & CF_UPER1)
uper = 1;
if (icreateinfo & CF_UPER15)
uper = 15;
bool onlygood = (icreateinfo & CF_ONLYGOOD) != 0;
bool recreate = (icreateinfo & CF_UNIQUE) != 0;
bool pregen = (icreateinfo & CF_PREGEN) != 0;
SetupAllItems(ii, idx, iseed, level, uper, onlygood, recreate, pregen);
gbIsHellfire = _gbIsHellfire;
}
void RecreateEar(int ii, WORD ic, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, int ibuff)
{
SetPlrHandItem(&items[ii], IDI_EAR);
tempstr[0] = (ic >> 8) & 0x7F;
tempstr[1] = ic & 0x7F;
tempstr[2] = (iseed >> 24) & 0x7F;
tempstr[3] = (iseed >> 16) & 0x7F;
tempstr[4] = (iseed >> 8) & 0x7F;
tempstr[5] = iseed & 0x7F;
tempstr[6] = Id & 0x7F;
tempstr[7] = dur & 0x7F;
tempstr[8] = mdur & 0x7F;
tempstr[9] = ch & 0x7F;
tempstr[10] = mch & 0x7F;
tempstr[11] = (ivalue >> 8) & 0x7F;
tempstr[12] = (ibuff >> 24) & 0x7F;
tempstr[13] = (ibuff >> 16) & 0x7F;
tempstr[14] = (ibuff >> 8) & 0x7F;
tempstr[15] = ibuff & 0x7F;
tempstr[16] = '\0';
sprintf(items[ii]._iName, "Ear of %s", tempstr);
items[ii]._iCurs = ((ivalue >> 6) & 3) + ICURS_EAR_SORCERER;
items[ii]._ivalue = ivalue & 0x3F;
items[ii]._iCreateInfo = ic;
items[ii]._iSeed = iseed;
}
void items_427A72()
{
PkItemStruct id;
BYTE *buffer;
if (CornerStone.activated) {
if (!CornerStone.item.isEmpty()) {
PackItem(&id, &CornerStone.item);
buffer = (BYTE *)&id;
for (int i = 0; i < sizeof(PkItemStruct); i++) {
sprintf(&sgOptions.Hellfire.szItem[i * 2], "%02X", buffer[i]);
}
} else {
sgOptions.Hellfire.szItem[0] = '\0';
}
}
}
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
return 0;
}
void hex2bin(const char *src, int bytes, char *target)
{
for (int i = 0; i < bytes; i++, src += 2) {
target[i] = (char2int(*src) << 4) | char2int(src[1]);
}
}
void items_427ABA(int x, int y)
{
PkItemStruct PkSItem;
if (CornerStone.activated || x == 0 || y == 0) {
return;
}
CornerStone.item._itype = ITYPE_NONE;
CornerStone.activated = TRUE;
if (dItem[x][y]) {
int ii = dItem[x][y] - 1;
for (int i = 0; i < numitems; i++) {
if (itemactive[i] == ii) {
DeleteItem(ii, i);
break;
}
}
dItem[x][y] = 0;
}
if (strlen(sgOptions.Hellfire.szItem) < sizeof(PkItemStruct) * 2)
return;
hex2bin(sgOptions.Hellfire.szItem, sizeof(PkItemStruct), (char *)&PkSItem);
int ii = AllocateItem();
dItem[x][y] = ii + 1;
UnPackItem(&PkSItem, &items[ii], (PkSItem.dwBuff & CF_HELLFIRE) != 0);
items[ii]._ix = x;
items[ii]._iy = y;
RespawnItem(&items[ii], FALSE);
CornerStone.item = items[ii];
}
void SpawnQuestItem(int itemid, int x, int y, int randarea, int selflag)
{
if (randarea) {
int tries = 0;
while (1) {
tries++;
if (tries > 1000 && randarea > 1)
randarea--;
x = random_(0, MAXDUNX);
y = random_(0, MAXDUNY);
bool failed = false;
for (int i = 0; i < randarea && !failed; i++) {
for (int j = 0; j < randarea && !failed; j++) {
failed = !ItemSpaceOk(i + x, j + y);
}
}
if (!failed)
break;
}
}
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
items[ii]._ix = x;
items[ii]._iy = y;
dItem[x][y] = ii + 1;
int curlv = items_get_currlevel();
GetItemAttrs(ii, itemid, curlv);
SetupItem(ii);
items[ii]._iPostDraw = TRUE;
if (selflag) {
items[ii]._iSelFlag = selflag;
items[ii]._iAnimFrame = items[ii]._iAnimLen;
items[ii]._iAnimFlag = FALSE;
}
}
void SpawnRock()
{
if (numitems >= MAXITEMS)
return;
int oi;
bool ostand = false;
for (int i = 0; i < nobjects && !ostand; i++) {
oi = objectactive[i];
ostand = object[oi]._otype == OBJ_STAND;
}
if (!ostand)
return;
int ii = AllocateItem();
int xx = object[oi]._ox;
int yy = object[oi]._oy;
items[ii]._ix = xx;
items[ii]._iy = yy;
dItem[xx][items[ii]._iy] = ii + 1;
int curlv = items_get_currlevel();
GetItemAttrs(ii, IDI_ROCK, curlv);
SetupItem(ii);
items[ii]._iSelFlag = 2;
items[ii]._iPostDraw = TRUE;
items[ii]._iAnimFrame = 11;
}
void SpawnRewardItem(int itemid, int xx, int yy)
{
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
items[ii]._ix = xx;
items[ii]._iy = yy;
dItem[xx][yy] = ii + 1;
int curlv = items_get_currlevel();
GetItemAttrs(ii, itemid, curlv);
SetupItem(ii);
items[ii]._iSelFlag = 2;
items[ii]._iPostDraw = TRUE;
items[ii]._iAnimFrame = 1;
items[ii]._iAnimFlag = TRUE;
items[ii]._iIdentified = TRUE;
}
void SpawnMapOfDoom(int xx, int yy)
{
SpawnRewardItem(IDI_MAPOFDOOM, xx, yy);
}
void SpawnRuneBomb(int xx, int yy)
{
SpawnRewardItem(IDI_RUNEBOMB, xx, yy);
}
void SpawnTheodore(int xx, int yy)
{
SpawnRewardItem(IDI_THEODORE, xx, yy);
}
void RespawnItem(ItemStruct *item, BOOL FlipFlag)
{
int it;
it = ItemCAnimTbl[item->_iCurs];
item->_iAnimData = itemanims[it];
item->_iAnimLen = ItemAnimLs[it];
item->_iAnimWidth = 96;
item->_iAnimWidth2 = 16;
item->_iPostDraw = FALSE;
item->_iRequest = FALSE;
if (FlipFlag) {
item->_iAnimFrame = 1;
item->_iAnimFlag = TRUE;
item->_iSelFlag = 0;
} else {
item->_iAnimFrame = item->_iAnimLen;
item->_iAnimFlag = FALSE;
item->_iSelFlag = 1;
}
if (item->_iCurs == ICURS_MAGIC_ROCK) {
item->_iSelFlag = 1;
PlaySfxLoc(ItemDropSnds[it], item->_ix, item->_iy);
}
if (item->_iCurs == ICURS_TAVERN_SIGN)
item->_iSelFlag = 1;
if (item->_iCurs == ICURS_ANVIL_OF_FURY)
item->_iSelFlag = 1;
}
void DeleteItem(int ii, int i)
{
itemavail[MAXITEMS - numitems] = ii;
numitems--;
if (numitems > 0 && i != numitems)
itemactive[i] = itemactive[numitems];
}
void ItemDoppel()
{
int idoppelx;
ItemStruct *i;
if (gbIsMultiplayer) {
for (idoppelx = 16; idoppelx < 96; idoppelx++) {
if (dItem[idoppelx][idoppely]) {
i = &items[dItem[idoppelx][idoppely] - 1];
if (i->_ix != idoppelx || i->_iy != idoppely)
dItem[idoppelx][idoppely] = 0;
}
}
idoppely++;
if (idoppely == 96)
idoppely = 16;
}
}
void ProcessItems()
{
int i, ii;
for (i = 0; i < numitems; i++) {
ii = itemactive[i];
if (items[ii]._iAnimFlag) {
items[ii]._iAnimFrame++;
if (items[ii]._iCurs == ICURS_MAGIC_ROCK) {
if (items[ii]._iSelFlag == 1 && items[ii]._iAnimFrame == 11)
items[ii]._iAnimFrame = 1;
if (items[ii]._iSelFlag == 2 && items[ii]._iAnimFrame == 21)
items[ii]._iAnimFrame = 11;
} else {
if (items[ii]._iAnimFrame == items[ii]._iAnimLen >> 1)
PlaySfxLoc(ItemDropSnds[ItemCAnimTbl[items[ii]._iCurs]], items[ii]._ix, items[ii]._iy);
if (items[ii]._iAnimFrame >= items[ii]._iAnimLen) {
items[ii]._iAnimFrame = items[ii]._iAnimLen;
items[ii]._iAnimFlag = FALSE;
items[ii]._iSelFlag = 1;
}
}
}
}
ItemDoppel();
}
void FreeItemGFX()
{
for (int i = 0; i < ITEMTYPES; i++) {
MemFreeDbg(itemanims[i]);
}
}
void GetItemFrm(int i)
{
items[i]._iAnimData = itemanims[ItemCAnimTbl[items[i]._iCurs]];
}
void GetItemStr(int i)
{
int nGold;
if (items[i]._itype != ITYPE_GOLD) {
if (items[i]._iIdentified)
strcpy(infostr, items[i]._iIName);
else
strcpy(infostr, items[i]._iName);
if (items[i]._iMagical == ITEM_QUALITY_MAGIC)
infoclr = COL_BLUE;
if (items[i]._iMagical == ITEM_QUALITY_UNIQUE)
infoclr = COL_GOLD;
} else {
nGold = items[i]._ivalue;
sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold));
}
}
void CheckIdentify(int pnum, int cii)
{
ItemStruct *pi;
if (cii >= NUM_INVLOC)
pi = &plr[pnum].InvList[cii - NUM_INVLOC];
else
pi = &plr[pnum].InvBody[cii];
pi->_iIdentified = TRUE;
CalcPlrInv(pnum, TRUE);
if (pnum == myplr)
SetCursor_(CURSOR_HAND);
}
static void RepairItem(ItemStruct *i, int lvl)
{
int rep, d;
if (i->_iDurability == i->_iMaxDur) {
return;
}
if (i->_iMaxDur <= 0) {
i->_itype = ITYPE_NONE;
return;
}
rep = 0;
do {
rep += lvl + random_(37, lvl);
d = i->_iMaxDur / (lvl + 9);
if (d < 1)
d = 1;
i->_iMaxDur = i->_iMaxDur - d;
if (!i->_iMaxDur) {
i->_itype = ITYPE_NONE;
return;
}
} while (rep + i->_iDurability < i->_iMaxDur);
i->_iDurability += rep;
if (i->_iDurability > i->_iMaxDur)
i->_iDurability = i->_iMaxDur;
}
void DoRepair(int pnum, int cii)
{
PlayerStruct *p;
ItemStruct *pi;
p = &plr[pnum];
PlaySfxLoc(IS_REPAIR, p->_px, p->_py);
if (cii >= NUM_INVLOC) {
pi = &p->InvList[cii - NUM_INVLOC];
} else {
pi = &p->InvBody[cii];
}
RepairItem(pi, p->_pLevel);
CalcPlrInv(pnum, TRUE);
if (pnum == myplr)
SetCursor_(CURSOR_HAND);
}
static void RechargeItem(ItemStruct *i, int r)
{
if (i->_iCharges != i->_iMaxCharges) {
do {
i->_iMaxCharges--;
if (i->_iMaxCharges == 0) {
return;
}
i->_iCharges += r;
} while (i->_iCharges < i->_iMaxCharges);
if (i->_iCharges > i->_iMaxCharges)
i->_iCharges = i->_iMaxCharges;
}
}
void DoRecharge(int pnum, int cii)
{
PlayerStruct *p;
ItemStruct *pi;
int r;
p = &plr[pnum];
if (cii >= NUM_INVLOC) {
pi = &p->InvList[cii - NUM_INVLOC];
} else {
pi = &p->InvBody[cii];
}
if (pi->_itype == ITYPE_STAFF && pi->_iSpell != SPL_NULL) {
r = GetSpellBookLevel(pi->_iSpell);
r = random_(38, p->_pLevel / r) + 1;
RechargeItem(pi, r);
CalcPlrInv(pnum, TRUE);
}
if (pnum == myplr)
SetCursor_(CURSOR_HAND);
}
static BOOL OilItem(ItemStruct *x, PlayerStruct *p)
{
int dur, r;
if (x->_iClass == ICLASS_MISC) {
return FALSE;
}
if (x->_iClass == ICLASS_GOLD) {
return FALSE;
}
if (x->_iClass == ICLASS_QUEST) {
return FALSE;
}
switch (p->_pOilType) {
case IMISC_OILACC:
case IMISC_OILMAST:
case IMISC_OILSHARP:
if (x->_iClass == ICLASS_ARMOR) {
return FALSE;
}
break;
case IMISC_OILDEATH:
if (x->_iClass == ICLASS_ARMOR) {
return FALSE;
}
if (x->_itype == ITYPE_BOW) {
return FALSE;
}
break;
case IMISC_OILHARD:
case IMISC_OILIMP:
if (x->_iClass == ICLASS_WEAPON) {
return FALSE;
}
break;
default:
break;
}
switch (p->_pOilType) {
case IMISC_OILACC:
if (x->_iPLToHit < 50) {
x->_iPLToHit += random_(68, 2) + 1;
}
break;
case IMISC_OILMAST:
if (x->_iPLToHit < 100) {
x->_iPLToHit += random_(68, 3) + 3;
}
break;
case IMISC_OILSHARP:
if (x->_iMaxDam - x->_iMinDam < 30) {
x->_iMaxDam = x->_iMaxDam + 1;
}
break;
case IMISC_OILDEATH:
if (x->_iMaxDam - x->_iMinDam < 30) {
x->_iMinDam = x->_iMinDam + 1;
x->_iMaxDam = x->_iMaxDam + 2;
}
break;
case IMISC_OILSKILL:
r = random_(68, 6) + 5;
if (x->_iMinStr > r) {
x->_iMinStr = x->_iMinStr - r;
} else {
x->_iMinStr = 0;
}
if (x->_iMinMag > r) {
x->_iMinMag = x->_iMinMag - r;
} else {
x->_iMinMag = 0;
}
if (x->_iMinDex > r) {
x->_iMinDex = x->_iMinDex - r;
} else {
x->_iMinDex = 0;
}
break;
case IMISC_OILBSMTH:
if (x->_iMaxDur != 255) {
if (x->_iDurability < x->_iMaxDur) {
dur = (x->_iMaxDur + 4) / 5 + x->_iDurability;
if (dur > x->_iMaxDur) {
dur = x->_iMaxDur;
}
} else {
if (x->_iMaxDur >= 100) {
return TRUE;
}
dur = x->_iMaxDur + 1;
x->_iMaxDur = dur;
}
x->_iDurability = dur;
}
break;
case IMISC_OILFORT:
if (x->_iMaxDur != 255 && x->_iMaxDur < 200) {
r = random_(68, 41) + 10;
x->_iMaxDur += r;
x->_iDurability += r;
}
break;
case IMISC_OILPERM:
x->_iDurability = 255;
x->_iMaxDur = 255;
break;
case IMISC_OILHARD:
if (x->_iAC < 60) {
x->_iAC += random_(68, 2) + 1;
}
break;
case IMISC_OILIMP:
if (x->_iAC < 120) {
x->_iAC += random_(68, 3) + 3;
}
break;
default:
return FALSE;
}
return TRUE;
}
void DoOil(int pnum, int cii)
{
PlayerStruct *p = &plr[pnum];
if (cii >= NUM_INVLOC || cii == INVLOC_HEAD || (cii > INVLOC_AMULET && cii <= INVLOC_CHEST)) {
if (OilItem(&p->InvBody[cii], p)) {
CalcPlrInv(pnum, TRUE);
if (pnum == myplr) {
SetCursor_(CURSOR_HAND);
}
}
}
}
void PrintItemOil(char IDidx)
{
switch (IDidx) {
case IMISC_OILACC:
strcpy(tempstr, "increases a weapon's");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "chance to hit");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILMAST:
strcpy(tempstr, "greatly increases a");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "weapon's chance to hit");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILSHARP:
strcpy(tempstr, "increases a weapon's");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "damage potential");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILDEATH:
strcpy(tempstr, "greatly increases a weapon's");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "damage potential - not bows");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILSKILL:
strcpy(tempstr, "reduces attributes needed");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "to use armor or weapons");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILBSMTH:
strcpy(tempstr, "restores 20% of an");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "item's durability");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILFORT:
strcpy(tempstr, "increases an item's");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "current and max durability");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILPERM:
strcpy(tempstr, "makes an item indestructible");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILHARD:
strcpy(tempstr, "increases the armor class");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "of armor and shields");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OILIMP:
strcpy(tempstr, "greatly increases the armor");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "class of armor and shields");
AddPanelString(tempstr, TRUE);
break;
case IMISC_RUNEF:
strcpy(tempstr, "sets fire trap");
AddPanelString(tempstr, TRUE);
break;
case IMISC_RUNEL:
strcpy(tempstr, "sets lightning trap");
AddPanelString(tempstr, TRUE);
break;
case IMISC_GR_RUNEL:
strcpy(tempstr, "sets lightning trap");
AddPanelString(tempstr, TRUE);
break;
case IMISC_GR_RUNEF:
strcpy(tempstr, "sets fire trap");
AddPanelString(tempstr, TRUE);
break;
case IMISC_RUNES:
strcpy(tempstr, "sets petrification trap");
AddPanelString(tempstr, TRUE);
break;
case IMISC_FULLHEAL:
strcpy(tempstr, "fully recover life");
AddPanelString(tempstr, TRUE);
break;
case IMISC_HEAL:
strcpy(tempstr, "recover partial life");
AddPanelString(tempstr, TRUE);
break;
case IMISC_OLDHEAL:
strcpy(tempstr, "recover life");
AddPanelString(tempstr, TRUE);
break;
case IMISC_DEADHEAL:
strcpy(tempstr, "deadly heal");
AddPanelString(tempstr, TRUE);
break;
case IMISC_MANA:
strcpy(tempstr, "recover mana");
AddPanelString(tempstr, TRUE);
break;
case IMISC_FULLMANA:
strcpy(tempstr, "fully recover mana");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXSTR:
strcpy(tempstr, "increase strength");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXMAG:
strcpy(tempstr, "increase magic");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXDEX:
strcpy(tempstr, "increase dexterity");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXVIT:
strcpy(tempstr, "increase vitality");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXWEAK:
strcpy(tempstr, "decrease strength");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXDIS:
strcpy(tempstr, "decrease strength");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXCLUM:
strcpy(tempstr, "decrease dexterity");
AddPanelString(tempstr, TRUE);
break;
case IMISC_ELIXSICK:
strcpy(tempstr, "decrease vitality");
AddPanelString(tempstr, TRUE);
break;
case IMISC_REJUV:
strcpy(tempstr, "recover life and mana");
AddPanelString(tempstr, TRUE);
break;
case IMISC_FULLREJUV:
strcpy(tempstr, "fully recover life and mana");
AddPanelString(tempstr, TRUE);
break;
}
}
void PrintItemPower(char plidx, ItemStruct *x)
{
switch (plidx) {
case IPL_TOHIT:
case IPL_TOHIT_CURSE:
sprintf(tempstr, "chance to hit: %+i%%", x->_iPLToHit);
break;
case IPL_DAMP:
case IPL_DAMP_CURSE:
sprintf(tempstr, "%+i%% damage", x->_iPLDam);
break;
case IPL_TOHIT_DAMP:
case IPL_TOHIT_DAMP_CURSE:
sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam);
break;
case IPL_ACP:
case IPL_ACP_CURSE:
sprintf(tempstr, "%+i%% armor", x->_iPLAC);
break;
case IPL_SETAC:
sprintf(tempstr, "armor class: %i", x->_iAC);
break;
case IPL_AC_CURSE:
sprintf(tempstr, "armor class: %i", x->_iAC);
break;
case IPL_FIRERES:
case IPL_FIRERES_CURSE:
if (x->_iPLFR < 75)
sprintf(tempstr, "Resist Fire: %+i%%", x->_iPLFR);
else
sprintf(tempstr, "Resist Fire: 75%% MAX");
break;
case IPL_LIGHTRES:
case IPL_LIGHTRES_CURSE:
if (x->_iPLLR < 75)
sprintf(tempstr, "Resist Lightning: %+i%%", x->_iPLLR);
else
sprintf(tempstr, "Resist Lightning: 75%% MAX");
break;
case IPL_MAGICRES:
case IPL_MAGICRES_CURSE:
if (x->_iPLMR < 75)
sprintf(tempstr, "Resist Magic: %+i%%", x->_iPLMR);
else
sprintf(tempstr, "Resist Magic: 75%% MAX");
break;
case IPL_ALLRES:
case IPL_ALLRES_CURSE:
if (x->_iPLFR < 75)
sprintf(tempstr, "Resist All: %+i%%", x->_iPLFR);
if (x->_iPLFR >= 75)
sprintf(tempstr, "Resist All: 75%% MAX");
break;
case IPL_SPLLVLADD:
if (x->_iSplLvlAdd == 1)
strcpy(tempstr, "spells are increased 1 level");
else if (x->_iSplLvlAdd > 1)
sprintf(tempstr, "spells are increased %i levels", x->_iSplLvlAdd);
else if (x->_iSplLvlAdd == -1)
strcpy(tempstr, "spells are decreased 1 level");
else if (x->_iSplLvlAdd < -1)
sprintf(tempstr, "spells are decreased %i levels", -x->_iSplLvlAdd);
else if (x->_iSplLvlAdd == 0)
strcpy(tempstr, "spell levels unchanged (?)");
break;
case IPL_CHARGES:
strcpy(tempstr, "Extra charges");
break;
case IPL_SPELL:
sprintf(tempstr, "%i %s charges", x->_iMaxCharges, spelldata[x->_iSpell].sNameText);
break;
case IPL_FIREDAM:
if (x->_iFMinDam == x->_iFMaxDam)
sprintf(tempstr, "Fire hit damage: %i", x->_iFMinDam);
else
sprintf(tempstr, "Fire hit damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
break;
case IPL_LIGHTDAM:
if (x->_iLMinDam == x->_iLMaxDam)
sprintf(tempstr, "Lightning hit damage: %i", x->_iLMinDam);
else
sprintf(tempstr, "Lightning hit damage: %i-%i", x->_iLMinDam, x->_iLMaxDam);
break;
case IPL_STR:
case IPL_STR_CURSE:
sprintf(tempstr, "%+i to strength", x->_iPLStr);
break;
case IPL_MAG:
case IPL_MAG_CURSE:
sprintf(tempstr, "%+i to magic", x->_iPLMag);
break;
case IPL_DEX:
case IPL_DEX_CURSE:
sprintf(tempstr, "%+i to dexterity", x->_iPLDex);
break;
case IPL_VIT:
case IPL_VIT_CURSE:
sprintf(tempstr, "%+i to vitality", x->_iPLVit);
break;
case IPL_ATTRIBS:
case IPL_ATTRIBS_CURSE:
sprintf(tempstr, "%+i to all attributes", x->_iPLStr);
break;
case IPL_GETHIT_CURSE:
case IPL_GETHIT:
sprintf(tempstr, "%+i damage from enemies", x->_iPLGetHit);
break;
case IPL_LIFE:
case IPL_LIFE_CURSE:
sprintf(tempstr, "Hit Points: %+i", x->_iPLHP >> 6);
break;
case IPL_MANA:
case IPL_MANA_CURSE:
sprintf(tempstr, "Mana: %+i", x->_iPLMana >> 6);
break;
case IPL_DUR:
strcpy(tempstr, "high durability");
break;
case IPL_DUR_CURSE:
strcpy(tempstr, "decreased durability");
break;
case IPL_INDESTRUCTIBLE:
strcpy(tempstr, "indestructible");
break;
case IPL_LIGHT:
sprintf(tempstr, "+%i%% light radius", 10 * x->_iPLLight);
break;
case IPL_LIGHT_CURSE:
sprintf(tempstr, "-%i%% light radius", -10 * x->_iPLLight);
break;
case IPL_MULT_ARROWS:
sprintf(tempstr, "multiple arrows per shot");
break;
case IPL_FIRE_ARROWS:
if (x->_iFMinDam == x->_iFMaxDam)
sprintf(tempstr, "fire arrows damage: %i", x->_iFMinDam);
else
sprintf(tempstr, "fire arrows damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
break;
case IPL_LIGHT_ARROWS:
if (x->_iLMinDam == x->_iLMaxDam)
sprintf(tempstr, "lightning arrows damage %i", x->_iLMinDam);
else
sprintf(tempstr, "lightning arrows damage %i-%i", x->_iLMinDam, x->_iLMaxDam);
break;
case IPL_FIREBALL:
if (x->_iFMinDam == x->_iFMaxDam)
sprintf(tempstr, "fireball damage: %i", x->_iFMinDam);
else
sprintf(tempstr, "fireball damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
break;
case IPL_THORNS:
strcpy(tempstr, "attacker takes 1-3 damage");
break;
case IPL_NOMANA:
strcpy(tempstr, "user loses all mana");
break;
case IPL_NOHEALPLR:
strcpy(tempstr, "you can't heal");
break;
case IPL_ABSHALFTRAP:
strcpy(tempstr, "absorbs half of trap damage");
break;
case IPL_KNOCKBACK:
strcpy(tempstr, "knocks target back");
break;
case IPL_3XDAMVDEM:
strcpy(tempstr, "+200% damage vs. demons");
break;
case IPL_ALLRESZERO:
strcpy(tempstr, "All Resistance equals 0");
break;
case IPL_NOHEALMON:
strcpy(tempstr, "hit monster doesn't heal");
break;
case IPL_STEALMANA:
if (x->_iFlags & ISPL_STEALMANA_3)
strcpy(tempstr, "hit steals 3% mana");
if (x->_iFlags & ISPL_STEALMANA_5)
strcpy(tempstr, "hit steals 5% mana");
break;
case IPL_STEALLIFE:
if (x->_iFlags & ISPL_STEALLIFE_3)
strcpy(tempstr, "hit steals 3% life");
if (x->_iFlags & ISPL_STEALLIFE_5)
strcpy(tempstr, "hit steals 5% life");
break;
case IPL_TARGAC:
strcpy(tempstr, "penetrates target's armor");
break;
case IPL_FASTATTACK:
if (x->_iFlags & ISPL_QUICKATTACK)
strcpy(tempstr, "quick attack");
if (x->_iFlags & ISPL_FASTATTACK)
strcpy(tempstr, "fast attack");
if (x->_iFlags & ISPL_FASTERATTACK)
strcpy(tempstr, "faster attack");
if (x->_iFlags & ISPL_FASTESTATTACK)
strcpy(tempstr, "fastest attack");
break;
case IPL_FASTRECOVER:
if (x->_iFlags & ISPL_FASTRECOVER)
strcpy(tempstr, "fast hit recovery");
if (x->_iFlags & ISPL_FASTERRECOVER)
strcpy(tempstr, "faster hit recovery");
if (x->_iFlags & ISPL_FASTESTRECOVER)
strcpy(tempstr, "fastest hit recovery");
break;
case IPL_FASTBLOCK:
strcpy(tempstr, "fast block");
break;
case IPL_DAMMOD:
sprintf(tempstr, "adds %i points to damage", x->_iPLDamMod);
break;
case IPL_RNDARROWVEL:
strcpy(tempstr, "fires random speed arrows");
break;
case IPL_SETDAM:
sprintf(tempstr, "unusual item damage");
break;
case IPL_SETDUR:
strcpy(tempstr, "altered durability");
break;
case IPL_FASTSWING:
strcpy(tempstr, "Faster attack swing");
break;
case IPL_ONEHAND:
strcpy(tempstr, "one handed sword");
break;
case IPL_DRAINLIFE:
strcpy(tempstr, "constantly lose hit points");
break;
case IPL_RNDSTEALLIFE:
strcpy(tempstr, "life stealing");
break;
case IPL_NOMINSTR:
strcpy(tempstr, "no strength requirement");
break;
case IPL_INFRAVISION:
strcpy(tempstr, "see with infravision");
break;
case IPL_INVCURS:
strcpy(tempstr, " ");
break;
case IPL_ADDACLIFE:
if (x->_iFMinDam == x->_iFMaxDam)
sprintf(tempstr, "lightning damage: %i", x->_iFMinDam);
else
sprintf(tempstr, "lightning damage: %i-%i", x->_iFMinDam, x->_iFMaxDam);
break;
case IPL_ADDMANAAC:
strcpy(tempstr, "charged bolts on hits");
break;
case IPL_FIRERESCLVL:
if (x->_iPLFR <= 0)
sprintf(tempstr, " ");
else if (x->_iPLFR >= 1)
sprintf(tempstr, "Resist Fire: %+i%%", x->_iPLFR);
break;
case IPL_DEVASTATION:
strcpy(tempstr, "occasional triple damage");
break;
case IPL_DECAY:
sprintf(tempstr, "decaying %+i%% damage", x->_iPLDam);
break;
case IPL_PERIL:
strcpy(tempstr, "2x dmg to monst, 1x to you");
break;
case IPL_JESTERS:
strcpy(tempstr, "Random 0 - 500% damage");
break;
case IPL_CRYSTALLINE:
sprintf(tempstr, "low dur, %+i%% damage", x->_iPLDam);
break;
case IPL_DOPPELGANGER:
sprintf(tempstr, "to hit: %+i%%, %+i%% damage", x->_iPLToHit, x->_iPLDam);
break;
case IPL_ACDEMON:
sprintf(tempstr, "extra AC vs demons");
break;
case IPL_ACUNDEAD:
sprintf(tempstr, "extra AC vs undead");
break;
case IPL_MANATOLIFE:
sprintf(tempstr, "50%% Mana moved to Health");
break;
case IPL_LIFETOMANA:
sprintf(tempstr, "40%% Health moved to Mana");
break;
default:
strcpy(tempstr, "Another ability (NW)");
break;
}
}
static void DrawUTextBack(CelOutputBuffer out)
{
CelDrawTo(out, RIGHT_PANEL_X - SPANEL_WIDTH + 24, 327, pSTextBoxCels, 1, 271);
DrawHalfTransparentRectTo(out, RIGHT_PANEL_X - SPANEL_WIDTH + 27, 28, 265, 297);
}
void PrintUString(CelOutputBuffer out, int x, int y, BOOL cjustflag, const char *str, text_color col)
{
int len, width, sx, sy, i, k;
BYTE c;
sx = x + 32;
sy = y * 12 + 44;
len = strlen(str);
k = 0;
if (cjustflag) {
width = 0;
for (i = 0; i < len; i++)
width += fontkern[fontframe[gbFontTransTbl[(BYTE)str[i]]]] + 1;
if (width < 257)
k = (257 - width) >> 1;
sx += k;
}
for (i = 0; i < len; i++) {
c = fontframe[gbFontTransTbl[(BYTE)str[i]]];
k += fontkern[c] + 1;
if (c && k <= 257) {
PrintChar(out, sx, sy, c, col);
}
sx += fontkern[c] + 1;
}
}
static void DrawULine(CelOutputBuffer out, int y)
{
BYTE *src = out.at(26 + RIGHT_PANEL - SPANEL_WIDTH, 25);
BYTE *dst = out.at(26 + RIGHT_PANEL_X - SPANEL_WIDTH, y * 12 + 38);
for (int i = 0; i < 3; i++, src += out.pitch(), dst += out.pitch())
memcpy(dst, src, 267); // BUGFIX: should be 267 (fixed)
}
void DrawUniqueInfo(CelOutputBuffer out)
{
int uid, y;
if ((!chrflag && !questlog) || gnScreenWidth >= SPANEL_WIDTH * 3) {
uid = curruitem._iUid;
DrawUTextBack(GlobalBackBuffer());
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, 2, TRUE, UniqueItemList[uid].UIName, COL_GOLD);
DrawULine(out, 5);
PrintItemPower(UniqueItemList[uid].UIPower1, &curruitem);
y = 6 - UniqueItemList[uid].UINumPL + 8;
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y, TRUE, tempstr, COL_WHITE);
if (UniqueItemList[uid].UINumPL > 1) {
PrintItemPower(UniqueItemList[uid].UIPower2, &curruitem);
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 2, TRUE, tempstr, COL_WHITE);
}
if (UniqueItemList[uid].UINumPL > 2) {
PrintItemPower(UniqueItemList[uid].UIPower3, &curruitem);
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 4, TRUE, tempstr, COL_WHITE);
}
if (UniqueItemList[uid].UINumPL > 3) {
PrintItemPower(UniqueItemList[uid].UIPower4, &curruitem);
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 6, TRUE, tempstr, COL_WHITE);
}
if (UniqueItemList[uid].UINumPL > 4) {
PrintItemPower(UniqueItemList[uid].UIPower5, &curruitem);
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 8, TRUE, tempstr, COL_WHITE);
}
if (UniqueItemList[uid].UINumPL > 5) {
PrintItemPower(UniqueItemList[uid].UIPower6, &curruitem);
PrintUString(out, 0 + RIGHT_PANEL - SPANEL_WIDTH, y + 10, TRUE, tempstr, COL_WHITE);
}
}
}
void PrintItemMisc(ItemStruct *x)
{
if (x->_iMiscId == IMISC_SCROLL) {
strcpy(tempstr, "Right-click to read");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_SCROLLT) {
strcpy(tempstr, "Right-click to read, then");
AddPanelString(tempstr, TRUE);
strcpy(tempstr, "left-click to target");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId >= IMISC_USEFIRST && x->_iMiscId <= IMISC_USELAST) {
PrintItemOil(x->_iMiscId);
strcpy(tempstr, "Right-click to use");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId > IMISC_OILFIRST && x->_iMiscId < IMISC_OILLAST) {
PrintItemOil(x->_iMiscId);
strcpy(tempstr, "Right click to use");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId > IMISC_RUNEFIRST && x->_iMiscId < IMISC_RUNELAST) {
PrintItemOil(x->_iMiscId);
strcpy(tempstr, "Right click to use");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_BOOK) {
strcpy(tempstr, "Right-click to read");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_NOTE) {
strcpy(tempstr, "Right click to read");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_MAPOFDOOM) {
strcpy(tempstr, "Right-click to view");
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_EAR) {
sprintf(tempstr, "Level: %i", x->_ivalue);
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_AURIC) {
sprintf(tempstr, "Doubles gold capacity");
AddPanelString(tempstr, TRUE);
}
}
static void PrintItemInfo(ItemStruct *x)
{
PrintItemMisc(x);
Uint8 str = x->_iMinStr;
Uint8 dex = x->_iMinDex;
Uint8 mag = x->_iMinMag;
if (str != 0 || mag != 0 || dex != 0) {
strcpy(tempstr, "Required:");
if (str)
sprintf(tempstr + strlen(tempstr), " %i Str", str);
if (mag)
sprintf(tempstr + strlen(tempstr), " %i Mag", mag);
if (dex)
sprintf(tempstr + strlen(tempstr), " %i Dex", dex);
AddPanelString(tempstr, TRUE);
}
pinfoflag = TRUE;
}
void PrintItemDetails(ItemStruct *x)
{
if (x->_iClass == ICLASS_WEAPON) {
if (x->_iMinDam == x->_iMaxDam) {
if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
sprintf(tempstr, "damage: %i Indestructible", x->_iMinDam);
else
sprintf(tempstr, "damage: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur);
} else {
if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
sprintf(tempstr, "damage: %i-%i Indestructible", x->_iMinDam, x->_iMaxDam);
else
sprintf(tempstr, "damage: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur);
}
AddPanelString(tempstr, TRUE);
}
if (x->_iClass == ICLASS_ARMOR) {
if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
sprintf(tempstr, "armor: %i Indestructible", x->_iAC);
else
sprintf(tempstr, "armor: %i Dur: %i/%i", x->_iAC, x->_iDurability, x->_iMaxDur);
AddPanelString(tempstr, TRUE);
}
if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
if (x->_iMinDam == x->_iMaxDam)
sprintf(tempstr, "dam: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur);
else
sprintf(tempstr, "dam: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur);
sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
AddPanelString(tempstr, TRUE);
}
if (x->_iPrePower != -1) {
PrintItemPower(x->_iPrePower, x);
AddPanelString(tempstr, TRUE);
}
if (x->_iSufPower != -1) {
PrintItemPower(x->_iSufPower, x);
AddPanelString(tempstr, TRUE);
}
if (x->_iMagical == ITEM_QUALITY_UNIQUE) {
AddPanelString("unique item", TRUE);
uitemflag = TRUE;
curruitem = *x;
}
PrintItemInfo(x);
}
void PrintItemDur(ItemStruct *x)
{
if (x->_iClass == ICLASS_WEAPON) {
if (x->_iMinDam == x->_iMaxDam) {
if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
sprintf(tempstr, "damage: %i Indestructible", x->_iMinDam);
else
sprintf(tempstr, "damage: %i Dur: %i/%i", x->_iMinDam, x->_iDurability, x->_iMaxDur);
} else {
if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
sprintf(tempstr, "damage: %i-%i Indestructible", x->_iMinDam, x->_iMaxDam);
else
sprintf(tempstr, "damage: %i-%i Dur: %i/%i", x->_iMinDam, x->_iMaxDam, x->_iDurability, x->_iMaxDur);
}
AddPanelString(tempstr, TRUE);
if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
AddPanelString(tempstr, TRUE);
}
if (x->_iMagical != ITEM_QUALITY_NORMAL)
AddPanelString("Not Identified", TRUE);
}
if (x->_iClass == ICLASS_ARMOR) {
if (x->_iMaxDur == DUR_INDESTRUCTIBLE)
sprintf(tempstr, "armor: %i Indestructible", x->_iAC);
else
sprintf(tempstr, "armor: %i Dur: %i/%i", x->_iAC, x->_iDurability, x->_iMaxDur);
AddPanelString(tempstr, TRUE);
if (x->_iMagical != ITEM_QUALITY_NORMAL)
AddPanelString("Not Identified", TRUE);
if (x->_iMiscId == IMISC_STAFF && x->_iMaxCharges) {
sprintf(tempstr, "Charges: %i/%i", x->_iCharges, x->_iMaxCharges);
AddPanelString(tempstr, TRUE);
}
}
if (x->_itype == ITYPE_RING || x->_itype == ITYPE_AMULET)
AddPanelString("Not Identified", TRUE);
PrintItemInfo(x);
}
void UseItem(int p, item_misc_id Mid, spell_id spl)
{
int l, j;
switch (Mid) {
case IMISC_HEAL:
case IMISC_FOOD:
j = plr[p]._pMaxHP >> 8;
l = ((j >> 1) + random_(39, j)) << 6;
if (plr[p]._pClass == PC_WARRIOR || plr[p]._pClass == PC_BARBARIAN)
l <<= 1;
if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD)
l += l >> 1;
plr[p]._pHitPoints += l;
if (plr[p]._pHitPoints > plr[p]._pMaxHP)
plr[p]._pHitPoints = plr[p]._pMaxHP;
plr[p]._pHPBase += l;
if (plr[p]._pHPBase > plr[p]._pMaxHPBase)
plr[p]._pHPBase = plr[p]._pMaxHPBase;
drawhpflag = TRUE;
break;
case IMISC_FULLHEAL:
plr[p]._pHitPoints = plr[p]._pMaxHP;
plr[p]._pHPBase = plr[p]._pMaxHPBase;
drawhpflag = TRUE;
break;
case IMISC_MANA:
j = plr[p]._pMaxMana >> 8;
l = ((j >> 1) + random_(40, j)) << 6;
if (plr[p]._pClass == PC_SORCERER)
l <<= 1;
if (plr[p]._pClass == PC_ROGUE || plr[p]._pClass == PC_MONK || plr[p]._pClass == PC_BARD)
l += l >> 1;
if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
plr[p]._pMana += l;
if (plr[p]._pMana > plr[p]._pMaxMana)
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pManaBase += l;
if (plr[p]._pManaBase > plr[p]._pMaxManaBase)
plr[p]._pManaBase = plr[p]._pMaxManaBase;
drawmanaflag = TRUE;
}
break;
case IMISC_FULLMANA:
if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pManaBase = plr[p]._pMaxManaBase;
drawmanaflag = TRUE;
}
break;
case IMISC_ELIXSTR:
ModifyPlrStr(p, 1);
break;
case IMISC_ELIXMAG:
ModifyPlrMag(p, 1);
if (gbIsHellfire) {
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pManaBase = plr[p]._pMaxManaBase;
drawmanaflag = TRUE;
}
break;
case IMISC_ELIXDEX:
ModifyPlrDex(p, 1);
break;
case IMISC_ELIXVIT:
ModifyPlrVit(p, 1);
if (gbIsHellfire) {
plr[p]._pHitPoints = plr[p]._pMaxHP;
plr[p]._pHPBase = plr[p]._pMaxHPBase;
drawhpflag = TRUE;
}
break;
case IMISC_REJUV:
j = plr[p]._pMaxHP >> 8;
l = ((j >> 1) + random_(39, j)) << 6;
if (plr[p]._pClass == PC_WARRIOR || plr[p]._pClass == PC_BARBARIAN)
l <<= 1;
if (plr[p]._pClass == PC_ROGUE)
l += l >> 1;
plr[p]._pHitPoints += l;
if (plr[p]._pHitPoints > plr[p]._pMaxHP)
plr[p]._pHitPoints = plr[p]._pMaxHP;
plr[p]._pHPBase += l;
if (plr[p]._pHPBase > plr[p]._pMaxHPBase)
plr[p]._pHPBase = plr[p]._pMaxHPBase;
drawhpflag = TRUE;
j = plr[p]._pMaxMana >> 8;
l = ((j >> 1) + random_(40, j)) << 6;
if (plr[p]._pClass == PC_SORCERER)
l <<= 1;
if (plr[p]._pClass == PC_ROGUE)
l += l >> 1;
if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
plr[p]._pMana += l;
if (plr[p]._pMana > plr[p]._pMaxMana)
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pManaBase += l;
if (plr[p]._pManaBase > plr[p]._pMaxManaBase)
plr[p]._pManaBase = plr[p]._pMaxManaBase;
drawmanaflag = TRUE;
}
break;
case IMISC_FULLREJUV:
plr[p]._pHitPoints = plr[p]._pMaxHP;
plr[p]._pHPBase = plr[p]._pMaxHPBase;
drawhpflag = TRUE;
if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pManaBase = plr[p]._pMaxManaBase;
drawmanaflag = TRUE;
}
break;
case IMISC_SCROLL:
if (spelldata[spl].sTargeted) {
plr[p]._pTSpell = spl;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
} else {
ClrPlrPath(p);
plr[p]._pSpell = spl;
plr[p]._pSplType = RSPLTYPE_INVALID;
plr[p]._pSplFrom = 3;
plr[p].destAction = ACTION_SPELL;
plr[p].destParam1 = cursmx;
plr[p].destParam2 = cursmy;
if (p == myplr && spl == SPL_NOVA)
NetSendCmdLoc(TRUE, CMD_NOVA, cursmx, cursmy);
}
break;
case IMISC_SCROLLT:
if (spelldata[spl].sTargeted) {
plr[p]._pTSpell = spl;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
} else {
ClrPlrPath(p);
plr[p]._pSpell = spl;
plr[p]._pSplType = RSPLTYPE_INVALID;
plr[p]._pSplFrom = 3;
plr[p].destAction = ACTION_SPELL;
plr[p].destParam1 = cursmx;
plr[p].destParam2 = cursmy;
}
break;
case IMISC_BOOK:
plr[p]._pMemSpells |= GetSpellBitmask(spl);
if (plr[p]._pSplLvl[spl] < MAX_SPELL_LEVEL)
plr[p]._pSplLvl[spl]++;
if (!(plr[p]._pIFlags & ISPL_NOMANA)) {
plr[p]._pMana += spelldata[spl].sManaCost << 6;
if (plr[p]._pMana > plr[p]._pMaxMana)
plr[p]._pMana = plr[p]._pMaxMana;
plr[p]._pManaBase += spelldata[spl].sManaCost << 6;
if (plr[p]._pManaBase > plr[p]._pMaxManaBase)
plr[p]._pManaBase = plr[p]._pMaxManaBase;
}
if (p == myplr)
CalcPlrBookVals(p);
drawmanaflag = TRUE;
break;
case IMISC_MAPOFDOOM:
doom_init();
break;
case IMISC_OILACC:
case IMISC_OILMAST:
case IMISC_OILSHARP:
case IMISC_OILDEATH:
case IMISC_OILSKILL:
case IMISC_OILBSMTH:
case IMISC_OILFORT:
case IMISC_OILPERM:
case IMISC_OILHARD:
case IMISC_OILIMP:
plr[p]._pOilType = Mid;
if (p != myplr) {
return;
}
if (sbookflag) {
sbookflag = FALSE;
}
if (!invflag) {
invflag = TRUE;
}
NewCursor(CURSOR_OIL);
break;
case IMISC_SPECELIX:
ModifyPlrStr(p, 3);
ModifyPlrMag(p, 3);
ModifyPlrDex(p, 3);
ModifyPlrVit(p, 3);
break;
case IMISC_RUNEF:
plr[p]._pTSpell = SPL_RUNEFIRE;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
break;
case IMISC_RUNEL:
plr[p]._pTSpell = SPL_RUNELIGHT;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
break;
case IMISC_GR_RUNEL:
plr[p]._pTSpell = SPL_RUNENOVA;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
break;
case IMISC_GR_RUNEF:
plr[p]._pTSpell = SPL_RUNEIMMOLAT;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
break;
case IMISC_RUNES:
plr[p]._pTSpell = SPL_RUNESTONE;
plr[p]._pTSplType = RSPLTYPE_INVALID;
if (p == myplr)
NewCursor(CURSOR_TELEPORT);
break;
default:
break;
}
}
BOOL StoreStatOk(ItemStruct *h)
{
BOOL sf;
sf = TRUE;
if (plr[myplr]._pStrength < h->_iMinStr)
sf = FALSE;
if (plr[myplr]._pMagic < h->_iMinMag)
sf = FALSE;
if (plr[myplr]._pDexterity < h->_iMinDex)
sf = FALSE;
return sf;
}
BOOL SmithItemOk(int i)
{
BOOL rv;
rv = TRUE;
if (AllItemsList[i].itype == ITYPE_MISC)
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_GOLD)
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_STAFF && (!gbIsHellfire || AllItemsList[i].iSpell))
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_RING)
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_AMULET)
rv = FALSE;
return rv;
}
int RndSmithItem(int lvl)
{
int i, ri;
int ril[512];
ri = 0;
for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd != IDROP_NEVER && SmithItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
&& ri < 512) {
ril[ri] = i;
ri++;
if (AllItemsList[i].iRnd == IDROP_DOUBLE
&& ri < 512) {
ril[ri] = i;
ri++;
}
}
}
return ril[random_(50, ri)] + 1;
}
void BubbleSwapItem(ItemStruct *a, ItemStruct *b)
{
ItemStruct h;
h = *a;
*a = *b;
*b = h;
}
void SortSmith()
{
int j, k;
BOOL sorted;
j = 0;
while (!smithitem[j + 1].isEmpty()) {
j++;
}
sorted = FALSE;
while (j > 0 && !sorted) {
sorted = TRUE;
for (k = 0; k < j; k++) {
if (smithitem[k].IDidx > smithitem[k + 1].IDidx) {
BubbleSwapItem(&smithitem[k], &smithitem[k + 1]);
sorted = FALSE;
}
}
j--;
}
}
void SpawnSmith(int lvl)
{
int i, iCnt, idata;
int maxValue, maxItems;
ItemStruct holditem;
holditem = items[0];
if (gbIsHellfire) {
maxValue = 200000;
maxItems = 25;
} else {
maxValue = 140000;
maxItems = 20;
}
iCnt = random_(50, maxItems - 10) + 10;
for (i = 0; i < iCnt; i++) {
do {
memset(&items[0], 0, sizeof(*items));
items[0]._iSeed = AdvanceRndSeed();
SetRndSeed(items[0]._iSeed);
idata = RndSmithItem(lvl) - 1;
GetItemAttrs(0, idata, lvl);
} while (items[0]._iIvalue > maxValue);
smithitem[i] = items[0];
smithitem[i]._iCreateInfo = lvl | CF_SMITH;
smithitem[i]._iIdentified = TRUE;
smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]);
}
for (i = iCnt; i < SMITH_ITEMS; i++)
smithitem[i]._itype = ITYPE_NONE;
SortSmith();
items[0] = holditem;
}
BOOL PremiumItemOk(int i)
{
BOOL rv;
rv = TRUE;
if (AllItemsList[i].itype == ITYPE_MISC)
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_GOLD)
rv = FALSE;
if (!gbIsHellfire && AllItemsList[i].itype == ITYPE_STAFF)
rv = FALSE;
if (gbIsMultiplayer) {
if (AllItemsList[i].iMiscId == IMISC_OILOF)
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_RING)
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_AMULET)
rv = FALSE;
}
return rv;
}
int RndPremiumItem(int minlvl, int maxlvl)
{
int i, ri;
int ril[512];
ri = 0;
for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd != IDROP_NEVER) {
if (PremiumItemOk(i)) {
if (AllItemsList[i].iMinMLvl >= minlvl && AllItemsList[i].iMinMLvl <= maxlvl && ri < 512) {
ril[ri] = i;
ri++;
}
}
}
}
return ril[random_(50, ri)] + 1;
}
static void SpawnOnePremium(int i, int plvl, int myplr)
{
int ivalue;
ItemStruct holditem = items[0];
int strength = get_max_strength(plr[myplr]._pClass);
if (strength < plr[myplr]._pStrength) {
strength = plr[myplr]._pStrength;
}
strength *= 1.2;
int dexterity = get_max_dexterity(plr[myplr]._pClass);
if (dexterity < plr[myplr]._pDexterity) {
dexterity = plr[myplr]._pDexterity;
}
dexterity *= 1.2;
int magic = get_max_magic(plr[myplr]._pClass);
if (magic < plr[myplr]._pMagic) {
magic = plr[myplr]._pMagic;
}
magic *= 1.2;
if (plvl > 30)
plvl = 30;
if (plvl < 1)
plvl = 1;
int count = 0;
do {
memset(&items[0], 0, sizeof(*items));
items[0]._iSeed = AdvanceRndSeed();
SetRndSeed(items[0]._iSeed);
int itype = RndPremiumItem(plvl >> 2, plvl) - 1;
GetItemAttrs(0, itype, plvl);
GetItemBonus(0, itype, plvl >> 1, plvl, TRUE, !gbIsHellfire);
if (!gbIsHellfire) {
if (items[0]._iIvalue > 140000)
continue;
break;
}
switch (items[0]._itype) {
case ITYPE_LARMOR:
case ITYPE_MARMOR:
case ITYPE_HARMOR:
ivalue = get_armor_max_value(myplr);
break;
case ITYPE_SHIELD:
ivalue = get_shield_max_value(myplr);
break;
case ITYPE_AXE:
ivalue = get_axe_max_value(myplr);
break;
case ITYPE_BOW:
ivalue = get_bow_max_value(myplr);
break;
case ITYPE_MACE:
ivalue = get_mace_max_value(myplr);
break;
case ITYPE_SWORD:
ivalue = get_sword_max_value(myplr);
break;
case ITYPE_HELM:
ivalue = get_helm_max_value(myplr);
break;
case ITYPE_STAFF:
ivalue = get_staff_max_value(myplr);
break;
case ITYPE_RING:
ivalue = get_ring_max_value(myplr);
break;
case ITYPE_AMULET:
ivalue = get_amulet_max_value(myplr);
break;
default:
ivalue = 0;
break;
}
ivalue *= 0.8;
count++;
} while ((items[0]._iIvalue > 200000
|| items[0]._iMinStr > strength
|| items[0]._iMinMag > magic
|| items[0]._iMinDex > dexterity
|| items[0]._iIvalue < ivalue)
&& count < 150);
premiumitem[i] = items[0];
premiumitem[i]._iCreateInfo = plvl | CF_SMITHPREMIUM;
premiumitem[i]._iIdentified = TRUE;
premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]);
items[0] = holditem;
}
void SpawnPremium(int pnum)
{
int i;
int lvl = plr[pnum]._pLevel;
int maxItems = gbIsHellfire ? SMITH_PREMIUM_ITEMS : 6;
if (numpremium < maxItems) {
for (i = 0; i < maxItems; i++) {
if (premiumitem[i].isEmpty()) {
int plvl = premiumlevel + (gbIsHellfire ? premiumLvlAddHellfire[i] : premiumlvladd[i]);
SpawnOnePremium(i, plvl, pnum);
}
}
numpremium = maxItems;
}
while (premiumlevel < lvl) {
premiumlevel++;
if (gbIsHellfire) {
premiumitem[0] = premiumitem[3];
premiumitem[1] = premiumitem[4];
premiumitem[2] = premiumitem[5];
premiumitem[3] = premiumitem[6];
premiumitem[4] = premiumitem[7];
premiumitem[5] = premiumitem[8];
premiumitem[6] = premiumitem[9];
premiumitem[7] = premiumitem[10];
premiumitem[8] = premiumitem[11];
premiumitem[9] = premiumitem[12];
SpawnOnePremium(10, premiumlevel + premiumLvlAddHellfire[10], pnum);
premiumitem[11] = premiumitem[13];
SpawnOnePremium(12, premiumlevel + premiumLvlAddHellfire[12], pnum);
premiumitem[13] = premiumitem[14];
SpawnOnePremium(14, premiumlevel + premiumLvlAddHellfire[14], pnum);
} else {
premiumitem[0] = premiumitem[2];
premiumitem[1] = premiumitem[3];
premiumitem[2] = premiumitem[4];
SpawnOnePremium(3, premiumlevel + premiumlvladd[3], pnum);
premiumitem[4] = premiumitem[5];
SpawnOnePremium(5, premiumlevel + premiumlvladd[5], pnum);
}
}
}
BOOL WitchItemOk(int i)
{
BOOL rv;
rv = FALSE;
if (AllItemsList[i].itype == ITYPE_MISC)
rv = TRUE;
if (AllItemsList[i].itype == ITYPE_STAFF)
rv = TRUE;
if (AllItemsList[i].iMiscId == IMISC_MANA)
rv = FALSE;
if (AllItemsList[i].iMiscId == IMISC_FULLMANA)
rv = FALSE;
if (AllItemsList[i].iSpell == SPL_TOWN)
rv = FALSE;
if (AllItemsList[i].iMiscId == IMISC_FULLHEAL)
rv = FALSE;
if (AllItemsList[i].iMiscId == IMISC_HEAL)
rv = FALSE;
if (AllItemsList[i].iMiscId > IMISC_OILFIRST && AllItemsList[i].iMiscId < IMISC_OILLAST)
rv = FALSE;
if (AllItemsList[i].iSpell == SPL_RESURRECT && !gbIsMultiplayer)
rv = FALSE;
if (AllItemsList[i].iSpell == SPL_HEALOTHER && !gbIsMultiplayer)
rv = FALSE;
return rv;
}
int RndWitchItem(int lvl)
{
int i, ri;
int ril[512];
ri = 0;
for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd != IDROP_NEVER && WitchItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
&& ri < 512) {
ril[ri] = i;
ri++;
}
}
return ril[random_(51, ri)] + 1;
}
void SortWitch()
{
int j, k;
BOOL sorted;
j = 3;
while (!witchitem[j + 1].isEmpty()) {
j++;
}
sorted = FALSE;
while (j > 3 && !sorted) {
sorted = TRUE;
for (k = 3; k < j; k++) {
if (witchitem[k].IDidx > witchitem[k + 1].IDidx) {
BubbleSwapItem(&witchitem[k], &witchitem[k + 1]);
sorted = FALSE;
}
}
j--;
}
}
void WitchBookLevel(int ii)
{
int slvl;
if (witchitem[ii]._iMiscId == IMISC_BOOK) {
witchitem[ii]._iMinMag = spelldata[witchitem[ii]._iSpell].sMinInt;
slvl = plr[myplr]._pSplLvl[witchitem[ii]._iSpell];
while (slvl) {
witchitem[ii]._iMinMag += 20 * witchitem[ii]._iMinMag / 100;
slvl--;
if (witchitem[ii]._iMinMag + 20 * witchitem[ii]._iMinMag / 100 > 255) {
witchitem[ii]._iMinMag = 255;
slvl = 0;
}
}
}
}
void SpawnWitch(int lvl)
{
int i, j, iCnt;
int idata, maxlvl, maxValue;
j = 3;
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_MANA, 1);
witchitem[0] = items[0];
witchitem[0]._iCreateInfo = lvl;
witchitem[0]._iStatFlag = TRUE;
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_FULLMANA, 1);
witchitem[1] = items[0];
witchitem[1]._iCreateInfo = lvl;
witchitem[1]._iStatFlag = TRUE;
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_PORTAL, 1);
witchitem[2] = items[0];
witchitem[2]._iCreateInfo = lvl;
witchitem[2]._iStatFlag = TRUE;
if (gbIsHellfire) {
iCnt = random_(51, WITCH_ITEMS - 10) + 10;
maxValue = 200000;
int bCnt;
int books = random_(3, 4);
for (i = 114, bCnt = 0; i <= 117 && bCnt < books; ++i) {
if (WitchItemOk(i)
&& lvl >= AllItemsList[i].iMinMLvl) {
memset(&items[0], 0, sizeof(*items));
items[0]._iSeed = AdvanceRndSeed();
SetRndSeed(items[0]._iSeed);
random_(0, 1);
GetItemAttrs(0, i, lvl);
witchitem[j] = items[0];
witchitem[j]._iCreateInfo = lvl | CF_WITCH;
witchitem[j]._iIdentified = TRUE;
WitchBookLevel(j);
witchitem[j]._iStatFlag = StoreStatOk(&witchitem[j]);
j++;
bCnt++;
}
}
} else {
iCnt = random_(51, WITCH_ITEMS - 12) + 10;
maxValue = 140000;
}
for (i = j; i < iCnt; i++) {
do {
memset(&items[0], 0, sizeof(*items));
items[0]._iSeed = AdvanceRndSeed();
SetRndSeed(items[0]._iSeed);
idata = RndWitchItem(lvl) - 1;
GetItemAttrs(0, idata, lvl);
maxlvl = -1;
if (random_(51, 100) <= 5)
maxlvl = 2 * lvl;
if (maxlvl == -1 && items[0]._iMiscId == IMISC_STAFF)
maxlvl = 2 * lvl;
if (maxlvl != -1)
GetItemBonus(0, idata, maxlvl >> 1, maxlvl, TRUE, TRUE);
} while (items[0]._iIvalue > maxValue);
witchitem[i] = items[0];
witchitem[i]._iCreateInfo = lvl | CF_WITCH;
witchitem[i]._iIdentified = TRUE;
WitchBookLevel(i);
witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]);
}
for (i = iCnt; i < WITCH_ITEMS; i++)
witchitem[i]._itype = ITYPE_NONE;
SortWitch();
}
int RndBoyItem(int lvl)
{
int i, ri;
int ril[512];
ri = 0;
for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd != IDROP_NEVER && PremiumItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
&& ri < 512) {
ril[ri] = i;
ri++;
}
}
return ril[random_(49, ri)] + 1;
}
void SpawnBoy(int lvl)
{
int itype;
int ivalue;
int count = 0;
int strength = get_max_strength(plr[myplr]._pClass);
int dexterity = get_max_dexterity(plr[myplr]._pClass);
int magic = get_max_magic(plr[myplr]._pClass);
plr_class pc = plr[myplr]._pClass;
if (strength < plr[myplr]._pStrength) {
strength = plr[myplr]._pStrength;
}
strength *= 1.2;
if (dexterity < plr[myplr]._pDexterity) {
dexterity = plr[myplr]._pDexterity;
}
dexterity *= 1.2;
if (magic < plr[myplr]._pMagic) {
magic = plr[myplr]._pMagic;
}
magic *= 1.2;
if (boylevel < (lvl >> 1) || boyitem.isEmpty()) {
do {
memset(&items[0], 0, sizeof(*items));
items[0]._iSeed = AdvanceRndSeed();
SetRndSeed(items[0]._iSeed);
itype = RndBoyItem(lvl) - 1;
GetItemAttrs(0, itype, lvl);
GetItemBonus(0, itype, lvl, 2 * lvl, TRUE, TRUE);
if (!gbIsHellfire) {
if (items[0]._iIvalue > 140000)
continue;
break;
}
ivalue = 0;
int itemType = items[0]._itype;
switch (itemType) {
case ITYPE_LARMOR:
case ITYPE_MARMOR:
case ITYPE_HARMOR:
ivalue = get_armor_max_value(myplr);
break;
case ITYPE_SHIELD:
ivalue = get_shield_max_value(myplr);
break;
case ITYPE_AXE:
ivalue = get_axe_max_value(myplr);
break;
case ITYPE_BOW:
ivalue = get_bow_max_value(myplr);
break;
case ITYPE_MACE:
ivalue = get_mace_max_value(myplr);
break;
case ITYPE_SWORD:
ivalue = get_sword_max_value(myplr);
break;
case ITYPE_HELM:
ivalue = get_helm_max_value(myplr);
break;
case ITYPE_STAFF:
ivalue = get_staff_max_value(myplr);
break;
case ITYPE_RING:
ivalue = get_ring_max_value(myplr);
break;
case ITYPE_AMULET:
ivalue = get_amulet_max_value(myplr);
break;
}
ivalue *= 0.8;
count++;
if (count < 200) {
switch (pc) {
case PC_WARRIOR:
if (itemType == ITYPE_BOW || itemType == ITYPE_STAFF)
ivalue = INT_MAX;
break;
case PC_ROGUE:
if (itemType == ITYPE_SWORD || itemType == ITYPE_STAFF || itemType == ITYPE_AXE || itemType == ITYPE_MACE || itemType == ITYPE_SHIELD)
ivalue = INT_MAX;
break;
case PC_SORCERER:
if (itemType == ITYPE_STAFF || itemType == ITYPE_AXE || itemType == ITYPE_BOW || itemType == ITYPE_MACE)
ivalue = INT_MAX;
break;
case PC_MONK:
if (itemType == ITYPE_BOW || itemType == ITYPE_MARMOR || itemType == ITYPE_SHIELD || itemType == ITYPE_MACE)
ivalue = INT_MAX;
break;
case PC_BARD:
if (itemType == ITYPE_AXE || itemType == ITYPE_MACE || itemType == ITYPE_STAFF)
ivalue = INT_MAX;
break;
case PC_BARBARIAN:
if (itemType == ITYPE_BOW || itemType == ITYPE_STAFF)
ivalue = INT_MAX;
break;
case NUM_CLASSES:
break;
}
}
} while ((items[0]._iIvalue > 200000
|| items[0]._iMinStr > strength
|| items[0]._iMinMag > magic
|| items[0]._iMinDex > dexterity
|| items[0]._iIvalue < ivalue)
&& count < 250);
boyitem = items[0];
boyitem._iCreateInfo = lvl | CF_BOY;
boyitem._iIdentified = TRUE;
boyitem._iStatFlag = StoreStatOk(&boyitem);
boylevel = lvl >> 1;
}
}
BOOL HealerItemOk(int i)
{
if (AllItemsList[i].itype != ITYPE_MISC)
return FALSE;
if (AllItemsList[i].iMiscId == IMISC_SCROLL)
return AllItemsList[i].iSpell == SPL_HEAL;
if (AllItemsList[i].iMiscId == IMISC_SCROLLT)
return AllItemsList[i].iSpell == SPL_HEALOTHER && gbIsMultiplayer;
if (!gbIsMultiplayer) {
if (AllItemsList[i].iMiscId == IMISC_ELIXSTR)
return !gbIsHellfire || plr[myplr]._pBaseStr < MaxStats[plr[myplr]._pClass][ATTRIB_STR];
if (AllItemsList[i].iMiscId == IMISC_ELIXMAG)
return !gbIsHellfire || plr[myplr]._pBaseMag < MaxStats[plr[myplr]._pClass][ATTRIB_MAG];
if (AllItemsList[i].iMiscId == IMISC_ELIXDEX)
return !gbIsHellfire || plr[myplr]._pBaseDex < MaxStats[plr[myplr]._pClass][ATTRIB_DEX];
if (AllItemsList[i].iMiscId == IMISC_ELIXVIT)
return !gbIsHellfire || plr[myplr]._pBaseVit < MaxStats[plr[myplr]._pClass][ATTRIB_VIT];
}
if (AllItemsList[i].iMiscId == IMISC_REJUV)
return TRUE;
if (AllItemsList[i].iMiscId == IMISC_FULLREJUV)
return TRUE;
return FALSE;
}
int RndHealerItem(int lvl)
{
int i, ri;
int ril[512];
ri = 0;
for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) {
if (!IsItemAvailable(i))
continue;
if (AllItemsList[i].iRnd != IDROP_NEVER && HealerItemOk(i) && lvl >= AllItemsList[i].iMinMLvl
&& ri < 512) {
ril[ri] = i;
ri++;
}
}
return ril[random_(50, ri)] + 1;
}
void SortHealer()
{
int j, k;
BOOL sorted;
j = 2;
while (!healitem[j + 1].isEmpty()) {
j++;
}
sorted = FALSE;
while (j > 2 && !sorted) {
sorted = TRUE;
for (k = 2; k < j; k++) {
if (healitem[k].IDidx > healitem[k + 1].IDidx) {
BubbleSwapItem(&healitem[k], &healitem[k + 1]);
sorted = FALSE;
}
}
j--;
}
}
void SpawnHealer(int lvl)
{
int i, nsi, srnd, itype;
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_HEAL, 1);
healitem[0] = items[0];
healitem[0]._iCreateInfo = lvl;
healitem[0]._iStatFlag = TRUE;
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_FULLHEAL, 1);
healitem[1] = items[0];
healitem[1]._iCreateInfo = lvl;
healitem[1]._iStatFlag = TRUE;
if (gbIsMultiplayer) {
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_RESURRECT, 1);
healitem[2] = items[0];
healitem[2]._iCreateInfo = lvl;
healitem[2]._iStatFlag = TRUE;
srnd = 3;
} else {
srnd = 2;
}
nsi = random_(50, gbIsHellfire ? 10 : 8) + 10;
for (i = srnd; i < nsi; i++) {
memset(&items[0], 0, sizeof(*items));
items[0]._iSeed = AdvanceRndSeed();
SetRndSeed(items[0]._iSeed);
itype = RndHealerItem(lvl) - 1;
GetItemAttrs(0, itype, lvl);
healitem[i] = items[0];
healitem[i]._iCreateInfo = lvl | CF_HEALER;
healitem[i]._iIdentified = TRUE;
healitem[i]._iStatFlag = StoreStatOk(&healitem[i]);
}
for (i = nsi; i < 20; i++) {
healitem[i]._itype = ITYPE_NONE;
}
SortHealer();
}
void SpawnStoreGold()
{
memset(&items[0], 0, sizeof(*items));
GetItemAttrs(0, IDI_GOLD, 1);
golditem = items[0];
golditem._iStatFlag = TRUE;
}
void RecreateSmithItem(int ii, int idx, int lvl, int iseed)
{
SetRndSeed(iseed);
int itype = RndSmithItem(lvl) - 1;
GetItemAttrs(ii, itype, lvl);
items[ii]._iSeed = iseed;
items[ii]._iCreateInfo = lvl | CF_SMITH;
items[ii]._iIdentified = TRUE;
}
void RecreatePremiumItem(int ii, int idx, int plvl, int iseed)
{
SetRndSeed(iseed);
int itype = RndPremiumItem(plvl >> 2, plvl) - 1;
GetItemAttrs(ii, itype, plvl);
GetItemBonus(ii, itype, plvl >> 1, plvl, TRUE, !gbIsHellfire);
items[ii]._iSeed = iseed;
items[ii]._iCreateInfo = plvl | CF_SMITHPREMIUM;
items[ii]._iIdentified = TRUE;
}
void RecreateBoyItem(int ii, int idx, int lvl, int iseed)
{
SetRndSeed(iseed);
int itype = RndBoyItem(lvl) - 1;
GetItemAttrs(ii, itype, lvl);
GetItemBonus(ii, itype, lvl, 2 * lvl, TRUE, TRUE);
items[ii]._iSeed = iseed;
items[ii]._iCreateInfo = lvl | CF_BOY;
items[ii]._iIdentified = TRUE;
}
void RecreateWitchItem(int ii, int idx, int lvl, int iseed)
{
if (idx == IDI_MANA || idx == IDI_FULLMANA || idx == IDI_PORTAL) {
GetItemAttrs(ii, idx, lvl);
} else if (gbIsHellfire && idx >= 114 && idx <= 117) {
SetRndSeed(iseed);
random_(0, 1);
GetItemAttrs(ii, idx, lvl);
} else {
SetRndSeed(iseed);
int itype = RndWitchItem(lvl) - 1;
GetItemAttrs(ii, itype, lvl);
int iblvl = -1;
if (random_(51, 100) <= 5)
iblvl = 2 * lvl;
if (iblvl == -1 && items[ii]._iMiscId == IMISC_STAFF)
iblvl = 2 * lvl;
if (iblvl != -1)
GetItemBonus(ii, itype, iblvl >> 1, iblvl, TRUE, TRUE);
}
items[ii]._iSeed = iseed;
items[ii]._iCreateInfo = lvl | CF_WITCH;
items[ii]._iIdentified = TRUE;
}
void RecreateHealerItem(int ii, int idx, int lvl, int iseed)
{
int itype;
if (idx == IDI_HEAL || idx == IDI_FULLHEAL || idx == IDI_RESURRECT) {
GetItemAttrs(ii, idx, lvl);
} else {
SetRndSeed(iseed);
itype = RndHealerItem(lvl) - 1;
GetItemAttrs(ii, itype, lvl);
}
items[ii]._iSeed = iseed;
items[ii]._iCreateInfo = lvl | CF_HEALER;
items[ii]._iIdentified = TRUE;
}
void RecreateTownItem(int ii, int idx, WORD icreateinfo, int iseed, int ivalue)
{
if (icreateinfo & CF_SMITH)
RecreateSmithItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
else if (icreateinfo & CF_SMITHPREMIUM)
RecreatePremiumItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
else if (icreateinfo & CF_BOY)
RecreateBoyItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
else if (icreateinfo & CF_WITCH)
RecreateWitchItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
else if (icreateinfo & CF_HEALER)
RecreateHealerItem(ii, idx, icreateinfo & CF_LEVEL, iseed);
}
void RecalcStoreStats()
{
int i;
for (i = 0; i < SMITH_ITEMS; i++) {
if (!smithitem[i].isEmpty()) {
smithitem[i]._iStatFlag = StoreStatOk(&smithitem[i]);
}
}
for (i = 0; i < SMITH_PREMIUM_ITEMS; i++) {
if (!premiumitem[i].isEmpty()) {
premiumitem[i]._iStatFlag = StoreStatOk(&premiumitem[i]);
}
}
for (i = 0; i < 20; i++) {
if (!witchitem[i].isEmpty()) {
witchitem[i]._iStatFlag = StoreStatOk(&witchitem[i]);
}
}
for (i = 0; i < 20; i++) {
if (!healitem[i].isEmpty()) {
healitem[i]._iStatFlag = StoreStatOk(&healitem[i]);
}
}
boyitem._iStatFlag = StoreStatOk(&boyitem);
}
int ItemNoFlippy()
{
int r = itemactive[numitems - 1];
items[r]._iAnimFrame = items[r]._iAnimLen;
items[r]._iAnimFlag = FALSE;
items[r]._iSelFlag = 1;
return r;
}
void CreateSpellBook(int x, int y, spell_id ispell, BOOL sendmsg, BOOL delta)
{
int lvl = currlevel;
if (gbIsHellfire) {
lvl = GetSpellBookLevel(ispell) + 1;
if (lvl < 1) {
return;
}
}
int idx = RndTypeItems(ITYPE_MISC, IMISC_BOOK, lvl);
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
while (true) {
memset(&items[ii], 0, sizeof(*items));
SetupAllItems(ii, idx, AdvanceRndSeed(), 2 * lvl, 1, TRUE, FALSE, delta);
if (items[ii]._iMiscId == IMISC_BOOK && items[ii]._iSpell == ispell)
break;
}
GetSuperItemSpace(x, y, ii);
if (sendmsg)
NetSendCmdDItem(FALSE, ii);
if (delta)
DeltaAddItem(ii);
}
static void CreateMagicItem(int x, int y, int lvl, int imisc, int imid, int icurs, BOOL sendmsg, BOOL delta)
{
if (numitems >= MAXITEMS)
return;
int ii = AllocateItem();
int idx = RndTypeItems(imisc, imid, lvl);
while (true) {
memset(&items[ii], 0, sizeof(*items));
SetupAllItems(ii, idx, AdvanceRndSeed(), 2 * lvl, 1, TRUE, FALSE, delta);
if (items[ii]._iCurs == icurs)
break;
idx = RndTypeItems(imisc, imid, lvl);
}
GetSuperItemSpace(x, y, ii);
if (sendmsg)
NetSendCmdDItem(FALSE, ii);
if (delta)
DeltaAddItem(ii);
}
void CreateMagicArmor(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta)
{
int lvl = items_get_currlevel();
CreateMagicItem(x, y, lvl, imisc, IMISC_NONE, icurs, sendmsg, delta);
}
void CreateAmulet(int x, int y, int lvl, BOOL sendmsg, BOOL delta)
{
CreateMagicItem(x, y, lvl, ITYPE_AMULET, IMISC_AMULET, ICURS_AMULET, sendmsg, delta);
}
void CreateMagicWeapon(int x, int y, int imisc, int icurs, BOOL sendmsg, BOOL delta)
{
int imid = IMISC_NONE;
if (imisc == ITYPE_STAFF)
imid = IMISC_STAFF;
int curlv = items_get_currlevel();
CreateMagicItem(x, y, curlv, imisc, imid, icurs, sendmsg, delta);
}
static void NextItemRecord(int i)
{
gnNumGetRecords--;
if (gnNumGetRecords == 0) {
return;
}
itemrecord[i].dwTimestamp = itemrecord[gnNumGetRecords].dwTimestamp;
itemrecord[i].nSeed = itemrecord[gnNumGetRecords].nSeed;
itemrecord[i].wCI = itemrecord[gnNumGetRecords].wCI;
itemrecord[i].nIndex = itemrecord[gnNumGetRecords].nIndex;
}
BOOL GetItemRecord(int nSeed, WORD wCI, int nIndex)
{
int i;
DWORD dwTicks;
dwTicks = SDL_GetTicks();
for (i = 0; i < gnNumGetRecords; i++) {
if (dwTicks - itemrecord[i].dwTimestamp > 6000) {
NextItemRecord(i);
i--;
} else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) {
return FALSE;
}
}
return TRUE;
}
void SetItemRecord(int nSeed, WORD wCI, int nIndex)
{
DWORD dwTicks;
dwTicks = SDL_GetTicks();
if (gnNumGetRecords == MAXITEMS) {
return;
}
itemrecord[gnNumGetRecords].dwTimestamp = dwTicks;
itemrecord[gnNumGetRecords].nSeed = nSeed;
itemrecord[gnNumGetRecords].wCI = wCI;
itemrecord[gnNumGetRecords].nIndex = nIndex;
gnNumGetRecords++;
}
void PutItemRecord(int nSeed, WORD wCI, int nIndex)
{
int i;
DWORD dwTicks;
dwTicks = SDL_GetTicks();
for (i = 0; i < gnNumGetRecords; i++) {
if (dwTicks - itemrecord[i].dwTimestamp > 6000) {
NextItemRecord(i);
i--;
} else if (nSeed == itemrecord[i].nSeed && wCI == itemrecord[i].wCI && nIndex == itemrecord[i].nIndex) {
NextItemRecord(i);
break;
}
}
}
} // namespace devilution