Jump to content

The mystery of "ISTimedActionQueue" !


RAINBOW

Recommended Posts

I've reached a point in modding, where I need to learn what this function:

 

ISTimedActionQueue

 

Does.  

 
What I have learned from delving into PZ modding, is that lua calls require knowing what is going on here.  
 

I'm assuming this is the handler for all the action "bar" related things that go on in PZ.  Such as eating a "Ham" item in my example. ("Jambon" if you are Robert Johnson :) ) so booleans like "Finished" and "Started" are all there in the documentation (as you would expect). 

 

 

My example pertains to the following piece of code I have copied out of the lua file which deals extensively with the inventory panel (You can find the example files in "Steam/SteamApps/Media/lua" incidentally!)

    -- alot of stuff here before     -- Then eat it.      ISTimedActionQueue.add(ISEatFoodAction:new(player, item, 240));

 I decided to debug with a few print statements before I got stuck into it-  Heres what I did to debug, basically just see what printed in console:

    -- Then eat it.      ISTimedActionQueue.add(ISEatFoodAction:new(player, item, 240));--debugprint(getItemText(item:getName()));print(item);print(player, item);print(item:getName());

The answer, quizzically, was none of the print statements worked! Interesting isn't it!

 

The method defined "item" here:

 

"ISInventoryPaneContextMenu.eatItem = function(item, player)"
 
My suspicions lie entirely with the ActionQueue functions.  Does anyone know what is going on here?
 
Link to comment
Share on other sites

I documented the TA I use for Unpack Bags, so maybe this'll help you:

 

-- =============================================================================-- Unpack Bags-- by RoboMat---- Created: 23.08.13 - 10:39-- =============================================================================require'TimedActions/ISBaseTimedAction';-- -------------------------------------------------- Global Variables-- ------------------------------------------------TAUnpackBag = ISBaseTimedAction:derive("TAUnpackBag");-- -------------------------------------------------- Functions-- ----------------------------------------------------- The condition which tells if the timed action is still valid.--function TAUnpackBag:isValid()    return true;end----- Stops the Timed Action.--function TAUnpackBag:stop()    ISBaseTimedAction.stop(self);end----- Is called on start of the Timed Action.--function TAUnpackBag:start()end----- Is called when the time has passed.--function TAUnpackBag:perform()    local player = self.character;    local bag = self.bag;    local inventory = bag:getInventory(); -- Get the bag's inventory.    local container = bag:getContainer(); -- Get the container in which the bag itself is contained.    -- Remove all items from the baggage container.    inventory:removeAllItems();    -- Now we move all the items from the bag to the container.    container:setDrawDirty(true);    for _, item in ipairs(self.itemsInBag) do        if item then            -- If the floor is selected add the items to the ground.            if container:getType() == "floor" then                player:getCurrentSquare():AddWorldInventoryItem(item, 0.0, 0.0, 0.0);            else                container:AddItem(item);            end        end    end    -- Make sure we refresh the inventory so the items show up.    local pdata = getPlayerData(player:getPlayerNum());    if pdata then        pdata.playerInventory:refreshBackpacks();        pdata.lootInventory:refreshBackpacks();    end    -- Remove Timed Action from stack.    ISBaseTimedAction.perform(self);end----- Constructor-- @param _character - The character who performs the action.-- @param _table - The table containing all items in the bag.-- @param _bag - The container / bag itself.-- @param _time - The time to complete the action.--function TAUnpackBag:new(_character, _table, _bag, _time)    local o = {};    setmetatable(o, self);    self.__index = self;    o.character = _character;    o.bag = _bag;    o.itemsInBag = _table;    o.stopOnWalk = false;    o.stopOnRun = false;    o.maxTime = _time;    return o;end

 

and yeah just like you thought you'll have to add it to the queue some time:

    ISTimedActionQueue.add(TAUnpackBag:new(_player, _itemsInContainer, bag, 50));

That's all you need :)

Link to comment
Share on other sites

Hmm.. This is all well and good, but what about when you are wanting to "Check" on the progress of a timed action?

 

Here's what I mean in code, the example is called from an overridden base lua file in my mod folder, and is working in the 'traditional sense' of throwing errors:

 

--Lots of stuff came before here....     -- Then eat it.ISTimedActionQueue.add(ISEatFoodAction:new(player, item, 240));  --------------------------------------------------------------- --+Debug+-- "The statement AAAAAA will print fine, just after this action queue has been called here in my--overrided base lua.  But BBBBB will not execute."player:Say("AAAAAA");---------------------------------------------------------------if ISTimedActionQueue.finish(ISEatFoodAction) == true thenplayer:Say("BBBBB"); end ---------------------------------------------------------------

 

