Aller au contenu

Photo

Language Clerk Conversation


  • Veuillez vous connecter pour répondre
23 réponses à ce sujet

#1
Evelath

Evelath
  • Members
  • 56 messages
Hello Everyone,

I am working on a set of scripts that involve an NPC that gives out Languages, however there are certain parameters to getting those languages.  

Here is an example of the script that is called when a player chooses the "Drow" language to learn:

void main()
{

    object oPC = GetPCSpeaker();
    object oLang = GetItemPossessedBy(oPC, "lang_token");

    if (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_13"))==TRUE)
        {
            SendMessageToPC(oPC, "You have already learned this language.");
            return;
        }

    if (GetIsObjectValid(GetItemPossessedBy(oPC, "lang_token"))==FALSE)
        {
            SendMessageToPC(oPC, "You can not learn anymore languages right now.");
            return;
        }

    if (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_13"))==FALSE)
        {
            DestroyObject(oLang);
            CreateItemOnObject("hlslang_13", GetPCSpeaker(), 1);
        }

}


Now, what I need to do is set-up a function that checks several things:

1) It needs to group together 16 different items, with different tags.
2) It needs to check to see how many of those items the player has.
3) It needs to check the INT bonus that a character has.
4) If a player has enough INT (for example, 12 INT, giving an additional language), then he/she can select the appropriate conversation option to bring up the full list of languages available on the server.

Also, if anyone sees area for improvement in my script above, please let me know.  My scripting knowledge is a work in progress, and if there are easier solutions, I would love to hear them.

Thanks!

Modifié par Evelath, 16 avril 2011 - 04:11 .


#2
_Guile

_Guile
  • Members
  • 685 messages
Let me improve the first script:

void main()
{
  //Declare all variables....
  object oPC = GetPCSpeaker();
  object oLang = GetItemPossessedBy(oPC, "lang_token");
  object oLang_2 = GetItemPossessedBy(oPC, "hlslang_13");

  if (oLang_2 == OBJECT_INVALID) //If the PC does NOT have the item
  { DestroyObject(oLang);
  CreateItemOnObject("hlslang_13", GetPCSpeaker(), 1); }
  else  //Otherwise they have the item!
  { SendMessageToPC(oPC, "You have already learned this language."); }
 
  if (oLang != OBJECT_INVALID) //If the PC does have the item...
  { SendMessageToPC(oPC, "You can not learn anymore languages right now."); }
}

if oLang does not equal (not there) kind of backwards language huh? it means they have it...or it's true...

Modifié par _Guile, 18 avril 2011 - 02:07 .


#3
Evelath

Evelath
  • Members
  • 56 messages
Thank you for that.  I am attempting to get the earlier function to work (Where I simply identify how many of a set of items a player has):

void main()
{

    object oPC          = GetPCSpeaker();
    int    nLanguage    = 0;

    if (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_1"))==TRUE)
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_2"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_3"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_4"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_5"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_6"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_7"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_10"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_11"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_12"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_13"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_14"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_15"))==TRUE);
       (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_16"))==TRUE);
        {
        nLanguage ++;

     string sResponse    = "You currently know " + IntToString(nLanguage) + " languages.";
        SendMessageToPC(oPC, sResponse);

        }


Obviously this isn't working as intended (tested it...)  My intention is to confine the number of languages known to a single number, that way I can later use IF statements to determine if the integer matches the appropriate INT bonus.

Any help would be appreciated :)

#4
_Guile

_Guile
  • Members
  • 685 messages
void main()
{

    object oPC = GetPCSpeaker();

    int  i;
    int nInt = 0;
    string sName = "hlslang_";
    string sConvert;
    object oItem;

    //Loop
    for(i=0; i<17; i++)
    {
      nInt += 1;
      sConvert = sName + IntToString(i);  //add "hlslang_" & the int i (which will change from 1 to 2 etc)
      
      oItem = GetItemPossessedBy(oPC, sConvert);

      if(oItem != OBJECT_INVALID)
      {  
        sResponse    = "You currently know " + IntToString(nInt) + " languages.";
        SendMessageToPC(oPC, sResponse);
      }

    }
 
//End Main Script
}

