Creating a battle system, getting undefined/not defined errors

Twine 2.5.1
Sugarcube 2.36.1

So what I’m looking to do might be a little complex I am trying to make a sort of battle system, I have a javascript function I’m working on to handle most of it, I think I’m getting close to it being in a useable spot. But I am having a few issues.

/* StoryInit for the game */
<<set $pSkills = []>>
<<set setup.Smash = {
        "sname": "Smash",
        "minDamage": 5,
        "maxDamage": 12,
        "staCost": 5,
        "cooldown": 1,
        "applyRandomDamage": true,
       " isOnCooldown": false
}>>
<<set setup.Fireball = {
        "sname": "Fireball",
        "minDamage": 10,
        "maxDamage": 20,
        "staCost": 20,
        "cooldown": 4,
        "applyRandomDamage": true,
       " isOnCooldown": false
}>>
<<set $pSkills.push(setup.Smash)>>
<<set $pSkills.push(setup.Fireball)>>

/* Javascript */
function UseSkill(sname, minDamage, maxDamage, staCost, cooldown) {
    // Check if the player has enough stamina to use the skill
    if (staCost && pCurSta < staCost) {
        alert("You are too tired to do that!")
        return
    }
    // Generate random damage
    var randomDamage = Math.floor(Math.random() * (maxDamage - minDamage + 1) + minDamage);
    eCurHp -= randomDamage;
    alert("You use " + sname + " and dealt " + randomDamage + " damage to the enemy!");

    // check if the skill has a cooldown
    if(cooldown) {
        pSkills[sname].cooldown = cooldown
        pSkills[sname].isOnCooldown = true
    }
    // check for skills on cooldown
    for (const [skill, properties] of Object.entries(pSkills)) {
        if (properties.isOnCooldown) {
            properties.cooldown--;
            if (properties.cooldown <= 0) {
                properties.isOnCooldown = false;
            }
        }
    }
    // Call the enemy attack function
		EnemyAttack();
}
// Define the enemy attack function
function EnemyAttack(){
    // check if the turn has been passed and the player's health is greater than 0
    if(State.variables.turns > 0 && pCurHp > 0) {
        var enemyDamage = Math.floor(Math.random() * (20 - 10 + 1) + 10);
        pCurHp -= enemyDamage;
        alert("The enemy attacks and dealt " + enemyDamage + " damage to you!");
    }
    // call the function to update the health bar
    window.Health(pCurHp, 100, "HealthBar", true);
      if(pCurHp <= 0){
        Story.go("defeat");
    }
  	if(eCurHp <= 0){
	// navigate the player to the victory passage
		Story.go("victory");
	}
}
window.UseSkill = UseSkill;
window.EnemyAttack = EnemyAttack;

/* The passage in which I'm trying to use the code above */
<div class="row">\
	<<for _slist = 0; _slist < $pSkills.length; _slist++>>\
    	@@.mc;<<link "$pSkills[_slist].sname">><<script>>UseSkill($pSkills[_slist].sname, $pSkills[_slist].minDamage, $pSkills[_slist].maxDamage, $pSkills[_slist].staCost, $pSkills[_slist].cooldown)<</script>><</link>>@@
<</for>></div>\

I am using this with HiEv’s HealthBar code and Josh Grams TinyQBN, though I’m pretty sure I didn’t create any incompatibilities with variables or anything like that. I think.

However, the game starts fine when going to the battlepassage the links/buttons appear fine and display the names correctly. But, attempting to click either of them, I get the following error

Error: <>: bad evaluation: $pSkills is not defined at Function.value

So I’m not quite sure what I’m doing wrong, or if in general as I’m new to a lot of this especially Javascript, if I’m on the right track with this stuff. So if anyone could help me resolve the error and help me get the code on track, I would appreciate it.

Hmm. I didn’t look at this as closely as I should have, but my first guess would be that you need to wrap your <<link>> bit at the end in a <<capture _slist>> because otherwise $pSkills[_slist] will be undefined (since the code behind the link doesn’t get run until you click, _slist will have its final value for all links, which is off the end of the array).

1 Like

