crafting: clicking on the recipe will show all possible ingredients player has

This commit is contained in:
minjaesong
2023-10-01 03:11:01 +09:00
parent 908a6ed953
commit abcc85a3de
4 changed files with 125 additions and 82 deletions

View File

@@ -948,3 +948,5 @@ fun distBetween(a: ActorWithBody, bpos: Vector2): Double {
val dist = min(min(bpos.distanceSquared(apos1), bpos.distanceSquared(apos2)), bpos.distanceSquared(apos3)) val dist = min(min(bpos.distanceSquared(apos1), bpos.distanceSquared(apos2)), bpos.distanceSquared(apos3))
return dist.sqrt() return dist.sqrt()
} }
fun getHashStr(length: Int = 5) = (0 until length).map { "YBNDRFG8EJKMCPQXOTLVWIS2A345H769"[Math.random().times(32).toInt()] }.joinToString("")

View File

@@ -155,6 +155,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
_getItemListPlayer().let { _getItemListPlayer().let {
it.removeFromForceHighlightList(oldSelectedItems) it.removeFromForceHighlightList(oldSelectedItems)
filterPlayerListUsing(recipeClicked)
it.addToForceHighlightList(selectedItems) it.addToForceHighlightList(selectedItems)
it.rebuild(catAll) it.rebuild(catAll)
} }
@@ -204,42 +205,42 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
// player inventory to the right // player inventory to the right
itemListPlayer = UIItemInventoryItemGrid( itemListPlayer = UIItemInventoryItemGrid(
this, this,
catBar, catBar,
{ INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory { INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory
thisOffsetX2, thisOffsetX2,
thisOffsetY, thisOffsetY,
6, UIInventoryFull.CELLS_VRT, 6, UIInventoryFull.CELLS_VRT,
drawScrollOnRightside = true, drawScrollOnRightside = true,
drawWallet = false, drawWallet = false,
highlightEquippedItem = false, highlightEquippedItem = false,
keyDownFun = { _, _, _, _, _ -> }, keyDownFun = { _, _, _, _, _ -> },
touchDownFun = { gameItem, amount, _, _, button -> recipeClicked?.let { recipe -> gameItem?.let { gameItem -> touchDownFun = { gameItem, amount, _, _, button -> recipeClicked?.let { recipe -> gameItem?.let { gameItem ->
val itemID = gameItem.dynamicID val itemID = gameItem.dynamicID
// don't rely on highlightedness of the button to determine the item on the button is the selected // don't rely on highlightedness of the button to determine the item on the button is the selected
// ingredient (because I don't fully trust my code lol) // ingredient (because I don't fully trust my code lol)
val targetItemToAlter = recipe.ingredients.filter { (key, mode) -> // altering recipe doesn't make sense if player selected a recipe that requires no tag-ingredients val targetItemToAlter = recipe.ingredients.filter { (key, mode) -> // altering recipe doesn't make sense if player selected a recipe that requires no tag-ingredients
val tags = key.split(',')
val wantsWall = tags.contains("WALL")
(mode == CraftingCodex.CraftingItemKeyMode.TAG && gameItem.hasAllTags(tags) && (wantsWall == gameItem.originalID.isWall())) // true if (wants wall and is wall) or (wants no wall and is not wall)
}.let {
if (it.size > 1)
println("[UICrafting] Your recipe seems to have two similar ingredients defined\n" +
"affected ingredients: ${it.joinToString()}\n" +
"the recipe: ${recipe}")
it.firstOrNull()
}
targetItemToAlter?.let { (key, mode) ->
val oldItem = _getItemListIngredients().getInventory().first { (itm, qty) ->
val tags = key.split(',') val tags = key.split(',')
val wantsWall = tags.contains("WALL") val wantsWall = tags.contains("WALL")
(mode == CraftingCodex.CraftingItemKeyMode.TAG && gameItem.hasAllTags(tags) && (wantsWall == gameItem.originalID.isWall())) // true if (wants wall and is wall) or (wants no wall and is not wall) (mode == CraftingCodex.CraftingItemKeyMode.TAG && ItemCodex[itm]!!.hasAllTags(tags) && (wantsWall == itm.isWall())) // true if (wants wall and is wall) or (wants no wall and is not wall)
}.let {
if (it.size > 1)
println("[UICrafting] Your recipe seems to have two similar ingredients defined\n" +
"affected ingredients: ${it.joinToString()}\n" +
"the recipe: ${recipe}")
it.firstOrNull()
} }
changeIngredient(recipe, oldItem, itemID)
targetItemToAlter?.let { (key, mode) -> refreshCraftButtonStatus()
val oldItem = _getItemListIngredients().getInventory().first { (itm, qty) -> }
val tags = key.split(',') } } }
val wantsWall = tags.contains("WALL")
(mode == CraftingCodex.CraftingItemKeyMode.TAG && ItemCodex[itm]!!.hasAllTags(tags) && (wantsWall == itm.isWall())) // true if (wants wall and is wall) or (wants no wall and is not wall)
}
changeIngredient(oldItem, itemID)
refreshCraftButtonStatus()
}
} } }
) )
// make grid mode buttons work together // make grid mode buttons work together
// itemListPlayer.gridModeButtons[0].clickOnceListener = { _,_ -> setCompact(false) } // itemListPlayer.gridModeButtons[0].clickOnceListener = { _,_ -> setCompact(false) }
@@ -249,39 +250,39 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
// crafting list to the left // crafting list to the left
itemListCraftable = UIItemCraftingCandidateGrid( itemListCraftable = UIItemCraftingCandidateGrid(
this, this,
catBar, catBar,
thisOffsetX, thisOffsetX,
thisOffsetY, thisOffsetY,
6, UIInventoryFull.CELLS_VRT - 2, // decrease the internal height so that craft/cancel button would fit in 6, UIInventoryFull.CELLS_VRT - 2, // decrease the internal height so that craft/cancel button would fit in
keyDownFun = { _, _, _, _, _ -> }, keyDownFun = { _, _, _, _, _ -> },
touchDownFun = { gameItem, amount, _, recipe0, button -> touchDownFun = { gameItem, amount, _, recipe0, button ->
(recipe0 as? CraftingCodex.CraftingRecipe)?.let { recipe -> (recipe0 as? CraftingCodex.CraftingRecipe)?.let { recipe ->
val selectedItems = ArrayList<ItemID>() val selectedItems = ArrayList<ItemID>()
val playerInventory = getPlayerInventory() val playerInventory = getPlayerInventory()
ingredients.clear() ingredients.clear()
recipeClicked = recipe recipeClicked = recipe
// printdbg(this, "Recipe selected: $recipe") // printdbg(this, "Recipe selected: $recipe")
recipe.ingredients.forEach { ingredient -> recipe.ingredients.forEach { ingredient ->
val selectedItem = getItemForIngredient(playerInventory, ingredient) val selectedItem = getItemForIngredient(playerInventory, ingredient)
selectedItems.add(selectedItem) selectedItems.add(selectedItem)
ingredients.add(selectedItem, ingredient.qty) ingredients.add(selectedItem, ingredient.qty)
}
_getItemListPlayer().removeFromForceHighlightList(oldSelectedItems)
_getItemListPlayer().addToForceHighlightList(selectedItems)
_getItemListPlayer().rebuild(catAll)
_getItemListIngredients().rebuild(catAll)
highlightCraftingCandidateButton(recipe)
oldSelectedItems.clear()
oldSelectedItems.addAll(selectedItems)
refreshCraftButtonStatus()
} }
_getItemListPlayer().removeFromForceHighlightList(oldSelectedItems)
_getItemListPlayer().addToForceHighlightList(selectedItems)
filterPlayerListUsing(recipeClicked)
_getItemListIngredients().rebuild(catAll)
highlightCraftingCandidateButton(recipe)
oldSelectedItems.clear()
oldSelectedItems.addAll(selectedItems)
refreshCraftButtonStatus()
} }
}
) )
buttonCraft = UIItemTextButton(this, buttonCraft = UIItemTextButton(this,
{ Lang["GAME_ACTION_CRAFT"] }, thisOffsetX + 3 + buttonWidth + listGap, craftButtonsY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true) { Lang["GAME_ACTION_CRAFT"] }, thisOffsetX + 3 + buttonWidth + listGap, craftButtonsY, buttonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
@@ -330,6 +331,18 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
addUIitem(buttonCraft) addUIitem(buttonCraft)
} }
private fun filterPlayerListUsing(recipe: CraftingCodex.CraftingRecipe?) {
if (recipe == null)
itemListPlayer.rebuild(catAll)
else {
val items = recipe.ingredients.flatMap { getItemCandidatesForIngredient(getPlayerInventory(), it).map { it.itm } }.sorted()
val filterFun = { pair: InventoryPair ->
items.binarySearch(pair.itm) >= 0
}
itemListPlayer.rebuild(filterFun)
}
}
var nearbyCraftingStations = emptyList<String>(); protected set var nearbyCraftingStations = emptyList<String>(); protected set
fun getCraftingStationsWithinReach(): List<String> { fun getCraftingStationsWithinReach(): List<String> {
@@ -340,14 +353,14 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
return nearbyCraftingStations.flatMap { (it.get() as CraftingStation).tags } return nearbyCraftingStations.flatMap { (it.get() as CraftingStation).tags }
} }
private fun changeIngredient(old: InventoryPair, new: ItemID) { private fun changeIngredient(recipe: CraftingCodex.CraftingRecipe?, old: InventoryPair, new: ItemID) {
itemListPlayer.removeFromForceHighlightList(oldSelectedItems) itemListPlayer.removeFromForceHighlightList(oldSelectedItems)
oldSelectedItems.remove(old.itm) oldSelectedItems.remove(old.itm)
oldSelectedItems.add(new) oldSelectedItems.add(new)
itemListPlayer.addToForceHighlightList(oldSelectedItems) itemListPlayer.addToForceHighlightList(oldSelectedItems)
itemListPlayer.rebuild(catAll) filterPlayerListUsing(recipe)
// change highlight status of itemListIngredients // change highlight status of itemListIngredients
itemListIngredients.getInventory().let { itemListIngredients.getInventory().let {
@@ -384,6 +397,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
resetSpinner() resetSpinner()
// reset selected recipe status // reset selected recipe status
recipeClicked = null recipeClicked = null
filterPlayerListUsing(recipeClicked)
highlightCraftingCandidateButton(null) highlightCraftingCandidateButton(null)
ingredients.clear() ingredients.clear()
itemListPlayer.removeFromForceHighlightList(oldSelectedItems) itemListPlayer.removeFromForceHighlightList(oldSelectedItems)
@@ -411,6 +425,8 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
UIItemInventoryItemGrid.tooltipShowing.clear() UIItemInventoryItemGrid.tooltipShowing.clear()
INGAME.setTooltipMessage(null) INGAME.setTooltipMessage(null)
resetUI()
} }
private var encumbrancePerc = 0f private var encumbrancePerc = 0f
@@ -507,7 +523,6 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
override fun doOpening(delta: Float) { override fun doOpening(delta: Float) {
super.doOpening(delta) super.doOpening(delta)
resetUI()
INGAME.setTooltipMessage(null) INGAME.setTooltipMessage(null)
} }
@@ -541,14 +556,28 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
val craftingStationAvailable: Boolean, val craftingStationAvailable: Boolean,
) )
fun getItemForIngredient(inventory: FixtureInventory, ingredient: CraftingCodex.CraftingIngredients): ItemID { fun getItemCandidatesForIngredient(inventory: FixtureInventory, ingredient: CraftingCodex.CraftingIngredients): List<InventoryPair> {
return if (ingredient.keyMode == CraftingCodex.CraftingItemKeyMode.TAG) { return if (ingredient.keyMode == CraftingCodex.CraftingItemKeyMode.TAG) {
val tags = ingredient.key.split(',') val tags = ingredient.key.split(',')
val wantsWall = tags.contains("WALL") val wantsWall = tags.contains("WALL")
// If the player has the required item, use it; otherwise, will take an item from the ItemCodex // If the player has the required item, use it; otherwise, will take an item from the ItemCodex
inventory.filter { (itm, qty) -> inventory.filter { (itm, qty) ->
ItemCodex[itm]?.hasAllTags(tags) == true && qty >= ingredient.qty && (wantsWall == itm.isWall()) // true if (wants wall and is wall) or (wants no wall and is not wall) ItemCodex[itm]?.hasAllTags(tags) == true && qty >= ingredient.qty && (wantsWall == itm.isWall()) // true if (wants wall and is wall) or (wants no wall and is not wall)
}.maxByOrNull { it.qty }?.itm ?: ((ItemCodex.itemCodex.firstNotNullOfOrNull { if (it.value.hasTag(ingredient.key)) it.key else null }) ?: throw NullPointerException("Item with tag '${ingredient.key}' not found. Possible cause: game or a module not updated or installed")) }
}
else {
listOf(InventoryPair(ingredient.key, -1))
}
}
fun getItemForIngredient(inventory: FixtureInventory, ingredient: CraftingCodex.CraftingIngredients): ItemID {
val candidate = getItemCandidatesForIngredient(inventory, ingredient)
return if (ingredient.keyMode == CraftingCodex.CraftingItemKeyMode.TAG) {
candidate.maxByOrNull { it.qty }?.itm ?: (
(ItemCodex.itemCodex.firstNotNullOfOrNull { if (it.value.hasTag(ingredient.key)) it.key else null }) ?:
throw NullPointerException("Item with tag '${ingredient.key}' not found. Possible cause: game or a module not updated or installed")
)
} }
else { else {
ingredient.key ingredient.key

View File

@@ -8,6 +8,7 @@ import net.torvald.terrarum.ceilToInt
import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.itemproperties.CraftingCodex import net.torvald.terrarum.itemproperties.CraftingCodex
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair
/** /**
* Created by minjaesong on 2022-06-28. * Created by minjaesong on 2022-06-28.
@@ -69,7 +70,11 @@ class UIItemCraftingCandidateGrid(
highlightRecipe(highlightedRecipe) highlightRecipe(highlightedRecipe)
} }
private var currentFilter1 = arrayOf("")
override fun rebuild(filter: Array<String>) { override fun rebuild(filter: Array<String>) {
currentFilter1 = filter
// filtering policy: if the player have all the ingredient item (regardless of the amount!), make the recipe visible // filtering policy: if the player have all the ingredient item (regardless of the amount!), make the recipe visible
craftingRecipes.clear() craftingRecipes.clear()
CraftingRecipeCodex.props.forEach { (_, recipes) -> CraftingRecipeCodex.props.forEach { (_, recipes) ->
@@ -111,14 +116,12 @@ class UIItemCraftingCandidateGrid(
itemPageCount = (recipesSortList.size.toFloat() / items.size.toFloat()).ceilToInt() itemPageCount = (recipesSortList.size.toFloat() / items.size.toFloat()).ceilToInt()
rebuildList = false rebuildList = false
} }
override fun rebuild(filterFun: (InventoryPair) -> Boolean) {
rebuild(currentFilter1)
}
override fun scrolled(amountX: Float, amountY: Float): Boolean { override fun scrolled(amountX: Float, amountY: Float): Boolean {
super.scrolled(amountX, amountY) super.scrolled(amountX, amountY)

View File

@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.* import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.UIItemInventoryCatBar.Companion.CAT_ALL import net.torvald.terrarum.UIItemInventoryCatBar.Companion.CAT_ALL
import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameitems.GameItem
@@ -54,6 +55,8 @@ open class UIItemInventoryItemGrid(
//override var oldPosX = posX //override var oldPosX = posX
//override var oldPosY = posY //override var oldPosY = posY
internal val instanceHash = getHashStr(5)
var numberMultiplier = 1L var numberMultiplier = 1L
private val hash = System.nanoTime() private val hash = System.nanoTime()
@@ -81,7 +84,7 @@ open class UIItemInventoryItemGrid(
arrayOf(GameItem.Category.MISC), arrayOf(GameItem.Category.MISC),
arrayOf(CAT_ALL) arrayOf(CAT_ALL)
)*/ )*/
protected var currentFilter = arrayOf(CAT_ALL) protected var currentFilter: (InventoryPair) -> Boolean = { _: InventoryPair -> true }
private val inventoryUI = parentUI private val inventoryUI = parentUI
@@ -373,21 +376,21 @@ open class UIItemInventoryItemGrid(
forceHighlightList.removeAll(items) forceHighlightList.removeAll(items)
} }
open fun rebuild(filter: Array<String>) { open fun rebuild(filterFun: (InventoryPair) -> Boolean) {
currentFilter = filterFun
//println("Rebuilt inventory") //println("Rebuilt inventory")
//println("rebuild: actual itempage: $itemPage") //println("rebuild: actual itempage: $itemPage")
//val filter = catIconsMeaning[selectedIcon] //val filter = catIconsMeaning[selectedIcon]
currentFilter = filter
inventorySortList.clear() inventorySortList.clear()
// filter items // filter items
getInventory().forEach { val filteredItems = getInventory().filter(filterFun)
if ((filter.contains((ItemCodex[it.itm]?.inventoryCategory ?: throw IllegalArgumentException("Unknown item: ${it.itm}"))) || filter[0] == CAT_ALL)) inventorySortList.addAll(filteredItems)
inventorySortList.add(it)
}
// sort if needed // sort if needed
// test sort by name // test sort by name
@@ -455,6 +458,12 @@ open class UIItemInventoryItemGrid(
rebuildList = false rebuildList = false
} }
open fun rebuild(filter: Array<String>) {
val filterFun = if (filter[0] == CAT_ALL) { item: InventoryPair -> true }
else { item: InventoryPair -> filter.contains(ItemCodex[item.itm]?.inventoryCategory ?: throw IllegalArgumentException("Unknown item: ${item.itm}")) }
rebuild(filterFun)
}
override fun dispose() { override fun dispose() {
tooltipShowing.remove(hash) tooltipShowing.remove(hash)
} }
@@ -485,7 +494,7 @@ open class UIItemInventoryItemGrid(
super.keyDown(keycode) super.keyDown(keycode)
items.forEach { if (it.mouseUp) it.keyDown(keycode) } items.forEach { if (it.mouseUp) it.keyDown(keycode) }
rebuild(currentFilter) // rebuild(currentFilter)
return true return true
} }
@@ -494,7 +503,7 @@ open class UIItemInventoryItemGrid(
super.keyUp(keycode) super.keyUp(keycode)
items.forEach { if (it.mouseUp) it.keyUp(keycode) } items.forEach { if (it.mouseUp) it.keyUp(keycode) }
rebuild(currentFilter) // rebuild(currentFilter)
return true return true
} }