Page 1 of 1
Function calls : from_inv_slot / to_inv_slot / after_...
Posted: Wed Nov 07, 2007 10:00 am
by Joramun
As discussed with Sophia, those functions get problematic
if someone tries to make a custom inventory with different
slot number, or to make "unpredicted" behavior, like an item
that would call a function once put into a chest.
I don't really understand when exactly "after_to_l_hand" and "after_from_l_hand" are called also...
EDIT: there can also be problems with the "fit_/slot/" properties for custom inventories...
Posted: Wed Nov 07, 2007 6:36 pm
by Remy
I don't really understand when exactly "after_to_l_hand" and "after_from_l_hand" are called also...
Well,
to_l_hand is called before the obj is popped from the mouse cursor,
after_to_l_hand is called after. Both, however, occur after the DSB Engine does a "fit_[slot]" check (so if that check fails, neither is called).
So, after the player clicks a slot (with an obj in the cursor), DSB checks "fit_", then calls "to_", then pops the obj to the slot, then calls "after_to_".
That's basically the sequence (slot "r_hand" has some further actions, which may or may not be relevant).
Really, I'd have to see how
sys_inventory actually handles "fit_" checks under the new system before making assumptions about what's left internally, handled by the DSB Engine alone. Depending on how/from where/why it gets called, the solution could be there. Obviously, it would have to be aware of the slot the player is trying to put something in, and if it is, then it could cover calling "to_" functions.
Posted: Wed Nov 07, 2007 7:06 pm
by Sophia
Under the new system, the only thing called by the engine for all slots is
sys_inventory. All that fit/to/from/etc. stuff is handled from there. Well, and the core engine takes care of the actual putting the instance into the slot, but that's just housekeeping. Currently, slot 0 (by default, "r_hand") has some hardcoded extra features, like triggering subrenderers when the inventory screen is up.
But why tell when I can show! It's not that long of a function:
Code: Select all
function sys_inventory(who, slot, pickup, putdown, when, force)
local from_word
if (when) then from_word = "after_from_"
else from_word = "from_" end
local to_word
if (when) then to_word = "after_to_"
else to_word = "to_" end
local slotname = inventory_info[slot].name
if (not when) then
local fit = false
if (force or not putdown) then
fit = true
else
local arch = dsb_find_arch(putdown)
if (slot <= INV_L_HAND) then fit = true
elseif (arch.no_fit_inventory) then fit = false
elseif (slot >= INV_PACK) then fit = true
else
fit = arch["fit_" .. slotname]
if (slot == INV_QUIVER and not fit) then
fit = arch.fit_sheath
end
end
end
if (not fit) then return false end
end
if (pickup) then
local arch = dsb_find_arch(pickup)
if (arch[from_word .. "anywhere"]) then
if (arch[from_word .. "anywhere"](arch, pickup, who)) then
return false
end
end
if (arch[from_word .. slotname]) then
if (arch[from_word .. slotname](arch, pickup, who)) then
return false
end
end
end
if (putdown) then
local arch = dsb_find_arch(putdown)
if (arch[to_word .. "anywhere"]) then
if (arch[to_word .. "anywhere"](arch, putdown, who)) then
return false
end
end
if (arch[to_word .. slotname]) then
if (arch[to_word .. slotname](arch, putdown, who)) then
return false
end
end
end
return true
end
As for chests, that's already handled. When an objzone is clicked, the
objzone_check method is called for that arch. For a chest, this checks fit_chest. (For convenience and logic, anything with fit_pouch set is also assumed to fit in a chest)
Posted: Wed Nov 07, 2007 7:15 pm
by Joramun
And so this function is called whenever an item is taken to/from any inventory slot...
Is it also called when an item is spawned in a character's inventory ?
Posted: Wed Nov 07, 2007 8:26 pm
by Sophia
Yes it is.
In that case, the return value is ignored-- the instance is going into the inventory no matter. In those cases, the force parameter is set to true.
Posted: Wed Nov 07, 2007 9:53 pm
by Remy
n that case, the return value is ignored-- the instance is going into the inventory no matter. In those cases, the force parameter is set to true.
Perhaps I'm reading it wrong, but if 'force' is supposed to work no matter what, shouldn't the second half of the function - after all the "fit" stuff is done - return "force" in the places where it returns 'false'? Namely, if an event handler exists, and that event handler returns something other than 'false' or 'nil'. I assume it's done this way because most handlers will return 'nil', but gives the designer an oppurtunity to cancel a move conditionally.
Posted: Wed Nov 07, 2007 11:37 pm
by Sophia
Your understanding of the function is right, and that would be a good change to ensure that the "proper" return value is always returned.
In practice, it makes no difference, because if force is set, the return value is ignored anyway. The function can return true, false, nil, or 3.14159, it doesn't matter. (Hence, it's being "forced")
It's simply there to inform the function the move is always going to succeed, so that it can carry out whatever it needs to do, even if it would normally fail. In this case, force tells it to not even bother with any of the fit_ values, because the inst will go into the inventory anyway.
Posted: Thu Nov 08, 2007 2:44 am
by Remy
Okay, well, then I have another question: if two insts are being swapped (one going from MOUSE_HAND to an inventory slot, and one going the other way), does sys_inventory get called just once for both, with both arguments - 'pickup' and 'putdown' - set?
'Cause if that's the case, I think there needs to be caveat - that 'to_[slot]' functions should be used for conditional checks and that 'after_to_[slot]' functions for any actual changes to a champion or the dungeon.
If both arch's have event functions defined, and the 'putdown' inst follows through with its handler, but the 'pickup' one hits a conditional and returns 'true', then the move will be cancelled; but 'putdown' will have already executed it's handler, which is bad.
Now, I don't think this needs to be enforced in the code - because it's too limiting for run-of-the-mill dungeons that will never exploit the ability to cancel moves this way - but it's something to keep in mind.
Either that, or do away with the exploit, but I really can't see another way to do the kinds of things you can do with it available.
(Actually, whether or not both insts are checked at the same time is irrelevant in this case. I imagine both are - since otherwise there will be a moment when either the MOUSE_HAND or an inventory slot will have two items - but the end result of a cancellation is the same.)
Posted: Thu Nov 08, 2007 4:49 am
by Sophia
Those are very good observations.
I've come up with a couple of ways to remedy this. First of all, I've added the following lines:
Code: Select all
if (type(fit) == "function") then
fit = fit(arch, putdown, who)
end
What this does is it allows the fit_* fields in the arch to be functions as well, giving the ability to dynamically cancel the move before anything's actually happened.
Now, this means that the fit_* functions will cancel on a false. The other ones would cancel on a true... and it just got too confusing. So I changed the function call to this:
Code: Select all
if (arch[from_word .. "anywhere"](arch, pickup, who) ~= nil)
Now, if it returns anything at all, that will be taken as failure. False, true, whatever. Chances are if everything went according to plan you're not going to have a return statement at all. (and in Lua, that's taken as a return of nil)
Finally, I changed the second set of functions (the ones operating on putdown, after pickup has already succeeded) to ignore the return value. Might as well not even invite the troublesome situation.

