0

I am currently trying to find a way to allow a function within an object to run once the object is called.

For example, take the following Object...

const textNodes = [
{
    id: 1,
    faction: "Greaser",
    text: "Do you want to help this person?",
    options: [
        {
            text: "Yes",
            nextText: 2
        },
        {
            text: "No",
            nextText: 2
        },
    ]
},
{
    id: 2,
    faction: "greaser",
    text: "It was a trap, do you run or kill them?",
    options: [
        {
            text: "Run",
            nextText: 3,
            damage: 0,
        },
        {
            text: "Kill",
            nextText: 5,
            damage: 8,
            moneyDrop: 20,
            radiationDamage: 2,
            logic: function update() {
                console.log("update function worked")

                if(character.greaser == true && this.faction == "greaser"){
                    console.log("greaser check worked");
                }

                character.health -= this.damage;
                character.cash += this.moneyDrop;
                character.radiationLevel += this.radiationDamage;
                character.maxHP -= this.radiationDamage;

                if(this.radiationDamage >= 1 ){
                    addRadiatedStatus();
                }

                console.log("character HP" + " " +  character.health);
                console.log("character maxHP" + " " +  character.maxHP);
                console.log("moneyDrop " + " " +  this.moneyDrop);
                console.log("character cash" + " " +  character.cash);
                console.log("radiation level" + " " +  character.radiationLevel);
                console.log("character Raditated?" + " " +  character.radiated);
            },
        },
    ]
}
]

As you can see , I have a function update() that is going to change a character object once the function is called.

I am currently calling the function like... textNodes[1].options[1].logic();

Of course, I do not want to do this, because I am building a rpg decision game. The user will be given a question and some choices, and allowed to create their own path. If the user gets 3 options, and the user picks option 2, I will run option 2's logic() / update() function.

Each game choice will have a function attached to it that does something different, and each time that I choose the option, I want the function to run automatically. I am not sure if this is even possible, but it seems like the most logical option.

The card decision game I am building is similar to https://www.youtube.com/watch?v=ByBUsBxPrZ4.

as you can see in this video, each card that is chosen ( tinder app style ) will update the game and the characters stats.

I want those update function to run as soon as an object option is called. I am not sure if this is possible, and a peer told me my hint to you is to use classes, but I do not often use classes unless I am coding in java, which I do not like frankly.

Sorry if this is hard to follow and thanks in advance.


Here is what I have tried.

const textNodes = [
    {
        id: 1,
        faction: "Greaser",
        text: "Do you want to help this person?",
        options: [
           {
            text: "Yes",
            nextText: 2
           },
           {
            text: "No",
            nextText: 2
           },
        ]
    },
    {
        id: 2,
        faction: "greaser",
        text: "It was a trap, do you run or kill them?",
        options: [
           {
            text: "Run",
            nextText: 3,
            damage: 0,
           },
           {
            text: "Kill",
            nextText: 5,
            damage: 8,
            moneyDrop: 20,
            radiationDamage: 2,
            logic: function update(){
                console.log("update function worked")
                if(character.greaser == true && this.faction == "greaser"){
                    console.log("greaser check worked");
                }
            character.health -= this.damage;
            character.cash += this.moneyDrop;
            character.radiationLevel += this.radiationDamage;
            character.maxHP -= this.radiationDamage;
            if(this.radiationDamage >= 1 ){
                addRadiatedStatus();
            }
            console.log("character HP" + " " +  character.health);
            console.log("character maxHP" + " " +  character.maxHP);
            console.log("moneyDrop " + " " +  this.moneyDrop);
            console.log("character cash" + " " +  character.cash);
            console.log("radiation level" + " " +  character.radiationLevel);
            console.log("character Raditated?" + " " +  character.radiated);

            },
            run2:  () =>{
                this.logic();
            }
           },
        ]
    }
]
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
ETHan
  • 159
  • 1
  • 12
  • 1
    I think you can help [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) – Nikita Madeev Jun 22 '20 at 14:07
  • Can you elaborate more on "as soon as an object option is called". What do you mean "called"? To my understanding you want to avoid explicitly calling the logic function and have it be called automatically. I just don't understand the trigger. – Σπύρος Γούλας Jun 22 '20 at 14:08
  • Do you know which option is selected by the user? If yes, did you try to call `logic` method directly on selected option? You can even check if object has `logic` property defined like this: https://jsbin.com/nuyenagiwe/1/edit?js,console – macborowy Jun 22 '20 at 14:28
  • @ΣπύροςΓούλας thank you for your comment. When i mean "called", I mean that whenever the user selects an "option" for that question ID, I want to run any and all functions that are within my object. So if the question ( id 2 ) is "Do you want to run or fight", and the user selects the option "fight", any function within that option will be run. If the user chooses to fight, maybe my function will subtract health from a player object. I am using this tutorial as a starting point, and might help understand what I am trying to do. https://www.youtube.com/watch?v=R1S_NhKkvGA&t=709s . – ETHan Jun 22 '20 at 15:40