As explained by @JoshGrams, you need to use a <<capture>> macro if you want to reference the <<for>> macro’s _slist variable within the body of the <<link>> macro.

You can also use TWEE Notation when supplying a code example that includes content from multiple Passages or Areas of your project. The following is a variation of your own example with the <> macro added so you can see what such an example would look like…

:: Story Javascript [script]
window.UseSkill = function (sname, minDamage, maxDamage, staCost, cooldown) {
	// Check if the player has enough stamina to use the skill
	if (staCost && pCurSta < staCost) {
		alert("You are too tired to do that!");
		return;
	}
	// Generate random damage
	var randomDamage = Math.floor(Math.random() * (maxDamage - minDamage + 1) + minDamage);
	eCurHp -= randomDamage;
	alert("You use " + sname + " and dealt " + randomDamage + " damage to the enemy!");

	// check if the skill has a cooldown
	if (cooldown) {
		pSkills[sname].cooldown = cooldown;
		pSkills[sname].isOnCooldown = true;
	}
	// check for skills on cooldown
	for (const [skill, properties] of Object.entries(pSkills)) {
		if (properties.isOnCooldown) {
			properties.cooldown--;
			if (properties.cooldown <= 0) {
				properties.isOnCooldown = false;
			}
		}
	}
	// Call the enemy attack function
	EnemyAttack();
};

// Define the enemy attack function
window.EnemyAttack = function () {
	// check if the turn has been passed and the player's health is greater than 0
	if (State.variables.turns > 0 && pCurHp > 0) {
		var enemyDamage = Math.floor(Math.random() * (20 - 10 + 1) + 10);
		pCurHp -= enemyDamage;
		alert("The enemy attacks and dealt " + enemyDamage + " damage to you!");
	}
	// call the function to update the health bar
	window.Health(pCurHp, 100, "HealthBar", true);
	if (pCurHp <= 0){
		Story.go("defeat");
	}
	if (eCurHp <= 0){
		// navigate the player to the victory passage
		Story.go("victory");
	}
};

:: StoryInit
<<set $pSkills = []>>
<<set setup.Smash = {
	"sname": "Smash",
	"minDamage": 5,
	"maxDamage": 12,
	"staCost": 5,
	"cooldown": 1,
	"applyRandomDamage": true,
	"isOnCooldown": false
}>>
<<set setup.Fireball = {
	"sname": "Fireball",
	"minDamage": 10,
	"maxDamage": 20,
	"staCost": 20,
	"cooldown": 4,
	"applyRandomDamage": true,
	"isOnCooldown": false
}>>
<<set $pSkills.push(setup.Smash)>>
<<set $pSkills.push(setup.Fireball)>>

:: Start
<<nobr>>
	<div class="row">
		<<for _slist = 0; _slist < $pSkills.length; _slist++>>
			<<capture _slist>>
				@@.mc;<<link `$pSkills[_slist].sname`>><<script>>UseSkill($pSkills[_slist].sname, $pSkills[_slist].minDamage, $pSkills[_slist].maxDamage, $pSkills[_slist].staCost, $pSkills[_slist].cooldown)<</script>><</link>>@@
			<</capture>>
			<br>
		<</for>>
	</div>
<</nobr>>

Now on to some of the other issues in your original example…

1: You are correctly using the special setup object to pre-define static objects that represent the damage types / Skills (eg. Smash & Fireball) in your project, which is a good thing.

However you then store an Object Reference to each of them within an Array based $pSkills Story Variable, which will result in those static objects being stored in the History & Save systems, and that defeats the purpose of defining them on setup.

You should instead be adding an Object Identifier to that $pSkills Array, which you then can use to access the object instance that is stored in setup.
eg.

/* Store the identifier of the Damage type Objects in the Array */
<<set $pSkills.push("Smash")>>
<<set $pSkills.push("Fireball")>>

/* Use that identifier to access the relevant Object in setup. */
Fireball: MinDamage: <<= setup[$pSkills[1]].minDamage >>
=>
Fireball: MinDamage: <<= setup["Fireball"].minDamage >>

2: Now that the $pSkills Array is storing Object Identifiers you can change to the range variation of the <<for>> macro…
(untested example)

