using VeloBrawl.General.NetIsland.LaserBattle.Objects.Laser; using VeloBrawl.Titan.DataStream; using VeloBrawl.Titan.Mathematical; using VeloBrawl.Titan.Mathematical.Data; using VeloBrawl.Tools.LaserCsv; using VeloBrawl.Tools.LaserCsv.Manufacturer.Laser; namespace VeloBrawl.General.NetIsland.LaserBattle.Significant; public class LogicSkillServer { private readonly LogicBattleModeServer _logicBattleModeServer; private readonly LogicSkillData _logicSkillData; private readonly int _maxCharge; private int _activeTime; private int _charge; private int _cooldownValue; private LogicVector2 _logicVector2 = new(); private int _tick; private LogicCharacterServer? _owner; public LogicSkillServer(LogicBattleModeServer logicBattleModeServer, int classId, int instanceId) { _logicBattleModeServer = logicBattleModeServer; _logicSkillData = ((LogicSkillData?)LogicDataTables.GetDataById(GlobalId.CreateGlobalId(classId, instanceId)))!; _tick = 0; _maxCharge = LogicMath.Max(1000, 1000 * _logicSkillData.GetMaxCharge()); _charge = _maxCharge; } public void Tick() { if (_charge < _maxCharge && !(_tick < _activeTime) && _logicSkillData.GetMaxCharge() != 0) { _charge += 1000 / (_logicSkillData.GetRechargeTime() / 50); _charge = LogicMath.Min(_maxCharge, _charge); } if (_tick < _activeTime) _tick++; } public bool BlockedForCastType(bool v2) { if (v2) return _tick < _activeTime; if (_tick == 0) return _logicSkillData.GetExecuteFirstAttackImmediately(); return _tick % (_logicSkillData.GetMsBetweenAttacks() / 50) == 0; } public bool Activate(bool wasReturn, LogicVector2 logicVector2) { _logicVector2 = logicVector2; if (_charge <= 1000 && _logicSkillData.GetMaxCharge() != 0) return false; if (_cooldownValue >= _logicBattleModeServer.GetTicksGone()) return false; if (wasReturn) return true; if (_logicSkillData.GetBehaviorType() != "Charge") _activeTime = _logicSkillData.GetActiveTime() / 50 - 2; else _activeTime = _logicSkillData.GetCastingRange() / 2 - 2; _tick = -1; _charge -= 1000; _cooldownValue = _logicBattleModeServer.GetTicksGone() + _logicSkillData.GetMsBetweenAttacks() / 10 - 10 / 2; SpawnProjectiles(logicVector2); return true; } public void SetOwner(LogicCharacterServer owner) { _owner = owner; } private void SpawnProjectiles(LogicVector2 target) { if (_owner == null) return; if (string.IsNullOrEmpty(_logicSkillData.GetProjectile())) return; var projData = LogicDataTables.GetProjectileByName(_logicSkillData.GetProjectile()); if (projData == null) return; var numBullets = _logicSkillData.GetNumBulletsInOneAttack(); if (numBullets < 1) numBullets = 1; var spread = _logicSkillData.GetSpread(); var baseAngle = LogicMath.GetAngle( target.GetX() - _owner.GetX(), target.GetY() - _owner.GetY()); var damage = _logicSkillData.GetDamage(); var castRange = _logicSkillData.GetCastingRange() * 300; if (castRange < 1) castRange = 6900; var startAngle = numBullets > 1 ? baseAngle - spread / 2 : baseAngle; var angleStep = numBullets > 1 ? spread / (numBullets - 1) : 0; for (var i = 0; i < numBullets; i++) { var angle = startAngle + angleStep * i; var cosA = LogicMath.Cos(angle); var sinA = LogicMath.Sin(angle); var tx = _owner.GetX() + castRange * cosA / 255; var ty = _owner.GetY() + castRange * sinA / 255; var proj = new LogicProjectileServer( _logicBattleModeServer, _owner, projData, _logicSkillData, _owner.GetX(), _owner.GetY(), tx, ty, damage); _owner.GetLogicGameObjectManager().AddLogicGameObject(proj); } } public void Encode(BitStream bitStream, bool interruptedSkill) { var v4 = (int)((ulong)(1374389535L * _activeTime) >> 32); bitStream.WritePositiveVIntMax255OftenZero((int)((v4 >> 4) + ((uint)v4 >> 31))); bitStream.WriteBoolean(BlockedForCastType(true)); bitStream.WritePositiveVIntMax255OftenZero(LogicMath.Clamp(_cooldownValue - _logicBattleModeServer.GetTicksGone(), 0, 100)); if (_logicSkillData.GetMaxCharge() >= 1) bitStream.WritePositiveIntMax4095(_charge); if (_logicSkillData.GetSkillCanChange()) bitStream.WritePositiveIntMax255(_logicSkillData.GetInstanceId()); } public LogicVector2 GetSkillCastPos() { return _logicVector2; } public LogicSkillData GetData() { return _logicSkillData; } public int GetMaxCharge() { return _maxCharge; } }