1 Answers1

1

The simplest thing is to put the call to logic (aka update) at the end of the functions that you want to have do an update after they've done their work.

If for some reason you don't want to do that, you can wrap them in another function that will do it. After creating textNodes:

for (const {options} of textNodes) {
    for (const option of options) {
        const original = option.theOtherFunction;
        option.theOtherFunction = function(...args) {
            const result = original.apply(this, args);
            this.logic();
            return result;
        };
    }
}

Now, calling textNodes[i].options[1].theOtherFunction() will do theOtherFunction's work, and then do a call to logic (unless an error is thrown).

Or in ES5:

textNodes.forEach(function(textNode) {
    textNode.options.forEach(function(option) {
        var original = option.theOtherFunction;
        option.theOtherFunction = function() {
            var result = original.apply(this, arguments);
            this.logic();
            return result;
        };
    });
});

Re calling this.logic from the function, as you can see it works just fine:

const textNodes = [{
    id: 1,
    faction: "Greaser",
    text: "Do you want to help this person?",
    options: [{
        text: "Yes",
        nextText: 2
      },
      {
        text: "No",
        nextText: 2
      },
    ]
  },
  {
    id: 2,
    faction: "greaser",
    text: "It was a trap, do you run or kill them?",
    options: [{
        text: "Run",
        nextText: 3,
        damage: 0,
      },
      {
        text: "Kill",
        nextText: 5,
        damage: 8,
        moneyDrop: 20,
        radiationDamage: 2,
        logic: function update() {
          console.log("update function worked")
          /*
          if (character.greaser == true && this.faction == "greaser") {
            console.log("greaser check worked");
          }
          character.health -= this.damage;
          character.cash += this.moneyDrop;
          character.radiationLevel += this.radiationDamage;
          character.maxHP -= this.radiationDamage;
          if (this.radiationDamage >= 1) {
            addRadiatedStatus();
          }
          console.log("character HP" + " " + character.health);
          console.log("character maxHP" + " " + character.maxHP);
          console.log("moneyDrop " + " " + this.moneyDrop);
          console.log("character cash" + " " + character.cash);
          console.log("radiation level" + " " + character.radiationLevel);
          console.log("character Raditated?" + " " + character.radiated);
          */
        },
        run2: function() {
          console.log("This is run2");
          this.logic();
        }
      },
    ]
  }
];

textNodes[1].options[1].run2();
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • thank you for the response T.J. However, I am a little confused here. I tried adding a key to my option called `runFunction: logic()`, but I get the error that logic does not exist. I also tried `this.logic` and that also didn't work. Is there a way to do this ( not the way you show after you say "if for some reason you don't want to do that", but just adding the function call at the end ). – ETHan Jun 22 '20 at 15:43
  • @ETHan - To help further, I need a [mcve] of the problem showing not just where/how `logic` is defined, but also where/how the function you want to call it from is defined. If it were on the `option` like `logic` is, `this.logic();` would work. – T.J. Crowder Jun 22 '20 at 16:01
  • I am defining logic here `logic: function update() { console.log("update function worked")` and then adding another key pair to that option like `run: this.logic()` and that doesn’t work. Let me send a JS fiddle for you to see. – ETHan Jun 22 '20 at 18:12
  • @ETHan - No, not a jsFiddle. Put the code necessary to answer the question **in** the question, not just linked. But `run: this.logic()` **calls** `this.logic()` an assigns the result to the `run` property, just like `foo: 42` assigns `42` to the `foo` property. If you meant that to be a function, you have to create a function: `run: function() { this.logic(); }`. – T.J. Crowder Jun 22 '20 at 22:09
  • I edited the post and added what I have been trying to do. – ETHan Jun 23 '20 at 01:34
  • @ETHan - Make `run` a traditional function like `logic` is, not an arrow function. Arrow functions *close over* `this`, but you want the traditional behavior of `this` being set by how the function is called. More details in the answers to [this question](https://stackoverflow.com/questions/31095710/methods-in-es6-objects-using-arrow-functions). – T.J. Crowder Jun 23 '20 at 09:02
  • Yes I did that and I am still not getting the function to run. `run: function run(){ this.logic();}` – ETHan Jun 23 '20 at 13:50
  • @ETHan - Again, to help further I need to see a [mcve] of the problem. Using a traditional function on the option object works just fine -- see the update at the end of the answer above. – T.J. Crowder Jun 23 '20 at 14:18