<<nobr>>
	<div class="row">
		<<for _skill range $pSkills>>
			<<capture _skill>>
				@@.mc;<<link `setup[_skill].sname`>><<script>>UseSkill(setup[_skill].sname, setup[_skill].minDamage, setup[_skill].maxDamage, setup[_skill].staCost, setup[_skill].cooldown)<</script>><</link>>@@
			<</capture>>
			<br>
		<</for>>
	</div>
<</nobr>>

3: You are passing multiple arguments to the UseSkill() function that are are all being sources from the same Element in the $pSkills Array.

So unless that same function can be called using arguments from other sources then in makes sense to just pass the Object Identifier to the function, and that function can lookup the Damage type / Skill definition itself.
(untested examples)

window.UseSkill = function (ID) {
	/* Lookup the relevent setup object */
	const skill = setup[ID];

	// Check if the player has enough stamina to use the skill
	if (skill.staCost && skill.pCurSta < skill.staCost) {
		alert("You are too tired to do that!");
		return;
	}

	/* rest of code from existing function with skill. added to each variable */
};

…and the Passage code for calling that changed function would now look something like…

<<nobr>>
	<div class="row">
		<<for _skill range $pSkills>>
			<<capture _skill>>
				@@.mc;<<link `setup[_skill].sname`>><<script>>UseSkill(_skill)<</script>><</link>>@@
			<</capture>>
			<br>
		<</for>>
	</div>
<</nobr>>

4: The <<script>> macro doesn’t do variable reference substitution so you should use the <<run>> macro to cakk the UseSkill() function…

<<nobr>>
	<div class="row">
		<<for _skill range $pSkills>>
			<<capture _skill>>
				@@.mc;<<link `setup[_skill].sname`>><<run UseSkill(_skill)>><</link>>@@
			<</capture>>
			<br>
		<</for>>
	</div>
<</nobr>>

note: The main reason many of the above examples are untested is because I don’t have the source code for functions like window.Health(), so I wasn’t able to test my own code without guessing what else was happening.

EDIT: I forgot to use back-quote characters to evaluate the expression being passed to the <<link>> macro call examples. See the Argument type macros: passing an expression as an argument section of the Macro Arguments documentation.

2 Likes

Thank you and Josh for the info taking the time to respond, and especially the detailed steps you’ve given! Appreciate the help! I think I’m understanding it a bit more, but I’m still not quite getting it to work right. I can show everything I have for this in a more complete form. From a new game, trying to get the code right.

:: Story Javascript [script]
/*-----------------------------------------------------------------------------------------*/
/* HiEv Status Bars for player HP and Stamina */
/*-----------------------------------------------------------------------------------------*/
window.Health = function (pCurHp, pMaxHp, BarID, Horizontal, Container) {
	if (Container == undefined) {
		Container = document;
	}
	var HP = parseInt((pCurHp / pMaxHp) * 100).clamp(0, 100);
	var BarElement = $(Container).find("#" + BarID);
	if (Horizontal) {
		BarElement.css({ width: HP + "%" });
	} else {
		BarElement.css({ height: HP + "%" });
	}
  	var col = "hsl(" + (Math.floor(HP * 2.6) - 20) + ", 100%, 50%)";
	BarElement.css("background-color", col);
	BarElement.attr("title", pCurHp + "/" + pMaxHp + " Health");
	$(Container).find("#" + BarID + "bkg").attr("title", pCurHp + "/" + pMaxHp + " Health");
};
window.Stamina = function (pCurSta, pMaxSta, BarID, Horizontal, Container) {
	if (Container == undefined) {
		Container = document;
	}
	var ST = parseInt((pCurSta / pMaxSta) * 100).clamp(0, 100);
	var BarElement = $(Container).find("#" + BarID);
	if (Horizontal) {
		BarElement.css({ width: ST + "%" });
	} else {
		BarElement.css({ height: ST + "%" });
	}
	BarElement.attr("title", pCurSta + "/" + pMaxSta + " Stamina");
	$(Container).find("#" + BarID + "bkg").attr("title", pCurSta + "/" + pMaxSta + " Stamina");
};

