| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- using UnityEngine;
- using System.Collections;
- public abstract class Weapon : MonoBehaviour
- {
- public string weaponName;
- public string description;
- public int damage;
- public float attackSpeed;
- public GameObject weaponModel; // Assign the 3D model for the weapon
- // Reference to the character wielding this weapon
- public Character Wielder { get; private set; }
- // Track if an attack is currently in progress
- protected bool isAttacking = false;
- public float lastAttackTime { get; private set; }
- // Abstract properties that must be implemented by derived classes
- public abstract int MinDamage { get; }
- public abstract int MaxDamage { get; }
- public abstract int Range { get; }
- public abstract int WeaponModifier { get; set; }
- protected int weaponModifier = 0; // Base modifier for the weapon, can be overridden by subclasses
- protected int baseWeaponModifier = 0; // Base modifier for the weapon, used for calculations
- public float AttackStarted { get; private set; }
- public void SetWielder(Character character)
- {
- Wielder = character;
- if (Wielder == null)
- {
- Debug.LogWarning($"Weapon {weaponName} - SetWielder called with null character!");
- }
- }
- public virtual int GetDamage()
- {
- return UnityEngine.Random.Range(MinDamage, MaxDamage + 1);
- }
- public virtual bool IsInRange(Vector3 attackerPosition, Vector3 targetPosition)
- {
- float distance = Vector3.Distance(attackerPosition, targetPosition);
- return distance <= Range;
- }
- public bool IsAttacking()
- {
- return isAttacking;
- }
- // Method to perform attack - can be called by the character
- public virtual void Attack(GameObject target)
- {
- if (Wielder == null)
- {
- Debug.LogError($"Cannot attack - {weaponName} has no wielder!");
- return;
- }
- if (isAttacking)
- {
- Debug.Log($"attack started {AttackStarted} time now {Time.time}"); ;
- Debug.Log($"{Wielder.CharacterName} is already attacking!");
- return;
- }
- Character targetCharacter = target.GetComponent<Character>();
- if (targetCharacter == null)
- {
- Debug.LogError($"Target {target.name} is not a character!");
- return;
- }
- if (!targetCharacter.IsTargetable)
- {
- Debug.Log($"Cannot attack {targetCharacter.CharacterName} - target is not targetable!");
- return;
- }
- if (!IsInRange(Wielder.transform.position, target.transform.position))
- {
- Debug.Log($"{Wielder.CharacterName} is not in range to attack {targetCharacter.CharacterName} with {weaponName}");
- return;
- }
- AttackStarted = Time.time;
- // Start the attack coroutine
- StartCoroutine(PerformAttackSequence(targetCharacter));
- }
- protected virtual IEnumerator PerformAttackSequence(Character target)
- {
- isAttacking = true;
- lastAttackTime = Time.time;
- Debug.Log($"{Wielder.CharacterName} begins attacking {target.CharacterName} with {weaponName} (attack speed: {attackSpeed}s)");
- // Wait for the attack speed duration
- yield return new WaitForSeconds(attackSpeed);
- // Check if target is still in range after attack speed delay
- if (!IsInRange(Wielder.transform.position, target.transform.position))
- {
- Debug.Log($"{target.CharacterName} moved out of range before {Wielder.CharacterName}'s attack completed!");
- isAttacking = false;
- yield break;
- }
- // Check if target is still targetable (not dead)
- if (!target.IsTargetable)
- {
- Debug.Log($"{target.CharacterName} is no longer targetable!");
- isAttacking = false;
- yield break;
- }
- // Perform hit calculation (d20 + weapon modifier vs target armor class)
- int d20Roll = Random.Range(1, 21);
- int attackRoll = d20Roll + WeaponModifier;
- bool hits = attackRoll >= target.ArmorClass;
- int healthBefore = target.CurrentHealth;
- Debug.Log($"=== ATTACK DEBUG ===");
- Debug.Log($"Attacker: {Wielder.CharacterName} with {weaponName}");
- Debug.Log($"Target: {target.CharacterName}");
- Debug.Log($"D20 Roll: {d20Roll} + Weapon Modifier: {WeaponModifier} = Attack Roll: {attackRoll}");
- Debug.Log($"Target AC: {target.ArmorClass}");
- Debug.Log($"Target Health Before: {healthBefore}/{target.MaxHealth}");
- if (hits)
- {
- int damageDealt = GetDamage();
- Debug.Log($"HIT! Damage Roll: {damageDealt}");
- target.TakeDamage(damageDealt);
- Debug.Log($"Target Health After: {target.CurrentHealth}/{target.MaxHealth}");
- Debug.Log($"{Wielder.CharacterName} hits {target.CharacterName} with {weaponName} for {damageDealt} damage!");
- }
- else
- {
- Debug.Log($"MISS! {attackRoll} < {target.ArmorClass}");
- Debug.Log($"Target Health After: {healthBefore}/{target.MaxHealth} (no change)");
- Debug.Log($"{Wielder.CharacterName} misses {target.CharacterName} with {weaponName}!");
- }
- Debug.Log($"=== END ATTACK ===");
- isAttacking = false;
- }
- }
|