The code throws a "Called T nil" error, and "BBBBB" is never printed! I double checked that "finish" is an acceptable boolean here. I looked for examples of checking for a finished action queue, and have last resorted to this post.  

 

Cheers in advance! Raenbow

Link to comment
Share on other sites

Ah ha! I've been editing code where I shouldn't be, haven't I?

 

I've been editing the "Right Click Inventory Panel" lua, when I needed to be in the "ISEatFoodAction.lua"!

 

it's no wonder I've been unable to find a finish option!

Link to comment
Share on other sites

Going out on a limb, but I'd assume it's because you're testing whether a uninitialized action is complete -- something that'd never happen, it not existing.

Try

o = ISEatFoodAction
:new(player, item, 240)

 

ISTimedActionQueue.add(o)

...

if ISTimedActionQueue.finish(o) == true then
player:Say("BBBBB");
end

Link to comment
Share on other sites

You could also hook into the perform() function of the timed action as that one is performed after the "progress bar" is full.

 

function ISFooBarAction:perform()    -- do fun code stuff here    player:Say('Never Gonna Give You Up');end

 

Unless I misunderstood what you want to do.

Link to comment
Share on other sites

The problem I have discovered, is I can hook into the Event fired in the "Right Click Inventory Panel" which is found here:

 

C:\Program Files (x86)\Steam\SteamApps\common\ProjectZomboid\media\lua\ISUI\ISInventoryPaneContextMenu.lua"

 

here's some sample code that fires okay from right clicking in game:

 
--The player has right clicked the menu.  function RClickMenu.init(player, context, items) --debugplayer:Say("AAAAAAAA"); end   Events.OnFillInventoryObjectContextMenu.Add(RClickMenu.init);

But! what about when I want to access the code within, in particular, the "ISEatFoodAction.perform"?

Link to comment
Share on other sites

Agh! Nevermind, I went back to it after a cup of tea, was calling a bloody nil table for the 1000th time, if anyone reading this ever see's the error "Called T nil table" or whatever it is, it is because one of your vars is undeclared.  thing is working perfectly now. lol ! Sorry I bloody wasted everyones time.

 

Here's some working code:

 
RClickMenu = {}; --The player has right clicked the menu.  If shit happens, do shit.function RClickMenu.init(player, context, items)  --custom SANCTUARY here:function ISEatFoodAction:perform()-- do fun code stuff hereself.character:Say('Never Gonna Give You Up');endend   Events.OnFillInventoryObjectContextMenu.Add(RClickMenu.init);

Fixed code-tags.

 

-RM

Link to comment
Share on other sites

I don't want to sound like a dick, but that's totally wrong RAINBOW ^^

 

Here is example code from my unpack bags mod. It does what you are trying to do (I think) which is starting a timed action once the player has clicked a context menu in the inventory.

 

Timed Action

-- =============================================================================-- Unpack Bags-- by RoboMat---- Created: 23.08.13 - 10:39-- =============================================================================require'TimedActions/ISBaseTimedAction';-- -------------------------------------------------- Global Variables-- ------------------------------------------------TAUnpackBag = ISBaseTimedAction:derive("TAUnpackBag");-- -------------------------------------------------- Functions-- ----------------------------------------------------- The condition which tells the timed action if it-- is still valid.--function TAUnpackBag:isValid()    return true;end----- Stops the Timed Action.--function TAUnpackBag:stop()    ISBaseTimedAction.stop(self);end----- Starts the Timed Action.--function TAUnpackBag:start()end----- Is called when the time has passed.--function TAUnpackBag:perform()    local player = self.character;    local bag = self.bag;    local inventory = bag:getInventory(); -- Get the bag's inventory.    local container = bag:getContainer(); -- Get the container in which the bag itself is contained.    -- Remove all items from the baggage container.    inventory:removeAllItems();    -- Now we move all the items from the bag to the container.    container:setDrawDirty(true);    for _, item in ipairs(self.itemsInBag) do        if item then            -- If the floor is selected add the items to the ground.            if container:getType() == "floor" then                player:getCurrentSquare():AddWorldInventoryItem(item, 0.0, 0.0, 0.0);            else                container:AddItem(item);            end        end    end    -- Make sure we refresh the inventory so the items show up.    local pdata = getPlayerData(player:getPlayerNum());    if pdata then        pdata.playerInventory:refreshBackpacks();        pdata.lootInventory:refreshBackpacks();    end    -- Remove Timed Action from stack.    ISBaseTimedAction.perform(self);end----- Constructor-- @param _character - The character who performs the action.-- @param _table - The table containing all items in the bag.-- @param _bag - The container / bag itself.-- @param _time - The time to complete the action.--function TAUnpackBag:new(_character, _table, _bag, _time)    local o = {};    setmetatable(o, self);    self.__index = self;    o.character = _character;    o.bag = _bag;    o.itemsInBag = _table;    o.stopOnWalk = false;    o.stopOnRun = false;    o.maxTime = _time;    return o;end

 