/*-----------------------------------------------------------------------------------------*/
/* Enemy Health Bar */
/*-----------------------------------------------------------------------------------------*/
window.EneHealth = function (eCurHp, eMaxHp, BarID, Horizontal, Container) {
	if (Container == undefined) {
		Container = document;
	}
	var EHP = parseInt((eCurHp / eMaxHp) * 100).clamp(0, 100);
	var BarElement = $(Container).find("#" + BarID);
	if (Horizontal) {
		BarElement.css({ width: EHP + "%" });
	} else {
		BarElement.css({ height: EHP + "%" });
	}
  	var cole = "hsl(" + (Math.floor(EHP * 2.6) - 20) + ", 100%, 50%)";
	BarElement.css("background-color", cole);
	BarElement.attr("title", eCurHp + "/" + eMaxHp + " Health");
	$(Container).find("#" + BarID + "bkg").attr("title", eCurHp + "/" + eMaxHp + " Health");
};

/*-----------------------------------------------------------------------------------------*/
/* Skills Function */
/*-----------------------------------------------------------------------------------------*/

window.UseSkill = function (ID) {
	/* Lookup the relevent setup object */
	const skill = setup[ID];
	// Check if the player has enough stamina to use the skill
	if (skill.staCost && skill.pCurSta < skill.staCost) {
		alert("You are too tired to do that!");
		return;
	}
    // Generate random damage
    var randomDamage = Math.floor(Math.random() * (skill.maxDamage - skill.minDamage + 1) + skill.minDamage);
    eCurHp -= randomDamage;
    alert("You use " + skill.sname + " and dealt " + randomDamage + " damage to the enemy!");
    for (const [skill, properties] of Object.entries(pSkills)) {
        if (properties.isOnCooldown) {
            properties.cooldown--;
            if (properties.cooldown <= 0) {
                properties.isOnCooldown = false;
            }
        }
    }
    // Call the enemy attack function
	EnemyAttack();
}
// Define the enemy attack function
function EnemyAttack(){
    // check if the turn has been passed and the player's health is greater than 0
    if(State.variables.turns > 0 && pCurHp > 0) {
        var enemyDamage = Math.floor(Math.random() * (20 - 10 + 1) + 10);
        pCurHp -= enemyDamage;
        alert("The enemy attacks and dealt " + enemyDamage + " damage to you!");
    }
}
window.EnemyAttack = EnemyAttack;

:: StoryInit
<<set $pCurHp to 100>>
<<set $pMaxHp to 100>>
<<set $pCurSta to 100>>
<<set $pMaxSta to 100>>
<<set $eCurHp to 1>>
<<set $eMaxHp to 1>>
<<set $eneAtk = {
	"minDamage" : 4,
        "maxDamage" : 8,
}>>
/* Used for handling player abilities */
<<set $pSkills = []>>
<<set setup.Smash = {
        "sname": "Smash",
        "minDamage": 5,
        "maxDamage": 12,
        "staCost": 5,
        "cooldown": 1,
        "applyRandomDamage": true,
       " isOnCooldown": false,
}>>
<<set setup.Fireball = {
        "sname": "Fireball",
        "minDamage": 10,
        "maxDamage": 20,
        "staCost": 20,
        "cooldown": 4,
        "applyRandomDamage": true,
       " isOnCooldown": false,
}>>
<<set $pSkills.push("Smash")>>
<<set $pSkills.push("Fireball")>>

:: Start
<<set $eCurHp to 25>>
<<set $eMaxHp to 25>>

[[BattleTest]]

:: BattleTest
Health $pCurHp
<div id="healthbarbkg" class="hpbarbkg"><div id="healthbar" class="hpbar"></div></div>
<<script>>$(document).one(':passagerender', function (ev) {
	Health(State.variables.pCurHp, State.variables.pMaxHp, "healthbar", true, ev.content);
});<</script>>
Stamina $pCurSta
<div id="staminabarbkg" class="stabarbkg"><div id="staminabar" class="stabar"></div></div>
<<script>>$(document).one(':passagerender', function (ev) {
	Stamina(State.variables.pCurSta, State.variables.pMaxSta, "staminabar", true, ev.content);
});<</script>>

