# Function Not Storing New Value of Variables?

I'm currently building a small-scope RPG and running into an issue with modifying variables. My goal is to alter my character's stats when I run a procedure to change their equipment. My code is as follows:

public class Player: MonoBehaviour   {
//Base stat variables
public static int PAtk = 12;
public static int PDef = 6;
//Battle-exclusive stats.  Will have equipment added onto them.
public static int Attack = PAtk;
public static int Defense = PDef;
//Equipment variables.
public string weapon;
public string armor;

private void Awake()
{
//Get equipment
EquipWeapon("Bronze Sword");
EquipArmor("Bronze Armor");
}

void EquipWeapon(string WeaponName)
{
weapon = WeaponName;
EquipmentManager.GetComponent<Equipment>().EquipStatIncrease(PAtk, Attack, PDef, Defense, WeaponName);
}
void EquipArmor(string ArmorName)
{
armor = ArmorName;
EquipmentManager.GetComponent<Equipment>().EquipStatIncrease(PAtk, Attack, PDef, Defense, ArmorName);
}
}

public class Equipment: MonoBehaviour  {
//Create dictionary to give each weapon a key ID.  This will be used for calling items in another array.
Dictionary<string, int> WeaponDictionary = new Dictionary<string, int>();
//Create weapon array for stats.
public int[,] WeaponStats;

// Start is called before the first frame update
void Awake()
{   //Declare weapon IDs
//Declare stat array
//Table: ID, Atk, Def
WeaponStats = new int[,]
{
{0,4,0},
{1,0,4}
};
}

public void EquipStatIncrease(int BaseAtk, int BattleAtk, int BaseDef, int BattleDef, string Equipment)
{
BattleAtk = BaseAtk + WeaponStats[WeaponDictionary[Equipment], 1];
Debug.Log(BattleAtk + "Battle Power");
BattleDef = BaseDef + WeaponStats[WeaponDictionary[Equipment], 2];
Debug.Log(BattleDef + "Battle Defense");
}
}


The general gist of it is once EquipWeapon or EquipArmor is ran, the equipment variables in the Player class will be updated. Afterwards, another function in the Equipment class will be ran with variables from the Player class passed over, in order to be modified by the WeaponStats array.

The Debug logs in EquipStatIncrease show me that I am getting the desired results. However, the Attack parameter that is being placed into the function is not being permanently modified. During the first execution of the EquipStatIncrease method, I will get a result of 16 BattleAtk and 6 BattleDef, due to the weapon being equipped. However, once it's run a second time to equip the armor, I'm shown a result of 12 BattleAtk and 10 BattleDef, even though BattleAtk should have stayed at 16. This leads me to believe that the variables I'm trying to transform are not being modified, and I'm not sure what to do about this. In the EquipStatIncrease parameters, BattleAtk gives the message Parameter 'BattleAtk' can be removed if it is not part of a shipped public API; its initial value is never used However, I don't know what action to take to resolve this.

I'm aware of being able to use an int function instead of void, but unless I'm missing something, that only works if I'm trying to change one variable. If I want to have an equipment object that affects 2 different stats at once(ex. a weapon that increases BattleAtk and BattleDef), then I don't see how an int function would work.

You are only modifying the local copy of the parameter. This happens, because an int is a value type. You must pass a reference type to your method. Pass it the player itself. A class is a reference type and a variable or parameter of a reference type contains a reference to the object, not a copy of the object.

public void EquipStatIncrease(Player player, string equipment)
{
player.Attack = player.PAtk + WeaponStats[WeaponDictionary[equipment], 1];
...
}


call it with

EquipmentManager.GetComponent<Equipment>().EquipStatIncrease(this, WeaponName);


Where I assume that you are calling this inside the player class.

Okay, I just saw that you have declared the fields as static in player. This means that these values will be the same for all the players. If this was your intent, leave it like this, otherwise use instance fields. You can access static fields through the type name: Player.PAtk (and don't need a reference).

If PAtk and PDef are not changing, you could declare them as const (constants are automatically static): public const int PAtk = 12, PDef = 6;

If all the fields used in EquipStatIncrease are static, you not even need the player parameter.

public void EquipStatIncrease(string equipment)
{
Player.Attack = Player.PAtk + WeaponStats[WeaponDictionary[equipment], 1];
...
}


Another way of handling it is to pass the variables to be changed by reference, either with the ref or the out keyword (there is also an in keyword, but doesn't help here). Use ref you want to pass the variable in and out, e.g. if you want to increment it. Use the out keyword if you want to assign it a value by ignoring its old value.

public void EquipStatIncrease(
int BaseAtk, ref int BattleAtk, int BaseDef, ref int BattleDef, string Equipment)
{ ... }


you must use the ref (or out) keyword at the call sites too:

EquipmentManager.GetComponent<Equipment>()
.EquipStatIncrease(PAtk, ref Attack, PDef, ref Defense, WeaponName);

• Thank you for the detailed response! I'm not as familiar with value/reference types as I should be, and this helped put a lot of things into clarity. Same with when to use static variables. Your use of this was very interesting and gave me some ideas. Truth be told, I had discovered that the Attack value was also resetting for a different reason. EquipStatIncrease is called twice, and Player.Attack's value was redeclared, but the dictionary call had added a value of 0, negating the work of the 1st call. Don't know if this was the sole cause. Thanks again! Dec 27, 2020 at 1:01