4

I'm trying to build a datapack that lets you craft xp bottles from glass bottles at the expense of 7 xp per bottle (because they drop 3 to 11 xp so the average is 7). I have almost everything working except for a check for if they have too little xp. If they have 7 or less xp, I would like to remove one bottle of enchanting from their inventory and give them one glass bottle, because the function for removing xp is called after they've crafted one and a scoreboard has counted it. My remove function currently looks like this:

#create dummy scoreboard to multiply bottles crafted by seven to get xp to be removed
scoreboard objectives add 7xp dummy
scoreboard players set @s 7xp -7
scoreboard players operation @s xpCrafted *= @s 7xp

#how do I get the value in xpCrafted into the command to remove xp?
xp add @s -7 points

#cleanup
scoreboard players reset xpCrafted
scoreboard players reset 7xp
scoreboard players set @e xpCrafted 0
scoreboard objectives remove 7xp

And my tick function like this:

execute as @e[scores={xpCrafted=1..}] at @s run function craft_xp:removexp

As the inline comment says, how do I get that value in xpCrafted into my xp removing command, and also how should I check to make sure the player has enough xp for the operation in the tick command (or elsewhere)? Presumably I would run a different command to remove the extra bottle if they didn't have enough xp, but I don't know how because there doesn't seem to be any type of if/else structure in commands. Finally, should a question like this be in two different questions or is one ok on this forum?

4

There is an xp scoreboard type:

/scoreboard objectives add scoreboardName xp {"text":"scoreboardDisplayName"}

For XP points that already existed before you set up the scoreboard, you can use the subcommand of the /xp command called "query", with it you can get the current level and the points since the last level:

/execute store result score @s <scoreboard> run xp query @s points

Additionally, you'll probably also track people with 1 or more complete XP levels, like this: @a[xp=1..]

  • How do I use the value of xpCrafted as the amount of xp to be added in the fourth command (execute run xp add...)? Right now that number is just a hard-coded -7. Essentially, how do I recall a value from a scoreboard and use it as an argument in a command? – Nik3141 Apr 10 at 15:56
  • 1
    Not sure exactly what you mean, but you can't fully use scoreboard values in everything. You can move numbers around between scoreboards and NBT using execute store in combination with scoreboard players get and data get, but not for example give someone as much XP points as there are points in a scoreboard. Except of course by giving one point if the score is above 0, subtracting one from the scoreboard, giving one point if the score is above 0, subtracting one from the scoreboard and so on. – Fabian Röling Apr 10 at 18:23
0

So I've created this function to be run when someone crafts a bottle (or multiple bottles):

#controller - sets up and then decides whether to cancel the crafting operation or remove the xp

#setup
scoreboard objectives add xpOwed dummy
scoreboard objectives add xpCurrent dummy
scoreboard objectives add xpDifference dummy

scoreboard players set @s xpOwed -7
execute store result score @s xpCurrent run xp query @s points

scoreboard players operation @s xpOwed *= @s xpCrafted
execute store result score @s xpDifference run scoreboard players operation @s xpCurrent -= @s xpOwed

#xpOwed has the amount of xp they owe, xpCurrent has how much they have,
#xpCrafted has the amount of bottles they crafted, and xpDifference is
#the difference of xp points between what they have and what they owe.

#somehow I need to loop the execute ... run function commands below a certain amount of times based on a scoreboard value

#if they are lacking xp, refund their bottles and xp
execute if score @s xpOwed > @s xpCurrent as @s run function craft_xp:cancel
execute if score @s xpOwed > @s xpCurrent as @s run say Sorry @s, but you don't have enough experience. Try crafting less bottles.
#if they have enough xp, remove the xp owed
execute if score @s xpOwed <= @s xpCurrent as @s run function craft_xp:removexp

#cleanup
scoreboard players reset xpOwed
scoreboard players reset xpCurrent
scoreboard players reset xpDifference
scoreboard players reset xpCrafted
scoreboard players set @e xpCrafted 0
scoreboard objectives remove xpOwed
scoreboard objectives remove xpCurrent
scoreboard objectives remove xpDifference

I also have these two functions, which are referenced in the above function.

#removexp - takes xp away based on how many bottles they've crafted
#needs to be looped @s xpOwed times
xp add @s -1 points

and

#cancel - gives player the amount of glass bottles that 
#they used and removes the amount of xp bottles they crafted
#needs to be looped @s xpCrafted times
clear @s minecraft:experience_bottle 1
give @s minecraft:experience_bottle 1

How do I loop the bottom two functions a certain amount of times based on a scoreboard score? I get that I decrement the score and test each time, but I don't really get how to actually implement it in my situation. Also, I know that xpDifference doesn't do anything yet. I might use it later so I left it in.

Edit: I'm trying recursion to see if it will work, so I'll probably open a new thread about how to fix my recursion bugs.

Edit 2: Here's the link to the finished datapack. Instead of crafting it, I just have the player throw glass bottles into a cauldron in order to convert them to bottles of enchanting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.