Loops are powerful, they shorten scripts tremendously, including Switch / Case Statements as well, but these subjects are best left to study in the Lexicon as they are subjects that are rather difficult to talk about on a forum for they are well beyond the scope of forums post... 

Hope that helped   :innocent:

Modifié par _Guile, 18 avril 2011 - 02:18 .


#5
Evelath

Evelath
  • Members
  • 56 messages
Thank you so much :)

I'm working my way through learning everything, and loops and case/break situations are what I am attempting to get through now, so it looks really good :)  I'll test it out and see how it goes.  Thanks again!

#6
Evelath

Evelath
  • Members
  • 56 messages
Minor bug.  The script compiles ( after declaring String sResponse ;) ), however when I added "hlslang_1" to my inventory, it states I have 2 languages.  "hlslang_11" to my inventory, it states I have 12.

All I can tell is that it seems to be setting a particular number (1), then adding the variable at the end of "hlslang_" to the amount of languages learned.  I'll take a whack at it later this evening, however if you beat me to it I appreciate it :)

#7
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
I noticed in your script attempt Evelath that you skipped "hlslang_8" and "hlslang_9". Are you not using those two language items? If not then you can't do the loop the same way that _Guile suggested.

Could try it more like this perhaps?


void main()
{
    object oPC = GetPCSpeaker();
    int i;
    int nInt = 0;
    object oItem;
    string sResponse;
   
    for(i=0; i<17; i++)
    {
          oItem = GetItemPossessedBy(oPC, "hlslang_" + IntToString(i));
          if (oItem != OBJECT_INVALID)
          nInt++;
    }

    if (nInt == 1)
    sResponse = "You currently know 1 language.";
    else
    sResponse = "You currently know " + IntToString(nInt) + " languages.";
    SendMessageToPC(oPC, sResponse);
}


Hope that works for ya. Good luck.

Modifié par GhostOfGod, 18 avril 2011 - 05:24 .


#8
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
The problem with the   GetItemPossessedBy function is that it loops through the players inventory every time you use it. I am not saying the method you are trying to use will not work, just that it is ineffecient.  It would be better if you just made a custom loop or function to go through the inventory only one time.  I made it into a function.  This way you can place it into an include to use it where ever you want.

int  GetNumLanguages(object oPC)
{
     int nCount;

     object oInv = GetFirstItemInInventory(oPC);
     while (GetIsObjectValid(oInv))
     {
        if(GetStringLeft(GetTag(oInv), 8) == "hlslang_") nCount++;
        GetNextItemInInventory(oInv);
        oInv = GetNextItemInInventory(oPC);
     }
     return nCount;


Modifié par Lightfoot8, 22 avril 2011 - 08:31 .


#9
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Another excellent suggestion by Lightfoot.

So you could save his function to your library or by itself in its own scirpt. For examples sake we'll say you leave it by itself and name the script "num_lang_inc". Then you could make a script like so:

#include "num_lang_inc"
void main()
{
    object oPC = GetPCSpeaker();
    int nLangs = GetNumLanguages(oPC);
    string sResponse;
   
    if (nLangs == 1)
    sResponse = "You currently know 1 language.";
    else
    sResponse = "You currently know " + IntToString(nLangs) + " languages.";
    SendMessageToPC(oPC, sResponse);
}

#10
Evelath

Evelath
  • Members
  • 56 messages
Thanks for the comments/suggestions.

I implemented the two scripts (include + main script), and it works appropriately when there are no languages present on the PC.  (It will state that I have 0 languages).  However when I add the language, I get the "Too Many Instructions" line.

I essentially did a copy of the script to identify how many language tokens a player has as well, and it's turning up the same error.

Any help is appreciated :)

