fix multiple issues based on recent stat and equipment/drop changes

This commit is contained in:
Pedro Gomes 2025-09-26 20:21:25 +01:00
parent fc204930bb
commit 73000d8cfb
12 changed files with 402 additions and 93 deletions

View File

@ -61,7 +61,7 @@ public class EquippableItemTypeDefinition : ScriptableObject
// Ensure equipmentKey is not empty and follows naming conventions
if (string.IsNullOrEmpty(equipmentKey))
{
equipmentKey = name.Replace(" ", "").Replace("(", "").Replace(")", "");
equipmentKey = name.Replace(" ", "").Replace("(", "").Replace(")", "").ToLower();
}
// Ensure displayName defaults to a readable version of equipmentKey if empty

View File

@ -14529,6 +14529,7 @@ Transform:
- {fileID: 2800905167933415666}
- {fileID: 1867733016440364756}
- {fileID: 7335229491322327302}
- {fileID: 7820666963490671549}
m_Father: {fileID: 7475116341965418816}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &7475116342667879665
@ -17496,6 +17497,53 @@ MonoBehaviour:
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &9218256788198729385
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7820666963490671549}
- component: {fileID: 2669018584948607872}
m_Layer: 0
m_Name: GameObjectPoolingManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7820666963490671549
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9218256788198729385}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7475116342638198534}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2669018584948607872
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9218256788198729385}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1acfd68aaf4b17f4e803c4c4d96f6c61, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::GameObjectPoolManager
poolConfigs: []
showDebugLogs: 0
showPoolStats: 0
--- !u!1001 &100665468315635800
PrefabInstance:
m_ObjectHideFlags: 0

View File

@ -78,7 +78,7 @@ Material:
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _Rotation: 10.59784
- _Rotation: 6.5173087
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1

View File

