Author Topic: Need help with...  (Read 645 times)

Legacy_Foregone_Conclusion

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Need help with...
« on: January 19, 2012, 10:31:18 pm »


               Firstly
This script below. I wanted to convert it to an onactivated script through conversation to an npc, versus using an object. What needs to change in order for it to target the player over it firing on the npc speaker? 

Secondly,
 I need a script that will lock a transition until it is used from the other side. Additionally, have that script remove a placeable object from being in front of the intended transition.

And thirdly: 
A script that attatches to an item as a useitem unique.. that when used on a target placeable will remove it, and play a vfx or two.

void main()
{

object oPC = GetLastUsedBy();
object oSelf = OBJECT_SELF;
object oItem = GetFirstItemInInventory(oPC);
effect eEffect = EffectVisualEffect(VFX_FNF_HOWL_WAR_CRY_FEMALE);
if (GetGold(oPC) >= 1000)
    {
    // If Player has 1k Gold
    while (GetIsObjectValid(oItem)==TRUE)
    {
      SetIdentified(oItem,TRUE);
      oItem = GetNextItemInInventory(oPC);
    }
    DelayCommand(1.0, AssignCommand(oPC, TakeGoldFromCreature(1000, oPC, TRUE)));
    DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC));
    }

if (GetGold(oPC) <= 1000)
    {
    // If Player does not have 1k gold
    AssignCommand(oSelf, SpeakString("You'll need more gold my friend!", TALKVOLUME_TALK));
    }
}
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #1 on: January 19, 2012, 10:46:24 pm »


               The script should work as long as you update how the PC is defined.
In this case, use:
object oPC = GetPCSpeaker();
instead of:
object oPC = GetLastUsedBy();

As for the other requests, they would take a bit more effort than I have time for right now.
The transition will probably work best by checking for a variable on the PC and only transporting them if that var exists.
Set the var on them when they use it from the first side.
The 3rd script would take a few more lines of code to handle the vfx.

Have you tried using one of the script generators to help you learn how to code?
http://nwvault.ign.c....Detail&id=1502

That may be able to handle most of the more basic scripts like this.
               
               

               


                     Modifié par wyldhunt1, 19 janvier 2012 - 10:48 .
                     
                  


            

Legacy_Foregone_Conclusion

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Need help with...
« Reply #2 on: January 19, 2012, 11:50:22 pm »


               Thanks for the fix. And yeah... I've never been good at scripting, trying to learn it myself. Having a simple yet detailed explanation of the in's and out's would help my understanding of it.
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #3 on: January 20, 2012, 12:14:29 am »


               There are a few good tutorials to help you figure it out.
The Vault has a series here: http://nwvault.ign.c...ripting/course/
Or, this thread has a big list of useful stuff: http://social.biowar...-3254065-1.html


Once you understand the very basics of what a variable is and the basic structure of the code, a script generator may be the next best step. Its examples will answer a lot of your questions about how to do stuff.

It's a lot easier than people usually assume once they understand the language structure.
Variables are references that you can call repeatedly in a script without having to worry about typos or making the engine re-check the same thing over and over.

int nSomeNumber = 10;

int tells the engine that you are defining a new variable, and that variable is an integer (A whole number).
nSomeNumber  is the name that you've given the variable. You can use any name you want. Just don't use the same name twice in the same function.
= 10 is the value that you are using for nSomeNumber. In this case, 10.
; is used like a period in code. You place a ; at the end of every statement to let the engine know where the end of the statement is at.

So, a translation of the above line would be:
I am declaring a new integer variable named nSomeNumber and it is equal to 10.

Once a variable is defined, you can use the name that you chose anywhere in the function and the engine will know to replace your variable name with the variables value.

So, I could say:

if (nSomeNumber > 0)
{
   string sSomeText = "Some Number is positive."; 
}


