Placeable Powerups that won't power you up again until you've rested

Hi, everyone. What I’m trying to do here is this. I’m trying to have a placeable, say a crystal ball on a pedestal, that will temporarily grant you say +20 to your lore skill when you touch it, but will not do that again until you’ve rested (or else you’re going to be able to raise your lore to ridiculously high levels by touching it again and again). After you’ve rested and your lore skill has gone back to what it originally was, then when you touch the thing again you’ll be granted +20 again – and again this won’t happen a second time until you’ve rested. Does anyone know how all this can be set up?

Here’s how I tried to do it. I set up a placeable with a suitable conversation for it. (You know, something like:

You see a crystal ball.
—> 1. Touch it.
* (Nothing happened.)
* (+20 lore [temp].)
—> 2. Leave.)

I’d then go to Module Properties —> Advanced —> Variables and there I’d declare a variable, ‘touchedball’. Back to the conversation file, at the node that goes ‘+20 lore’ I’d place a suitable script under the ‘Actions Taken’ tab. In the script there would be a line that goes:

SetLocalInt(GetModule(), “touchedball”, 1);

Then at the ‘nothing happened’ node I’d place a suitable conditional script under the ‘Text Appears When’ tab to test if you’ve already touched the ball – thus setting ‘touchedball’ to 1 – whereupon the game would tell you nothing happened. The question now would be how to make ‘touchedball’ reset itself to 0 whenever you rest. (And here’s where the headache begins (sigh)…)

I figured all I had to do was go to Module Properties —> Events —> OnPlayerRest and modify the script there (‘x2_mod_def_rest’) by adding the line

SetLocalInt(GetModule(), “touchedball”, 0);

and then saving the script under some other name. Here’s the strange thing. All this worked beautifully in one module but not at all in another. Why? :worried:

I suspect the fact that I used CEP 2.65 in one of the two modules – the one in which it didn’t work out – would have had something to do with it, but I’ve absolutely no idea just how the CEP’s been affecting the thing. (Don’t know if the fact that I used the MBH henchman kit v23 might have got something to do with it all; I used the kit for both modules.) When I tried to save my altered version of ‘x2_mod_def_rest’ in the module that did the job, there were no compile errors. But there were in the module that didn’t do the job; the compiler kept showing another script, ‘x0_inc_HENAI’, and complaining of various errors which I simply had no idea how to rectify.

I tried changing the variable ‘touchedball’ to one that’s attached to the PC rather than the module. Accordingly I was careful to change ‘GetModule()’ to ‘GetPCSpeaker()’ in all the scripts used in the conversation file above, and also change the appropriate line in my altered version of ‘x2_mod_def_rest’ to

SetLocalInt(GetLastPCRested(), “touchedball”, 0);

It worked… not.

What gives? What can I do? Or is there some other strategy I can use to create the crystal ball powerup I described? Any help will be appreciated. Thanks!

(EDIT: Actually, how important is the script ‘x2_mod_def_rest’? Must anything I place in the ‘OnPlayerRest’ slot be only a modification of ‘x2_mod_def_rest’, or can I put a fresh script of my own in the ‘OnPlayerRest’ slot? From what I can tell, ‘x2_mod_def_rest’ only controls whether you can rest when you’re riding a horse and what sorts of encounters you might have when resting etc…)

hi, k.t.

yes, this kind of thing can be confusing. you’re actually almost there, you’ve got a good approach ; i think it’s just that last 10% that always takes 90% of the effort. there are actually many ways to do what you want, here’s one possible way.

  • suppose you have a variable called touchedball. in the placeable’s on-used script, check to see if the pc touching it has this variable set – i.e.,

      if (GetLocalInt(GetLastUsedBy(), "touchedball")) {
      	// ...do stuff here
      }
    

    – and if so, exit the script. if not, add the pc’s temporary bonus and set the variable on the pc – i.e.,

      	SetLocalInt(GetLastUsedBy(), "touchedball", 1);
    
  • in your on-rest script, simply clear the variable –

      	DeleteLocalInt(GetLastPCRested(), "touchedball");
    

.

