Navigation

    City of Arabel

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Scripting Request

    Scripting
    2
    7
    1861
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Yardsale
      Yardsale last edited by

      This is something I want to do, but I'm so busy I can't even find some time to work on it. I don't expect players to do this entirely alone, but if someone wants to do something that will add a lot of value to many projects I have in my mind, this would help immensely.

      The task is to code a generic and flexible CoA Trigger for various purposes. I want to be able to only set a number of variables on a trigger in order for it to work out of the box. Those variables are outlined below ((There could be more variables, I might not have forseen them all)).

      Then the trigger would have the very same script in the OnEnter and OnExit event, and this particular script would evaluate said variables and take the appropriate action. It needs to be highly modular, so typically the OnEnter / OnExit script would be a very short main() function, with an include file for all the lenghty functions and verifications.

      There also need to be failsafes for certain variables that could be optional. If those variables are not set on the item, they should either be ignored, or replaced by default values.

      Variables

      sTriggerFiringEvent
      purpose: Determines on which event (Enter/Exit), the code will run.
      possible values: OnEnter / OnExit
      
      sTriggeringConditionType
      purpose: Determines which condition has to be met in order for the trigger to -actually- do something. (Multiple Values separated by commas can be used)
      possible values: PossessionOfItem / HasQuest / HasCompletedQuest / NumberOfPCEntered / NumberOfPCExited / PCClass / PCOverLevel / PCUnderLevel / PCIsFactionMember / PCBeatDC /
      
      sTriggeringConditionValue
      purpose: Contains the value for the Condition Type, for example, if the condition Type is HasQuest,PCClass then the value could be "qParner,Wizard"
      
      sResultScript
      purpose: Contains the script to execute if the Triggering Condition is met
      possible values: any script name
      
      sTagOfObjectToExecute
      purpose: the ResultScript could have to be fired on some object, PC, placeable, etc, if so, we need the tag of it.
      possible values: The tag of an object, or PC if it's on the PC. 
      
      iRandomnessOfTriggering
      purpose: Can randomize the triggering of the code by a certain percentage
      possible values: 1 to 100
      
      

      Functions Prototypes

      int isTriggeringConditionMet(string sTriggeringConditionType, string sTriggeringConditionValue);
      ---And load of others I didn't have the time to think about beforehand.
      
      
      1 Reply Last reply Reply Quote
      • C
        COA_Aristos last edited by

        Comments -

        1. There is no mechanism by which a script can tell which event triggered it, if any. So, get rid of "sTriggerFiringEvent" and have seperate OnEnter and OnExit scripts, and put it in the "how to use this system" to only use one or the other and not both (though, that would be possible too I suppose if there were a reason for it).

        2. Scripts aren't fired on objects, they are fired BY objects. It would make the most sense to have the fired off scripts do their own grabbing of variables from the triggered object, getting passed only the triggering object (which is the only info they can't get on their own). They would have to be passed values by local variables on some object anyway.

        3. Are multiple conditions meant to be ANDs or ORs?

        4. Will need additional delimiters in the "ConditionalValue" in order to pass on more than one string to the conditional checking code ie. pass "Reflex:15" or "Spellcraft:20" to the "PCBeatDC" checking code. I'd suggest ":".

        Therefore I'd suggest change to the following specifications-

        sOnEnterConditionType 
        sOnExitConditionType
        purpose: Determines which condition has to be met in order for the trigger to -actually- do something. (Multiple Values separated by commas can be used, in which case all conditions must be met) 
        possible values: PossessionOfItem / HasQuest / HasCompletedQuest / NumberOfPCEntered / NumberOfPCExited / PCClass / PCOverLevel / PCUnderLevel / PCIsFactionMember / PCBeatDC / ect.
        
        sOnEnterConditionValue 
        sOnExitConditionValue
        purpose: Contains the value for the Condition Type, for example, if the condition Type is HasQuest,PCClass then the value could be "qParner,Wizard" or is PosessionofItem,PCBeatDC could be "WhiteStagMeat,Spellcraft:20"
        
        sOnEnterScript
        sOnExitScript
        purpose: Contains the name of the script to execute if the Triggering Condition is met.  OBJECT_SELF will be the triggered object, GetLocalObject(OBJECT_SELF,"oTriggeringPC") will be the triggering PC.
        
        sOnEnterScriptData
        sOnExitScriptData
        purpose : Contains and data which needs to be passed on to the triggered script.  Data will be in GetLocalObject(OBJECT_SELF,"sScriptData").  NOTE: Use "sScriptData" directly unless you are using two different OnEnter and OnExit conditional scripts.
        
        iOnEnterRandomness 
        iOnExitRandomness
        purpose: Can randomize the triggering of the code by a certain percentage 
        possible values: 1 to 100
        

        There will be three scripts - two very small OnEnter and OnExit and the larger #include to contain the function

        I'd also suggest that the main function be broken up into smaller functions (ie. each conditional gets it's own function, same name as the conditional, to which is passed the value for it to test).

        –----------------------------
        Character - Belir Faethalor (Hellos)
        Character - Pang (smash!)
        Character - Hannan Swift (dead)
        Character - Zacham Nefzen (dead)

        1 Reply Last reply Reply Quote
        • Yardsale
          Yardsale last edited by

          @COA_Aristos:

          Comments -

          1. There is no mechanism by which a script can tell which event triggered it, if any. So, get rid of "sTriggerFiringEvent" and have seperate OnEnter and OnExit scripts, and put it in the "how to use this system" to only use one or the other and not both (though, that would be possible too I suppose if there were a reason for it).

          What I meant is that both OnEnter and OnExit will be the same script. Each of them will start by checking the variable on themselves. If they are the script supposed to fire, they continue, otherwise, they do nothing.

          Example: A PC walk over the trigger. It triggers OnEnter. The trigger run the script, checks the variable on itself, but the variable is set to OnExit, so it exits the function before doing anything. When the PC exit the trigger, then the function will run completely.

          1. Scripts aren't fired on objects, they are fired BY objects. It would make the most sense to have the fired off scripts do their own grabbing of variables from the triggered object, getting passed only the triggering object (which is the only info they can't get on their own). They would have to be passed values by local variables on some object anyway.

          I know, I meant BY.

          1. Are multiple conditions meant to be ANDs or ORs?

          ANDs.

          1. Will need additional delimiters in the "ConditionalValue" in order to pass on more than one string to the conditional checking code ie. pass "Reflex:15" or "Spellcraft:20" to the "PCBeatDC" checking code. I'd suggest ":".

          Yes, that could work.

          1 Reply Last reply Reply Quote
          • C
            COA_Aristos last edited by

            What I meant is that both OnEnter and OnExit will be the same script. Each of them will start by checking the variable on themselves. If they are the script supposed to fire, they continue, otherwise, they do nothing.

            Example: A PC walk over the trigger. It triggers OnEnter. The trigger run the script, checks the variable on itself, but the variable is set to OnExit, so it exits the function before doing anything. When the PC exit the trigger, then the function will run completely.

            So, something like

            if GetLocalVariable(OBJECT_SELF,"sTriggerFiringEvent") != WhatEventTriggeredMe() return;
            

            Not possible.

            I suppose as a cludge you could determine if the PC is in the area of the trigger or area, if so it would be an OnEnter event if not an OnExit event. Maybe. Very prone to lag induced errors I would think. But doable.

            –----------------------------
            Character - Belir Faethalor (Hellos)
            Character - Pang (smash!)
            Character - Hannan Swift (dead)
            Character - Zacham Nefzen (dead)

            1 Reply Last reply Reply Quote
            • Yardsale
              Yardsale last edited by

              I suppose that having the OnEnter and OnExit scripts be different could work, I don't mind much as long as both retain the same logic and can use the same parameters.

              OnEnter

              If sFiringEvent on OBJECT_SELF = OnEnter Then continue
              Else return;
              
              

              OnExit

              If sFiringEvent on OBJECT_SELF = OnExit Then continue
              Else return;
              
              
              1 Reply Last reply Reply Quote
              • C
                COA_Aristos last edited by

                OnEnter

                // ConditionalTrigger_OnEnd (or whatever)
                
                #include "ConditionalTrigger_Include" // (or whatever)
                
                main()
                {
                // Find the PC who entered or exited - only trigger for PCs
                     object oPC = GetEnteringObject();
                
                // Error checking code
                     if !GetIsPC(oPC) || GetIsDM(oPC)
                          return;
                     if GetLocalString(OBJECT_SELF,"sTriggerFiringEvent") != "OnEnter"
                          return;
                     ActionConditonalTriggering(oPC);
                }
                

                OnExit

                // ConditionalTrigger_OnEnd (or whatever)
                
                #include "ConditionalTrigger_Include" // (or whatever)
                
                main()
                {
                // Find the PC who entered or exited - only trigger for PCs
                     object oPC = GetExitingObject();
                
                // Error checking code
                     if !GetIsPC(oPC) || GetIsDM(oPC)
                          return;
                     if GetLocalString(OBJECT_SELF,"sTriggerFiringEvent") != "OnExit"
                          return;
                     ActionConditionalTriggering(oPC);
                }
                

                Include file

                // "ConditionalTrigger_Include" (or whatever)
                #include "NW_I0_PLOT"
                
                // This function likely also allready exists in some include file in some COA system somewhere
                
                int GetClassNumberByName(string sClass)
                {
                     if sClass == "Barbarian" return CLASS_TYPE_BARBARIAN;
                     if sClass == "Cleric" return CLASS_TYPE_CLERIC;
                     if sClass == "Druid" return CLASS_TYPE_DRUID;
                     if sClass == "Fighter" return CLASS_TYPE_FIGHTER;
                     if sClass == "Monk" return CLASS_TYPE_MONK;
                     if sClass == "Paladin" return CLASS_TYPE_PALADIN;
                     if sClass == "Ranger" return CLASS_TYPE_RANGER;
                     if sClass == "Rogue" return CLASS_TYPE_ROGUE;
                     if sClass == "Sorcerer" return CLASS_TYPE_SORCERER;
                     if sClass == "Wizard" return CLASS_TYPE_WIZARD;
                     if sClass == "Arcane Archer" return CLASS_TYPE_ARCANE_ARCHER;
                     if sClass == "Assassin" return CLASS_TYPE_ASSASSIN;
                     if sClass == "Devine Champion" return CLASS_TYPE_DEVINE_CHAMPION;
                     if sClass == "Red Dragon Disciple" return CLASS_TYPE_DRAGON_DISCIPLE;
                     if sClass == "RDD" return CLASS_TYPE_DRAGON_DISCIPLE;
                     if sClass == "Harper Scout" return CLASS_TYPE_HARPER;
                     if sClass == "Harper" return CLASS_TYPE_HARPER;
                     if sClass == "Pale Master" return CLASS_TYPE_PALE_MASTER;
                     if sClass == "Shadow Dancer" return CLASS_TYPE_SHADOWDANCER;
                     if sClass == "Shifter" return CLASS_TYPE_SHIFTER;
                     if sClass == "Weapon Master" return CLASS_TYPE_WEAPON_MASTER;
                     return -1; // Invalid Class Name    
                }
                
                int isTriggeringConditionMet(object oPC,string sConditionType,string sConditionValue)
                {
                // Various setup things
                     string sType;
                     string sValue;
                     string sValue2;
                     int iDelimiterLocation;
                
                     if (sConditionType == "") return FALSE; // No Condition then it can't be met
                
                     while sConditionType != ""
                     {
                // extract entries from the strings using delimiters "," and ":"
                          iDelimiterLocation = FindSubString(sConditionType,",");
                          if iDelimiterLocation == -1
                               sType = sConditionType;
                          else {
                               sType = GetStringLeft(sConditionType,iDelimiterLocation);
                               sConditionType = GetStringRight(sConditionType,GetStringLength(sConditionType)-iDelimiterLocation-1); }
                          iDelimiterLocation = FindSubString(sConditionValue,",");
                          if iDelimiterLocation == -1
                               sValue = sConditionValue;
                          else {          
                               sValue = GetStringLeft(sConditionValue,iDelimiterLocation);
                               sConditionValue = GetStringRight(sConditionValue,GetStringLength(sConditionValue)-iDelimiterLocation-1); }
                          iDelimiterLocation = FindSubString(sValue,":");
                          if iDelimiterLocation == -1
                               sValue2="";
                          else {
                               sValue = GetStringLeft(sValue,iDelimiterLocation);
                               sValue2 = GetStringRight(sValue,GetStringLength(sValue)-iDelimiterLocation-1);
                          }
                ///////////////////////////////////////////////////////////////
                //////////  HERE IS WHERE THE CONDITIONS ARE CHECKED //////////
                ///////////////////////////////////////////////////////////////
                          if sType == "HasItem"
                          {
                               if !HasItem(oPC,sValue) return FALSE;
                          }
                          else if sType == "UnderLevel"
                          {
                               if !(GetHitDice(oPC) < StringToInt(sValue)) return FALSE;
                          }
                          else if sType == "OverLevel"
                          {
                               if !(GetHitDice(oPC) > StringToInt(sValue)) return FALSE;
                          }
                          else if sType == "HasClass"
                          {
                               if !(GetLevelByClass(oPC,GetClassNumberByName(sValue)) > 0) return FALSE;
                          }
                          else if sType == "UnderClassLevel"
                          {
                               if !(GetLevelByClass(oPC,GetClassNumberByName(sValue)) < StringToInt(sValue2)) return FALSE;
                          }
                          else if sType == "OverClassLevel"
                          {
                               if !(GetLevelByClass(oPC,GetClassNumberByName(sValue)) > StringToInt(sValue2)) return FALSE;
                          }
                
                          // ect. ect. ect. more else ifs need to be added for more conditionals //
                          // Be sure to check if the condition is NOT met, and to return FALSE if NOT met //
                
                          else return FALSE; // Unsupported conditions can not be met.
                
                ///////////////////////////////////////////////////////////////
                //////////  END WHERE CONDITIONS ARE CHECKED         //////////
                ///////////////////////////////////////////////////////////////
                     }
                     return TRUE;
                }
                
                void ActionConditionalTriggering(object oPC)
                {
                // Randomness - do first for efficiency
                     int iRandomness = GetLocalInt(OBJECT_SELF,"iRandomnessOfTriggering");
                     if (iRandomness != 0) && (iRandomness >= d100()) return;
                
                // Find the object to execute the script - exit if unable to find
                     string sTagOfObjectToExecute = GetLocalString(OBJECT_SELF,"sTagOfObjectToExecute");
                     object oExecutingObject = (sTagOfObjectToExecute == "") ? OBJECT_SELF :
                                               (sTagOfObjectToExecute == "SELF") ? OBJECT_SELF :
                                               (sTagOfObjectToExecute == "PC") ? oPC :
                                               GetObjectByTag(sTagOfObjectToExecute);
                     if oExecutingObject == OBJECT_INVALID return;  // unable to find object, exit without comment
                
                // Find if condition is met
                     if !isTriggeringConditionMet(oPC,
                                                  GetLocalString(OBJECT_SELF,"sTriggeringConditionType"),
                                                  GetLocalString(OBJECT_SELF,"sTriggeringConditionValue"))
                          return; // exit without comment if condition is not met
                
                // Execute Script - invalid script name will perform no action.
                     SetLocalObject(oExecutingObject,"oCT_PC",oPC); // not sure how to pass this info to the script
                     SetLocalObject(oExecutingObject,"oCT_Trigger",OBJECT_SELF); // but probably have to do it somehow
                     ExecuteScript(GetLocalString(OBJECT_SELF,"sResultScript"),oExecutingObject);
                    return;
                }
                

                Implimented Conditions

                HasItem - sItemTag = checks if triggering PC has sItemTag in it's inventory
                UnderLevel - iLevel = checks if triggering PC has fewer hit dice than iLevel
                OverLevel - iLevel = checks if triggering PC has more hit dice than iLevel
                HasClass - sClassName = checks if triggering PC has at least 1 level in sClassName
                UnderClassLevel - sClassName:iLevel - checks if Triggering PC has fewer than iLevel levels in sClassName
                OverClassLevel - sClassName:iLevel - checks if Triggering PC has more then iLevel levels in sClassName

                Someone else will have to write the code for the other conditions, but it should be realitively easy

                –----------------------------
                Character - Belir Faethalor (Hellos)
                Character - Pang (smash!)
                Character - Hannan Swift (dead)
                Character - Zacham Nefzen (dead)

                1 Reply Last reply Reply Quote
                • Yardsale
                  Yardsale last edited by

                  That's great! It'll save me some time!

                  Awesome.

                  Thank you.

                  1 Reply Last reply Reply Quote
                  • 1 / 1
                  • First post
                    Last post