@ -246,6 +246,7 @@ Transform:
- {fileID: 420608364184142292}
- {fileID: 6271934422900593977}
- {fileID: 4961326857616103880}
- {fileID: 9002944841475030830}
- {fileID: 973730420210444529}
- {fileID: 8393963620684186734}
- {fileID: 8562165150208867301}
@ -455,75 +456,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7ca3982b2d6cbba488bda7bf46c32099, type: 3}
m_Name:
m_EditorClassIdentifier:
Cunning:
statTag: {fileID: 11400000, guid: 5e7fa12b38e5ba44cad020ebc8804748, type: 2}
BaseValue: 0
Flow:
statTag: {fileID: 11400000, guid: 0a3089ca453f0a14696b531656ecad10, type: 2}
BaseValue: 0
Presence:
statTag: {fileID: 11400000, guid: 5ba45103d2ec7e74c99b1e53a70810cd, type: 2}
BaseValue: 0
AttackDamage:
statTag: {fileID: 11400000, guid: 09eb68d1a036a1643b74420197b999bd, type: 2}
BaseValue: 1
SpellDamage:
statTag: {fileID: 11400000, guid: 918ee6f8846e6a9449166ac16b6330ae, type: 2}
BaseValue: 1
AttackSpeed:
statTag: {fileID: 11400000, guid: 836e8572c96c9d64f9ad748d01500018, type: 2}
BaseValue: 0
CritChance:
statTag: {fileID: 11400000, guid: 831eab0f4c8fb69459a620afd95f698f, type: 2}
BaseValue: 3
CritDamage:
statTag: {fileID: 11400000, guid: ad5c133149d9aa641be97f85e426a01f, type: 2}
BaseValue: 50
AuraPower:
statTag: {fileID: 11400000, guid: 44e4512b7be56204580faea713895b3a, type: 2}
BaseValue: 0
MaxHealth:
statTag: {fileID: 11400000, guid: 4242916f0b1bf6e4e8a04bce7028b3f4, type: 2}
BaseValue: 30
HealthRegen:
statTag: {fileID: 11400000, guid: a70c329febb9ee44dae1fefd0cf27f2f, type: 2}
BaseValue: 0
MaxMana:
statTag: {fileID: 11400000, guid: ddf35a6cffc8596479023996fb35f0ac, type: 2}
BaseValue: 100
ManaRegen:
statTag: {fileID: 11400000, guid: 03ad6f3efa4fe124ebd0833927315467, type: 2}
BaseValue: 3
Armor:
statTag: {fileID: 11400000, guid: 9ffd1c81aeea68b4eb6b0f054f0d989f, type: 2}
BaseValue: 1
MagicResistance:
statTag: {fileID: 11400000, guid: 5ff891a32306c504f8f6159f69a1866e, type: 2}
BaseValue: 1
DodgeChance:
statTag: {fileID: 11400000, guid: 625888cd3080b0f4e8660da3da8765a3, type: 2}
BaseValue: 0
BlockChance:
statTag: {fileID: 11400000, guid: 575b03db75017764392e042ddb7a357b, type: 2}
BaseValue: 0
BlockEffectiveness:
statTag: {fileID: 11400000, guid: 14c919138a352e64da794fb96cfadeec, type: 2}
BaseValue: 0
AreaEffectiveness:
statTag: {fileID: 11400000, guid: 847692d8f2a672f49a8932fbf04f0aec, type: 2}
BaseValue: 0
CooldownReduction:
statTag: {fileID: 11400000, guid: bfc7f6dd11d04364aa8560538f97058e, type: 2}
BaseValue: 0
MovementSpeed:
statTag: {fileID: 11400000, guid: a6f35800a90acf64d915a9531d3798b0, type: 2}
BaseValue: 0
ReputationGainIncrease:
statTag: {fileID: 11400000, guid: 94178b288ffb90e44a9c25066831f9b0, type: 2}
BaseValue: 0
GoldCostReduction:
statTag: {fileID: 11400000, guid: 9baf13da92ad0b349ad82ffb56054b9e, type: 2}
BaseValue: 0
showDebugStats: 0
onUpdateStatValues:
m_PersistentCalls:
m_Calls: []
@ -827,6 +760,68 @@ MonoBehaviour:
m_Calls: []
startingOutputModifierPercent: 0
currentOutputModifierPercent: 0
--- !u!1 &2437200879231412815
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 9002944841475030830}
- component: {fileID: 6724482519051982687}
m_Layer: 0
m_Name: EquipmentDropTable
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &9002944841475030830
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2437200879231412815}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1040714684719195969}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6724482519051982687
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2437200879231412815}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: adb6baec1716da0409c4a040454a1a4a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::EquipmentDropTable
dropChance: 15
minTier: 0
maxTier: 2
possibleEquipment:
- equipmentType: {fileID: 11400000, guid: a8b9c44760450794299fcb8e3cd443b3, type: 2}
weight: 1
lowestPossibleDifficulty: 0
highestPossibleDifficulty: 6
- equipmentType: {fileID: 11400000, guid: 9044a1de874c1294bbd261141af44093, type: 2}
weight: 1
lowestPossibleDifficulty: 0
highestPossibleDifficulty: 6
coinPrefab: {fileID: 7706952695029526538, guid: b0bce3e9bc0755445abb649e0c306c79, type: 3}
coinAmount: 12
onCoinDrop: {fileID: 11400000, guid: 48da3b1185c086c4c81a2b97ab7685fc, type: 2}
equipmentDropPrefab: {fileID: 7187375229850072788, guid: 6067f5d34154eb3498e9a5fdfcee4b00, type: 3}
usePlayerLevel: 1
fixedLevel: 1
--- !u!1 &2748734579092027444
GameObject:
m_ObjectHideFlags: 0
@ -5928,7 +5923,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!4 &4961326857616103880
Transform:
m_ObjectHideFlags: 0
@ -5962,15 +5957,7 @@ MonoBehaviour:
coinAmount: 12
extraDropChance: 10
onCoinDrop: {fileID: 11400000, guid: 48da3b1185c086c4c81a2b97ab7685fc, type: 2}
guaranteedItemDrop: []
guaranteedOnlyOnePerKill: []
extraDrops:
- {fileID: 11400000, guid: 26b042abfe9104448a1e9599be66e71a, type: 2}
- {fileID: 11400000, guid: e08687c26614d154cb5a9a01f4b97635, type: 2}
- {fileID: 11400000, guid: bf5ebc199ded3fa48872c4a1caeba0b2, type: 2}
- {fileID: 11400000, guid: 753401cb84e3c5c4ebaef324c0399eb0, type: 2}
- {fileID: 11400000, guid: 60a432442ce35934eb0a7170f0a113f0, type: 2}
- {fileID: 11400000, guid: e2c921ce12afad24f8780b0b7555cb0b, type: 2}
nonEquippablesDrops: []
weightedDropLootTable:
- drop: {fileID: 11400000, guid: 7520aac8c5a8a1f469cf449dc9678082, type: 2}

