Feature Specification: Resting
Moderators: ALFA Administrators, Staff - Technical
- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
I took a look at the persistent storage object script. A couple comments:
1. It looks like it's incomplete. Specifically, the initialization script has an empty else clause and is at odds with the prototype. Are you still working on this? Also, can you convert comments to the //! standard for things you want the documentation parser to pick up? I've done this for all function prototypes but kept comments within functions private (use standard // comment prefix). That way, we can actually have some worthwhile developer docs when we're done coding w/o investing any extra time.
2. I think it's preferrable to expose set/get primitive function calls for handling PC data persistence than to call functions which return the skin object reference. The latter permits scripters to play around with the object reference within the application in ways they really shouldn't (like DestroyObject()). So unless you object, I'd like to limit the PC persistence interface to the appropriate PCGet and PCSet functions.
P.S. I couldn't find any acr_game_loc_i script in the repository but I did find an _acr_location_i script. This deals with persistent locations, so was this the script you intended to reference or did you not commit the file to the repository yet? And given the "_" prefix, does that mean it's a private script not to be referenced by other scripts?
P.P.S. Are the core functions you wrote ready for use or do you need more time to test? They're still noted as untested on the development priority thread so I'm not sure if you're still fiddling with them.
1. It looks like it's incomplete. Specifically, the initialization script has an empty else clause and is at odds with the prototype. Are you still working on this? Also, can you convert comments to the //! standard for things you want the documentation parser to pick up? I've done this for all function prototypes but kept comments within functions private (use standard // comment prefix). That way, we can actually have some worthwhile developer docs when we're done coding w/o investing any extra time.
2. I think it's preferrable to expose set/get primitive function calls for handling PC data persistence than to call functions which return the skin object reference. The latter permits scripters to play around with the object reference within the application in ways they really shouldn't (like DestroyObject()). So unless you object, I'd like to limit the PC persistence interface to the appropriate PCGet and PCSet functions.
P.S. I couldn't find any acr_game_loc_i script in the repository but I did find an _acr_location_i script. This deals with persistent locations, so was this the script you intended to reference or did you not commit the file to the repository yet? And given the "_" prefix, does that mean it's a private script not to be referenced by other scripts?
P.P.S. Are the core functions you wrote ready for use or do you need more time to test? They're still noted as untested on the development priority thread so I'm not sure if you're still fiddling with them.
As I see it, the medium on which to store persistant player information should be seperate from the system which processes said information. Other systems may persistantly store things on PCsç i p h é r wrote:Just your simple garden variety confusion. I *thought* that was part of the persistent pc status project, as well as "status" logging and restoring. I'll check it out and adjust as needed. Looks like we duplicated some minor effort, but not a big deal.
Oh. I'd intended for it to be both. I'd certainly like any behavior which would classify as "warning" or "fatal" levels going through it, while the "info" level is more standard debugging output (and is deactivated on most systems by default).ç i p h é r wrote:Because there wasn't anything specifically noted in the specification for debugging or logging. I figured our needs would eventually reveal themselves once we had something functional and we got requests to add certain information. Just to be clear, my interpretation of the intent of a debugging system is to provide builders and server admins with the tools they need to diagnose real time problems, not as a test tool for developers to evaluate their scripts.
I just didn't want everything to get jumbled up with NWN1 stuff. No big deal.ç i p h é r wrote:I posted a note about this earlier. Given the time remaining before NWN2 arrives and the resources we have on the tech team, I didn't see the purpose in maintaining a repository for both versions. I only wanted NWN1 content in there initially to get a handle on sourceforge and do some testing with file releases, but again, time and resources permitting. At this juncture, I'd rather invest the time and resources on NWN2 and avoid committing anything more to content we intend to replace.
Do you have a different opinion? Do you see a need for separation? I interpretted the lack of response to my initial recommendation as agreement. We still need to migrate the files over, but I didn't want to do that until you were ready.
Good idea, using the OnSpawn event. I'll upload the little event-handler I wrote after my first reply, which uses DelayCommand() polling. We can always change it later if NWN2 permits. The file is acr_onpcspawn_i.nss.ç i p h é r wrote:I was actually hoping/expecting to get an OnSpawn event like we do for NPCs. That should tell us definitively when a player is actually IN the game, unlike the present which requires a small work around (you probably noticed that). Obviously, it's not possible to test an event that doesn't yet exist, though we could simulate it with custom events (for testing purposes) now that I think about it. Nevertheless, it's an easy change we can make once we have an actual list of events from Obsidian.
I wouldn't say I'm "done" working on anything, but yeah it is basically done. I'll get started on the comments when I have time.ç i p h é r wrote:1. It looks like it's incomplete. Specifically, the initialization script has an empty else clause and is at odds with the prototype. Are you still working on this? Also, can you convert comments to the //! standard for things you want the documentation parser to pick up? I've done this for all function prototypes but kept comments within functions private (use standard // comment prefix). That way, we can actually have some worthwhile developer docs when we're done coding w/o investing any extra time.
I had done it that way originally, then changed my mind and erased it all. Nothing outside the ACR should be storing data on PCs anyways, and returning the object reference allows us to do a lot of things without having to write a new function for them all. Things like the game location structures, arrays, and that sort of thing. The biggest reason I changed it was thinking of creature status, if we wanted to store PC status on the c-skin and pet status on a pet token, it made sense to use the same API for each. We can prevent and un-equiping of the c-skin in the module event scripts, but the only thing we can't prevent is a call to DestroyObject. It just doesn't seem likely to me that anyone will call GetPCPersistentStorageObject() then DestroyObject() on it, I find it far more likely a GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC) would precede that call. Of course, we can always override DestroyObject() to keep it from functioning on that resref if we really want to.ç i p h é r wrote:2. I think it's preferrable to expose set/get primitive function calls for handling PC data persistence than to call functions which return the skin object reference. The latter permits scripters to play around with the object reference within the application in ways they really shouldn't (like DestroyObject()). So unless you object, I'd like to limit the PC persistence interface to the appropriate PCGet and PCSet functions.
Oops, thats really old. I'll upload the latest.ç i p h é r wrote:P.S. I couldn't find any acr_game_loc_i script in the repository but I did find an _acr_location_i script. This deals with persistent locations, so was this the script you intended to reference or did you not commit the file to the repository yet? And given the "_" prefix, does that mean it's a private script not to be referenced by other scripts?
Heh, I more or less fiddle with everything. I'd hoped someone else would jump on the spawn system grenade, but as no one else has, I thought I'd focus my efforts on that since its something builders are going to want to use pretty early on. I write a lot of the code I do as ideas come to me, as I find it easier to write and understand code than to make notes on architecture and design, so more often than not I just start coding something if I have a random idea of how a system should work.ç i p h é r wrote:P.P.S. Are the core functions you wrote ready for use or do you need more time to test? They're still noted as untested on the development priority thread so I'm not sure if you're still fiddling with them.
I can get those ready for testing though, I might even have a day of free time this weekend

- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
While all the functions won't be used all the time by a specific application, it seemed reasonable to put functions that are part of the same system, and which need to be called from the application, all in the same include file (more library file than header). I could pull out the initialization function and drop it into an OnClientEnter include, though many other systems would tie into that as well and I imagine that could get rather messy. Anyway, it's a minor issue really (kinda like coding semantics). It can work both ways.
I didn't follow what you meant to do with creature status and pet tokens. Why not store pet status information on the PC skin as well? Obviously, you've given this some thought but off the top of my head, I don't see why we'd need two separate storage objects. One object. One API. Simple. Feel free to burst my bubble though...and I've no doubt you will, blast ye!
I didn't follow what you meant to do with creature status and pet tokens. Why not store pet status information on the PC skin as well? Obviously, you've given this some thought but off the top of my head, I don't see why we'd need two separate storage objects. One object. One API. Simple. Feel free to burst my bubble though...and I've no doubt you will, blast ye!

Off the top of my head, the systems which would need to access the PC's pStorage object would be,ç i p h é r wrote:While all the functions won't be used all the time by a specific application, it seemed reasonable to put functions that are part of the same system, and which need to be called from the application, all in the same include file (think library file, not header). I could pull out the initialization function and drop it into an OnClientEnter include, though many other systems would tie into that as well and I imagine that could get rather messy. Anyway, it's a minor issue really (kinda like coding semantics). It can work both ways.
- Portalling
- Pets
- Creature status
- Currency system (maybe this would be part of creature status, though)
- Language system
- Nonlethal damage (part of creature status? probably)
- Crafting system
- Probably other stuff I'm forgetting.
Well, creature/pet status takes up quite a few variables, and the more variables we have on an object, the slower reads and writes are. In addtion there seems to be a limit on the number of local variables which can be saved to an item before the game just says "screw this" and doesn't save any on that item. I'm not sure what that limit is, though I can do more testing. I was concerned that a large number of pets (which would certainly have more variables than simple creature status, as I intend to take advantage of the dynamic event scripts on creatures to literally make pets on the fly) could put us over this limit. Even if its all accessed through our APIs, its a potential memory leak which could cause all the data on the PC's c-skin to not be saved on logout. Maybe this variable limit is too high to be of concern (anyone know anything about it? I'd not heard of it before my testing), but I'd like to err on the side of caution.ç i p h é r wrote:I didn't follow what you meant to do with creature status and pet tokens. Why not store pet status information on the PC skin as well? Obviously, you've given this some thought but off the top of my head, I don't see why we'd need two separate storage objects. One object. One API. Simple. Feel free to burst my bubble though...and I've no doubt you will, blast ye!
The downside of using weightless item tokens as pet items/tools/storage devices is of course finding the item in a PC's inventory takes a while. Looping through an inventory is slow. But I think that would be a pretty rare event, since the items would be used and targetted directly, I'm not even sure we'd need to loop through the inventory at all point, unless we have a DM tool to find and manage all pets on a PC without the DM having to rumage through bags.
Of course, persistant effects on the c-skin are another possible source of a memory leak. Those could be replaced by item tokens as well, and with SetDescription() functions, be more user-friendly for DMs to remove (and maybe add).
- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
I've not heard anything official about variable limits, but I don't troll forums. Is this some obscure discovery?
If you know for certain there is a hardcoded variable limit, testing to discover it would obviously be a good idea. By and large though, I think most game-systems, like language, pets, currency, and crafting will have specific items associated with them which we would use to store relevant data persistently. The only things I thought we'd store on the Skin was PC information, like status (health, condition) and location (including for portalling) or any other non-game system.
If you know for certain there is a hardcoded variable limit, testing to discover it would obviously be a good idea. By and large though, I think most game-systems, like language, pets, currency, and crafting will have specific items associated with them which we would use to store relevant data persistently. The only things I thought we'd store on the Skin was PC information, like status (health, condition) and location (including for portalling) or any other non-game system.
I guess so. I'll make up a small framework to test what the limit is. I guess it could be based on size, or number.ç i p h é r wrote:I've not heard anything official about variable limits, but I don't troll forums. Is this some obscure discovery?
Pets I'd agree, their status should be stored on tokens. But why no language on a c-skin? And currency? I'd rather not store things on items if there isn't a good reason to, since it increases access time (finding the item) and just clutters up an inventory in general.ç i p h é r wrote:By and large though, I think most game-systems, like language, pets, currency, and crafting will have specific items associated with them which we would use to store relevant data persistently. The only things I thought we'd store on the Skin was PC information, like status (health, condition) and location (including for portalling) or any other non-game system.
If we make our data storage and retrieval tools to function on any object, we can use the same code to store on a c-skin as an item, and I think this should reduce the total number of sloc and tedium needed. Things like the game location struct will need to be stored in more than a few places I think, and it just doesn't make sense to me to write more code for it just to keep a scripter from being able to act directly on the c-skin object. If the only fear is DestroyObject(GetPCPersistentStorageObject()), I think thats pretty unlikely without purposeful sabotage, and DestroyObject (GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC)) is far more likely.
But mostly, I'm sort of afraid of how things are done now in the ACR. Currently, no singular API is used for anything. We don't have sets of generic tools to aid scripters, for the most part. So some people use GetStorageObject(), found in the spell tracking code I believe, and some do a GetItemByTag() sort of thing. I think coders are a lot more likely to get sloppy if they (for example) need the array functions on a c-skin and find there aren't any definied. In that case, its a lot easier to call GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC) and then use the generic array functions.
- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
Language would be one of those abstract, behind the scenes things we'd stick on the skin, yeah. But currency, for instance, is going to have items associated with it upon which we'll likely store specific values.Ronan wrote:Pets I'd agree, their status should be stored on tokens. But why no language on a c-skin? And currency? I'd rather not store things on items if there isn't a good reason to, since it increases access time (finding the item) and just clutters up an inventory in general.
As an example, if we create and use individual items that can stack, the stack size represents the quantity so no local vars would be needed there. If we use coin purses, the logical place to store quantity information is on the purse itself, assuming purses themselves are not containers for stackable coinage. Items in inventory are already persistent so storing on the skin seems unnecessary as long as the data is on the inventory items. Totals can be stored as local variables on the PC if we want to optimize processing - the item acquired events will trigger for every object in a player's inventory on first login so totals can be safely recalculated between sessions without having to store them persistently.
Regarding the persistence functions, if I understand you correctly you're advocating generic functions to retrieve specific storage objects vs a more specific API for acting on those objects?
In other words:
GetPCStorageObject(object oPC)
GetPortalStorageObject(object oPC)
GetCurrencyStorageObject(object oPC)
As opposed to more specific data management, such as:
PCSetPersistentInt(object oPC, string sKey, int nVal)
PCGetPersistentInt(object oPC, string sKey, int nVal)
PCSetPersistentArray(object oPC, string sName, string sArray)
PCGetPersistentArray(object oPC, string sName, string sArray)
CurrencySetPersistentFloat(object oPC, string sKey, float fVal)
CurrencyGetPersistentFloat(object oPC, string sKey, float fVal)
Is that what you mean?
Oops, I actually hadn't seen this post.
And now for some confusing nomenclature, I've got another sort of API named "acr_storageobj_i.nss"
I should probably change the name, it was one of the first things I wrote, and at the time I was thinking it would only be used to store local variables and items. But its also used to uniquely identify effects.
Some things I noticed on the rest scripts, is that you've got no way to uniquely identify effects. This is one of the chief uses of the Storage Objects, to identify where certain effects came from. Without this, we can't really tell the difference between one EffectBlindness() and another. So I have all systems which apply effects like such do so with a global variable pointing to their "storage object" (in actuallity a merchant generated at the start location). For example, the nonlethal damage system applies a -4 AB penalty by the following:
_nonlethalEffectsObj, is the global variable pointing to the storage object. So you can remove that specific effect with:
CreateStorageObject() even allows you to specific whether the effects should be removable or not. This will be used in the case of weather, Mythals, and other environmental effects that do not originate with the PC (so cannot be dispelled, cured, etc). I had a more complex system of identifying the causes of effects in mind using bitwise flags, but I never decided on how to implement it exactly, so those changes may have to come later if they do.
Its not important, but I've also got a constant for every bit in acr_tools_i, called BIT_*.
After next week I should have some time to work on this stuff again.
Well, it might not. Depends on how we implement it. Going with an arbritrary number of coins, there is no item, so its all on the c-skin.ç i p h é r wrote:Language would be one of those abstract, behind the scenes things we'd stick on the skin, yeah. But currency, for instance, is going to have items associated with it upon which we'll likely store specific values.
Yes, so that existing functions to manipulate local variable data don't have to be re-written for each storage object.ç i p h é r wrote:Regarding the persistence functions, if I understand you correctly you're advocating generic functions to retrieve specific storage objects vs a more specific API for acting on those objects?
And now for some confusing nomenclature, I've got another sort of API named "acr_storageobj_i.nss"