that depends on who’s going to be using your module and how. is it a multi-player module, or single-player ? will there be horses ? if this is a single-player horseless module, you may be better off writing your own script from scratch. the same goes for any of the scripts – unless there’s a need for what’s already there in your module, you can replace the script w/something of your own making. having said that, it may be a good idea to study the script beforehand so you understand fully what functionality you’ll be losing if you replace the entire script.

1 Like

It’s important to understand that OnPlayerRest is called multiple times when you perform the “rest” action: when starting, when cancelled and when finished. You want to clear the variable (I store it on PC who used the placeable) when the rest is finished successfully. The Lore bonus will be removed automatically.

Here’s a complete solution:

Placeable’s OnUsed script:

void main()
{
    object oUser = GetLastUsedBy();

    if(GetLocalInt(oUser, "ball"))
    {
        SpeakString("You have to rest before you use this object again");
        return;
    }

    ApplyEffectToObject(DURATION_TYPE_PERMANENT,
        EffectSkillIncrease(SKILL_LORE, 20), oUser);

    SetLocalInt(oUser, "ball", TRUE);
}

OnPlayerRest script:

void main()
{
    object oPC = GetLastPCRested();

    switch(GetLastRestEventType())
    {
        case REST_EVENTTYPE_REST_STARTED:
        {
            FloatingTextStringOnCreature("Rest started", oPC);
            break;
        }
        case REST_EVENTTYPE_REST_CANCELLED:
        {
            FloatingTextStringOnCreature("Rest cancelled", oPC);
            break;
        }
        case REST_EVENTTYPE_REST_FINISHED:
        {
            FloatingTextStringOnCreature("Rest finished", oPC);
            DeleteLocalInt(oPC, "cball");
            break;
        }
    }

    // vanilla rest event handler compatibility
    ExecuteScript("x2_mod_def_rest", OBJECT_SELF);
}

EDIT BELOW THIS LINE

It is not important at all - it can be safely blanked. What you see in the default is related to horses (as you found yourself), which you can delete or replace with your own system.

2 Likes

Also, for the module that didn’t work, if you still have compilation errors, by all means post more detail…

…and of course check module properties to ensure it’s not calling some other script on rest.

1 Like

At least now I know I’m not restricted to modifying the script ‘x2_mod_def_rest’ and can instead place a fresh script of my own in the ‘OnPlayerRest’ slot, depending on what I want. (Yup, it’s meant to be a single-player module and horses, well, aren’t going to be that important in it.) Once I knew all this I put in my own script and now everything worked beautifully. :wink:

The downside, though, is that regarding horses – well, the paladin’s mount specifically – I notice any mount summoned by a paladin will stay around even after he’s rested (instead of being automatically unsummoned) if I don’t use ‘x2_mod_def_rest’ anymore. Part of ‘x2_mod_def_rest’ does tell the game to unsummon the mount, but when I snipped out that part of ‘x2_mod_def_rest’, placed it in my own script and compiled, I found that it didn’t work out well. I then found out (from the NWN Lexicon) that it was because I had to put in '#include “x3_inc_horse” for the said part to work. But the moment I brought this into my own script and compiled, all Hell broke loose: the dreaded ‘x0_inc_HENAI’ complaint appeared, the first error being:

X0_INC_HENAI.nss(220): ERROR: PARSING VARIABLE LIST

I know it’s not exactly a big deal if a paladin’s mount stays on even when he takes a rest (actually, can he unsummon his mount?), but still I’d have liked it more if the mount didn’t stay. Any idea how it could be done (or exactly what’s the problem with that *^$%^## ‘x0_inc_HENAI’ thing)?

Thanks for the help in any case, fellas. You rock, all of you.

Put this at the end of your custom OnPlayerRest script:

ExecuteScript("x2_mod_def_rest", OBJECT_SELF)

This way you can have both custom rest functionality and a vanilla functionality fallback.

Just make sure x2_mod_def_rest is not overridden by you (read: it does not appear on the script list inside the module.

1 Like

Hey, it worked!

Thanks ever so much, pal! :smile:

(Glad this $@!!** problem’s over and done with… Wonder how many more new headaches await me in working on my module…)

One less for sure. I assume it’s obvious now that no “horse stuff” is directly needed in your script, but for completeness (and improved educational value) I included that line in the script from my previous answer.

Have fun coding.

1 Like