Posted: Thu Nov 08, 2007 10:32 am
by Joramun
...I thought that false == nil in LUA...
So the function sys_inventory is called once "before" and once "after" the swap of items (or between NULL and an item) :
- "fit_" can interrupt the swap.
- "to_" & "from_" applies if 'fit' is true, and can also interrupt the swap
( it's ok if I want some item to be unmovable from the inventory )
- 'after_" applies after the swap...
I agree it's better to hide the swap in between as a "core function", but somehow the current design makes me uncomfortable.
It's possible in a "normal" dungeon to make weird things with the "to_" and "from_" functions,
that should normally be used only for checking special cases of "fit_" (like a torch going into a hand).
The use of the "after_" functions seems ok, even though the return value of "after_from" can impede the execution of "after_to"...
And about the dsb_spawn calling sys_inventory :
what happens if the spawn fails ?
(e.g. if the inventory slot is taken already)
Posted: Thu Nov 08, 2007 5:37 pm
by Remy
...I thought that false == nil in LUA...
Not quite. Lua will accept 'nil' as 'false', but 'false' is never 'nil'. 'nil' is the absense of a value, 'false'
is a value - it can never mean the absense of itself.
- "fit_" can interrupt the swap.
- "to_" & "from_" applies if 'fit' is true, and can also interrupt the swap
Again, not quite. At least, not anymore. 'to_*' can no longer interrupt swaps - to stop an inst from going to a slot, it must be handled in a 'fit_*'. (Which is actually rather brilliant, and much better than the idea I had when I said "enforced in code").
It's possible in a "normal" dungeon to make weird things with the "to_" and "from_" functions,
I'm wondering how you classify a dungeon as "normal" - if it's doing wierd things in 'to_*' and 'from_*' functions, and you don't call that "normal", then, obviously, the dungeon isn't "normal".
It can only do wierd things if the designer specifically returns values with event handlers - in other words, the designer has to make an active choice.
This applies to 'after_*' functions as well - they shouldn't be returning anything, since returning values here does absolutely nothing - the swap has already taken place, it can't be stopped at this point. If the designer makes them return values, he's trying to do something he likely shouldn't be.
what happens if the spawn fails ?
The inst is never created, so even if
sys_inventory is called, both 'pickup' and 'putdown' are 'nil', and no event functions will be executed.
Posted: Thu Nov 08, 2007 7:31 pm
by Sophia
Joramun wrote:...I thought that false == nil in LUA...
Nil evalulates to false when it's taken as a boolean, but other than that, they're distinct values.
As an aside, one of the few things that actually annoys me about Lua is that the number zero is
not evalulated in this way.
Code: Select all
num = 0
if (num) then
-- This code will execute
else
-- This code won't!
end
Joramun wrote:It's possible in a "normal" dungeon to make weird things with the "to_" and "from_" functions,
that should normally be used only for checking special cases of "fit_" (like a torch going into a hand).
"Normal" and "weird" are pretty subjective when we're talking about custom dungeons, aren't they?
My motivation behind allowing the from_* to return a value that can be acted upon was actually exactly what you said was weird-- to embed a check in there. In the current code, there's no opposite to "fit." This is why I made from_* execute first, so it can also forbid taking something
out of the hand. For example, say you want to create a cursed sword that won't let you take it out of your weapon hand. That code would have to be in from_r_hand.
Joramun wrote:The use of the "after_" functions seems ok, even though the return value of "after_from" can impede the execution of "after_to"...
Well, yes. Realistically, though, after_* shouldn't return anything, because the return value won't do anything. If it returns something, I'd say that's a flaw in the dungeon designer's code. You're right about that situation though-- I'm going to leave it in for the bizarre circumstances I haven't thought of where some twisted mind might find it useful.
So, in other words, if Zyx ever gets into DSB editing, we'll find out what it's for.
RemyR wrote:If the designer makes them return values, he's trying to do something he likely shouldn't be.
Or something delightfully twisted us mere mortals cannot yet grasp.
(Ok, so I'm being optimistic!)
RemyR wrote:The inst is never created, so even if sys_inventory is called, both 'pickup' and 'putdown' are 'nil', and no event functions will be executed.
It's never called.
If the slot you try to
dsb_spawn or
dsb_move into is full, the function returns nil and does nothing else significant.
Posted: Thu Nov 08, 2007 11:46 pm
by Joramun
You'll soon see what's a weird dungeon.
This is the second item in my list of projects in DSB.
Anyway, my brain is too small to figure out what the last version of the sys_inventory function must look like now, I was only talking about the one above. So don't worry about my remarks on "to_*" "from_*" etc.