1. SPS Accounts:
    Do you find yourself coming back time after time? Do you appreciate the ongoing hard work to keep this community focused and successful in its mission? Please consider supporting us by upgrading to an SPS Account. Besides the warm and fuzzy feeling that comes from supporting a good cause, you'll also get a significant number of ever-expanding perks and benefits on the site and the forums. Click here to find out more.
    Dismiss Notice
Dismiss Notice
You are currently viewing Boards o' Magick as a guest, but you can register an account here. Registration is fast, easy and free. Once registered you will have access to search the forums, create and respond to threads, PM other members, upload screenshots and access many other features unavailable to guests.

BoM cultivates a friendly and welcoming atmosphere. We have been aiming for quality over quantity with our forums from their inception, and believe that this distinction is truly tangible and valued by our members. We'd love to have you join us today!

(If you have any problems with the registration process or your account login, please contact us. If you've forgotten your username or password, click here.)

Neverwinter Nights Forum Update

Discussion in 'Game/SP News & Comments' started by NewsPro, Jul 5, 2002.

  1. NewsPro Gems: 30/31
    Latest gem: King's Tears


    Joined:
    May 19, 2015
    Messages:
    3,599
    Likes Received:
    0
    (Originally posted by Z-Layrex)

    Noel Borstad, Programmer

    String Matching: We decided that regular expressions were too complex and too powerful for what we needed, so we made up our own little syntax for string matching based on wildcards:

    ** will match zero or more characters
    *w one or more whitespace
    *n one or more numeric
    *p one or more punctuation
    *a one or more alphabetic
    | is or
    ( and ) can be used for blocks

    - setting a creature to listen for "**" will match any string
    - telling him to listen for "**funk**" will match any string that contains the word "funk".
    - "**(bash|open|unlock)**(chest|door)" will match strings like "open the door please" or "he just bashed that chest!"

    Go wild!


    Brenon Holmes, Programmer


    EffectHitPointChangeWhenDying():EffectHitPointChangeWhenDying() currently (in the current build) only works with negative values when applied initially as a temporary duration effect... after the next build it should work no matter how you apply it.

    David Gaider, Designer


    Placeables: If you want a placeable object to be clickable, make sure that on its first tab the 'Useable' box is checked. Then put your script into its OnUsed script (with the PC identified as GetLastUsedBy).

    Dead Bodies: Ok, the way to script the corpse to remain after it is dead is to add the following line into its OnSpawn script:

    SetIsDestroyable(FALSE);

    If you don't want the body to be raiseable/resurrectable:

    SetIsDestroyable(FALSE, FALSE);

    If the creature has the standard OnSpawn script, just remember to copy it and save it under a different name, first. If you want the dead body to fade away after a certain time, do the following:

    1. In the OnSpawn script, uncomment this line: 'SetSpawnInCondition (NW_FLAG_DEATH_EVENT);' and re-save the script (under a different name if it is the generic one).

    2. Create a script in the OnUserDefined that says this:

    void main()
    {
    nEvent = GetUserDefinedEventNumber();
    if (nEvent == 1007) // Death event
    {
    DelayCommand(300.0, SetIsDestroyable(TRUE));
    }
    }

    The above script sets the timer before body decay to 5 real-time minutes. Change the number of seconds in the DelayCommand to whatever you wish. NOTE: Dead creature bodies that do not decay are NOT containers. They cannot be selected and their inventory taken... you cannot have it both ways. Dead bodies also do not run scripts. The only way I can think of doing both is to have the creature add into its OnDeath script (changing the above script in OnUserDefined, effectively) that everything it is supposed to drop gets put into a container (like a body bag) and spawned next to it on the ground. Other people might certainly have better ideas about this than I, of course.


    Player Factions: A party of players are one faction. If a player is not a member of his party, then he is his own faction. The GetFirst/NextFactionMember command requires you to input a member of that faction as the object... if the object is a PC, it will only cycle through members of his faction. One note about that command, however: if the 'bPCOnly' at the end is set to TRUE, then ONLY player characters (not associates such as henchmen or familiars and such) are returned. If set to FALSE, then ONLY non-player characters are returned. If you want to cycle through a party and identify both the players as well as their existing associates, you'd have to run the command twice.

    Sitting NPCs: Two choices:

    1) Make a script that has the NPC sit back down. Go into his dialogue file and add the script to the Aborted and Ended section in 'Other Files'. This will make him sit again when the dialogue is done.

    2) Go into the 'Working Scripts' sticky thread up top. I believe there is a script in there (in the later pages... page 10?) where someone got it to work so NPC's remain seated while speaking. I have not tried it, personally, so I can't claim it's veracity.


    Light Sources: Whenever you change light sources, you have to include in the script the command RecomputeStaticLighting. There's an example of this in the 'Commonly Asked Questions' sticky up top.

    Actions:

    Quote: Ahh, I understand. However, I don't understand how AssignCommand works. Specifically what gets sent as an action?

    AssignCommand(object oActionSubject, action aAction to assign);

    What are actions I can perform. I don't see anything in toolset of type action. I am confused.

    I suppose 'actions' are just commands. I remember Brenon saying once that AssignCommand could send any void-returning command. Why it doesn't say void instead of action, then? I have no idea.

    More:
    Hmmm. Have you tried adding ActionPlayAnimation (NIMATION_PLACEABLE_DEACTIVATE) to your script instead of setting the default state in the toolset? Try it so that your object shuts itself off when the module begins... and then turns itself back on later.

    And More:

    Quote: Running this script ONENTER for Area or Module actually crashes the module:

    void main()
    {
    ActionPlayAnimation (ANIMATION_PLACEABLE_DEACTIVATE);
    }

    Well, sure... you are telling the module or area, itself, to play an animation. Modules and areas don't do that. You would have to use AssignCommand to actually send this command to a specific object.

    And Even More:

    Quote: I haven't tried scripting the animation changes yet -- but why wouldn't the 'state' stuff work?

    It's possible that this may not be a bug at all. Not all placeables are animated or have 'activated' and 'deactivated' states, just as they don't all have open and closed states. The animation for the magic sparks may simply exist or not. It's possible that, in this case, you may have to spawn in the placeable object and use DestroyObject if you want an on/off effect.


    One Liners: Go into the creature's OnSpawn script and uncomment the line 'SetSpawnInCondition (NW_FLAG_SPECIAL_ COMBAT_CONVERSATION);'. Then save the script under a different name and recompile. Now put the one-liner you want the creature to say at the top of its dialogue. In its 'Text Appears When' script area, place the script "nw_d2_gen_combat". On perceiving a PC, the creature will display its one liner and then attack.

    Conversations: The thing to remember is that when you line up your 'starting nodes' underneath the Root, they should be in reverse order of completion. Let's say your NPC gave three jobs. Imagine the following structure under the root:

    #1. "I don't have any more jobs for you."
    #2. "Are you finished job #3?"
    #3. "Are you finished job #2?"
    #4. "Are you finished job #1?"
    #5. "Would you like a job?"
    #6. "Hello!"

    The thing to remember is that when the NPC is clicked on for dialogue, the computer will begin scanning the scripts in the 'Text Appears When' part of these nodes. If the script returns TRUE (or there is no script), that node is initiated. If it returns FALSE, it continues onto the next node. The following is a rundown of what scripts would be at each node:

    #1 - script in 'Text Appears When' set to return TRUE if "Job" variable on PC set to 4 like so:

    int StartingConditional()
    {
    int nJob = GetLocalInt(GetPCSpeaker(), "Job") == 4;
    return nJob;
    }

    #2 - script in 'Text Appears When' set to return TRUE if "Job" variable on PC set to 3 (set below). If the PC has finished the job, have NPC give reward and set "Job" variable to 4 (no more jobs) in 'Actions Taken' like so:

    void main()
    {
    SetLocalInt(GetPCSpeaker(), "Job", 4);
    }

    #3 - script in 'Text Appears When' set to return TRUE if "Job" variable on PC set to 2 (set below). If the PC has finished the job, have NPC give reward and job #3... set "Job" variable to 3 in 'Actions Taken'.

    #4 - script in 'Text Appears When' set to return TRUE if "Job" variable on PC set to 1 (set below). If the PC has finished the job, have NPC give reward and job #2... set "Job" variable to 2 in 'Actions Taken'.

    #5 - Script in 'Text Appears When' returns TRUE if "TalkedToJoe" variable on the PC set to 1 (set below). In the dialogue, if the PC accepts job#1, set the "Job" variable on the PC to 1 in 'Actions Taken'.

    #6 - no script in 'Text Appears When' (if all other scripts above are FALSE, this is the first time the PC has spoken to this NPC). On the first line, put a script in 'Actions Taken' that sets a "TalkedToJoe" variable on the PC to 1 in 'Actions Taken'.


    Journals: Ok, this is assuming you want all players enter to get the same journal entry and when the creature is slain, all players have their journal entry changed, correct? Ok, then... when you set up the journal entry you'll name the category (this is the title that appears in the journal) and give it a tag (let's make the tag "Creature1". Click on the category and press Add... this allows you to add the first entry that gets sent to everyone. Write up the text and give it an ID number (let's say 10). Then add another entry to the same category... give it the text for when the beast dies. Give it a number higher than the first (let's say 20). If the plot is finished at this point, click on 'Finish Category'. To give the journal entry to all who enter (but none if this particular beast is dead), put the following script in the OnClientEnter event of the module:

    void main()
    {
    object oPC = GetEnteringObject();
    int nDead = GetLocalInt(GetModule(), "Monster_Dead");
    if (nDead == FALSE)
    {
    AddJournalQuestEntry("Creature1", 10, oPC);
    }
    }

    Go to the creature that needs to be killed, now. Go into its OnSpawn script and uncomment (remove the beginning '//' double slashes) the line that says 'SetSpawnInCondition (NW_FLAG_DEATH_EVENT);'. Re-save the OnSpawn script under a new name and compile it. Create a new script, now, and put it in its OnUserDefined event that does this:

    void main()
    {
    nEvent = GetUserDefinedEventNumber();
    if (nEvent == 1007) // OnDeath event
    {
    SetLocalInt(GetModule(), "Monster_Dead", TRUE)
    AddJournalQuestEntry("Creature1", 20, oPC, TRUE, TRUE);
    }
    }

    The above script should make it so that new players no longer get the quest and all players currently in the game have their quest updated to show the creature being dead.


    Custom Tokens: You want to use SetCustomToken. For instance, if I use the command in script:

    SetCustomToken(100, GetName(oPC));

    In actual dialogue I could write

    "Let's talk about , shall we?"

    As for integers and other data, you just need to convert it into a string, first, for use in the SetCustomToken command. Try IntToString.

    More:
    Just don't use the numbers 1 through 9 for your custom tokens. Those are reserved and will give you funny results.


    Polymorph: I suppose you could polymorph someone into a pixie, yes, since it's one of the polymorph options available. Try making the effect an extraordinary effect, since I think it's the magical effects that are lost when you rest. You can do that like so:

    effect ePixie = ExtraordinaryEffect (EffectPolymorph (POLYMORPH_TYPE_PIXIE));
    ApplyEffectToObject (DURATION_TYPE_PERMANENT, ePixie, oPC);

    In the OnClientEnter, you'd want to replace the oPC with GetEnteringObject(). If resting or dying turns the player back into what they were, I think your only option might be to apply the effect again by editing the OnPlayerRest and OnPlayerDeath scripts.


    Variables: No, there's no performance implications based on where you store a variable. It would take a LOT of variables stored somewhere to cause a problem. Use them wherever it is most convenient for you.

    Brenon Holmes Adds:

    Quote: Another issue is that if you store flags and infos on PCs remember that when the PCs leave the information in them might not have been saved. This is both a good thing and a bad thing. Good thing is that your world if properly coded will reset. Bad thing is if not properly coded will have lots of problems. I am writing a module based on a book, and I have my handsful trying to handle breaks in plot if the PC were to get booted from the server

    If the same player rejoins with the same player name they will get all the local variables set on that PC. Even if a PC is booted from a server they still leave a data structure that contains all of the local variables stored on the PC when they leave. The only time they will not is if the server does not have the opportunity to save out a proper data structure for an exiting object... ie: the server crashes.
     
    Last edited by a moderator: Jan 4, 2018
Sorcerer's Place is a project run entirely by fans and for fans. Maintaining Sorcerer's Place and a stable environment for all our hosted sites requires a substantial amount of our time and funds on a regular basis, so please consider supporting us to keep the site up & running smoothly. Thank you!

Sorcerers.net is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to products on amazon.com, amazon.ca and amazon.co.uk. Amazon and the Amazon logo are trademarks of Amazon.com, Inc. or its affiliates.