Enemy Health $eCurHp
<div id="enemybarbkg" class="enebarbkg"><div id="enemybar" class="enebar"></div></div>
<<script>>$(document).one(':passagerender', function (ev) {
	EneHealth(State.variables.eCurHp, State.variables.eMaxHp, "enemybar", true, ev.content);
});<</script>>

<<nobr>>
	<div class="row">
		<<for _skill range $pSkills>>
			<<capture _skill>>
				<<link "setup[_skill].sname">><<run UseSkill(_skill)>><</link>>
			<</capture>>
			<br>
		<</for>>
	</div>
<</nobr>>

<<link "Refresh">><<script>>state.display(state.active.title, null, "back")<</script>><</link>>

Then the stylesheet, since it’s used for the HP/Stamina bars

:: stylesheet
.row {
  display: flex;
  flex-direction: row;
}

.row:after {
  content: "";
  display: table;
  clear: both;
}

/* Health and Stamina Bars */
.hpbarbkg {  
	position: relative;
	height: 15px;
	width: 100%;
	background-color: #111;
	background-image: linear-gradient(to right, rgba(68, 68, 68, 0.5), rgba(34, 34, 34, 0.5) 5px), linear-gradient(to bottom, rgba(68, 68, 68, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to left, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to top, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 10;
	visibility: visible;
}
.hpbar {  
	position: absolute;
	bottom: 0px;
	left: 0px;
	height: 15px;
	background-color: transparent;
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 20;
	transition: width ease 1s, background-color ease 1s;
}
.stabarbkg {  
	position: relative;
	height: 15px;
	width: 100%;
	background-color: #111;
	background-image: linear-gradient(to right, rgba(68, 68, 68, 0.5), rgba(34, 34, 34, 0.5) 5px), linear-gradient(to bottom, rgba(68, 68, 68, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to left, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to top, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 10;
	visibility: visible;
}
.stabar {  
	position: absolute;
	bottom: 0px;
	left: 0px;
	height: 15px;
	background-color: transparent;
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 20;
	transition: width ease 1s, background-color ease 1s;
}
#staminabar {  
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), radial-gradient( circle at bottom right, orange, orange 60% );
}
/* Enemy Health Bar */
.enebarbkg {  
	position: relative;
	height: 15px;
	width: 100%;
	background-color: #111;
	background-image: linear-gradient(to right, rgba(68, 68, 68, 0.5), rgba(34, 34, 34, 0.5) 5px), linear-gradient(to bottom, rgba(68, 68, 68, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to left, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to top, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 10;
	visibility: visible;
}
.enebar { 
	position: absolute;
	bottom: -3px;
	left: -2px;
	height: 15px;
	background-color: transparent;
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	z-index: 20;
  	border-radius: 10px;
	transition: width ease 1s, background-color ease 1s;
}

It tosses the error: Error: <>: bad evaluation: eCurHp is not defined.
So, I’m not sure how to properly let it access that variable in this situation. I’ve tried a couple different ways I’ve seen posted about about initializing the variable in the javascript section to see if that works. But haven’t gotten anything to work for me yet.

note: In TWEE Notation the stylesheet Passage Tag is used to indicate a Passage that contains just CSS. You can name this Passage whatever you like, I generally name it Story Stylesheet as that is the name of the equivalent area in a Twine 2.x application project. So your CSS example would look something like…

:: Story Stylesheet [stylesheet]
.row {
  display: flex;
  flex-direction: row;
}

.row:after {
  content: "";
  display: table;
  clear: both;
}

/* Health and Stamina Bars */
.hpbarbkg {  
	position: relative;
	height: 15px;
	width: 100%;
	background-color: #111;
	background-image: linear-gradient(to right, rgba(68, 68, 68, 0.5), rgba(34, 34, 34, 0.5) 5px), linear-gradient(to bottom, rgba(68, 68, 68, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to left, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to top, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 10;
	visibility: visible;
}
.hpbar {  
	position: absolute;
	bottom: 0px;
	left: 0px;
	height: 15px;
	background-color: transparent;
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 20;
	transition: width ease 1s, background-color ease 1s;
}
.stabarbkg {  
	position: relative;
	height: 15px;
	width: 100%;
	background-color: #111;
	background-image: linear-gradient(to right, rgba(68, 68, 68, 0.5), rgba(34, 34, 34, 0.5) 5px), linear-gradient(to bottom, rgba(68, 68, 68, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to left, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to top, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 10;
	visibility: visible;
}
.stabar {  
	position: absolute;
	bottom: 0px;
	left: 0px;
	height: 15px;
	background-color: transparent;
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 20;
	transition: width ease 1s, background-color ease 1s;
}
#staminabar {  
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), radial-gradient( circle at bottom right, orange, orange 60% );
}
/* Enemy Health Bar */
.enebarbkg {  
	position: relative;
	height: 15px;
	width: 100%;
	background-color: #111;
	background-image: linear-gradient(to right, rgba(68, 68, 68, 0.5), rgba(34, 34, 34, 0.5) 5px), linear-gradient(to bottom, rgba(68, 68, 68, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to left, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to top, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	border-radius: 10px;
	z-index: 10;
	visibility: visible;
}
.enebar { 
	position: absolute;
	bottom: -3px;
	left: -2px;
	height: 15px;
	background-color: transparent;
	background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0) 5px), linear-gradient(to right, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px), linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 5px);
	z-index: 20;
  	border-radius: 10px;
	transition: width ease 1s, background-color ease 1s;
}

1: Your UseSkill() function includes a reference to an underfined eCurHp variable, and that variable was not passed as an argument in the original signature of that function…

function UseSkill(sname, minDamage, maxDamage, staCost, cooldown)

…so it has always been undefined.

As you also have a Story Variable $eCurHp of the same name I will assume that is the variable you are trying to alter the value of, and you will need to use the State.variables object to do that…

window.UseSkill = function (ID) {
	/* Lookup the relevent setup object */
	const skill = setup[ID];
	// Check if the player has enough stamina to use the skill
	if (skill.staCost && skill.pCurSta < skill.staCost) {
		alert("You are too tired to do that!");
		return;
	}
	// Generate random damage
	var randomDamage = Math.floor(Math.random() * (skill.maxDamage - skill.minDamage + 1) + skill.minDamage);
	State.variables.eCurHp -= randomDamage;
	alert("You use " + skill.sname + " and dealt " + randomDamage + " damage to the enemy!");
	for (const [skill, properties] of Object.entries(pSkills)) {
		if (properties.isOnCooldown) {
			properties.cooldown--;
			if (properties.cooldown <= 0) {
				properties.isOnCooldown = false;
			}
		}
	}
	// Call the enemy attack function
	EnemyAttack();
}

2: In the BattleTest Passage you are creating three event listeners that all listen for the same :passagerender event.

Creating three listeners when you only need one is a waste of resources, so delete all three of the existing related <<script>> macro calls and add something like the following to the end of that Passage…

<<script>>
	$(document).one(':passagerender', function (ev) {
		let v = State.variables;
		Health(v.pCurHp, v.pMaxHp, "healthbar", true, ev.content);
		Stamina(v.pCurSta, v.pMaxSta, "staminabar", true, ev.content);
		EneHealth(v.eCurHp, v.eMaxHp, "enemybar", true, ev.content);
	});
<</script>>

3: The “Refresh” link in the BattleTest Passage is using a state.display() function call, and there are two issues with that fact:

3a: The state API used in the 1.x series of SugarCube was replaced with the State API in the 2.x series, notice the uppercase S.

3b. The State.display() function was moved to the Engine API in the 2.5.0 release of SugarCube 2, then was later replaced with the Engine.play() function.

I couldn’t find the documentation for the old state.display() function, and my recall of it is a little fuzzy.

If you want that “Refresh” link to navigate forward to the BattleTest Passage then simply use a Markup based link that does so…

[[Refresh|BattleTest]]

…as that will cause History to be updated with the new values of the changed variables.

If on the other hand you want to dynamically “refresh” what is currently being display by the current Passage then more information is needed to know exactly what parts of the current Passage you want updated.