The line if (nSomeNumber > 0) is checking to see if the variable nSomeNumber is greater than (>) the number 0.
That line reads out almost like English. "If the variable nSomeNumber is greater than zero"
You'll notice that the code under it is wrapped in curly brackets. IE { and }.
These are used to separate a block of code from the rest of the code.
The "if" statement ran a check to see if something was true. The code in the curly brackets under it will only run if that check returns true. If it returns false, everything inside of the { } will be ignored.

Thus, our final sentence for that block of code would look something like:
If the variable named nSomeNumber is greater than 0, then declare a new string variable named sSomeText which is equal to the value "Some Number is positive".

A couple of things to note about the line
string sSomeText = "Some Number is positive."; 
Any actual text that you want to use as a text string in game will need parenthesis around it (").
Note the ; at the end of the line.

You can also store variables on objects to use later in some other script.
You could do something like:

object oPC = GetEnteringObject();
SetLocalInt(oPC, "TriggerCheck", 1);


on an On Enter of a trigger.
That would store an int variable on the oPC object. The variables name is TriggerCheck. The value is equal to 1.

Now, in an entirely different script, you could use:

object oPC = GetEnteringObject();
if (GetLocalInt(oPC, "TriggerCheck") == 1)
{
  //Add code here to transport the player
}


Note that oPC is actually a variable (of the "object" type) that we defined on the first line.
oPC is equal to whatever is returned by the GetEnteringObject() check.
By using oPC as an object variable, we only have to check to see who is entering the trigger once. After that, oPC will always call that same object.

The code block above will read much like in English:
If we can get an integer variable off of the oPC object named TriggerCheck with a value equal to 1, then run code to transport the player.
               
               

               


                     Modifié par wyldhunt1, 20 janvier 2012 - 12:50 .
                     
                  


            

Legacy_ehye_khandee

  • Hero Member
  • *****
  • Posts: 1415
  • Karma: +0/-0
Need help with...
« Reply #4 on: January 20, 2012, 12:17:04 am »


               google the nwn lexicon

It can be a big help.

Be well. Game on!
GM_ODA
http://playnwn.com
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #5 on: January 20, 2012, 01:03:24 am »


               The Lex is at the top of the list in the second link I gave above.
It is the most complete reference for finding or understanding how any of the bits of code work.

It is large enough that you may need a more basic tutorial to help you understand what you're looking at before the Lex will make a lot of sense, if you don't understand the basics of programming structure in Aurorascript yet.
It's well worth browsing though. I still keep it open while I code as a quick reference.
               
               

               
            

Legacy_Foregone_Conclusion

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Need help with...
« Reply #6 on: January 20, 2012, 01:45:56 am »


               Okay so using the script generator, with some understanding  I generated the onuse item effect to destroy a placeable.

But it came out like this :

void OnActivate(object oEventItem, object oActTarget, location lActTarget, object oActivator)
{
   object oTarget;
   effect eVFX;
   int nType;
   object oPC = oActivator;

   // The target must be a certain type of object.
   nType = GetObjectType(oActTarget);
   if ( nType != OBJECT_TYPE_PLACEABLE )
   {
       SendMessageToPC(oActivator, "Improper use of this item!");
       return;
   }

   // Destroy an object (not fully effective until this script ends).

   eVFX = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION);
   oTarget = GetObjectByTag("Hellfiretombcover");
   ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oTarget);
   DestroyObject(oTarget, 3.0);
}

The very first line is obviously incorrect. It should be Void main() right? So what do I do with the extra stuff on top? Moving it down a line gets it recognized as an unknow value when trying to compile it.  Same for putting it under the squiggly bracket.  Removing it gives me an "missing Int value"
               
               

               


                     Modifié par Foregone_Conclusion, 20 janvier 2012 - 01:58 .
                     
                  


            

Legacy_Foregone_Conclusion

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Need help with...
« Reply #7 on: January 20, 2012, 02:05:11 am »


               Nevermind that. I redid the script with the "old" system and it came out looking right. However when I use it, the VFX doesn't actually show up. I hear it, but no actual effect shows up. Ideas? this is the corrected version :