View File

@ -12,7 +12,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 97c2864d727cc3f4485dcd520d9b2793, type: 3}
m_Name: Helmet
m_EditorClassIdentifier: Assembly-CSharp::EquippableItemTypeDefinition
equipmentKey: Helmet
equipmentKey: helmet
displayName: Helmet
shortName: Helmet
description:

View File

@ -12,7 +12,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 97c2864d727cc3f4485dcd520d9b2793, type: 3}
m_Name: Shoulder
m_EditorClassIdentifier: Assembly-CSharp::EquippableItemTypeDefinition
equipmentKey: Shoulder
equipmentKey: shoulder
displayName: Shoulder
shortName: Shoulder
description:

View File

@ -0,0 +1,268 @@
using Kryz.CharacterStats.Examples;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
[System.Serializable]
public class WeightedEquipmentType
{
public EquippableItemTypeDefinition equipmentType;
public float weight = 1f;
public DifficultyLevels lowestPossibleDifficulty = DifficultyLevels.E;
public DifficultyLevels highestPossibleDifficulty = DifficultyLevels.SS;
public int LowestDifficultyDrop => (int)lowestPossibleDifficulty;
public int HighestDifficultyDrop => (int)highestPossibleDifficulty;
}
public class EquipmentDropTable : MonoBehaviour
{
[Header("Drop Settings")]
[SerializeField] private int dropChance = 50; // Percentage chance to drop equipment
[SerializeField] private EquippableItemGenerator.ItemTier minTier = EquippableItemGenerator.ItemTier.Common;
[SerializeField] private EquippableItemGenerator.ItemTier maxTier = EquippableItemGenerator.ItemTier.Rare;
[Header("Equipment Types")]
[SerializeField] private List<WeightedEquipmentType> possibleEquipment = new List<WeightedEquipmentType>();
[Header("Coin Drop")]
[SerializeField] private GameObject coinPrefab;
[SerializeField] private int coinAmount = 10;
[SerializeField] private GameEvent_Int onCoinDrop;
[Header("Prefabs")]
[SerializeField] private GameObject equipmentDropPrefab; // Should have EquippableItemDrop component
[Header("Level Scaling")]
[SerializeField] private bool usePlayerLevel = true;
[SerializeField] private int fixedLevel = 1;
public void DropLoot()
{
Vector3 dropPosition = transform.position;
dropPosition.y = 0f;
// Always drop coins
DropCoins(dropPosition);
// Roll for equipment drop
if (ShouldDropEquipment())
{
DropRandomEquipment(dropPosition);
}
}
private void DropCoins(Vector3 position)
{
if (coinPrefab == null) return;
GameObject coinDrop = Instantiate(coinPrefab, position, transform.rotation);
CoinDrop coinDropComponent = coinDrop.GetComponent<CoinDrop>();
if (coinDropComponent != null)
{
// Apply difficulty scaling if available
int finalAmount = coinAmount;
if (GameDifficultyController.Instance != null)
{
finalAmount = Mathf.RoundToInt(coinAmount * (1 + GameConstants.GameBalancing.IncreasedCoinDropBasedOnDifficultyMultiplier * GameDifficultyController.Instance.GetCurrentDifficultyLevel()));
}
coinDropComponent.Init(finalAmount);
onCoinDrop?.Raise(finalAmount);
}
}
private bool ShouldDropEquipment()
{
if (possibleEquipment.Count == 0) return false;
// Apply difficulty scaling to drop chance if available
float finalDropChance = dropChance;
if (GameDifficultyController.Instance != null)
{
finalDropChance *= (1 + GameConstants.GameBalancing.IncreasedItemDropBasedOnDifficultyMultiplier * GameDifficultyController.Instance.GetCurrentDifficultyLevel());
}
return Random.Range(0f, 100f) < finalDropChance;
}
private void DropRandomEquipment(Vector3 position)
{
// Select random equipment type based on weights
EquippableItemTypeDefinition selectedType = GetRandomWeightedEquipmentType();
if (selectedType == null) return;
// Generate random tier within range
EquippableItemGenerator.ItemTier randomTier = GetRandomTier();
// Determine item level
int itemLevel = usePlayerLevel ? GetPlayerLevel() : fixedLevel;
// Generate the item using your existing generator
EquippableItemInstance generatedItem = EquippableItemGenerator.Instance.GenerateFromEquipmentType(
selectedType,
randomTier,
itemLevel
);
// Create the interactable drop
SpawnEquipmentDrop(generatedItem, position);
Debug.Log($"Dropped {randomTier} {selectedType.GetDisplayName()} (Level {itemLevel})");
}
private EquippableItemTypeDefinition GetRandomWeightedEquipmentType()
{
int currentDifficulty = GameDifficultyController.Instance?.GetCurrentDifficultyLevel() ?? 0;
// Filter equipment types for current difficulty and null checks
var validEquipment = possibleEquipment.Where(e =>
e.equipmentType != null &&
e.LowestDifficultyDrop <= currentDifficulty &&
e.HighestDifficultyDrop >= currentDifficulty
).ToList();
if (validEquipment.Count == 0)
{
Debug.LogWarning($"No equipment available for difficulty level {currentDifficulty}");
return null;
}
// Calculate total weight for valid equipment
float totalWeight = validEquipment.Sum(e => e.weight);
if (totalWeight <= 0)
{
// If no weights, pick randomly from valid equipment
return validEquipment[Random.Range(0, validEquipment.Count)].equipmentType;
}
// Weighted random selection
float randomValue = Random.Range(0f, totalWeight);
float currentWeight = 0f;
foreach (var equipment in validEquipment)
{
currentWeight += equipment.weight;
if (randomValue <= currentWeight)
{
return equipment.equipmentType;
}
}
return validEquipment[0].equipmentType; // Fallback
}
private EquippableItemGenerator.ItemTier GetRandomTier()
{
int minTierValue = (int)minTier;
int maxTierValue = (int)maxTier;
int randomTierValue = Random.Range(minTierValue, maxTierValue + 1);
return (EquippableItemGenerator.ItemTier)randomTierValue;
}
private void SpawnEquipmentDrop(EquippableItemInstance item, Vector3 position)
{
if (equipmentDropPrefab == null)
{
Debug.LogError("Equipment drop prefab is not assigned!");
return;
}
GameObject dropObject = Instantiate(equipmentDropPrefab, position, transform.rotation);
EquippableItemDrop dropComponent = dropObject.GetComponent<EquippableItemDrop>();
if (dropComponent != null)
{
dropComponent.itemDrop = item;
}
else
{
Debug.LogError("Equipment drop prefab doesn't have EquippableItemDrop component!");
Destroy(dropObject);
}
}
private int GetPlayerLevel()
{
// Replace this with your actual player level system
// For example: return PlayerController.Instance.Level;
return 1; // Placeholder
}
#region Editor Testing
[ContextMenu("Test Drop")]
private void TestDrop()
{
if (Application.isPlaying)
{
DropLoot();
}
else
{
Debug.Log("Test drop only works in play mode");
}
}
[ContextMenu("Validate Setup")]
private void ValidateSetup()
{
int issues = 0;
int currentDifficulty = GameDifficultyController.Instance?.GetCurrentDifficultyLevel() ?? 0;
if (possibleEquipment.Count == 0)
{
Debug.LogWarning("No equipment types configured");
issues++;
}
int validForCurrentDifficulty = 0;
foreach (var equipment in possibleEquipment)
{
if (equipment.equipmentType == null)
{
Debug.LogWarning("Found null equipment type reference");
issues++;
}
else if (equipment.LowestDifficultyDrop <= currentDifficulty &&
equipment.HighestDifficultyDrop >= currentDifficulty)
{
validForCurrentDifficulty++;
}
}
if (validForCurrentDifficulty == 0 && possibleEquipment.Count > 0)
{
Debug.LogWarning($"No equipment types are valid for current difficulty level {currentDifficulty}");
issues++;
}
if (equipmentDropPrefab == null)
{
Debug.LogWarning("Equipment drop prefab not assigned");
issues++;
}
else if (equipmentDropPrefab.GetComponent<EquippableItemDrop>() == null)
{
Debug.LogWarning("Equipment drop prefab missing EquippableItemDrop component");
issues++;
}
if (coinPrefab == null)
{
Debug.LogWarning("Coin prefab not assigned");
issues++;
}
if (issues == 0)
{
Debug.Log($"Equipment drop table setup is valid! {validForCurrentDifficulty} equipment types available for current difficulty.");
}
else
{
Debug.LogWarning($"Found {issues} setup issues");
}
}
#endregion
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: adb6baec1716da0409c4a040454a1a4a

View File

@ -44,15 +44,17 @@ public class Health : Resource
absorbEffectInstance = GetComponent<AbsorbEffectInstance>();
damageIncomeModifierEffectInstance = GetComponent<DamageIncomeModifierEffectInstance>();
baseRegenValue = character.GetStat("healthregen").BaseValue;
baseMaxValue = character.GetStat("maxhealth").BaseValue;
character.onAllStatsUpdated.AddListener(CalculateMaxValueBasedOnStat);
}
protected override void Start()
{
baseRegenValue = character.GetStat("healthregen").BaseValue;
baseMaxValue = character.GetStat("maxhealth").BaseValue;
base.Start();
}

