<commit_before>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectHekate.Core
{
    public interface IBulletSystem
    {
        IBullet FireBasicBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex);
        IBullet FireScriptedBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex, BulletUpdateDelegate bulletFunc);

        IReadOnlyCollection<IBullet> Bullets { get; }

        void Update(float dt);
    }

    public class BulletSystem : IBulletSystem
    {
        public const int MaxBullets = 2048;

        // TODO: break bullets into arrays of components
        private readonly Bullet[] _bullets = new Bullet[MaxBullets];
        private readonly float[] _bulletWaitTimers = new float[MaxBullets];
        private readonly IEnumerator<WaitInFrames>[] _bulletEnumerators = new IEnumerator<WaitInFrames>[MaxBullets];
        private int _availableBulletIndex;

        public IReadOnlyCollection<IBullet> Bullets { get; private set; }

        public BulletSystem()
        {
            for (var i = 0; i < MaxBullets; i++) {
                _bullets[i] = new Bullet();
                _bulletWaitTimers[i] = -1.0f;
                _bulletEnumerators[i] = null;
            }

            Bullets = Array.AsReadOnly(_bullets);
        }

        public IBullet FireBasicBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex)
        {
            return InternalFireBullet(x, y, angle, speedPerFrame, spriteIndex, null);
        }

        public IBullet FireScriptedBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex, BulletUpdateDelegate bulletFunc)
        {
            return InternalFireBullet(x, y, angle, speedPerFrame, spriteIndex, bulletFunc);
        }

        private Bullet InternalFireBullet(float x, float y, float angle, float speed, int spriteIndex, BulletUpdateDelegate bulletFunc)
        {
            var bullet = FindNextAvailableBullet();

            bullet.X = x;
            bullet.Y = y;
            bullet.Angle = angle;
            bullet.Speed = speed;
            bullet.SpriteIndex = spriteIndex;
            bullet.UpdateFunc = bulletFunc;

            return bullet;
        }
        
        private Bullet FindNextAvailableBullet()
        {
            int i;
            for (i = 0; i < MaxBullets; i++)
            {
                var trueIndex = (_availableBulletIndex + i) % MaxBullets;

                if (!_bullets[trueIndex].IsActive)
                {
                    _availableBulletIndex = trueIndex;
                    break;
                }
            }

            if (i == MaxBullets) _availableBulletIndex = (_availableBulletIndex + 1) % MaxBullets;

            return _bullets[_availableBulletIndex];
        }


        public void Update(float dt)
        {
            for (var i = 0; i < MaxBullets; i++) {
                var b = _bullets[i];

                if (!b.IsActive) {
                    continue;
                }

                b.X += (float)Math.Cos(b.Angle) * b.Speed;
                b.Y += (float)Math.Sin(b.Angle) * b.Speed;
                    
                // if the bullet's "update state" is ready
                if (_bulletWaitTimers[i] <= 0) {
                    var loopAgain = true;

                    // this loopAgain variable basically means: start from the beginning of the Update function if the function reaches completion
                    // this means that if there isn't a yield return, the function will loop infinitely
                    // TODO: somehow prevent that
                    while (loopAgain) {<commit_msg>Fixes bullet system's not working properly with non-scripted bullets.<commit_after>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ProjectHekate.Core
{
    public interface IBulletSystem
    {
        IBullet FireBasicBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex);
        IBullet FireScriptedBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex, BulletUpdateDelegate bulletFunc);

        IReadOnlyCollection<IBullet> Bullets { get; }

        void Update(float dt);
    }

    public class BulletSystem : IBulletSystem
    {
        public const int MaxBullets = 2048;

        // TODO: break bullets into arrays of components
        private readonly Bullet[] _bullets = new Bullet[MaxBullets];
        private readonly float[] _bulletWaitTimers = new float[MaxBullets];
        private readonly IEnumerator<WaitInFrames>[] _bulletEnumerators = new IEnumerator<WaitInFrames>[MaxBullets];
        private int _availableBulletIndex;

        public IReadOnlyCollection<IBullet> Bullets { get; private set; }

        public BulletSystem()
        {
            for (var i = 0; i < MaxBullets; i++) {
                _bullets[i] = new Bullet();
                _bulletWaitTimers[i] = -1.0f;
                _bulletEnumerators[i] = null;
            }

            Bullets = Array.AsReadOnly(_bullets);
        }

        public IBullet FireBasicBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex)
        {
            return InternalFireBullet(x, y, angle, speedPerFrame, spriteIndex, null);
        }

        public IBullet FireScriptedBullet(float x, float y, float angle, float speedPerFrame, int spriteIndex, BulletUpdateDelegate bulletFunc)
        {
            return InternalFireBullet(x, y, angle, speedPerFrame, spriteIndex, bulletFunc);
        }

        private Bullet InternalFireBullet(float x, float y, float angle, float speed, int spriteIndex, BulletUpdateDelegate bulletFunc)
        {
            var bullet = FindNextAvailableBullet();

            bullet.X = x;
            bullet.Y = y;
            bullet.Angle = angle;
            bullet.Speed = speed;
            bullet.SpriteIndex = spriteIndex;
            bullet.UpdateFunc = bulletFunc;

            return bullet;
        }
        
        private Bullet FindNextAvailableBullet()
        {
            int i;
            for (i = 0; i < MaxBullets; i++)
            {
                var trueIndex = (_availableBulletIndex + i) % MaxBullets;

                if (!_bullets[trueIndex].IsActive)
                {
                    _availableBulletIndex = trueIndex;
                    break;
                }
            }

            if (i == MaxBullets) _availableBulletIndex = (_availableBulletIndex + 1) % MaxBullets;

            return _bullets[_availableBulletIndex];
        }


        public void Update(float dt)
        {
            for (var i = 0; i < MaxBullets; i++) {
                var b = _bullets[i];

                if (!b.IsActive) {
                    continue;
                }

                b.X += (float)Math.Cos(b.Angle) * b.Speed;
                b.Y += (float)Math.Sin(b.Angle) * b.Speed;

                // if the bullet does not have a special update function, skip the wait logic
                if (b.UpdateFunc == null) {
                    continue;
                }

                // if the bullet's "update state" is ready
                if (_bulletWaitTimers[i] <= 0) {
                    var loopAgain = true;

                    // this loopAgain variable basically means: start from the beginning of the Update function if the function reaches completion
                    // this means that if there isn't a yield return, the function will loop infinitely
                    // TODO: somehow prevent that
                    while (loopAgain) {
{'fraction_non_alphanumeric': 0.0791800128122998, 'fraction_numerical': 0.0028187059577194106, 'mean_word_length': 1.8772576483597494, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1988634', 'n_tokens_mistral': 2128, 'n_tokens_neox': 1978, 'n_words': 596}