--*********************************************************** --** THE INDIE STONE ** --*********************************************************** require "ISUI/ISRadialMenu" ISLightSourceRadialMenu = ISBaseObject:derive("ISLightSourceRadialMenu") local function predicateLightSource(item) -- getLightStrength() may be > 0 even though the battery is dead. return (item:getLightStrength() > 0) or (item:getFullType() == "Base.Candle") end local function comparatorDrainableUsesInt(item1, item2) return item1:getDrainableUsesInt() - item2:getDrainableUsesInt() end function ISLightSourceRadialMenu:center() local menu = getPlayerRadialMenu(self.playerNum) local x = getPlayerScreenLeft(self.playerNum) local y = getPlayerScreenTop(self.playerNum) local w = getPlayerScreenWidth(self.playerNum) local h = getPlayerScreenHeight(self.playerNum) x = x + w / 2 y = y + h / 2 menu:setX(x - menu:getWidth() / 2) menu:setY(y - menu:getHeight() / 2) end function ISLightSourceRadialMenu:getInsertBatteryRecipe(item, containerList) if not item then return nil end local playerObj = self.character local recipes = RecipeManager.getUniqueRecipeItems(item, playerObj, containerList) if not recipes then return nil end for i=1,recipes:size() do local recipe = recipes:get(i-1) if recipe:getResult():getFullType() == item:getFullType() then local sourceItem = recipe:findSource(item:getFullType()) local sourceBattery = recipe:findSource("Base.Battery") if sourceItem and sourceItem:isDestroy() and sourceBattery and sourceBattery:isDestroy() then local numberOfTimes = RecipeManager.getNumberOfTimesRecipeCanBeDone(recipe, playerObj, containerList, item) if numberOfTimes ~= 0 then return recipe end end end end return nil end function ISLightSourceRadialMenu:getRemoveBatteryRecipe(item, containerList) if not item then return nil end local playerObj = self.character local recipes = RecipeManager.getUniqueRecipeItems(item, playerObj, containerList) if not recipes then return nil end for i=1,recipes:size() do local recipe = recipes:get(i-1) if recipe:getSource():size() == 1 and recipe:getResult():getFullType() == "Base.Battery" then local sourceItem = recipe:findSource(item:getFullType()) if sourceItem and sourceItem:isKeep() then local numberOfTimes = RecipeManager.getNumberOfTimesRecipeCanBeDone(recipe, playerObj, containerList, item) if numberOfTimes ~= 0 then return recipe end end end end return nil end local function replaceItemInTable(itemList, replaced, replaceWith) for i,item in ipairs(itemList) do if item == replaced then itemList[i] = replaceWith return true end end return false end function ISLightSourceRadialMenu:fillMenuForItem(menu, item) if not (menu and item) then return; end; if not predicateLightSource(item) then return; end; local playerObj = self.character; local containerList = ISInventoryPaneContextMenu.getContainers(playerObj) if item:getFullType() == "Base.Candle" then local recipe = getScriptManager():getRecipe("Light Candle") if not recipe then return end local numberOfTimes = RecipeManager.getNumberOfTimesRecipeCanBeDone(recipe, playerObj, containerList, item) if numberOfTimes == 0 then return end menu:addSlice(item:getDisplayName() .. "\n" .. recipe:getName(), getTexture("media/ui/vehicles/vehicle_lightsON.png"), ISLightSourceRadialMenu.onLightCandle, self, item) return end if item:getFullType() == "Base.CandleLit" then local recipe = getScriptManager():getRecipe("Extinguish Candle") if not recipe then return end local numberOfTimes = RecipeManager.getNumberOfTimesRecipeCanBeDone(recipe, playerObj, containerList, item) if numberOfTimes == 0 then return end menu:addSlice(item:getDisplayName() .. "\n" .. recipe:getName(), getTexture("media/ui/vehicles/vehicle_lightsOFF.png"), ISLightSourceRadialMenu.onExtinguishCandle, self, item) return end local recipe = self:getInsertBatteryRecipe(item, containerList) if recipe then menu:addSlice(item:getDisplayName() .. "\n" .. recipe:getName(), getTexture("media/ui/LightSourceRadial_InsertBattery.png"), ISLightSourceRadialMenu.onInsertBattery, self, item) end recipe = self:getRemoveBatteryRecipe(item, containerList) if recipe then menu:addSlice(item:getDisplayName() .. "\n" .. recipe:getName(), getTexture("media/ui/LightSourceRadial_RemoveBattery.png"), ISLightSourceRadialMenu.onRemoveBattery, self, item) end if item:canBeActivated() and item:canEmitLight() then if item:isActivated() then menu:addSlice(item:getDisplayName() .. "\n" .. getText("ContextMenu_Turn_Off"), getTexture("media/ui/vehicles/vehicle_lightsOFF.png"), ISLightSourceRadialMenu.onToggle, self, item) else menu:addSlice(item:getDisplayName() .. "\n" .. getText("ContextMenu_Turn_On"), getTexture("media/ui/vehicles/vehicle_lightsON.png"), ISLightSourceRadialMenu.onToggle, self, item) end end end function ISLightSourceRadialMenu:fillMenu() local menu = getPlayerRadialMenu(self.playerNum) menu:clear() local playerObj = self.character local playerInv = playerObj:getInventory() local items = playerInv:getAllEvalRecurse(predicateLightSource, ArrayList.new()) local hasType = {} local itemList = {} for i=1,items:size() do local item = items:get(i-1) local fullType = item:getFullType() local accept = true if hasType[fullType] then if (fullType == "Base.Candle") or (fullType == "Base.CandleLit") then -- Remove duplicate Candle and CandleLit accept = false else -- Prefer non-dead light source over a dead one local other = hasType[fullType] if item:canEmitLight() and not other:canEmitLight() then if replaceItemInTable(itemList, other, item) then accept = false end else accept = false end end end if accept then hasType[fullType] = item table.insert(itemList, item) end end -- do equip menu entries for _,item in ipairs(itemList) do if not (playerObj:isPrimaryHandItem(item) or playerObj:isSecondaryHandItem(item)) then menu:addSlice(item:getDisplayName() .. "\n" .. getText("ContextMenu_Equip_Primary"), item:getTex(), ISLightSourceRadialMenu.onEquipLight, self, item, true); menu:addSlice(item:getDisplayName() .. "\n" .. getText("ContextMenu_Equip_Secondary"), item:getTex(), ISLightSourceRadialMenu.onEquipLight, self, item, false); end end local primary = playerObj:getPrimaryHandItem(); local secondary = playerObj:getSecondaryHandItem(); -- do unequip options early so they are grouped with the equip menu entries if primary and predicateLightSource(primary) then menu:addSlice(primary:getDisplayName() .. "\n" .. getText("ContextMenu_Unequip"), getTexture("media/ui/ZoomOut.png"), ISLightSourceRadialMenu.onEquipLight, self, primary) end; if secondary and predicateLightSource(secondary) then menu:addSlice(secondary:getDisplayName() .. "\n" .. getText("ContextMenu_Unequip"), getTexture("media/ui/ZoomOut.png"), ISLightSourceRadialMenu.onEquipLight, self, secondary) end; -- do other options for light sources last self:fillMenuForItem(menu, primary); self:fillMenuForItem(menu, secondary); end function ISLightSourceRadialMenu:display() local menu = getPlayerRadialMenu(self.playerNum) self:center() menu:addToUIManager() if JoypadState.players[self.playerNum+1] then menu:setHideWhenButtonReleased(Joypad.RBumper) setJoypadFocus(self.playerNum, menu) self.character:setJoypadIgnoreAimUntilCentered(true) end end function ISLightSourceRadialMenu:onEquipLight(item, primary) local playerObj = self.character if playerObj:isPrimaryHandItem(item) or playerObj:isSecondaryHandItem(item) then ISTimedActionQueue.add(ISUnequipAction:new(playerObj, item, 50)); else ISInventoryPaneContextMenu.transferIfNeeded(playerObj, item) ISTimedActionQueue.add(ISEquipWeaponAction:new(playerObj, item, 50, primary, false)); end if not item:isActivated() then item:setActivated(true) end; end function ISLightSourceRadialMenu:onInsertBattery(item) local playerObj = self.character local containerList = ISInventoryPaneContextMenu.getContainers(playerObj) local recipe = self:getInsertBatteryRecipe(item, containerList) if not recipe then return end ISInventoryPaneContextMenu.OnCraft(item, recipe, self.playerNum, false) end function ISLightSourceRadialMenu:onRemoveBattery(item) local playerObj = self.character local containerList = ISInventoryPaneContextMenu.getContainers(playerObj) local recipe = self:getRemoveBatteryRecipe(item, containerList) if not recipe then return end ISInventoryPaneContextMenu.OnCraft(item, recipe, self.playerNum, false) end function ISLightSourceRadialMenu:onToggle(item) if item:canBeActivated() then item:setActivated(not item:isActivated()) end end function ISLightSourceRadialMenu:onLightCandle(item) local playerObj = self.character local recipe = getScriptManager():getRecipe("Light Candle") if not recipe then return end ISInventoryPaneContextMenu.OnCraft(item, recipe, self.playerNum, false) end function ISLightSourceRadialMenu:onExtinguishCandle(item) local playerObj = self.character local recipe = getScriptManager():getRecipe("Extinguish Candle") if not recipe then return end ISInventoryPaneContextMenu.OnCraft(item, recipe, self.playerNum, false) end function ISLightSourceRadialMenu:new(character) local o = ISBaseObject.new(self) o.character = character o.playerNum = character:getPlayerNum() return o end ----- local STATE = {} STATE[1] = {} STATE[2] = {} STATE[3] = {} STATE[4] = {} function ISLightSourceRadialMenu.checkKey(key) if key ~= getCore():getKey("Equip/Turn On/Off Light Source") then return false end if isGamePaused() then return false end local playerObj = getSpecificPlayer(0) if not playerObj or playerObj:isDead() then return false end local queue = ISTimedActionQueue.queues[playerObj] if queue and #queue.queue > 0 then return false end if getCell():getDrag(0) then return false end return true end function ISLightSourceRadialMenu.onKeyPressed(key) if not ISLightSourceRadialMenu.checkKey(key) then return end local radialMenu = getPlayerRadialMenu(0) if getCore():getOptionRadialMenuKeyToggle() and radialMenu:isReallyVisible() then STATE[1].radialWasVisible = true radialMenu:removeFromUIManager() return end STATE[1].keyPressedMS = getTimestampMs() STATE[1].radialWasVisible = false end function ISLightSourceRadialMenu.onKeyRepeat(key) if not ISLightSourceRadialMenu.checkKey(key) then return end if STATE[1].radialWasVisible then return end if not STATE[1].keyPressedMS then return end local radialMenu = getPlayerRadialMenu(0) local delay = 500 if (getTimestampMs() - STATE[1].keyPressedMS >= delay) and not radialMenu:isReallyVisible() then local rm = ISLightSourceRadialMenu:new(getSpecificPlayer(0)) rm:fillMenu() rm:display() end end function ISLightSourceRadialMenu.onKeyReleased(key) if not ISLightSourceRadialMenu.checkKey(key) then return end if not STATE[1].keyPressedMS then return end local radialMenu = getPlayerRadialMenu(0) if radialMenu:isReallyVisible() or STATE[1].radialWasVisible then if not getCore():getOptionRadialMenuKeyToggle() then radialMenu:removeFromUIManager() end return end if getTimestampMs() - STATE[1].keyPressedMS < 500 then ItemBindingHandler.toggleLight(key) end STATE[1].keyPressedMS = nil end local function OnGameStart() Events.OnKeyStartPressed.Add(ISLightSourceRadialMenu.onKeyPressed) Events.OnKeyKeepPressed.Add(ISLightSourceRadialMenu.onKeyRepeat) Events.OnKeyPressed.Add(ISLightSourceRadialMenu.onKeyReleased) end Events.OnGameStart.Add(OnGameStart)