Some things I noticed on the rest scripts, is that you've got no way to uniquely identify effects. This is one of the chief uses of the Storage Objects, to identify where certain effects came from. Without this, we can't really tell the difference between one EffectBlindness() and another. So I have all systems which apply effects like such do so with a global variable pointing to their "storage object" (in actuallity a merchant generated at the start location). For example, the nonlethal damage system applies a -4 AB penalty by the following:
Code: Select all
// When initializing the system:
_nonlethalEffectsObj = CreateStorageObject();
// When applying the blindness effect:
AssignCommand(_nonlethalEffectsObj, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oPC));
Code: Select all
if(GetEffectCreator(eff) == nonlethalEffectsObj ) {
RemoveEffect(eff)
}
Its not important, but I've also got a constant for every bit in acr_tools_i, called BIT_*.
After next week I should have some time to work on this stuff again.
- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
Yes, effects are indeed a problem not only in terms of identifying the source of the effect (and thus knowing if it's the effect you want to alter) but also in identifying the exact modifiers the effect has applied to the PC. Eg: A PC is ability drained with a negative energy attack but also equips a cursed item, both of which happen to apply a permanent negative modifier on the same attributes. When resting, the negative modifiers from the ability drain attack should heal but not from the curse. There are more situations to puzzle through of course and we need to be sure that the sources of effects use the same system in recording the effect as the rest of the ACR uses to manage it.
I'm glad you've spent time thinking on this as I'd really like to be able to fully implement ability damage recovery as well as condition restoration on login (true persistence finally!). I've put this on the shelf until we're ready to cross that bridge (and maybe we'll have more functions at our disposal courtesy of Obsidian). I'll look through what you've got when you're done or if you want to open a discussion about the what and how of it all. It'd be an interesting discussion for certain.
I'm glad you've spent time thinking on this as I'd really like to be able to fully implement ability damage recovery as well as condition restoration on login (true persistence finally!). I've put this on the shelf until we're ready to cross that bridge (and maybe we'll have more functions at our disposal courtesy of Obsidian). I'll look through what you've got when you're done or if you want to open a discussion about the what and how of it all. It'd be an interesting discussion for certain.
Thats easy enough, the cursed item scripts would (hopefully) apply an effect from the cursed item itself, while the energy drain attack would be from the creature who cast the spell. Any ability drain due to fatigue could be placed from a storage object which does all the fatigue-related effects in the ACR. All could be told apart easily.ç i p h é r wrote:Yes, effects are indeed a problem not only in terms of identifying the source of the effect (and thus knowing if it's the effect you want to alter) but also in identifying the exact modifiers the effect has applied to the PC. Eg: A PC is ability drained with a negative energy attack but also equips a cursed item, both of which happen to apply a permanent negative modifier on the same attributes. When resting, the negative modifiers from the ability drain attack should heal but not from the curse.
As far as tracking ability drain, couldn't we have a specific storage object for that? Then on each rest, all the effects placed by that object could be stripped, variables which track their strength adjusted to the new values, and the effects re-applied?
- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
One other thing I totally forgot to mention is I think we can do away with the bedroll. I don't really see what it adds to the game, and sometimes if a PC looses one it can be a PITA to replace it since no one bothers to put them on merchants (need a DM, usually). Plus they add weight to a PC's inventory, often for little reason if the PC sleeps in inns or such (and is a wild elf druid really going to use a bedroll?).
- ç i p h é r
- Retired
- Posts: 2904
- Joined: Fri Oct 21, 2005 4:12 pm
- Location: US Central (GMT - 6)
Rangers, Barbarians, and Druids don't require them actually, nor is it required indoors, but yeah. I don't think it really adds much. The only thing is that this is tied to frequency of rest. So if we remove bedrolls, then do we have a single rest cycle outdoors? once every 8 hours? 24 hours? Unlimited but with chance of random encounters?
(on the plus side, it gets rid of an inventory check for a bedroll though we can optimize this if need be)
(on the plus side, it gets rid of an inventory check for a bedroll though we can optimize this if need be)
"We" used to have a system where it made sense. Basically, you could sleep on the bare ground, on a bed roll or even in a tent. That scale offered different healing factors. Bare ground didn't heal anything, or very little. And a tent gave the best healing. Of course nothing over exagerated for points healed.