#11
Evelath

Evelath
  • Members
  • 56 messages
Also, another question.

Rather than using language tokens, would it be easier and/or more efficient to use Player Skins (this will be used on a PW.)?  I've read a bit about PC skins, however I am not sure whether it would be most feasible to utilize them in this case.

#12
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Can you post your script. I do not see any error in what I posted. The only problem I can currently see happening is if you are nesting that function inside of another Inventory looping function.


EDIT:  *Cringes*    On the other hand.   Sorry my fault . 

Change the line: 

 

GetNextItemInInventory(oInv);

To

oInv = GetNextItemInInventory(oPC);

Modifié par Lightfoot8, 18 avril 2011 - 08:17 .


#13
Evelath

Evelath
  • Members
  • 56 messages
A late 'thank you' to everyone assisting.  I am now attempting to link the current code(s) that you provided, with another script that sets the Int Bonus for a character (base, w/o items) to a single number that can then be matched against the current number of languages that a character knows.

#include "nw_i0_plot"

int GetIntBonus(object oPC)

{
    int    nInt     = GetIntelligence(oPC);
    int    nBonus;

    if (nInt = 12)
    {
    nBonus + 1;
    }


    return nBonus;



}

I started working on a separate function to call; however I am thinking that it may be easier to run a Loop?  It would simply need to check nInt to determine if it is an even value (12, 14, 16, 18, 20, etc. stopping at likely 30), and then setting nBonus to the appropriate amount (if nInt = 12, then nBonus = 1).  The above however, has a number of parameters that I am not sure would be able to work in a Loop situation.  A little lost with this being a bit more complex than my previous scripts (or I am atleast making it that way.)

#14
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
If my scripting hat is on right this morning something like this perhaps?


int GetIntBonus(object oPC)
{
    int iIntelligence = GetAbilityScore(oPC, ABILITY_INTELLIGENCE, TRUE);
    int iIntBonus;

    if (iIntelligence < 12)
    {
        return iIntBonus;
    }

    else if (iIntelligence > 30)
    {
        iIntBonus = 10;
        return iIntBonus;
    }

    else
    {
        while (iIntelligence > 11)
        {
            if (iIntelligence % 2 == 0) iIntBonus++;
            iIntelligence--;
        }
        return iIntBonus;
    }
}


Hope it helps. Good luck.

#15
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Why not just use the built in function.  

Function - GetAbilityModifier


If you still wanted to script it. You can reduce your function down to one line. 

int GetIntBonus(object oPC)
{
 return  (GetAbilityScore(oPC,ABILITY_INTELLIGENCE,TRUE)-10)/2;
}  



If you wanted adjusted ability scores to effect how many languages they can learn, just change the TRUE to a FALSE.

Modifié par Lightfoot8, 22 avril 2011 - 08:58 .


#16
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Maybe he wants to use a big convoluted unnecessary script? :lol:

Ok ok. So I was waaay overthinking things as usual. However he did say he wanted it capped at 30. If that is the case then definitely still use Lightfoots version but maybe like this?


int GetIntBonus(object oPC)
{
    int iIntelligence = GetAbilityScore(oPC,ABILITY_INTELLIGENCE,TRUE);
    if (iIntelligence > 30) return 10;
    else return  (iIntelligence - 10) / 2;

Modifié par GhostOfGod, 22 avril 2011 - 09:06 .


#17
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Hmm..actually thinking about the above....if the intelligence is 11 will (iIntelligence - 10) / 2; round up to a 1? Maybe GetAbilityModifier would work better?

Edit: Nevermind. Everything after the decimal is ignored. I need some coffee....where's the coffee?

Modifié par GhostOfGod, 22 avril 2011 - 09:28 .


#18
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
The Only real draw back to GetAbilityModifier is that I seen no way to force it to get the bonus from the unmodified intelligence score. If he is wanting to use the modified scores it will work great.

#19
Evelath

Evelath
  • Members
  • 56 messages
Alrighty, so I feel like I continue to complicate things as I progress! :)