/*
 *  Script generated by LS Script Generator, v.TK.0
 *
 *  For download info, please visit:
 *  http://nwvault.ign.c....Detail&id=1502
 */


void main()
{
    object oTarget;
    effect eVFX;
    int nType;
    object oEventItem = GetItemActivated();
    object oActTarget = GetItemActivatedTarget();
    location lActTarget = GetItemActivatedTargetLocation();
    object oActivator = GetItemActivator();

    object oPC = oActivator;

    // The target must be a certain type of object.
    nType = GetObjectType(oActTarget);
    if ( nType != OBJECT_TYPE_PLACEABLE )
    {
        SendMessageToPC(oActivator, "Improper use of this item!");
        return;
    }

    // Destroy an object (not fully effective until this script ends).

    eVFX = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION);
    oTarget = GetObjectByTag("hellfiretombcover");
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oTarget);
    DestroyObject(oTarget, 3.0);
}

Other than that, it works perfectly!
               
               

               


                     Modifié par Foregone_Conclusion, 20 janvier 2012 - 02:32 .
                     
                  


            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #8 on: January 20, 2012, 02:32:37 am »


               Interesting. I haven't tried the new script generator yet.

That is valid code.
However, it won't do anything by itself.
As you guessed, you need a void main().

That code is a custom function.
If you read any of the tutorials, they'll get in to that and explain it better than I could do here.

void OnActivate(object oEventItem, object oActTarget, location lActTarget, object oActivator)

void is a key word that tells the engine that you are defining a new function.
OnActivate is the name of the new function (It can be any unique name, much like the name of a variable.).
The stuff inside of the brackets ( and ) is a list of information that the function requires in order to work properly.
In this case, you need to give the function the following list of stuff:
An object that the function can use for the oEventItem variable. (Probably the item used)
An object that the function can use for the oActTarget variable. (Probably the target of the item used)
A location that can be used for the lActTarget variable. (Probably the target location of the item used)
An object to be used for the oActivator variable. (Probably the object that used the item)

Once a function has been defined, you can use the function in your script by calling the function name and feeding it all of the info that it needs.

A finished script using this function might look like:

void OnActivate(object oEventItem, object oActTarget, location lActTarget, object oActivator)
{
object oTarget;
effect eVFX;
int nType;
object oPC = oActivator;

// The target must be a certain type of object.
nType = GetObjectType(oActTarget);
if ( nType != OBJECT_TYPE_PLACEABLE )
{
SendMessageToPC(oActivator, "Improper use of this item!");
return;
}

// Destroy an object (not fully effective until this script ends).

eVFX = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION);
oTarget = GetObjectByTag("Hellfiretombcover");
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oTarget);
DestroyObject(oTarget, 3.0);
}
void main()
{
  OnActivate(GetItemActivated(), GetItemActivatedTarget(), GetItemActivatedTargetLocation(), GetItemActivator());
}


Notice the void main() at the bottom that calls the function and gives the function all of the info that it needs.

Generating custom functions seems like it may be a bit much for novice scripters to handle. I'm not sure why it would be giving you custom functions without the void main() to call the function to make sure that it works for you.

Glad to see you got it figured out though.
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #9 on: January 20, 2012, 02:35:17 am »


               My guess is that you are destroying the object immediately, before the vfx can manifest.

Try adding a delay to when it gets destroyed, like so:

/*
* Script generated by LS Script Generator, v.TK.0
*
* For download info, please visit:
* http://nwvault.ign.c....Detail&id=1502
*/


void main()
{
object oTarget;
effect eVFX;
int nType;
object oEventItem = GetItemActivated();
object oActTarget = GetItemActivatedTarget();
location lActTarget = GetItemActivatedTargetLocation();
object oActivator = GetItemActivator();

object oPC = oActivator;

// The target must be a certain type of object.
nType = GetObjectType(oActTarget);
if ( nType != OBJECT_TYPE_PLACEABLE )
{
SendMessageToPC(oActivator, "Improper use of this item!");
return;
}

// Destroy an object (not fully effective until this script ends).

eVFX = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION);
oTarget = GetObjectByTag("hellfiretombcover");
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVFX, GetLocation(oTarget));
DestroyObject(oTarget, 3.0);
}

