My RPG attack function seems to only work once each for the player and enemy.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Spiky_Potato

So I am coding a prototype for my game to get a test model and to mess around with battle mechanics before I commit to a full dive. There have definitely been hurdles but I’ve managed to overcome all of them up till now.

The code I’m using to tell the game to attack a target(Either the player or enemy) seems to only work once for each target and then stops working altogether.

Below is my BattleHandler Script for any who wants to brave the answer:

extends Node
onready var ActionButtons = $UI/ActionButtons
onready var Victory = $UI/Victory
onready var Enemy = $Enemy
signal end_turn

# Player Initialization
var JobData = load("res://Jobs/Base Jobs/Squire.tres")
var WeaponData = load("res://Items/Weapons/Squire's Sword.tres")
var ArmorData = load("res://Items/Armors/Tweed Tunic.tres")
var PlayerHealth = 0
var PlayerAttackStat = WeaponData.BaseAttack + JobData.Strength
var PlayerDefenseStat = ArmorData.BaseDefense + JobData.Vitality

# Enemy Initialization
signal EnemyDefeated
var EnemyData = load("res://Enemies/Gellie.tres")
var EnemyHealth = 0
var EnemyAttackStat = EnemyData.BaseAttack + EnemyData.Strength
var EnemyDefenseStat = EnemyData.BaseDefense + EnemyData.Vitality

# Battle Functions
func SetHealth(Target, TargetLabel):
    TargetLabel.value = Target

func Attack(Damage, Target, TargetLabel):
    Target = Target - Damage
    SetHealth(Target, TargetLabel)
    emit_signal("end_turn")

func _ready():
    Victory.hide()
    EnemyHealth = EnemyData.MaxHealth
    SetHealth(EnemyHealth, $Enemy/Health)
    PlayerHealth = JobData.MaxHealth
    SetHealth(PlayerHealth, $Player/Health)
    StartPlayerTurn()

func StartEnemyTurn():
    ActionButtons.hide()
    if EnemyHealth <= 0:
	    emit_signal("EnemyDefeated")
	    VictoryScreen()
	    pass
    if EnemyData != null:
	    yield(get_tree().create_timer(0.4),"timeout")
	    Attack(3, PlayerHealth, $Player/Health)
    StartPlayerTurn()

func StartPlayerTurn():
    ActionButtons.show()
    yield(self, "end_turn")
    StartEnemyTurn()

func _on_AttackButton_pressed():
    Attack(3, EnemyHealth, $Enemy/Health)

func VictoryScreen():
    EnemyData = null
    Enemy.hide()
    Victory.show()
:bust_in_silhouette: Reply From: hilfazer

I had a look at the code and i think your functions do get called as expected.

The problem is your EnemyHealth and PlayerHealth variables are not modified after you set them in _ready().
Integer variable (i’m assuming your vars are still int after _ready) are passed by value, not by reference.

What you can do is make your Attack function calculate and return new Health value and then assign that value to either PlayerHealth or EnemyHealth. Something like this (the function can now be static so i made is such):

static func Attack(Damage, Target):
    return Target - Damage

and use it like this

if EnemyData != null:
        yield(get_tree().create_timer(0.4),"timeout")
        PlayerHealth = Attack(3, PlayerHealth)
        SetHealth(PlayerHealth, $Player/Health)
        emit_signal("end_turn")

Hmmm, didn’t even occur to me to do that, thanks so much mate. I ended up reworking the whole script out of frustration and it works now, but I will definitely remember this for if I encounter this problem again. Thanks for the help.

Spiky_Potato | 2021-09-06 16:31