diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 09210bcb6..d8f35c1de 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -947,4 +947,6 @@ fun distBetween(a: ActorWithBody, bpos: Vector2): Double { val apos3 = Vector2(apos1.x - ww, apos1.y) val dist = min(min(bpos.distanceSquared(apos1), bpos.distanceSquared(apos2)), bpos.distanceSquared(apos3)) return dist.sqrt() -} \ No newline at end of file +} + +fun getHashStr(length: Int = 5) = (0 until length).map { "YBNDRFG8EJKMCPQXOTLVWIS2A345H769"[Math.random().times(32).toInt()] }.joinToString("") diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UICrafting.kt b/src/net/torvald/terrarum/modulebasegame/ui/UICrafting.kt index 3b62b5bac..5e9f9e7e4 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UICrafting.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UICrafting.kt @@ -155,6 +155,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { _getItemListPlayer().let { it.removeFromForceHighlightList(oldSelectedItems) + filterPlayerListUsing(recipeClicked) it.addToForceHighlightList(selectedItems) it.rebuild(catAll) } @@ -204,42 +205,42 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { // player inventory to the right itemListPlayer = UIItemInventoryItemGrid( - this, - catBar, - { INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory - thisOffsetX2, - thisOffsetY, - 6, UIInventoryFull.CELLS_VRT, - drawScrollOnRightside = true, - drawWallet = false, - highlightEquippedItem = false, - keyDownFun = { _, _, _, _, _ -> }, - touchDownFun = { gameItem, amount, _, _, button -> recipeClicked?.let { recipe -> gameItem?.let { gameItem -> - val itemID = gameItem.dynamicID - // 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) - val targetItemToAlter = recipe.ingredients.filter { (key, mode) -> // altering recipe doesn't make sense if player selected a recipe that requires no tag-ingredients + this, + catBar, + { INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory + thisOffsetX2, + thisOffsetY, + 6, UIInventoryFull.CELLS_VRT, + drawScrollOnRightside = true, + drawWallet = false, + highlightEquippedItem = false, + keyDownFun = { _, _, _, _, _ -> }, + touchDownFun = { gameItem, amount, _, _, button -> recipeClicked?.let { recipe -> gameItem?.let { gameItem -> + val itemID = gameItem.dynamicID + // 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) + 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 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() + (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) } - - targetItemToAlter?.let { (key, mode) -> - 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() - } - } } } + changeIngredient(recipe, oldItem, itemID) + refreshCraftButtonStatus() + } + } } } ) // make grid mode buttons work together // itemListPlayer.gridModeButtons[0].clickOnceListener = { _,_ -> setCompact(false) } @@ -249,39 +250,39 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { // crafting list to the left itemListCraftable = UIItemCraftingCandidateGrid( - this, - catBar, - thisOffsetX, - thisOffsetY, - 6, UIInventoryFull.CELLS_VRT - 2, // decrease the internal height so that craft/cancel button would fit in - keyDownFun = { _, _, _, _, _ -> }, - touchDownFun = { gameItem, amount, _, recipe0, button -> - (recipe0 as? CraftingCodex.CraftingRecipe)?.let { recipe -> - val selectedItems = ArrayList() + this, + catBar, + thisOffsetX, + thisOffsetY, + 6, UIInventoryFull.CELLS_VRT - 2, // decrease the internal height so that craft/cancel button would fit in + keyDownFun = { _, _, _, _, _ -> }, + touchDownFun = { gameItem, amount, _, recipe0, button -> + (recipe0 as? CraftingCodex.CraftingRecipe)?.let { recipe -> + val selectedItems = ArrayList() - val playerInventory = getPlayerInventory() - ingredients.clear() - recipeClicked = recipe + val playerInventory = getPlayerInventory() + ingredients.clear() + recipeClicked = recipe // printdbg(this, "Recipe selected: $recipe") - recipe.ingredients.forEach { ingredient -> - val selectedItem = getItemForIngredient(playerInventory, ingredient) - selectedItems.add(selectedItem) - 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() + recipe.ingredients.forEach { ingredient -> + val selectedItem = getItemForIngredient(playerInventory, ingredient) + selectedItems.add(selectedItem) + ingredients.add(selectedItem, ingredient.qty) } + + _getItemListPlayer().removeFromForceHighlightList(oldSelectedItems) + _getItemListPlayer().addToForceHighlightList(selectedItems) + filterPlayerListUsing(recipeClicked) + _getItemListIngredients().rebuild(catAll) + + highlightCraftingCandidateButton(recipe) + + oldSelectedItems.clear() + oldSelectedItems.addAll(selectedItems) + + refreshCraftButtonStatus() } + } ) buttonCraft = UIItemTextButton(this, { 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) } + 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(); protected set fun getCraftingStationsWithinReach(): List { @@ -340,14 +353,14 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { 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) oldSelectedItems.remove(old.itm) oldSelectedItems.add(new) itemListPlayer.addToForceHighlightList(oldSelectedItems) - itemListPlayer.rebuild(catAll) + filterPlayerListUsing(recipe) // change highlight status of itemListIngredients itemListIngredients.getInventory().let { @@ -384,6 +397,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { resetSpinner() // reset selected recipe status recipeClicked = null + filterPlayerListUsing(recipeClicked) highlightCraftingCandidateButton(null) ingredients.clear() itemListPlayer.removeFromForceHighlightList(oldSelectedItems) @@ -411,6 +425,8 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { UIItemInventoryItemGrid.tooltipShowing.clear() INGAME.setTooltipMessage(null) + + resetUI() } private var encumbrancePerc = 0f @@ -507,7 +523,6 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { override fun doOpening(delta: Float) { super.doOpening(delta) - resetUI() INGAME.setTooltipMessage(null) } @@ -541,14 +556,28 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory { val craftingStationAvailable: Boolean, ) - fun getItemForIngredient(inventory: FixtureInventory, ingredient: CraftingCodex.CraftingIngredients): ItemID { + fun getItemCandidatesForIngredient(inventory: FixtureInventory, ingredient: CraftingCodex.CraftingIngredients): List { return if (ingredient.keyMode == CraftingCodex.CraftingItemKeyMode.TAG) { val tags = ingredient.key.split(',') val wantsWall = tags.contains("WALL") // If the player has the required item, use it; otherwise, will take an item from the ItemCodex 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) - }.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 { ingredient.key diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIItemCraftingCandidateGrid.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIItemCraftingCandidateGrid.kt index e3d90ff7d..b8cab7e56 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIItemCraftingCandidateGrid.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIItemCraftingCandidateGrid.kt @@ -8,6 +8,7 @@ import net.torvald.terrarum.ceilToInt import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.itemproperties.CraftingCodex import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory +import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair /** * Created by minjaesong on 2022-06-28. @@ -69,7 +70,11 @@ class UIItemCraftingCandidateGrid( highlightRecipe(highlightedRecipe) } + private var currentFilter1 = arrayOf("") + override fun rebuild(filter: Array) { + currentFilter1 = filter + // filtering policy: if the player have all the ingredient item (regardless of the amount!), make the recipe visible craftingRecipes.clear() CraftingRecipeCodex.props.forEach { (_, recipes) -> @@ -111,14 +116,12 @@ class UIItemCraftingCandidateGrid( itemPageCount = (recipesSortList.size.toFloat() / items.size.toFloat()).ceilToInt() - - - rebuildList = false } - - + override fun rebuild(filterFun: (InventoryPair) -> Boolean) { + rebuild(currentFilter1) + } override fun scrolled(amountX: Float, amountY: Float): Boolean { super.scrolled(amountX, amountY) diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt index 9def7983a..7fcb8577e 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIItemInventoryItemGrid.kt @@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.terrarum.* +import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.UIItemInventoryCatBar.Companion.CAT_ALL import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameitems.GameItem @@ -54,6 +55,8 @@ open class UIItemInventoryItemGrid( //override var oldPosX = posX //override var oldPosY = posY + internal val instanceHash = getHashStr(5) + var numberMultiplier = 1L private val hash = System.nanoTime() @@ -81,7 +84,7 @@ open class UIItemInventoryItemGrid( arrayOf(GameItem.Category.MISC), arrayOf(CAT_ALL) )*/ - protected var currentFilter = arrayOf(CAT_ALL) + protected var currentFilter: (InventoryPair) -> Boolean = { _: InventoryPair -> true } private val inventoryUI = parentUI @@ -373,21 +376,21 @@ open class UIItemInventoryItemGrid( forceHighlightList.removeAll(items) } - open fun rebuild(filter: Array) { + open fun rebuild(filterFun: (InventoryPair) -> Boolean) { + currentFilter = filterFun + //println("Rebuilt inventory") //println("rebuild: actual itempage: $itemPage") //val filter = catIconsMeaning[selectedIcon] - currentFilter = filter inventorySortList.clear() // filter items - getInventory().forEach { - if ((filter.contains((ItemCodex[it.itm]?.inventoryCategory ?: throw IllegalArgumentException("Unknown item: ${it.itm}"))) || filter[0] == CAT_ALL)) - inventorySortList.add(it) - } + val filteredItems = getInventory().filter(filterFun) + inventorySortList.addAll(filteredItems) + // sort if needed // test sort by name @@ -455,6 +458,12 @@ open class UIItemInventoryItemGrid( rebuildList = false } + open fun rebuild(filter: Array) { + 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() { tooltipShowing.remove(hash) } @@ -485,7 +494,7 @@ open class UIItemInventoryItemGrid( super.keyDown(keycode) items.forEach { if (it.mouseUp) it.keyDown(keycode) } - rebuild(currentFilter) +// rebuild(currentFilter) return true } @@ -494,7 +503,7 @@ open class UIItemInventoryItemGrid( super.keyUp(keycode) items.forEach { if (it.mouseUp) it.keyUp(keycode) } - rebuild(currentFilter) +// rebuild(currentFilter) return true }