3
\$\begingroup\$

I'm making a text-based RPG in JavaScript. I made a skill leveling system that works, but I feel like the function arguments get passed around a lot and, the code is not very scalable. Do you have any suggestions on how I can improve this code? Ideally, I want to call only one function like: addExperience(25, charisma);

What my code does:
The properties object gives each skill level a title. Currently, all skills have the same title. In the future, these will have different titles and number of titles.

The player object has a skill level and experience key for each skill, so the skills can level independently.

I've also posted the HTML and CSS code for completion. However, this is not important because I only wrote it to test the JavaScript code, and it is not part of the game.

// Skill variable
const properties = {
  strength: [
    "Dabbler",
    "Skilled",
    "Untrained",
    "Proficient",
    "Amateur",
    "Superb",
    "Master",
  ],
  endurance: [
    "Dabbler",
    "Skilled",
    "Untrained",
    "Proficient",
    "Amateur",
    "Superb",
    "Master",
  ],
  charisma: [
    "Dabbler",
    "Skilled",
    "Untrained",
    "Proficient",
    "Amateur",
    "Superb",
    "Master",
  ],
};

// Player variables
const player = {
  stats: {
    strength: {
      level: 0,
      experience: 0,
    },
    endurance: {
      level: 0,
      experience: 0,
    },
    charisma: {
      level: 0,
      experience: 0,
    },
  },
};

function getExperienceToNextLevel(level, skill) {
  if (level < skill.length) {
    return ((level * (level + 1)) / 2) * 1000;
  }
}

function addExperience(amount, stat, skill) {
  if (stat.level !== skill.length - 1) {
    stat.experience += amount;
    while (stat.experience >= getExperienceToNextLevel(stat.level, skill)) {
      stat.experience -= getExperienceToNextLevel(stat.level, skill);
      ++stat.level;
    }
  }
  display(stat, skill);
}

function display(stat, skill) {
  document.getElementById("level-display").innerHTML = `${stat.level} ${
    skill[stat.level]
  }`;

  document.getElementById("xp-display").innerHTML = `${stat.experience}`;
}
body {
  background: #ff930f;
  background: linear-gradient(
    90deg,
    rgba(255, 147, 15, 1) 0%,
    rgba(255, 249, 91, 1) 100%
  );
  box-sizing: border-box;
  font-family: sans-serif;
  margin: 0;
  padding: 0;
}

.title {
  background-color: rgb(0, 0, 0, 0.1);
  color: #fff;
  margin: 5% auto;
  padding: 25px;
  text-align: center;
  text-shadow: 2px 2px rgb(0, 0, 0, 0.5);
}

.display {
  background-color: rgb(0, 0, 0, 0.1);
  color: #fff;
  margin: 5%;
  padding: 25px;
  text-align: center;
  text-shadow: 2px 2px rgb(0, 0, 0, 0.5);
}

.xp-buttons {
  text-align: center;
}

.xp-buttons button {
  background-color: #333;
  border: none;
  border-radius: 999rem;
  color: #fff;
  font-weight: 700;
  height: 2.5rem;
  max-width: auto;
  min-width: 5rem;
  transition-duration: 0.2s;
  margin: 0 auto;
}

.xp-buttons button:hover {
  background-color: #444;
  cursor: pointer;
}
<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="JavaScript - Debugger" />
    <title>JavaScript - Debugger</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
    <main>
      <h1 class="title">JavaScript - Debugger</h1>
      <div class="display">
        <h2>Level: <span id="level-display"></span></h2>
        <h2>XP: <span id="xp-display"></span></h2>
      </div>
      <div class="xp-buttons">
        <button
          onclick="addExperience(50, player.stats.charisma, properties.charisma)"
        >
          50 XP
        </button>
        <button
          onclick="addExperience(1000, player.stats.charisma,properties.charisma)"
        >
          1000 XP
        </button>
        <button
          onclick="addExperience(0, player.stats.charisma,properties.charisma)"
        >
          Update
        </button>
      </div>
    </main>
    <script src="app.js"></script>
  </body>
</html>

\$\endgroup\$
1
  • 3
    \$\begingroup\$ Test code is perfectly fine, and it does provide context on the use of the code. \$\endgroup\$
    – pacmaninbw
    Jan 27, 2022 at 12:49

1 Answer 1

4
\$\begingroup\$

A short review;

  • I don't like the signature of the function

    addExperience(50, player.stats.charisma, properties.charisma)
    

    could be

    addExperience(50, player, "charisma");
    

    or even

    player.addExperience(50, "charisma");
    

    and if it was me, I would make it more Yoda like

    or even

    player.addExperience("charisma", 50);
    
  • I would keep track of total experience, and not reset it every time you reach a new level. In case you ever want to rebalance the levels of existing characters.

  • I would recommend reading up on the MVC model. If you follow it, then addExperience does not call display

  • Its stub code, but display is too generic a name

  • You seem to treat stats and skills as the same, to me they are not?

  • properties should probably be statTitles?

\$\endgroup\$
5
  • \$\begingroup\$ Thank you for your suggestion! The objects indeed need some reorganizing. I will try to implement the Yoda-like signature. Although a player like object still needs to be passed into the function. Because in the future, I want to add skills to NPC's. \$\endgroup\$
    – LuckyLuke
    Jan 27, 2022 at 17:22
  • \$\begingroup\$ addExperience(50, player, "charisma"); is not very friendly to some js code minifier. \$\endgroup\$
    – tsh
    Jan 29, 2022 at 7:34
  • \$\begingroup\$ @tsh Do you have a link or logic to back that up? Super interested. \$\endgroup\$
    – konijn
    Jan 30, 2022 at 12:25
  • \$\begingroup\$ stackoverflow.com/a/31361878 \$\endgroup\$
    – tsh
    Jan 30, 2022 at 12:55
  • \$\begingroup\$ Maybe I am having a brain fart, but that link says that prototype design is not friendly for minifiers? The code you quote does not use that? \$\endgroup\$
    – konijn
    Jan 31, 2022 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.