What would be involved if I wanted to have only certain languages involved in the selection?

For example, if I wanted to allow a player with 10 INT to choose 1 regional language (and also ensure they get their racial language), how would I go about doing that without interferring with the function that is getting the number of items in their inventory?

I've noticed "case" and "break" statements, would this involve those?

#20
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Question: do all PC's get a racial language?   or at least all PC that are not human ?  Or do even some of the humans get racical languages?  
I  guess I do not reall need that answered, 

I would start by first setting up some constants for the languages, with a few functions in an include file so you dont have to keep looking things up.   I assume you are useing the DMFI languages, If so you could do something like this. 

const int LANGUAGE_ELVEN    = 1;
const int LANGUAGE_GNOME    = 2;
const int LANGUAGE_HALFLING =3;
const int LANGUAGE_DWARVEN  = 4;
const int LANGUAGE_ORC      = 5;
const int LANGUAGE_GOBLIN   = 6;
const int LANGUAGE_DRACONIC = 7;
const int LANGUAGE_ANIMAL   = 8;
const int LANGUAGE_CANT     = 9;
const int LANGUAGE_CELESTIAL = 10;
const int LANGUAGE_ABYSSAL   = 11;
const int LANGUAGE_INFERNAL  = 12;
const int LANGUAGE_DROW      = 13;
const int LANGUAGE_SYLVAN    = 14;// Extra 0 in the resref.
const int LANGUAGE_RASHEMI   = 15;//Extra 0 in the resref.
const int LANGUAGE_MULHORANDI= 16;//Extra 0 in the resref.
   
int GetIntBonus(object oPC);
   
// Gets the number og languages the PC already has.
int  GetNumLanguages(object oPC);

//Gets the tag for the given LANGUAGE_*
string GetLanguageTag(int nLangConstant);
   

//Gets the tag for the given LANGUAGE_*
string GetLanguageResRef(int nLangConstant);
   
// gets the number of languages the PC is allowed to have.
int GetNumAllowedLang(object oPC);
   
int GetIntBonus(object oPC)
{
 return  (GetAbilityScore(oPC,ABILITY_INTELLIGENCE,TRUE)-10)/2;
}
   
string GetLanguageTag(int nLangConstant)
{
  return "hlslang_" + IntToString(nLangConstant);
}
   

string GetLanguageResRef(int nLangConstant)
{
  string sPrefix = "hlslang_";
  if (nLangConstant > 13 && nLangConstant < 17) sPrefix += "0";
  return  "hlslang_" + IntToString(nLangConstant);
}
   

int  GetNumLanguages(object oPC)
{
     int nCount;
   
     object oInv = GetFirstItemInInventory(oPC);
     while (GetIsObjectValid(oInv))
     {
        if(GetStringLeft(GetTag(oInv), 8) == "hlslang_") nCount++;
        oInv = GetNextItemInInventory(oPC);
     }
     return nCount;
}
    
int GetNumAllowedLang(object oPC)
{
  int nNumLang = GetIntBonus( oPC) +1;
     
  // Assuming that all races except humans get
  //there racial language free.
  if ( GetAppearanceType(oPC)!=APPEARANCE_TYPE_HUMAN)nNumLang++;
  return nNumLang;
}
 



Hope that helps some. 

#21
Evelath

Evelath
  • Members
  • 56 messages
 First off, thank you so much for taking the time to help me out :)

I am using the DMFI, however I had found another vault entry (it escapes me now, as I am at work) that essentially follows the came concept line as DMFI ("hlslang_"), only includes regional languages for Faerun (Chondanthan for example).  Would I simply follow the same concept that you presented, by declaring the additional language constants and utilizing the same script?

For example:

A human character enters the server, he receives no language tokens.
He is allowed to choose a total of TWO languages, one of which being a regional language, the other being a different (ie: Drow) language?

Meanwhile, an elven character would automatically get the Elven Token, and also be able to select two languages, similar to the Human.

Just want to clarify it, thanks again for helping me with this, as it is one of the last systems that I need to implement in terms of scripting for the PW.  :)

#22
Evelath

Evelath
  • Members
  • 56 messages
So I've been tinkering with this script still.  The final function you included increased the number of learnable languages by 1 if the PC was not human.  Would it be fair to say that following that same formula with classes would be just as feasible?  My goal is to implement several class-specific languages (ie: Assassin's Cant), however still grant the player the option to choose his own languages.

Would this work? (away from toolset):

int GetNumAllowedLang(object oPC)
{
  int nNumLang = GetIntBonus( oPC) +1;

  // Assuming that all races except humans get
  //there racial language free.
  if (( GetAppearanceType(oPC)!=APPEARANCE_TYPE_HUMAN))nNumLang++||
     ( GetLevelByclass(class_TYPE_ASSASSIN, oPC)>0)||
     ( GetLevelByclass(class_TYPE_DRUID, oPC)>0)||
     ( GetLevelByclass(class_TYPE_ROGUE, oPC)>0)||
     ( GetLevelByclass(class_TYPE_RANGER, oPC)>0);

     {
     nNumLang++;
     }



  return nNumLang;
}

Again, if a player is:

*Elf
*Assassin
*Druid

He should receive the Druidic Language, Elf Language, Assassins Cant Language, and still be allowed to pick additional languages if his INT bonus is high enough.  Thanks for the help :)

#23
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
int GetNumAllowedLang(object oPC)
{
  int nNumLang = GetIntBonus( oPC) +1;

  // Assuming that all races except humans get
  //there racial language free.
  if ( GetAppearanceType(oPC)!=APPEARANCE_TYPE_HUMAN)nNumLang++;

  // +1 for each class they have that gets a language.
  if ( GetLevelByclass(class_TYPE_ASSASSIN, oPC)>0) nNumLang++;
  if ( GetLevelByclass(class_TYPE_DRUID, oPC)>0)nNumLang++;
  if ( GetLevelByclass(class_TYPE_ROGUE, oPC)>0)nNumLang++;
  if ( GetLevelByclass(class_TYPE_RANGER, oPC)>0)nNumLang++;
 
  return nNumLang;
}


Something more like the above.  Keep in mind that this board changes  C LASS to all lower case (class). 

#24
Evelath

Evelath
  • Members
  • 56 messages
Thanks for all the help so far :)

Now that I have secured the include file for the Language System, I want to ensure that I keep it as slim as possible.  As I see it, unless I am mistaken, I will need to make around 82 additional scripts to ensure that whenever a player selects a particular choice from the conversation, they are checked for that language token, and proceed from there.

Essentially:


void main()
{

    object oPC = GetPCSpeaker();
    object oLang    = GetItemPossessedBy(oPC, "lang_token");
    object oLang2   = GetItemPossessedBy(oPC, "hlslang_13");

    if (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_13"))==TRUE)
        {
            SendMessageToPC(oPC, "You have already learned this language.");
        }

    if (GetIsObjectValid(GetItemPossessedBy(oPC, "lang_token"))==FALSE)
        {
            SendMessageToPC(oPC, "You can not learn anymore languages right now.");
        }

    else (GetIsObjectValid(GetItemPossessedBy(oPC, "hlslang_13"))==FALSE);
        {
            DestroyObject(oLang);
            CreateItemOnObject("hlslang_13", GetPCSpeaker(), 1);
        }
}


I imagine there is an easier way, as I am looking at the function titled: "GetLanguageResRef" and "GetLanguageTag", however I can't seem to figure out where to place them in order to slim things down.

Thanks :)