After this lesson, even with shouldUseModifiers set to True on my enemies, they no longer get the weapon modifiers added to them? Is this a bug? Adressed later?
Thank you for any responses, appreciate it.
After this lesson, even with shouldUseModifiers set to True on my enemies, they no longer get the weapon modifiers added to them? Is this a bug? Adressed later?
Thank you for any responses, appreciate it.
This is because the IModifierProvider was removed from the Fighter script.
Sam’s original design assumed that the enemies would never need modifiers, but this isn’t the way everybody necessarily wants to do things. IModifierProvider was removed from Fighter because the WeaponConfig is already in the StatsEquipment which will provide the modifiers.
You can add the IModifierProvider back into Fighter, and start the GetAdditiveModifiers and GetPercentageModifiers IEnumerables with this line:
if(gameObject.CompareTag("Player")) yield break;
This will prevent the player from getting double modifiers for having the weapon in the StatsInventory and also in Fighter.
Thanks, will try this in a bit!
EDIT: Seems to have solved it, thank you! And this shouldn’t mess with the player weapon bonuses at all, right?
This is my current code in the Fighter script:
public IEnumerable<float> GetAdditiveModifiers(Stat stat)
{
if (gameObject.CompareTag("Player")) { yield break; }
if (stat == Stat.Damage)
{
yield return currentWeaponConfig.GetDamage();
}
}
public IEnumerable<float> GetPercentageModifiers(Stat stat)
{
if (gameObject.CompareTag("Player")) { yield break; }
if (stat == Stat.Damage)
{
yield return currentWeaponConfig.GetPercentageBonus();
}
}
Thank you!
But it is on the WeaponConfig.cs, where we configured our weapons with. I’m experiencing the same issue:
shouldUseModifiers
is enabled, neither the player nor the enemies use them, but are when I as a player pick up the same weapon via pickup.
The problem occurs both in my project and in the final project I downloaded from the dialogue course. I am not able to diagnose the problem, but to solve it if I make some kind of bridge from a MonoBehavior to this Scriptable Object, but this is not necessary when it works as a pickup. By the way this Bridge (Script):
using RPG.Combat;
using System.Collections.Generic;
using UnityEngine;
namespace RPG.Stats
{
public class WeaponModifierProvider : MonoBehaviour, IModifierProvider
{
[SerializeField] WeaponConfig weaponConfig;
public WeaponConfig WeaponConfig { set { weaponConfig = value; } }
public IEnumerable<float> GetAdditiveModifiers(Stat stat)
{
return weaponConfig.GetAdditiveModifiers(stat);
}
public IEnumerable<float> GetPercentageModifiers(Stat stat)
{
return weaponConfig.GetPercentageModifiers(stat);
}
}
}
// And remove the IModifierProvider from the WeaponConfig.cs
public class WeaponConfig : EquipableItem //, removed IModifierProvider
// And over in the Fighter Script, subscribing to it when we equip a new weapon:
public void EquipWeapon(WeaponConfig weapon)
{
currentWeaponConfig = weapon;
currentWeapon.value = AttachWeapon(weapon);
if (TryGetComponent<WeaponModifierProvider>(out var weaponModifierProvider))
{
weaponModifierProvider.WeaponConfig = weapon;
}
}
While it -=is=- on the WeaponConfig, ScriptableObjects aren’t caught up automagically by the GetComponents<IModifierProvider>()
call. Nor should they be because the relationship is many Fighter/Equipment to one WeaponConfig. We’re only interested in the WeaponConfig if it’s equipped, and the only way to get at that is through the StatsEquipment or the Fighter.
Since our enemies don’t have a StatsEquipment, we need to get at the data through the Fighter.
Not a bit because if it’s on the Player, the method will just gracefully exit.
Well, if I put this little print statement into BaseStat.cs, I don’t expect to find my WeaponConfig.cs
in there, since it’s not a component attached to the player:
if (gameObject.CompareTag("Player") && stat == Stat.Damage) { foreach (var x in GetComponents<IModifierProvider>()) print(x); }
But what I do not understand is why I still get modifiers after my equipment has been updated? So when this call is made in the Fighter.cs
, because initially without this call, I do not:
void UpdateWeapon()
{
var weaponConfig = equipment.GetItemInSlot(EquipLocation.Weapon) as WeaponConfig;
if (weaponConfig != null)
{
EquipWeapon(weaponConfig);
Debug.Log("Type of weaponConfig: " + weaponConfig.GetType());
}
else
{
EquipWeapon(defaultWeapon);
}
}
Is it because we’re retrieving it from a MonoBehaviour
, from the Equipment
class?
This is my WeaponConfig.cs
:
public class WeaponConfig : EquipableItem, IModifierProvider
{
// ...
// Not working when Weapons set in the inspector - Bug
public IEnumerable<float> GetAdditiveModifiers(Stat stat)
{
if (stat == Stat.Damage)
{
Debug.Log("Call");
yield return weaponDamage;
}
}
public IEnumerable<float> GetPercentageModifiers(Stat stat)
{
if (stat == Stat.Damage)
{
yield return percentageBonus;
}
}
This Debug.Log
also only gets executed, when retrieving it from the Equipment
class
Without the ,IModifierProvider interface declaration on the Fighter, the WeaponConfig’s GetAdditiveModifiers and GetPercentageModifiers will never be returned from Fighter because Fighter won’t be gathered in a GetComponents<IModifierProvider>()
call.
However, if you have a StatsEquipment on your character and your Fighter does have an IModifierProvider interface declaration, then the WeaponConfig would be getting called twice, once from within the GetxModifiers call in StatsEquipment and once within the GetxModifiers call in Fighter. This is why Sam had the interface call removed from Fighter, to prevent this.
If, however, you want the enemies to get modifiers, then Fighter needs the interface, and we have to put a check within Fighter to prevent the modifiers from being returned a second time in the case that this is a player.
I must admit, I’ve been quite perplexed by that. It’s clear now that we’re directly invoking the modifiers in the WeaponConfig
from StatsEquipment
, a script I missed as I got lost in the amount of scripts we have (It might want to consider reorganizing them for better clarity )… Ironically, I had the RPG.Inventories.StatsEquipment
output in the console, yet I didn’t connect the dots when the number of calls remained consistent before & after equipping weapons through the UI. I mistakenly attributed this to another cause.
Initially, I was under the impression that the problem stemmed from attempting to access a Scriptable Object as if it were a component, which led me to erroneously suspect the following line of code, given that Equipment is a MonoBehaviour:
var weaponConfig = equipment.GetItemInSlot(EquipLocation.Weapon) as WeaponConfig;
However, that simply couldn’t be. I acknowledge my error and sincerely apologize for any confusion caused. I’m grateful for your patience as I have navigated through this misunderstanding.
However, Unarmed is not an EquipableItem
, so its modifiers are never used
Unarmed should be a WeaponConfig, actually. All WeaponConfigs are through inheritance also EquipableItems. It should also have an empty WeaponModel (as in no actual rendered mesh, just a GameObject with hit effect sounds.
I know, but not in the context of equipping & using its modifiers.
I also don’t see the point of using its modifiers. In case we insist on using it, then as for our current inventory system, over in StatsEquipment
, iterate over all slots, not just the populated slots, check if the item in the weapon slot is null & assign the default weapon (Unarmed or whatever you have) to it instead.
The Fighter should already be doing this (though it doesn’t put the weapon in the StatsEquipment… without a great deal of additional code, putting the default SO in the StatsEquipment is the source of a major item duplication bug.
But not for the player, it deals the damage modelled in the progression.
Enemies use modifiers for each weapon they have equipped, as there is no condition as to whether a weapon is equipped in the equipment inventory or not.
Without additional code, the player is not using the modifiers if nothing is equipped.
I love solving corner cases. Try this:
public IEnumerable<float> GetAdditiveModifiers(Stat stat)
{
if (gameObject.CompareTag("Player") && currentWeaponConfig!=defaultWeapon) { yield break; }
if (stat == Stat.Damage)
{
yield return currentWeaponConfig.GetDamage();
}
}
public IEnumerable<float> GetPercentageModifiers(Stat stat)
{
if (gameObject.CompareTag("Player") && currentWeaponConfig!=defaultWeapon) { yield break; }
if (stat == Stat.Damage)
{
yield return currentWeaponConfig.GetPercentageBonus();
}
}
I prefer not to use it as it often leads to hard coding, which can detract from the aesthetics of the code. I strive to maintain a level of generality in my coding practices whenever feasible.
However as I mentioned earlier, using a modifier for something that isn’t equipped, in this case a weapon, so fighting with bare hands, what’s the objective? I mean, we can use traits to increase strength.
What if, with your suggestion, we want to use modifiers for everything that isn’t currently equipped? Boots, trousers, shield, etc.? - We’d have to make that if-statement quite a bit more & I’m not saying my suggestion is better in any way, just pointing it out that we do not need a corner case for this one
Generally, I bake in the stats of unequipped slots into the Progression class in the first place. You generally don’t start a game with a Healthy Hat or a BreastPlate of Righteousness. I was only addressing your concern about the player not using the modifiers on the default weapon. As the default weapon is usually unarmed, I tend not to worry about the player’s fighter not picking up stat bonuses.
Not my concern, I just mentioned it when you replied to me with that:
And I agree with you that we should model it in the progression class & I’m not worried about any modifiers for unequipped slots either.
However, we got the main objective sorted out now
This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.