2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 18:09:57 -04:00
# include "FurnaceRecipe.h"
# include "Item.h"
2012-06-14 09:06:06 -04:00
# include <fstream>
2014-06-21 15:33:23 -04:00
2016-11-07 17:15:07 -05:00
# define FURNACE_RECIPE_FILE FILE_IO_PREFIX "furnace.txt"
2012-06-14 09:06:06 -04:00
2014-08-31 13:00:36 -04:00
typedef std : : list < cFurnaceRecipe : : cRecipe > RecipeList ;
typedef std : : list < cFurnaceRecipe : : cFuel > FuelList ;
2012-06-14 09:06:06 -04:00
struct cFurnaceRecipe : : sFurnaceRecipeState
{
RecipeList Recipes ;
FuelList Fuel ;
} ;
cFurnaceRecipe : : cFurnaceRecipe ( )
2014-08-31 13:00:36 -04:00
: m_pState ( new sFurnaceRecipeState )
2012-06-14 09:06:06 -04:00
{
ReloadRecipes ( ) ;
}
cFurnaceRecipe : : ~ cFurnaceRecipe ( )
{
ClearRecipes ( ) ;
delete m_pState ;
2014-10-20 16:55:07 -04:00
m_pState = nullptr ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
void cFurnaceRecipe : : ReloadRecipes ( void )
2012-06-14 09:06:06 -04:00
{
ClearRecipes ( ) ;
2013-09-28 15:36:01 -04:00
LOGD ( " Loading furnace recipes... " ) ;
2012-06-14 09:06:06 -04:00
2014-06-21 19:06:58 -04:00
std : : ifstream f ( FURNACE_RECIPE_FILE , std : : ios : : in ) ;
2013-06-16 16:24:07 -04:00
if ( ! f . good ( ) )
2012-06-14 09:06:06 -04:00
{
2014-06-26 12:18:41 -04:00
LOG ( " Could not open the furnace recipes file \" %s \" . No furnace recipes are available. " , FURNACE_RECIPE_FILE ) ;
2012-06-14 09:06:06 -04:00
return ;
}
2016-02-05 16:45:45 -05:00
2014-06-26 12:18:41 -04:00
unsigned int LineNum = 0 ;
2014-06-21 15:33:23 -04:00
AString ParsingLine ;
2012-06-14 09:06:06 -04:00
2014-06-21 19:06:58 -04:00
while ( std : : getline ( f , ParsingLine ) )
2012-06-14 09:06:06 -04:00
{
2014-06-26 12:18:41 -04:00
LineNum + + ;
2014-06-21 15:33:23 -04:00
if ( ParsingLine . empty ( ) )
2012-06-14 09:06:06 -04:00
{
2016-11-07 17:15:07 -05:00
// There is a problem here on Android. Text files transferred from another OS may have a newline representation Android's implementation of getline doesn't expect
// Thus, part of a newline may be left in ParsingLine. ::empty() thus thinks the string isn't empty, and the below code outputs interesting errors since it was passed a nearly empty string
2017-08-24 05:19:40 -04:00
// Ref: https://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
2016-11-07 17:15:07 -05:00
// TODO: There is a solution in the above reference, but it isn't very pretty. Fix it somehow.
2012-06-14 09:06:06 -04:00
continue ;
}
2014-08-31 13:00:36 -04:00
// Remove comments from the line:
size_t FirstCommentSymbol = ParsingLine . find ( ' # ' ) ;
if ( ( FirstCommentSymbol ! = AString : : npos ) & & ( FirstCommentSymbol ! = 0 ) )
{
2015-05-24 07:56:56 -04:00
ParsingLine . erase ( ParsingLine . begin ( ) + static_cast < const long > ( FirstCommentSymbol ) , ParsingLine . end ( ) ) ;
2014-08-31 13:00:36 -04:00
}
2014-06-26 11:51:19 -04:00
switch ( ParsingLine [ 0 ] )
2013-06-16 16:24:07 -04:00
{
2014-06-26 11:51:19 -04:00
case ' # ' :
2012-06-14 09:06:06 -04:00
{
2014-06-26 11:51:19 -04:00
// Comment
break ;
2012-06-14 09:06:06 -04:00
}
2014-06-26 11:51:19 -04:00
case ' ! ' :
{
2014-06-26 12:18:41 -04:00
AddFuelFromLine ( ParsingLine , LineNum ) ;
2014-06-26 11:51:19 -04:00
break ;
2014-06-21 15:33:23 -04:00
}
2014-06-26 11:51:19 -04:00
default :
{
2014-06-26 12:18:41 -04:00
AddRecipeFromLine ( ParsingLine , LineNum ) ;
2014-06-26 11:51:19 -04:00
break ;
}
} // switch (ParsingLine[0])
} // while (getline(ParsingLine))
2012-06-14 09:06:06 -04:00
2018-01-03 12:41:16 -05:00
LOG ( " Loaded %zu furnace recipes and %zu fuels " , m_pState - > Recipes . size ( ) , m_pState - > Fuel . size ( ) ) ;
2014-06-21 15:33:23 -04:00
}
2012-06-14 09:06:06 -04:00
2014-06-21 15:33:23 -04:00
2014-08-31 14:53:41 -04:00
void cFurnaceRecipe : : AddFuelFromLine ( const AString & a_Line , unsigned int a_LineNum )
2014-06-26 12:18:41 -04:00
{
2014-08-31 13:00:36 -04:00
AString Line ( a_Line ) ;
Line . erase ( Line . begin ( ) ) ; // Remove the beginning "!"
Line . erase ( std : : remove_if ( Line . begin ( ) , Line . end ( ) , isspace ) , Line . end ( ) ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cItem > Item = cpp14 : : make_unique < cItem > ( ) ;
2014-08-31 13:00:36 -04:00
int BurnTime ;
const AStringVector & Sides = StringSplit ( Line , " = " ) ;
if ( Sides . size ( ) ! = 2 )
2014-06-26 12:18:41 -04:00
{
2018-01-03 12:41:16 -05:00
LOGWARNING ( " furnace.txt: line %d: A single '=' was expected, got %zu " , a_LineNum , Sides . size ( ) - 1 ) ;
2014-08-31 13:00:36 -04:00
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
2014-06-26 12:18:41 -04:00
return ;
}
2014-08-31 13:00:36 -04:00
if ( ! ParseItem ( Sides [ 0 ] , * Item ) )
{
LOGWARNING ( " furnace.txt: line %d: Cannot parse item \" %s \" . " , a_LineNum , Sides [ 0 ] . c_str ( ) ) ;
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
return ;
}
2014-06-26 12:18:41 -04:00
2014-08-31 13:00:36 -04:00
if ( ! StringToInteger < int > ( Sides [ 1 ] , BurnTime ) )
2014-06-26 12:18:41 -04:00
{
2014-08-31 13:00:36 -04:00
LOGWARNING ( " furnace.txt: line %d: Cannot parse burn time. " , a_LineNum ) ;
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
2014-06-26 12:18:41 -04:00
return ;
}
2014-08-31 13:00:36 -04:00
// Add to fuel list:
cFuel Fuel ;
2014-08-31 16:04:52 -04:00
Fuel . In = Item . release ( ) ;
2014-08-31 13:00:36 -04:00
Fuel . BurnTime = BurnTime ;
m_pState - > Fuel . push_back ( Fuel ) ;
2014-06-26 12:18:41 -04:00
}
2014-08-31 14:53:41 -04:00
void cFurnaceRecipe : : AddRecipeFromLine ( const AString & a_Line , unsigned int a_LineNum )
2014-06-21 15:33:23 -04:00
{
2014-08-31 13:00:36 -04:00
AString Line ( a_Line ) ;
Line . erase ( std : : remove_if ( Line . begin ( ) , Line . end ( ) , isspace ) , Line . end ( ) ) ;
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
int CookTime = 200 ;
2018-04-11 02:46:11 -04:00
float Reward = 0 ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cItem > InputItem = cpp14 : : make_unique < cItem > ( ) ;
std : : unique_ptr < cItem > OutputItem = cpp14 : : make_unique < cItem > ( ) ;
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
const AStringVector & Sides = StringSplit ( Line , " = " ) ;
if ( Sides . size ( ) ! = 2 )
{
2018-01-03 12:41:16 -05:00
LOGWARNING ( " furnace.txt: line %d: A single '=' was expected, got %zu " , a_LineNum , Sides . size ( ) - 1 ) ;
2014-08-31 13:00:36 -04:00
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
return ;
}
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
const AStringVector & InputSplit = StringSplit ( Sides [ 0 ] , " @ " ) ;
if ( ! ParseItem ( InputSplit [ 0 ] , * InputItem ) )
2014-06-21 15:33:23 -04:00
{
2014-08-31 13:00:36 -04:00
LOGWARNING ( " furnace.txt: line %d: Cannot parse input item \" %s \" . " , a_LineNum , InputSplit [ 0 ] . c_str ( ) ) ;
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
return ;
2014-06-21 15:33:23 -04:00
}
2014-08-31 13:00:36 -04:00
if ( InputSplit . size ( ) > 1 )
2014-06-21 15:33:23 -04:00
{
2014-08-31 13:00:36 -04:00
if ( ! StringToInteger < int > ( InputSplit [ 1 ] , CookTime ) )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
LOGWARNING ( " furnace.txt: line %d: Cannot parse cook time \" %s \" . " , a_LineNum , InputSplit [ 1 ] . c_str ( ) ) ;
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
return ;
2012-06-14 09:06:06 -04:00
}
}
2018-04-11 02:46:11 -04:00
const AStringVector & OutputSplit = StringSplit ( Sides [ 1 ] , " $ " ) ;
if ( ! ParseItem ( OutputSplit [ 0 ] , * OutputItem ) )
2012-06-14 09:06:06 -04:00
{
2018-04-11 02:46:11 -04:00
LOGWARNING ( " furnace.txt: line %d: Cannot parse output item \" %s \" . " , a_LineNum , OutputSplit [ 0 ] . c_str ( ) ) ;
2014-08-31 13:00:36 -04:00
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
return ;
2012-06-14 09:06:06 -04:00
}
2018-04-11 02:46:11 -04:00
if ( OutputSplit . size ( ) > 1 )
{
if ( ! StringToFloat ( OutputSplit [ 1 ] , Reward ) )
{
LOGWARNING ( " furnace.txt: line %d: Cannot parse reward \" %s \" . " , a_LineNum , OutputSplit [ 1 ] . c_str ( ) ) ;
LOGINFO ( " Offending line: \" %s \" " , a_Line . c_str ( ) ) ;
return ;
}
}
2014-08-31 13:00:36 -04:00
cRecipe Recipe ;
2014-08-31 16:04:52 -04:00
Recipe . In = InputItem . release ( ) ;
Recipe . Out = OutputItem . release ( ) ;
2014-08-31 13:00:36 -04:00
Recipe . CookTime = CookTime ;
2018-04-11 02:46:11 -04:00
Recipe . Reward = Reward ;
2014-08-31 13:00:36 -04:00
m_pState - > Recipes . push_back ( Recipe ) ;
2014-06-21 15:33:23 -04:00
}
2014-08-31 13:00:36 -04:00
bool cFurnaceRecipe : : ParseItem ( const AString & a_String , cItem & a_Item )
2014-06-21 15:33:23 -04:00
{
2014-08-31 13:00:36 -04:00
AString ItemString = a_String ;
2016-02-05 16:45:45 -05:00
2014-08-31 13:00:36 -04:00
const AStringVector & SplitAmount = StringSplit ( ItemString , " , " ) ;
ItemString = SplitAmount [ 0 ] ;
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
const AStringVector & SplitMeta = StringSplit ( ItemString , " : " ) ;
ItemString = SplitMeta [ 0 ] ;
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
if ( ! StringToItem ( ItemString , a_Item ) )
{
return false ;
}
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
if ( SplitAmount . size ( ) > 1 )
{
if ( ! StringToInteger < char > ( SplitAmount [ 1 ] . c_str ( ) , a_Item . m_ItemCount ) )
2014-06-21 15:33:23 -04:00
{
2014-08-31 13:00:36 -04:00
return false ;
2014-06-21 15:33:23 -04:00
}
2012-06-14 09:06:06 -04:00
}
2014-06-21 15:33:23 -04:00
2014-08-31 13:00:36 -04:00
if ( SplitMeta . size ( ) > 1 )
{
if ( ! StringToInteger < short > ( SplitMeta [ 1 ] . c_str ( ) , a_Item . m_ItemDamage ) )
{
return false ;
}
}
return true ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
void cFurnaceRecipe : : ClearRecipes ( void )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
for ( RecipeList : : iterator itr = m_pState - > Recipes . begin ( ) ; itr ! = m_pState - > Recipes . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
cRecipe Recipe = * itr ;
delete Recipe . In ;
2014-10-20 16:55:07 -04:00
Recipe . In = nullptr ;
2014-08-31 13:00:36 -04:00
delete Recipe . Out ;
2014-10-20 16:55:07 -04:00
Recipe . Out = nullptr ;
2012-06-14 09:06:06 -04:00
}
m_pState - > Recipes . clear ( ) ;
2013-06-16 16:24:07 -04:00
for ( FuelList : : iterator itr = m_pState - > Fuel . begin ( ) ; itr ! = m_pState - > Fuel . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
cFuel Fuel = * itr ;
delete Fuel . In ;
2014-10-20 16:55:07 -04:00
Fuel . In = nullptr ;
2012-06-14 09:06:06 -04:00
}
m_pState - > Fuel . clear ( ) ;
}
2013-06-16 16:24:07 -04:00
2014-08-31 13:00:36 -04:00
const cFurnaceRecipe : : cRecipe * cFurnaceRecipe : : GetRecipeFrom ( const cItem & a_Ingredient ) const
2012-06-14 09:06:06 -04:00
{
2017-12-21 06:36:58 -05:00
const cRecipe * BestRecipe = nullptr ;
2013-06-16 16:24:07 -04:00
for ( RecipeList : : const_iterator itr = m_pState - > Recipes . begin ( ) ; itr ! = m_pState - > Recipes . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
const cRecipe & Recipe = * itr ;
if ( ( Recipe . In - > m_ItemType = = a_Ingredient . m_ItemType ) & & ( Recipe . In - > m_ItemCount < = a_Ingredient . m_ItemCount ) )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
if ( BestRecipe & & ( BestRecipe - > In - > m_ItemCount > Recipe . In - > m_ItemCount ) )
2012-06-14 09:06:06 -04:00
{
continue ;
}
else
{
2014-08-31 13:00:36 -04:00
BestRecipe = & Recipe ;
2012-06-14 09:06:06 -04:00
}
}
}
return BestRecipe ;
}
2013-06-16 16:24:07 -04:00
2014-12-13 12:49:11 -05:00
bool cFurnaceRecipe : : IsFuel ( const cItem & a_Item ) const
{
2014-12-17 13:14:01 -05:00
for ( auto & Fuel : m_pState - > Fuel )
2014-12-13 12:49:11 -05:00
{
if ( ( Fuel . In - > m_ItemType = = a_Item . m_ItemType ) & & ( Fuel . In - > m_ItemCount < = a_Item . m_ItemCount ) )
{
return true ;
}
}
return false ;
}
2013-06-16 16:24:07 -04:00
int cFurnaceRecipe : : GetBurnTime ( const cItem & a_Fuel ) const
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
int BestFuel = 0 ;
for ( FuelList : : const_iterator itr = m_pState - > Fuel . begin ( ) ; itr ! = m_pState - > Fuel . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
const cFuel & Fuel = * itr ;
if ( ( Fuel . In - > m_ItemType = = a_Fuel . m_ItemType ) & & ( Fuel . In - > m_ItemCount < = a_Fuel . m_ItemCount ) )
2012-06-14 09:06:06 -04:00
{
2014-08-31 13:00:36 -04:00
if ( BestFuel > 0 & & ( BestFuel > Fuel . BurnTime ) )
2012-06-14 09:06:06 -04:00
{
continue ;
}
else
{
2014-08-31 13:00:36 -04:00
BestFuel = Fuel . BurnTime ;
2012-06-14 09:06:06 -04:00
}
}
}
return BestFuel ;
2013-06-16 16:24:07 -04:00
}