first commit

This commit is contained in:
2026-06-04 23:22:13 +03:00
commit d329f501be
310 changed files with 36395 additions and 0 deletions
@@ -0,0 +1,90 @@
using OTGIntegrated.Combat;
using OTGIntegrated.Stats;
using UnityEngine;
namespace OTGIntegrated.Weapons
{
public sealed class WeaponController : MonoBehaviour
{
public Transform attackOrigin;
public LayerMask hitMask = ~0;
[SerializeField] private float meleeRadius = 0.7f;
private readonly Collider[] hits = new Collider[16];
public bool Attack(WeaponData weapon, PlayerStats stats)
{
if (weapon == null || stats == null)
{
return false;
}
Transform origin = attackOrigin != null ? attackOrigin : transform;
Vector3 start = origin.position + Vector3.up * 0.8f;
Vector3 forward = origin.forward;
forward.y = 0f;
forward = forward.sqrMagnitude > 0.001f ? forward.normalized : transform.forward;
float finalDamage = weapon.damage + stats.Damage;
bool critical = Random.value < stats.CriticalChance;
if (critical)
{
finalDamage *= 1.75f;
}
if (weapon.isRanged)
{
if (Physics.Raycast(start, forward, out RaycastHit hit, weapon.range, hitMask, QueryTriggerInteraction.Ignore))
{
return ApplyDamage(hit.collider, finalDamage, critical);
}
return false;
}
Vector3 center = start + forward * Mathf.Max(0.6f, weapon.range * 0.55f);
int count = Physics.OverlapSphereNonAlloc(center, meleeRadius + weapon.range * 0.12f, hits, hitMask, QueryTriggerInteraction.Ignore);
bool damaged = false;
for (int i = 0; i < count; i++)
{
Collider hit = hits[i];
if (hit == null || hit.transform == transform || hit.GetComponentInParent<PlayerStats>() != null)
{
continue;
}
if (ApplyDamage(hit, finalDamage, critical))
{
damaged = true;
break;
}
}
return damaged;
}
private bool ApplyDamage(Collider collider, float amount, bool critical)
{
Damageable damageable = collider.GetComponentInParent<Damageable>();
if (damageable == null || !damageable.IsAlive)
{
return false;
}
damageable.TakeDamage(amount, gameObject);
if (critical)
{
OTGIntegrated.Core.GameEvents.RaiseNotification("Критический удар");
}
return true;
}
private void OnDrawGizmosSelected()
{
Gizmos.color = new Color(1f, 0.45f, 0.1f, 0.25f);
Transform origin = attackOrigin != null ? attackOrigin : transform;
Gizmos.DrawWireSphere(origin.position + origin.forward * 1.3f + Vector3.up * 0.8f, meleeRadius);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7d25d48e1be8c2d95b45706eb4944524
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+35
View File
@@ -0,0 +1,35 @@
using UnityEngine;
namespace OTGIntegrated.Weapons
{
[CreateAssetMenu(fileName = "WeaponData", menuName = "OTG Integrated/Weapon Data")]
public sealed class WeaponData : ScriptableObject
{
public string weaponId;
public string displayName;
public float damage = 10f;
public float attackRate = 0.8f;
public float range = 2.2f;
public bool isRanged;
public float manaCost;
[TextArea(2, 5)] public string description;
private void OnValidate()
{
if (string.IsNullOrWhiteSpace(weaponId))
{
weaponId = name;
}
if (string.IsNullOrWhiteSpace(displayName))
{
displayName = weaponId;
}
damage = Mathf.Max(0f, damage);
attackRate = Mathf.Max(0.05f, attackRate);
range = Mathf.Max(0.2f, range);
manaCost = Mathf.Max(0f, manaCost);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c307d00ca873da936be63d5e61d7d250
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+186
View File
@@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using OTGIntegrated.Core;
using OTGIntegrated.Items;
using OTGIntegrated.Player;
using OTGIntegrated.Stats;
using UnityEngine;
using UnityEngine.EventSystems;
namespace OTGIntegrated.Weapons
{
[Serializable]
public sealed class WeaponUnlock
{
public ItemData item;
public WeaponData weapon;
}
public sealed class WeaponManager : MonoBehaviour
{
public List<WeaponData> availableWeapons = new List<WeaponData>();
public List<WeaponUnlock> itemUnlocks = new List<WeaponUnlock>();
public WeaponData startingWeapon;
public WeaponController weaponController;
private PlayerStats playerStats;
private PlayerController playerController;
private OTGIntegrated.Inventory.Inventory inventory;
private WeaponData currentWeapon;
private float nextAttackTime;
public WeaponData CurrentWeapon => currentWeapon;
public float CurrentFinalDamage => currentWeapon == null || playerStats == null ? 0f : currentWeapon.damage + playerStats.Damage;
public void Initialize(PlayerStats stats, OTGIntegrated.Inventory.Inventory inventory)
{
playerStats = stats;
this.inventory = inventory;
playerController = GetComponent<PlayerController>();
if (weaponController == null)
{
weaponController = GetComponent<WeaponController>();
}
if (currentWeapon == null)
{
EquipWeapon(startingWeapon != null ? startingWeapon : availableWeapons.Count > 0 ? availableWeapons[0] : null);
}
}
private void OnEnable()
{
GameEvents.OnItemAdded += HandleItemAdded;
}
private void OnDisable()
{
GameEvents.OnItemAdded -= HandleItemAdded;
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && CanAcceptCombatInput())
{
TryAttack();
}
}
public bool EquipWeapon(WeaponData weapon)
{
if (weapon == null)
{
return false;
}
currentWeapon = weapon;
if (!availableWeapons.Contains(weapon))
{
availableWeapons.Add(weapon);
}
GameEvents.RaiseWeaponChanged(currentWeapon);
GameEvents.RaiseNotification($"Оружие: {currentWeapon.displayName}");
return true;
}
public bool TryAttack()
{
if (currentWeapon == null || weaponController == null || playerStats == null)
{
return false;
}
if (Time.time < nextAttackTime)
{
return false;
}
if (currentWeapon.manaCost > 0f && !playerStats.SpendMana(currentWeapon.manaCost))
{
return false;
}
nextAttackTime = Time.time + currentWeapon.attackRate;
bool hit = weaponController.Attack(currentWeapon, playerStats);
if (!hit)
{
GameEvents.RaiseNotification("Атака");
}
return hit;
}
public string SaveData()
{
return currentWeapon != null ? currentWeapon.weaponId : string.Empty;
}
public void LoadData(string weaponId)
{
if (string.IsNullOrWhiteSpace(weaponId))
{
EquipWeapon(startingWeapon);
return;
}
for (int i = 0; i < availableWeapons.Count; i++)
{
WeaponData weapon = availableWeapons[i];
if (weapon != null && weapon.weaponId == weaponId)
{
EquipWeapon(weapon);
return;
}
}
for (int i = 0; i < itemUnlocks.Count; i++)
{
WeaponUnlock unlock = itemUnlocks[i];
if (unlock != null && unlock.weapon != null && unlock.weapon.weaponId == weaponId)
{
EquipWeapon(unlock.weapon);
return;
}
}
}
private void HandleItemAdded(ItemData item, int amount)
{
if (item == null || amount <= 0)
{
return;
}
for (int i = 0; i < itemUnlocks.Count; i++)
{
WeaponUnlock unlock = itemUnlocks[i];
if (unlock != null && unlock.item == item && unlock.weapon != null)
{
EquipWeapon(unlock.weapon);
return;
}
}
}
private bool CanAcceptCombatInput()
{
if (playerController == null)
{
playerController = GetComponent<PlayerController>();
}
if (playerController != null && !playerController.InputEnabled)
{
return false;
}
if (GameManager.Instance != null && GameManager.Instance.uiManager != null && GameManager.Instance.uiManager.IsBlockingGameplay)
{
return false;
}
return EventSystem.current == null || !EventSystem.current.IsPointerOverGameObject();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f116a0ea3320b4ef29761908b1f7a3ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: