/** * @file items.cpp * * Implementation of item functionality. */ #include #include "all.h" #include "options.h" DEVILUTION_BEGIN_NAMESPACE 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); AutoPlace(p, 0, 1, 3, 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(s)); if (sLevel != -1 && lvl >= sLevel) { rv--; bs = static_cast(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(s)); if (sLevel != -1 && l >= sLevel) { rv--; bs = static_cast(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(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(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(int i, BOOL FlipFlag) { 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]._iPostDraw = FALSE; items[i]._iRequest = FALSE; if (FlipFlag) { 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; } if (items[i]._iCurs == ICURS_MAGIC_ROCK) { items[i]._iSelFlag = 1; PlaySfxLoc(ItemDropSnds[it], items[i]._ix, items[i]._iy); } if (items[i]._iCurs == ICURS_TAVERN_SIGN) items[i]._iSelFlag = 1; if (items[i]._iCurs == ICURS_ANVIL_OF_FURY) items[i]._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; } } } DEVILUTION_END_NAMESPACE