2018-02-08 23:40:26 +00:00
// Hyperbolic Rogue -- Orb Strategy Mode
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
2019-08-10 11:43:24 +00:00
/** \file inventory.cpp
* \ brief Orb Strategy Mode
*/
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2019-08-09 20:07:03 +00:00
namespace hr {
2017-09-01 20:13:00 +00:00
2020-03-27 20:14:09 +00:00
/** \brief Implementation of the Orb Strategy Mode.
2020-03-27 20:47:09 +00:00
*
2020-03-27 20:14:09 +00:00
* The most important functions called outside is hr : : inv : : show ( ) .
*/
2019-08-09 20:07:03 +00:00
EX namespace inv {
2019-09-06 07:17:45 +00:00
# if CAP_INV
2020-03-27 20:47:09 +00:00
/** \brief is the Orb Strategy Mode active? */
2019-08-09 20:07:03 +00:00
EX bool on ;
2020-03-27 20:47:09 +00:00
/** \brief the number of Orbs used up in each type */
2019-08-09 20:07:03 +00:00
EX array < int , ittypes > usedup ;
2020-03-27 20:47:09 +00:00
/** \brief the number of Orbs remaining in each type -- it is recalculated based on your treasure and hr::inv::usedup after every move */
2019-08-09 20:07:03 +00:00
EX array < int , ittypes > remaining ;
2020-03-27 20:47:09 +00:00
/** \brief extra orbs can be added to OSM using -IX commandline option */
2019-09-05 10:00:55 +00:00
EX array < int , ittypes > extra_orbs ;
2017-09-01 20:13:00 +00:00
2020-03-27 20:47:09 +00:00
/** \brief random seed used for hr::inv::invr */
2019-09-05 10:00:55 +00:00
EX int rseed ;
2020-03-27 20:47:09 +00:00
/** \brief have we used any 'forbidden' orbs? */
2019-08-09 20:07:03 +00:00
EX bool usedForbidden ;
2020-03-27 20:10:55 +00:00
2020-03-27 20:47:09 +00:00
/** \brief initialize the OSM data for a new game */
2019-08-09 20:07:03 +00:00
EX void init ( ) {
2017-09-01 20:13:00 +00:00
rseed = hrandpos ( ) ;
usedForbidden = false ;
for ( int i = 0 ; i < ittypes ; i + + ) usedup [ i ] = 0 ;
}
static const int MIRRORED = 1000 ;
static const int TESTMIRRORED = 900 ;
struct lateextraorb {
eItem treasure ;
eItem orb ;
} ;
vector < lateextraorb > lateextraorbs = {
{ itPower , itOrbFlash } ,
{ itPower , itOrbSpeed } ,
{ itPower , itOrbAether } ,
{ itPower , itOrbWinter } ,
{ itTrollEgg , itOrbFish } ,
{ itTrollEgg , itOrbStunning } ,
{ itTrollEgg , itOrbLuck } ,
{ itTrollEgg , itOrbLife } ,
{ itTrollEgg , itOrbDigging } ,
{ itTrollEgg , itOrbSpace } ,
{ itFulgurite , itOrbLightning } ,
{ itWindstone , itOrbSpeed } ,
{ itDragon , itOrbDragon } ,
{ itSlime , itOrbFlash } ,
2017-09-03 10:17:53 +00:00
{ itDodeca , itOrbShield } ,
{ itGreenGrass , itOrbHorns } ,
{ itGreenGrass , itOrbShield } ,
{ itGreenGrass , itOrbThorns }
2017-09-01 20:13:00 +00:00
} ;
2020-03-27 20:47:09 +00:00
/** \brief how many orbs can we get from Orb-of-Mirroring orb */
2017-09-01 20:13:00 +00:00
int mirrorqty0 ( eItem orb ) {
if ( shmup : : on & & isShmupLifeOrb ( orb ) )
return 3 ;
if ( orb = = itOrbWater ) return 10 ;
if ( orb = = itOrbSummon ) return 9 ;
if ( orb = = itOrbEmpathy ) return 9 ;
if ( orb = = itOrbMatter ) return 9 ;
2019-01-11 14:02:04 +00:00
if ( orb = = itOrbIntensity ) return 8 ;
2017-09-01 20:13:00 +00:00
if ( orb = = itOrbLuck ) return 8 ;
if ( orb = = itOrbSpace ) return 7 ;
if ( orb = = itOrbWinter ) return 6 ;
if ( orb = = itOrbLife ) return 6 ;
if ( orb = = itOrbLove ) return 6 ;
if ( orb = = itOrbRecall ) return 6 ;
if ( orb = = itOrbDigging ) return 6 ;
2019-01-11 14:02:04 +00:00
if ( orb = = itOrbGravity ) return 6 ;
2020-02-27 18:54:18 +00:00
if ( orb = = itOrbImpact ) return 6 ;
2017-09-01 20:13:00 +00:00
if ( orb = = itOrbTime ) return 5 ;
if ( orb = = itOrbAir ) return 5 ;
if ( orb = = itOrbFish ) return 5 ;
if ( orb = = itOrbStunning ) return 5 ;
if ( orb = = itOrbUndeath ) return 5 ;
if ( orb = = itOrb37 ) return 5 ;
if ( orb = = itOrbDomination ) return 5 ;
if ( orb = = itOrbBull ) return 5 ;
if ( orb = = itOrbHorns ) return 5 ;
if ( orb = = itOrbAether ) return 4 ;
if ( orb = = itOrbInvis ) return 4 ;
if ( orb = = itOrbFire ) return 4 ;
if ( orb = = itOrbDragon ) return 4 ;
if ( orb = = itOrbIllusion ) return 4 ;
if ( orb = = itOrbDiscord ) return 4 ;
if ( orb = = itOrbBeauty ) return 4 ;
if ( orb = = itOrbMirror ) return 1 ;
return 3 ;
}
int mirrorqty ( eItem orb ) {
2017-09-01 20:37:20 +00:00
if ( orb = = itOrbMirror ) return 1 ;
2017-09-01 20:13:00 +00:00
return int ( mirrorqty0 ( orb ) * sqrt ( 1.000001 + items [ itPower ] / 20. ) ) ;
}
2020-03-27 20:10:55 +00:00
2020-03-27 20:47:09 +00:00
/** \brief PRNG used for calculating how many Orbs you get for your collected treasure */
2018-06-17 16:32:06 +00:00
std : : mt19937 invr ;
2017-09-01 20:13:00 +00:00
2020-03-27 20:47:09 +00:00
/** \brief initialize hr::inv::invr */
2017-09-01 20:13:00 +00:00
void sirand ( int i ) {
invr . seed ( i ) ;
}
2020-03-27 20:47:09 +00:00
/** \brief get the next random value from hr::inv::invr */
2017-09-01 20:13:00 +00:00
int irand ( int i ) {
return invr ( ) % i ;
}
2019-09-05 10:00:55 +00:00
EX eItem whichorbinfo ;
EX string orbinfoline , extra ;
2017-10-10 10:43:41 +00:00
string extraline ( eItem it , string s ) {
return " " + XLAT1 ( iinf [ it ] . name ) + " ( " + s + " ) " ;
}
2017-09-01 20:13:00 +00:00
void gainOrbs ( eItem it , eItem o ) {
int qty = items [ it ] ;
if ( it = = itHolyGrail ) {
remaining [ itOrbIllusion ] + = qty ;
2017-10-10 10:43:41 +00:00
if ( it = = itOrbIllusion ) {
2017-10-10 13:00:38 +00:00
orbinfoline + = XLAT ( " Unlocked by: %1 in %2 " , it , landof ( it ) ) ;
2017-10-10 10:43:41 +00:00
orbinfoline + = XLAT ( " (next at %1) " , its ( qty + 1 ) ) ;
}
2017-09-01 20:13:00 +00:00
}
else {
bool nextfound = false ;
2019-06-17 08:13:08 +00:00
int fst = ( chaosmode ? 5 : 10 ) ;
if ( qty > = fst ) remaining [ o ] + + ;
2017-10-10 10:43:41 +00:00
else {
if ( whichorbinfo = = o ) {
if ( it = = itHyperstone ) {
2019-06-17 08:13:08 +00:00
extra + = extraline ( it , its ( fst ) ) ;
2017-10-10 10:43:41 +00:00
}
else {
2017-10-10 13:00:38 +00:00
orbinfoline + = XLAT ( " Unlocked by: %1 in %2 " , it , landof ( it ) ) ;
2017-10-10 10:43:41 +00:00
orbinfoline + = XLAT ( " (next at %1) " , its ( 10 ) ) ;
}
}
nextfound = true ;
}
2019-06-17 08:13:08 +00:00
int last = fst ;
2017-09-01 20:13:00 +00:00
for ( int k = 0 ; k < 30 | | ! nextfound ; k + + ) {
2019-06-17 08:13:08 +00:00
int maxstep = chaosmode ? 10 + 2 * k : 15 + 5 * k ;
2017-09-01 20:13:00 +00:00
if ( o = = itOrbMirror )
maxstep + = 5 * ( k - 1 ) * ( k - 2 ) ;
else
maxstep + = ( k - 1 ) * ( k - 2 ) ;
int xnext ;
if ( k > = 30 | | o = = itOrbMirror ) {
xnext = last + maxstep / 2 ; last = xnext - 1 ;
maxstep = 1 ;
}
else
xnext = last + 1 + irand ( maxstep ) ;
2017-10-10 10:43:41 +00:00
if ( xnext > qty & & ! nextfound ) {
if ( whichorbinfo = = o ) {
if ( it = = itHyperstone ) {
extra + = extraline ( it , its ( last + maxstep ) ) ;
}
2017-10-10 13:00:38 +00:00
else {
orbinfoline + = XLAT ( " Unlocked by: %1 in %2 " , it , landof ( it ) ) ;
if ( maxstep = = 1 )
orbinfoline + = XLAT ( " (next at %1) " , its ( last + 1 ) ) ;
else
orbinfoline + = XLAT ( " (next at %1 to %2) " , its ( last + 1 ) , its ( last + maxstep ) ) ;
}
2017-10-10 10:43:41 +00:00
}
nextfound = true ;
}
2017-09-01 20:13:00 +00:00
if ( xnext < = qty ) remaining [ o ] + + ;
last = xnext ;
}
}
}
int nextp2 ( int i ) {
int z = 1 ;
while ( z < = i ) z < < = 1 ;
return z ;
}
2017-10-10 10:43:41 +00:00
void gainMirrors ( eItem forwhich ) {
int qtl = items [ forwhich ] ;
2017-09-01 20:13:00 +00:00
while ( qtl > 0 ) qtl > > = 1 , remaining [ itOrbMirror ] + + ;
2017-10-10 10:43:41 +00:00
if ( whichorbinfo = = itOrbMirror )
2018-06-25 19:52:21 +00:00
extra + = extraline ( forwhich , its ( nextp2 ( items [ forwhich ] ) ) ) ;
2017-09-01 20:13:00 +00:00
}
vector < eItem > offensiveOrbs = {
itOrbFlash , itOrbLightning , itOrbPsi , itOrbThorns ,
itOrbFreedom , itOrbSword , itOrbSword2 ,
itOrbHorns , itOrbDragon , itOrbStunning
} ;
vector < eItem > elementalOrbs = { itOrbFire , itOrbWater , itOrbDigging , itOrbAir } ;
vector < eItem > demonicOrbs = { itOrbFire , itOrbHorns , itOrbSummon } ;
bool isIn ( eItem o , vector < eItem > & l ) {
for ( auto it : l ) if ( it = = o ) return true ;
return false ;
}
void gainRandomOrbs ( vector < eItem > orblist , eItem which , int each , int reduce ) {
2018-06-22 12:47:24 +00:00
const int qoff = isize ( orblist ) ;
2017-09-01 20:13:00 +00:00
for ( int i = 1 ; i < qoff ; i + + ) swap ( orblist [ i ] , orblist [ irand ( 1 + i ) ] ) ;
for ( int i = 0 ; i < 20 ; i + + ) {
2017-10-10 10:43:41 +00:00
int nextat = ( i + 1 ) * each + reduce ;
if ( items [ which ] > = nextat ) {
remaining [ orblist [ i % qoff ] ] + + ;
}
else {
if ( isIn ( whichorbinfo , orblist ) )
extra + = extraline ( which , its ( nextat ) + " ? " ) ;
break ;
}
2017-09-01 20:13:00 +00:00
}
}
2017-10-10 10:43:41 +00:00
void gainGuestOrbs ( ) {
2018-12-23 02:13:08 +00:00
for ( auto & oi : orbinfos ) {
2017-10-10 10:43:41 +00:00
if ( oi . flags & orbgenflags : : OSM_AT10 ) {
eItem it = treasureType ( oi . l ) ;
2019-06-17 08:13:08 +00:00
int fst = chaosmode ? 5 : 10 ;
if ( items [ it ] > = fst ) {
2017-10-10 10:43:41 +00:00
remaining [ oi . orb ] + + ;
}
2019-06-17 08:13:08 +00:00
if ( whichorbinfo = = oi . orb ) extra + = extraline ( it , its ( fst ) ) ;
2017-10-10 10:43:41 +00:00
}
2017-09-01 20:13:00 +00:00
}
2017-10-10 10:43:41 +00:00
}
void gainLove ( ) {
2017-09-01 20:13:00 +00:00
if ( princess : : reviveAt ) {
remaining [ itOrbLove ] + + ;
int s = gold ( NO_LOVE ) ;
int last = princess : : reviveAt ;
for ( int k = 0 ; ; k + + ) {
int nextstep = 50 + 20 * k ;
last + = nextstep ;
if ( last > s ) {
2017-10-10 10:43:41 +00:00
if ( whichorbinfo = = itOrbLove ) {
orbinfoline + = XLAT ( " Unlocked by: %1 in %2 " , itSavedPrincess , laPrincessQuest ) ;
orbinfoline + = XLAT ( " (next at %1) " , its ( last ) ) ;
}
2017-09-01 20:13:00 +00:00
break ;
}
else { last + = nextstep ; remaining [ itOrbLove ] + + ; }
}
}
2017-10-10 10:43:41 +00:00
}
void gainLate ( eItem tr , eItem orb ) {
int at = 10 + irand ( 41 ) ;
int itr = items [ tr ] ;
if ( itr > = at ) remaining [ orb ] + + ;
if ( whichorbinfo = = orb )
extra + = extraline ( tr , itr > = at ? ( its ( at ) + " ! " ) : " 10-50 " ) ;
}
2020-03-27 20:47:09 +00:00
/** \brief Compute how many orbs you get for your current treasure. This is called after every move, and should give consistent results */
2019-08-09 20:07:03 +00:00
EX void compute ( ) {
2017-10-10 10:43:41 +00:00
extra = " " ;
orbinfoline = " " ;
2018-01-25 16:18:30 +00:00
for ( int i = 0 ; i < ittypes ; i + + ) remaining [ i ] = extra_orbs [ i ] - usedup [ i ] ;
2017-10-10 10:43:41 +00:00
for ( int i = 0 ; i < ittypes ; i + + ) if ( usedup [ i ] > = TESTMIRRORED ) {
remaining [ i ] + = MIRRORED ;
remaining [ i ] - = mirrorqty0 ( eItem ( i ) ) ;
remaining [ i ] + = mirrorqty ( eItem ( i ) ) ;
}
sirand ( rseed ) ;
2017-09-01 20:13:00 +00:00
2017-10-10 10:43:41 +00:00
gainGuestOrbs ( ) ;
gainOrbs ( itShard , itOrbMirror ) ;
gainOrbs ( itHyperstone , itOrbMirror ) ;
gainOrbs ( itDiamond , itOrbFlash ) ;
gainOrbs ( itGold , itOrbLife ) ;
gainOrbs ( itSpice , itOrbShield ) ;
gainOrbs ( itRuby , itOrbLightning ) ;
gainOrbs ( itElixir , itOrbSpeed ) ;
gainOrbs ( itBone , itGreenStone ) ;
gainOrbs ( itHell , itOrbYendor ) ;
gainOrbs ( itStatue , itOrbTeleport ) ;
gainOrbs ( itFeather , itOrbSafety ) ;
2017-10-10 13:00:38 +00:00
gainOrbs ( itSapphire , itOrbMorph ) ;
2017-10-10 10:43:41 +00:00
gainOrbs ( itFernFlower , itOrbThorns ) ;
gainOrbs ( itWine , itOrbAether ) ;
gainOrbs ( itSilver , itOrbDigging ) ;
gainOrbs ( itRoyalJelly , itOrbInvis ) ;
gainOrbs ( itEmerald , itOrbPsi ) ;
gainOrbs ( itPower , itOrbFire ) ;
gainOrbs ( itHolyGrail , itOrbIllusion ) ;
gainOrbs ( itGrimoire , itOrbDragon ) ;
gainOrbs ( itPirate , itOrbTime ) ;
gainOrbs ( itRedGem , itOrbSpace ) ;
gainOrbs ( itBombEgg , itOrbFriend ) ;
gainOrbs ( itCoast , itOrbEmpathy ) ;
gainOrbs ( itWhirlpool , itOrbWater ) ;
gainOrbs ( itPalace , itOrbDiscord ) ;
gainOrbs ( itFjord , itOrbFish ) ;
gainOrbs ( itSavedPrincess , itOrbLove ) ;
gainOrbs ( itIvory , itOrbMatter ) ;
gainOrbs ( itZebra , itOrbFrog ) ;
gainOrbs ( itElemental , itOrbSummon ) ;
gainOrbs ( itFulgurite , itOrbStunning ) ;
gainOrbs ( itMutant , itOrbLuck ) ;
gainOrbs ( itMutant2 , itOrbFreedom ) ;
gainOrbs ( itLotus , itOrbUndeath ) ;
gainOrbs ( itWindstone , itOrbAir ) ;
gainOrbs ( itRose , itOrbBeauty ) ;
gainOrbs ( itCoral , itOrb37 ) ;
gainOrbs ( itBabyTortoise , itOrbShell ) ;
gainOrbs ( itApple , itOrbEnergy ) ;
gainOrbs ( itDragon , itOrbDomination ) ;
gainOrbs ( itKraken , itOrbSword ) ;
gainOrbs ( itBarrow , itOrbSword2 ) ;
gainOrbs ( itTrollEgg , itOrbStone ) ;
gainOrbs ( itSlime , itOrbRecall ) ;
gainOrbs ( itAmethyst , itOrbNature ) ;
gainOrbs ( itDodeca , itOrbDash ) ;
gainOrbs ( itGreenGrass , itOrbBull ) ;
gainOrbs ( itBull , itOrbHorns ) ;
if ( items [ itOrbYendor ] ) remaining [ itOrbMirror ] + + ;
gainMirrors ( itOrbYendor ) ;
gainMirrors ( itHolyGrail ) ;
gainLove ( ) ;
2017-09-01 20:13:00 +00:00
gainRandomOrbs ( offensiveOrbs , itBone , 25 , 0 ) ;
gainRandomOrbs ( elementalOrbs , itElemental , 12 , 0 ) ;
gainRandomOrbs ( demonicOrbs , itHell , 20 , 100 ) ;
2017-10-10 13:00:38 +00:00
gainOrbs ( itLavaLily , itOrbLava ) ;
gainOrbs ( itHunting , itOrbSide3 ) ;
gainOrbs ( itBlizzard , itOrbWinter ) ;
gainOrbs ( itTerra , itOrbSide1 ) ;
2017-12-21 15:35:19 +00:00
2017-10-10 10:43:41 +00:00
for ( auto & it : lateextraorbs ) gainLate ( it . treasure , it . orb ) ;
2017-09-01 20:13:00 +00:00
2017-12-21 15:35:19 +00:00
gainOrbs ( itGlowCrystal , itOrbSide2 ) ;
2017-12-30 22:47:10 +00:00
gainOrbs ( itSwitch , itOrbPhasing ) ;
gainOrbs ( itMagnet , itOrbMagnetism ) ;
2018-01-03 20:51:11 +00:00
gainOrbs ( itRuins , itOrbSlaying ) ;
2018-12-23 02:14:48 +00:00
gainOrbs ( itWest , itOrbGravity ) ;
2018-12-25 18:27:19 +00:00
gainOrbs ( itVarTreasure , itOrbIntensity ) ;
2018-12-25 18:26:06 +00:00
gainOrbs ( itBrownian , itOrbChoice ) ;
2020-02-26 00:41:41 +00:00
gainOrbs ( itFrog , itOrbImpact ) ;
2020-02-26 01:49:35 +00:00
gainOrbs ( itWet , itOrbPlague ) ;
2020-02-26 00:41:41 +00:00
gainOrbs ( itEclectic , itOrbChaos ) ;
2017-12-21 15:35:19 +00:00
2018-04-30 22:21:18 +00:00
# if CAP_DAILY
daily : : gifts ( ) ;
# endif
2017-09-01 20:13:00 +00:00
if ( items [ itOrbLove ] & & ! items [ itSavedPrincess ] ) items [ itSavedPrincess ] = 1 ;
int & r = remaining [ itGreenStone ] ;
if ( items [ itBone ] > = 0 ) {
for ( int i = 0 ; i < ittypes ; i + + ) if ( i ! = itGreenStone ) {
r + = usedup [ i ] ;
if ( usedup [ i ] > = TESTMIRRORED ) r - = ( MIRRORED - mirrorqty0 ( eItem ( i ) ) ) ;
}
}
items [ itGreenStone ] + = r ;
usedup [ itGreenStone ] + = r ;
r = 0 ;
if ( shmup : : on ) for ( int i = 0 ; i < ittypes ; i + + ) {
if ( remaining [ i ] & & isShmupLifeOrb ( eItem ( i ) ) ) {
gainLife ( ) ;
remaining [ i ] - - ;
usedup [ i ] + + ;
}
}
items [ itInventory ] = 0 ;
for ( int i = 0 ; i < ittypes ; i + + )
if ( i ! = itGreenStone & & i ! = itOrbYendor )
items [ itInventory ] + = remaining [ i ] ;
}
map < char , eItem > orbmap ;
2019-01-03 01:07:31 +00:00
string orbkeys = " zfwplSetsTaMIYgCcPOWAFydLGRUkouE.,bVNxDjJZnrvhBm!23456789@#$% " ;
2017-09-01 20:13:00 +00:00
typedef pair < int , int > pxy ;
vector < pxy > orbcoord ;
int sq ( pxy p ) {
int zz = ( 2 * p . first + p . second ) * ( 2 * p . first + p . second ) + 3 * p . second * p . second ;
zz * = 20 ; zz + = abs ( p . second ) ;
zz * = 20 ; zz + = abs ( p . first ) ;
zz * = 4 ; zz + = ( p . first > 0 ) * 2 + ( p . second > 0 ) ;
return zz ;
}
bool plain ;
eItem which ;
bool mirroring ;
2019-09-05 10:00:55 +00:00
EX const char * helptext =
2017-09-01 20:13:00 +00:00
" You are playing in the Orb Strategy Mode. Collecting treasure "
" gives you access to magical Orb powers. In this mode, "
" unlocking requirements are generally higher, and "
" several quests and lands "
" give you extremely powerful Orbs of the Mirror. \n " ;
void evokeBeautyAt ( cell * c ) {
forCellEx ( c2 , c )
if ( c2 - > monst & & ! isFriendly ( c2 - > monst ) & & ! isIvy ( c2 - > monst ) ) {
c2 - > stuntime + = 3 ;
checkStunKill ( c2 ) ;
}
}
void evokeOrb ( eItem it ) {
if ( it = = itOrbFreedom )
for ( int i = 0 ; i < numplayers ( ) ; i + + )
if ( multi : : playerActive ( i ) )
checkFreedom ( playerpos ( i ) ) ;
if ( it = = itOrbBeauty ) {
for ( int i = 0 ; i < numplayers ( ) ; i + + )
if ( multi : : playerActive ( i ) )
evokeBeautyAt ( playerpos ( i ) ) ;
if ( items [ itOrbEmpathy ] )
for ( cell * c : dcal ) if ( isFriendly ( c - > monst ) )
evokeBeautyAt ( c ) ;
}
2020-02-26 00:41:52 +00:00
if ( it = = itOrbDigging ) {
forCellCM ( c2 , cwt . at ) {
earthFloor ( c2 ) ;
if ( c2 - > wall = = waCavewall & & ! c2 - > monst )
c2 - > wall = waNone ;
}
}
2017-09-01 20:13:00 +00:00
if ( it = = itOrbSword | | it = = itOrbSword2 ) {
for ( int i = 0 ; i < numplayers ( ) ; i + + )
if ( multi : : playerActive ( i ) ) {
2018-08-17 22:46:45 +00:00
cwt . at = playerpos ( i ) ;
2017-09-01 20:13:00 +00:00
multi : : cpid = i ;
swordAttackStatic ( it = = itOrbSword2 ) ;
}
}
}
2017-10-10 10:43:41 +00:00
2019-09-05 10:00:55 +00:00
EX string osminfo ( eItem orb ) {
2017-10-10 10:43:41 +00:00
string s = XLAT ( " Number of uses left: %1 " , its ( remaining [ orb ] ) ) ;
int us = usedup [ orb ] ;
if ( us > = TESTMIRRORED ) s + = XLAT ( " (mirrored) " ) , us = us - MIRRORED + mirrorqty0 ( orb ) ;
if ( us ) s + = XLAT ( " (used %1 times) " , its ( us ) ) ;
return s ;
}
2018-01-25 16:23:16 +00:00
2019-08-09 20:07:03 +00:00
EX bool activating ;
2017-09-01 20:13:00 +00:00
2020-03-27 20:47:09 +00:00
/** \brief show the OSM Orb screen */
2019-08-09 20:07:03 +00:00
EX void show ( ) {
2017-09-01 20:13:00 +00:00
2019-11-14 19:08:23 +00:00
multi : : cpid = 0 ; /* just in case */
2017-09-01 20:13:00 +00:00
if ( remaining [ itOrbSword ] ) items [ itOrbSword ] + + ;
if ( remaining [ itOrbSword2 ] ) items [ itOrbSword2 ] + + ;
gamescreen ( 2 ) ;
if ( remaining [ itOrbSword ] ) items [ itOrbSword ] - - ;
if ( remaining [ itOrbSword2 ] ) items [ itOrbSword2 ] - - ;
cmode = sm : : CENTER ;
orbcoord . clear ( ) ;
2017-10-10 13:00:38 +00:00
for ( int y = - 3 ; y < = 3 ; y + + ) for ( int x = - 5 ; x < = 5 ; x + + ) if ( x + y < = 5 & & x + y > = - 5 & & ( x | | y ) )
2017-09-01 20:13:00 +00:00
orbcoord . emplace_back ( x , y ) ;
sort ( orbcoord . begin ( ) , orbcoord . end ( ) , [ ] ( pxy p1 , pxy p2 ) {
return sq ( p1 ) < sq ( p2 ) ; } ) ;
ld rad = min ( vid . xres , vid . yres ) / 20 ;
ld rad3 = int ( rad * sqrt ( 3 ) ) ;
compute ( ) ;
orbmap . clear ( ) ;
which = itNone ;
if ( plain ) dialog : : init ( XLAT ( mirroring ? " mirror what? " : " inventory " ) , forecolor , 150 , 100 ) ;
int j = 0 , oc = 6 ;
2019-06-13 15:04:23 +00:00
if ( 1 ) {
2019-08-19 07:39:19 +00:00
dynamicval < eModel > pm ( pmodel , flat_model ( ) ) ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
2019-06-13 15:04:23 +00:00
// dynamicval<videopar> v(vid, vid);
2020-04-16 22:53:58 +00:00
// pconf.alpha = vid.scale = 1;
dynamicval < ld > va ( pconf . alpha , 1 ) ;
dynamicval < ld > vs ( pconf . scale , 1 ) ;
dynamicval < ld > vc ( pconf . camera_angle , 0 ) ;
2019-06-13 15:04:23 +00:00
calcparam ( ) ;
2017-09-01 20:13:00 +00:00
for ( int i = 0 ; i < ittypes ; i + + ) {
eItem o = eItem ( i ) ;
if ( itemclass ( o ) = = IC_ORB ) {
char c = orbkeys [ j + + ] ;
2020-02-26 00:42:04 +00:00
if ( c = = 0 ) println ( hlog , " missing char for " , dnameof ( o ) ) ;
2017-09-01 20:13:00 +00:00
if ( remaining [ i ] | | usedup [ i ] ) {
orbmap [ c ] = o ;
if ( plain )
dialog : : addSelItem ( XLAT1 ( iinf [ o ] . name ) , its ( remaining [ i ] ) , c ) ;
else {
auto pos = orbcoord [ oc + + ] ;
2018-11-17 18:24:02 +00:00
ld px = current_display - > xcenter + 2 * rad * pos . first + rad * pos . second ;
ld py = current_display - > ycenter + pos . second * rad3 ;
2017-09-01 20:13:00 +00:00
int icol = iinf [ o ] . color ;
if ( ! remaining [ i ] ) icol = gradient ( icol , 0 , 0 , .5 , 1 ) ;
bool gg = graphglyph ( ) ;
if ( ! hiliteclick ) {
if ( gg ) {
initquickqueue ( ) ;
transmatrix V = atscreenpos ( px , py , rad * 2 ) ;
drawItemType ( o , NULL , V , icol , ticks / 3 + i * 137 , false ) ;
quickqueue ( ) ;
}
int tcol = remaining [ i ] ? darkenedby ( icol , 1 ) : 0 ;
if ( remaining [ i ] ! = 1 | | ! gg )
displaystr ( px , py , 2 , gg ? rad : rad * 3 / 2 , remaining [ i ] < = 0 ? " X " : remaining [ i ] = = 1 ? " o " : its ( remaining [ i ] ) , tcol , 8 ) ;
}
bool b = hypot ( mousex - px , mousey - py ) < rad ;
if ( b ) {
getcstat = c ,
which = o ;
}
}
}
}
}
2019-06-13 15:04:23 +00:00
}
2017-09-01 20:13:00 +00:00
if ( plain ) {
dialog : : addBreak ( 750 ) ;
dialog : : addItem ( XLAT ( " help " ) , SDLK_F1 ) ;
dialog : : addItem ( XLAT ( " return to the game " ) , ' i ' ) ;
dialog : : display ( ) ;
which = orbmap [ getcstat ] ;
}
else {
if ( which = = itNone ) {
displaystr ( vid . xres / 2 , vid . fsize * 2 , 2 , vid . fsize * 2 , XLAT ( " Which orb to use? " ) , 0xC0C0C0 , 8 ) ;
}
else {
int icol = iinf [ which ] . color ;
displaystr ( vid . xres / 2 , vid . fsize * 2 , 2 , vid . fsize * 2 , XLAT1 ( iinf [ which ] . name ) , icol , 8 ) ;
if ( mirroring )
displaystr ( vid . xres / 2 , vid . fsize * 4 , 2 , vid . fsize , usedup [ which ] > = TESTMIRRORED ? XLAT ( " already mirrored " ) : XLAT ( " Uses to gain: %1 " , its ( mirrorqty ( which ) ) ) , icol , 8 ) ;
else {
2017-10-10 10:43:41 +00:00
whichorbinfo = which ;
compute ( ) ;
2017-09-01 20:13:00 +00:00
2017-10-10 10:43:41 +00:00
displaystr ( vid . xres / 2 , vid . fsize * 4 , 2 , vid . fsize , orbinfoline , icol , 8 ) ;
if ( extra ! = " " )
displaystr ( vid . xres / 2 , vid . fsize * 5 , 2 , vid . fsize , XLAT ( " Extras: " ) + extra , icol , 8 ) ;
2017-09-01 20:13:00 +00:00
}
if ( remaining [ which ] ! = 1 | | usedup [ which ] ) {
2017-10-10 10:43:41 +00:00
displaystr ( vid . xres / 2 , vid . yres - vid . fsize * 6 , 2 , vid . fsize , osminfo ( which ) , icol , 8 ) ;
2017-09-01 20:13:00 +00:00
}
# if ISMOBILE==0
string hot = XLAT1 ( " Hotkey: " ) ; hot + = getcstat ;
displaystr ( vid . xres / 2 , vid . yres - vid . fsize * 5 , 2 , vid . fsize , hot , icol , 8 ) ;
# endif
2017-10-10 10:43:41 +00:00
2017-10-13 19:28:03 +00:00
eLand pl = getPrizeLand ( ) ;
eOrbLandRelation olr = getOLR ( which , pl ) ;
2017-09-01 20:13:00 +00:00
2018-09-04 17:53:42 +00:00
color_t col = 0 ;
2017-10-13 19:28:03 +00:00
const char * fmsg = NULL ;
if ( olr = = olrDangerous )
col = 0xC00000 ,
fmsg = " Using %the1 in %the2 sounds dangerous... " ;
else if ( olr = = olrUseless )
col = 0xC00000 ,
fmsg = " %The1 is mostly useless in %the2... " ;
else if ( olr = = olrForbidden )
col = 0x804000 ,
fmsg = " %The1 is forbidden in %the2 (disables some achievements) " ;
2017-09-01 20:13:00 +00:00
2017-10-13 19:28:03 +00:00
if ( fmsg )
displaystr ( vid . xres / 2 , vid . yres - vid . fsize * 4 , 2 , vid . fsize , XLAT ( fmsg , which , pl ) , col , 8 ) ;
2017-09-01 20:13:00 +00:00
}
}
dialog : : displayPageButtons ( 3 , 0 ) ;
mouseovers = " " ;
keyhandler = [ ] ( int sym , int uni ) {
if ( plain ) dialog : : handleNavigation ( sym , uni ) ;
if ( orbmap . count ( uni ) ) {
eItem orb = orbmap [ uni ] ;
if ( remaining [ orb ] < = 0 ) ;
else if ( orb = = itOrbMirror ) {
mirroring = ! mirroring ;
// an amusing message
if ( remaining [ itOrbMirror ] > = 2 & & ! mirroring )
addMessage ( XLAT ( " You mirror %the1. " , orb ) ) ;
if ( mirroring ) {
bool next = false ;
2018-08-17 22:46:45 +00:00
forCellEx ( c2 , cwt . at ) if ( c2 - > wall = = waMirror | | c2 - > wall = = waCloud | | c2 - > wall = = waMirrorWall )
2017-09-01 20:13:00 +00:00
next = true ;
if ( ! next ) {
addMessage ( XLAT ( " You need to stand next to a magic mirror or cloud to use %the1. " , itOrbMirror ) ) ;
mirroring = false ;
}
}
}
else if ( mirroring ) {
if ( usedup [ orb ] > = TESTMIRRORED ) {
addMessage ( XLAT ( " Each orb type can be mirrored only once. " ) ) ;
mirroring = false ;
}
else if ( remaining [ orb ] > 0 ) {
usedup [ itOrbMirror ] + + ;
usedup [ orb ] + = MIRRORED ;
usedup [ orb ] - = mirrorqty0 ( orb ) ;
addMessage ( XLAT ( " You mirror %the1. " , orb ) ) ;
mirroring = false ;
}
else mirroring = false ;
}
2018-08-17 22:46:45 +00:00
else if ( ( isHaunted ( cwt . at - > land ) | | cwt . at - > land = = laDungeon ) & & orb = = itOrbSafety ) {
2017-09-01 20:13:00 +00:00
addMessage ( XLAT ( " This would only move you deeper into the trap! " ) ) ;
}
else {
2018-08-17 22:46:45 +00:00
eItem it = cwt . at - > item ;
cwt . at - > item = orbmap [ uni ] ;
2018-01-25 16:23:16 +00:00
inv : : activating = true ;
2018-08-17 22:46:45 +00:00
collectItem ( cwt . at , true ) ;
2018-01-25 16:23:16 +00:00
inv : : activating = false ;
addMessage ( XLAT ( " You activate %the1. " , orbmap [ uni ] ) ) ;
2018-08-17 22:46:45 +00:00
if ( ! cwt . at - > item ) usedup [ orbmap [ uni ] ] + + ;
2017-10-13 19:28:03 +00:00
if ( getOLR ( it , getPrizeLand ( ) ) = = olrForbidden )
2017-09-01 20:13:00 +00:00
usedForbidden = true ;
2018-08-17 22:46:45 +00:00
cwt . at - > item = it ;
2017-09-01 20:13:00 +00:00
evokeOrb ( orbmap [ uni ] ) ;
checkmove ( ) ;
popScreenAll ( ) ;
}
}
else if ( uni = = ' 1 ' ) plain = ! plain ;
else if ( sym = = SDLK_F1 )
2017-10-14 11:07:29 +00:00
gotoHelp ( which ? generateHelpForItem ( which ) : XLAT ( helptext ) ) ;
2017-09-01 20:13:00 +00:00
else if ( doexiton ( sym , uni ) ) {
if ( mirroring ) mirroring = false ;
popScreen ( ) ;
}
} ;
}
2017-12-01 23:31:36 +00:00
# if CAP_SAVE
2019-09-05 10:00:55 +00:00
EX void applyBox ( eItem it ) {
2020-03-27 19:05:58 +00:00
scores : : applyBoxNum ( inv : : usedup [ it ] ) ;
2017-09-01 20:13:00 +00:00
}
2017-12-01 23:31:36 +00:00
# endif
2017-09-01 20:13:00 +00:00
2019-08-09 20:07:03 +00:00
EX int incheck ;
2017-09-01 20:13:00 +00:00
2019-08-09 20:07:03 +00:00
EX void check ( int delta ) {
2017-09-01 20:13:00 +00:00
incheck + = delta ;
for ( int i = 0 ; i < ittypes ; i + + ) {
eItem it = eItem ( i ) ;
if ( itemclass ( it ) = = IC_ORB )
items [ it ] + = delta * remaining [ it ] * orbcharges ( it ) ;
}
}
2019-09-06 07:17:45 +00:00
# endif
2019-09-13 01:10:26 +00:00
# if !CAP_INV
EX always_false on , activating ;
# endif
EX }
}