Inventory

-- =============================================================================-- Unpack Bags-- by RoboMat---- Created: 22.08.13 - 12:00-- =============================================================================require'Mods/UnpackBags/TimedActions/TAUnpackBag';require'TimedActions/ISTimedActionQueue';-- -------------------------------------------------- Local Variables-- ------------------------------------------------local zomboid = zomboid;local table = table;-- -------------------------------------------------- Local Functions-- ----------------------------------------------------- Creates the timed action which empties the bag.-- @param _items - A table containing the clicked items / stack.-- @param _player - The player who clicked the menu.-- @param _itemsInContainer - The items contained in the bag.-- @param _bag - The bag to unpack.--local function onUnpackBag(_items, _player, _itemsInContainer, _bag)    local bag = _bag;    local bagWeight = bag:getInventory():getCapacityWeight();    local container = bag:getContainer();    local conWeight = bag:getContainer():getCapacityWeight();    -- We check if the target bag has enough free capacity to hold the items.    if container:getCapacity() < (bagWeight + conWeight) then        zomboid.okModal("There is not enough space to unpack the bag here.", true);        return;    end    ISTimedActionQueue.add(TAUnpackBag:new(_player, _itemsInContainer, bag, 50));end----- Creates a context menu entry when the player selects-- an inventory container (e.g. hiking bag).-- @param _player - The player who clicked the menu.-- @param _context - The context menu to add a new option to.-- @param _items - A table containing the clicked items / stack.--local function createMenu(_player, _context, _items)    local itemTable = _items; -- The table containing the clicked items.    local context = _context;    local player = getSpecificPlayer(_player);    -- We iterate through the table of clicked items. We have    -- to seperate between single items, stacks and expanded    -- stacks.    for i1 = 1, #itemTable do        local item = itemTable[i1];        if instanceof(item, "InventoryItem") and instanceof(item, "InventoryContainer") then            local bag = item; -- Store the clicked bag.            local itemsInContainer = table.convertArrayList(bag:getInventory():getItems()); -- Get its contents.            -- Only create a menu entry if the bag contains an item.            if #itemsInContainer > 0 then                context:addOption("Unpack (" .. #itemsInContainer .. " Items)", itemTable, onUnpackBag, player, itemsInContainer, bag);            end        elseif type(itemTable[i1]) == "table" then            -- We start to iterate at the second index to jump over the dummy            -- item that is contained in the item-table.            for i2 = 2, #itemTable[i1].items do                local item = itemTable[i1].items[i2];                if instanceof(item, "InventoryItem") and instanceof(item, "InventoryContainer") then                    local bag = item;                    local itemsInContainer = table.convertArrayList(bag:getInventory():getItems());                    if #itemsInContainer > 0 then                        context:addOption("Unpack (" .. #itemsInContainer .. " Items)", itemTable, onUnpackBag, player, itemsInContainer, bag);                    end                end            end        end    endend-- -------------------------------------------------- Game Hooks-- ------------------------------------------------Events.OnPreFillInventoryObjectContextMenu.Add(createMenu);

 

You never directly call a timed action's functions since they are called automatically by the engine. You only add them to the queue:

local function onUnpackBag(_items, _player, _itemsInContainer, _bag)    -- <snip>     -- this is all you will ever need to call for a timed action    ISTimedActionQueue.add(TAUnpackBag:new(_player, _itemsInContainer, bag, 50));end
Link to comment
Share on other sites

To elaborate:

 

ISEatFoodAction can be compared to a class that you'd have in an OOP language.
 

The ...new() function is a constructor which creates a new object (through metatable-wizardy and magic) and returns it.

So you could rewrite the above example like this:

 

-- Create a new instance of the timed action.local TAobject = TAUnpackBag:new(_player, _itemsInContainer, bag, -- Add it to the queue for timed actions.ISTimedActionQueue.add(TAobject);

 

Of course you could now call the methods of the created objects outside of the timed action queue (albeit I never tried that, because I never needed it^^) like this:

 

TAObject:perform()

 

If you'd try to call TAUnpackBAgs:perform() you'd try to call a function and since perform() internally tries to access variables that are only initialised via a constructor you'll get "tried to call nil" exceptions a lot.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...