Actually, no... It is delayed. Didn't notice that... I'll update if I see anything else obvious.

EDIT: Updated to trigger the effect at the objects location instead of on the object itself.
               
               

               


                     Modifié par wyldhunt1, 20 janvier 2012 - 03:05 .
                     
                  


            

Legacy_Foregone_Conclusion

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Need help with...
« Reply #10 on: January 20, 2012, 02:54:21 am »


               Okay I changed the ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oTarget);  to

ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oPC); Since the target is being destroyed it doesn't execute the vfx I guess.
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #11 on: January 20, 2012, 03:04:15 am »


               I'm updating my last post to trigger the effect at the location of the object instead of on the object itself.
Since the location of the object should stay the same even if the object is destroyed, I think it'll work as you wanted.

I'm at work right now, so I can't try to compile it or anything.
If I made a typo, let me know.
The only line I need to change is:
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oTarget);

I'll put a note to let you know when it's updated.

EDIT: Done
               
               

               


                     Modifié par wyldhunt1, 20 janvier 2012 - 03:05 .
                     
                  


            

Legacy_Foregone_Conclusion

  • Newbie
  • *
  • Posts: 40
  • Karma: +0/-0
Need help with...
« Reply #12 on: January 20, 2012, 10:14:47 am »


               Edit: Nevermind, Works like a charm. However... more newby questions!

But a quick question, I have a number of Onequip scripts now for items. One problem I'm running into is that they are firing when picked up,OnAcquire instead of OnEquip. The script fires when equipped still however. Also, the effects of the script don't remove after the item is dropped from inventory, and the effects even stack up multiple times. Which is obviously a problem.

This script here, being an example of one :

void main()
{
   effect eEffect;
   effect eVFX;
   object oEventItem = GetPCItemLastEquipped();
   object oEquippedBy = GetPCItemLastEquippedBy();

   object oPC = oEquippedBy;

   // Apply some visual effects.
   eVFX = ExtraordinaryEffect(EffectVisualEffect(VFX_IMP_AURA_HOLY));
   ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVFX, oPC);
   eVFX = EffectVisualEffect(VFX_FNF_DISPEL_DISJUNCTION);
   ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oPC);

   // Apply some effects.
   eEffect = ExtraordinaryEffect(EffectRegenerate(10, 15.0));
   ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oPC, 3600.0);
   eEffect = ExtraordinaryEffect(EffectTemporaryHitpoints(65));
   ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oPC, 3600.0);

}

So I assume I need to either add another script that effects onacquire and onequip?  Or is this script itself just missing the IF functions?
               
               

               


                     Modifié par Foregone_Conclusion, 20 janvier 2012 - 10:59 .
                     
                  


            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Need help with...
« Reply #13 on: January 20, 2012, 03:45:59 pm »


               What you need to do is include the switches library so you can run the routines only on the correct events.  The full script you'd be looking to use, based on the one you posted, would be something like this:

