Added the new recipe parser, parsing the crafting.txt file. Included are a few recipes. The old parser still works, but will be replaced soon.
git-svn-id: http://mc-server.googlecode.com/svn/trunk@549 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
ce5d97d65b
commit
b355bdecce
|
@ -2,6 +2,7 @@ MCServer.exe
|
||||||
MCServer*debug.cmd
|
MCServer*debug.cmd
|
||||||
Plugins
|
Plugins
|
||||||
webadmin
|
webadmin
|
||||||
|
crafting.ini
|
||||||
banned.example.ini
|
banned.example.ini
|
||||||
furnace.txt
|
furnace.txt
|
||||||
groups.example.ini
|
groups.example.ini
|
||||||
|
|
|
@ -458,6 +458,14 @@
|
||||||
RelativePath="..\source\cPiston.h"
|
RelativePath="..\source\cPiston.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\CraftingRecipes.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\CraftingRecipes.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cRecipeChecker.cpp"
|
RelativePath="..\source\cRecipeChecker.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1383,10 +1391,10 @@
|
||||||
RelativePath="..\source\cStairs.h"
|
RelativePath="..\source\cStairs.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cStep.h"
|
RelativePath="..\source\cStep.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cTorch.h"
|
RelativePath="..\source\cTorch.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -356,6 +356,7 @@
|
||||||
<ClCompile Include="..\source\cPiston.cpp" />
|
<ClCompile Include="..\source\cPiston.cpp" />
|
||||||
<ClCompile Include="..\Source\cPluginManager.cpp" />
|
<ClCompile Include="..\Source\cPluginManager.cpp" />
|
||||||
<ClCompile Include="..\source\cPlugin_NewLua.cpp" />
|
<ClCompile Include="..\source\cPlugin_NewLua.cpp" />
|
||||||
|
<ClCompile Include="..\source\CraftingRecipes.cpp" />
|
||||||
<ClCompile Include="..\Source\cRecipeChecker.cpp" />
|
<ClCompile Include="..\Source\cRecipeChecker.cpp" />
|
||||||
<ClCompile Include="..\source\cRedstone.cpp" />
|
<ClCompile Include="..\source\cRedstone.cpp" />
|
||||||
<ClCompile Include="..\source\cRedstoneSimulator.cpp" />
|
<ClCompile Include="..\source\cRedstoneSimulator.cpp" />
|
||||||
|
@ -537,6 +538,7 @@
|
||||||
<ClInclude Include="..\source\cPiston.h" />
|
<ClInclude Include="..\source\cPiston.h" />
|
||||||
<ClInclude Include="..\Source\cPluginManager.h" />
|
<ClInclude Include="..\Source\cPluginManager.h" />
|
||||||
<ClInclude Include="..\source\cPlugin_NewLua.h" />
|
<ClInclude Include="..\source\cPlugin_NewLua.h" />
|
||||||
|
<ClInclude Include="..\source\CraftingRecipes.h" />
|
||||||
<ClInclude Include="..\Source\cRecipeChecker.h" />
|
<ClInclude Include="..\Source\cRecipeChecker.h" />
|
||||||
<ClInclude Include="..\source\cRedstone.h" />
|
<ClInclude Include="..\source\cRedstone.h" />
|
||||||
<ClInclude Include="..\source\cRedstoneSimulator.h" />
|
<ClInclude Include="..\source\cRedstoneSimulator.h" />
|
||||||
|
@ -705,4 +707,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -909,6 +909,7 @@
|
||||||
<ClCompile Include="..\source\FastNBT.cpp">
|
<ClCompile Include="..\source\FastNBT.cpp">
|
||||||
<Filter>Storage</Filter>
|
<Filter>Storage</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\CraftingRecipes.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\source\cServer.h">
|
<ClInclude Include="..\source\cServer.h">
|
||||||
|
@ -1417,6 +1418,8 @@
|
||||||
<ClInclude Include="..\source\FastNBT.h">
|
<ClInclude Include="..\source\FastNBT.h">
|
||||||
<Filter>Storage</Filter>
|
<Filter>Storage</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\cStep.h" />
|
||||||
|
<ClInclude Include="..\source\CraftingRecipes.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\source\AllToLua.pkg">
|
<None Include="..\source\AllToLua.pkg">
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
|
||||||
|
# This file describes the crafting recipes that MCServer knows.
|
||||||
|
# The syntax is as follows:
|
||||||
|
# <Line> = <Recipe>#<Comment>
|
||||||
|
# <Recipe> = <Result> = <Ingredient1> | <Ingredient2> | ... | <IngredientN>
|
||||||
|
# <IngredientN> = <ItemID>, <X1> : <Y1>, <X2> : <Y2>, ..., <Xn> : <Yn>
|
||||||
|
# <ItemID> = <ItemType> [^<DamageValue>]
|
||||||
|
# <Xn>, <Yn> = "1" .. "3", or "*" for any value. "*:*" can be replaced by a single "*".
|
||||||
|
# <Result> = <ItemType> [^<DamageValue>] [, <Count>]
|
||||||
|
#
|
||||||
|
# The Xn, Yn coordinates are a reference to the crafting grid:
|
||||||
|
# 1:1 | 2:1 | 3:1
|
||||||
|
# 1:2 | 2:2 | 3:2
|
||||||
|
# 1:3 | 2:3 | 3:3
|
||||||
|
#
|
||||||
|
# <ItemType> can be either a number, or an item name (checked against items.ini)
|
||||||
|
#
|
||||||
|
# ^<DamageValue> is optional, if not present, any damage value is matched for ingredients and zero is produced for the result
|
||||||
|
#
|
||||||
|
# Ingredients with an asterisk for a coord will not match already matched crafting grid items. This enables simplifying some of the recipes,
|
||||||
|
# e. g. hoe: "Iron, 2:1, *:1"
|
||||||
|
# -- this means "one iron at 2:1, and another one at either 1:1 or 3:1"
|
||||||
|
#
|
||||||
|
# To require multiple items of the same type in a slot, specify the slot number several times:
|
||||||
|
# "Iron, 1:1 2:2, 2:2"
|
||||||
|
# -- this means "take one iron from slot 1:1 and two irons from slot 2:2"
|
||||||
|
# Note that asterisked items cannot require multiple items in a single slot.
|
||||||
|
#
|
||||||
|
# Note that due to technical problems, it is NOT advised to use asterisked ingredients in crossing directions, such as "*:1, "2:*".
|
||||||
|
# The parser may be unable to match such a recipe to the crafting grid!
|
||||||
|
#
|
||||||
|
# Whitespace is optional. Use it reasonably. Please do NOT use Tabs in the middle of lines!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#******************************************************#
|
||||||
|
# Basic Crafts
|
||||||
|
#
|
||||||
|
|
||||||
|
# Need to list each of the four log types, otherwise all logs would get converted into apple planks (^0)
|
||||||
|
Planks ^0, 4 = Log ^0, *
|
||||||
|
Planks ^1, 4 = Log ^1, *
|
||||||
|
Planks ^2, 4 = Log ^2, *
|
||||||
|
Planks ^3, 4 = Log ^3, *
|
||||||
|
Stick, 4 = Planks, 2:2, 2:3
|
||||||
|
Workbench = Planks, 1:1, 1:2, 2:1, 2:2
|
||||||
|
Chest = Planks, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||||
|
Furnace = Cobblestone, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||||
|
Torch, 4 = Stick, 1:2 | Coal, 1:1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#******************************************************#
|
||||||
|
# Food
|
||||||
|
#
|
||||||
|
Bread = Wheat, 1:1, 2:1, 3:1
|
||||||
|
Bowl = Planks, 1:1, 2:2, 3:1
|
||||||
|
MushroomStew = Bowl, * | BrownMushroom, * | RedMushroom, *
|
||||||
|
GoldenApple = RedApple, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||||
|
Cake = MilkBucket, 1:1, 2:1, 3:1 | Sugar, 1:2, 3:2 | Egg, 2:2 | Wheat, 1:3, 2:3, 3:3
|
||||||
|
Cookie = Wheat, *, * | CocoaBeans, *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#******************************************************#
|
||||||
|
# Hoe:
|
||||||
|
#
|
||||||
|
WoodenHoe = Stick, 2:2, 2:3 | Planks, 2:1, *:1
|
||||||
|
StoneHoe = Stick, 2:2, 2:3 | Cobblestone, 2:1, *:1
|
||||||
|
GoldenHoe = Stick, 2:2, 2:3 | GoldIngot, 2:1, *:1
|
||||||
|
IronHoe = Stick, 2:2, 2:3 | IronIngot, 2:1, *:1
|
||||||
|
DiamondHoe = Stick, 2:2, 2:3 | Diamond, 2:1, *:1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#******************************************************#
|
||||||
|
# Color mixing:
|
||||||
|
#
|
||||||
|
OrangeDye, 2 = YellowDye, * | RedDye, *
|
||||||
|
CyanDye, 2 = GreenDye, * | BlueDye, *
|
||||||
|
PurpleDye, 2 = RedDye, * | BlueDye, *
|
||||||
|
GrayDye, 2 = BlackDye, * | WhiteDye, *
|
||||||
|
LtBlueDye, 2 = BlueDye, * | WhiteDye, *
|
||||||
|
PinkDye, 2 = RedDye, * | WhiteDye, *
|
||||||
|
LimeDye, 2 = GreenDye, * | WhiteDye, *
|
||||||
|
MagentaDye, 2 = PurpleDye, * | PinkDye, *
|
||||||
|
LtGrayDye, 2 = GrayDye, * | WhiteDye, *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#******************************************************#
|
||||||
|
# Colored wool:
|
||||||
|
#
|
||||||
|
WhiteWool = Wool, * | BoneMeal, *
|
||||||
|
OrangeWool = Wool, * | OrangeDye, *
|
||||||
|
MagentaWool = Wool, * | MagentaDye, *
|
||||||
|
LightBlueWool = Wool, * | LightBlueDye, *
|
||||||
|
YellowWool = Wool, * | YellowDye, *
|
||||||
|
LimeWool = Wool, * | LimeDye, *
|
||||||
|
PinkWool = Wool, * | PinkDye, *
|
||||||
|
GrayWool = Wool, * | GrayDye, *
|
||||||
|
LightGrayWool = Wool, * | LightGrayDye, *
|
||||||
|
CyanWool = Wool, * | CyanDye, *
|
||||||
|
VioletWool = Wool, * | VioletDye, *
|
||||||
|
BlueWool = Wool, * | BlueDye, *
|
||||||
|
BrownWool = Wool, * | BrownDye, *
|
||||||
|
GreenWool = Wool, * | GreenDye, *
|
||||||
|
RedWool = Wool, * | RedDye, *
|
||||||
|
BlackWool = Wool, * | BlackDye, *
|
92
items.ini
92
items.ini
|
@ -42,6 +42,36 @@ piston=33
|
||||||
pistonextension=34
|
pistonextension=34
|
||||||
cloth=35
|
cloth=35
|
||||||
wool=35
|
wool=35
|
||||||
|
whitewool=35:0
|
||||||
|
orangewool=35:1
|
||||||
|
magentawool=35:2
|
||||||
|
lightbluewool=35:3
|
||||||
|
yellowwool=35:4
|
||||||
|
limewool=35:5
|
||||||
|
lightgreenwool=35:5
|
||||||
|
ltgreenwool=35:5
|
||||||
|
pinkwool=35:6
|
||||||
|
graywool=35:7
|
||||||
|
greywool=35:7
|
||||||
|
darkgraywool=35:7
|
||||||
|
darkgreywool=35:7
|
||||||
|
dkgraywool=35:7
|
||||||
|
dkgreywool=35:7
|
||||||
|
lightgraywool=35:8
|
||||||
|
lightgreywool=35:8
|
||||||
|
ltgraywool=35:8
|
||||||
|
ltgreywool=35:8
|
||||||
|
cyanwool=35:9
|
||||||
|
purplewool=35:10
|
||||||
|
violetwool=35:10
|
||||||
|
bluewool=35:11
|
||||||
|
darkbluewool=35:11
|
||||||
|
brownwool=35:12
|
||||||
|
greenwool=35:13
|
||||||
|
darkgreenwool=35:13
|
||||||
|
dkgreenwool=35:13
|
||||||
|
redwool=35:14
|
||||||
|
blackwool=35:15
|
||||||
flower=37
|
flower=37
|
||||||
rose=38
|
rose=38
|
||||||
brownmushroom=39
|
brownmushroom=39
|
||||||
|
@ -156,18 +186,29 @@ ironaxe=258
|
||||||
flintandsteel=259
|
flintandsteel=259
|
||||||
lighter=259
|
lighter=259
|
||||||
apple=260
|
apple=260
|
||||||
|
redapple=260
|
||||||
bow=261
|
bow=261
|
||||||
arrow=262
|
arrow=262
|
||||||
coal=263
|
coal=263
|
||||||
diamond=264
|
diamond=264
|
||||||
|
ironingot=265
|
||||||
ironbar=265
|
ironbar=265
|
||||||
|
goldingot=266
|
||||||
|
goldeningot=266
|
||||||
goldbar=266
|
goldbar=266
|
||||||
|
goldenbar=266
|
||||||
ironsword=267
|
ironsword=267
|
||||||
|
woodensword=268
|
||||||
woodsword=268
|
woodsword=268
|
||||||
|
woodenshovel=269
|
||||||
woodshovel=269
|
woodshovel=269
|
||||||
|
woodenspade=269
|
||||||
woodspade=269
|
woodspade=269
|
||||||
|
woodenpickaxe=270
|
||||||
woodpickaxe=270
|
woodpickaxe=270
|
||||||
|
woodenpick=270
|
||||||
woodpick=270
|
woodpick=270
|
||||||
|
woodenaxe=271
|
||||||
woodaxe=271
|
woodaxe=271
|
||||||
stonesword=272
|
stonesword=272
|
||||||
stoneshovel=273
|
stoneshovel=273
|
||||||
|
@ -183,23 +224,32 @@ diamondpick=278
|
||||||
diamondaxe=279
|
diamondaxe=279
|
||||||
stick=280
|
stick=280
|
||||||
bowl=281
|
bowl=281
|
||||||
|
mushroomstew=282
|
||||||
bowlwithsoup=282
|
bowlwithsoup=282
|
||||||
soupbowl=282
|
soupbowl=282
|
||||||
soup=282
|
soup=282
|
||||||
|
goldensword=283
|
||||||
goldsword=283
|
goldsword=283
|
||||||
|
goldenshovel=284
|
||||||
goldshovel=284
|
goldshovel=284
|
||||||
|
goldenspade=284
|
||||||
goldspade=284
|
goldspade=284
|
||||||
|
goldenpickaxe=285
|
||||||
goldpickaxe=285
|
goldpickaxe=285
|
||||||
|
goldenpick=285
|
||||||
goldpick=285
|
goldpick=285
|
||||||
|
goldenaxe=286
|
||||||
goldaxe=286
|
goldaxe=286
|
||||||
string=287
|
string=287
|
||||||
feather=288
|
feather=288
|
||||||
gunpowder=289
|
gunpowder=289
|
||||||
woodhoe=290
|
woodhoe=290
|
||||||
|
woodenhoe=290
|
||||||
stonehoe=291
|
stonehoe=291
|
||||||
ironhoe=292
|
ironhoe=292
|
||||||
diamondhoe=293
|
diamondhoe=293
|
||||||
goldhoe=294
|
goldhoe=294
|
||||||
|
goldenhoe=294
|
||||||
seeds=295
|
seeds=295
|
||||||
wheat=296
|
wheat=296
|
||||||
bread=297
|
bread=297
|
||||||
|
@ -219,9 +269,13 @@ diamondhelmet=310
|
||||||
diamondchestplate=311
|
diamondchestplate=311
|
||||||
diamondpants=312
|
diamondpants=312
|
||||||
diamondboots=313
|
diamondboots=313
|
||||||
|
goldenhelmet=314
|
||||||
goldhelmet=314
|
goldhelmet=314
|
||||||
|
goldenchestplate=315
|
||||||
goldchestplate=315
|
goldchestplate=315
|
||||||
|
goldenpants=316
|
||||||
goldpants=316
|
goldpants=316
|
||||||
|
goldenboots=317
|
||||||
goldboots=317
|
goldboots=317
|
||||||
flint=318
|
flint=318
|
||||||
meat=319
|
meat=319
|
||||||
|
@ -231,8 +285,10 @@ cookedpork=320
|
||||||
painting=321
|
painting=321
|
||||||
paintings=321
|
paintings=321
|
||||||
goldenapple=322
|
goldenapple=322
|
||||||
|
goldapple=322
|
||||||
sign=323
|
sign=323
|
||||||
wooddoor=324
|
wooddoor=324
|
||||||
|
woodendoor=324
|
||||||
bucket=325
|
bucket=325
|
||||||
waterbucket=326
|
waterbucket=326
|
||||||
lavabucket=327
|
lavabucket=327
|
||||||
|
@ -247,6 +303,7 @@ milkbucket=335
|
||||||
brick=336
|
brick=336
|
||||||
clay=337
|
clay=337
|
||||||
reed=338
|
reed=338
|
||||||
|
sugarcane=338
|
||||||
paper=339
|
paper=339
|
||||||
book=340
|
book=340
|
||||||
slimeorb=341
|
slimeorb=341
|
||||||
|
@ -265,7 +322,42 @@ fish=349
|
||||||
cookedfish=350
|
cookedfish=350
|
||||||
dye=351
|
dye=351
|
||||||
inksac=351:0
|
inksac=351:0
|
||||||
|
blackdye=351:0
|
||||||
|
reddye=351:1
|
||||||
|
rosered=351:1
|
||||||
|
greendye=351:2
|
||||||
cactusgreen=351:2
|
cactusgreen=351:2
|
||||||
|
cocoabeans=351:3
|
||||||
|
browndye=351:3
|
||||||
|
lapislazuli=351:4
|
||||||
|
bluedye=351:4
|
||||||
|
darkbluedye=351:4
|
||||||
|
dkbluedye=351:4
|
||||||
|
purpledye=351:5
|
||||||
|
violetdye=351:5
|
||||||
|
cyandye=351:6
|
||||||
|
lightgreydye=351:7
|
||||||
|
lightgraydye=351:7
|
||||||
|
ltgreydye=351:7
|
||||||
|
ltgraydye=351:7
|
||||||
|
greydye=351:8
|
||||||
|
graydye=351:8
|
||||||
|
darkgreydye=351:8
|
||||||
|
darkgraydye=351:8
|
||||||
|
dkgreydye=351:8
|
||||||
|
dkgraydye=351:8
|
||||||
|
pinkdye=351:9
|
||||||
|
limedye=351:10
|
||||||
|
lightgreendye=351:10
|
||||||
|
ltgreendye=351:10
|
||||||
|
dandellionyellow=351:11
|
||||||
|
yellowdye=351:11
|
||||||
|
lightbluedye=351:12
|
||||||
|
ltbluedye=351:12
|
||||||
|
magentadye=351:13
|
||||||
|
orangedye=351:14
|
||||||
|
bonemeal=351:15
|
||||||
|
whitedye=351:15
|
||||||
bone=352
|
bone=352
|
||||||
sugar=353
|
sugar=353
|
||||||
cake=354
|
cake=354
|
||||||
|
|
26
recipes.txt
26
recipes.txt
|
@ -86,32 +86,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#******************************************************#
|
|
||||||
# Basic Crafts
|
|
||||||
#
|
|
||||||
1x1,1:1:17:1@5:4 # -> 4 Planks
|
|
||||||
1x2,*:*:5:1@280:4 # -> 4 Sticks
|
|
||||||
2x2,*:*:5:1@58:1 # -> Crafting bench
|
|
||||||
3x3,2:2:5:-1@54:1 # -> Chest
|
|
||||||
3x3,2:2:4:-1@61:1 # -> Furnace
|
|
||||||
1x2,1:1:263:1,1:2:280:1@50:4 # -> Torch
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#******************************************************#
|
|
||||||
# Food
|
|
||||||
#
|
|
||||||
3x1,*:3:296:1@297:1 # -> Bread
|
|
||||||
3x2,1:2:5:1,3:2:5:1,2:3:5:1@281:4 # -> Bowl
|
|
||||||
1x3,1:1:49:1,1:2:48:1,1:3:281:1@282:1 # -> Mushroom Stew
|
|
||||||
3x3,2:2:41:-1,2:2:260:1@322:1 # -> Golden Apple
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#******************************************************#
|
#******************************************************#
|
||||||
# Utilities
|
# Utilities
|
||||||
#
|
#
|
||||||
|
|
37842
source/Bindings.cpp
37842
source/Bindings.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on Mon Jun 4 01:27:12 2012.
|
** Generated automatically by tolua++-1.0.92 on 06/04/12 10:48:42.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported function */
|
/* Exported function */
|
||||||
TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
|
TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "BlockID.h"
|
#include "BlockID.h"
|
||||||
#include "../iniFile/iniFile.h"
|
#include "../iniFile/iniFile.h"
|
||||||
|
#include "cItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +36,11 @@ public:
|
||||||
return m_Ini.GetValueI("Items", a_ItemName, -1);
|
return m_Ini.GetValueI("Items", a_ItemName, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AString ResolveString(AString & a_ItemName)
|
||||||
|
{
|
||||||
|
return m_Ini.GetValue("Items", a_ItemName, "");
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
cIniFile m_Ini;
|
cIniFile m_Ini;
|
||||||
} ;
|
} ;
|
||||||
|
@ -58,12 +64,47 @@ int BlockStringToType(const AString & a_BlockTypeString)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return gsBlockIDMap.Resolve(a_BlockTypeString);
|
return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item)
|
||||||
|
{
|
||||||
|
AString Resolved = TrimString(gsBlockIDMap.ResolveString(TrimString(a_ItemTypeString)));
|
||||||
|
AString txt = (!Resolved.empty()) ? Resolved : a_ItemTypeString;
|
||||||
|
AStringVector Split = StringSplit(txt, ":");
|
||||||
|
if (Split.size() == 1)
|
||||||
|
{
|
||||||
|
Split = StringSplit(txt, "^");
|
||||||
|
}
|
||||||
|
if (Split.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
a_Item.m_ItemID = (ENUM_ITEM_ID)atoi(Split[0].c_str());
|
||||||
|
if ((a_Item.m_ItemID == 0) && (Split[0] != "0"))
|
||||||
|
{
|
||||||
|
// Parsing the number failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Split.size() > 1)
|
||||||
|
{
|
||||||
|
a_Item.m_ItemHealth = atoi(Split[1].c_str());
|
||||||
|
if ((a_Item.m_ItemHealth == 0) && (Split[1] != "0"))
|
||||||
|
{
|
||||||
|
// Parsing the number failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EMCSBiome StringToBiome(const AString & a_BiomeString)
|
EMCSBiome StringToBiome(const AString & a_BiomeString)
|
||||||
{
|
{
|
||||||
// If it is a number, return it:
|
// If it is a number, return it:
|
||||||
|
|
|
@ -145,7 +145,8 @@ enum ENUM_ITEM_ID
|
||||||
E_ITEM_GRASS = 2,
|
E_ITEM_GRASS = 2,
|
||||||
E_ITEM_DIRT = 3,
|
E_ITEM_DIRT = 3,
|
||||||
E_ITEM_COBBLESTONE = 4,
|
E_ITEM_COBBLESTONE = 4,
|
||||||
E_ITEM_WOOD = 5,
|
E_ITEM_PLANKS = 5,
|
||||||
|
E_ITEM_WOOD = 5, // obsolete, use E_ITEM_PLANKS instead
|
||||||
E_ITEM_SAPLING = 6,
|
E_ITEM_SAPLING = 6,
|
||||||
E_ITEM_BEDROCK = 7,
|
E_ITEM_BEDROCK = 7,
|
||||||
E_ITEM_WATER = 8,
|
E_ITEM_WATER = 8,
|
||||||
|
@ -443,8 +444,18 @@ enum
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd: cItem.h:
|
||||||
|
class cItem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Translates a blocktype string into blocktype. Takes either a number or an items.ini alias as input. Returns -1 on failure.
|
/// Translates a blocktype string into blocktype. Takes either a number or an items.ini alias as input. Returns -1 on failure.
|
||||||
extern int BlockStringToType(const AString & a_BlockTypeString);
|
extern int BlockStringToType(const AString & a_BlockTypeString); // tolua_export
|
||||||
|
|
||||||
|
/// Translates an itemtype string into an item. Takes either a number, number^number, number:number or an items.ini alias as input. Returns true if successful.
|
||||||
|
extern bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item); // tolua_export
|
||||||
|
|
||||||
/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure.
|
/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure.
|
||||||
extern EMCSBiome StringToBiome(const AString & a_BiomeString);
|
extern EMCSBiome StringToBiome(const AString & a_BiomeString);
|
||||||
|
|
|
@ -0,0 +1,520 @@
|
||||||
|
|
||||||
|
// CraftingRecipes.cpp
|
||||||
|
|
||||||
|
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CraftingRecipes.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCraftingRecipes::cCraftingRecipes(void)
|
||||||
|
{
|
||||||
|
LoadRecipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCraftingRecipes::~cCraftingRecipes()
|
||||||
|
{
|
||||||
|
ClearRecipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Offers an item resulting from the crafting grid setup. Doesn't modify the grid
|
||||||
|
cItem cCraftingRecipes::Offer(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid, a_GridWidth, a_GridHeight));
|
||||||
|
if (Recipe.get() == NULL)
|
||||||
|
{
|
||||||
|
return cItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Recipe->m_Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Crafts the item resulting from the crafting grid setup. Modifies the grid, returns the crafted item
|
||||||
|
cItem cCraftingRecipes::Craft(cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid, a_GridWidth, a_GridHeight));
|
||||||
|
if (Recipe.get() == NULL)
|
||||||
|
{
|
||||||
|
return cItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume the ingredients from the grid:
|
||||||
|
for (cRecipeSlots::const_iterator itr = Recipe->m_Ingredients.begin(); itr != Recipe->m_Ingredients.end(); ++itr)
|
||||||
|
{
|
||||||
|
int GridIdx = itr->x + a_GridWidth * itr->y;
|
||||||
|
a_CraftingGrid[GridIdx].m_ItemCount -= itr->m_Item.m_ItemCount;
|
||||||
|
if (a_CraftingGrid[GridIdx].m_ItemCount <= 0)
|
||||||
|
{
|
||||||
|
a_CraftingGrid[GridIdx].Empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Recipe->m_Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cCraftingRecipes::LoadRecipes(void)
|
||||||
|
{
|
||||||
|
LOG("-- Loading crafting recipes from crafting.txt --");
|
||||||
|
ClearRecipes();
|
||||||
|
|
||||||
|
// Load the crafting.txt file:
|
||||||
|
cFile f;
|
||||||
|
if (!f.Open("crafting.txt", cFile::fmRead))
|
||||||
|
{
|
||||||
|
LOGWARNING("Cannot open file \"crafting.txt\", no crafting recipes will be available!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AString Everything;
|
||||||
|
f.ReadRestOfFile(Everything);
|
||||||
|
f.Close();
|
||||||
|
|
||||||
|
// Split it into lines, then process each line as a single recipe:
|
||||||
|
AStringVector Split = StringSplit(Everything, "\n");
|
||||||
|
int LineNum = 1;
|
||||||
|
for (AStringVector::const_iterator itr = Split.begin(); itr != Split.end(); ++itr, ++LineNum)
|
||||||
|
{
|
||||||
|
// Remove anything after a '#' sign and trim away the whitespace:
|
||||||
|
AString Recipe = TrimString(itr->substr(0, itr->find('#')));
|
||||||
|
if (Recipe.empty())
|
||||||
|
{
|
||||||
|
// Empty recipe
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AddRecipeLine(LineNum, Recipe);
|
||||||
|
} // for itr - Split[]
|
||||||
|
LOG("-- %d crafting recipes loaded from crafting.txt --", m_Recipes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cCraftingRecipes::ClearRecipes(void)
|
||||||
|
{
|
||||||
|
for (cRecipes::iterator itr = m_Recipes.begin(); itr != m_Recipes.end(); ++itr)
|
||||||
|
{
|
||||||
|
delete *itr;
|
||||||
|
}
|
||||||
|
m_Recipes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine)
|
||||||
|
{
|
||||||
|
AStringVector Sides = StringSplit(a_RecipeLine, "=");
|
||||||
|
if (Sides.size() != 2)
|
||||||
|
{
|
||||||
|
LOGWARNING("crafting.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::auto_ptr<cCraftingRecipes::cRecipe> Recipe(new cCraftingRecipes::cRecipe);
|
||||||
|
|
||||||
|
// Parse the result:
|
||||||
|
AStringVector ResultSplit = StringSplit(Sides[0], ",");
|
||||||
|
if (ResultSplit.empty())
|
||||||
|
{
|
||||||
|
LOGWARNING("crafting.txt: line %d: Result is empty, ignoring the recipe.", a_LineNum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!ParseItem(ResultSplit[0], Recipe->m_Result))
|
||||||
|
{
|
||||||
|
LOGWARNING("crafting.txt: line %d: Cannot parse result item, ignoring the recipe.", a_LineNum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ResultSplit.size() > 1)
|
||||||
|
{
|
||||||
|
Recipe->m_Result.m_ItemCount = atoi(ResultSplit[1].c_str());
|
||||||
|
if (Recipe->m_Result.m_ItemCount == 0)
|
||||||
|
{
|
||||||
|
LOGWARNING("crafting.txt: line %d: Cannot parse result count, ignoring the recipe.", a_LineNum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Recipe->m_Result.m_ItemCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse each ingredient:
|
||||||
|
AStringVector Ingredients = StringSplit(Sides[1], "|");
|
||||||
|
int Num = 1;
|
||||||
|
for (AStringVector::const_iterator itr = Ingredients.begin(); itr != Ingredients.end(); ++itr, ++Num)
|
||||||
|
{
|
||||||
|
if (!ParseIngredient(*itr, Recipe.get()))
|
||||||
|
{
|
||||||
|
LOGWARNING("crafting.txt: line %d: Cannot parse ingredient #%d, ignoring the recipe.", a_LineNum, Num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} // for itr - Ingredients[]
|
||||||
|
|
||||||
|
NormalizeIngredients(Recipe.get());
|
||||||
|
|
||||||
|
m_Recipes.push_back(Recipe.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cCraftingRecipes::ParseItem(const AString & a_String, cItem & a_Item)
|
||||||
|
{
|
||||||
|
// The caller provides error logging
|
||||||
|
|
||||||
|
AStringVector Split = StringSplit(a_String, "^");
|
||||||
|
if (Split.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StringToItem(Split[0], a_Item))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Split.size() > 1)
|
||||||
|
{
|
||||||
|
AString Damage = TrimString(Split[1]);
|
||||||
|
a_Item.m_ItemHealth = atoi(Damage.c_str());
|
||||||
|
if ((a_Item.m_ItemHealth == 0) && (Damage.compare("0") != 0))
|
||||||
|
{
|
||||||
|
// Parsing the number failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cCraftingRecipes::ParseIngredient(const AString & a_String, cRecipe * a_Recipe)
|
||||||
|
{
|
||||||
|
// a_String is in this format: "ItemType^damage, X:Y, X:Y, X:Y..."
|
||||||
|
AStringVector Split = StringSplit(a_String, ",");
|
||||||
|
if (Split.size() < 2)
|
||||||
|
{
|
||||||
|
// Not enough split items
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cItem Item;
|
||||||
|
if (!ParseItem(Split[0], Item))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Item.m_ItemCount = 1;
|
||||||
|
|
||||||
|
cCraftingRecipes::cRecipeSlots TempSlots;
|
||||||
|
for (AStringVector::const_iterator itr = Split.begin() + 1; itr != Split.end(); ++itr)
|
||||||
|
{
|
||||||
|
// Parse the coords in the split item:
|
||||||
|
AStringVector Coords = StringSplit(*itr, ":");
|
||||||
|
if ((Coords.size() == 1) && (TrimString(Coords[0]) == "*"))
|
||||||
|
{
|
||||||
|
cCraftingRecipes::cRecipeSlot Slot;
|
||||||
|
Slot.m_Item = Item;
|
||||||
|
Slot.x = -1;
|
||||||
|
Slot.y = -1;
|
||||||
|
TempSlots.push_back(Slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Coords.size() != 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Coords[0] = TrimString(Coords[0]);
|
||||||
|
Coords[1] = TrimString(Coords[1]);
|
||||||
|
if (Coords[0].empty() || Coords[1].empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cCraftingRecipes::cRecipeSlot Slot;
|
||||||
|
Slot.m_Item = Item;
|
||||||
|
switch (Coords[0][0])
|
||||||
|
{
|
||||||
|
case '1': Slot.x = 0; break;
|
||||||
|
case '2': Slot.x = 1; break;
|
||||||
|
case '3': Slot.x = 2; break;
|
||||||
|
case '*': Slot.x = -1; break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (Coords[1][0])
|
||||||
|
{
|
||||||
|
case '1': Slot.y = 0; break;
|
||||||
|
case '2': Slot.y = 1; break;
|
||||||
|
case '3': Slot.y = 2; break;
|
||||||
|
case '*': Slot.y = -1; break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TempSlots.push_back(Slot);
|
||||||
|
} // for itr - Split[]
|
||||||
|
|
||||||
|
// Append the ingredients:
|
||||||
|
a_Recipe->m_Ingredients.insert(a_Recipe->m_Ingredients.end(), TempSlots.begin(), TempSlots.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cCraftingRecipes::NormalizeIngredients(cCraftingRecipes::cRecipe * a_Recipe)
|
||||||
|
{
|
||||||
|
// Calculate the minimum coords for ingredients, excluding the "anywhere" items:
|
||||||
|
int MinX = MAX_GRID_WIDTH, MaxX = 0;
|
||||||
|
int MinY = MAX_GRID_HEIGHT, MaxY = 0;
|
||||||
|
for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (itr->x >= 0)
|
||||||
|
{
|
||||||
|
MinX = std::min(itr->x, MinX);
|
||||||
|
MaxX = std::max(itr->x, MaxX);
|
||||||
|
}
|
||||||
|
if (itr->y >= 0)
|
||||||
|
{
|
||||||
|
MinY = std::min(itr->y, MinY);
|
||||||
|
MaxY = std::max(itr->y, MaxY);
|
||||||
|
}
|
||||||
|
} // for itr - a_Recipe->m_Ingredients[]
|
||||||
|
|
||||||
|
// Move ingredients so that the minimum coords are 0:0
|
||||||
|
for (cRecipeSlots::iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (itr->x >= 0)
|
||||||
|
{
|
||||||
|
itr->x -= MinX;
|
||||||
|
}
|
||||||
|
if (itr->y >= 0)
|
||||||
|
{
|
||||||
|
itr->y -= MinY;
|
||||||
|
}
|
||||||
|
} // for itr - a_Recipe->m_Ingredients[]
|
||||||
|
a_Recipe->m_Width = std::max(MaxX - MinX + 1, 1);
|
||||||
|
a_Recipe->m_Height = std::max(MaxY - MinY + 1, 1);
|
||||||
|
|
||||||
|
// TODO: Compress two same ingredients with the same coords into a single ingredient with increased item count
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCraftingRecipes::cRecipe * cCraftingRecipes::FindRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight)
|
||||||
|
{
|
||||||
|
ASSERT(a_GridWidth <= MAX_GRID_WIDTH);
|
||||||
|
ASSERT(a_GridHeight <= MAX_GRID_HEIGHT);
|
||||||
|
|
||||||
|
// Get the real bounds of the crafting grid:
|
||||||
|
int GridLeft = MAX_GRID_WIDTH, GridTop = MAX_GRID_HEIGHT;
|
||||||
|
int GridRight = 0, GridBottom = 0;
|
||||||
|
for (int y = 0; y < a_GridHeight; y++ ) for(int x = 0; x < a_GridWidth; x++)
|
||||||
|
{
|
||||||
|
if (!a_CraftingGrid[x + y * a_GridWidth].IsEmpty())
|
||||||
|
{
|
||||||
|
GridRight = MAX(x, GridRight);
|
||||||
|
GridBottom = MAX(y, GridBottom);
|
||||||
|
GridLeft = MIN(x, GridLeft);
|
||||||
|
GridTop = MIN(y, GridTop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int GridWidth = GridRight - GridLeft + 1;
|
||||||
|
int GridHeight = GridBottom - GridTop + 1;
|
||||||
|
|
||||||
|
// Search in the possibly minimized grid, but keep the stride:
|
||||||
|
const cItem * Grid = a_CraftingGrid + GridLeft + (a_GridWidth * GridTop);
|
||||||
|
cRecipe * Recipe = FindRecipeCropped(Grid, GridWidth, GridHeight, a_GridWidth);
|
||||||
|
if (Recipe == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A recipe has been found, move it to correspond to the original crafting grid:
|
||||||
|
for (cRecipeSlots::iterator itrS = Recipe->m_Ingredients.begin(); itrS != Recipe->m_Ingredients.end(); ++itrS)
|
||||||
|
{
|
||||||
|
itrS->x += GridLeft;
|
||||||
|
itrS->y += GridTop;
|
||||||
|
} // for itrS - Recipe->m_Ingredients[]
|
||||||
|
|
||||||
|
return Recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCraftingRecipes::cRecipe * cCraftingRecipes::FindRecipeCropped(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride)
|
||||||
|
{
|
||||||
|
for (cRecipes::const_iterator itr = m_Recipes.begin(); itr != m_Recipes.end(); ++itr)
|
||||||
|
{
|
||||||
|
// Both the crafting grid and the recipes are normalized. The only variable possible is the "anywhere" items.
|
||||||
|
// This still means that the "anywhere" item may be the one that is offsetting the grid contents to the right or downwards, so we need to check all possible positions.
|
||||||
|
// E. g. recipe "A, * | B, 1:1 | ..." still needs to check grid for B at 2:2 (in case A was in grid's 1:1)
|
||||||
|
// Calculate the maximum offsets for this recipe relative to the grid size, and iterate through all combinations of offsets.
|
||||||
|
// Also, this calculation automatically filters out recipes that are too large for the current grid - the loop won't be entered at all.
|
||||||
|
|
||||||
|
int MaxOfsX = a_GridWidth - (*itr)->m_Width;
|
||||||
|
int MaxOfsY = a_GridHeight - (*itr)->m_Height;
|
||||||
|
for (int x = 0; x <= MaxOfsX; x++) for (int y = 0; y <= MaxOfsY; y++)
|
||||||
|
{
|
||||||
|
cRecipe * Recipe = MatchRecipe(a_CraftingGrid, a_GridWidth, a_GridHeight, a_GridStride, *itr, x, y);
|
||||||
|
if (Recipe != NULL)
|
||||||
|
{
|
||||||
|
return Recipe;
|
||||||
|
}
|
||||||
|
} // for y, for x
|
||||||
|
} // for itr - m_Recipes[]
|
||||||
|
|
||||||
|
// No matching recipe found
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY)
|
||||||
|
{
|
||||||
|
// Check the regular items first:
|
||||||
|
bool HasMatched[MAX_GRID_WIDTH][MAX_GRID_HEIGHT];
|
||||||
|
memset(HasMatched, 0, sizeof(HasMatched));
|
||||||
|
for (cRecipeSlots::const_iterator itrS = a_Recipe->m_Ingredients.begin(); itrS != a_Recipe->m_Ingredients.end(); ++itrS)
|
||||||
|
{
|
||||||
|
if ((itrS->x < 0) || (itrS->y < 0))
|
||||||
|
{
|
||||||
|
// "Anywhere" item, process later
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ASSERT(itrS->x + a_OffsetX < a_GridWidth);
|
||||||
|
ASSERT(itrS->y + a_OffsetY < a_GridHeight);
|
||||||
|
int GridID = (itrS->x + a_OffsetX) + a_GridStride * (itrS->y + a_OffsetY);
|
||||||
|
if (
|
||||||
|
(itrS->x >= a_GridWidth) ||
|
||||||
|
(itrS->y >= a_GridHeight) ||
|
||||||
|
(itrS->m_Item.m_ItemID != a_CraftingGrid[GridID].m_ItemID) || // same item type?
|
||||||
|
(itrS->m_Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items
|
||||||
|
(
|
||||||
|
(itrS->m_Item.m_ItemHealth > 0) && // should compare damage values?
|
||||||
|
(itrS->m_Item.m_ItemHealth != a_CraftingGrid[GridID].m_ItemHealth)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Doesn't match
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
HasMatched[itrS->x + a_OffsetX][itrS->y + a_OffsetY] = true;
|
||||||
|
} // for itrS - Recipe->m_Ingredients[]
|
||||||
|
|
||||||
|
// Process the "Anywhere" items now, and only in the cells that haven't matched yet
|
||||||
|
// The "anywhere" items are processed on a first-come-first-served basis.
|
||||||
|
// Do not use a recipe with one horizontal and one vertical "anywhere" ("*:1, 1:*") as it may not match properly!
|
||||||
|
cRecipeSlots MatchedSlots; // Stores the slots of "anywhere" items that have matched, with the match coords
|
||||||
|
for (cRecipeSlots::const_iterator itrS = a_Recipe->m_Ingredients.begin(); itrS != a_Recipe->m_Ingredients.end(); ++itrS)
|
||||||
|
{
|
||||||
|
if ((itrS->x >= 0) && (itrS->y >= 0))
|
||||||
|
{
|
||||||
|
// Regular item, already processed
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int StartX = 0, EndX = a_GridWidth - 1;
|
||||||
|
int StartY = 0, EndY = a_GridHeight - 1;
|
||||||
|
if (itrS->x >= 0)
|
||||||
|
{
|
||||||
|
StartX = itrS->x;
|
||||||
|
EndX = itrS->x;
|
||||||
|
}
|
||||||
|
else if (itrS->y >= 0)
|
||||||
|
{
|
||||||
|
StartY = itrS->y;
|
||||||
|
EndY = itrS->y;
|
||||||
|
}
|
||||||
|
bool Found = false;
|
||||||
|
for (int x = StartX; x <= EndX; x++) for (int y = StartY; y <= EndY; y++)
|
||||||
|
{
|
||||||
|
if (HasMatched[x][y])
|
||||||
|
{
|
||||||
|
// Already matched some other item
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int GridIdx = x + a_GridStride * y;
|
||||||
|
if (
|
||||||
|
(a_CraftingGrid[GridIdx].m_ItemID == itrS->m_Item.m_ItemID) &&
|
||||||
|
(
|
||||||
|
(itrS->m_Item.m_ItemHealth < 0) || // doesn't want damage comparison
|
||||||
|
(itrS->m_Item.m_ItemHealth == a_CraftingGrid[GridIdx].m_ItemHealth) // the damage matches
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
HasMatched[x][y] = true;
|
||||||
|
Found = true;
|
||||||
|
MatchedSlots.push_back(*itrS);
|
||||||
|
MatchedSlots.back().x = x;
|
||||||
|
MatchedSlots.back().y = y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for y, for x - "anywhere"
|
||||||
|
if (!Found)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} // for itrS - a_Recipe->m_Ingredients[]
|
||||||
|
|
||||||
|
// Check if the whole grid has matched:
|
||||||
|
for (int x = 0; x < a_GridWidth; x++) for (int y = 0; y < a_GridHeight; y++)
|
||||||
|
{
|
||||||
|
if (!HasMatched[x][y] && !a_CraftingGrid[x + a_GridStride * y].IsEmpty())
|
||||||
|
{
|
||||||
|
// There's an unmatched item in the grid
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} // for y, for x
|
||||||
|
|
||||||
|
// The recipe has matched. Create a copy of the recipe and set its coords to match the crafting grid:
|
||||||
|
std::auto_ptr<cRecipe> Recipe(new cRecipe);
|
||||||
|
Recipe->m_Result = a_Recipe->m_Result;
|
||||||
|
Recipe->m_Width = a_Recipe->m_Width;
|
||||||
|
Recipe->m_Height = a_Recipe->m_Height;
|
||||||
|
for (cRecipeSlots::const_iterator itrS = a_Recipe->m_Ingredients.begin(); itrS != a_Recipe->m_Ingredients.end(); ++itrS)
|
||||||
|
{
|
||||||
|
if ((itrS->x < 0) || (itrS->y < 0))
|
||||||
|
{
|
||||||
|
// "Anywhere" item, process later
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Recipe->m_Ingredients.push_back(*itrS);
|
||||||
|
}
|
||||||
|
Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());
|
||||||
|
return Recipe.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
|
||||||
|
// CraftingRecipes.h
|
||||||
|
|
||||||
|
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCraftingRecipes
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int MAX_GRID_WIDTH = 3;
|
||||||
|
static const int MAX_GRID_HEIGHT = 3;
|
||||||
|
|
||||||
|
cCraftingRecipes(void);
|
||||||
|
~cCraftingRecipes();
|
||||||
|
|
||||||
|
/// Offers an item resulting from the crafting grid setup. Doesn't modify the grid
|
||||||
|
cItem Offer(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight);
|
||||||
|
|
||||||
|
/// Crafts the item resulting from the crafting grid setup. Modifies the grid, returns the crafted item
|
||||||
|
cItem Craft(cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct cRecipeSlot
|
||||||
|
{
|
||||||
|
cItem m_Item;
|
||||||
|
int x, y; // 1..3, or -1 for "any"
|
||||||
|
} ;
|
||||||
|
typedef std::vector<cRecipeSlot> cRecipeSlots;
|
||||||
|
|
||||||
|
// A single recipe, stored. Each recipe is normalized right after parsing (NormalizeIngredients())
|
||||||
|
struct cRecipe
|
||||||
|
{
|
||||||
|
cRecipeSlots m_Ingredients;
|
||||||
|
cItem m_Result;
|
||||||
|
|
||||||
|
// Size of the regular items in the recipe; "anywhere" items are excluded:
|
||||||
|
int m_Width;
|
||||||
|
int m_Height;
|
||||||
|
} ;
|
||||||
|
typedef std::vector<cRecipe *> cRecipes;
|
||||||
|
|
||||||
|
cRecipes m_Recipes;
|
||||||
|
|
||||||
|
void LoadRecipes(void);
|
||||||
|
void ClearRecipes(void);
|
||||||
|
|
||||||
|
/// Parses the recipe line and adds it into m_Recipes. a_LineNum is used for diagnostic warnings only
|
||||||
|
void AddRecipeLine(int a_LineNum, const AString & a_RecipeLine);
|
||||||
|
|
||||||
|
/// Parses an item string in the format "<ItemType>[^<Damage>]", returns true if successful.
|
||||||
|
bool ParseItem(const AString & a_String, cItem & a_Item);
|
||||||
|
|
||||||
|
/// Parses one ingredient and adds it to the specified recipe. Returns true if successful.
|
||||||
|
bool ParseIngredient(const AString & a_String, cRecipe * a_Recipe);
|
||||||
|
|
||||||
|
/// Moves the recipe to top-left corner, sets its MinWidth / MinHeight
|
||||||
|
void NormalizeIngredients(cRecipe * a_Recipe);
|
||||||
|
|
||||||
|
/// Finds a recipe matching the crafting grid. Returns a newly allocated recipe (with all its coords set) or NULL if not found. Caller must delete return value!
|
||||||
|
cRecipe * FindRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight);
|
||||||
|
|
||||||
|
/// Same as FindRecipe, but the grid is guaranteed to be of minimal dimensions needed
|
||||||
|
cRecipe * FindRecipeCropped(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride);
|
||||||
|
|
||||||
|
/// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value!
|
||||||
|
cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -88,10 +88,7 @@ AStringVector StringSplit(const AString & str, const AString & delim)
|
||||||
size_t Prev = 0;
|
size_t Prev = 0;
|
||||||
while ((cutAt = str.find_first_of(delim, Prev)) != str.npos)
|
while ((cutAt = str.find_first_of(delim, Prev)) != str.npos)
|
||||||
{
|
{
|
||||||
if (cutAt > 0)
|
results.push_back(str.substr(Prev, cutAt - Prev));
|
||||||
{
|
|
||||||
results.push_back(str.substr(Prev, cutAt - Prev));
|
|
||||||
}
|
|
||||||
Prev = cutAt + delim.length();
|
Prev = cutAt + delim.length();
|
||||||
}
|
}
|
||||||
if (Prev < str.length())
|
if (Prev < str.length())
|
||||||
|
@ -104,6 +101,40 @@ AStringVector StringSplit(const AString & str, const AString & delim)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AString TrimString(const AString & str)
|
||||||
|
{
|
||||||
|
size_t len = str.length();
|
||||||
|
size_t start = 0;
|
||||||
|
while (start < len)
|
||||||
|
{
|
||||||
|
if (str[start] > 32)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
if (start == len)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t end = len;
|
||||||
|
while (end >= start)
|
||||||
|
{
|
||||||
|
if (str[end] > 32)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
--end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.substr(start, end - start + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AString & StrToUpper(AString & s)
|
AString & StrToUpper(AString & s)
|
||||||
{
|
{
|
||||||
AString::iterator i = s.begin();
|
AString::iterator i = s.begin();
|
||||||
|
|
|
@ -33,6 +33,9 @@ extern AString & AppendPrintf (AString & str, const char * format, ...);
|
||||||
/// Split the string at delimiters, return as a stringvector
|
/// Split the string at delimiters, return as a stringvector
|
||||||
extern AStringVector StringSplit(const AString & str, const AString & delim);
|
extern AStringVector StringSplit(const AString & str, const AString & delim);
|
||||||
|
|
||||||
|
/// Trime whitespace at both ends of the string
|
||||||
|
extern AString TrimString(const AString & str);
|
||||||
|
|
||||||
/// In-place string conversion to uppercase; returns the same string
|
/// In-place string conversion to uppercase; returns the same string
|
||||||
extern AString & StrToUpper(AString & s);
|
extern AString & StrToUpper(AString & s);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "cCraftingWindow.h"
|
#include "cCraftingWindow.h"
|
||||||
#include "cItem.h"
|
#include "cItem.h"
|
||||||
#include "cRecipeChecker.h"
|
#include "cRecipeChecker.h"
|
||||||
|
#include "CraftingRecipes.h"
|
||||||
#include "cPlayer.h"
|
#include "cPlayer.h"
|
||||||
#include "cClientHandle.h"
|
#include "cClientHandle.h"
|
||||||
#include "cInventory.h"
|
#include "cInventory.h"
|
||||||
|
@ -13,6 +14,10 @@
|
||||||
#include "packets/cPacket_WindowClick.h"
|
#include "packets/cPacket_WindowClick.h"
|
||||||
#include "packets/cPacket_InventorySlot.h"
|
#include "packets/cPacket_InventorySlot.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cCraftingWindow::cCraftingWindow( cWindowOwner* a_Owner, bool a_bInventoryVisible )
|
cCraftingWindow::cCraftingWindow( cWindowOwner* a_Owner, bool a_bInventoryVisible )
|
||||||
: cWindow( a_Owner, a_bInventoryVisible )
|
: cWindow( a_Owner, a_bInventoryVisible )
|
||||||
{
|
{
|
||||||
|
@ -23,6 +28,10 @@ cCraftingWindow::cCraftingWindow( cWindowOwner* a_Owner, bool a_bInventoryVisibl
|
||||||
SetSlots( Slots, 10 );
|
SetSlots( Slots, 10 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCraftingWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
void cCraftingWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
||||||
{
|
{
|
||||||
bool bDontCook = false;
|
bool bDontCook = false;
|
||||||
|
@ -59,25 +68,41 @@ void cCraftingWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_P
|
||||||
cWindow::Clicked( a_ClickPacket, a_Player );
|
cWindow::Clicked( a_ClickPacket, a_Player );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( a_ClickPacket->m_SlotNum >= 0 && a_ClickPacket->m_SlotNum < 10 )
|
if ((a_ClickPacket->m_SlotNum >= 0) && (a_ClickPacket->m_SlotNum < 10))
|
||||||
{
|
{
|
||||||
cItem CookedItem;
|
cItem CookedItem;
|
||||||
if( a_ClickPacket->m_SlotNum == 0 && !bDontCook )
|
if ((a_ClickPacket->m_SlotNum == 0) && !bDontCook)
|
||||||
{
|
{
|
||||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( GetSlots()+1, 3, 3, true );
|
// Consume the ingredients from the crafting grid:
|
||||||
|
CookedItem = cRoot::Get()->GetCraftingRecipes()->Craft(GetSlots() + 1, 3, 3);
|
||||||
|
LOGD("New recipes crafted: %i x %i", CookedItem.m_ItemID, CookedItem.m_ItemCount);
|
||||||
|
// Upgrade the crafting result from the new crafting grid contents:
|
||||||
|
CookedItem = cRoot::Get()->GetCraftingRecipes()->Offer(GetSlots() + 1, 3, 3);
|
||||||
|
if (CookedItem.IsEmpty())
|
||||||
|
{
|
||||||
|
// Fallback to the old recipes:
|
||||||
|
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( GetSlots()+1, 3, 3, true );
|
||||||
|
LOGD("Old recipes crafted: %i x %i", CookedItem.m_ItemID, CookedItem.m_ItemCount );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( GetSlots()+1, 3, 3 );
|
CookedItem = cRoot::Get()->GetCraftingRecipes()->Offer(GetSlots() + 1, 3, 3);
|
||||||
|
LOGD("New recipes offer: %i x %i", CookedItem.m_ItemID, CookedItem.m_ItemCount );
|
||||||
|
if (CookedItem.IsEmpty())
|
||||||
|
{
|
||||||
|
// Fallback to the old recipes
|
||||||
|
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( GetSlots()+1, 3, 3 );
|
||||||
|
LOGD("Old recipes offer: %i x %i", CookedItem.m_ItemID, CookedItem.m_ItemCount );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*GetSlot(0) = CookedItem;
|
*GetSlot(0) = CookedItem;
|
||||||
LOG("You cooked: %i x %i !!", GetSlot(0)->m_ItemID, GetSlot(0)->m_ItemCount );
|
LOG("You cooked: %i x %i !!", GetSlot(0)->m_ItemID, GetSlot(0)->m_ItemCount );
|
||||||
}
|
}
|
||||||
SendWholeWindow( a_Player.GetClientHandle() );
|
SendWholeWindow( a_Player.GetClientHandle() );
|
||||||
a_Player.GetInventory().SendWholeInventory( a_Player.GetClientHandle() );
|
a_Player.GetInventory().SendWholeInventory( a_Player.GetClientHandle() );
|
||||||
//Separate packet for result =/ Don't know why
|
|
||||||
|
// Separate packet for result =/ Don't know why
|
||||||
|
|
||||||
cPacket_InventorySlot Packet;
|
cPacket_InventorySlot Packet;
|
||||||
Packet.m_WindowID = (char)GetWindowID();
|
Packet.m_WindowID = (char)GetWindowID();
|
||||||
Packet.m_SlotNum = 0;
|
Packet.m_SlotNum = 0;
|
||||||
|
@ -85,9 +110,12 @@ void cCraftingWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_P
|
||||||
Packet.m_ItemCount = GetSlot(0)->m_ItemCount;
|
Packet.m_ItemCount = GetSlot(0)->m_ItemCount;
|
||||||
Packet.m_ItemUses = (char)GetSlot(0)->m_ItemHealth;
|
Packet.m_ItemUses = (char)GetSlot(0)->m_ItemHealth;
|
||||||
a_Player.GetClientHandle()->Send( Packet );
|
a_Player.GetClientHandle()->Send( Packet );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCraftingWindow::Close( cPlayer & a_Player )
|
void cCraftingWindow::Close( cPlayer & a_Player )
|
||||||
{
|
{
|
||||||
// Start from slot 1, don't drop what's in the result slot
|
// Start from slot 1, don't drop what's in the result slot
|
||||||
|
@ -105,4 +133,8 @@ void cCraftingWindow::Close( cPlayer & a_Player )
|
||||||
Item->Empty();
|
Item->Empty();
|
||||||
}
|
}
|
||||||
cWindow::Close( a_Player );
|
cWindow::Close( a_Player );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,30 +7,51 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::list< cFurnaceRecipe::Recipe > RecipeList;
|
typedef std::list< cFurnaceRecipe::Recipe > RecipeList;
|
||||||
typedef std::list< cFurnaceRecipe::Fuel > FuelList;
|
typedef std::list< cFurnaceRecipe::Fuel > FuelList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct cFurnaceRecipe::sFurnaceRecipeState
|
struct cFurnaceRecipe::sFurnaceRecipeState
|
||||||
{
|
{
|
||||||
RecipeList Recipes;
|
RecipeList Recipes;
|
||||||
FuelList Fuel;
|
FuelList Fuel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cFurnaceRecipe::cFurnaceRecipe()
|
cFurnaceRecipe::cFurnaceRecipe()
|
||||||
: m_pState( new sFurnaceRecipeState )
|
: m_pState( new sFurnaceRecipeState )
|
||||||
{
|
{
|
||||||
ReloadRecipes();
|
ReloadRecipes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cFurnaceRecipe::~cFurnaceRecipe()
|
cFurnaceRecipe::~cFurnaceRecipe()
|
||||||
{
|
{
|
||||||
ClearRecipes();
|
ClearRecipes();
|
||||||
delete m_pState;
|
delete m_pState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFurnaceRecipe::ReloadRecipes()
|
void cFurnaceRecipe::ReloadRecipes()
|
||||||
{
|
{
|
||||||
ClearRecipes();
|
ClearRecipes();
|
||||||
LOG("--Loading furnace recipes--");
|
LOG("-- Loading furnace recipes --");
|
||||||
|
|
||||||
std::ifstream f;
|
std::ifstream f;
|
||||||
char a_File[] = "furnace.txt";
|
char a_File[] = "furnace.txt";
|
||||||
|
@ -152,9 +173,13 @@ void cFurnaceRecipe::ReloadRecipes()
|
||||||
}
|
}
|
||||||
LOG("Got %i furnace recipes, and %i fuels.", m_pState->Recipes.size(), m_pState->Fuel.size() );
|
LOG("Got %i furnace recipes, and %i fuels.", m_pState->Recipes.size(), m_pState->Fuel.size() );
|
||||||
|
|
||||||
LOG("--Done loading furnace recipes--");
|
LOG("-- Done loading furnace recipes --");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFurnaceRecipe::ClearRecipes()
|
void cFurnaceRecipe::ClearRecipes()
|
||||||
{
|
{
|
||||||
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 )
|
||||||
|
|
|
@ -125,7 +125,7 @@ void PrintNear( std::ifstream & f, int a_History = 64 )
|
||||||
|
|
||||||
void cRecipeChecker::ReloadRecipes()
|
void cRecipeChecker::ReloadRecipes()
|
||||||
{
|
{
|
||||||
LOG("--Loading recipes--");
|
LOG("-- Loading recipes from recipes.txt --");
|
||||||
ClearRecipes();
|
ClearRecipes();
|
||||||
|
|
||||||
std::ifstream f;
|
std::ifstream f;
|
||||||
|
@ -369,7 +369,7 @@ void cRecipeChecker::ReloadRecipes()
|
||||||
}
|
}
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
LOG("--Done loading recipes, found %i recipes", m_pState->Recipes.size() );
|
LOG("-- Done loading recipes, found %i recipes --", m_pState->Recipes.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "cFurnaceRecipe.h"
|
#include "cFurnaceRecipe.h"
|
||||||
#include "cGroupManager.h"
|
#include "cGroupManager.h"
|
||||||
#include "cRecipeChecker.h"
|
#include "cRecipeChecker.h"
|
||||||
|
#include "CraftingRecipes.h"
|
||||||
#include "cPluginManager.h"
|
#include "cPluginManager.h"
|
||||||
#include "cMonsterConfig.h"
|
#include "cMonsterConfig.h"
|
||||||
#include "cSleep.h"
|
#include "cSleep.h"
|
||||||
|
@ -40,7 +41,8 @@ cRoot::cRoot()
|
||||||
: m_Server( 0 )
|
: m_Server( 0 )
|
||||||
, m_MonsterConfig( 0 )
|
, m_MonsterConfig( 0 )
|
||||||
, m_GroupManager( 0 )
|
, m_GroupManager( 0 )
|
||||||
, m_RecipeChecker( 0 )
|
, m_RecipeChecker(NULL)
|
||||||
|
, m_CraftingRecipes(NULL)
|
||||||
, m_FurnaceRecipe( 0 )
|
, m_FurnaceRecipe( 0 )
|
||||||
, m_WebAdmin( 0 )
|
, m_WebAdmin( 0 )
|
||||||
, m_PluginManager( 0 )
|
, m_PluginManager( 0 )
|
||||||
|
@ -85,11 +87,11 @@ void cRoot::InputThread(void* a_Params)
|
||||||
|
|
||||||
void cRoot::Start()
|
void cRoot::Start()
|
||||||
{
|
{
|
||||||
if( m_Log ) delete m_Log, m_Log = 0;
|
delete m_Log;
|
||||||
m_Log = new cMCLogger();
|
m_Log = new cMCLogger();
|
||||||
|
|
||||||
m_bStop = false;
|
m_bStop = false;
|
||||||
while(!m_bStop)
|
while (!m_bStop)
|
||||||
{
|
{
|
||||||
m_bRestart = false;
|
m_bRestart = false;
|
||||||
|
|
||||||
|
@ -122,6 +124,7 @@ void cRoot::Start()
|
||||||
LOG("Loading settings...");
|
LOG("Loading settings...");
|
||||||
m_GroupManager = new cGroupManager();
|
m_GroupManager = new cGroupManager();
|
||||||
m_RecipeChecker = new cRecipeChecker();
|
m_RecipeChecker = new cRecipeChecker();
|
||||||
|
m_CraftingRecipes = new cCraftingRecipes;
|
||||||
m_FurnaceRecipe = new cFurnaceRecipe();
|
m_FurnaceRecipe = new cFurnaceRecipe();
|
||||||
|
|
||||||
LOG("Loading worlds...");
|
LOG("Loading worlds...");
|
||||||
|
@ -166,8 +169,9 @@ void cRoot::Start()
|
||||||
LOG("Stopping WebAdmin...");
|
LOG("Stopping WebAdmin...");
|
||||||
delete m_WebAdmin; m_WebAdmin = 0;
|
delete m_WebAdmin; m_WebAdmin = 0;
|
||||||
LOG("Unloading recipes...");
|
LOG("Unloading recipes...");
|
||||||
delete m_FurnaceRecipe; m_FurnaceRecipe = 0;
|
delete m_FurnaceRecipe; m_FurnaceRecipe = NULL;
|
||||||
delete m_RecipeChecker; m_RecipeChecker = 0;
|
delete m_RecipeChecker; m_RecipeChecker = NULL;
|
||||||
|
delete m_CraftingRecipes; m_CraftingRecipes = NULL;
|
||||||
LOG("Forgetting groups...");
|
LOG("Forgetting groups...");
|
||||||
delete m_GroupManager; m_GroupManager = 0;
|
delete m_GroupManager; m_GroupManager = 0;
|
||||||
LOG("Unloading worlds...");
|
LOG("Unloading worlds...");
|
||||||
|
|
|
@ -14,6 +14,7 @@ class cThread;
|
||||||
class cMonsterConfig;
|
class cMonsterConfig;
|
||||||
class cGroupManager;
|
class cGroupManager;
|
||||||
class cRecipeChecker;
|
class cRecipeChecker;
|
||||||
|
class cCraftingRecipes;
|
||||||
class cFurnaceRecipe;
|
class cFurnaceRecipe;
|
||||||
class cWebAdmin;
|
class cWebAdmin;
|
||||||
class cPluginManager;
|
class cPluginManager;
|
||||||
|
@ -32,26 +33,27 @@ class cRoot //tolua_export
|
||||||
public:
|
public:
|
||||||
static cRoot* Get() { return s_Root; } //tolua_export
|
static cRoot* Get() { return s_Root; } //tolua_export
|
||||||
|
|
||||||
cRoot();
|
cRoot(void);
|
||||||
~cRoot();
|
~cRoot();
|
||||||
|
|
||||||
void Start();
|
void Start(void);
|
||||||
|
|
||||||
cServer* GetServer(void) { return m_Server; } //tolua_export
|
cServer * GetServer(void) { return m_Server; } //tolua_export
|
||||||
cWorld* GetDefaultWorld(void); //tolua_export
|
cWorld * GetDefaultWorld(void); //tolua_export
|
||||||
cWorld* GetWorld( const AString & a_WorldName ); //tolua_export
|
cWorld * GetWorld(const AString & a_WorldName); //tolua_export
|
||||||
|
|
||||||
/// Calls the callback for each world; returns true if the callback didn't abort (return true)
|
/// Calls the callback for each world; returns true if the callback didn't abort (return true)
|
||||||
bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings <<
|
bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings <<
|
||||||
|
|
||||||
cMonsterConfig *GetMonsterConfig() { return m_MonsterConfig;}
|
cMonsterConfig * GetMonsterConfig() { return m_MonsterConfig; }
|
||||||
|
|
||||||
cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export
|
cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export
|
||||||
cRecipeChecker * GetRecipeChecker(void) { return m_RecipeChecker; } // tolua_export
|
cRecipeChecker * GetRecipeChecker (void) { return m_RecipeChecker; } // tolua_export
|
||||||
cFurnaceRecipe * GetFurnaceRecipe(void) { return m_FurnaceRecipe; } // tolua_export
|
cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export
|
||||||
cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export
|
cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // tolua_export
|
||||||
cPluginManager * GetPluginManager(void) { return m_PluginManager; } // tolua_export
|
cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export
|
||||||
cAuthenticator & GetAuthenticator(void) { return m_Authenticator; }
|
cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export
|
||||||
|
cAuthenticator & GetAuthenticator (void) { return m_Authenticator; }
|
||||||
|
|
||||||
void ServerCommand(const char* a_Cmd ); //tolua_export
|
void ServerCommand(const char* a_Cmd ); //tolua_export
|
||||||
|
|
||||||
|
@ -78,12 +80,13 @@ private:
|
||||||
cServer * m_Server;
|
cServer * m_Server;
|
||||||
cMonsterConfig * m_MonsterConfig;
|
cMonsterConfig * m_MonsterConfig;
|
||||||
|
|
||||||
cGroupManager * m_GroupManager;
|
cGroupManager * m_GroupManager;
|
||||||
cRecipeChecker * m_RecipeChecker;
|
cRecipeChecker * m_RecipeChecker;
|
||||||
cFurnaceRecipe * m_FurnaceRecipe;
|
cCraftingRecipes * m_CraftingRecipes;
|
||||||
cWebAdmin * m_WebAdmin;
|
cFurnaceRecipe * m_FurnaceRecipe;
|
||||||
cPluginManager * m_PluginManager;
|
cWebAdmin * m_WebAdmin;
|
||||||
cAuthenticator m_Authenticator;
|
cPluginManager * m_PluginManager;
|
||||||
|
cAuthenticator m_Authenticator;
|
||||||
|
|
||||||
cMCLogger * m_Log;
|
cMCLogger * m_Log;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "cWindow.h"
|
#include "cWindow.h"
|
||||||
#include "cItem.h"
|
#include "cItem.h"
|
||||||
#include "cRecipeChecker.h"
|
#include "cRecipeChecker.h"
|
||||||
|
#include "CraftingRecipes.h"
|
||||||
#include "cRoot.h"
|
#include "cRoot.h"
|
||||||
#include "packets/cPacket_WindowClick.h"
|
#include "packets/cPacket_WindowClick.h"
|
||||||
|
|
||||||
|
@ -69,16 +70,29 @@ void cSurvivalInventory::Clicked( cPacket* a_ClickPacket )
|
||||||
LOG("No Inventory window! WTF");
|
LOG("No Inventory window! WTF");
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Packet->m_SlotNum >= (short)c_CraftOffset && Packet->m_SlotNum < (short)(c_CraftOffset+c_CraftSlots+1) )
|
if ((Packet->m_SlotNum >= (short)c_CraftOffset) && (Packet->m_SlotNum < (short)(c_CraftOffset + c_CraftSlots + 1)))
|
||||||
{
|
{
|
||||||
cItem CookedItem;
|
cItem CookedItem;
|
||||||
if( Packet->m_SlotNum == 0 && !bDontCook )
|
if ((Packet->m_SlotNum == 0) && !bDontCook)
|
||||||
{
|
{
|
||||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( m_Slots+c_CraftOffset+1, 2, 2, true );
|
// Consume the items from the crafting grid:
|
||||||
|
CookedItem = cRoot::Get()->GetCraftingRecipes()->Craft(m_Slots + c_CraftOffset + 1, 2, 2);
|
||||||
|
// Upgrade the crafting result from the new crafting grid contents:
|
||||||
|
CookedItem = cRoot::Get()->GetCraftingRecipes()->Offer(m_Slots + c_CraftOffset + 1, 2, 2);
|
||||||
|
if (CookedItem.IsEmpty())
|
||||||
|
{
|
||||||
|
// Fallback to the old recipes:
|
||||||
|
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( m_Slots+c_CraftOffset+1, 2, 2, true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( m_Slots+c_CraftOffset+1, 2, 2 );
|
CookedItem = cRoot::Get()->GetCraftingRecipes()->Offer(m_Slots + c_CraftOffset + 1, 2, 2);
|
||||||
|
if (CookedItem.IsEmpty())
|
||||||
|
{
|
||||||
|
// Fallback to the old recipes:
|
||||||
|
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( m_Slots+c_CraftOffset+1, 2, 2 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_Slots[c_CraftOffset] = CookedItem;
|
m_Slots[c_CraftOffset] = CookedItem;
|
||||||
LOG("You cooked: %i x %i !!", m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount );
|
LOG("You cooked: %i x %i !!", m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount );
|
||||||
|
|
Loading…
Reference in New Issue