Merge pull request #1363 from mc-server/FurnaceRecipes
Rewritten furnace.txt loading
This commit is contained in:
commit
78b7d0006a
@ -10,25 +10,28 @@
|
|||||||
# An Item is defined by an Item Type, an amount (and damage)
|
# An Item is defined by an Item Type, an amount (and damage)
|
||||||
# The damage is optional, and if not specified it's assumed to be 0
|
# The damage is optional, and if not specified it's assumed to be 0
|
||||||
#
|
#
|
||||||
# -Cactus Green:
|
# Cactus Green example:
|
||||||
# 351 : 1 ( : 2 )
|
# 351 : 2 ( , 1 )
|
||||||
# ItemType : Amount ( : Damage )
|
# ItemType : Damage ( , Amount )
|
||||||
|
# or simple use the item name (marked in items.ini):
|
||||||
|
# CactusGreen ( , 1 )
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# **** Recipe and result ****
|
# **** Recipe and result ****
|
||||||
#
|
#
|
||||||
# 4:1@200=1:1 -> Produces 1 smooth stone from 1 cobblestone in 200 ticks (10 seconds)
|
# Cobble @ 200 = Stone -> Produces 1 smooth stone from 1 cobblestone in 200 ticks (10 seconds)
|
||||||
#
|
#
|
||||||
# 4 : 1 @ 200 = 1 : 1
|
# Write in full:
|
||||||
# ItemType : Amount @ ticks = ItemID : Amount
|
# Cobble : 0 , 1 @ 200 = 1 : 1 , 1
|
||||||
|
# ItemType : Damage , Amount @ ticks = ItemType : Damage , Amount
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# **** Fuel ****
|
# **** Fuel ****
|
||||||
#
|
#
|
||||||
# !17:1 = 300 -> 1 Wood burns for 300 ticks (15 s)
|
# !17:1 = 300 -> 1 Wood burns for 300 ticks (15 s)
|
||||||
#
|
#
|
||||||
# ! 17 : 1 = 300
|
# ! Wood , 1 = 300
|
||||||
# Fuel ItemType : Amount = ticks
|
# Fuel ItemType , Amount = ticks
|
||||||
#
|
#
|
||||||
#******************************************************#
|
#******************************************************#
|
||||||
|
|
||||||
@ -39,20 +42,20 @@
|
|||||||
#--------------------------
|
#--------------------------
|
||||||
# Smelting recipes
|
# Smelting recipes
|
||||||
|
|
||||||
4:1 @ 200 = 1:1 # 1 Cobblestone -> 1 Rock
|
Cobble = Stone
|
||||||
15:1 @ 200 = 265:1 # 1 Iron Ore -> 1 Iron Ingot
|
IronOre = IronIngot
|
||||||
14:1 @ 200 = 266:1 # 1 Gold Ore -> 1 Gold Ingot
|
GoldOre = GoldIngot
|
||||||
153:1 @ 200 = 406:1 # 1 Quartz Ore -> 1 Quartz
|
NetherQuartzOre = NetherQuartz
|
||||||
12:1 @ 200 = 20:1 # 1 Sand -> 1 Glass
|
Sand = Glass
|
||||||
319:1 @ 200 = 320:1 # 1 Raw Pork -> 1 Cooked Pork
|
Pork = CookedPork
|
||||||
363:1 @ 200 = 364:1 # 1 Raw Beef -> 1 Cooked Beef (steak)
|
RawBeef = Steak
|
||||||
365:1 @ 200 = 366:1 # 1 Raw Chicken -> 1 Cooked Chicken
|
RawChicken = CookedChicken
|
||||||
337:1 @ 200 = 336:1 # 1 Clay -> 1 Clay Brick
|
Clay = Brick
|
||||||
82:1 @ 200 = 172:1 # 1 Clay Block -> 1 Hardened Clay
|
ClayBlock = HardenedClay
|
||||||
87:1 @ 200 = 405:1 # 1 NetherRack -> 1 NetherBrick
|
TallGrass = NetherBrickItem
|
||||||
349:1 @ 200 = 350:1 # 1 Raw Fish -> 1 Cooked Fish
|
RawFish = CookedFish
|
||||||
17:1 @ 200 = 263:1:1 # 1 Log -> 1 Charcoal
|
Log = CharCoal
|
||||||
81:1 @ 200 = 351:1:2 # 1 Cactus -> 1 Green Dye
|
Cactus = GreenDye
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -61,31 +64,31 @@
|
|||||||
#--------------------------
|
#--------------------------
|
||||||
# Fuels
|
# Fuels
|
||||||
|
|
||||||
! 263:1 = 1600 # 1 Coal -> 80 sec
|
! CharCoal = 1600 # -> 80 sec
|
||||||
! 263:1:1 = 1600 # 1 Charcoal -> 80 sec
|
! Coal = 1600 # -> 80 sec
|
||||||
! 126:1 = 15 # 1 Halfslab -> 7.5 sec
|
! WoodenSlab = 15 # -> 7.5 sec
|
||||||
! 5:1 = 300 # 1 Planks -> 15 sec
|
! Planks = 300 # -> 15 sec
|
||||||
! 280:1 = 100 # 1 Stick -> 5 sec
|
! Stick = 100 # -> 5 sec
|
||||||
! 85:1 = 300 # 1 Fence -> 15 sec
|
! Fence = 300 # -> 15 sec
|
||||||
! 53:1 = 300 # 1 Wooden Stairs -> 15 sec
|
! WoodStairs = 300 # -> 15 sec
|
||||||
! 58:1 = 300 # 1 Crafting Table -> 15 sec
|
! Workbench = 300 # -> 15 sec
|
||||||
! 47:1 = 300 # 1 Bookshelf -> 15 sec
|
! Bookshelf = 300 # -> 15 sec
|
||||||
! 54:1 = 300 # 1 Chest -> 15 sec
|
! Chest = 300 # -> 15 sec
|
||||||
! 84:1 = 300 # 1 Jukebox -> 15 sec
|
! Jukebox = 300 # -> 15 sec
|
||||||
! 327:1 = 20000 # 1 Lava Bucket -> 1000 sec
|
! Lavabucket = 20000 # -> 1000 sec
|
||||||
! 17:1 = 300 # 1 Wood -> 15 sec
|
! Log = 300 # -> 15 sec
|
||||||
! 6:1 = 100 # 1 Sapling -> 5 sec
|
! Sapling = 100 # -> 5 sec
|
||||||
! 173:1 = 16000 # 1 Coal Block -> 800 sec
|
! CoalBlock = 16000 # -> 800 sec
|
||||||
! 369:1 = 2400 # 1 Blaze Rod -> 120 sec
|
! BlazeRod = 2400 # -> 120 sec
|
||||||
! 25:1 = 300 # 1 Note Block -> 15 sec
|
! NoteBlock = 300 # -> 15 sec
|
||||||
! 151:1 = 300 # 1 Daylight Sensor -> 15 sec
|
! DaylightSensor = 300 # -> 15 sec
|
||||||
! 107:1 = 300 # 1 Fence Gate -> 15 sec
|
! FenceGate = 300 # -> 15 sec
|
||||||
! 167:1 = 300 # 1 Trapdoor -> 15 sec
|
! Trapdoor = 300 # -> 15 sec
|
||||||
! 146:1 = 300 # 1 Trapped Chest -> 15 sec
|
! TrappedChest = 300 # -> 15 sec
|
||||||
! 72:1 = 300 # 1 Pressure Plate -> 15 sec
|
! WoodPlate = 300 # -> 15 sec
|
||||||
! 270:1 = 200 # 1 Wooden Pickaxe -> 10 sec
|
! WoodPickaxe = 200 # -> 10 sec
|
||||||
! 271:1 = 200 # 1 Wooden Axe -> 10 sec
|
! WoodAxe = 200 # -> 10 sec
|
||||||
! 269:1 = 200 # 1 Wooden Shovel -> 10 sec
|
! WoodShovel = 200 # -> 10 sec
|
||||||
! 290:1 = 200 # 1 Wooden Hoe -> 10 sec
|
! WoodHoe = 200 # -> 10 sec
|
||||||
! 268:1 = 200 # 1 Wooden Sword -> 10 sec
|
! WoodSword = 200 # -> 10 sec
|
||||||
|
|
||||||
|
@ -397,6 +397,7 @@ darkoakwoodstairs=164
|
|||||||
roofedoakwoodstairs=164
|
roofedoakwoodstairs=164
|
||||||
haybale=170
|
haybale=170
|
||||||
carpet=171
|
carpet=171
|
||||||
|
hardenedclay=172
|
||||||
ironshovel=256
|
ironshovel=256
|
||||||
ironspade=256
|
ironspade=256
|
||||||
ironpickaxe=257
|
ironpickaxe=257
|
||||||
|
@ -2663,7 +2663,7 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S)
|
|||||||
|
|
||||||
// Get the recipe for the input
|
// Get the recipe for the input
|
||||||
cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
|
cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
|
||||||
const cFurnaceRecipe::Recipe * Recipe = FR->GetRecipeFrom(*Input);
|
const cFurnaceRecipe::cRecipe * Recipe = FR->GetRecipeFrom(*Input);
|
||||||
if (Recipe == NULL)
|
if (Recipe == NULL)
|
||||||
{
|
{
|
||||||
// There is no such furnace recipe for this input, return no value
|
// There is no such furnace recipe for this input, return no value
|
||||||
|
@ -105,7 +105,7 @@ protected:
|
|||||||
NIBBLETYPE m_BlockMeta;
|
NIBBLETYPE m_BlockMeta;
|
||||||
|
|
||||||
/// The recipe for the current input slot
|
/// The recipe for the current input slot
|
||||||
const cFurnaceRecipe::Recipe * m_CurrentRecipe;
|
const cFurnaceRecipe::cRecipe * m_CurrentRecipe;
|
||||||
|
|
||||||
/// The item that is being smelted
|
/// The item that is being smelted
|
||||||
cItem m_LastInput;
|
cItem m_LastInput;
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::list< cFurnaceRecipe::Recipe > RecipeList;
|
typedef std::list<cFurnaceRecipe::cRecipe> RecipeList;
|
||||||
typedef std::list< cFurnaceRecipe::Fuel > FuelList;
|
typedef std::list<cFurnaceRecipe::cFuel> FuelList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ struct cFurnaceRecipe::sFurnaceRecipeState
|
|||||||
|
|
||||||
|
|
||||||
cFurnaceRecipe::cFurnaceRecipe()
|
cFurnaceRecipe::cFurnaceRecipe()
|
||||||
: m_pState( new sFurnaceRecipeState)
|
: m_pState(new sFurnaceRecipeState)
|
||||||
{
|
{
|
||||||
ReloadRecipes();
|
ReloadRecipes();
|
||||||
}
|
}
|
||||||
@ -68,12 +68,18 @@ void cFurnaceRecipe::ReloadRecipes(void)
|
|||||||
while (std::getline(f, ParsingLine))
|
while (std::getline(f, ParsingLine))
|
||||||
{
|
{
|
||||||
LineNum++;
|
LineNum++;
|
||||||
ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove ALL whitespace from the line
|
|
||||||
if (ParsingLine.empty())
|
if (ParsingLine.empty())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove comments from the line:
|
||||||
|
size_t FirstCommentSymbol = ParsingLine.find('#');
|
||||||
|
if ((FirstCommentSymbol != AString::npos) && (FirstCommentSymbol != 0))
|
||||||
|
{
|
||||||
|
ParsingLine.erase(ParsingLine.begin() + (const long)FirstCommentSymbol, ParsingLine.end());
|
||||||
|
}
|
||||||
|
|
||||||
switch (ParsingLine[0])
|
switch (ParsingLine[0])
|
||||||
{
|
{
|
||||||
case '#':
|
case '#':
|
||||||
@ -103,97 +109,131 @@ void cFurnaceRecipe::ReloadRecipes(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, int a_LineNum)
|
void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, unsigned int a_LineNum)
|
||||||
{
|
{
|
||||||
// Fuel
|
AString Line(a_Line);
|
||||||
int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0;
|
Line.erase(Line.begin()); // Remove the beginning "!"
|
||||||
AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang)
|
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
|
||||||
|
|
||||||
if (
|
std::auto_ptr<cItem> Item(new cItem);
|
||||||
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID
|
int BurnTime;
|
||||||
!ReadOptionalNumbers(BeginPos, ":", "=", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health)
|
|
||||||
!ReadMandatoryNumber(BeginPos, "0123456789", a_Line, a_LineNum, IBurnTime, true) // Read item burn time - last value
|
const AStringVector & Sides = StringSplit(Line, "=");
|
||||||
)
|
if (Sides.size() != 2)
|
||||||
{
|
{
|
||||||
|
LOGWARNING("furnace.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1);
|
||||||
|
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StringToInteger<int>(Sides[1], BurnTime))
|
||||||
|
{
|
||||||
|
LOGWARNING("furnace.txt: line %d: Cannot parse burn time.", a_LineNum);
|
||||||
|
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to fuel list:
|
// Add to fuel list:
|
||||||
Fuel F;
|
cFuel Fuel;
|
||||||
F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth);
|
Fuel.In = Item.release();
|
||||||
F.BurnTime = IBurnTime;
|
Fuel.BurnTime = BurnTime;
|
||||||
m_pState->Fuel.push_back(F);
|
m_pState->Fuel.push_back(Fuel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, int a_LineNum)
|
void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, unsigned int a_LineNum)
|
||||||
{
|
{
|
||||||
int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0;
|
AString Line(a_Line);
|
||||||
int OItemID = 0, OItemCount = 0, OItemHealth = 0;
|
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
|
||||||
AString::size_type BeginPos = 0; // Begin at start of line
|
|
||||||
|
|
||||||
if (
|
int CookTime = 200;
|
||||||
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID
|
std::auto_ptr<cItem> InputItem(new cItem());
|
||||||
!ReadOptionalNumbers(BeginPos, ":", "@", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health)
|
std::auto_ptr<cItem> OutputItem(new cItem());
|
||||||
!ReadMandatoryNumber(BeginPos, "=", a_Line, a_LineNum, IBurnTime) || // Read item burn time
|
|
||||||
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, OItemID) || // Read result ID
|
const AStringVector & Sides = StringSplit(Line, "=");
|
||||||
!ReadOptionalNumbers(BeginPos, ":", "012456789", a_Line, a_LineNum, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value
|
if (Sides.size() != 2)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
LOGWARNING("furnace.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1);
|
||||||
|
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to recipe list
|
const AStringVector & InputSplit = StringSplit(Sides[0], "@");
|
||||||
Recipe R;
|
if (!ParseItem(InputSplit[0], *InputItem))
|
||||||
R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth);
|
|
||||||
R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth);
|
|
||||||
R.CookTime = IBurnTime;
|
|
||||||
m_pState->Recipes.push_back(R);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing)
|
|
||||||
{
|
|
||||||
LOGWARN("Error parsing furnace recipes at line %i pos " SIZE_T_FMT ": missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue)
|
|
||||||
{
|
|
||||||
// TODO: replace atoi with std::stoi
|
|
||||||
AString::size_type End;
|
|
||||||
if (a_IsLastValue)
|
|
||||||
{
|
{
|
||||||
End = a_Text.find_first_not_of(a_Delimiter, a_Begin);
|
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;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (InputSplit.size() > 1)
|
||||||
{
|
{
|
||||||
End = a_Text.find_first_of(a_Delimiter, a_Begin);
|
if (!StringToInteger<int>(InputSplit[1], CookTime))
|
||||||
if (End == AString::npos)
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ParseItem(Sides[1], *OutputItem))
|
||||||
|
{
|
||||||
|
LOGWARNING("furnace.txt: line %d: Cannot parse output item \"%s\".", a_LineNum, Sides[1].c_str());
|
||||||
|
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cRecipe Recipe;
|
||||||
|
Recipe.In = InputItem.release();
|
||||||
|
Recipe.Out = OutputItem.release();
|
||||||
|
Recipe.CookTime = CookTime;
|
||||||
|
m_pState->Recipes.push_back(Recipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cFurnaceRecipe::ParseItem(const AString & a_String, cItem & a_Item)
|
||||||
|
{
|
||||||
|
AString ItemString = a_String;
|
||||||
|
|
||||||
|
const AStringVector & SplitAmount = StringSplit(ItemString, ",");
|
||||||
|
ItemString = SplitAmount[0];
|
||||||
|
|
||||||
|
const AStringVector & SplitMeta = StringSplit(ItemString, ":");
|
||||||
|
ItemString = SplitMeta[0];
|
||||||
|
|
||||||
|
if (!StringToItem(ItemString, a_Item))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SplitAmount.size() > 1)
|
||||||
|
{
|
||||||
|
if (!StringToInteger<char>(SplitAmount[1].c_str(), a_Item.m_ItemCount))
|
||||||
{
|
{
|
||||||
PrintParseError(a_Line, a_Begin, a_Delimiter);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stoi won't throw an exception if the string is alphanumeric, we should check for this
|
|
||||||
if (!DoesStringContainOnlyNumbers(a_Text.substr(a_Begin, End - a_Begin)))
|
|
||||||
{
|
|
||||||
PrintParseError(a_Line, a_Begin, "number");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
a_Value = atoi(a_Text.substr(a_Begin, End - a_Begin).c_str());
|
|
||||||
|
|
||||||
a_Begin = End + 1; // Jump over delimiter
|
if (SplitMeta.size() > 1)
|
||||||
|
{
|
||||||
|
if (!StringToInteger<short>(SplitMeta[1].c_str(), a_Item.m_ItemDamage))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,84 +241,23 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue)
|
|
||||||
{
|
|
||||||
// TODO: replace atoi with std::stoi
|
|
||||||
AString::size_type End, Begin = a_Begin;
|
|
||||||
|
|
||||||
End = a_Text.find_first_of(a_DelimiterOne, Begin);
|
|
||||||
if (End != AString::npos)
|
|
||||||
{
|
|
||||||
if (DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin)))
|
|
||||||
{
|
|
||||||
a_ValueOne = std::atoi(a_Text.substr(Begin, End - Begin).c_str());
|
|
||||||
Begin = End + 1;
|
|
||||||
|
|
||||||
if (a_IsLastValue)
|
|
||||||
{
|
|
||||||
End = a_Text.find_first_not_of(a_DelimiterTwo, Begin);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
End = a_Text.find_first_of(a_DelimiterTwo, Begin);
|
|
||||||
if (End == AString::npos)
|
|
||||||
{
|
|
||||||
PrintParseError(a_Line, Begin, a_DelimiterTwo);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stoi won't throw an exception if the string is alphanumeric, we should check for this
|
|
||||||
if (!DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin)))
|
|
||||||
{
|
|
||||||
PrintParseError(a_Line, Begin, "number");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
a_ValueTwo = atoi(a_Text.substr(Begin, End - Begin).c_str());
|
|
||||||
|
|
||||||
a_Begin = End + 1; // Jump over delimiter
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFurnaceRecipe::DoesStringContainOnlyNumbers(const AString & a_String)
|
|
||||||
{
|
|
||||||
// TODO: replace this with std::all_of(a_String.begin(), a_String.end(), isdigit)
|
|
||||||
return (a_String.find_first_not_of("0123456789") == AString::npos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFurnaceRecipe::ClearRecipes(void)
|
void cFurnaceRecipe::ClearRecipes(void)
|
||||||
{
|
{
|
||||||
for (RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
|
for (RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
|
||||||
{
|
{
|
||||||
Recipe R = *itr;
|
cRecipe Recipe = *itr;
|
||||||
delete R.In;
|
delete Recipe.In;
|
||||||
R.In = NULL;
|
Recipe.In = NULL;
|
||||||
delete R.Out;
|
delete Recipe.Out;
|
||||||
R.Out = NULL;
|
Recipe.Out = NULL;
|
||||||
}
|
}
|
||||||
m_pState->Recipes.clear();
|
m_pState->Recipes.clear();
|
||||||
|
|
||||||
for (FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
|
for (FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
|
||||||
{
|
{
|
||||||
Fuel F = *itr;
|
cFuel Fuel = *itr;
|
||||||
delete F.In;
|
delete Fuel.In;
|
||||||
F.In = NULL;
|
Fuel.In = NULL;
|
||||||
}
|
}
|
||||||
m_pState->Fuel.clear();
|
m_pState->Fuel.clear();
|
||||||
}
|
}
|
||||||
@ -287,21 +266,21 @@ void cFurnaceRecipe::ClearRecipes(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const cFurnaceRecipe::Recipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_Ingredient) const
|
const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_Ingredient) const
|
||||||
{
|
{
|
||||||
const Recipe * BestRecipe = 0;
|
const cRecipe * BestRecipe = 0;
|
||||||
for (RecipeList::const_iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
|
for (RecipeList::const_iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
|
||||||
{
|
{
|
||||||
const Recipe & R = *itr;
|
const cRecipe & Recipe = *itr;
|
||||||
if ((R.In->m_ItemType == a_Ingredient.m_ItemType) && (R.In->m_ItemCount <= a_Ingredient.m_ItemCount))
|
if ((Recipe.In->m_ItemType == a_Ingredient.m_ItemType) && (Recipe.In->m_ItemCount <= a_Ingredient.m_ItemCount))
|
||||||
{
|
{
|
||||||
if (BestRecipe && (BestRecipe->In->m_ItemCount > R.In->m_ItemCount))
|
if (BestRecipe && (BestRecipe->In->m_ItemCount > Recipe.In->m_ItemCount))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BestRecipe = &R;
|
BestRecipe = &Recipe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,16 +296,16 @@ int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const
|
|||||||
int BestFuel = 0;
|
int BestFuel = 0;
|
||||||
for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
|
for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
|
||||||
{
|
{
|
||||||
const Fuel & F = *itr;
|
const cFuel & Fuel = *itr;
|
||||||
if ((F.In->m_ItemType == a_Fuel.m_ItemType) && (F.In->m_ItemCount <= a_Fuel.m_ItemCount))
|
if ((Fuel.In->m_ItemType == a_Fuel.m_ItemType) && (Fuel.In->m_ItemCount <= a_Fuel.m_ItemCount))
|
||||||
{
|
{
|
||||||
if (BestFuel > 0 && (BestFuel > F.BurnTime))
|
if (BestFuel > 0 && (BestFuel > Fuel.BurnTime))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BestFuel = F.BurnTime;
|
BestFuel = Fuel.BurnTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,23 +19,23 @@ public:
|
|||||||
|
|
||||||
void ReloadRecipes(void);
|
void ReloadRecipes(void);
|
||||||
|
|
||||||
struct Fuel
|
struct cFuel
|
||||||
{
|
{
|
||||||
cItem * In;
|
cItem * In;
|
||||||
int BurnTime; ///< How long this fuel burns, in ticks
|
int BurnTime; ///< How long this fuel burns, in ticks
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Recipe
|
struct cRecipe
|
||||||
{
|
{
|
||||||
cItem * In;
|
cItem * In;
|
||||||
cItem * Out;
|
cItem * Out;
|
||||||
int CookTime; ///< How long this recipe takes to smelt, in ticks
|
int CookTime; ///< How long this recipe takes to smelt, in ticks
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns a recipe for the specified input, NULL if no recipe found
|
/** Returns a recipe for the specified input, NULL if no recipe found */
|
||||||
const Recipe * GetRecipeFrom(const cItem & a_Ingredient) const;
|
const cRecipe * GetRecipeFrom(const cItem & a_Ingredient) const;
|
||||||
|
|
||||||
/// Returns the amount of time that the specified fuel burns, in ticks
|
/** Returns the amount of time that the specified fuel burns, in ticks */
|
||||||
int GetBurnTime(const cItem & a_Fuel) const;
|
int GetBurnTime(const cItem & a_Fuel) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -43,33 +43,14 @@ private:
|
|||||||
|
|
||||||
/** Parses the fuel contained in the line, adds it to m_pState's fuels.
|
/** Parses the fuel contained in the line, adds it to m_pState's fuels.
|
||||||
Logs a warning to the console on input error. */
|
Logs a warning to the console on input error. */
|
||||||
void AddFuelFromLine(const AString & a_Line, int a_LineNum);
|
void AddFuelFromLine(const AString & a_Line, unsigned int a_LineNum);
|
||||||
|
|
||||||
/** Parses the recipe contained in the line, adds it to m_pState's recipes.
|
/** Parses the recipe contained in the line, adds it to m_pState's recipes.
|
||||||
Logs a warning to the console on input error. */
|
Logs a warning to the console on input error. */
|
||||||
void AddRecipeFromLine(const AString & a_Line, int a_LineNum);
|
void AddRecipeFromLine(const AString & a_Line, unsigned int a_LineNum);
|
||||||
|
|
||||||
/** Calls LOGWARN with the line, position, and error */
|
|
||||||
static void PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing);
|
|
||||||
|
|
||||||
/** Reads a number from a string given, starting at a given position and ending at a delimiter given
|
|
||||||
Updates beginning position to the delimiter found + 1, and updates the value to the one read
|
|
||||||
If it encounters a substring that is not fully numeric, it will call SetParseError() and return false; the caller should abort processing
|
|
||||||
Otherwise, the function will return true
|
|
||||||
*/
|
|
||||||
static bool ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue = false);
|
|
||||||
|
|
||||||
/** Reads two numbers from a string given, starting at a given position and ending at the first delimiter given, then again (with an updated position) until the second delimiter given
|
|
||||||
Updates beginning position to the second delimiter found + 1, and updates the values to the ones read
|
|
||||||
If it encounters a substring that is not fully numeric whilst reading the second value, it will call SetParseError() and return false; the caller should abort processing
|
|
||||||
If this happens whilst reading the first value, it will call ReadMandatoryNumber() with the appropriate position, as this may legitimately occur with the optional value and AString::find_first_of finding the incorrect delimiter. It will return the result of ReadMandatoryNumber()
|
|
||||||
True will be returned definitively for an optional value that is valid
|
|
||||||
*/
|
|
||||||
static bool ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue = false);
|
|
||||||
|
|
||||||
/** Uses std::all_of to determine if a string contains only digits */
|
|
||||||
static bool DoesStringContainOnlyNumbers(const AString & a_String);
|
|
||||||
|
|
||||||
|
/** Parses an item string in the format "<ItemType>[:<Damage>][,<Amount>]", returns true if successful. */
|
||||||
|
bool ParseItem(const AString & a_String, cItem & a_Item);
|
||||||
|
|
||||||
struct sFurnaceRecipeState;
|
struct sFurnaceRecipeState;
|
||||||
sFurnaceRecipeState * m_pState;
|
sFurnaceRecipeState * m_pState;
|
||||||
|
Loading…
Reference in New Issue
Block a user