Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!


New Premium Module: Tyrants of the Moonsea! Read More
Attention, new and old users! Please read the new rules of conduct for the forums, and we hope you enjoy your stay!

Set/Get PC location to an item in their inventory

I have an item that through a conversation a PC can use to Set Location
Then through a second choice in the conversation Jump to that location.

currently it stores the location on the PC. I need to know how to set it on the object itself, I am hoping that will make it stick over server resets? I am having trouble figuring this out, please help.


  • NeverwinterWightsNeverwinterWights Member Posts: 229
    edited May 2018
    You'll want to use the GetItemPossessedBy function:
    object oItem = GetItemPossessedBy(oPC, "Tag of item here"); SetLocalLocation(oItem, "blah blah", lLocation);
    And as long as the character is saved at some point after this then the location will stick to the item.

  • QuilistanQuilistan Member Posts: 70
    awesome! just what I needed to figure it out!

    resting after setting the location saves it persistent. Which is perfect for what I need.

    thank you

  • SherincallSherincall Member Posts: 375
    Careful though! Storing the location like that (i.e. SetLocalLocation) can be problematic. A Location is basically just a compound {object oArea, vector vPosition, float fFacing} variable. The oArea is the Object ID of the area. Object IDs are different across server restarts - which is why SetLocalObject() is generally useless for persistence. However, the initial area initialization in the module is deterministic, meaning areas will always get the same object ID, so this will work.

    ...until you add/remove some areas to your module. Then the area IDs will be shifted, and your location will be broken. And it will be broken in such a way that it would refer to a different area.

    It'd be much safer to store the location as separate variables, such as {string sAreaTag, vector vPosition}, then find the area object with GetObjectByTag(). If you have multiple areas with the same tag, then use area resref instead/aswell.

  • NeverwinterWightsNeverwinterWights Member Posts: 229
    edited May 2018
    As per @Sherincall advice I do use a more robust version. If you want a more worry free version in case of removing/adding areas to your module you'd want to use something more like:

    //////////////////////////////////////////////////////////////////////////////// void SavePersistentLocation(object oPC) { object oDBItem = GetItemPossessedBy(oPC, "PLAYER_HANDBOOK"); if (!GetIsObjectValid(oDBItem)) { CreateItemOnObject("playerhandbook", oPC); } SetLocalLocation(oDBItem, "PERSISTENT_LOC", GetLocation(oPC)); SetLocalString(oDBItem, "PERSISTENT_AREA", GetTag(GetArea(oPC))); } //////////////////////////////////////////////////////////////////////////////// void ReturnToPersistentLocation(object oPC) { object oDBItem = GetItemPossessedBy(oPC, "PLAYER_HANDBOOK"); if (GetIsObjectValid(oDBItem)) { string sArea = GetLocalString(oDBItem, "PERSISTENT_AREA"); location lStoredLoc = GetLocalLocation(oDBItem, "PERSISTENT_LOC"); if (sArea != "") { object oArea = GetAreaFromLocation(lStoredLoc); if (oArea != OBJECT_INVALID) AssignCommand(oPC, ActionJumpToLocation(lStoredLoc)); else SendMessageToPC(oPC, "The area you are trying to teleport to is not valid."); } else { SendMessageToPC(oPC, "You do not have a saved location."); } } else { SendMessageToPC(oPC, "You do not have a valid database item."); } } ////////////////////////////////////////////////////////////////////////////////

    Also since we now have the GetSurfaceMaterial function to check the surface at a location which returns 0 if the location is invalid or has no surface, I'm playing around with the idea of changing how to check for valid locations with persistent locations.

    Post edited by NeverwinterWights on
  • MermutMermut Member Posts: 38
    If you're concerned about saving locations and temporary areas, you could save the location of the transition into the temporary zones in the transition script as a fall back location and remove that location in the temporary area's on exit script.

  • meaglynmeaglyn Member Posts: 55
    You should use a position not a vector otherwise you lose the facing, or use a vector and a facing if you want. A vector plus an area is not a complete location as defined in NWN.
    Also the code above isn't really using the saved area tag. You could use that tag to find the right area and do the jump still. What's there won't handle the case Sherincall mentioned of changed area IDs. It only handles removed areas.

  • NeverwinterWightsNeverwinterWights Member Posts: 229
    edited May 2018
    The code above is just using the tag to confirm that that a location has even been saved. Could have used resref, some other variable, or whatever. I just used tag. GetAreaFromLocation is checking for the object. But yeah it won't account for id changes.

  • prwoprwo Member Posts: 65
    Just another idea: Use an (invisible) object (e.g. Waypoint) to track the location "physically".
    When you want to "save" the location: Check if your tracker object already exists -> if so, delete it. Create a new tracker object at the current location.
    When you want to jump to the "saved" location: Check if your tracker object exists -> if so, jump to it. If not (e.g. because the area has been removed), display a corresponding message.
    This way the system handles the Area and Location for you.

Sign In or Register to comment.