--*********************************************************** --** ROBERT JOHNSON ** --*********************************************************** require "ISUI/ISCollapsableWindow" ISCraftingUI = ISCollapsableWindow:derive("ISCraftingUI"); ISCraftingUI.instance = nil; ISCraftingUI.largeFontHeight = getTextManager():getFontHeight(UIFont.Large) ISCraftingUI.mediumFontHeight = getTextManager():getFontHeight(UIFont.Medium) ISCraftingUI.smallFontHeight = getTextManager():getFontHeight(UIFont.Small) ISCraftingUI.bottomInfoHeight = ISCraftingUI.smallFontHeight * 2 ISCraftingUI.qwertyConfiguration = true; ISCraftingUI.bottomTextSpace = " "; ISCraftingUI.leftCategory = Keyboard.KEY_LEFT; ISCraftingUI.rightCategory = Keyboard.KEY_RIGHT; ISCraftingUI.upArrow = Keyboard.KEY_UP; ISCraftingUI.downArrow = Keyboard.KEY_DOWN; function ISCraftingUI:getRecipeListBox() return self.panel.activeView.view.recipes end function ISCraftingUI:setVisible(bVisible) self.javaObject:setVisible(bVisible); self.javaObject:setEnabled(bVisible) if not bVisible then -- save the selected index self.selectedIndex = {}; for i,v in ipairs(self.categories) do self.selectedIndex[v.category] = v.recipes.selected; end end -- if getPlayer() then -- self.character:setBlockMovement(bVisible); -- end if bVisible and self.recipesList then self:refresh(); end -- load saved selected index if bVisible then for i,v in ipairs(self.categories) do if self.selectedIndex[v.category] then v.recipes.selected = self.selectedIndex[v.category]; end end end self.craftInProgress = false; local recipeListBox = self:getRecipeListBox() recipeListBox:ensureVisible(recipeListBox.selected); if bVisible then self.knownRecipes = RecipeManager.getKnownRecipesNumber(self.character); self.totalRecipes = getAllRecipes():size(); end -- print("KNOWN RECIPES", self.knownRecipes, self.totalRecipes); end function ISCraftingUI:refresh() local recipeListBox = self:getRecipeListBox() local selectedItem = recipeListBox.items[recipeListBox.selected]; if selectedItem then selectedItem = selectedItem.item.recipe end local selectedView = self.panel.activeView.name; self:getContainers(); self:populateRecipesList(); self:sortList(); for i=#self.categories,1,-1 do local categoryUI = self.categories[i]; -- Remove unknown categories (due to recipes being forgotten). local found = false; for j=1,#self.recipesListH do if self.recipesListH[j] == categoryUI.category then found = true; break; end end if not found then self.panel:removeView(categoryUI); table.remove(self.categories, i); else categoryUI:filter(); end end self.panel:activateView(selectedView); if selectedItem then for i,item in ipairs(recipeListBox.items) do if item.item.recipe == selectedItem then recipeListBox.selected = i; break; end end end -- create the new categories if needed local k for k = 1 , #self.recipesListH, 1 do local i = self.recipesListH[k] local v = self.recipesList[i] --for i,v in pairs(self.recipesList) do local found = false; for k,l in ipairs(self.categories) do if i == l.category then found = true; break; end end if not found then local cat1 = ISCraftingCategoryUI:new(0, 0, self.width, self.panel.height - self.panel.tabHeight, self); cat1:initialise(); local catName = getTextOrNull("IGUI_CraftCategory_"..i) or i self.panel:addView(catName, cat1); cat1.infoText = getText("UI_CraftingUI"); cat1.parent = self; cat1.category = i; for s,d in ipairs(v) do cat1.recipes:addItem(s,d); end table.insert(self.categories, cat1); end end -- switch panel if there's no item in this list if #recipeListBox.items == 0 then self.panel:activateView(getText("IGUI_CraftCategory_General")); end -- self:refreshTickBox(); self:refreshIngredientList() end function ISCraftingUI:isWaterSource(item, count) -- Fk'n rounding differences between Java and Lua broke simple getUsedDelta()/getUseDelta() here, so I added getDrainableUsesInt() return instanceof(item, "DrainableComboItem") and item:isWaterSource() and item:getDrainableUsesInt() >= count end function ISCraftingUI:transferItems() local result = {} local recipeListBox = self:getRecipeListBox() local recipe = recipeListBox.items[recipeListBox.selected].item.recipe; local items = RecipeManager.getAvailableItemsNeeded(recipe, self.character, self.containerList, nil, nil); if items:isEmpty() then return result end; for i=1,items:size() do local item = items:get(i-1) table.insert(result, item) if not recipe:isCanBeDoneFromFloor() then if item:getContainer() ~= self.character:getInventory() then ISTimedActionQueue.add(ISInventoryTransferAction:new(self.character, item, item:getContainer(), self.character:getInventory(), nil)); end end end return result end function ISCraftingUI:getAvailableItemsType() local result = {}; local recipeListBox = self:getRecipeListBox() local recipe = recipeListBox.items[recipeListBox.selected].item.recipe; local items = RecipeManager.getAvailableItemsAll(recipe, self.character, self.containerList, nil, nil); for i=0, recipe:getSource():size()-1 do local source = recipe:getSource():get(i); local sourceItemTypes = {}; for k=1,source:getItems():size() do local sourceFullType = source:getItems():get(k-1); sourceItemTypes[sourceFullType] = true; end for x=0,items:size()-1 do local item = items:get(x) if sourceItemTypes["Water"] and self:isWaterSource(item, source:getCount()) then result["Water"] = (result["Water"] or 0) + item:getDrainableUsesInt() elseif sourceItemTypes[item:getFullType()] then local count = 1 if not source:isDestroy() and item:IsDrainable() then count = item:getDrainableUsesInt() end if not source:isDestroy() and instanceof(item, "Food") then if source:getUse() > 0 then count = -item:getHungerChange() * 100 end end result[item:getFullType()] = (result[item:getFullType()] or 0) + count; end end end return result; end function ISCraftingUI:initialise() ISCollapsableWindow.initialise(self); end function ISCraftingUI:close() ISCollapsableWindow.close(self) if JoypadState.players[self.playerNum+1] then setJoypadFocus(self.playerNum, nil) end end ISCraftingUI.sortByName = function(a,b) return string.sort(b.recipe:getName(), a.recipe:getName()); end function ISCraftingUI:getContainers() if not self.character then return end -- get all the surrounding inventory of the player, gonna check for the item in them too self.containerList = ArrayList.new(); for i,v in ipairs(getPlayerInventory(self.playerNum).inventoryPane.inventoryPage.backpacks) do -- if v.inventory ~= self.character:getInventory() then -- owner inventory already check in RecipeManager self.containerList:add(v.inventory); -- end end for i,v in ipairs(getPlayerLoot(self.playerNum).inventoryPane.inventoryPage.backpacks) do self.containerList:add(v.inventory); end end function ISCraftingUI:refreshTickBox() local recipeListBox = self:getRecipeListBox() local selectedItem = recipeListBox.items[recipeListBox.selected].item; self.tickBox.options = {}; self.tickBox.optionCount = 1; for m,l in ipairs(selectedItem.multipleItems) do self.tickBox:addOption(l.name, nil, l.texture) if m == 1 then self.tickBox:setSelected(m, true) end end end function ISCraftingUI:drawNonEvolvedIngredient(y, item, alt) if y + self:getYScroll() >= self.height then return y + self.itemheight end if y + self.itemheight + self:getYScroll() <= 0 then return y + self.itemheight end if not self.parent.recipeListHasFocus and self.selected == item.index then self:drawRectBorder(1, y, self:getWidth()-2, self.itemheight, 1.0, 0.5, 0.5, 0.5); end if item.item.multipleHeader then local r,g,b = 1,1,1 if not item.item.available then r,g,b = 0.54,0.54,0.54 end self:drawText(item.text, 12, y + 2, r, g, b, 1, self.font) self:drawTexture(item.item.texture, 4, y + (item.height - item.item.texture:getHeight()) / 2 - 2, 1,1,1,1) else local r,g,b local r2,g2,b2,a2 local typesAvailable = item.item.selectedItem.typesAvailable if typesAvailable and (not typesAvailable[item.item.fullType] or typesAvailable[item.item.fullType] < item.item.count) then r,g,b = 0.54,0.54,0.54; r2,g2,b2,a2 = 1,1,1,0.3; else r,g,b = 1,1,1; r2,g2,b2,a2 = 1,1,1,0.9; end local imgW = 20 local imgH = 20 local dx = 6 + (item.item.multiple and 10 or 0) self:drawText(item.text, dx + imgW + 4, y + (item.height - ISCraftingUI.smallFontHeight) / 2, r, g, b, 1, self.font) if item.item.texture then local texWidth = item.item.texture:getWidth() local texHeight = item.item.texture:getHeight() self:drawTextureScaledAspect(item.item.texture, dx, y + (self.itemheight - imgH) / 2, 20, 20, a2,r2,g2,b2) end end return y + self.itemheight; end -- Return true if item2's type is in item1's getClothingExtraItem() list. function ISCraftingUI:isExtraClothingItemOf(item1, item2) local scriptItem = getScriptManager():FindItem(item1.fullType) if not scriptItem then return false end local extras = scriptItem:getClothingItemExtra() if not extras then return false end local moduleName = scriptItem:getModule():getName() for i=1,extras:size() do local extra = extras:get(i-1) local fullType = moduleDotType(moduleName, extra) if item2.fullType == fullType then return true end end return false end function ISCraftingUI:removeExtraClothingItemsFromList(index, item, itemList) for k=#itemList,index,-1 do local item2 = itemList[k] if self:isExtraClothingItemOf(item, item2) then table.remove(itemList, k) end end end -- Non-evolved recipes function ISCraftingUI:refreshIngredientPanel() local hasFocus = not self.recipeListHasFocus self.recipeListHasFocus = true self.ingredientPanel:setVisible(false) local recipeListbox = self:getRecipeListBox() if not recipeListbox.items or #recipeListbox.items == 0 or not recipeListbox.items[recipeListbox.selected] then return end local selectedItem = recipeListbox.items[recipeListbox.selected].item; if not selectedItem or selectedItem.evolved then return end selectedItem.typesAvailable = self:getAvailableItemsType() self.recipeListHasFocus = not hasFocus self.ingredientPanel:setVisible(true) self.ingredientPanel:clear() -- Display single-item sources before multi-item sources local sortedSources = {} for _,source in ipairs(selectedItem.sources) do table.insert(sortedSources, source) end table.sort(sortedSources, function(a,b) return #a.items == 1 and #b.items > 1 end) for _,source in ipairs(sortedSources) do local available = {} local unavailable = {} for _,item in ipairs(source.items) do local data = {} data.selectedItem = selectedItem data.name = item.name data.texture = item.texture data.fullType = item.fullType data.count = item.count data.recipe = selectedItem.recipe data.multiple = #source.items > 1 if selectedItem.typesAvailable and (not selectedItem.typesAvailable[item.fullType] or selectedItem.typesAvailable[item.fullType] < item.count) then table.insert(unavailable, data) else table.insert(available, data) end end table.sort(available, function(a,b) return not string.sort(a.name, b.name) end) table.sort(unavailable, function(a,b) return not string.sort(a.name, b.name) end) if #source.items > 1 then local data = {} data.selectedItem = selectedItem data.texture = self.TreeExpanded data.multipleHeader = true data.available = #available > 0 self.ingredientPanel:addItem(getText("IGUI_CraftUI_OneOf"), data) end -- Hack for "Dismantle Digital Watch" and similar recipes. -- Recipe sources include both left-hand and right-hand versions of the same item. -- We only want to display one of them. ---[[ for j=1,#available do local item = available[j] self:removeExtraClothingItemsFromList(j+1, item, available) end for j=1,#available do local item = available[j] self:removeExtraClothingItemsFromList(1, item, unavailable) end for j=1,#unavailable do local item = unavailable[j] self:removeExtraClothingItemsFromList(j+1, item, unavailable) end --]] for k,item in ipairs(available) do if #source.items > 1 and item.count > 1 then self.ingredientPanel:addItem(getText("IGUI_CraftUI_CountNumber", item.name, item.count), item) else self.ingredientPanel:addItem(item.name, item) end; end for k,item in ipairs(unavailable) do if #source.items > 1 and item.count > 1 then self.ingredientPanel:addItem(getText("IGUI_CraftUI_CountNumber", item.name, item.count), item) else self.ingredientPanel:addItem(item.name, item) end end end self.refreshTypesAvailableMS = getTimestampMs() self.ingredientPanel.doDrawItem = ISCraftingUI.drawNonEvolvedIngredient end function ISCraftingUI:drawEvolvedIngredient(y, item, alt) if y + self:getYScroll() >= self.height then return y + self.itemheight end if y + self.itemheight + self:getYScroll() <= 0 then return y + self.itemheight end local a = 0.9; if not item.item.available then a = 0.3; end self:drawRectBorder(0, (y), self:getWidth(), self.itemheight - 1, a, self.borderColor.r, self.borderColor.g, self.borderColor.b); if self.selected == item.index then self:drawRect(0, (y), self:getWidth(), self.itemheight - 1, 0.3, 0.7, 0.35, 0.15); end local imgW = 20 local imgH = 20 self:drawText(item.text, 6 + imgW + 4, y + (item.height - ISCraftingUI.smallFontHeight) / 2, 1, 1, 1, a, self.font); if item.item.texture then local texWidth = item.item.texture:getWidth(); local texHeight = item.item.texture:getHeight(); self:drawTextureScaledAspect(item.item.texture, 6, y + (self.itemheight - imgH) / 2, 20, 20, a,1,1,1); end if item.item.poison then if self.PoisonTexture then local textW = getTextManager():MeasureStringX(self.font, item.text) self:drawTexture(self.PoisonTexture, 6 + imgW + 4 + textW + 6, y + (self.itemheight - self.PoisonTexture:getHeight()) / 2, a, 1, 1, 1) end end return y + self.itemheight; end function ISCraftingUI:onDblClickIngredientListbox(data) if data and data.available then self:addItemInEvolvedRecipe(data) end end function ISCraftingUI:onAddRandomIngredient(button) self:addItemInEvolvedRecipe(button.list[ZombRand(1, #button.list+1)]); end function ISCraftingUI:onAddIngredient() local item = self.ingredientListbox.items[self.ingredientListbox.selected] if item and item.item.available then self:addItemInEvolvedRecipe(item.item); end end -- Evolved recipes only function ISCraftingUI:refreshIngredientList() if not self.catListButtons then self.catListButtons = {}; end for i,v in ipairs(self.catListButtons) do v:setVisible(false); self:removeChild(v); end self.catListButtons = {}; local hasFocus = not self.recipeListHasFocus self.recipeListHasFocus = true self.ingredientListbox:setVisible(false) local recipeListbox = self:getRecipeListBox() if not recipeListbox.items or #recipeListbox.items == 0 or not recipeListbox.items[recipeListbox.selected] then return end local selectedItem = recipeListbox.items[recipeListbox.selected].item; if not selectedItem or not selectedItem.evolved then return end self.recipeListHasFocus = not hasFocus self.ingredientListbox:setVisible(true) local available = {} local unavailable = {} for k,item in ipairs(selectedItem.items) do local data = {} data.available = item.available data.name = item.name data.texture = item.texture data.item = item.itemToAdd data.baseItem = selectedItem.baseItem data.recipe = selectedItem.recipe data.poison = item.poison if instanceof(item.itemToAdd, "Food") then if not data.recipe:needToBeCooked(item.itemToAdd) then item.available = false; data.available = false; end if item.itemToAdd:isFrozen() and (not data.recipe:isAllowFrozenItem()) then item.available = false; data.available = false; end end if item.available then table.insert(available, data) else table.insert(unavailable, data) end end table.sort(available, function(a,b) return not string.sort(a.name, b.name) end) table.sort(unavailable, function(a,b) return not string.sort(a.name, b.name) end) self.ingredientListbox:clear() -- check for every item category to add a "add random category" buttons in bottom of the ingredient list self.catList = {}; for k,item in ipairs(available) do self.ingredientListbox:addItem(item.name, item) local foodType = item.item:IsFood() and item.item:getFoodType() if foodType then if not self.catList[foodType] then self.catList[foodType] = {}; end table.insert(self.catList[foodType], item); end end for k,item in ipairs(unavailable) do self.ingredientListbox:addItem(item.name, item) end local y = self.ingredientListbox:getY(); for i,v in pairs(self.catList) do local button = ISButton:new(self.ingredientListbox:getX() + self.ingredientListbox:getWidth() + 10 , y ,50,20,getText("ContextMenu_AddRandom", getText("ContextMenu_FoodType_"..i)), self, ISCraftingUI.onAddRandomIngredient); button.list = self.catList[i]; button:initialise() self:addChild(button); table.insert(self.catListButtons, button); y = y + 25; end end local function tableSize(table1) if not table1 then return 0 end local count = 0; for _,v in pairs(table1) do count = count + 1; end return count; end local function areTablesDifferent(table1, table2) local size1 = tableSize(table1) local size2 = tableSize(table2) if size1 ~= size2 then return true end if size1 == 0 then return false end for k1,v1 in pairs(table1) do if table2[k1] ~= v1 then return true end end return false end function ISCraftingUI:render() ISCollapsableWindow.render(self); if self.isCollapsed then return end local multipleItemEvolvedRecipes = {}; self.addIngredientButton:setVisible(false); -- draw bottom infos local rh = self.resizable and self:resizeWidgetHeight() or 0 self:drawRectBorder(0, 0, self:getWidth(), self:getHeight(), self.borderColor.a, self.borderColor.r,self.borderColor.g,self.borderColor.b); self.javaObject:DrawTextureScaledColor(nil, 0, self:getHeight() - rh - ISCraftingUI.bottomInfoHeight, self:getWidth(), 1, self.borderColor.r, self.borderColor.g,self.borderColor.b,self.borderColor.a); local textWidth = getTextManager():MeasureStringX(UIFont.Small, getText("IGUI_CraftingUI_KnownRecipes", self.knownRecipes,self.totalRecipes)) self:drawText(getText("IGUI_CraftingUI_KnownRecipes", self.knownRecipes,self.totalRecipes), self.width - textWidth - 5, self.panel:getY() + self.panel.tabHeight + 8, 1,1,1,1, UIFont.Small); local textY = self:getHeight() - rh - ISCraftingUI.bottomInfoHeight + (ISCraftingUI.bottomInfoHeight - ISCraftingUI.smallFontHeight) / 2 local buttonSize = 24 local buttonSpace = 8 local buttonY = self:getHeight() - rh - ISCraftingUI.bottomInfoHeight + (ISCraftingUI.bottomInfoHeight - buttonSize) / 2 local spacing = 32 if self.drawJoypadFocus and self.ingredientListbox:getIsVisible() then local width1 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelAddIngredient) local width3 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelFavorite) local width4 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelClose) local totalWidth = width1 + width3 + width4 + spacing * 2 local left = (self.width - totalWidth) / 2 self:drawTextureScaled(Joypad.Texture.AButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelAddIngredient, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) left = left + width1 + spacing self:drawTextureScaled(Joypad.Texture.YButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelFavorite, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) left = left + width3 + spacing self:drawTextureScaled(Joypad.Texture.BButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelClose, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) elseif self.drawJoypadFocus then local width1 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelCraftOne) local width2 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelCraftAll) local width3 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelFavorite) local width4 = buttonSize + buttonSpace + getTextManager():MeasureStringX(UIFont.Small, self.LabelClose) local totalWidth = width1 + width2 + width3 + width4 + spacing * 3 local left = (self.width - totalWidth) / 2 self:drawTextureScaled(Joypad.Texture.AButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelCraftOne, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) left = left + width1 + spacing self:drawTextureScaled(Joypad.Texture.XButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelCraftAll, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) left = left + width2 + spacing self:drawTextureScaled(Joypad.Texture.YButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelFavorite, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) left = left + width3 + spacing self:drawTextureScaled(Joypad.Texture.BButton, left, buttonY, buttonSize, buttonSize, 1, 1, 1, 1) self:drawText(self.LabelClose, left + buttonSize + buttonSpace, textY, 1, 1, 1, 1, UIFont.Small) else local text = self.ingredientListbox:getIsVisible() and self.bottomInfoText2 or self.bottomInfoText1 local noteX = 0 local noteWidth = self.width if noteWidth ~= self.keysRichText.width then self.keysRichText:setWidth(noteWidth) self.keysRichText.textDirty = true end if text ~= self.keysText then self.keysText = text self.keysRichText:setText(" " .. text) self.keysRichText.textDirty = true end local noteY = self:getHeight() - rh - ISCraftingUI.bottomInfoHeight noteY = noteY + (ISCraftingUI.bottomInfoHeight - self.keysRichText.height) / 2 self.keysRichText:render(noteX, noteY, self) end local noteX = self:getWidth() / 3 + 10 local noteWidth = self.width - 10 - noteX if noteWidth ~= self.noteRichText.width then self.noteRichText:setWidth(noteWidth) self.noteRichText.textDirty = true end local noteY = self:getHeight() - rh - ISCraftingUI.bottomInfoHeight - self.noteRichText.height - 4 if noteY >= self.craftOneButton:getBottom() + 10 then self.noteRichText:render(noteX, noteY, self) end local recipeListBox = self:getRecipeListBox() if not recipeListBox.items or #recipeListBox.items == 0 or not recipeListBox.items[recipeListBox.selected] then self.craftOneButton:setVisible(false); self.craftAllButton:setVisible(false); self.debugGiveIngredientsButton:setVisible(false); self.ingredientPanel:setVisible(false); self.ingredientListbox:setVisible(false); self.selectedRecipeItem = nil return end -- draw recipes infos local x = self:getWidth()/3 + 80; local y = 110; local selectedItem = recipeListBox.items[recipeListBox.selected].item; if not selectedItem.evolved then local now = getTimestampMs() if not self.refreshTypesAvailableMS or (self.refreshTypesAvailableMS + 500 < now) then self.refreshTypesAvailableMS = now local typesAvailable = self:getAvailableItemsType(); self.needRefreshIngredientPanel = self.needRefreshIngredientPanel or areTablesDifferent(selectedItem.typesAvailable, typesAvailable); selectedItem.typesAvailable = typesAvailable; end self:getContainers(); selectedItem.available = RecipeManager.IsRecipeValid(selectedItem.recipe, self.character, nil, self.containerList); self.craftOneButton:setVisible(true); self.craftAllButton:setVisible(true); self.debugGiveIngredientsButton:setVisible(getDebug()); else self.craftOneButton:setVisible(false); self.craftAllButton:setVisible(false); self.debugGiveIngredientsButton:setVisible(false); end -- render the right part, the craft information self:drawRectBorder(x, y, 32 + 10, 32 + 10, 1.0, 1.0, 1.0, 1.0); if selectedItem.texture then if selectedItem.texture:getWidth() <= 32 and selectedItem.texture:getHeight() <= 32 then local newX = (32 - selectedItem.texture:getWidthOrig()) / 2; local newY = (32 - selectedItem.texture:getHeightOrig()) / 2; self:drawTexture(selectedItem.texture,x+5 + newX,y+5 + newY,1,1,1,1); else self:drawTextureScaledAspect(selectedItem.texture,x+5,y+5,32,32,1,1,1,1); end end self:drawText(selectedItem.recipe:getName() , x + 32 + 15, y, 1,1,1,1, UIFont.Large); local name = selectedItem.evolved and selectedItem.resultName or selectedItem.itemName self:drawText(name, x + 32 + 15, y + ISCraftingUI.largeFontHeight, 1,1,1,1, UIFont.Small); y = y + math.max(45, ISCraftingUI.largeFontHeight + ISCraftingUI.smallFontHeight); local imgW = 20; local imgH = 20; local imgPadX = 4; local dyText = (imgH - ISCraftingUI.smallFontHeight) / 2; if selectedItem.evolved and selectedItem.baseItem then self:drawText(getText("IGUI_CraftUI_BaseItem"), x, y, 1,1,1,1, UIFont.Medium); y = y + ISCraftingUI.mediumFontHeight; local offset = 15; local labelWidth = self.LabelDashWidth local r,g,b = 1,1,1 local r2,g2,b2 = 1,1,1; if not selectedItem.available then r,g,b = 0.54,0.54,0.54 r2,g2,b2 = 1,0.3,0.3; end self:drawText(self.LabelDash, x + offset, y + dyText, r,g,b,1, UIFont.Small); self:drawTextureScaledAspect(selectedItem.baseItem:getTex(), x + offset + labelWidth + imgPadX, y, imgW, imgH, 1,r2,b2,g2); self:drawText(selectedItem.baseItem:getDisplayName(), x + offset + labelWidth + imgPadX + imgW + imgPadX, y + dyText, r,g,b,1, UIFont.Small); y = y + ISCraftingUI.smallFontHeight + 7; if selectedItem.extraItems and #selectedItem.extraItems > 0 then self:drawText(getText("IGUI_CraftUI_AlreadyContainsItems"), x, y, 1,1,1,1, UIFont.Medium); y = y + ISCraftingUI.mediumFontHeight + 7; self:drawText(self.LabelDash, x + offset, y + dyText, r,g,b,1, UIFont.Small); local newX = x + offset + labelWidth + imgPadX; for g,h in ipairs(selectedItem.extraItems) do self:drawTextureScaledAspect(h, newX, y, imgW, imgH, g2,r2,b2,g2); newX = newX + 22; end if self.character and self.character:isKnownPoison(selectedItem.baseItem) and self.PoisonTexture then self:drawTexture(self.PoisonTexture, newX, y + (imgH - self.PoisonTexture:getHeight()) / 2, 1,r2,g2,b2) end y = y + ISCraftingUI.mediumFontHeight + 7; elseif self.character and self.character:isKnownPoison(selectedItem.baseItem) and self.PoisonTexture then self:drawText(getText("IGUI_CraftUI_AlreadyContainsItems"), x, y, 1,1,1,1, UIFont.Medium); y = y + ISCraftingUI.mediumFontHeight + 7; self:drawText(self.LabelDash, x + offset, y + dyText, r,g,b,1, UIFont.Small); local newX = x + offset + labelWidth + imgPadX; self:drawTexture(self.PoisonTexture, newX, y + (imgH - self.PoisonTexture:getHeight()) / 2, 1,r2,g2,b2) y = y + ISCraftingUI.smallFontHeight + 7; end end if not selectedItem.evolved then self:drawText(getText("IGUI_CraftUI_RequiredItems"), x, y, 1,1,1,1, UIFont.Medium); else self:drawText(getText("IGUI_CraftUI_ItemsToAdd"), x, y, 1,1,1,1, UIFont.Medium); end y = y + ISCraftingUI.mediumFontHeight + 7; if selectedItem.evolved then self.ingredientListbox:setX(x + 15) self.ingredientListbox:setY(y) self.ingredientListbox:setHeight(self.ingredientListbox.itemheight * 8) self.addIngredientButton:setX(self.ingredientListbox:getX()); self.addIngredientButton:setY(self.ingredientListbox:getY() + self.ingredientListbox:getHeight() + 10); self.addIngredientButton:setVisible(true); if selectedItem.available then self.addIngredientButton.enable = true; else self.addIngredientButton.enable = false; end local item = self.ingredientListbox.items[self.ingredientListbox.selected] if not item or not item.item.available then self.addIngredientButton.enable = false; else self.addIngredientButton.enable = true; end else self.ingredientPanel:setX(x + 15) self.ingredientPanel:setY(y) self.ingredientPanel:setHeight(self.ingredientListbox.itemheight * 8) y = self.ingredientPanel:getBottom() end if selectedItem ~= self.selectedRecipeItem then self:refreshIngredientPanel() self:refreshIngredientList() self.selectedRecipeItem = selectedItem end if selectedItem.evolved then y = self.ingredientListbox:getBottom() end -- y = y + 10; -- if selectedItem.multipleItems then -- self.tickBox:setX(x); -- self.tickBox:setY(y); -- self.tickBox:setVisible(true); -- else -- self.tickBox:setVisible(false); -- end -- y = y + (#self.tickBox.options * 20); -- y = y + 10; y = y + 4; if not selectedItem.evolved and (selectedItem.recipe:getRequiredSkillCount() > 0) then self:drawText(getText("IGUI_CraftUI_RequiredSkills"), x, y, 1,1,1,1, UIFont.Medium); y = y + ISCraftingUI.mediumFontHeight; for i=1,selectedItem.recipe:getRequiredSkillCount() do local skill = selectedItem.recipe:getRequiredSkill(i-1); local perk = PerkFactory.getPerk(skill:getPerk()); local playerLevel = self.character and self.character:getPerkLevel(skill:getPerk()) or 0 local perkName = perk and perk:getName() or skill:getPerk():name() local text = " - " .. perkName .. ": " .. tostring(playerLevel) .. " / " .. tostring(skill:getLevel()); local r,g,b = 1,1,1 if self.character and (playerLevel < skill:getLevel()) then g = 0; b = 0; end self:drawText(text, x + 15, y, r,g,b,1, UIFont.Small); y = y + ISCraftingUI.smallFontHeight; end y = y + 4; end if not selectedItem.evolved and selectedItem.recipe:getNearItem() then self:drawText(getText("IGUI_CraftUI_NearItem", selectedItem.recipe:getNearItem()), x, y, 1,1,1,1, UIFont.Medium); y = y + ISCraftingUI.mediumFontHeight; end if not selectedItem.evolved then self:drawText(getText("IGUI_CraftUI_RequiredTime", selectedItem.recipe:getTimeToMake()), x, y, 1,1,1,1, UIFont.Medium); y = y + ISCraftingUI.mediumFontHeight; end if not selectedItem.evolved and selectedItem.recipe:getTooltip() then y = y + 10 local tooltip = getText(selectedItem.recipe:getTooltip()) local numLines = 1 local p = string.find(tooltip, "\n") while p do numLines = numLines + 1 p = string.find(tooltip, "\n", p + 4) end self:drawText(tooltip, x, y, 1,1,1,1, UIFont.Small); y = y + ISCraftingUI.smallFontHeight * numLines; end if not selectedItem.evolved then y = y + 10 self.craftOneButton:setX(x); self.craftOneButton:setY(y); self.craftOneButton.enable = selectedItem.available; self.craftAllButton:setX(self.craftOneButton:getX() + 5 + self.craftOneButton:getWidth()); self.craftAllButton:setY(y); self.craftAllButton.enable = selectedItem.available; local title = getText("IGUI_CraftUI_ButtonCraftAll") if self.craftAllButton.enable then local count = RecipeManager.getNumberOfTimesRecipeCanBeDone(selectedItem.recipe, self.character, self.containerList, nil) if count > 1 then title = getText("IGUI_CraftUI_ButtonCraftAllCount", count) elseif count == 1 then self.craftAllButton.enable = false end end if title ~= self.craftAllButton:getTitle() then self.craftAllButton:setTitle(title) self.craftAllButton:setWidthToTitle() end self.debugGiveIngredientsButton:setX(self.craftAllButton:getRight() + 5) self.debugGiveIngredientsButton:setY(y); y = y + self.craftAllButton:getHeight() + 10; end -- stop allowing crafting while driving self.craftOneButton.tooltip = nil; self.craftAllButton.tooltip = nil; if self.character:isDriving() then self.craftAllButton.enable = false; self.craftOneButton.enable = false; self.craftOneButton.tooltip = getText("Tooltip_CantCraftDriving"); self.craftAllButton.tooltip = getText("Tooltip_CantCraftDriving"); end local currentAction = ISTimedActionQueue.getTimedActionQueue(self.character); if currentAction and currentAction.queue and currentAction.queue[1] and self.craftInProgress then self.taskLabel:setX(x); if selectedItem.evolved then y = self.addIngredientButton:getY() + 30; end self.taskLabel:setY(y); self.taskLabel.name = currentAction.queue[1].jobType; self:drawProgressBar(x, y + 20, getTextManager():MeasureStringX(UIFont.Small, self.taskLabel.name), self.lineH, currentAction.queue[1].action:getJobDelta(), self.fgBar) if not self.taskLabel.name or self.taskLabel.name == "" then self.taskLabel:setVisible(false); else self.taskLabel:setVisible(true); end else self.taskLabel:setVisible(false); end if self.drawJoypadFocus and self.recipeListHasFocus then local ui = self:getRecipeListBox() local dx,dy = 0,self:titleBarHeight() local parent = ui.parent while parent ~= self do dx = dx + parent:getX() dy = dy + parent:getY() parent = parent.parent end self:drawRectBorder(ui:getX(), dy + ui:getY(), ui:getWidth(), ui:getHeight(), 0.4, 0.2, 1.0, 1.0); self:drawRectBorder(ui:getX()+1, dy + ui:getY()+1, ui:getWidth()-2, ui:getHeight()-2, 0.4, 0.2, 1.0, 1.0); elseif self.drawJoypadFocus and self.ingredientPanel:getIsVisible() then local ui = self.ingredientPanel self:drawRectBorder(ui:getX(), ui:getY(), ui:getWidth(), ui:getHeight(), 0.4, 0.2, 1.0, 1.0); self:drawRectBorder(ui:getX()+1, ui:getY()+1, ui:getWidth()-2, ui:getHeight()-2, 0.4, 0.2, 1.0, 1.0); elseif self.drawJoypadFocus and self.ingredientListbox:getIsVisible() then local ui = self.ingredientListbox self:drawRectBorder(ui:getX(), ui:getY(), ui:getWidth(), ui:getHeight(), 0.4, 0.2, 1.0, 1.0); self:drawRectBorder(ui:getX()+1, ui:getY()+1, ui:getWidth()-2, ui:getHeight()-2, 0.4, 0.2, 1.0, 1.0); end end function ISCraftingUI:new (x, y, width, height, character) local o = {}; if x == 0 and y == 0 then x = (getCore():getScreenWidth() / 2) - (width / 2); y = (getCore():getScreenHeight() / 2) - (height / 2); end o = ISCollapsableWindow:new(x, y, width, height); o.minimumWidth = 800 o.minimumHeight = 600 setmetatable(o, self); if getCore():getKey("Forward") ~= 44 then -- hack, seriously, need a way to detect qwert/azerty keyboard :( ISCraftingUI.qwertyConfiguration = false; end o.LabelDash = "-" o.LabelDashWidth = getTextManager():MeasureStringX(UIFont.Small, o.LabelDash) o.LabelCraftOne = getText("IGUI_CraftUI_CraftOne") o.LabelCraftAll = getText("IGUI_CraftUI_CraftAll") o.LabelAddIngredient = getText("IGUI_CraftUI_ButtonAddIngredient") o.LabelFavorite = getText("IGUI_CraftUI_Favorite") o.LabelClose = getText("IGUI_CraftUI_Close") o.bottomInfoText1 = getText("IGUI_CraftUI_Controls1", getKeyName(ISCraftingUI.upArrow), getKeyName(ISCraftingUI.downArrow), getKeyName(ISCraftingUI.leftCategory), getKeyName(ISCraftingUI.rightCategory)); o.bottomInfoText2 = getText("IGUI_CraftUI_Controls2", getKeyName(ISCraftingUI.upArrow), getKeyName(ISCraftingUI.downArrow), getKeyName(ISCraftingUI.leftCategory), getKeyName(ISCraftingUI.rightCategory)); o.title = getText("IGUI_CraftUI_Title"); self.__index = self; o.character = character; o.playerNum = character and character:getPlayerNum() or -1 o:setResizable(true); o.lineH = 10; o.fgBar = {r=0, g=0.6, b=0, a=0.7 } o.craftInProgress = false; o.selectedIndex = {} o.recipeListHasFocus = true o.TreeExpanded = getTexture("media/ui/TreeExpanded.png") o.PoisonTexture = getTexture("media/ui/SkullPoison.png") o.knownRecipes = RecipeManager.getKnownRecipesNumber(o.character); o.totalRecipes = getAllRecipes():size(); o:setWantKeyEvents(true); return o; end function ISCraftingUI:onActivateView() local recipeListBox = self:getRecipeListBox() recipeListBox:ensureVisible(recipeListBox.selected); end function ISCraftingUI:createChildren() ISCollapsableWindow.createChildren(self); local th = self:titleBarHeight(); local rh = self.resizable and self:resizeWidgetHeight() or 0 self.panel = ISTabPanel:new(0, th, self.width, self.height-th-rh-ISCraftingUI.bottomInfoHeight); self.panel:initialise(); self.panel:setAnchorRight(true) self.panel:setAnchorBottom(true) self.panel.borderColor = { r = 0, g = 0, b = 0, a = 0}; self.panel.onActivateView = ISCraftingUI.onActivateView; self.panel.target = self; self.panel:setEqualTabWidth(false) self:addChild(self.panel); -- self.panel:setOnTabTornOff(self, ISCraftingUI.onTabTornOff) -- populate all the recipes, splitted in categories self:populateRecipesList(); self.categories = {}; local k for k = 1 , #self.recipesListH, 1 do local i = self.recipesListH[k] local l = self.recipesList[i] --for i,l in pairs(self.recipesList) do local cat1 = ISCraftingCategoryUI:new(0, 0, self.width, self.panel.height - self.panel.tabHeight, self); cat1:initialise(); cat1:setAnchorRight(true) cat1:setAnchorBottom(true) local catName = getTextOrNull("IGUI_CraftCategory_"..i) or i self.panel:addView(catName, cat1); cat1.infoText = getText("UI_CraftingUI"); cat1.parent = self; cat1.category = i; for s,d in ipairs(l) do cat1.recipes:addItem(s,d); end table.insert(self.categories, cat1); end self.craftOneButton = ISButton:new(0, self.height-ISCraftingUI.bottomInfoHeight-20-15, 50,25,getText("IGUI_CraftUI_ButtonCraftOne"),self, ISCraftingUI.craft); self.craftOneButton:initialise() self:addChild(self.craftOneButton); self.craftAllButton = ISButton:new(0, self.height-ISCraftingUI.bottomInfoHeight-20-15, 50,25,getText("IGUI_CraftUI_ButtonCraftAll"),self, ISCraftingUI.craftAll); self.craftAllButton:initialise() self:addChild(self.craftAllButton); self.debugGiveIngredientsButton = ISButton:new(0, 0, 50, 25, "DBG: Give Ingredients", self, ISCraftingUI.debugGiveIngredients); self.debugGiveIngredientsButton:initialise(); self:addChild(self.debugGiveIngredientsButton); self.taskLabel = ISLabel:new(4,5,19,"",1,1,1,1,UIFont.Small, true); self:addChild(self.taskLabel); self.addIngredientButton = ISButton:new(0, self.height-ISCraftingUI.bottomInfoHeight-20-15, 50,25,getText("IGUI_CraftUI_ButtonAddIngredient"),self, ISCraftingUI.onAddIngredient); self.addIngredientButton:initialise() self:addChild(self.addIngredientButton); self.addIngredientButton:setVisible(false); -- self.tickBox = ISTickBox:new(0, 0, 100, 20, "", self, ISCraftingUI.tickBoxChange) -- self.tickBox.onlyOnePossibility = true; -- self.tickBox.choicesColor = {r=1, g=1, b=1, a=1} -- self.tickBox:initialise(); -- self:addChild(self.tickBox) -- For non-evolved recipes self.ingredientPanel = ISScrollingListBox:new(1, 30, self.width / 3, self.height - (59 + ISCraftingUI.bottomInfoHeight)); self.ingredientPanel:initialise() self.ingredientPanel:instantiate() self.ingredientPanel.itemheight = math.max(ISCraftingUI.smallFontHeight, 22) self.ingredientPanel.font = UIFont.NewSmall self.ingredientPanel.doDrawItem = self.drawNonEvolvedIngredient self.ingredientPanel.drawBorder = true self.ingredientPanel:setVisible(false) self:addChild(self.ingredientPanel) -- For evolved recipes self.ingredientListbox = ISScrollingListBox:new(1, 30, self.width / 3, self.height - (59 + ISCraftingUI.bottomInfoHeight)); self.ingredientListbox:initialise(); self.ingredientListbox:instantiate(); self.ingredientListbox.itemheight = math.max(ISCraftingUI.smallFontHeight, 22); self.ingredientListbox.selected = 0; self.ingredientListbox.joypadParent = self; self.ingredientListbox.font = UIFont.NewSmall self.ingredientListbox.doDrawItem = self.drawEvolvedIngredient self.ingredientListbox:setOnMouseDoubleClick(self, self.onDblClickIngredientListbox); self.ingredientListbox.drawBorder = true self.ingredientListbox:setVisible(false) -- self.ingredientListbox.resetSelectionOnChangeFocus = true; self:addChild(self.ingredientListbox); self.ingredientListbox.PoisonTexture = self.PoisonTexture self.noteRichText = ISRichTextLayout:new(self.width) self.noteRichText:setMargins(0, 0, 0, 0) self.noteRichText:setText(getText("IGUI_CraftUI_Note")) self.noteRichText.textDirty = true self.keysRichText = ISRichTextLayout:new(self.width) self.keysRichText:setMargins(5, 0, 5, 0) self:refresh(); end function ISCraftingUI:populateRecipesList() local allRecipes = getAllRecipes(); self.allRecipesList = {}; self.recipesList = {}; self.recipesListH = {}; self.recipesList[getText("IGUI_CraftCategory_Favorite")] = {}; -- set these 2 to have a good order self.recipesListH[#self.recipesListH+1] = getText("IGUI_CraftCategory_Favorite") self.recipesList[getText("IGUI_CraftCategory_General")] = {}; self.recipesListH[#self.recipesListH+1] = getText("IGUI_CraftCategory_General") self:getContainers(); for i=0,allRecipes:size()-1 do local newItem = {}; local recipe = allRecipes:get(i); if not recipe:isHidden() and (not recipe:needToBeLearn() or (self.character and self.character:isRecipeKnown(recipe))) then if recipe:getCategory() then newItem.category = recipe:getCategory(); else newItem.category = getText("IGUI_CraftCategory_General"); end if not self.recipesList[newItem.category] then self.recipesList[newItem.category] = {}; self.recipesListH[#self.recipesListH+1] = newItem.category end newItem.recipe = recipe; if self.character then newItem.available = RecipeManager.IsRecipeValid(recipe, self.character, nil, self.containerList); local modData = self.character:getModData(); if modData[self:getFavoriteModDataLocalString(recipe)] or false then -- Update the favorite list and save backward compatibility --table.remove(modData, self:getFavoriteModDataLocalString(recipe)); modData[self:getFavoriteModDataString(recipe)] = true; end newItem.favorite = modData[self:getFavoriteModDataString(recipe)] or false; end if newItem.favorite then table.insert(self.recipesList[getText("IGUI_CraftCategory_Favorite")], newItem); end local resultItem = self:GetItemInstance(recipe:getResult():getFullType()); if resultItem then newItem.texture = resultItem:getTex(); newItem.itemName = resultItem:getDisplayName(); if recipe:getResult():getCount() > 1 then newItem.itemName = (recipe:getResult():getCount() * resultItem:getCount()) .. " " .. newItem.itemName; end end newItem.sources = {}; for x=0,recipe:getSource():size()-1 do local source = recipe:getSource():get(x); local sourceInList = {}; sourceInList.items = {} for k=1,source:getItems():size() do local sourceFullType = source:getItems():get(k-1) local item = nil local itemName = nil if sourceFullType == "Water" then item = self:GetItemInstance("Base.WaterDrop"); elseif luautils.stringStarts(sourceFullType, "[") then -- a Lua test function item = self:GetItemInstance("Base.WristWatch_Right_DigitalBlack"); else item = self:GetItemInstance(sourceFullType); end if item then local itemInList = {}; itemInList.count = source:getCount(); itemInList.texture = item:getTex(); if sourceFullType == "Water" then if itemInList.count == 1 then itemInList.name = getText("IGUI_CraftUI_CountOneUnit", getText("ContextMenu_WaterName")) else itemInList.name = getText("IGUI_CraftUI_CountUnits", getText("ContextMenu_WaterName"), itemInList.count) end if recipe:getHeat() < 0 then itemInList.name = getText("IGUI_FoodTemperatureNaming", getText("IGUI_Temp_Hot"), itemInList.name); elseif recipe:getHeat() > 0 then itemInList.name = getText("IGUI_FoodTemperatureNaming", getText("IGUI_Temp_Cold"), itemInList.name); end; elseif source:getItems():size() > 1 then -- no units itemInList.name = item:getDisplayName() elseif not source:isDestroy() and item:IsDrainable() then if itemInList.count == 1 then itemInList.name = getText("IGUI_CraftUI_CountOneUnit", item:getDisplayName()) else itemInList.name = getText("IGUI_CraftUI_CountUnits", item:getDisplayName(), itemInList.count) end if recipe:getHeat() < 0 then itemInList.name = getText("IGUI_FoodTemperatureNaming", getText("IGUI_Temp_Hot"), itemInList.name); elseif recipe:getHeat() > 0 then itemInList.name = getText("IGUI_FoodTemperatureNaming", getText("IGUI_Temp_Cold"), itemInList.name); end; elseif not source:isDestroy() and source:getUse() > 0 then -- food itemInList.count = source:getUse() if itemInList.count == 1 then itemInList.name = getText("IGUI_CraftUI_CountOneUnit", item:getDisplayName()) else itemInList.name = getText("IGUI_CraftUI_CountUnits", item:getDisplayName(), itemInList.count) end elseif itemInList.count > 1 then itemInList.name = getText("IGUI_CraftUI_CountNumber", item:getDisplayName(), itemInList.count) else itemInList.name = item:getDisplayName() end itemInList.fullType = item:getFullType() if sourceFullType == "Water" then itemInList.fullType = "Water" end table.insert(sourceInList.items, itemInList); end end table.insert(newItem.sources, sourceInList) end table.insert(self.recipesList[newItem.category], newItem); table.insert(self.allRecipesList, newItem); end end -- now do the evolved recipe local newRecipe = {}; local itemInList = {}; local doneRecipes = {}; local doneItems = {}; -- first we get all our available evolvedRecipe for i=0,self.containerList:size()-1 do local container = self.containerList:get(i); for x=0,container:getItems():size() - 1 do local baseItem = container:getItems():get(x); local evorecipe = RecipeManager.getEvolvedRecipe(baseItem, self.character, self.containerList, false); if evorecipe and evorecipe:size() > 0 then for y=0,evorecipe:size() - 1 do local evo = evorecipe:get(y); --if recipe is hidden skip it - unless we already have a result item if (not evo:isHidden() or baseItem:getType() ~= evo:getBaseItem()) then newRecipe = {}; if not doneRecipes[evo:getName() .. baseItem:getFullType()] then doneRecipes[evo:getName() .. baseItem:getFullType()] = true; doneItems = {}; newRecipe.baseItem = baseItem; local resultItem = self:GetItemInstance(evo:getFullResultItem()); if resultItem then newRecipe.texture = resultItem:getTex(); newRecipe.resultName = resultItem:getDisplayName(); newRecipe.items = {}; newRecipe.available = false; newRecipe.itemName = evo:getName(); if baseItem:getType() ~= evo:getBaseItem() then newRecipe.customRecipeName = getText("IGUI_CraftUI_FromBaseItem", baseItem:getDisplayName()); -- add the textures of our extra items to display them newRecipe.extraItems = {}; if baseItem:getExtraItems() then for u=0,baseItem:getExtraItems():size()-1 do local extraItem = self:GetItemInstance(baseItem:getExtraItems():get(u)); if extraItem then table.insert(newRecipe.extraItems, extraItem:getTex()); end end end if instanceof(baseItem, "Food") and baseItem:getSpices() then for u=0,baseItem:getSpices():size()-1 do local extraItem = self:GetItemInstance(baseItem:getSpices():get(u)); if extraItem then table.insert(newRecipe.extraItems, extraItem:getTex()); end end end end newRecipe.recipe = evo; newRecipe.evolved = true; local itemCanBeUse = evo:getItemsCanBeUse(self.character, baseItem, self.containerList); for l=0, itemCanBeUse:size()-1 do local newItem = itemCanBeUse:get(l); if not doneItems[newItem] then doneItems[newItem] = true; newRecipe.available = true; itemInList.texture = newItem:getTex(); itemInList.name = newItem:getName(); itemInList.fullType = newItem:getFullType(); itemInList.itemToAdd = newItem; itemInList.available = true; itemInList.poison = self.character:isKnownPoison(newItem) table.insert(newRecipe.items, itemInList); itemInList = {}; end end if self.character then local modData = self.character:getModData(); newRecipe.favorite = modData[self:getFavoriteModDataString(evo)] or false; end table.insert(self.recipesList["Cooking"], newRecipe); table.insert(self.allRecipesList, newRecipe); if newRecipe.favorite then table.insert(self.recipesList[getText("IGUI_CraftCategory_Favorite")], newRecipe); end end end end end end end end -- then we look for missing recipes local allRecipes = RecipeManager.getAllEvolvedRecipes(); for i=0, allRecipes:size()-1 do local evolvedRecipe = allRecipes:get(i); local found = false; if not evolvedRecipe:isHidden() then for x,v in ipairs(self.recipesList["Cooking"]) do if v.evolved and v.recipe == evolvedRecipe then -- check possible missing items local possibleItems = evolvedRecipe:getPossibleItems(); for k=0, possibleItems:size() -1 do local possibleItem = possibleItems:get(k); local found2 = false; for g,h in ipairs(v.items) do if h.fullType == possibleItem:getFullType() then found2 = true; break; end end if not found2 then local newItem = self:GetItemInstance(possibleItem:getFullType()); itemInList.texture = newItem:getTex(); itemInList.name = newItem:getDisplayName(); itemInList.available = false; table.insert(v.items, itemInList); itemInList = {}; end end found = true; end end if not found then -- recipe not in list, we add it with all the missing items newRecipe = {}; local resultItem = self:GetItemInstance(evolvedRecipe:getFullResultItem()); if resultItem then newRecipe.texture = resultItem:getTex(); newRecipe.resultName = resultItem:getDisplayName(); newRecipe.items = {}; newRecipe.available = false; newRecipe.itemName = evolvedRecipe:getName(); newRecipe.recipe = evolvedRecipe; newRecipe.evolved = true; newRecipe.baseItem = self:GetItemInstance(evolvedRecipe:getModule():getName() .. "." .. evolvedRecipe:getBaseItem()); local possibleItems = evolvedRecipe:getPossibleItems(); for k=0, possibleItems:size() -1 do local possibleItem = possibleItems:get(k); local newItem = self:GetItemInstance(possibleItem:getFullType()); itemInList.texture = newItem:getTex(); itemInList.name = newItem:getDisplayName(); itemInList.available = false; table.insert(newRecipe.items, itemInList); itemInList = {}; end if self.character then local modData = self.character:getModData(); newRecipe.favorite = modData[self:getFavoriteModDataString(evolvedRecipe)] or false; end table.insert(self.recipesList["Cooking"], newRecipe); if newRecipe.favorite then table.insert(self.recipesList[getText("IGUI_CraftCategory_Favorite")], newRecipe); end else print('ISCraftingUI: no such result item '..tostring(evolvedRecipe:getFullResultItem())) end end end end -- if #self.recipesList["Favorite"] == 0 then self.recipesList["Favorite"] = nil; end end function ISCraftingUI:sortList() -- sort list with items you can craft in first local availableList = {}; local notAvailableList = {}; for i,v in pairs(self.recipesList) do if not availableList[i] then availableList[i] = {}; notAvailableList[i] = {}; end for k,l in ipairs(v) do if l.available then table.insert(availableList[i], l); else table.insert(notAvailableList[i], l); end end end self.recipesList = {}; -- now populate our list for i,v in pairs(availableList) do table.sort(v, ISCraftingUI.sortByName); if not self.recipesList[i] then self.recipesList[i] = {}; end for k,l in ipairs(v) do self.recipesList[i][#self.recipesList[i]+1] = l; end end for i,v in pairs(notAvailableList) do table.sort(v, ISCraftingUI.sortByName); if not self.recipesList[i] then self.recipesList[i] = {}; end for k,l in ipairs(v) do self.recipesList[i][#self.recipesList[i]+1] = l; end end end ISCraftingUI.toggleCraftingUI = function() local ui = getPlayerCraftingUI(0) if ui then if ui:getIsVisible() then ui:setVisible(false) ui:removeFromUIManager() -- avoid update() while hidden else ui:setVisible(true) ui:addToUIManager() end end end ISCraftingUI.onPressKey = function(key) if not MainScreen.instance or not MainScreen.instance.inGame or MainScreen.instance:getIsVisible() then return end if key == getCore():getKey("Crafting UI") then ISCraftingUI.toggleCraftingUI(); end end function ISCraftingUI:isKeyConsumed(key) return key == Keyboard.KEY_ESCAPE or key == getCore():getKey("Crafting UI") or key == ISCraftingUI.upArrow or key == ISCraftingUI.downArrow or key == ISCraftingUI.leftCategory or key == ISCraftingUI.rightCategory or key == Keyboard.KEY_C or key == Keyboard.KEY_R or key == Keyboard.KEY_F end function ISCraftingUI:onKeyRelease(key) local ui = self if not ui.panel or not ui.panel.activeView then return; end if key == getCore():getKey("Crafting UI") then ISCraftingUI.toggleCraftingUI(); return; end if key == Keyboard.KEY_ESCAPE then ISCraftingUI.toggleCraftingUI(); return; end local self = ui.panel.activeView.view.recipes; if key == ISCraftingUI.upArrow then self.selected = self.selected - 1; if self.selected <= 0 then self.selected = self.count; end elseif key == ISCraftingUI.downArrow then self.selected = self.selected + 1; if self.selected > self.count then self.selected = 1; end end local viewIndex = ui.panel:getActiveViewIndex() local oldViewIndex = viewIndex if key == ISCraftingUI.leftCategory then if viewIndex == 1 then viewIndex = #ui.panel.viewList else viewIndex = viewIndex - 1 end elseif key == ISCraftingUI.rightCategory then if viewIndex == #ui.panel.viewList then viewIndex = 1 else viewIndex = viewIndex + 1 end end if key == Keyboard.KEY_C then if ui.ingredientListbox:getIsVisible() then ui:onAddIngredient(); elseif ui.craftOneButton.enable then ui:craft(); end elseif key == Keyboard.KEY_R and ui.craftAllButton.enable then ui:craftAll(); elseif key == Keyboard.KEY_F then ui.panel.activeView.view:addToFavorite(true); end if oldViewIndex ~= viewIndex then ui.panel:activateView(ui.panel.viewList[viewIndex].name) end ui.panel.activeView.view.recipes:ensureVisible(ui.panel.activeView.view.recipes.selected) end function ISCraftingUI:getFavoriteModDataString(recipe) local text = "craftingFavorite:" .. recipe:getOriginalname(); if instanceof(recipe, "EvolvedRecipe") then text = text .. ':' .. recipe:getBaseItem() text = text .. ':' .. recipe:getResultItem() else for i=0,recipe:getSource():size()-1 do local source = recipe:getSource():get(i) for j=1,source:getItems():size() do text = text .. ':' .. source:getItems():get(j-1); end end end return text; end function ISCraftingUI:getFavoriteModDataLocalString(recipe) -- For backward compatibility only local text = "craftingFavorite:" .. recipe:getName(); if instanceof(recipe, "EvolvedRecipe") then text = text .. ':' .. recipe:getBaseItem() text = text .. ':' .. recipe:getResultItem() else for i=0,recipe:getSource():size()-1 do local source = recipe:getSource():get(i) for j=1,source:getItems():size() do text = text .. ':' .. source:getItems():get(j-1); end end end return text; end --[[ -- just enable/disable the crafting UI ISCraftingUI.onKeyPressed = function (key) if key == getCore():getKey("Crafting UI") then if not ISCraftingUI.instance then ISCraftingUI.instance = ISCraftingUI:new(0,0,800,600,getPlayer()); ISCraftingUI.instance:initialise(); ISCraftingUI.instance:addToUIManager(); ISCraftingUI.instance:setVisible(true); else ISCraftingUI.instance:setVisible(not ISCraftingUI.instance:getIsVisible()); end end end ISCraftingUI.load = function() ISCraftingUI.instance = ISCraftingUI:new(0,0,800,600,nil); ISCraftingUI.instance:initialise(); ISCraftingUI.instance:addToUIManager(); -- ISCraftingUI.instance:setVisible(true); end --]] function ISCraftingUI:update() if self.craftInProgress then local currentAction = ISTimedActionQueue.getTimedActionQueue(self.character); if not currentAction or not currentAction.queue or not currentAction.queue[1] then self:refresh(); self.craftInProgress = false; end end if self.needRefreshIngredientPanel then self.needRefreshIngredientPanel = false self:refreshIngredientPanel() end end function ISCraftingUI:onResize() self.ingredientPanel:setWidth(self.width / 3) self.ingredientListbox:setWidth(self.width / 3) if self.catListButtons then for _,button in ipairs(self.catListButtons) do button:setX(self.ingredientListbox:getRight() + 10) end end end function ISCraftingUI:addItemInEvolvedRecipe(button) -- get the required item -- local itemFound = nil; -- for i=0,self.containerList:size()-1 do -- itemFound = self.containerList:get(i):FindAndReturn(button.item) -- if itemFound then break; end -- end -- if itemFound then local returnToContainer = {}; if not self.character:getInventory():contains(button.item) then -- take the item if it's not in our inventory ISTimedActionQueue.add(ISInventoryTransferAction:new(self.character, button.item, button.item:getContainer(), self.character:getInventory(), nil)); table.insert(returnToContainer, button.item) end if not self.character:getInventory():contains(button.baseItem) then -- take the base item if it's not in our inventory ISTimedActionQueue.add(ISInventoryTransferAction:new(self.character, button.baseItem, button.baseItem:getContainer(), self.character:getInventory(), nil)); table.insert(returnToContainer, button.baseItem) end ISTimedActionQueue.add(ISAddItemInRecipe:new(self.character, button.recipe, button.baseItem, button.item, (70 - self.character:getPerkLevel(Perks.Cooking)))); self.craftInProgress = true; ISCraftingUI.ReturnItemsToOriginalContainer(self.character, returnToContainer); -- end self:refresh(); end function ISCraftingUI:craftAll() self:craft(nil, true); end function ISCraftingUI:craft(button, all) self.craftInProgress = false local recipeListBox = self:getRecipeListBox() local selectedItem = recipeListBox.items[recipeListBox.selected].item; if selectedItem.evolved then return; end if not RecipeManager.IsRecipeValid(selectedItem.recipe, self.character, nil, self.containerList) then return; end -- local multipleItemSelected = nil; -- -- if we had more than one choice, grab the selected item -- if selectedItem.multipleItems then -- local selectedIndex = -1; -- for i,v in pairs(self.tickBox.selected) do -- if v == true then selectedIndex = i; break; end -- end -- if selectedItem.multipleItems[selectedIndex] then -- multipleItemSelected = selectedItem.multipleItems[selectedIndex].name; -- end -- end if not getPlayer() then return; end local itemsUsed = self:transferItems(); if #itemsUsed == 0 then self:refresh(); return end local returnToContainer = {}; local container = itemsUsed[1]:getContainer() if not selectedItem.recipe:isCanBeDoneFromFloor() then container = self.character:getInventory() for _,item in ipairs(itemsUsed) do if item:getContainer() ~= self.character:getInventory() then table.insert(returnToContainer, item) end end end local action = ISCraftAction:new(self.character, itemsUsed[1], selectedItem.recipe:getTimeToMake(), selectedItem.recipe, container, self.containerList) if all then action:setOnComplete(ISCraftingUI.onCraftComplete, self, action, selectedItem.recipe, container, self.containerList) else action:setOnComplete(ISCraftingUI.refresh, self) -- keep a track of our current task because we'll refresh the list once it's done end ISTimedActionQueue.add(action); ISCraftingUI.ReturnItemsToOriginalContainer(self.character, returnToContainer) end function ISCraftingUI:onCraftComplete(completedAction, recipe, container, containers) if not RecipeManager.IsRecipeValid(recipe, self.character, nil, containers) then return end local items = RecipeManager.getAvailableItemsNeeded(recipe, self.character, containers, nil, nil) if items:isEmpty() then self:refresh() return end local previousAction = completedAction local returnToContainer = {}; if not recipe:isCanBeDoneFromFloor() then for i=1,items:size() do local item = items:get(i-1) if item:getContainer() ~= self.character:getInventory() then local action = ISInventoryTransferAction:new(self.character, item, item:getContainer(), self.character:getInventory(), nil) ISTimedActionQueue.addAfter(previousAction, action) previousAction = action table.insert(returnToContainer, item) end end end local action = ISCraftAction:new(self.character, items:get(0), recipe:getTimeToMake(), recipe, container, containers) action:setOnComplete(ISCraftingUI.onCraftComplete, self, action, recipe, container, containers) ISTimedActionQueue.addAfter(previousAction, action) ISCraftingUI.ReturnItemsToOriginalContainer(self.character, returnToContainer) end function ISCraftingUI.ReturnItemsToOriginalContainer(playerObj, items) for _,item in ipairs(items) do if item:getContainer() ~= playerObj:getInventory() then local action = ISInventoryTransferAction:new(playerObj, item, playerObj:getInventory(), item:getContainer(), nil) action:setAllowMissingItems(true) ISTimedActionQueue.add(action) end end end function ISCraftingUI:GetItemInstance(type) if not self.ItemInstances then self.ItemInstances = {} end local item = self.ItemInstances[type] if not item then item = InventoryItemFactory.CreateItem(type) if item then self.ItemInstances[type] = item self.ItemInstances[item:getFullType()] = item end end return item end function ISCraftingUI:onGainJoypadFocus(joypadData) self.drawJoypadFocus = true end function ISCraftingUI:onJoypadDown(button) if button == Joypad.AButton then if self.ingredientListbox:getIsVisible() and not self.recipeListHasFocus then local item = self.ingredientListbox.items[self.ingredientListbox.selected] if item and item.item.available then self:addItemInEvolvedRecipe(item.item) end elseif self.craftOneButton.enable then self:craft() end end if button == Joypad.BButton then self:setVisible(false) setJoypadFocus(self.playerNum, nil) end if button == Joypad.XButton then if self.craftAllButton.enable then self:craftAll() end end if button == Joypad.YButton then self.panel.activeView.view:addToFavorite(true); end if button == Joypad.LBumper or button == Joypad.RBumper then local viewIndex = self.panel:getActiveViewIndex() if button == Joypad.LBumper then if viewIndex == 1 then viewIndex = #self.panel.viewList else viewIndex = viewIndex - 1 end elseif button == Joypad.RBumper then if viewIndex == #self.panel.viewList then viewIndex = 1 else viewIndex = viewIndex + 1 end end self.panel:activateView(self.panel.viewList[viewIndex].name) local recipeListBox = self:getRecipeListBox() recipeListBox:ensureVisible(recipeListBox.selected) end end function ISCraftingUI:onJoypadDirUp() if self.recipeListHasFocus then self:getRecipeListBox():onJoypadDirUp() elseif self.ingredientPanel:getIsVisible() then self.ingredientPanel:onJoypadDirUp() elseif self.ingredientListbox:getIsVisible() then self.ingredientListbox:onJoypadDirUp() end end function ISCraftingUI:onJoypadDirDown() if self.recipeListHasFocus then self:getRecipeListBox():onJoypadDirDown() elseif self.ingredientPanel:getIsVisible() then self.ingredientPanel:onJoypadDirDown() elseif self.ingredientListbox:getIsVisible() then self.ingredientListbox:onJoypadDirDown() end end function ISCraftingUI:onJoypadDirLeft() self.recipeListHasFocus = true end function ISCraftingUI:onJoypadDirRight() if self.recipeListHasFocus and self.ingredientPanel:getIsVisible() then self.recipeListHasFocus = false elseif self.recipeListHasFocus and self.ingredientListbox:getIsVisible() then self.recipeListHasFocus = false end end function ISCraftingUI:debugGiveIngredients() local recipeListBox = self:getRecipeListBox() local selectedItem = recipeListBox.items[recipeListBox.selected].item if selectedItem.evolved then return end local recipe = selectedItem.recipe local items = {} local options = {} options.AvailableItemsAll = RecipeManager.getAvailableItemsAll(recipe, self.character, self:getContainers(), nil, nil) options.MaxItemsPerSource = 10 options.NoDuplicateKeep = true RecipeUtils.CreateSourceItems(recipe, options, items) for _,item in ipairs(items) do self.character:getInventory():AddItem(item) end end --Events.OnMainMenuEnter.Add(ISCraftingUI.load); Events.OnCustomUIKey.Add(ISCraftingUI.onPressKey); --Events.OnKeyPressed.Add(ISCraftingUI.onKeyPressed);