/**
* @ file items . cpp
*
* Implementation of item functionality .
*/
# include <algorithm>
# include <climits>
# include <cstdint>
# include <bitset>
# include <fmt/format.h>
# include "cursor.h"
# include "doom.h"
# include "dx.h"
# include "engine/render/cel_render.hpp"
# include "engine/render/text_render.hpp"
# include "init.h"
# include "lighting.h"
# include "missiles.h"
# include "options.h"
# include "stores.h"
# include "utils/language.h"
# include "utils/math.h"
namespace devilution {
namespace {
std : : optional < CelSprite > itemanims [ ITEMTYPES ] ;
} // namespace
enum anim_armor_id : uint8_t {
// clang-format off
ANIM_ID_LIGHT_ARMOR = 0 ,
ANIM_ID_MEDIUM_ARMOR = 1 < < 4 ,
ANIM_ID_HEAVY_ARMOR = 1 < < 5 ,
// clang-format on
} ;
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 ;
bool UniqueItemFlags [ 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 } ;
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 ] = {
N_ ( " Oil of Accuracy " ) ,
N_ ( " Oil of Mastery " ) ,
N_ ( " Oil of Sharpness " ) ,
N_ ( " Oil of Death " ) ,
N_ ( " Oil of Skill " ) ,
N_ ( " Blacksmith Oil " ) ,
N_ ( " Oil of Fortitude " ) ,
N_ ( " Oil of Permanence " ) ,
N_ ( " Oil of Hardening " ) ,
N_ ( " 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. */
_sfx_id 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. */
_sfx_id 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 ,
} ;
/** 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 ) ) ;
}
BYTE GetOutlineColor ( const ItemStruct & item , bool checkReq )
{
if ( checkReq & & ! item . _iStatFlag )
return ICOL_RED ;
if ( item . _itype = = ITYPE_GOLD )
return ICOL_YELLOW ;
if ( item . _iMagical = = ITEM_QUALITY_MAGIC )
return ICOL_BLUE ;
if ( item . _iMagical = = ITEM_QUALITY_UNIQUE )
return ICOL_YELLOW ;
return ICOL_WHITE ;
}
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 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 ] = LoadCel ( arglist , ItemAnimWidth ) ;
}
memset ( UniqueItemFlags , 0 , sizeof ( UniqueItemFlags ) ) ;
}
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 ) ! = 0 )
return false ;
if ( nSolidTable [ dPiece [ xp ] [ yp ] ] )
return false ;
return true ;
}
void AddInitItems ( )
{
int x , y , j , rnd ;
int curlv = items_get_currlevel ( ) ;
rnd = GenerateRnd ( 3 ) + 3 ;
for ( j = 0 ; j < rnd ; j + + ) {
int ii = AllocateItem ( ) ;
x = GenerateRnd ( 80 ) + 16 ;
y = GenerateRnd ( 80 ) + 16 ;
while ( ! ItemPlace ( x , y ) ) {
x = GenerateRnd ( 80 ) + 16 ;
y = GenerateRnd ( 80 ) + 16 ;
}
items [ ii ] . position = { x , y } ;
dItem [ x ] [ y ] = ii + 1 ;
items [ ii ] . _iSeed = AdvanceRndSeed ( ) ;
SetRndSeed ( items [ ii ] . _iSeed ) ;
if ( GenerateRnd ( 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 = GenerateRnd ( 80 ) + 16 ;
y = GenerateRnd ( 80 ) + 16 ;
while ( ! ItemPlace ( x , y ) ) {
x = GenerateRnd ( 80 ) + 16 ;
y = GenerateRnd ( 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 ] . position = { 0 , 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 ( sgGameInitInfo . bCowQuest & & currlevel = = 20 )
SpawnQuestItem ( IDI_BROWNSUIT , { 25 , 25 } , 3 , 1 ) ;
if ( sgGameInitInfo . bCowQuest & & 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 playerId , bool Loadgfx )
{
auto & player = plr [ playerId ] ;
int mind = 0 ; // min damage
int maxd = 0 ; // max damage
int tac = 0 ; // accuracy
int g ;
int i ;
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_t 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 = & player . 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 = math : : Sign ( itm - > _iPLAC ) ;
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 ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_SHIELD & & player . InvBody [ INVLOC_HAND_LEFT ] . _iStatFlag ) {
maxd = 3 ;
}
if ( player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_SHIELD & & player . InvBody [ INVLOC_HAND_RIGHT ] . _iStatFlag ) {
maxd = 3 ;
}
if ( player . _pClass = = HeroClass : : Monk ) {
mind = std : : max ( mind , player . _pLevel / 2 ) ;
maxd = std : : max ( maxd , ( int ) player . _pLevel ) ;
}
}
if ( ( player . _pSpellFlags & 2 ) = = 2 ) {
sadd + = 2 * player . _pLevel ;
dadd + = player . _pLevel + player . _pLevel / 2 ;
vadd + = 2 * player . _pLevel ;
}
if ( ( player . _pSpellFlags & 4 ) = = 4 ) {
sadd - = 2 * player . _pLevel ;
dadd - = player . _pLevel + player . _pLevel / 2 ;
vadd - = 2 * player . _pLevel ;
}
player . _pIMinDam = mind ;
player . _pIMaxDam = maxd ;
player . _pIAC = tac ;
player . _pIBonusDam = bdam ;
player . _pIBonusToHit = btohit ;
player . _pIBonusAC = bac ;
player . _pIFlags = iflgs ;
player . pDamAcFlags = pDamAcFlags ;
player . _pIBonusDamMod = dmod ;
player . _pIGetHit = ghit ;
lrad = clamp ( lrad , 2 , 15 ) ;
if ( player . _pLightRad ! = lrad & & playerId = = myplr ) {
ChangeLightRadius ( player . _plid , lrad ) ;
ChangeVisionRadius ( player . _pvid , lrad ) ;
player . _pLightRad = lrad ;
}
player . _pStrength = std : : max ( 0 , sadd + player . _pBaseStr ) ;
player . _pMagic = std : : max ( 0 , madd + player . _pBaseMag ) ;
player . _pDexterity = std : : max ( 0 , dadd + player . _pBaseDex ) ;
player . _pVitality = std : : max ( 0 , vadd + player . _pBaseVit ) ;
if ( player . _pClass = = HeroClass : : Rogue ) {
player . _pDamageMod = player . _pLevel * ( player . _pStrength + player . _pDexterity ) / 200 ;
} else if ( player . _pClass = = HeroClass : : Monk ) {
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype ! = ITYPE_STAFF ) {
if ( player . InvBody [ INVLOC_HAND_RIGHT ] . _itype ! = ITYPE_STAFF & & ( ! player . InvBody [ INVLOC_HAND_LEFT ] . isEmpty ( ) | | ! player . InvBody [ INVLOC_HAND_RIGHT ] . isEmpty ( ) ) ) {
player . _pDamageMod = player . _pLevel * ( player . _pStrength + player . _pDexterity ) / 300 ;
} else {
player . _pDamageMod = player . _pLevel * ( player . _pStrength + player . _pDexterity ) / 150 ;
}
} else {
player . _pDamageMod = player . _pLevel * ( player . _pStrength + player . _pDexterity ) / 150 ;
}
} else if ( player . _pClass = = HeroClass : : Bard ) {
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_SWORD | | player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_SWORD )
player . _pDamageMod = player . _pLevel * ( player . _pStrength + player . _pDexterity ) / 150 ;
else if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_BOW | | player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_BOW ) {
player . _pDamageMod = player . _pLevel * ( player . _pStrength + player . _pDexterity ) / 250 ;
} else {
player . _pDamageMod = player . _pLevel * player . _pStrength / 100 ;
}
} else if ( player . _pClass = = HeroClass : : Barbarian ) {
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_AXE | | player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_AXE ) {
player . _pDamageMod = player . _pLevel * player . _pStrength / 75 ;
} else if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_MACE | | player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_MACE ) {
player . _pDamageMod = player . _pLevel * player . _pStrength / 75 ;
} else if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_BOW | | player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_BOW ) {
player . _pDamageMod = player . _pLevel * player . _pStrength / 300 ;
} else {
player . _pDamageMod = player . _pLevel * player . _pStrength / 100 ;
}
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_SHIELD | | player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_SHIELD ) {
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_SHIELD )
player . _pIAC - = player . InvBody [ INVLOC_HAND_LEFT ] . _iAC / 2 ;
else if ( player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_SHIELD )
player . _pIAC - = player . InvBody [ INVLOC_HAND_RIGHT ] . _iAC / 2 ;
} else if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype ! = ITYPE_STAFF & & player . InvBody [ INVLOC_HAND_RIGHT ] . _itype ! = ITYPE_STAFF & & player . InvBody [ INVLOC_HAND_LEFT ] . _itype ! = ITYPE_BOW & & player . InvBody [ INVLOC_HAND_RIGHT ] . _itype ! = ITYPE_BOW ) {
player . _pDamageMod + = player . _pLevel * player . _pVitality / 100 ;
}
player . _pIAC + = player . _pLevel / 4 ;
} else {
player . _pDamageMod = player . _pLevel * player . _pStrength / 100 ;
}
player . _pISpells = spl ;
EnsureValidReadiedSpell ( player ) ;
player . _pISplLvlAdd = spllvladd ;
player . _pIEnAc = enac ;
if ( player . _pClass = = HeroClass : : Barbarian ) {
mr + = player . _pLevel ;
fr + = player . _pLevel ;
lr + = player . _pLevel ;
}
if ( ( player . _pSpellFlags & 4 ) = = 4 ) {
mr - = player . _pLevel ;
fr - = player . _pLevel ;
lr - = player . _pLevel ;
}
if ( ( iflgs & ISPL_ALLRESZERO ) ! = 0 ) {
// reset resistances to zero if the respective special effect is active
mr = 0 ;
fr = 0 ;
lr = 0 ;
}
player . _pMagResist = clamp ( mr , 0 , MAXRESIST ) ;
player . _pFireResist = clamp ( fr , 0 , MAXRESIST ) ;
player . _pLghtResist = clamp ( lr , 0 , MAXRESIST ) ;
if ( player . _pClass = = HeroClass : : Warrior ) {
vadd * = 2 ;
} else if ( player . _pClass = = HeroClass : : Barbarian ) {
vadd + = vadd ;
vadd + = ( vadd / 4 ) ;
} else if ( player . _pClass = = HeroClass : : Rogue | | player . _pClass = = HeroClass : : Monk | | player . _pClass = = HeroClass : : Bard ) {
vadd + = vadd / 2 ;
}
ihp + = ( vadd < < 6 ) ; // BUGFIX: blood boil can cause negative shifts here (see line 757)
if ( player . _pClass = = HeroClass : : Sorcerer ) {
madd * = 2 ;
}
if ( player . _pClass = = HeroClass : : Rogue | | player . _pClass = = HeroClass : : Monk ) {
madd + = madd / 2 ;
} else if ( player . _pClass = = HeroClass : : Bard ) {
madd + = ( madd / 4 ) + ( madd / 2 ) ;
}
imana + = ( madd < < 6 ) ;
player . _pMaxHP = ihp + player . _pMaxHPBase ;
player . _pHitPoints = std : : min ( ihp + player . _pHPBase , player . _pMaxHP ) ;
if ( playerId = = myplr & & ( player . _pHitPoints > > 6 ) < = 0 ) {
SetPlayerHitPoints ( playerId , 0 ) ;
}
player . _pMaxMana = imana + player . _pMaxManaBase ;
player . _pMana = std : : min ( imana + player . _pManaBase , player . _pMaxMana ) ;
player . _pIFMinDam = fmin ;
player . _pIFMaxDam = fmax ;
player . _pILMinDam = lmin ;
player . _pILMaxDam = lmax ;
if ( ( iflgs & ISPL_INFRAVISION ) ! = 0 ) {
player . _pInfraFlag = true ;
} else {
player . _pInfraFlag = false ;
}
player . _pBlockFlag = false ;
if ( player . _pClass = = HeroClass : : Monk ) {
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_STAFF & & player . InvBody [ INVLOC_HAND_LEFT ] . _iStatFlag ) {
player . _pBlockFlag = true ;
player . _pIFlags | = ISPL_FASTBLOCK ;
}
if ( player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_STAFF & & player . InvBody [ INVLOC_HAND_RIGHT ] . _iStatFlag ) {
player . _pBlockFlag = true ;
player . _pIFlags | = ISPL_FASTBLOCK ;
}
if ( player . InvBody [ INVLOC_HAND_LEFT ] . isEmpty ( ) & & player . InvBody [ INVLOC_HAND_RIGHT ] . isEmpty ( ) )
player . _pBlockFlag = true ;
if ( player . InvBody [ INVLOC_HAND_LEFT ] . _iClass = = ICLASS_WEAPON & & player . InvBody [ INVLOC_HAND_LEFT ] . _iLoc ! = ILOC_TWOHAND & & player . InvBody [ INVLOC_HAND_RIGHT ] . isEmpty ( ) )
player . _pBlockFlag = true ;
if ( player . InvBody [ INVLOC_HAND_RIGHT ] . _iClass = = ICLASS_WEAPON & & player . InvBody [ INVLOC_HAND_RIGHT ] . _iLoc ! = ILOC_TWOHAND & & player . InvBody [ INVLOC_HAND_LEFT ] . isEmpty ( ) )
player . _pBlockFlag = true ;
}
player . _pwtype = WT_MELEE ;
g = 0 ;
if ( ! player . InvBody [ INVLOC_HAND_LEFT ] . isEmpty ( )
& & player . InvBody [ INVLOC_HAND_LEFT ] . _iClass = = ICLASS_WEAPON
& & player . InvBody [ INVLOC_HAND_LEFT ] . _iStatFlag ) {
g = player . InvBody [ INVLOC_HAND_LEFT ] . _itype ;
}
if ( ! player . InvBody [ INVLOC_HAND_RIGHT ] . isEmpty ( )
& & player . InvBody [ INVLOC_HAND_RIGHT ] . _iClass = = ICLASS_WEAPON
& & player . InvBody [ INVLOC_HAND_RIGHT ] . _iStatFlag ) {
g = player . 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 :
player . _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 ( player . InvBody [ INVLOC_HAND_LEFT ] . _itype = = ITYPE_SHIELD & & player . InvBody [ INVLOC_HAND_LEFT ] . _iStatFlag ) {
player . _pBlockFlag = true ;
g + + ;
}
if ( player . InvBody [ INVLOC_HAND_RIGHT ] . _itype = = ITYPE_SHIELD & & player . InvBody [ INVLOC_HAND_RIGHT ] . _iStatFlag ) {
player . _pBlockFlag = true ;
g + + ;
}
if ( player . InvBody [ INVLOC_CHEST ] . _itype = = ITYPE_HARMOR & & player . InvBody [ INVLOC_CHEST ] . _iStatFlag ) {
if ( player . _pClass = = HeroClass : : Monk & & player . InvBody [ INVLOC_CHEST ] . _iMagical = = ITEM_QUALITY_UNIQUE )
player . _pIAC + = player . _pLevel / 2 ;
g + = ANIM_ID_HEAVY_ARMOR ;
} else if ( player . InvBody [ INVLOC_CHEST ] . _itype = = ITYPE_MARMOR & & player . InvBody [ INVLOC_CHEST ] . _iStatFlag ) {
if ( player . _pClass = = HeroClass : : Monk ) {
if ( player . InvBody [ INVLOC_CHEST ] . _iMagical = = ITEM_QUALITY_UNIQUE )
player . _pIAC + = player . _pLevel * 2 ;
else
player . _pIAC + = player . _pLevel / 2 ;
}
g + = ANIM_ID_MEDIUM_ARMOR ;
} else if ( player . _pClass = = HeroClass : : Monk ) {
player . _pIAC + = player . _pLevel * 2 ;
}
if ( player . _pgfxnum ! = g & & Loadgfx ) {
player . _pgfxnum = g ;
ResetPlayerGFX ( player ) ;
SetPlrAnims ( player ) ;
if ( player . _pmode = = PM_STAND ) {
LoadPlrGFX ( player , player_graphic : : Stand ) ;
player . AnimInfo . ChangeAnimationData ( & * player . AnimationData [ static_cast < size_t > ( player_graphic : : Stand ) ] . CelSpritesForDirections [ player . _pdir ] , player . _pNFrames , 3 ) ;
} else {
LoadPlrGFX ( player , player_graphic : : Walk ) ;
player . AnimInfo . ChangeAnimationData ( & * player . AnimationData [ static_cast < size_t > ( player_graphic : : Walk ) ] . CelSpritesForDirections [ player . _pdir ] , player . _pWFrames , 0 ) ;
}
} else {
player . _pgfxnum = g ;
}
if ( player . InvBody [ INVLOC_AMULET ] . isEmpty ( ) | | player . InvBody [ INVLOC_AMULET ] . IDidx ! = IDI_AURIC ) {
int half = MaxGold ;
MaxGold = GOLD_MAX_LIMIT ;
if ( half ! = MaxGold )
StripTopGold ( playerId ) ;
} else {
MaxGold = GOLD_MAX_LIMIT * 2 ;
}
drawmanaflag = true ;
drawhpflag = true ;
}
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 ( PlayerStruct & player )
{
int i ;
ItemStruct * pi ;
bool sf , changeflag ;
int sa , ma , da ;
sa = 0 ;
ma = 0 ;
da = 0 ;
pi = player . 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 = player . InvBody ;
for ( i = 0 ; i < NUM_INVLOC ; i + + , pi + + ) {
if ( ! pi - > isEmpty ( ) & & pi - > _iStatFlag ) {
sf = true ;
if ( sa + player . _pBaseStr < pi - > _iMinStr )
sf = false ;
if ( ma + player . _pBaseMag < pi - > _iMinMag )
sf = false ;
if ( da + player . _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 ( const PlayerStruct & player , ItemStruct * x )
{
if ( player . _pMagic < x - > _iMinMag )
return false ;
if ( player . _pStrength < x - > _iMinStr )
return false ;
if ( player . _pDexterity < x - > _iMinDex )
return false ;
return true ;
}
void CalcPlrItemMin ( PlayerStruct & player )
{
ItemStruct * pi = player . InvList ;
int i = player . _pNumInv ;
while ( i - - ) {
pi - > _iStatFlag = ItemMinStats ( player , pi ) ;
pi + + ;
}
pi = player . SpdList ;
for ( i = MAXBELTITEMS ; i ! = 0 ; i - - ) {
if ( ! pi - > isEmpty ( ) ) {
pi - > _iStatFlag = ItemMinStats ( player , pi ) ;
}
pi + + ;
}
}
void CalcPlrBookVals ( PlayerStruct & player )
{
if ( currlevel = = 0 ) {
for ( int i = 1 ; ! witchitem [ i ] . isEmpty ( ) ; i + + ) {
WitchBookLevel ( i ) ;
witchitem [ i ] . _iStatFlag = StoreStatOk ( & witchitem [ i ] ) ;
}
}
for ( int i = 0 ; i < player . _pNumInv ; i + + ) {
if ( player . InvList [ i ] . _itype = = ITYPE_MISC & & player . InvList [ i ] . _iMiscId = = IMISC_BOOK ) {
player . InvList [ i ] . _iMinMag = spelldata [ player . InvList [ i ] . _iSpell ] . sMinInt ;
int slvl = player . _pSplLvl [ player . InvList [ i ] . _iSpell ] ;
while ( slvl ! = 0 ) {
player . InvList [ i ] . _iMinMag + = 20 * player . InvList [ i ] . _iMinMag / 100 ;
slvl - - ;
if ( player . InvList [ i ] . _iMinMag + 20 * player . InvList [ i ] . _iMinMag / 100 > 255 ) {
player . InvList [ i ] . _iMinMag = 255 ;
slvl = 0 ;
}
}
player . InvList [ i ] . _iStatFlag = ItemMinStats ( player , & player . InvList [ i ] ) ;
}
}
}
void CalcPlrInv ( int playerId , bool Loadgfx )
{
auto & player = plr [ playerId ] ;
CalcPlrItemMin ( player ) ;
CalcSelfItems ( player ) ;
CalcPlrItemVals ( playerId , Loadgfx ) ;
CalcPlrItemMin ( player ) ;
if ( playerId = = myplr ) {
CalcPlrBookVals ( player ) ;
player . CalcScrolls ( ) ;
CalcPlrStaff ( playerId ) ;
if ( playerId = = 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 playerId )
{
auto & player = plr [ playerId ] ;
for ( auto & item : player . InvBody ) {
item . _itype = ITYPE_NONE ;
}
// converting this to a for loop creates a `rep stosd` instruction,
// so this probably actually was a memset
memset ( & player . InvGrid , 0 , sizeof ( player . InvGrid ) ) ;
for ( auto & item : player . InvList ) {
item . _itype = ITYPE_NONE ;
}
player . _pNumInv = 0 ;
for ( auto & item : player . SpdList ) {
item . _itype = ITYPE_NONE ;
}
switch ( player . _pClass ) {
case HeroClass : : Warrior :
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_LEFT ] , IDI_WARRIOR ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_LEFT ] ) ;
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_RIGHT ] , IDI_WARRSHLD ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_RIGHT ] ) ;
# ifdef _DEBUG
if ( ! debug_mode_key_w )
# endif
{
SetPlrHandItem ( & player . HoldItem , IDI_WARRCLUB ) ;
GetPlrHandSeed ( & player . HoldItem ) ;
AutoPlaceItemInInventory ( player , player . HoldItem , true ) ;
}
SetPlrHandItem ( & player . SpdList [ 0 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 0 ] ) ;
SetPlrHandItem ( & player . SpdList [ 1 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 1 ] ) ;
break ;
case HeroClass : : Rogue :
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_LEFT ] , IDI_ROGUE ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_LEFT ] ) ;
SetPlrHandItem ( & player . SpdList [ 0 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 0 ] ) ;
SetPlrHandItem ( & player . SpdList [ 1 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 1 ] ) ;
break ;
case HeroClass : : Sorcerer :
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_LEFT ] , gbIsHellfire ? IDI_SORCERER : 166 ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_LEFT ] ) ;
SetPlrHandItem ( & player . SpdList [ 0 ] , gbIsHellfire ? IDI_HEAL : IDI_MANA ) ;
GetPlrHandSeed ( & player . SpdList [ 0 ] ) ;
SetPlrHandItem ( & player . SpdList [ 1 ] , gbIsHellfire ? IDI_HEAL : IDI_MANA ) ;
GetPlrHandSeed ( & player . SpdList [ 1 ] ) ;
break ;
case HeroClass : : Monk :
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_LEFT ] , IDI_SHORTSTAFF ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_LEFT ] ) ;
SetPlrHandItem ( & player . SpdList [ 0 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 0 ] ) ;
SetPlrHandItem ( & player . SpdList [ 1 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 1 ] ) ;
break ;
case HeroClass : : Bard :
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_LEFT ] , IDI_BARDSWORD ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_LEFT ] ) ;
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_RIGHT ] , IDI_BARDDAGGER ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_RIGHT ] ) ;
SetPlrHandItem ( & player . SpdList [ 0 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 0 ] ) ;
SetPlrHandItem ( & player . SpdList [ 1 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 1 ] ) ;
break ;
case HeroClass : : Barbarian :
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_LEFT ] , 139 ) ; // TODO: add more enums to items
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_LEFT ] ) ;
SetPlrHandItem ( & player . InvBody [ INVLOC_HAND_RIGHT ] , IDI_WARRSHLD ) ;
GetPlrHandSeed ( & player . InvBody [ INVLOC_HAND_RIGHT ] ) ;
SetPlrHandItem ( & player . SpdList [ 0 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 0 ] ) ;
SetPlrHandItem ( & player . SpdList [ 1 ] , IDI_HEAL ) ;
GetPlrHandSeed ( & player . SpdList [ 1 ] ) ;
break ;
}
SetPlrHandItem ( & player . HoldItem , IDI_GOLD ) ;
GetPlrHandSeed ( & player . HoldItem ) ;
# ifdef _DEBUG
if ( ! debug_mode_key_w ) {
# endif
player . HoldItem . _ivalue = 100 ;
player . HoldItem . _iCurs = ICURS_GOLD_SMALL ;
player . _pGold = player . HoldItem . _ivalue ;
player . InvList [ player . _pNumInv + + ] = player . HoldItem ;
player . InvGrid [ 30 ] = player . _pNumInv ;
# ifdef _DEBUG
} else {
player . HoldItem . _ivalue = GOLD_MAX_LIMIT ;
player . HoldItem . _iCurs = ICURS_GOLD_LARGE ;
player . _pGold = player . HoldItem . _ivalue * 40 ;
for ( auto & cell : player . InvGrid ) {
GetPlrHandSeed ( & player . HoldItem ) ;
player . InvList [ player . _pNumInv + + ] = player . HoldItem ;
cell = player . _pNumInv ;
}
}
# endif
CalcPlrItemVals ( playerId , 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 ( Point position , int8_t inum )
{
int rs ;
int xx , yy ;
bool savail ;
yy = 0 ;
for ( int j = position . y - 1 ; j < = position . y + 1 ; j + + ) {
xx = 0 ;
for ( int i = position . x - 1 ; i < = position . x + 1 ; i + + ) {
itemhold [ xx ] [ yy ] = ItemSpaceOk ( i , j ) ;
xx + + ;
}
yy + + ;
}
savail = false ;
for ( int j = 0 ; j < 3 ; j + + ) {
for ( int i = 0 ; i < 3 ; i + + ) {
if ( itemhold [ i ] [ j ] )
savail = true ;
}
}
rs = GenerateRnd ( 15 ) + 1 ;
if ( ! savail )
return false ;
xx = 0 ;
yy = 0 ;
while ( rs > 0 ) {
if ( itemhold [ xx ] [ yy ] )
rs - - ;
if ( rs < = 0 )
continue ;
xx + + ;
if ( xx ! = 3 )
continue ;
xx = 0 ;
yy + + ;
if ( yy = = 3 )
yy = 0 ;
}
xx + = position . x - 1 ;
yy + = position . y - 1 ;
items [ inum ] . position = { xx , 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 ( Point position , int8_t inum )
{
if ( GetItemSpace ( position , inum ) )
return ;
for ( int k = 2 ; k < 50 ; k + + ) {
for ( int j = - k ; j < = k ; j + + ) {
int yy = position . y + j ;
for ( int i = - k ; i < = k ; i + + ) {
int xx = i + position . x ;
if ( ! ItemSpaceOk ( xx , yy ) )
continue ;
items [ inum ] . position = { xx , yy } ;
dItem [ xx ] [ yy ] = inum + 1 ;
return ;
}
}
}
}
Point GetSuperItemLoc ( Point position )
{
Point ret ;
for ( int k = 1 ; k < 50 ; k + + ) {
for ( int j = - k ; j < = k ; j + + ) {
ret . y = position . y + j ;
for ( int i = - k ; i < = k ; i + + ) {
ret . x = i + position . x ;
if ( ItemSpaceOk ( ret . x , ret . y ) ) {
return ret ;
}
}
}
}
return ret ; // TODO handle no space for dropping items
}
void CalcItemValue ( int i )
{
int 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 ;
items [ i ] . _iIvalue = std : : max ( v , 1 ) ;
}
void GetBookSpell ( int i , int lvl )
{
int rv ;
if ( lvl = = 0 )
lvl = 1 ;
int maxSpells = gbIsHellfire ? MAX_SPELLS : 37 ;
rv = GenerateRnd ( maxSpells ) + 1 ;
if ( gbIsSpawn & & lvl > 5 )
lvl = 5 ;
int s = SPL_FIREBOLT ;
enum spell_id bs = SPL_FIREBOLT ;
while ( rv > 0 ) {
int sLevel = GetSpellBookLevel ( static_cast < spell_id > ( s ) ) ;
if ( sLevel ! = - 1 & & lvl > = sLevel ) {
rv - - ;
bs = static_cast < spell_id > ( s ) ;
}
s + + ;
if ( ! gbIsMultiplayer ) {
if ( s = = SPL_RESURRECT )
s = SPL_TELEKINESIS ;
}
if ( ! gbIsMultiplayer ) {
if ( s = = SPL_HEALOTHER )
s = SPL_FLARE ;
}
if ( s = = maxSpells )
s = 1 ;
}
strcat ( items [ i ] . _iName , _ ( spelldata [ bs ] . sNameText ) ) ;
strcat ( items [ i ] . _iIName , _ ( spelldata [ bs ] . sNameText ) ) ;
items [ i ] . _iSpell = bs ;
items [ i ] . _iMinMag = spelldata [ bs ] . sMinInt ;
items [ i ] . _ivalue + = spelldata [ bs ] . sBookCost ;
items [ i ] . _iIvalue + = spelldata [ bs ] . sBookCost ;
if ( spelldata [ bs ] . sType = = STYPE_FIRE )
items [ i ] . _iCurs = ICURS_BOOK_RED ;
else if ( spelldata [ bs ] . sType = = STYPE_LIGHTNING )
items [ i ] . _iCurs = ICURS_BOOK_BLUE ;
else if ( spelldata [ bs ] . sType = = STYPE_MAGIC )
items [ i ] . _iCurs = ICURS_BOOK_GREY ;
}
static bool control_WriteStringToBuffer ( const char * str )
{
return GetLineWidth ( str , GameFontSmall , 0 ) < 125 ;
}
void GetStaffPower ( int i , int lvl , int bs , bool onlygood )
{
int l [ 256 ] ;
char istr [ 128 ] ;
int nl , j , preidx ;
int tmp ;
tmp = GenerateRnd ( 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 )
continue ;
if ( onlygood & & ! PL_Prefix [ j ] . PLOk )
continue ;
l [ nl ] = j ;
nl + + ;
if ( PL_Prefix [ j ] . PLDouble ) {
l [ nl ] = j ;
nl + + ;
}
}
if ( nl ! = 0 ) {
preidx = l [ GenerateRnd ( 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 ( 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 ) ;
}
strcpy ( istr , fmt : : format ( _ ( /* TRANSLATORS: Constructs item names. Format: <Prefix> <Item> of <Suffix>. Example: King's Long Sword of the Whale */ " {:s} of {:s} " ) , items [ i ] . _iIName , _ ( spelldata [ bs ] . sNameText ) ) . c_str ( ) ) ;
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 & & GenerateRnd ( 4 ) = = 0 ) {
GetItemPower ( i , lvl / 2 , lvl , PLT_STAFF , onlygood ) ;
} else {
int maxSpells = gbIsHellfire ? MAX_SPELLS : 37 ;
l = lvl / 2 ;
if ( l = = 0 )
l = 1 ;
rv = GenerateRnd ( maxSpells ) + 1 ;
if ( gbIsSpawn & & lvl > 10 )
lvl = 10 ;
int s = SPL_FIREBOLT ;
enum spell_id bs = SPL_NULL ;
while ( rv > 0 ) {
int sLevel = GetSpellStaffLevel ( static_cast < spell_id > ( s ) ) ;
if ( sLevel ! = - 1 & & l > = sLevel ) {
rv - - ;
bs = static_cast < spell_id > ( s ) ;
}
s + + ;
if ( ! gbIsMultiplayer & & s = = SPL_RESURRECT )
s = SPL_TELEKINESIS ;
if ( ! gbIsMultiplayer & & s = = SPL_HEALOTHER )
s = SPL_FLARE ;
if ( s = = maxSpells )
s = SPL_FIREBOLT ;
}
if ( ! control_WriteStringToBuffer ( istr ) )
strcpy ( istr , fmt : : format ( _ ( " {:s} of {:s} " ) , items [ i ] . _iName , _ ( spelldata [ bs ] . sNameText ) ) . c_str ( ) ) ;
strcpy ( istr , fmt : : format ( _ ( " Staff of {:s} " ) , _ ( spelldata [ bs ] . sNameText ) ) . c_str ( ) ) ;
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 + GenerateRnd ( 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 = GenerateRnd ( cnt ) ;
t = rnd [ r ] ;
} else {
r = GenerateRnd ( 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 + GenerateRnd ( 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 ( ) ;
switch ( sgGameInitInfo . nDifficulty ) {
case DIFF_NORMAL :
rndv = 5 * itemlevel + GenerateRnd ( 10 * itemlevel ) ;
break ;
case DIFF_NIGHTMARE :
rndv = 5 * ( itemlevel + 16 ) + GenerateRnd ( 10 * ( itemlevel + 16 ) ) ;
break ;
case DIFF_HELL :
rndv = 5 * ( itemlevel + 32 ) + GenerateRnd ( 10 * ( itemlevel + 32 ) ) ;
break ;
}
if ( leveltype = = DTYPE_HELL )
rndv + = rndv / 8 ;
items [ i ] . _ivalue = std : : min ( rndv , GOLD_MAX_LIMIT ) ;
SetPlrHandGoldCurs ( & items [ i ] ) ;
}
int RndPL ( int param1 , int param2 )
{
return param1 + GenerateRnd ( 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 ;
[[fallthrough]] ;
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 = std : : max ( items [ i ] . _iPLFR + r , 0 ) ;
items [ i ] . _iPLLR = std : : max ( items [ i ] . _iPLLR + r , 0 ) ;
items [ i ] . _iPLMR = std : : max ( items [ i ] . _iPLMR + r , 0 ) ;
break ;
case IPL_SPLLVLADD :
items [ i ] . _iSplLvlAdd = r ;
break ;
case IPL_CHARGES :
items [ i ] . _iCharges * = param1 ;
items [ i ] . _iMaxCharges = items [ i ] . _iCharges ;
break ;
case IPL_SPELL :
items [ i ] . _iSpell = static_cast < spell_id > ( param1 ) ;
items [ i ] . _iCharges = param2 ;
items [ i ] . _iMaxCharges = param2 ;
break ;
case IPL_FIREDAM :
items [ i ] . _iFlags | = ISPL_FIREDAM ;
items [ i ] . _iFlags & = ~ ISPL_LIGHTDAM ;
items [ i ] . _iFMinDam = param1 ;
items [ i ] . _iFMaxDam = param2 ;
items [ i ] . _iLMinDam = 0 ;
items [ i ] . _iLMaxDam = 0 ;
break ;
case IPL_LIGHTDAM :
items [ i ] . _iFlags | = ISPL_LIGHTDAM ;
items [ i ] . _iFlags & = ~ ISPL_FIREDAM ;
items [ i ] . _iLMinDam = param1 ;
items [ i ] . _iLMaxDam = param2 ;
items [ i ] . _iFMinDam = 0 ;
items [ i ] . _iFMaxDam = 0 ;
break ;
case IPL_STR :
items [ i ] . _iPLStr + = r ;
break ;
case IPL_STR_CURSE :
items [ i ] . _iPLStr - = r ;
break ;
case IPL_MAG :
items [ i ] . _iPLMag + = r ;
break ;
case IPL_MAG_CURSE :
items [ i ] . _iPLMag - = r ;
break ;
case IPL_DEX :
items [ i ] . _iPLDex + = r ;
break ;
case IPL_DEX_CURSE :
items [ i ] . _iPLDex - = r ;
break ;
case IPL_VIT :
items [ i ] . _iPLVit + = r ;
break ;
case IPL_VIT_CURSE :
items [ i ] . _iPLVit - = r ;
break ;
case IPL_ATTRIBS :
items [ i ] . _iPLStr + = r ;
items [ i ] . _iPLMag + = r ;
items [ i ] . _iPLDex + = r ;
items [ i ] . _iPLVit + = r ;
break ;
case IPL_ATTRIBS_CURSE :
items [ i ] . _iPLStr - = r ;
items [ i ] . _iPLMag - = r ;
items [ i ] . _iPLDex - = r ;
items [ i ] . _iPLVit - = r ;
break ;
case IPL_GETHIT_CURSE :
items [ i ] . _iPLGetHit + = r ;
break ;
case IPL_GETHIT :
items [ i ] . _iPLGetHit - = r ;
break ;
case IPL_LIFE :
items [ i ] . _iPLHP + = r < < 6 ;
break ;
case IPL_LIFE_CURSE :
items [ i ] . _iPLHP - = r < < 6 ;
break ;
case IPL_MANA :
items [ i ] . _iPLMana + = r < < 6 ;
drawmanaflag = true ;
break ;
case IPL_MANA_CURSE :
items [ i ] . _iPLMana - = r < < 6 ;
drawmanaflag = true ;
break ;
case IPL_DUR :
r2 = r * items [ i ] . _iMaxDur / 100 ;
items [ i ] . _iMaxDur + = r2 ;
items [ i ] . _iDurability + = r2 ;
break ;
case IPL_CRYSTALLINE :
items [ i ] . _iPLDam + = 140 + r * 2 ;
[[fallthrough]] ;
case IPL_DUR_CURSE :
items [ i ] . _iMaxDur - = r * items [ i ] . _iMaxDur / 100 ;
items [ i ] . _iMaxDur = std : : max < uint8_t > ( 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 ;
items [ i ] . _iPLFR = std : : max < int16_t > ( 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 ;
default :
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 , affix_item_type flgs , bool onlygood )
{
int l [ 256 ] ;
char istr [ 128 ] ;
goodorevil goe ;
int pre = GenerateRnd ( 4 ) ;
int post = GenerateRnd ( 3 ) ;
if ( pre ! = 0 & & post = = 0 ) {
if ( GenerateRnd ( 2 ) ! = 0 )
post = 1 ;
else
pre = 0 ;
}
int preidx = - 1 ;
int sufidx = - 1 ;
goe = GOE_ANY ;
if ( ! onlygood & & GenerateRnd ( 3 ) ! = 0 )
onlygood = true ;
if ( pre = = 0 ) {
int nt = 0 ;
for ( int j = 0 ; PL_Prefix [ j ] . PLPower ! = IPL_INVALID ; j + + ) {
if ( ! IsPrefixValidForItemType ( j , flgs ) )
continue ;
if ( PL_Prefix [ j ] . PLMinLvl < minlvl | | PL_Prefix [ j ] . PLMinLvl > maxlvl )
continue ;
if ( onlygood & & ! PL_Prefix [ j ] . PLOk )
continue ;
if ( flgs = = PLT_STAFF & & PL_Prefix [ j ] . PLPower = = IPL_CHARGES )
continue ;
l [ nt ] = j ;
nt + + ;
if ( PL_Prefix [ j ] . PLDouble ) {
l [ nt ] = j ;
nt + + ;
}
}
if ( nt ! = 0 ) {
preidx = l [ GenerateRnd ( 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 ) {
int nl = 0 ;
for ( int 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 [ GenerateRnd ( nl ) ] ;
strcpy ( istr , fmt : : format ( _ ( " {:s} of {:s} " ) , items [ i ] . _iIName , _ ( PL_Suffix [ sufidx ] . PLName ) ) . c_str ( ) ) ;
strcpy ( items [ i ] . _iIName , istr ) ;
items [ i ] . _iMagical = ITEM_QUALITY_MAGIC ;
SaveItemSuffix ( i , sufidx ) ;
items [ i ] . _iSufPower = PL_Suffix [ sufidx ] . PLPower ;
}
}
if ( ! control_WriteStringToBuffer ( items [ i ] . _iIName ) ) {
int aii = items [ i ] . IDidx ;
if ( AllItemsList [ aii ] . iSName ! = nullptr )
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 ) {
strcpy ( istr , fmt : : format ( _ ( " {:s} of {:s} " ) , items [ i ] . _iIName , _ ( PL_Suffix [ sufidx ] . PLName ) ) . c_str ( ) ) ;
strcpy ( items [ i ] . _iIName , istr ) ;
}
}
if ( preidx ! = - 1 | | sufidx ! = - 1 )
CalcItemValue ( i ) ;
}
void GetItemBonus ( int i , int minlvl , int maxlvl , bool onlygood , bool 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 ] ? & * itemanims [ it ] : nullptr ;
items [ i ] . _iAnimLen = ItemAnimLs [ it ] ;
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 ) ! = 0 )
return 0 ;
if ( GenerateRnd ( 100 ) > 40 )
return 0 ;
if ( GenerateRnd ( 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 = GenerateRnd ( ri ) ;
return ril [ r ] + 1 ;
}
int RndUItem ( int m )
{
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 ( ) ;
int ri = 0 ;
for ( int 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 [ GenerateRnd ( ri ) ] ;
}
int RndAllItems ( )
{
int ril [ 512 ] ;
if ( GenerateRnd ( 100 ) > 25 )
return 0 ;
int curlv = items_get_currlevel ( ) ;
int ri = 0 ;
for ( int 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 [ GenerateRnd ( ri ) ] ;
}
int RndTypeItems ( int itype , int imid , int lvl )
{
int ril [ 512 ] ;
int ri = 0 ;
for ( int i = 0 ; AllItemsList [ i ] . iLoc ! = ILOC_INVALID ; i + + ) {
if ( ! IsItemAvailable ( i ) )
continue ;
bool okflag = true ;
if ( AllItemsList [ i ] . iRnd = = IDROP_NEVER )
okflag = false ;
if ( lvl * 2 < 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 [ GenerateRnd ( ri ) ] ;
}
_unique_items CheckUnique ( int i , int lvl , int uper , bool recreate )
{
std : : bitset < 128 > uok = { } ;
if ( GenerateRnd ( 100 ) > uper )
return UITEM_INVALID ;
int numu = 0 ;
for ( int 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 | | ! UniqueItemFlags [ j ] | | gbIsMultiplayer ) ) {
uok [ j ] = true ;
numu + + ;
}
}
if ( numu = = 0 )
return UITEM_INVALID ;
GenerateRnd ( 10 ) ; /// BUGFIX: unused, last unique in array always gets chosen
uint8_t idata = 0 ;
while ( numu > 0 ) {
if ( uok [ idata ] )
numu - - ;
if ( numu > 0 )
idata = ( idata + 1 ) % 128 ;
}
return ( _unique_items ) idata ;
}
void GetUniqueItem ( int i , _unique_items uid )
{
UniqueItemFlags [ 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 ( _unique_items 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 = GenerateRnd ( items [ ii ] . _iMaxDur / 2 ) + ( items [ ii ] . _iMaxDur / 4 ) + 1 ;
}
void SetupAllItems ( int ii , int idx , int iseed , int lvl , int uper , bool onlygood , bool recreate , bool pregen )
{
int iblvl ;
items [ ii ] . _iSeed = iseed ;
SetRndSeed ( iseed ) ;
GetItemAttrs ( ii , idx , lvl / 2 ) ;
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 ( GenerateRnd ( 100 ) < = 10 | | GenerateRnd ( 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 ) {
_unique_items uid = CheckUnique ( ii , iblvl , uper , recreate ) ;
if ( uid = = UITEM_INVALID ) {
GetItemBonus ( ii , iblvl / 2 , 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 , ( _unique_items ) iseed ) ; // uid is stored in iseed for uniques
}
}
SetupItem ( ii ) ;
}
void SpawnItem ( int m , Point position , bool sendmsg )
{
int idx ;
bool onlygood = true ;
if ( monster [ m ] . _uniqtype | | ( ( monster [ m ] . MData - > mTreasure & 0x8000 ) & & gbIsMultiplayer ) ) {
idx = RndUItem ( m ) ;
if ( idx < 0 ) {
SpawnUnique ( ( _unique_items ) - ( idx + 1 ) , position . x , position . 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 ( ( _unique_items ) - ( idx + 1 ) , position . x , position . y ) ;
return ;
}
} else {
idx = IDI_BRAIN ;
quests [ Q_MUSHROOM ] . _qvar1 = QS_BRAINSPAWNED ;
}
if ( numitems > = MAXITEMS )
return ;
int ii = AllocateItem ( ) ;
GetSuperItemSpace ( position , ii ) ;
int uper = 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 , uper , onlygood , false , false ) ;
if ( sendmsg )
NetSendCmdDItem ( false , ii ) ;
}
static void SetupBaseItem ( Point position , int idx , bool onlygood , bool sendmsg , bool delta )
{
if ( numitems > = MAXITEMS )
return ;
int ii = AllocateItem ( ) ;
GetSuperItemSpace ( position , 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 ( Point position , bool onlygood , bool sendmsg , bool delta )
{
int idx = onlygood ? RndUItem ( - 1 ) : RndAllItems ( ) ;
SetupBaseItem ( position , idx , onlygood , sendmsg , delta ) ;
}
void SetupAllUseful ( int ii , int iseed , int lvl )
{
int idx ;
items [ ii ] . _iSeed = iseed ;
SetRndSeed ( iseed ) ;
if ( gbIsHellfire ) {
idx = GenerateRnd ( 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 ( GenerateRnd ( 2 ) ! = 0 )
idx = IDI_HEAL ;
else
idx = IDI_MANA ;
if ( lvl > 1 & & GenerateRnd ( 3 ) = = 0 )
idx = IDI_PORTAL ;
}
GetItemAttrs ( ii , idx , lvl ) ;
items [ ii ] . _iCreateInfo = lvl | CF_USEFUL ;
SetupItem ( ii ) ;
}
void CreateRndUseful ( Point position , bool sendmsg )
{
if ( numitems > = MAXITEMS )
return ;
int ii = AllocateItem ( ) ;
GetSuperItemSpace ( position , ii ) ;
int curlv = items_get_currlevel ( ) ;
SetupAllUseful ( ii , AdvanceRndSeed ( ) , curlv ) ;
if ( sendmsg )
NetSendCmdDItem ( false , ii ) ;
}
void CreateTypeItem ( Point position , 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 ( position , idx , onlygood , sendmsg , delta ) ;
}
void RecreateItem ( int ii , int idx , uint16_t 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 ) ! = 0 ) {
RecreateTownItem ( ii , idx , icreateinfo , iseed ) ;
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 ) ! = 0 )
uper = 1 ;
if ( ( icreateinfo & CF_UPER15 ) ! = 0 )
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 , uint16_t 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 ' ;
strcpy ( items [ ii ] . _iName , fmt : : format ( _ ( /* TRANSLATORS: {:s} will be a Character Name */ " Ear of {:s} " ) , tempstr ) . c_str ( ) ) ;
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 ( )
{
if ( ! CornerStone . activated )
return ;
if ( ! CornerStone . item . isEmpty ( ) ) {
PkItemStruct id ;
PackItem ( & id , & CornerStone . item ) ;
BYTE * buffer = ( BYTE * ) & id ;
for ( size_t 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 ( Point position )
{
PkItemStruct PkSItem ;
if ( CornerStone . activated | | position . x = = 0 | | position . y = = 0 ) {
return ;
}
CornerStone . item . _itype = ITYPE_NONE ;
CornerStone . activated = true ;
if ( dItem [ position . x ] [ position . y ] ) {
int ii = dItem [ position . x ] [ position . y ] - 1 ;
for ( int i = 0 ; i < numitems ; i + + ) {
if ( itemactive [ i ] = = ii ) {
DeleteItem ( ii , i ) ;
break ;
}
}
dItem [ position . x ] [ position . y ] = 0 ;
}
if ( strlen ( sgOptions . Hellfire . szItem ) < sizeof ( PkItemStruct ) * 2 )
return ;
hex2bin ( sgOptions . Hellfire . szItem , sizeof ( PkItemStruct ) , ( char * ) & PkSItem ) ;
int ii = AllocateItem ( ) ;
dItem [ position . x ] [ position . y ] = ii + 1 ;
UnPackItem ( & PkSItem , & items [ ii ] , ( PkSItem . dwBuff & CF_HELLFIRE ) ! = 0 ) ;
items [ ii ] . position = position ;
RespawnItem ( & items [ ii ] , false ) ;
CornerStone . item = items [ ii ] ;
}
void SpawnQuestItem ( int itemid , Point position , int randarea , int selflag )
{
if ( randarea ) {
int tries = 0 ;
while ( true ) {
tries + + ;
if ( tries > 1000 & & randarea > 1 )
randarea - - ;
position . x = GenerateRnd ( MAXDUNX ) ;
position . y = GenerateRnd ( MAXDUNY ) ;
bool failed = false ;
for ( int i = 0 ; i < randarea & & ! failed ; i + + ) {
for ( int j = 0 ; j < randarea & & ! failed ; j + + ) {
failed = ! ItemSpaceOk ( i + position . x , j + position . y ) ;
}
}
if ( ! failed )
break ;
}
}
if ( numitems > = MAXITEMS )
return ;
int ii = AllocateItem ( ) ;
items [ ii ] . position = position ;
dItem [ position . x ] [ position . 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 ] . position . x ;
int yy = object [ oi ] . position . y ;
items [ ii ] . position = { xx , yy } ;
dItem [ xx ] [ items [ ii ] . position . y ] = 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 , Point position )
{
if ( numitems > = MAXITEMS )
return ;
int ii = AllocateItem ( ) ;
items [ ii ] . position = position ;
dItem [ position . x ] [ position . y ] = 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 ( Point position )
{
SpawnRewardItem ( IDI_MAPOFDOOM , position ) ;
}
void SpawnRuneBomb ( Point position )
{
SpawnRewardItem ( IDI_RUNEBOMB , position ) ;
}
void SpawnTheodore ( Point position )
{
SpawnRewardItem ( IDI_THEODORE , position ) ;
}
void RespawnItem ( ItemStruct * item , bool FlipFlag )
{
int it ;
it = ItemCAnimTbl [ item - > _iCurs ] ;
item - > _iAnimData = & * itemanims [ it ] ;
item - > _iAnimLen = ItemAnimLs [ it ] ;
item - > _iPostDraw = false ;
item - > _iRequest = false ;
if ( FlipFlag ) {
item - > _iAnimFrame = 1 ;
item - > _iAnimFlag = true ;
item - > _iSelFlag = 0 ;
} else {
item - > _iAnimFrame = item - > _iAnimLen ;
item - > _iAnimFlag = false ;
item - > _iSelFlag = 1 ;
}
if ( item - > _iCurs = = ICURS_MAGIC_ROCK ) {
item - > _iSelFlag = 1 ;
PlaySfxLoc ( ItemDropSnds [ it ] , item - > position . x , item - > position . y ) ;
}
if ( item - > _iCurs = = ICURS_TAVERN_SIGN )
item - > _iSelFlag = 1 ;
if ( item - > _iCurs = = ICURS_ANVIL_OF_FURY )
item - > _iSelFlag = 1 ;
}
void DeleteItem ( int ii , int i )
{
itemavail [ MAXITEMS - numitems ] = ii ;
numitems - - ;
if ( numitems > 0 & & i ! = numitems )
itemactive [ i ] = itemactive [ numitems ] ;
}
void ItemDoppel ( )
{
if ( ! gbIsMultiplayer )
return ;
static int idoppely = 16 ;
for ( int idoppelx = 16 ; idoppelx < 96 ; idoppelx + + ) {
if ( dItem [ idoppelx ] [ idoppely ] ) {
ItemStruct * i = & items [ dItem [ idoppelx ] [ idoppely ] - 1 ] ;
if ( i - > position . x ! = idoppelx | | i - > position . y ! = idoppely )
dItem [ idoppelx ] [ idoppely ] = 0 ;
}
}
idoppely + + ;
if ( idoppely = = 96 )
idoppely = 16 ;
}
void ProcessItems ( )
{
for ( int i = 0 ; i < numitems ; i + + ) {
int ii = itemactive [ i ] ;
if ( ! items [ ii ] . _iAnimFlag )
continue ;
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 / 2 )
PlaySfxLoc ( ItemDropSnds [ ItemCAnimTbl [ items [ ii ] . _iCurs ] ] , items [ ii ] . position . x , items [ ii ] . position . y ) ;
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 ( auto & itemanim : itemanims ) {
itemanim = std : : nullopt ;
}
}
void GetItemFrm ( int i )
{
items [ i ] . _iAnimData = & * itemanims [ ItemCAnimTbl [ items [ i ] . _iCurs ] ] ;
}
void GetItemStr ( int i )
{
if ( items [ i ] . _itype ! = ITYPE_GOLD ) {
if ( items [ i ] . _iIdentified )
strcpy ( infostr , items [ i ] . _iIName ) ;
else
strcpy ( infostr , items [ i ] . _iName ) ;
infoclr = items [ i ] . getTextColor ( true ) ;
} else {
int nGold = items [ i ] . _ivalue ;
strcpy ( infostr , fmt : : format ( ngettext ( " {:d} gold piece " , " {:d} gold pieces " , nGold ) , nGold ) . c_str ( ) ) ;
}
}
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 )
NewCursor ( CURSOR_HAND ) ;
}
static void RepairItem ( ItemStruct * i , int lvl )
{
if ( i - > _iDurability = = i - > _iMaxDur ) {
return ;
}
if ( i - > _iMaxDur < = 0 ) {
i - > _itype = ITYPE_NONE ;
return ;
}
int rep = 0 ;
do {
rep + = lvl + GenerateRnd ( lvl ) ;
i - > _iMaxDur - = std : : max ( i - > _iMaxDur / ( lvl + 9 ) , 1 ) ;
if ( ! i - > _iMaxDur ) {
i - > _itype = ITYPE_NONE ;
return ;
}
} while ( rep + i - > _iDurability < i - > _iMaxDur ) ;
i - > _iDurability = std : : min < int > ( i - > _iDurability + rep , i - > _iMaxDur ) ;
}
void DoRepair ( int pnum , int cii )
{
ItemStruct * pi ;
auto & player = plr [ pnum ] ;
PlaySfxLoc ( IS_REPAIR , player . position . tile . x , player . position . tile . y ) ;
if ( cii > = NUM_INVLOC ) {
pi = & player . InvList [ cii - NUM_INVLOC ] ;
} else {
pi = & player . InvBody [ cii ] ;
}
RepairItem ( pi , player . _pLevel ) ;
CalcPlrInv ( pnum , true ) ;
if ( pnum = = myplr )
NewCursor ( CURSOR_HAND ) ;
}
static void RechargeItem ( ItemStruct * i , int r )
{
if ( i - > _iCharges = = i - > _iMaxCharges )
return ;
do {
i - > _iMaxCharges - - ;
if ( i - > _iMaxCharges = = 0 ) {
return ;
}
i - > _iCharges + = r ;
} while ( i - > _iCharges < i - > _iMaxCharges ) ;
i - > _iCharges = std : : min ( i - > _iCharges , i - > _iMaxCharges ) ;
}
void DoRecharge ( int pnum , int cii )
{
ItemStruct * pi ;
auto & player = plr [ pnum ] ;
if ( cii > = NUM_INVLOC ) {
pi = & player . InvList [ cii - NUM_INVLOC ] ;
} else {
pi = & player . InvBody [ cii ] ;
}
if ( pi - > _itype = = ITYPE_STAFF & & pi - > _iSpell ! = SPL_NULL ) {
int r = GetSpellBookLevel ( pi - > _iSpell ) ;
r = GenerateRnd ( player . _pLevel / r ) + 1 ;
RechargeItem ( pi , r ) ;
CalcPlrInv ( pnum , true ) ;
}
if ( pnum = = myplr )
NewCursor ( CURSOR_HAND ) ;
}
static bool OilItem ( ItemStruct * x , PlayerStruct & player )
{
int r ;
if ( x - > _iClass = = ICLASS_MISC ) {
return false ;
}
if ( x - > _iClass = = ICLASS_GOLD ) {
return false ;
}
if ( x - > _iClass = = ICLASS_QUEST ) {
return false ;
}
switch ( player . _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 ( player . _pOilType ) {
case IMISC_OILACC :
if ( x - > _iPLToHit < 50 ) {
x - > _iPLToHit + = GenerateRnd ( 2 ) + 1 ;
}
break ;
case IMISC_OILMAST :
if ( x - > _iPLToHit < 100 ) {
x - > _iPLToHit + = GenerateRnd ( 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 = GenerateRnd ( 6 ) + 5 ;
x - > _iMinStr = std : : max ( 0 , x - > _iMinStr - r ) ;
x - > _iMinMag = std : : max ( 0 , x - > _iMinMag - r ) ;
x - > _iMinDex = std : : max ( 0 , x - > _iMinDex - r ) ;
break ;
case IMISC_OILBSMTH :
if ( x - > _iMaxDur = = 255 )
return true ;
if ( x - > _iDurability < x - > _iMaxDur ) {
x - > _iDurability = ( x - > _iMaxDur + 4 ) / 5 + x - > _iDurability ;
x - > _iDurability = std : : min < int > ( x - > _iDurability , x - > _iMaxDur ) ;
} else {
if ( x - > _iMaxDur > = 100 ) {
return true ;
}
x - > _iMaxDur + + ;
x - > _iDurability = x - > _iMaxDur ;
}
break ;
case IMISC_OILFORT :
if ( x - > _iMaxDur ! = 255 & & x - > _iMaxDur < 200 ) {
r = GenerateRnd ( 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 + = GenerateRnd ( 2 ) + 1 ;
}
break ;
case IMISC_OILIMP :
if ( x - > _iAC < 120 ) {
x - > _iAC + = GenerateRnd ( 3 ) + 3 ;
}
break ;
default :
return false ;
}
return true ;
}
void DoOil ( int pnum , int cii )
{
if ( cii < NUM_INVLOC & & cii ! = INVLOC_HEAD & & ( cii < = INVLOC_AMULET | | cii > INVLOC_CHEST ) )
return ;
auto & player = plr [ pnum ] ;
if ( ! OilItem ( & player . InvBody [ cii ] , player ) )
return ;
CalcPlrInv ( pnum , true ) ;
if ( pnum = = myplr ) {
NewCursor ( CURSOR_HAND ) ;
}
}
void PrintItemOil ( char IDidx )
{
switch ( IDidx ) {
case IMISC_OILACC :
strcpy ( tempstr , _ ( " increases a weapon's " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " chance to hit " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILMAST :
strcpy ( tempstr , _ ( " greatly increases a " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " weapon's chance to hit " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILSHARP :
strcpy ( tempstr , _ ( " increases a weapon's " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " damage potential " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILDEATH :
strcpy ( tempstr , _ ( " greatly increases a weapon's " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " damage potential - not bows " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILSKILL :
strcpy ( tempstr , _ ( " reduces attributes needed " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " to use armor or weapons " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILBSMTH :
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " restores 20% of an " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " item's durability " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILFORT :
strcpy ( tempstr , _ ( " increases an item's " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " current and max durability " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILPERM :
strcpy ( tempstr , _ ( " makes an item indestructible " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILHARD :
strcpy ( tempstr , _ ( " increases the armor class " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " of armor and shields " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OILIMP :
strcpy ( tempstr , _ ( " greatly increases the armor " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " class of armor and shields " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_RUNEF :
strcpy ( tempstr , _ ( " sets fire trap " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_RUNEL :
strcpy ( tempstr , _ ( " sets lightning trap " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_GR_RUNEL :
strcpy ( tempstr , _ ( " sets lightning trap " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_GR_RUNEF :
strcpy ( tempstr , _ ( " sets fire trap " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_RUNES :
strcpy ( tempstr , _ ( " sets petrification trap " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_FULLHEAL :
strcpy ( tempstr , _ ( " fully recover life " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_HEAL :
strcpy ( tempstr , _ ( " recover partial life " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_OLDHEAL :
strcpy ( tempstr , _ ( " recover life " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_DEADHEAL :
strcpy ( tempstr , _ ( " deadly heal " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_MANA :
strcpy ( tempstr , _ ( " recover mana " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_FULLMANA :
strcpy ( tempstr , _ ( " fully recover mana " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXSTR :
strcpy ( tempstr , _ ( " increase strength " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXMAG :
strcpy ( tempstr , _ ( " increase magic " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXDEX :
strcpy ( tempstr , _ ( " increase dexterity " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXVIT :
strcpy ( tempstr , _ ( " increase vitality " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXWEAK :
strcpy ( tempstr , _ ( " decrease strength " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXDIS :
strcpy ( tempstr , _ ( " decrease strength " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXCLUM :
strcpy ( tempstr , _ ( " decrease dexterity " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_ELIXSICK :
strcpy ( tempstr , _ ( " decrease vitality " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_REJUV :
strcpy ( tempstr , _ ( " recover life and mana " ) ) ;
AddPanelString ( tempstr ) ;
break ;
case IMISC_FULLREJUV :
strcpy ( tempstr , _ ( " fully recover life and mana " ) ) ;
AddPanelString ( tempstr ) ;
break ;
}
}
void PrintItemPower ( char plidx , ItemStruct * x )
{
switch ( plidx ) {
case IPL_TOHIT :
case IPL_TOHIT_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " chance to hit: {:+d}% " ) , x - > _iPLToHit ) . c_str ( ) ) ;
break ;
case IPL_DAMP :
case IPL_DAMP_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d}% damage " ) , x - > _iPLDam ) . c_str ( ) ) ;
break ;
case IPL_TOHIT_DAMP :
case IPL_TOHIT_DAMP_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " to hit: {:+d}%, {:+d}% damage " ) , x - > _iPLToHit , x - > _iPLDam ) . c_str ( ) ) ;
break ;
case IPL_ACP :
case IPL_ACP_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d}% armor " ) , x - > _iPLAC ) . c_str ( ) ) ;
break ;
case IPL_SETAC :
strcpy ( tempstr , fmt : : format ( _ ( " armor class: {:d} " ) , x - > _iAC ) . c_str ( ) ) ;
break ;
case IPL_AC_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " armor class: {:d} " ) , x - > _iAC ) . c_str ( ) ) ;
break ;
case IPL_FIRERES :
case IPL_FIRERES_CURSE :
if ( x - > _iPLFR < 75 )
strcpy ( tempstr , fmt : : format ( _ ( " Resist Fire: {:+d}% " ) , x - > _iPLFR ) . c_str ( ) ) ;
else
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " Resist Fire: 75% MAX " ) ) ;
break ;
case IPL_LIGHTRES :
case IPL_LIGHTRES_CURSE :
if ( x - > _iPLLR < 75 )
strcpy ( tempstr , fmt : : format ( _ ( " Resist Lightning: {:+d}% " ) , x - > _iPLLR ) . c_str ( ) ) ;
else
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " Resist Lightning: 75% MAX " ) ) ;
break ;
case IPL_MAGICRES :
case IPL_MAGICRES_CURSE :
if ( x - > _iPLMR < 75 )
strcpy ( tempstr , fmt : : format ( _ ( " Resist Magic: {:+d}% " ) , x - > _iPLMR ) . c_str ( ) ) ;
else
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " Resist Magic: 75% MAX " ) ) ;
break ;
case IPL_ALLRES :
case IPL_ALLRES_CURSE :
if ( x - > _iPLFR < 75 )
strcpy ( tempstr , fmt : : format ( _ ( " Resist All: {:+d}% " ) , x - > _iPLFR ) . c_str ( ) ) ;
if ( x - > _iPLFR > = 75 )
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " Resist All: 75% MAX " ) ) ;
break ;
case IPL_SPLLVLADD :
if ( x - > _iSplLvlAdd > 0 )
strcpy ( tempstr , fmt : : format ( ngettext ( " spells are increased {:d} level " , " spells are increased {:d} levels " , x - > _iSplLvlAdd ) , x - > _iSplLvlAdd ) . c_str ( ) ) ;
else if ( x - > _iSplLvlAdd < 0 )
strcpy ( tempstr , fmt : : format ( ngettext ( " spells are decreased {:d} level " , " spells are decreased {:d} levels " , - x - > _iSplLvlAdd ) , - x - > _iSplLvlAdd ) . c_str ( ) ) ;
else if ( x - > _iSplLvlAdd = = 0 )
strcpy ( tempstr , _ ( " spell levels unchanged (?) " ) ) ;
break ;
case IPL_CHARGES :
strcpy ( tempstr , _ ( " Extra charges " ) ) ;
break ;
case IPL_SPELL :
strcpy ( tempstr , fmt : : format ( ngettext ( " {:d} {:s} charge " , " {:d} {:s} charges " , x - > _iMaxCharges ) , x - > _iMaxCharges , _ ( spelldata [ x - > _iSpell ] . sNameText ) ) . c_str ( ) ) ;
break ;
case IPL_FIREDAM :
if ( x - > _iFMinDam = = x - > _iFMaxDam )
strcpy ( tempstr , fmt : : format ( _ ( " Fire hit damage: {:d} " ) , x - > _iFMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " Fire hit damage: {:d}-{:d} " ) , x - > _iFMinDam , x - > _iFMaxDam ) . c_str ( ) ) ;
break ;
case IPL_LIGHTDAM :
if ( x - > _iLMinDam = = x - > _iLMaxDam )
strcpy ( tempstr , fmt : : format ( _ ( " Lightning hit damage: {:d} " ) , x - > _iLMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " Lightning hit damage: {:d}-{:d} " ) , x - > _iLMinDam , x - > _iLMaxDam ) . c_str ( ) ) ;
break ;
case IPL_STR :
case IPL_STR_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d} to strength " ) , x - > _iPLStr ) . c_str ( ) ) ;
break ;
case IPL_MAG :
case IPL_MAG_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d} to magic " ) , x - > _iPLMag ) . c_str ( ) ) ;
break ;
case IPL_DEX :
case IPL_DEX_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d} to dexterity " ) , x - > _iPLDex ) . c_str ( ) ) ;
break ;
case IPL_VIT :
case IPL_VIT_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d} to vitality " ) , x - > _iPLVit ) . c_str ( ) ) ;
break ;
case IPL_ATTRIBS :
case IPL_ATTRIBS_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d} to all attributes " ) , x - > _iPLStr ) . c_str ( ) ) ;
break ;
case IPL_GETHIT_CURSE :
case IPL_GETHIT :
strcpy ( tempstr , fmt : : format ( _ ( " {:+d} damage from enemies " ) , x - > _iPLGetHit ) . c_str ( ) ) ;
break ;
case IPL_LIFE :
case IPL_LIFE_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " Hit Points: {:+d} " ) , x - > _iPLHP > > 6 ) . c_str ( ) ) ;
break ;
case IPL_MANA :
case IPL_MANA_CURSE :
strcpy ( tempstr , fmt : : format ( _ ( " Mana: {:+d} " ) , x - > _iPLMana > > 6 ) . c_str ( ) ) ;
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 :
/*xgettext:no-c-format*/ strcpy ( tempstr , fmt : : format ( _ ( " +{:d}% light radius " ) , 10 * x - > _iPLLight ) . c_str ( ) ) ;
break ;
case IPL_LIGHT_CURSE :
/*xgettext:no-c-format*/ strcpy ( tempstr , fmt : : format ( _ ( " -{:d}% light radius " ) , - 10 * x - > _iPLLight ) . c_str ( ) ) ;
break ;
case IPL_MULT_ARROWS :
strcpy ( tempstr , _ ( " multiple arrows per shot " ) ) ;
break ;
case IPL_FIRE_ARROWS :
if ( x - > _iFMinDam = = x - > _iFMaxDam )
strcpy ( tempstr , fmt : : format ( _ ( " fire arrows damage: {:d} " ) , x - > _iFMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " fire arrows damage: {:d}-{:d} " ) , x - > _iFMinDam , x - > _iFMaxDam ) . c_str ( ) ) ;
break ;
case IPL_LIGHT_ARROWS :
if ( x - > _iLMinDam = = x - > _iLMaxDam )
strcpy ( tempstr , fmt : : format ( _ ( " lightning arrows damage {:d} " ) , x - > _iLMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " lightning arrows damage {:d}-{:d} " ) , x - > _iLMinDam , x - > _iLMaxDam ) . c_str ( ) ) ;
break ;
case IPL_FIREBALL :
if ( x - > _iFMinDam = = x - > _iFMaxDam )
strcpy ( tempstr , fmt : : format ( _ ( " fireball damage: {:d} " ) , x - > _iFMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " fireball damage: {:d}-{:d} " ) , x - > _iFMinDam , x - > _iFMaxDam ) . c_str ( ) ) ;
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 :
/*xgettext:no-c-format*/ 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 ) ! = 0 )
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " hit steals 3% mana " ) ) ;
if ( ( x - > _iFlags & ISPL_STEALMANA_5 ) ! = 0 )
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " hit steals 5% mana " ) ) ;
break ;
case IPL_STEALLIFE :
if ( ( x - > _iFlags & ISPL_STEALLIFE_3 ) ! = 0 )
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " hit steals 3% life " ) ) ;
if ( ( x - > _iFlags & ISPL_STEALLIFE_5 ) ! = 0 )
/*xgettext:no-c-format*/ 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 ) ! = 0 )
strcpy ( tempstr , _ ( " quick attack " ) ) ;
if ( ( x - > _iFlags & ISPL_FASTATTACK ) ! = 0 )
strcpy ( tempstr , _ ( " fast attack " ) ) ;
if ( ( x - > _iFlags & ISPL_FASTERATTACK ) ! = 0 )
strcpy ( tempstr , _ ( " faster attack " ) ) ;
if ( ( x - > _iFlags & ISPL_FASTESTATTACK ) ! = 0 )
strcpy ( tempstr , _ ( " fastest attack " ) ) ;
break ;
case IPL_FASTRECOVER :
if ( ( x - > _iFlags & ISPL_FASTRECOVER ) ! = 0 )
strcpy ( tempstr , _ ( " fast hit recovery " ) ) ;
if ( ( x - > _iFlags & ISPL_FASTERRECOVER ) ! = 0 )
strcpy ( tempstr , _ ( " faster hit recovery " ) ) ;
if ( ( x - > _iFlags & ISPL_FASTESTRECOVER ) ! = 0 )
strcpy ( tempstr , _ ( " fastest hit recovery " ) ) ;
break ;
case IPL_FASTBLOCK :
strcpy ( tempstr , _ ( " fast block " ) ) ;
break ;
case IPL_DAMMOD :
strcpy ( tempstr , fmt : : format ( ngettext ( " adds {:d} point to damage " , " adds {:d} points to damage " , x - > _iPLDamMod ) , x - > _iPLDamMod ) . c_str ( ) ) ;
break ;
case IPL_RNDARROWVEL :
strcpy ( tempstr , _ ( " fires random speed arrows " ) ) ;
break ;
case IPL_SETDAM :
strcpy ( 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 )
strcpy ( tempstr , fmt : : format ( _ ( " lightning damage: {:d} " ) , x - > _iFMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " lightning damage: {:d}-{:d} " ) , x - > _iFMinDam , x - > _iFMaxDam ) . c_str ( ) ) ;
break ;
case IPL_ADDMANAAC :
strcpy ( tempstr , _ ( " charged bolts on hits " ) ) ;
break ;
case IPL_FIRERESCLVL :
if ( x - > _iPLFR < = 0 )
strcpy ( tempstr , " " ) ;
else if ( x - > _iPLFR > = 1 )
strcpy ( tempstr , fmt : : format ( _ ( " Resist Fire: {:+d}% " ) , x - > _iPLFR ) . c_str ( ) ) ;
break ;
case IPL_DEVASTATION :
strcpy ( tempstr , _ ( " occasional triple damage " ) ) ;
break ;
case IPL_DECAY :
strcpy ( tempstr , fmt : : format ( _ ( " decaying {:+d}% damage " ) , x - > _iPLDam ) . c_str ( ) ) ;
break ;
case IPL_PERIL :
strcpy ( tempstr , _ ( " 2x dmg to monst, 1x to you " ) ) ;
break ;
case IPL_JESTERS :
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " Random 0 - 500% damage " ) ) ;
break ;
case IPL_CRYSTALLINE :
strcpy ( tempstr , fmt : : format ( _ ( " low dur, {:+d}% damage " ) , x - > _iPLDam ) . c_str ( ) ) ;
break ;
case IPL_DOPPELGANGER :
strcpy ( tempstr , fmt : : format ( _ ( " to hit: {:+d}%, {:+d}% damage " ) , x - > _iPLToHit , x - > _iPLDam ) . c_str ( ) ) ;
break ;
case IPL_ACDEMON :
strcpy ( tempstr , _ ( " extra AC vs demons " ) ) ;
break ;
case IPL_ACUNDEAD :
strcpy ( tempstr , _ ( " extra AC vs undead " ) ) ;
break ;
case IPL_MANATOLIFE :
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " 50% Mana moved to Health " ) ) ;
break ;
case IPL_LIFETOMANA :
/*xgettext:no-c-format*/ strcpy ( tempstr , _ ( " 40% Health moved to Mana " ) ) ;
break ;
default :
strcpy ( tempstr , _ ( " Another ability (NW) " ) ) ;
break ;
}
}
static void DrawUTextBack ( const CelOutputBuffer & out )
{
CelDrawTo ( out , RIGHT_PANEL_X - SPANEL_WIDTH + 24 , 327 , * pSTextBoxCels , 1 ) ;
DrawHalfTransparentRectTo ( out , RIGHT_PANEL_X - SPANEL_WIDTH + 27 , 28 , 265 , 297 ) ;
}
static void DrawULine ( const 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 ( const CelOutputBuffer & out )
{
if ( ( chrflag | | questlog ) & & gnScreenWidth < SPANEL_WIDTH * 3 ) {
return ;
}
DrawUTextBack ( GlobalBackBuffer ( ) ) ;
SDL_Rect rect { 32 + RIGHT_PANEL - SPANEL_WIDTH , 44 + 2 * 12 , 257 , 0 } ;
const UItemStruct & uitem = UniqueItemList [ curruitem . _iUid ] ;
DrawString ( out , _ ( uitem . UIName ) , rect , UIS_CENTER ) ;
DrawULine ( out , 5 ) ;
rect . y + = ( 12 - uitem . UINumPL ) * 12 ;
PrintItemPower ( uitem . UIPower1 , & curruitem ) ;
DrawString ( out , tempstr , rect , UIS_SILVER | UIS_CENTER ) ;
if ( uitem . UINumPL > 1 ) {
rect . y + = 2 * 12 ;
PrintItemPower ( uitem . UIPower2 , & curruitem ) ;
DrawString ( out , tempstr , rect , UIS_SILVER | UIS_CENTER ) ;
}
if ( uitem . UINumPL > 2 ) {
rect . y + = 2 * 12 ;
PrintItemPower ( uitem . UIPower3 , & curruitem ) ;
DrawString ( out , tempstr , rect , UIS_SILVER | UIS_CENTER ) ;
}
if ( uitem . UINumPL > 3 ) {
rect . y + = 2 * 12 ;
PrintItemPower ( uitem . UIPower4 , & curruitem ) ;
DrawString ( out , tempstr , rect , UIS_SILVER | UIS_CENTER ) ;
}
if ( uitem . UINumPL > 4 ) {
rect . y + = 2 * 12 ;
PrintItemPower ( uitem . UIPower5 , & curruitem ) ;
DrawString ( out , tempstr , rect , UIS_SILVER | UIS_CENTER ) ;
}
if ( uitem . UINumPL > 5 ) {
rect . y + = 2 * 12 ;
PrintItemPower ( uitem . UIPower6 , & curruitem ) ;
DrawString ( out , tempstr , rect , UIS_SILVER | UIS_CENTER ) ;
}
}
void PrintItemMisc ( ItemStruct * x )
{
if ( x - > _iMiscId = = IMISC_SCROLL ) {
strcpy ( tempstr , _ ( " Right-click to read " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_SCROLLT ) {
strcpy ( tempstr , _ ( " Right-click to read, then " ) ) ;
AddPanelString ( tempstr ) ;
strcpy ( tempstr , _ ( " left-click to target " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId > = IMISC_USEFIRST & & x - > _iMiscId < = IMISC_USELAST ) {
PrintItemOil ( x - > _iMiscId ) ;
strcpy ( tempstr , _ ( " Right-click to use " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId > IMISC_OILFIRST & & x - > _iMiscId < IMISC_OILLAST ) {
PrintItemOil ( x - > _iMiscId ) ;
strcpy ( tempstr , _ ( " Right click to use " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId > IMISC_RUNEFIRST & & x - > _iMiscId < IMISC_RUNELAST ) {
PrintItemOil ( x - > _iMiscId ) ;
strcpy ( tempstr , _ ( " Right click to use " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_BOOK ) {
strcpy ( tempstr , _ ( " Right-click to read " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_NOTE ) {
strcpy ( tempstr , _ ( " Right click to read " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_MAPOFDOOM ) {
strcpy ( tempstr , _ ( " Right-click to view " ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_EAR ) {
strcpy ( tempstr , fmt : : format ( _ ( " Level: {:d} " ) , x - > _ivalue ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_AURIC ) {
strcpy ( tempstr , _ ( " Doubles gold capacity " ) ) ;
AddPanelString ( tempstr ) ;
}
}
static void PrintItemInfo ( ItemStruct * x )
{
PrintItemMisc ( x ) ;
uint8_t str = x - > _iMinStr ;
uint8_t dex = x - > _iMinDex ;
uint8_t mag = x - > _iMinMag ;
if ( str ! = 0 | | mag ! = 0 | | dex ! = 0 ) {
strcpy ( tempstr , _ ( " Required: " ) ) ;
if ( str )
strcpy ( tempstr + strlen ( tempstr ) , fmt : : format ( _ ( " {:d} Str " ) , str ) . c_str ( ) ) ;
if ( mag )
strcpy ( tempstr + strlen ( tempstr ) , fmt : : format ( _ ( " {:d} Mag " ) , mag ) . c_str ( ) ) ;
if ( dex )
strcpy ( tempstr + strlen ( tempstr ) , fmt : : format ( _ ( " {:d} Dex " ) , dex ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
}
pinfoflag = true ;
}
void PrintItemDetails ( ItemStruct * x )
{
if ( x - > _iClass = = ICLASS_WEAPON ) {
if ( x - > _iMinDam = = x - > _iMaxDam ) {
if ( x - > _iMaxDur = = DUR_INDESTRUCTIBLE )
strcpy ( tempstr , fmt : : format ( _ ( " damage: {:d} Indestructible " ) , x - > _iMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( /* TRANSLATORS: Dur: is durability */ " damage: {:d} Dur: {:d}/{:d} " ) , x - > _iMinDam , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
} else {
if ( x - > _iMaxDur = = DUR_INDESTRUCTIBLE )
strcpy ( tempstr , fmt : : format ( _ ( " damage: {:d}-{:d} Indestructible " ) , x - > _iMinDam , x - > _iMaxDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( /* TRANSLATORS: Dur: is durability */ " damage: {:d}-{:d} Dur: {:d}/{:d} " ) , x - > _iMinDam , x - > _iMaxDam , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
}
AddPanelString ( tempstr ) ;
}
if ( x - > _iClass = = ICLASS_ARMOR ) {
if ( x - > _iMaxDur = = DUR_INDESTRUCTIBLE )
strcpy ( tempstr , fmt : : format ( _ ( " armor: {:d} Indestructible " ) , x - > _iAC ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( /* TRANSLATORS: Dur: is durability */ " armor: {:d} Dur: {:d}/{:d} " ) , x - > _iAC , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMiscId = = IMISC_STAFF & & x - > _iMaxCharges ! = 0 ) {
if ( x - > _iMinDam = = x - > _iMaxDam )
strcpy ( tempstr , fmt : : format ( _ ( /* TRANSLATORS: dam: is damage Dur: is durability */ " dam: {:d} Dur: {:d}/{:d} " ) , x - > _iMinDam , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( /* TRANSLATORS: dam: is damage Dur: is durability */ " dam: {:d}-{:d} Dur: {:d}/{:d} " ) , x - > _iMinDam , x - > _iMaxDam , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
strcpy ( tempstr , fmt : : format ( _ ( " Charges: {:d}/{:d} " ) , x - > _iCharges , x - > _iMaxCharges ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iPrePower ! = - 1 ) {
PrintItemPower ( x - > _iPrePower , x ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iSufPower ! = - 1 ) {
PrintItemPower ( x - > _iSufPower , x ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMagical = = ITEM_QUALITY_UNIQUE ) {
AddPanelString ( _ ( " unique item " ) ) ;
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 )
strcpy ( tempstr , fmt : : format ( _ ( " damage: {:d} Indestructible " ) , x - > _iMinDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " damage: {:d} Dur: {:d}/{:d} " ) , x - > _iMinDam , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
} else {
if ( x - > _iMaxDur = = DUR_INDESTRUCTIBLE )
strcpy ( tempstr , fmt : : format ( _ ( " damage: {:d}-{:d} Indestructible " ) , x - > _iMinDam , x - > _iMaxDam ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " damage: {:d}-{:d} Dur: {:d}/{:d} " ) , x - > _iMinDam , x - > _iMaxDam , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
}
AddPanelString ( tempstr ) ;
if ( x - > _iMiscId = = IMISC_STAFF & & x - > _iMaxCharges ) {
strcpy ( tempstr , fmt : : format ( _ ( " Charges: {:d}/{:d} " ) , x - > _iCharges , x - > _iMaxCharges ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
}
if ( x - > _iMagical ! = ITEM_QUALITY_NORMAL )
AddPanelString ( _ ( " Not Identified " ) ) ;
}
if ( x - > _iClass = = ICLASS_ARMOR ) {
if ( x - > _iMaxDur = = DUR_INDESTRUCTIBLE )
strcpy ( tempstr , fmt : : format ( _ ( " armor: {:d} Indestructible " ) , x - > _iAC ) . c_str ( ) ) ;
else
strcpy ( tempstr , fmt : : format ( _ ( " armor: {:d} Dur: {:d}/{:d} " ) , x - > _iAC , x - > _iDurability , x - > _iMaxDur ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
if ( x - > _iMagical ! = ITEM_QUALITY_NORMAL )
AddPanelString ( _ ( " Not Identified " ) ) ;
if ( x - > _iMiscId = = IMISC_STAFF & & x - > _iMaxCharges ) {
strcpy ( tempstr , fmt : : format ( _ ( " Charges: {:d}/{:d} " ) , x - > _iCharges , x - > _iMaxCharges ) . c_str ( ) ) ;
AddPanelString ( tempstr ) ;
}
}
if ( x - > _itype = = ITYPE_RING | | x - > _itype = = ITYPE_AMULET )
AddPanelString ( _ ( " Not Identified " ) ) ;
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 ) + GenerateRnd ( j ) ) < < 6 ;
if ( plr [ p ] . _pClass = = HeroClass : : Warrior | | plr [ p ] . _pClass = = HeroClass : : Barbarian )
l * = 2 ;
if ( plr [ p ] . _pClass = = HeroClass : : Rogue | | plr [ p ] . _pClass = = HeroClass : : Monk | | plr [ p ] . _pClass = = HeroClass : : Bard )
l + = l / 2 ;
plr [ p ] . _pHitPoints = std : : min ( l + plr [ p ] . _pHitPoints , plr [ p ] . _pMaxHP ) ;
plr [ p ] . _pHPBase = std : : min ( l + 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 ) + GenerateRnd ( j ) ) < < 6 ;
if ( plr [ p ] . _pClass = = HeroClass : : Sorcerer )
l * = 2 ;
if ( plr [ p ] . _pClass = = HeroClass : : Rogue | | plr [ p ] . _pClass = = HeroClass : : Monk | | plr [ p ] . _pClass = = HeroClass : : Bard )
l + = l / 2 ;
if ( ( plr [ p ] . _pIFlags & ISPL_NOMANA ) = = 0 ) {
plr [ p ] . _pMana = std : : min ( l + plr [ p ] . _pMana , plr [ p ] . _pMaxMana ) ;
plr [ p ] . _pManaBase = std : : min ( l + plr [ p ] . _pManaBase , plr [ p ] . _pMaxManaBase ) ;
drawmanaflag = true ;
}
break ;
case IMISC_FULLMANA :
if ( ( plr [ p ] . _pIFlags & ISPL_NOMANA ) = = 0 ) {
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 / 2 ) + GenerateRnd ( j ) ) < < 6 ;
if ( plr [ p ] . _pClass = = HeroClass : : Warrior | | plr [ p ] . _pClass = = HeroClass : : Barbarian )
l * = 2 ;
if ( plr [ p ] . _pClass = = HeroClass : : Rogue )
l + = l / 2 ;
plr [ p ] . _pHitPoints = std : : min ( plr [ p ] . _pHitPoints + l , plr [ p ] . _pMaxHP ) ;
plr [ p ] . _pHPBase = std : : min ( plr [ p ] . _pHPBase + l , plr [ p ] . _pMaxHPBase ) ;
drawhpflag = true ;
j = plr [ p ] . _pMaxMana > > 8 ;
l = ( ( j / 2 ) + GenerateRnd ( j ) ) < < 6 ;
if ( plr [ p ] . _pClass = = HeroClass : : Sorcerer )
l * = 2 ;
if ( plr [ p ] . _pClass = = HeroClass : : Rogue )
l + = l / 2 ;
if ( ( plr [ p ] . _pIFlags & ISPL_NOMANA ) = = 0 ) {
plr [ p ] . _pMana = std : : min ( plr [ p ] . _pMana + l , plr [ p ] . _pMaxMana ) ;
plr [ p ] . _pManaBase = std : : min ( plr [ p ] . _pManaBase + l , 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 ) = = 0 ) {
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 ( plr [ 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 ( myplr , 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 ( plr [ 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 ) = = 0 ) {
plr [ p ] . _pMana + = spelldata [ spl ] . sManaCost < < 6 ;
plr [ p ] . _pMana = std : : min ( plr [ p ] . _pMana , plr [ p ] . _pMaxMana ) ;
plr [ p ] . _pManaBase + = spelldata [ spl ] . sManaCost < < 6 ;
plr [ p ] . _pManaBase = std : : min ( plr [ p ] . _pManaBase , plr [ p ] . _pMaxManaBase ) ;
}
if ( p = = myplr )
CalcPlrBookVals ( plr [ 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 )
{
if ( plr [ myplr ] . _pStrength < h - > _iMinStr )
return false ;
if ( plr [ myplr ] . _pMagic < h - > _iMinMag )
return false ;
if ( plr [ myplr ] . _pDexterity < h - > _iMinDex )
return false ;
return true ;
}
bool SmithItemOk ( int i )
{
if ( AllItemsList [ i ] . itype = = ITYPE_MISC )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_GOLD )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_STAFF & & ( ! gbIsHellfire | | AllItemsList [ i ] . iSpell ) )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_RING )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_AMULET )
return false ;
return true ;
}
template < bool ( * Ok ) ( int ) , bool ConsiderDropRate = false >
int RndVendorItem ( int minlvl , int maxlvl )
{
int ril [ 512 ] ;
int ri = 0 ;
for ( int i = 1 ; AllItemsList [ i ] . iLoc ! = ILOC_INVALID ; i + + ) {
if ( ! IsItemAvailable ( i ) )
continue ;
if ( AllItemsList [ i ] . iRnd = = IDROP_NEVER )
continue ;
if ( ! Ok ( i ) )
continue ;
if ( AllItemsList [ i ] . iMinMLvl < minlvl | | AllItemsList [ i ] . iMinMLvl > maxlvl )
continue ;
ril [ ri ] = i ;
ri + + ;
if ( ri = = 512 )
break ;
if ( ! ConsiderDropRate | | AllItemsList [ i ] . iRnd ! = IDROP_DOUBLE )
continue ;
ril [ ri ] = i ;
ri + + ;
if ( ri = = 512 )
break ;
}
return ril [ GenerateRnd ( ri ) ] + 1 ;
}
int RndSmithItem ( int lvl )
{
return RndVendorItem < SmithItemOk , true > ( 0 , lvl ) ;
}
void SortVendor ( ItemStruct * items )
{
int count = 1 ;
while ( ! items [ count ] . isEmpty ( ) )
count + + ;
auto cmp = [ ] ( const ItemStruct & a , const ItemStruct & b ) {
return a . IDidx < b . IDidx ;
} ;
std : : sort ( items , items + count , cmp ) ;
}
void SpawnSmith ( int lvl )
{
constexpr int PinnedItemCount = 0 ;
int maxValue , maxItems ;
ItemStruct holditem ;
holditem = items [ 0 ] ;
if ( gbIsHellfire ) {
maxValue = 200000 ;
maxItems = 25 ;
} else {
maxValue = 140000 ;
maxItems = 20 ;
}
int iCnt = GenerateRnd ( maxItems - 10 ) + 10 ;
for ( int i = 0 ; i < iCnt ; i + + ) {
do {
memset ( & items [ 0 ] , 0 , sizeof ( * items ) ) ;
items [ 0 ] . _iSeed = AdvanceRndSeed ( ) ;
SetRndSeed ( items [ 0 ] . _iSeed ) ;
int 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 ( int i = iCnt ; i < SMITH_ITEMS ; i + + )
smithitem [ i ] . _itype = ITYPE_NONE ;
SortVendor ( smithitem + PinnedItemCount ) ;
items [ 0 ] = holditem ;
}
bool PremiumItemOk ( int i )
{
if ( AllItemsList [ i ] . itype = = ITYPE_MISC )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_GOLD )
return false ;
if ( ! gbIsHellfire & & AllItemsList [ i ] . itype = = ITYPE_STAFF )
return false ;
if ( gbIsMultiplayer ) {
if ( AllItemsList [ i ] . iMiscId = = IMISC_OILOF )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_RING )
return false ;
if ( AllItemsList [ i ] . itype = = ITYPE_AMULET )
return false ;
}
return true ;
}
int RndPremiumItem ( int minlvl , int maxlvl )
{
return RndVendorItem < PremiumItemOk > ( minlvl , maxlvl ) ;
}
static void SpawnOnePremium ( int i , int plvl , int myplr )
{
int ivalue = 0 ;
bool keepgoing = false ;
ItemStruct holditem = items [ 0 ] ;
int strength = std : : max ( plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Strength ) , plr [ myplr ] . _pStrength ) ;
int dexterity = std : : max ( plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Dexterity ) , plr [ myplr ] . _pDexterity ) ;
int magic = std : : max ( plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Magic ) , plr [ myplr ] . _pMagic ) ;
strength * = 1.2 ;
dexterity * = 1.2 ;
magic * = 1.2 ;
plvl = clamp ( plvl , 1 , 30 ) ;
int count = 0 ;
do {
keepgoing = false ;
memset ( & items [ 0 ] , 0 , sizeof ( * items ) ) ;
items [ 0 ] . _iSeed = AdvanceRndSeed ( ) ;
SetRndSeed ( items [ 0 ] . _iSeed ) ;
int itype = RndPremiumItem ( plvl / 4 , plvl ) - 1 ;
GetItemAttrs ( 0 , itype , plvl ) ;
GetItemBonus ( 0 , plvl / 2 , plvl , true , ! gbIsHellfire ) ;
if ( ! gbIsHellfire ) {
if ( items [ 0 ] . _iIvalue > 140000 ) {
keepgoing = true ; // prevent breaking the do/while loop too early by failing hellfire's condition in while
continue ;
}
break ;
}
switch ( items [ 0 ] . _itype ) {
case ITYPE_LARMOR :
case ITYPE_MARMOR :
case ITYPE_HARMOR : {
const auto mostValuablePlayerArmor = plr [ myplr ] . GetMostValuableItem (
[ ] ( const ItemStruct & item ) {
return item . _itype = = ITYPE_LARMOR
| | item . _itype = = ITYPE_MARMOR
| | item . _itype = = ITYPE_HARMOR ;
} ) ;
ivalue = mostValuablePlayerArmor = = nullptr ? 0 : mostValuablePlayerArmor - > _iIvalue ;
break ;
}
case ITYPE_SHIELD :
case ITYPE_AXE :
case ITYPE_BOW :
case ITYPE_MACE :
case ITYPE_SWORD :
case ITYPE_HELM :
case ITYPE_STAFF :
case ITYPE_RING :
case ITYPE_AMULET : {
const auto mostValuablePlayerItem = plr [ myplr ] . GetMostValuableItem (
[ ] ( const ItemStruct & item ) { return item . _itype = = items [ 0 ] . _itype ; } ) ;
ivalue = mostValuablePlayerItem = = nullptr ? 0 : mostValuablePlayerItem - > _iIvalue ;
break ;
}
default :
ivalue = 0 ;
break ;
}
ivalue * = 0.8 ;
count + + ;
} while ( keepgoing
| | ( (
items [ 0 ] . _iIvalue > 200000
| | items [ 0 ] . _iMinStr > strength
| | items [ 0 ] . _iMinMag > magic
| | items [ 0 ] . _iMinDex > dexterity
| | items [ 0 ] . _iIvalue < ivalue )
& & count < 150 ) ) ;
premiumitems [ i ] = items [ 0 ] ;
premiumitems [ i ] . _iCreateInfo = plvl | CF_SMITHPREMIUM ;
premiumitems [ i ] . _iIdentified = true ;
premiumitems [ i ] . _iStatFlag = StoreStatOk ( & premiumitems [ i ] ) ;
items [ 0 ] = holditem ;
}
void SpawnPremium ( int pnum )
{
int lvl = plr [ pnum ] . _pLevel ;
int maxItems = gbIsHellfire ? SMITH_PREMIUM_ITEMS : 6 ;
if ( numpremium < maxItems ) {
for ( int i = 0 ; i < maxItems ; i + + ) {
if ( premiumitems [ i ] . isEmpty ( ) ) {
int plvl = premiumlevel + ( gbIsHellfire ? premiumLvlAddHellfire [ i ] : premiumlvladd [ i ] ) ;
SpawnOnePremium ( i , plvl , pnum ) ;
}
}
numpremium = maxItems ;
}
while ( premiumlevel < lvl ) {
premiumlevel + + ;
if ( gbIsHellfire ) {
premiumitems [ 0 ] = premiumitems [ 3 ] ;
premiumitems [ 1 ] = premiumitems [ 4 ] ;
premiumitems [ 2 ] = premiumitems [ 5 ] ;
premiumitems [ 3 ] = premiumitems [ 6 ] ;
premiumitems [ 4 ] = premiumitems [ 7 ] ;
premiumitems [ 5 ] = premiumitems [ 8 ] ;
premiumitems [ 6 ] = premiumitems [ 9 ] ;
premiumitems [ 7 ] = premiumitems [ 10 ] ;
premiumitems [ 8 ] = premiumitems [ 11 ] ;
premiumitems [ 9 ] = premiumitems [ 12 ] ;
SpawnOnePremium ( 10 , premiumlevel + premiumLvlAddHellfire [ 10 ] , pnum ) ;
premiumitems [ 11 ] = premiumitems [ 13 ] ;
SpawnOnePremium ( 12 , premiumlevel + premiumLvlAddHellfire [ 12 ] , pnum ) ;
premiumitems [ 13 ] = premiumitems [ 14 ] ;
SpawnOnePremium ( 14 , premiumlevel + premiumLvlAddHellfire [ 14 ] , pnum ) ;
} else {
premiumitems [ 0 ] = premiumitems [ 2 ] ;
premiumitems [ 1 ] = premiumitems [ 3 ] ;
premiumitems [ 2 ] = premiumitems [ 4 ] ;
SpawnOnePremium ( 3 , premiumlevel + premiumlvladd [ 3 ] , pnum ) ;
premiumitems [ 4 ] = premiumitems [ 5 ] ;
SpawnOnePremium ( 5 , premiumlevel + premiumlvladd [ 5 ] , pnum ) ;
}
}
}
bool WitchItemOk ( int i )
{
if ( AllItemsList [ i ] . itype ! = ITYPE_MISC & & AllItemsList [ i ] . itype ! = ITYPE_STAFF )
return false ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_MANA )
return false ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_FULLMANA )
return false ;
if ( AllItemsList [ i ] . iSpell = = SPL_TOWN )
return false ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_FULLHEAL )
return false ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_HEAL )
return false ;
if ( AllItemsList [ i ] . iMiscId > IMISC_OILFIRST & & AllItemsList [ i ] . iMiscId < IMISC_OILLAST )
return false ;
if ( AllItemsList [ i ] . iSpell = = SPL_RESURRECT & & ! gbIsMultiplayer )
return false ;
if ( AllItemsList [ i ] . iSpell = = SPL_HEALOTHER & & ! gbIsMultiplayer )
return false ;
return true ;
}
int RndWitchItem ( int lvl )
{
return RndVendorItem < WitchItemOk > ( 0 , lvl ) ;
}
void WitchBookLevel ( int ii )
{
if ( witchitem [ ii ] . _iMiscId ! = IMISC_BOOK )
return ;
witchitem [ ii ] . _iMinMag = spelldata [ witchitem [ ii ] . _iSpell ] . sMinInt ;
int 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 )
{
constexpr int PinnedItemCount = 3 ;
int iCnt ;
int idata , maxlvl , maxValue ;
int j = PinnedItemCount ;
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 = GenerateRnd ( WITCH_ITEMS - 10 ) + 10 ;
maxValue = 200000 ;
int books = GenerateRnd ( 4 ) ;
for ( int i = 114 , bCnt = 0 ; i < = 117 & & bCnt < books ; + + i ) {
if ( ! WitchItemOk ( i ) )
continue ;
if ( lvl < AllItemsList [ i ] . iMinMLvl )
continue ;
memset ( & items [ 0 ] , 0 , sizeof ( * items ) ) ;
items [ 0 ] . _iSeed = AdvanceRndSeed ( ) ;
SetRndSeed ( items [ 0 ] . _iSeed ) ;
GenerateRnd ( 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 = GenerateRnd ( WITCH_ITEMS - 12 ) + 10 ;
maxValue = 140000 ;
}
for ( int 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 ( GenerateRnd ( 100 ) < = 5 )
maxlvl = 2 * lvl ;
if ( maxlvl = = - 1 & & items [ 0 ] . _iMiscId = = IMISC_STAFF )
maxlvl = 2 * lvl ;
if ( maxlvl ! = - 1 )
GetItemBonus ( 0 , maxlvl / 2 , 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 ( int i = iCnt ; i < WITCH_ITEMS ; i + + )
witchitem [ i ] . _itype = ITYPE_NONE ;
SortVendor ( witchitem + PinnedItemCount ) ;
}
int RndBoyItem ( int lvl )
{
return RndVendorItem < PremiumItemOk > ( 0 , lvl ) ;
}
void SpawnBoy ( int lvl )
{
int itype ;
int ivalue = 0 ;
bool keepgoing = false ;
int count = 0 ;
HeroClass pc = plr [ myplr ] . _pClass ;
int strength = std : : max ( plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Strength ) , plr [ myplr ] . _pStrength ) ;
int dexterity = std : : max ( plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Dexterity ) , plr [ myplr ] . _pDexterity ) ;
int magic = std : : max ( plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Magic ) , plr [ myplr ] . _pMagic ) ;
strength * = 1.2 ;
dexterity * = 1.2 ;
magic * = 1.2 ;
if ( boylevel > = ( lvl / 2 ) & & ! boyitem . isEmpty ( ) )
return ;
do {
keepgoing = false ;
memset ( & items [ 0 ] , 0 , sizeof ( * items ) ) ;
items [ 0 ] . _iSeed = AdvanceRndSeed ( ) ;
SetRndSeed ( items [ 0 ] . _iSeed ) ;
itype = RndBoyItem ( lvl ) - 1 ;
GetItemAttrs ( 0 , itype , lvl ) ;
GetItemBonus ( 0 , lvl , 2 * lvl , true , true ) ;
if ( ! gbIsHellfire ) {
if ( items [ 0 ] . _iIvalue > 90000 ) {
keepgoing = true ; // prevent breaking the do/while loop too early by failing hellfire's condition in while
continue ;
}
break ;
}
ivalue = 0 ;
int itemType = items [ 0 ] . _itype ;
switch ( itemType ) {
case ITYPE_LARMOR :
case ITYPE_MARMOR :
case ITYPE_HARMOR : {
const auto mostValuablePlayerArmor = plr [ myplr ] . GetMostValuableItem (
[ ] ( const ItemStruct & item ) {
return item . _itype = = ITYPE_LARMOR
| | item . _itype = = ITYPE_MARMOR
| | item . _itype = = ITYPE_HARMOR ;
} ) ;
ivalue = mostValuablePlayerArmor = = nullptr ? 0 : mostValuablePlayerArmor - > _iIvalue ;
break ;
}
case ITYPE_SHIELD :
case ITYPE_AXE :
case ITYPE_BOW :
case ITYPE_MACE :
case ITYPE_SWORD :
case ITYPE_HELM :
case ITYPE_STAFF :
case ITYPE_RING :
case ITYPE_AMULET : {
const auto mostValuablePlayerItem = plr [ myplr ] . GetMostValuableItem (
[ itemType ] ( const ItemStruct & item ) { return item . _itype = = itemType ; } ) ;
ivalue = mostValuablePlayerItem = = nullptr ? 0 : mostValuablePlayerItem - > _iIvalue ;
break ;
}
}
ivalue * = 0.8 ;
count + + ;
if ( count < 200 ) {
switch ( pc ) {
case HeroClass : : Warrior :
if ( itemType = = ITYPE_BOW | | itemType = = ITYPE_STAFF )
ivalue = INT_MAX ;
break ;
case HeroClass : : Rogue :
if ( itemType = = ITYPE_SWORD | | itemType = = ITYPE_STAFF | | itemType = = ITYPE_AXE | | itemType = = ITYPE_MACE | | itemType = = ITYPE_SHIELD )
ivalue = INT_MAX ;
break ;
case HeroClass : : Sorcerer :
if ( itemType = = ITYPE_STAFF | | itemType = = ITYPE_AXE | | itemType = = ITYPE_BOW | | itemType = = ITYPE_MACE )
ivalue = INT_MAX ;
break ;
case HeroClass : : Monk :
if ( itemType = = ITYPE_BOW | | itemType = = ITYPE_MARMOR | | itemType = = ITYPE_SHIELD | | itemType = = ITYPE_MACE )
ivalue = INT_MAX ;
break ;
case HeroClass : : Bard :
if ( itemType = = ITYPE_AXE | | itemType = = ITYPE_MACE | | itemType = = ITYPE_STAFF )
ivalue = INT_MAX ;
break ;
case HeroClass : : Barbarian :
if ( itemType = = ITYPE_BOW | | itemType = = ITYPE_STAFF )
ivalue = INT_MAX ;
break ;
}
}
} while ( keepgoing
| | ( (
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 / 2 ;
}
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 < plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Strength ) ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_ELIXMAG )
return ! gbIsHellfire | | plr [ myplr ] . _pBaseMag < plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Magic ) ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_ELIXDEX )
return ! gbIsHellfire | | plr [ myplr ] . _pBaseDex < plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Dexterity ) ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_ELIXVIT )
return ! gbIsHellfire | | plr [ myplr ] . _pBaseVit < plr [ myplr ] . GetMaximumAttributeValue ( CharacterAttribute : : Vitality ) ;
}
if ( AllItemsList [ i ] . iMiscId = = IMISC_REJUV )
return true ;
if ( AllItemsList [ i ] . iMiscId = = IMISC_FULLREJUV )
return true ;
return false ;
}
int RndHealerItem ( int lvl )
{
return RndVendorItem < HealerItemOk > ( 0 , lvl ) ;
}
void SpawnHealer ( int lvl )
{
constexpr int PinnedItemCount = 2 ;
int srnd ;
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 ;
}
int nsi = GenerateRnd ( gbIsHellfire ? 10 : 8 ) + 10 ;
for ( int i = srnd ; i < nsi ; i + + ) {
memset ( & items [ 0 ] , 0 , sizeof ( * items ) ) ;
items [ 0 ] . _iSeed = AdvanceRndSeed ( ) ;
SetRndSeed ( items [ 0 ] . _iSeed ) ;
int 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 ( int i = nsi ; i < 20 ; i + + ) {
healitem [ i ] . _itype = ITYPE_NONE ;
}
SortVendor ( healitem + PinnedItemCount ) ;
}
void SpawnStoreGold ( )
{
memset ( & items [ 0 ] , 0 , sizeof ( * items ) ) ;
GetItemAttrs ( 0 , IDI_GOLD , 1 ) ;
golditem = items [ 0 ] ;
golditem . _iStatFlag = true ;
}
void RecreateSmithItem ( int ii , 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 plvl , int iseed )
{
SetRndSeed ( iseed ) ;
int itype = RndPremiumItem ( plvl / 4 , plvl ) - 1 ;
GetItemAttrs ( ii , itype , plvl ) ;
GetItemBonus ( ii , plvl / 2 , plvl , true , ! gbIsHellfire ) ;
items [ ii ] . _iSeed = iseed ;
items [ ii ] . _iCreateInfo = plvl | CF_SMITHPREMIUM ;
items [ ii ] . _iIdentified = true ;
}
void RecreateBoyItem ( int ii , int lvl , int iseed )
{
SetRndSeed ( iseed ) ;
int itype = RndBoyItem ( lvl ) - 1 ;
GetItemAttrs ( ii , itype , lvl ) ;
GetItemBonus ( ii , 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 ) ;
GenerateRnd ( 1 ) ;
GetItemAttrs ( ii , idx , lvl ) ;
} else {
SetRndSeed ( iseed ) ;
int itype = RndWitchItem ( lvl ) - 1 ;
GetItemAttrs ( ii , itype , lvl ) ;
int iblvl = - 1 ;
if ( GenerateRnd ( 100 ) < = 5 )
iblvl = 2 * lvl ;
if ( iblvl = = - 1 & & items [ ii ] . _iMiscId = = IMISC_STAFF )
iblvl = 2 * lvl ;
if ( iblvl ! = - 1 )
GetItemBonus ( ii , iblvl / 2 , 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 )
{
if ( idx = = IDI_HEAL | | idx = = IDI_FULLHEAL | | idx = = IDI_RESURRECT ) {
GetItemAttrs ( ii , idx , lvl ) ;
} else {
SetRndSeed ( iseed ) ;
int 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 , uint16_t icreateinfo , int iseed )
{
if ( ( icreateinfo & CF_SMITH ) ! = 0 )
RecreateSmithItem ( ii , icreateinfo & CF_LEVEL , iseed ) ;
else if ( ( icreateinfo & CF_SMITHPREMIUM ) ! = 0 )
RecreatePremiumItem ( ii , icreateinfo & CF_LEVEL , iseed ) ;
else if ( ( icreateinfo & CF_BOY ) ! = 0 )
RecreateBoyItem ( ii , icreateinfo & CF_LEVEL , iseed ) ;
else if ( ( icreateinfo & CF_WITCH ) ! = 0 )
RecreateWitchItem ( ii , idx , icreateinfo & CF_LEVEL , iseed ) ;
else if ( ( icreateinfo & CF_HEALER ) ! = 0 )
RecreateHealerItem ( ii , idx , icreateinfo & CF_LEVEL , iseed ) ;
}
void RecalcStoreStats ( )
{
for ( int i = 0 ; i < SMITH_ITEMS ; i + + ) {
if ( ! smithitem [ i ] . isEmpty ( ) ) {
smithitem [ i ] . _iStatFlag = StoreStatOk ( & smithitem [ i ] ) ;
}
}
for ( int i = 0 ; i < SMITH_PREMIUM_ITEMS ; i + + ) {
if ( ! premiumitems [ i ] . isEmpty ( ) ) {
premiumitems [ i ] . _iStatFlag = StoreStatOk ( & premiumitems [ i ] ) ;
}
}
for ( int i = 0 ; i < 20 ; i + + ) {
if ( ! witchitem [ i ] . isEmpty ( ) ) {
witchitem [ i ] . _iStatFlag = StoreStatOk ( & witchitem [ i ] ) ;
}
}
for ( int 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 ( Point position , 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 ( position , ii ) ;
if ( sendmsg )
NetSendCmdDItem ( false , ii ) ;
if ( delta )
DeltaAddItem ( ii ) ;
}
static void CreateMagicItem ( Point position , 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 ( position , ii ) ;
if ( sendmsg )
NetSendCmdDItem ( false , ii ) ;
if ( delta )
DeltaAddItem ( ii ) ;
}
void CreateMagicArmor ( Point position , int imisc , int icurs , bool sendmsg , bool delta )
{
int lvl = items_get_currlevel ( ) ;
CreateMagicItem ( position , lvl , imisc , IMISC_NONE , icurs , sendmsg , delta ) ;
}
void CreateAmulet ( Point position , int lvl , bool sendmsg , bool delta )
{
CreateMagicItem ( position , lvl , ITYPE_AMULET , IMISC_AMULET , ICURS_AMULET , sendmsg , delta ) ;
}
void CreateMagicWeapon ( Point position , 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 ( position , 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 , uint16_t wCI , int nIndex )
{
uint32_t ticks = SDL_GetTicks ( ) ;
for ( int i = 0 ; i < gnNumGetRecords ; i + + ) {
if ( ticks - 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 , uint16_t wCI , int nIndex )
{
uint32_t ticks = SDL_GetTicks ( ) ;
if ( gnNumGetRecords = = MAXITEMS ) {
return ;
}
itemrecord [ gnNumGetRecords ] . dwTimestamp = ticks ;
itemrecord [ gnNumGetRecords ] . nSeed = nSeed ;
itemrecord [ gnNumGetRecords ] . wCI = wCI ;
itemrecord [ gnNumGetRecords ] . nIndex = nIndex ;
gnNumGetRecords + + ;
}
void PutItemRecord ( int nSeed , uint16_t wCI , int nIndex )
{
uint32_t ticks = SDL_GetTicks ( ) ;
for ( int i = 0 ; i < gnNumGetRecords ; i + + ) {
if ( ticks - itemrecord [ i ] . dwTimestamp > 6000 ) {
NextItemRecord ( i ) ;
i - - ;
} else if ( nSeed = = itemrecord [ i ] . nSeed & & wCI = = itemrecord [ i ] . wCI & & nIndex = = itemrecord [ i ] . nIndex ) {
NextItemRecord ( i ) ;
break ;
}
}
}
} // namespace devilution