View File

@ -28,7 +28,7 @@ public class EquippableItemGenerator : MonoBehaviour
{
if (_instance == null)
{
_instance = FindObjectOfType<EquippableItemGenerator>();
_instance = FindFirstObjectByType<EquippableItemGenerator>();
}
return _instance;
}

View File

@ -20,15 +20,16 @@ public class Mana : Resource
{
character = GetComponent<CharacterStats>();
baseRegenValue = character.GetStat("manaregen").BaseValue;
baseMaxValue = character.GetStat("maxmana").BaseValue;
character.onAllStatsUpdated.AddListener(CalculateMaxValueBasedOnStat);
}
protected override void Start()
{
baseRegenValue = character.GetStat("manaregen").BaseValue;
baseMaxValue = character.GetStat("maxmana").BaseValue;
base.Start();
}

View File

@ -7,20 +7,21 @@ public class BasicEnemyNPCController : NPCControllerBase
[Header("Events:")]
[SerializeField] protected GameEvent_Float experienceOnDeath;
protected DropTable dropTable;
//protected DropTable dropTable;
protected EquipmentDropTable dropTable;
protected override void Awake()
{
dropTable = GetComponentInChildren<DropTable>();
dropTable = GetComponentInChildren<EquipmentDropTable>();
base.Awake();
}
protected override void OnDeath()
{
RPC_OnDeath(dropTable.CalculateLootDrop());
RPC_OnDeath(false);
}
protected override void RPC_OnDeath(bool lootDropped)
protected override void RPC_OnDeath(bool deprecated)
{
if (isDead) return;
@ -32,7 +33,7 @@ public class BasicEnemyNPCController : NPCControllerBase
experienceOnDeath.Raise(health.GetMaxValue() * GameConstants.GameBalancing.HealthIntoExperienceMultiplier);
dropTable.DropLoot(lootDropped);
dropTable.DropLoot();
animatorController.SetDead();
}