-1

I am trying to make this simple loot system to work but I keep getting this TypeError and I have tried everything I could think of.

Everything is explained in the code I added below. It was working yesterday but it seems like today is no longer working...

Here is the code in the JS file:

console.info("Working!");
var items;
//here I get the json
$.getJSON('js/items.json', function(data) {
    return items = data;
});
//run the function cuz laziness to put it every time in the console
loot();

function loot() {
  //these are the drops from the mob
  const ids = [1, 2, 3, 4, 5, 6, 7];
  //define a random number to see what loot it drops
  let rand = Math.floor((Math.random() * 100) + 1);
  var loot;
  //if the chance is between 1 and 5(including them) do that
  if (rand >= 1 && rand <= 5) {
    var legends = [];
    //here I loop inside the ids constant to see what items are legendary and if they are push them to the legends array
    for (var id in ids) {
      //HERE IS THE PROBLEM I get Uncaught TypeError here and I have tried everything
      if (items[ids[id]].rarity == "Legendary") {
        legends.push(ids[id]);
      };
    };
    console.log(`legends: ${legends}`);
    //then I random the items inside legends array to get the loot
    loot = legends[Math.floor(Math.random() * legends.length)];
  };
  console.warn(`You looted a ${items[loot].name} | ${items[loot].rarity}`);
};

and here is the JSON file:

{
  "1": {
    "id": 1,
    "name": "Sword of Heaven",
    "rarity": "Legendary"
  },
  "2": {
    "id": 2,
    "name": "Wooden Sword",
    "rarity": "Common"
  },
  "3": {
    "id": 3,
    "name": "Glass of the Gods",
    "rarity": "Rare"
  },
  "4": {
    "id": 4,
    "name": "Minor HP Potion",
    "rarity": "Common"
  },
  "5": {
    "id": 5,
    "name": "The Enchiridion!",
    "rarity": "Legendary"
  },
  "6": {
    "id": 6,
    "name": "Major MP Potion",
    "rarity": "Rare"
  },
  "7": {
    "id": 7,
    "name": "Helm of the Forsaken",
    "rarity": "Rare"
  }
}
UzendayoNE
  • 161
  • 1
  • 12

2 Answers2

3

try to move your loot function into asynchronous getJson's callback:

console.info("Working!");
var items;
//here I get the json
$.getJSON('js/items.json', function(data) {
    items = data;
    //run the function cuz laziness to put it every time in the console
    loot();
});

if you run it outside of this callback, items variable is not populated yet

if you want to use as function, move AJAX call into loot function, store result and make sure to run it only once:

function lootRun(refresh) {
  // use self in order to reach it from anonymous callback
  var self = this; 
  if (!self.items || refresh) {
    $.getJSON('js/items.json', function(data) {
      // kind of inner functional cache
      self.items = data; 
      loot(self.items);
    });
  }
  else {
    loot(self.items);
  }
}

function loot(items) {
  //these are the drops from the mob
  const ids = [1, 2, 3, 4, 5, 6, 7];
  //define a random number to see what loot it drops
  let rand = Math.floor((Math.random() * 100) + 1);
  var loot;
  //if the chance is between 1 and 5(including them) do that
  if (rand >= 1 && rand <= 5) {
    var legends = [];
    //here I loop inside the ids constant to see what items are legendary and if they are push them to the legends array
    ids.forEach(function(id) {
      //HERE IS THE PROBLEM I get Uncaught TypeError here and I have tried everything
      if (items[id].rarity == "Legendary") {
        legends.push(id);
      };
    });

    console.log(`legends: ${legends}`);
    //then I random the items inside legends array to get the loot
    loot = legends[Math.floor(Math.random() * legends.length)];
    console.warn(`You looted a ${items[loot].name} |     ${items[loot].rarity}`);
  };
};

now you can run your main loot function via lootRun, pass true to lootRun, if you want to refresh data from server

Andriy
  • 14,781
  • 4
  • 46
  • 50
  • it works now but how can I make it so I don't have to put it inside the callback? because I want to use the function every time I run the function. – UzendayoNE Jan 31 '17 at 14:03
  • @FINDarkside, this is not correct, since `var id in ids` will return only available within `ids` array keys, in our example: 0, 1, 2, 3, 4, 5 and 6 – Andriy Jan 31 '17 at 14:03
  • Hi @Mr.Swaggalicious: Instead you can use promises . Based on the success promise you can take the decision of triggering loot(); functionality. – Vali Shah Jan 31 '17 at 14:04
  • @ValiShah I will look into promises. thanks for suggestion :') – UzendayoNE Jan 31 '17 at 14:08
  • @Mr.Swaggalicious, I updated my unswer, so you can call it as function. using `lootRun()` function. Pass `true` to `lootRun`, if you want to refresh data from server – Andriy Jan 31 '17 at 14:31
1

A few things to note - getJson is asynchronous, so items may be undefined. Move it into the getJson callback. Also, you're trying to get the name of an item that's undefined. You need to move the last console.log statement into the if statement so that you aren't using loot (which is undefined) to index the array.

var data = {
  "1": {
    "id": 1,
    "name": "Sword of Heaven",
    "rarity": "Legendary"
  },
  "2": {
    "id": 2,
    "name": "Wooden Sword",
    "rarity": "Common"
  },
  "3": {
    "id": 3,
    "name": "Glass of the Gods",
    "rarity": "Rare"
  },
  "4": {
    "id": 4,
    "name": "Minor HP Potion",
    "rarity": "Common"
  },
  "5": {
    "id": 5,
    "name": "The Enchiridion!",
    "rarity": "Legendary"
  },
  "6": {
    "id": 6,
    "name": "Major MP Potion",
    "rarity": "Rare"
  },
  "7": {
    "id": 7,
    "name": "Helm of the Forsaken",
    "rarity": "Rare"
  }
};

// here I get the json
$.getJSON('js/items.json', function(data) {
  loot(data);
});

function loot(items) {
  //these are the drops from the mob
  const ids = [1, 2, 3, 4, 5, 6, 7];
  //define a random number to see what loot it drops
  let rand = Math.floor((Math.random() * 100) + 1);
  var loot;
  //if the chance is between 1 and 5(including them) do that
  if (rand >= 1 && rand <= 5) {
    var legends = [];
    //here I loop inside the ids constant to see what items are legendary and if they are push them to the legends array
    ids.forEach(function(id) {
      //HERE IS THE PROBLEM I get Uncaught TypeError here and I have tried everything
      if (items[id].rarity == "Legendary") {
        legends.push(id);
      };
    });

    console.log(`legends: ${legends}`);
    //then I random the items inside legends array to get the loot
    loot = legends[Math.floor(Math.random() * legends.length)];
    console.warn(`You looted a ${items[loot].name} | ${items[loot].rarity}`);
  };
};
Max Sindwani
  • 1,267
  • 7
  • 15