Function calls : from_inv_slot / to_inv_slot / after_...
Moderator: Sophia
Forum rules
Please read the Forum rules and policies before posting.
Please read the Forum rules and policies before posting.
Function calls : from_inv_slot / to_inv_slot / after_...
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...
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...
What Is Your Quest ?
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).I don't really understand when exactly "after_to_l_hand" and "after_from_l_hand" are called also...
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.
- Sophia
- Concise and Honest
- Posts: 4240
- Joined: Thu Sep 12, 2002 9:50 pm
- Location: Nowhere in particular
- Contact:
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:
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)
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
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.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.
- Sophia
- Concise and Honest
- Posts: 4240
- Joined: Thu Sep 12, 2002 9:50 pm
- Location: Nowhere in particular
- Contact:
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.
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.
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.)
'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.)
- Sophia
- Concise and Honest
- Posts: 4240
- Joined: Thu Sep 12, 2002 9:50 pm
- Location: Nowhere in particular
- Contact:
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:
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:
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.
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
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)
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.
...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)
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)
What Is Your Quest ?
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....I thought that false == nil in LUA...
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").- "fit_" can interrupt the swap.
- "to_" & "from_" applies if 'fit' is true, and can also interrupt the swap
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's possible in a "normal" dungeon to make weird things with the "to_" and "from_" functions,
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.
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.what happens if the spawn fails ?
- Sophia
- Concise and Honest
- Posts: 4240
- Joined: Thu Sep 12, 2002 9:50 pm
- Location: Nowhere in particular
- Contact:
Nil evalulates to false when it's taken as a boolean, but other than that, they're distinct values.Joramun wrote:...I thought that false == nil in LUA...
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
"Normal" and "weird" are pretty subjective when we're talking about custom dungeons, aren't they?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).
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.
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.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"...
So, in other words, if Zyx ever gets into DSB editing, we'll find out what it's for.
Or something delightfully twisted us mere mortals cannot yet grasp.RemyR wrote:If the designer makes them return values, he's trying to do something he likely shouldn't be.
(Ok, so I'm being optimistic!)
It's never called.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.
If the slot you try to dsb_spawn or dsb_move into is full, the function returns nil and does nothing else significant.
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.
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.
What Is Your Quest ?