#include "x2_inc_switches"
void Buff (object oPC);
void Unbuff (object oPC);
void main()
{
 object oPC, oItem;
 int nEvent = GetUserDefinedItemEventNumber();
 if (nEvent == X2_ITEM_EVENT_EQUIP)
    {
     oPC   = GetPCItemLastEquippedBy();
     oItem = GetPCItemLastEquipped();
     // This is assigned to the item so you can remove the effects on unequip.
     AssignCommand (oItem, Buff (oPC));
    }
 else if (nEvent == X2_ITEM_EVENT_UNEQUIP)
    {
     oPC   = GetPCItemLastUnequippedBy();
     oItem = GetPCItemLastUnequipped();
     // Assigned so the item is OBJECT_SELF, for easier creator checking.
     AssignCommand (oItem, Unbuff (oPC));
    }
 else if (nEvent == X2_ITEM_EVENT_ACQUIRE)
    {
     oPC   = GetModuleItemAcquiredBy();
     oItem = GetModuleItemAcquired();
     object oOldOwner  = GetModuleItemAcquiredFrom();
    }
 else if (nEvent == X2_ITEM_EVENT_UNACQUIRE)
    {
     oPC   = GetModuleItemLostBy();
     oItem = GetModuleItemLost();
     object oNewOwner = GetItemPossessor (oItem);
    }
 else if (nEvent == X2_ITEM_EVENT_ACTIVATE)
    {
     oPC   = GetItemActivator();
     oItem = GetItemActivated();
     object   oTarget = GetItemActivatedTarget();
     location lTarget = (GetIsObjectValid( oTarget) ? GetLocation( oTarget) : GetItemActivatedTargetLocation());
    }
}
void Buff (object oPC)
{
 effect eEffect1, eEffect2, eVFX, eDur, eLink;
 eVFX = EffectVisualEffect(VFX_FNF_DISPEL_DISJUNCTION);
 eDur     = EffectVisualEffect(VFX_IMP_AURA_HOLY);
 eEffect1 = ExtraordinaryEffect(EffectRegenerate (10, 15.0));
 eEffect2 = ExtraordinaryEffect(EffectTemporaryHitpoints(65));
 eLink    = EffectLinkEffects (eEffect1, eEffect2);
 eLink    = EffectLinkEffects (eLink, eDur);
 ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 3600.0);
 ApplyEffectToObject(DURATION_TYPE_INSTANT,   eVFX, oPC);
 SetLocalInt (OBJECT_SELF, "BUFFED", TRUE);
}
void Unbuff (object oPC)
{
 effect eEffect = GetFirstEffect (oPC);
 while (GetIsEffectValid (eEffect))
    {
     if (GetEffectCreator (eEffect) == OBJECT_SELF)
        {
         RemoveEffect (oPC, eEffect);
        }
     eEffect = GetNextEffect (oPC);
    }
 SetLocalInt (OBJECT_SELF, "BUFFED", FALSE);
}



  You need to create the effects in an assigned subroutine so you can make the item the effect creator.  That allows you to check against that item when it's unequipped to remove only the effects it made.
  I used a variable check for simplicities sake, but a loop through the effects present on the PC to see if any of them have been created by that item would be slightly more reliable.

  Hopefully this quick tag framework will be of use to you for your other scripts.  If they're the same sort, buff on equip/remove effects on unequip, you'd just need to change the effects in the Buff script.
               
               

               
            

Legacy_wyldhunt1

  • Sr. Member
  • ****
  • Posts: 443
  • Karma: +0/-0
Need help with...
« Reply #14 on: January 20, 2012, 09:22:37 pm »


               There are a couple of ways to set up tag based scripts, which is what you’re dealing with.
There are a few tutorials on tag based scripting in one of my links in an earlier post, which I advise you to read because tag based scripting is important to understand.

The basic idea is that your module event scripts which deal with items will have a small block of code that executes a script with a name equal to the item’s tag.
So, if an item has a tag of “MyItem”, then a script named “myitem” will fire every time ‘any’ event happens concerning that item.
In the item’s script, you need to control which part of the script fires for each event.
If you look at the example that Failed.Bard posted, you’ll see that it is divided up in to sections.
Each section begins with an int variable which represents the number of the event that just triggered.
Under that, there is a block of code wrapped in curly braces { }.
The code in the curly braces will only run if the event that triggered is equal to the event named above the curly braces.
Each of these events already has some default variables defined so that you know how to define things such as the item or the character using the item.

By using this template, you can have an item that does something different for each event.
In this case, Failed.Bard added code to the X2_ITEM_EVENT_EQUIP block of code and the X2_ITEM_EVENT_UNEQUIP block of code.
The other blocks of code are still empty. All they do is define a few variables and then never do anything with them.

If you need help deciphering any of it, let me know.
               
               

               


                     Modifié par wyldhunt1, 20 janvier 2012 - 09:32 .