| @@ -23,9 +23,9 @@ find . -iname "*.c" \ | |||
| | xargs clang-format -i | |||
| done | |||
| cd logic && dotnet format && cd .. | |||
| cd installer && dotnet format && cd .. | |||
| cd launcher && dotnet format && cd .. | |||
| cd playback && dotnet format && cd .. | |||
| pushd logic && dotnet format && popd | |||
| pushd installer && dotnet format && popd | |||
| pushd launcher && dotnet format && popd | |||
| pushd playback && dotnet format && popd | |||
| echo "Done!" | |||
| echo "Done!" | |||
| @@ -1,6 +1,6 @@ | |||
| using System.Windows; | |||
| [assembly:ThemeInfo( | |||
| [assembly: ThemeInfo( | |||
| ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located | |||
| //(used if a resource is not found in the page, | |||
| // or application resource dictionaries) | |||
| @@ -71,23 +71,29 @@ namespace starter.viewmodel.settings | |||
| /// </summary> | |||
| public string Route | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return Downloader.Program.Data.FilePath; | |||
| } | |||
| set { | |||
| set | |||
| { | |||
| Downloader.Program.Data.FilePath = value; | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// if the route was set or is under editing | |||
| /// </summary> | |||
| public bool EditingRoute { | |||
| get; set; } | |||
| public bool EditingRoute | |||
| { | |||
| get; set; | |||
| } | |||
| ///< summary> | |||
| /// if already installed | |||
| /// </summary> | |||
| public bool installed { | |||
| get; set; } | |||
| public bool installed | |||
| { | |||
| get; set; | |||
| } | |||
| } | |||
| } | |||
| namespace Downloader | |||
| @@ -224,7 +230,8 @@ namespace Downloader | |||
| GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName); | |||
| Dictionary<string, string> test = request.GetRequestHeaders(); | |||
| request.SetCosProgressCallback(delegate(long completed, long total) { | |||
| request.SetCosProgressCallback(delegate (long completed, long total) | |||
| { | |||
| Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total)); | |||
| }); | |||
| // 执行请求 | |||
| @@ -834,7 +841,8 @@ namespace WebConnect | |||
| async public Task LoginToEEsast(HttpClient client, string useremail, string password) | |||
| { | |||
| string token = ""; | |||
| using (var response = await client.PostAsync("https://api.eesast.com/users/login", JsonContent.Create(new { | |||
| using (var response = await client.PostAsync("https://api.eesast.com/users/login", JsonContent.Create(new | |||
| { | |||
| email = useremail, | |||
| password = password, | |||
| }))) | |||
| @@ -843,9 +851,10 @@ namespace WebConnect | |||
| { | |||
| case System.Net.HttpStatusCode.OK: | |||
| Console.WriteLine("Success login"); | |||
| token = (System.Text.Json.JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), typeof(LoginResponse), new JsonSerializerOptions() { | |||
| PropertyNamingPolicy = JsonNamingPolicy.CamelCase, | |||
| }) as LoginResponse) | |||
| token = (System.Text.Json.JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), typeof(LoginResponse), new JsonSerializerOptions() | |||
| { | |||
| PropertyNamingPolicy = JsonNamingPolicy.CamelCase, | |||
| }) as LoginResponse) | |||
| ?.Token ?? | |||
| throw new Exception("no token!"); | |||
| logintoken = token; | |||
| @@ -30,20 +30,24 @@ namespace starter.viewmodel.settings | |||
| public string Route | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return obj.Route; | |||
| } | |||
| set { | |||
| set | |||
| { | |||
| obj.Route = value; | |||
| this.RaisePropertyChanged("Route"); | |||
| } | |||
| } | |||
| public bool Installed | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return obj.installed; | |||
| } | |||
| set { | |||
| set | |||
| { | |||
| obj.installed = value; | |||
| this.RaisePropertyChanged("Installed"); | |||
| this.RaisePropertyChanged("InstIntroVis"); | |||
| @@ -53,10 +57,12 @@ namespace starter.viewmodel.settings | |||
| } | |||
| public bool EditingRoute | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return obj.EditingRoute; | |||
| } | |||
| set { | |||
| set | |||
| { | |||
| obj.EditingRoute = value; | |||
| this.RaisePropertyChanged("EditingRoute"); | |||
| this.RaisePropertyChanged("MoveIntroVis"); | |||
| @@ -65,7 +71,8 @@ namespace starter.viewmodel.settings | |||
| } | |||
| public Visibility RouteBoxVis // if the route editing textbox is visible | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return obj.EditingRoute ? Visibility.Visible : Visibility.Collapsed; | |||
| } | |||
| } | |||
| @@ -74,19 +81,22 @@ namespace starter.viewmodel.settings | |||
| /// </summary> | |||
| public Visibility InstIntroVis | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return obj.installed ? Visibility.Collapsed : Visibility.Visible; | |||
| } | |||
| } | |||
| public Visibility EditIntroVis | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| return obj.installed ? Visibility.Visible : Visibility.Collapsed; | |||
| } | |||
| } | |||
| public Visibility MoveIntroVis | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| if (obj.installed == true && obj.EditingRoute == true) | |||
| return Visibility.Visible; | |||
| else | |||
| @@ -97,7 +107,8 @@ namespace starter.viewmodel.settings | |||
| private BaseCommand clickBrowseCommand; | |||
| public BaseCommand ClickBrowseCommand | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| if (clickBrowseCommand == null) | |||
| { | |||
| clickBrowseCommand = new BaseCommand(new Action<object>(o => | |||
| @@ -105,31 +116,32 @@ namespace starter.viewmodel.settings | |||
| using (FolderBrowserDialog dialog = new FolderBrowserDialog()) | |||
| { | |||
| _ = dialog.ShowDialog(); | |||
| if (dialog.SelectedPath != String.Empty) | |||
| Route = dialog.SelectedPath; | |||
| if (dialog.SelectedPath != String.Empty) | |||
| Route = dialog.SelectedPath; | |||
| } | |||
| })); | |||
| } | |||
| })); | |||
| } | |||
| return clickBrowseCommand; | |||
| } | |||
| } | |||
| private BaseCommand clickConfirmCommand; | |||
| public BaseCommand ClickConfirmCommand | |||
| { | |||
| get { | |||
| if (clickConfirmCommand == null) | |||
| return clickBrowseCommand; | |||
| } | |||
| } | |||
| private BaseCommand clickConfirmCommand; | |||
| public BaseCommand ClickConfirmCommand | |||
| { | |||
| get | |||
| { | |||
| if (clickConfirmCommand == null) | |||
| { | |||
| clickConfirmCommand = new BaseCommand(new Action<object>(o => | |||
| { | |||
| if (obj.install()) | |||
| { | |||
| EditingRoute = false; | |||
| Installed = true; | |||
| } | |||
| })); | |||
| Installed = true; | |||
| } | |||
| })); | |||
| } | |||
| return clickConfirmCommand; | |||
| } | |||
| } | |||
| } | |||
| return clickConfirmCommand; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| using System.Windows; | |||
| [assembly:ThemeInfo( | |||
| [assembly: ThemeInfo( | |||
| ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located | |||
| //(used if a resource is not found in the page, | |||
| // or application resource dictionaries) | |||
| @@ -48,125 +48,129 @@ namespace GameClass.GameObj | |||
| () => | |||
| { | |||
| LinkedListNode<BuffValue> buffNode; | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| buffNode = buffList[(int)buffType].AddLast(bf); | |||
| } | |||
| ReCalculateFunc(); | |||
| Thread.Sleep(buffTime); | |||
| try | |||
| { | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| buffList[(int)buffType].Remove(buffNode); | |||
| } | |||
| } | |||
| catch | |||
| { | |||
| } | |||
| ReCalculateFunc(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| private int ReCalculateFloatBuff(BuffType buffType, int orgVal, int maxVal, int minVal) | |||
| { | |||
| double times = 1.0; | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| buffNode = buffList[(int)buffType].AddLast(bf); | |||
| } | |||
| ReCalculateFunc(); | |||
| Thread.Sleep(buffTime); | |||
| try | |||
| { | |||
| lock (buffListLock[(int)buffType]) | |||
| foreach (var add in buffList[(int)buffType]) | |||
| { | |||
| buffList[(int)buffType].Remove(buffNode); | |||
| times *= add.lfValue; | |||
| } | |||
| } | |||
| catch | |||
| { | |||
| } | |||
| ReCalculateFunc(); | |||
| return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| private int ReCalculateFloatBuff(BuffType buffType, int orgVal, int maxVal, int minVal) | |||
| { | |||
| double times = 1.0; | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| foreach (var add in buffList[(int)buffType]) | |||
| public void AddMoveSpeed(double add, int buffTime, Action<int> SetNewMoveSpeed, int orgMoveSpeed) => AddBuff(new BuffValue(add), buffTime, BuffType.AddSpeed, () => SetNewMoveSpeed(ReCalculateFloatBuff(BuffType.AddSpeed, orgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed))); | |||
| public bool HasFasterSpeed | |||
| { | |||
| get | |||
| { | |||
| times *= add.lfValue; | |||
| } | |||
| lock (buffListLock[(int)BuffType.AddSpeed]) | |||
| { | |||
| return buffList[(int)BuffType.AddSpeed].Count != 0; | |||
| } | |||
| return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); | |||
| } | |||
| public void AddMoveSpeed(double add, int buffTime, Action<int> SetNewMoveSpeed, int orgMoveSpeed) => AddBuff(new BuffValue(add), buffTime, BuffType.AddSpeed, () => SetNewMoveSpeed(ReCalculateFloatBuff(BuffType.AddSpeed, orgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed))); | |||
| public bool HasFasterSpeed | |||
| { | |||
| get { | |||
| lock (buffListLock[(int)BuffType.AddSpeed]) | |||
| { | |||
| return buffList[(int)BuffType.AddSpeed].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void AddShield(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Shield, () => | |||
| {}); | |||
| public bool HasShield | |||
| { | |||
| get { | |||
| lock (buffListLock[(int)BuffType.Shield]) | |||
| public void AddShield(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Shield, () => | |||
| { }); | |||
| public bool HasShield | |||
| { | |||
| get | |||
| { | |||
| return buffList[(int)BuffType.Shield].Count != 0; | |||
| } | |||
| lock (buffListLock[(int)BuffType.Shield]) | |||
| { | |||
| return buffList[(int)BuffType.Shield].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void AddLIFE(int totelTime) => AddBuff(new BuffValue(), totelTime, BuffType.AddLIFE, () => | |||
| {}); | |||
| public bool HasLIFE | |||
| { | |||
| get { | |||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||
| public void AddLIFE(int totelTime) => AddBuff(new BuffValue(), totelTime, BuffType.AddLIFE, () => | |||
| { }); | |||
| public bool HasLIFE | |||
| { | |||
| get | |||
| { | |||
| return buffList[(int)BuffType.AddLIFE].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| public bool TryActivatingLIFE() | |||
| { | |||
| if (HasLIFE) | |||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||
| { | |||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||
| { | |||
| buffList[(int)BuffType.AddLIFE].Clear(); | |||
| return buffList[(int)BuffType.AddLIFE].Count != 0; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| public bool TryActivatingLIFE() | |||
| { | |||
| if (HasLIFE) | |||
| { | |||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||
| { | |||
| buffList[(int)BuffType.AddLIFE].Clear(); | |||
| } | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => | |||
| {}); | |||
| public bool HasSpear | |||
| { | |||
| get { | |||
| lock (buffListLock[(int)BuffType.Spear]) | |||
| public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => | |||
| { }); | |||
| public bool HasSpear | |||
| { | |||
| get | |||
| { | |||
| return buffList[(int)BuffType.Spear].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// 清除所有buff | |||
| /// </summary> | |||
| public void ClearAll() | |||
| { | |||
| for (int i = 0; i < buffList.Length; ++i) | |||
| lock (buffListLock[(int)BuffType.Spear]) | |||
| { | |||
| lock (buffListLock[i]) | |||
| { | |||
| buffList[i].Clear(); | |||
| } | |||
| return buffList[(int)BuffType.Spear].Count != 0; | |||
| } | |||
| } | |||
| public BuffManeger() | |||
| { | |||
| var buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||
| buffList = new LinkedList<BuffValue>[buffTypeArray.Length]; | |||
| buffListLock = new object[buffList.Length]; | |||
| int i = 0; | |||
| foreach (BuffType type in buffTypeArray) | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// 清除所有buff | |||
| /// </summary> | |||
| public void ClearAll() | |||
| { | |||
| for (int i = 0; i < buffList.Length; ++i) | |||
| { | |||
| lock (buffListLock[i]) | |||
| { | |||
| buffList[i] = new LinkedList<BuffValue>(); | |||
| buffListLock[i++] = new object(); | |||
| buffList[i].Clear(); | |||
| } | |||
| } | |||
| } | |||
| public BuffManeger() | |||
| { | |||
| var buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||
| buffList = new LinkedList<BuffValue>[buffTypeArray.Length]; | |||
| buffListLock = new object[buffList.Length]; | |||
| int i = 0; | |||
| foreach (BuffType type in buffTypeArray) | |||
| { | |||
| buffList[i] = new LinkedList<BuffValue>(); | |||
| buffListLock[i++] = new object(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -23,7 +23,8 @@ namespace GameClass.GameObj | |||
| public int TimeUntilCommonSkillAvailable | |||
| { | |||
| get => timeUntilCommonSkillAvailable; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| timeUntilCommonSkillAvailable = value < 0 ? 0 : value; | |||
| } | |||
| @@ -11,7 +11,7 @@ namespace GameClass.GameObj | |||
| { | |||
| private readonly object beAttackedLock = new(); | |||
| #region 角色的基本属性及方法,包括与道具的交互方法 | |||
| #region 角色的基本属性及方法,包括与道具的交互方法 | |||
| /// <summary> | |||
| /// 装弹冷却 | |||
| @@ -20,8 +20,9 @@ namespace GameClass.GameObj | |||
| public int CD | |||
| { | |||
| get => cd; | |||
| private | |||
| set { | |||
| private | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| cd = value; | |||
| @@ -40,7 +41,8 @@ namespace GameClass.GameObj | |||
| public int HP | |||
| { | |||
| get => hp; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| hp = value <= MaxHp ? value : MaxHp; | |||
| } | |||
| @@ -60,7 +62,8 @@ namespace GameClass.GameObj | |||
| public double Vampire | |||
| { | |||
| get => vampire; | |||
| set { | |||
| set | |||
| { | |||
| if (value > 1) | |||
| lock (gameObjLock) | |||
| vampire = 1; | |||
| @@ -76,7 +79,8 @@ namespace GameClass.GameObj | |||
| public double OriVampire | |||
| { | |||
| get => oriVampire; | |||
| set { | |||
| set | |||
| { | |||
| if (value > 1) | |||
| lock (gameObjLock) | |||
| vampire = 1; | |||
| @@ -94,7 +98,8 @@ namespace GameClass.GameObj | |||
| public BulletType BulletOfPlayer | |||
| { | |||
| get => bulletOfPlayer; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| bulletOfPlayer = value; | |||
| } | |||
| @@ -104,7 +109,8 @@ namespace GameClass.GameObj | |||
| public Prop? PropInventory // 持有的道具 | |||
| { | |||
| get => propInventory; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| propInventory = value; | |||
| @@ -134,7 +140,8 @@ namespace GameClass.GameObj | |||
| public bool IsModifyingProp | |||
| { | |||
| get => isModifyingProp; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isModifyingProp = value; | |||
| @@ -149,7 +156,8 @@ namespace GameClass.GameObj | |||
| public bool IsInvisible | |||
| { | |||
| get => isInvisible; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isInvisible = value; | |||
| @@ -346,7 +354,8 @@ namespace GameClass.GameObj | |||
| public long TeamID | |||
| { | |||
| get => teamID; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| teamID = value; | |||
| @@ -358,7 +367,8 @@ namespace GameClass.GameObj | |||
| public long PlayerID | |||
| { | |||
| get => playerID; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| playerID = value; | |||
| @@ -372,16 +382,17 @@ namespace GameClass.GameObj | |||
| public string Message | |||
| { | |||
| get => message; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| message = value; | |||
| } | |||
| } | |||
| } | |||
| #endregion | |||
| #endregion | |||
| #region 角色拥有的buff相关属性、方法 | |||
| #region 角色拥有的buff相关属性、方法 | |||
| public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal => | |||
| { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; }, | |||
| OrgMoveSpeed); | |||
| @@ -399,7 +410,8 @@ namespace GameClass.GameObj | |||
| private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||
| public Dictionary<BuffType, bool> Buff | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| Dictionary<BuffType, bool> buff = new Dictionary<BuffType, bool>(); | |||
| foreach (BuffType type in buffTypeArray) | |||
| { | |||
| @@ -432,7 +444,7 @@ namespace GameClass.GameObj | |||
| hp = MaxHp; | |||
| } | |||
| } | |||
| #endregion | |||
| #endregion | |||
| public override void Reset() // 要加锁吗? | |||
| { | |||
| _ = AddDeathCount(); | |||
| @@ -29,8 +29,9 @@ namespace GameClass.GameObj | |||
| public XY Position | |||
| { | |||
| get => position; | |||
| protected | |||
| set { | |||
| protected | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| position = value; | |||
| @@ -43,7 +44,8 @@ namespace GameClass.GameObj | |||
| public XY FacingDirection | |||
| { | |||
| get => facingDirection; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| facingDirection = value; | |||
| } | |||
| @@ -54,7 +56,8 @@ namespace GameClass.GameObj | |||
| public bool CanMove | |||
| { | |||
| get => canMove; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| canMove = value; | |||
| @@ -66,7 +69,8 @@ namespace GameClass.GameObj | |||
| public bool IsMoving | |||
| { | |||
| get => isMoving; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isMoving = value; | |||
| @@ -78,7 +82,8 @@ namespace GameClass.GameObj | |||
| public bool IsResetting | |||
| { | |||
| get => isResetting; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isResetting = value; | |||
| @@ -92,7 +97,8 @@ namespace GameClass.GameObj | |||
| public PlaceType Place | |||
| { | |||
| get => place; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| place = value; | |||
| @@ -106,7 +112,8 @@ namespace GameClass.GameObj | |||
| public int MoveSpeed | |||
| { | |||
| get => moveSpeed; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| moveSpeed = value; | |||
| @@ -120,8 +127,9 @@ namespace GameClass.GameObj | |||
| public int OrgMoveSpeed | |||
| { | |||
| get => orgMoveSpeed; | |||
| protected | |||
| set { | |||
| protected | |||
| set | |||
| { | |||
| orgMoveSpeed = value; | |||
| } | |||
| } | |||
| @@ -12,7 +12,8 @@ namespace GameClass.GameObj | |||
| public ICharacter? Parent | |||
| { | |||
| get => parent; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| parent = value; | |||
| @@ -43,14 +43,14 @@ namespace GameClass.GameObj | |||
| { | |||
| } | |||
| } | |||
| ///// <summary> | |||
| ///// 坑人地雷 | |||
| ///// </summary> | |||
| // public abstract class DebuffMine : Prop | |||
| //{ | |||
| // public DebuffMine(XYPosition initPos) : base(initPos) { } | |||
| // } | |||
| #region 所有增益道具 | |||
| ///// <summary> | |||
| ///// 坑人地雷 | |||
| ///// </summary> | |||
| // public abstract class DebuffMine : Prop | |||
| //{ | |||
| // public DebuffMine(XYPosition initPos) : base(initPos) { } | |||
| // } | |||
| #region 所有增益道具 | |||
| /// <summary> | |||
| /// 增加速度 | |||
| /// </summary> | |||
| @@ -95,7 +95,7 @@ namespace GameClass.GameObj | |||
| } | |||
| public override PropType GetPropType() => PropType.Spear; | |||
| } | |||
| #endregion | |||
| #endregion | |||
| // #region 所有坑人地雷 | |||
| ///// <summary> | |||
| ///// 减速 | |||
| @@ -13,7 +13,8 @@ namespace GameClass.GameObj | |||
| private readonly List<Character> playerList; | |||
| public int Score | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| int score = 0; | |||
| foreach (var player in playerList) | |||
| score += player.Score; | |||
| @@ -33,8 +33,9 @@ namespace GameClass.Skill | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.Vampire += 0.5; | |||
| Debugger.Output(player, "becomes vampire!"); }, | |||
| player.Vampire += 0.5; | |||
| Debugger.Output(player, "becomes vampire!"); | |||
| }, | |||
| () => | |||
| { | |||
| double tempVam = player.Vampire - 0.5; | |||
| @@ -65,8 +66,9 @@ namespace GameClass.Skill | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.IsInvisible = true; | |||
| Debugger.Output(player, "uses atombomb!"); }, | |||
| player.IsInvisible = true; | |||
| Debugger.Output(player, "uses atombomb!"); | |||
| }, | |||
| () => | |||
| { player.IsInvisible = false; }); | |||
| } | |||
| @@ -93,8 +95,9 @@ namespace GameClass.Skill | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||
| Debugger.Output(player, "uses atombomb!"); }, | |||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||
| Debugger.Output(player, "uses atombomb!"); | |||
| }, | |||
| () => | |||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||
| } | |||
| @@ -121,10 +124,11 @@ namespace GameClass.Skill | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||
| Debugger.Output(player, "moves very fast!"); }, | |||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||
| Debugger.Output(player, "moves very fast!"); | |||
| }, | |||
| () => | |||
| {}); | |||
| { }); | |||
| } | |||
| } | |||
| public class NoCommonSkill : ICommonSkill // 这种情况不该发生,定义着以防意外 | |||
| @@ -164,53 +168,55 @@ namespace GameClass.Skill | |||
| (() => | |||
| { | |||
| startSkill(); | |||
| new FrameRateTaskExecutor<int>( | |||
| () => !player.IsResetting, | |||
| () => | |||
| new FrameRateTaskExecutor<int>( | |||
| () => !player.IsResetting, | |||
| () => | |||
| { | |||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: (long)(commonSkill.DurationTime) | |||
| ) | |||
| { | |||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: (long)(commonSkill.DurationTime) | |||
| ) { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| } | |||
| .Start(); | |||
| endSkill(); | |||
| Debugger.Output(player, "return to normal."); | |||
| new FrameRateTaskExecutor<int>( | |||
| () => player.TimeUntilCommonSkillAvailable > 0 && !player.IsResetting, | |||
| () => | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| } | |||
| .Start(); | |||
| endSkill(); | |||
| Debugger.Output(player, "return to normal."); | |||
| new FrameRateTaskExecutor<int>( | |||
| () => player.TimeUntilCommonSkillAvailable > 0 && !player.IsResetting, | |||
| () => | |||
| { | |||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: (long)(commonSkill.SkillCD - commonSkill.DurationTime) | |||
| ) | |||
| { | |||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: (long)(commonSkill.SkillCD - commonSkill.DurationTime) | |||
| ) { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| } | |||
| .Start(); | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| } | |||
| .Start(); | |||
| player.TimeUntilCommonSkillAvailable = 0; | |||
| Debugger.Output(player, "CommonSkill is ready."); | |||
| } | |||
| player.TimeUntilCommonSkillAvailable = 0; | |||
| Debugger.Output(player, "CommonSkill is ready."); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| } | |||
| else | |||
| { | |||
| Debugger.Output(player, "CommonSkill is cooling down!"); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -29,19 +29,19 @@ namespace GameClass.Skill // 被动技能开局时就释放,持续到游戏 | |||
| () => true, | |||
| () => | |||
| { | |||
| lastHP = nowHP; // lastHP等于上一帧的HP | |||
| nowHP = player.HP; // nowHP更新为这一帧的HP | |||
| if (lastHP > nowHP) // 这一帧扣血了 | |||
| { | |||
| waitTime = 0; | |||
| } | |||
| else if (waitTime < interval) | |||
| { | |||
| waitTime += GameData.frameDuration; | |||
| } | |||
| lastHP = nowHP; // lastHP等于上一帧的HP | |||
| nowHP = player.HP; // nowHP更新为这一帧的HP | |||
| if (lastHP > nowHP) // 这一帧扣血了 | |||
| { | |||
| waitTime = 0; | |||
| } | |||
| else if (waitTime < interval) | |||
| { | |||
| waitTime += GameData.frameDuration; | |||
| } | |||
| if (waitTime >= interval) // 回复时,每帧(50ms)回复5,即1s回复100。 | |||
| player.TryAddHp(recoverDegree); | |||
| if (waitTime >= interval) // 回复时,每帧(50ms)回复5,即1s回复100。 | |||
| player.TryAddHp(recoverDegree); | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| @@ -52,29 +52,29 @@ namespace GameClass.Skill // 被动技能开局时就释放,持续到游戏 | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) | |||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||
| if (b) | |||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||
| #if DEBUG | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||
| } | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||
| } | |||
| #endif | |||
| } | |||
| }.Start(); | |||
| } | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| } | |||
| public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.FastBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| // 以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.FastBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| // 以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| PlaceType nowPlace = player.Place; | |||
| PlaceType lastPlace = nowPlace; | |||
| bool speedup = false; | |||
| @@ -88,20 +88,20 @@ public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||
| () => true, | |||
| () => | |||
| { | |||
| lastPlace = nowPlace; | |||
| nowPlace = player.Place; | |||
| if ((lastPlace == PlaceType.Grass1 || lastPlace == PlaceType.Grass2 || lastPlace == PlaceType.Grass3) && nowPlace == PlaceType.Land) | |||
| { | |||
| if (!speedup) | |||
| { | |||
| lastPlace = nowPlace; | |||
| nowPlace = player.Place; | |||
| if ((lastPlace == PlaceType.Grass1 || lastPlace == PlaceType.Grass2 || lastPlace == PlaceType.Grass3) && nowPlace == PlaceType.Land) | |||
| { | |||
| if (!speedup) | |||
| { | |||
| new Thread(() => | |||
| { | |||
| speedup = true; | |||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||
| speedup = false; | |||
| }) | |||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||
| speedup = false; | |||
| }) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| @@ -113,41 +113,41 @@ public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) | |||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||
| if (b) | |||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||
| #if DEBUG | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||
| } | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||
| } | |||
| #endif | |||
| } | |||
| }.Start(); | |||
| } | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| public class Vampire : IPassiveSkill // 被动就是吸血,普通子弹 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.LineBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| // 以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| } | |||
| } | |||
| public class Vampire : IPassiveSkill // 被动就是吸血,普通子弹 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.LineBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| // 以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| player.OriVampire = 0.5; | |||
| player.Vampire = player.OriVampire; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public class NoPassiveSkill : IPassiveSkill // 没技能,这种情况不应该发生,先定义着以防意外 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.OrdinaryBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| // 以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| } | |||
| } | |||
| public class NoPassiveSkill : IPassiveSkill // 没技能,这种情况不应该发生,先定义着以防意外 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.OrdinaryBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| // 以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -66,65 +66,28 @@ namespace GameEngine | |||
| { | |||
| if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况 | |||
| return; | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = true; | |||
| double moveVecLength = 0.0; | |||
| double deltaLen = moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); // 转向,并用deltaLen存储行走的误差 | |||
| IGameObj? collisionObj = null; | |||
| bool isDestroyed = false; | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting, | |||
| () => | |||
| { | |||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||
| bool flag; // 循环标志 | |||
| do | |||
| { | |||
| flag = false; | |||
| collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength)); | |||
| if (collisionObj == null) | |||
| break; | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = true; | |||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||
| double moveVecLength = 0.0; | |||
| double deltaLen = moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); // 转向,并用deltaLen存储行走的误差 | |||
| IGameObj? collisionObj = null; | |||
| bool isDestroyed = false; | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting, | |||
| () => | |||
| { | |||
| case AfterCollision.ContinueCheck: | |||
| flag = true; | |||
| break; | |||
| case AfterCollision.Destroyed: | |||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | |||
| isDestroyed = true; | |||
| return false; | |||
| case AfterCollision.MoveMax: | |||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||
| moveVecLength = 0; | |||
| break; | |||
| } | |||
| } while (flag); | |||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||
| deltaLen += moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); | |||
| return true; | |||
| }, | |||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||
| () => | |||
| { | |||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||
| bool flag; | |||
| do | |||
| { | |||
| flag = false; | |||
| if (!isDestroyed) | |||
| { | |||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||
| if ((collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength))) == null) | |||
| { | |||
| obj.Move(new XY(direction, moveVecLength)); | |||
| } | |||
| else | |||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||
| bool flag; // 循环标志 | |||
| do | |||
| { | |||
| flag = false; | |||
| collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength)); | |||
| if (collisionObj == null) | |||
| break; | |||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||
| { | |||
| case AfterCollision.ContinueCheck: | |||
| @@ -133,43 +96,81 @@ namespace GameEngine | |||
| case AfterCollision.Destroyed: | |||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | |||
| isDestroyed = true; | |||
| break; | |||
| return false; | |||
| case AfterCollision.MoveMax: | |||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||
| moveVecLength = 0; | |||
| break; | |||
| } | |||
| } while (flag); | |||
| deltaLen += moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); | |||
| return true; | |||
| }, | |||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||
| () => | |||
| { | |||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||
| bool flag; | |||
| do | |||
| { | |||
| flag = false; | |||
| if (!isDestroyed) | |||
| { | |||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||
| if ((collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength))) == null) | |||
| { | |||
| obj.Move(new XY(direction, moveVecLength)); | |||
| } | |||
| else | |||
| { | |||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||
| { | |||
| case AfterCollision.ContinueCheck: | |||
| flag = true; | |||
| break; | |||
| case AfterCollision.Destroyed: | |||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | |||
| isDestroyed = true; | |||
| break; | |||
| case AfterCollision.MoveMax: | |||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||
| moveVecLength = 0; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } while (flag); | |||
| if (leftTime > 0) | |||
| { | |||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||
| } | |||
| } | |||
| } while (flag); | |||
| if (leftTime > 0) | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = false; // 结束移动 | |||
| EndMove(obj); | |||
| return 0; | |||
| }, | |||
| maxTotalDuration: moveTime | |||
| ) | |||
| { | |||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||
| } | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = false; // 结束移动 | |||
| EndMove(obj); | |||
| return 0; | |||
| }, | |||
| maxTotalDuration: moveTime | |||
| ) { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) | |||
| Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) | |||
| Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); | |||
| #if DEBUG | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: Object moving time exceed for once."); | |||
| } | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: Object moving time exceed for once."); | |||
| } | |||
| #endif | |||
| } | |||
| }.Start(); | |||
| } | |||
| }.Start(); | |||
| } | |||
| ).Start(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -23,14 +23,16 @@ namespace Gaming | |||
| OnCollision: (obj, collisionObj, moveVec) => | |||
| { | |||
| //BulletBomb((Bullet)obj, (GameObj)collisionObj); | |||
| return MoveEngine.AfterCollision.Destroyed; }, | |||
| return MoveEngine.AfterCollision.Destroyed; | |||
| }, | |||
| EndMove: obj => | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| #endif | |||
| BulletBomb((Bullet)obj, null); } | |||
| BulletBomb((Bullet)obj, null); | |||
| } | |||
| ); | |||
| } | |||
| private void BombOnePlayer(Bullet bullet, Character playerBeingShot) | |||
| @@ -75,136 +77,136 @@ namespace Gaming | |||
| Thread.Sleep(GameData.reviveTime); | |||
| playerBeingShot.AddShield(GameData.shieldTimeAtBirth); // 复活加个盾 | |||
| playerBeingShot.AddShield(GameData.shieldTimeAtBirth); // 复活加个盾 | |||
| // gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| // try | |||
| //{ | |||
| // gameMap.GameObjDict[GameObjIdx.Player].Add(playerBeingShot); | |||
| // } | |||
| // finally { gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); } | |||
| // gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| // try | |||
| //{ | |||
| // gameMap.GameObjDict[GameObjIdx.Player].Add(playerBeingShot); | |||
| // } | |||
| // finally { gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); } | |||
| if (gameMap.Timer.IsGaming) | |||
| { | |||
| playerBeingShot.CanMove = true; | |||
| } | |||
| playerBeingShot.IsResetting = false; | |||
| } | |||
| if (gameMap.Timer.IsGaming) | |||
| { | |||
| playerBeingShot.CanMove = true; | |||
| } | |||
| playerBeingShot.IsResetting = false; | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| } | |||
| private void BulletBomb(Bullet bullet, GameObj? objBeingShot) | |||
| { | |||
| private void BulletBomb(Bullet bullet, GameObj? objBeingShot) | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(bullet, "bombed!"); | |||
| Debugger.Output(bullet, "bombed!"); | |||
| #endif | |||
| bullet.CanMove = false; | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (ObjOfCharacter _bullet in gameMap.GameObjDict[GameObjIdx.Bullet]) | |||
| { | |||
| if (_bullet.ID == bullet.ID) | |||
| bullet.CanMove = false; | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (ObjOfCharacter _bullet in gameMap.GameObjDict[GameObjIdx.Bullet]) | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.BombedBullet].Add(new BombedBullet(bullet)); | |||
| } | |||
| finally | |||
| if (_bullet.ID == bullet.ID) | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].ExitWriteLock(); | |||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.BombedBullet].Add(new BombedBullet(bullet)); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.BombedBullet].ExitWriteLock(); | |||
| } | |||
| gameMap.GameObjDict[GameObjIdx.Bullet].Remove(_bullet); | |||
| break; | |||
| } | |||
| gameMap.GameObjDict[GameObjIdx.Bullet].Remove(_bullet); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||
| } | |||
| /*if (objBeingShot != null) | |||
| { | |||
| else if (objBeingShot is Bullet) //子弹不能相互引爆,若要更改这一设定,取消注释即可。 | |||
| } | |||
| finally | |||
| { | |||
| new Thread(() => { BulletBomb((Bullet)objBeingShot, null); }) { IsBackground = true }.Start(); | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||
| } | |||
| }*/ | |||
| // 子弹爆炸会发生的事↓↓↓ | |||
| var beAttackedList = new List<Character>(); | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| if (bullet.CanAttack(player)) | |||
| /*if (objBeingShot != null) | |||
| { | |||
| else if (objBeingShot is Bullet) //子弹不能相互引爆,若要更改这一设定,取消注释即可。 | |||
| { | |||
| beAttackedList.Add(player); | |||
| if (player.ID != bullet.Parent.ID) | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * bullet.AP)); | |||
| new Thread(() => { BulletBomb((Bullet)objBeingShot, null); }) { IsBackground = true }.Start(); | |||
| } | |||
| }*/ | |||
| // 子弹爆炸会发生的事↓↓↓ | |||
| var beAttackedList = new List<Character>(); | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| if (bullet.CanAttack(player)) | |||
| { | |||
| beAttackedList.Add(player); | |||
| if (player.ID != bullet.Parent.ID) | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * bullet.AP)); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||
| } | |||
| foreach (Character beAttackedPlayer in beAttackedList) | |||
| { | |||
| BombOnePlayer(bullet, beAttackedPlayer); | |||
| foreach (Character beAttackedPlayer in beAttackedList) | |||
| { | |||
| BombOnePlayer(bullet, beAttackedPlayer); | |||
| } | |||
| beAttackedList.Clear(); | |||
| } | |||
| beAttackedList.Clear(); | |||
| } | |||
| public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头) | |||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (player == null) | |||
| { | |||
| public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头) | |||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (player == null) | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine("the player who will attack is NULL!"); | |||
| Console.WriteLine("the player who will attack is NULL!"); | |||
| #endif | |||
| return false; | |||
| } | |||
| return false; | |||
| } | |||
| if (player.IsResetting) | |||
| return false; | |||
| Bullet? bullet = player.RemoteAttack( | |||
| new XY // 子弹紧贴人物生成。 | |||
| ( | |||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle)), | |||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle)) | |||
| ) | |||
| ); | |||
| if (bullet != null) | |||
| { | |||
| bullet.CanMove = true; | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.Bullet].Add(bullet); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||
| } | |||
| moveEngine.MoveObj(bullet, (int)((player.AttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms | |||
| if (player.IsResetting) | |||
| return false; | |||
| Bullet? bullet = player.RemoteAttack( | |||
| new XY // 子弹紧贴人物生成。 | |||
| ( | |||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle)), | |||
| (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle)) | |||
| ) | |||
| ); | |||
| if (bullet != null) | |||
| { | |||
| bullet.CanMove = true; | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[GameObjIdx.Bullet].Add(bullet); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Bullet].ExitWriteLock(); | |||
| } | |||
| moveEngine.MoveObj(bullet, (int)((player.AttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms | |||
| #if DEBUG | |||
| Console.WriteLine($"playerID:{player.ID} successfully attacked!"); | |||
| Console.WriteLine($"playerID:{player.ID} successfully attacked!"); | |||
| #endif | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine($"playerID:{player.ID} has no bullets so that he can't attack!"); | |||
| Console.WriteLine($"playerID:{player.ID} has no bullets so that he can't attack!"); | |||
| #endif | |||
| return false; | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -64,57 +64,58 @@ namespace Gaming | |||
| { | |||
| while (!gameMap.Timer.IsGaming) | |||
| Thread.Sleep(newPlayer.CD); | |||
| long lastTime = Environment.TickCount64; | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| if (!newPlayer.IsResetting) | |||
| long lastTime = Environment.TickCount64; | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| if (!newPlayer.IsResetting) | |||
| { | |||
| long nowTime = Environment.TickCount64; | |||
| if (newPlayer.BulletNum == newPlayer.MaxBulletNum) | |||
| lastTime = nowTime; | |||
| if (nowTime - lastTime >= newPlayer.CD) | |||
| { | |||
| _ = newPlayer.TryAddBulletNum(); | |||
| lastTime = nowTime; | |||
| } | |||
| } | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| { | |||
| long nowTime = Environment.TickCount64; | |||
| if (newPlayer.BulletNum == newPlayer.MaxBulletNum) | |||
| lastTime = nowTime; | |||
| if (nowTime - lastTime >= newPlayer.CD) | |||
| AllowTimeExceed = true | |||
| /*MaxTolerantTimeExceedCount = 5, | |||
| TimeExceedAction = exceedTooMuch => | |||
| { | |||
| _ = newPlayer.TryAddBulletNum(); | |||
| lastTime = nowTime; | |||
| } | |||
| if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); | |||
| }*/ | |||
| } | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) { | |||
| AllowTimeExceed = true | |||
| /*MaxTolerantTimeExceedCount = 5, | |||
| TimeExceedAction = exceedTooMuch => | |||
| { | |||
| if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); | |||
| }*/ | |||
| } | |||
| .Start(); | |||
| } | |||
| .Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return newPlayer.ID; | |||
| } | |||
| public bool StartGame(int milliSeconds) | |||
| { | |||
| } | |||
| public bool StartGame(int milliSeconds) | |||
| { | |||
| if (gameMap.Timer.IsGaming) | |||
| return false; | |||
| return false; | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| player.CanMove = true; | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| player.CanMove = true; | |||
| player.AddShield(GameData.shieldTimeAtBirth); | |||
| } | |||
| player.AddShield(GameData.shieldTimeAtBirth); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||
| } | |||
| propManager.StartProducing(); | |||
| @@ -127,24 +128,24 @@ namespace Gaming | |||
| loopCondition: () => gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| foreach (var kvp in gameMap.GameObjDict) // 检查物体位置 | |||
| { | |||
| if (kvp.Key == GameObjIdx.Bullet || kvp.Key == GameObjIdx.Player || kvp.Key == GameObjIdx.Prop) | |||
| { | |||
| gameMap.GameObjLockDict[kvp.Key].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (var item in gameMap.GameObjDict[kvp.Key]) | |||
| { | |||
| item.Place = gameMap.GetPlaceType(item.Position); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[kvp.Key].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| foreach (var kvp in gameMap.GameObjDict) // 检查物体位置 | |||
| { | |||
| if (kvp.Key == GameObjIdx.Bullet || kvp.Key == GameObjIdx.Player || kvp.Key == GameObjIdx.Prop) | |||
| { | |||
| gameMap.GameObjLockDict[kvp.Key].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (var item in gameMap.GameObjDict[kvp.Key]) | |||
| { | |||
| item.Place = gameMap.GetPlaceType(item.Position); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[kvp.Key].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| @@ -152,20 +153,20 @@ namespace Gaming | |||
| { | |||
| AllowTimeExceed = true | |||
| }.Start(); | |||
| } | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| // 开始游戏 | |||
| if (!gameMap.Timer.StartGame(milliSeconds)) | |||
| return false; | |||
| return false; | |||
| EndGame(); // 游戏结束时要做的事 | |||
| return true; | |||
| } | |||
| } | |||
| public void EndGame() | |||
| { | |||
| public void EndGame() | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| /*try | |||
| { | |||
| @@ -174,169 +175,169 @@ public void EndGame() | |||
| { | |||
| }*/ | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| } | |||
| public void MovePlayer(long playerID, int moveTimeInMilliseconds, double angle) | |||
| { | |||
| } | |||
| public void MovePlayer(long playerID, int moveTimeInMilliseconds, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| moveManager.MovePlayer(player, moveTimeInMilliseconds, angle); | |||
| moveManager.MovePlayer(player, moveTimeInMilliseconds, angle); | |||
| #if DEBUG | |||
| Console.WriteLine($"PlayerID:{playerID} move to ({player.Position.x},{player.Position.y})!"); | |||
| Console.WriteLine($"PlayerID:{playerID} move to ({player.Position.x},{player.Position.y})!"); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine($"PlayerID:{playerID} player does not exists!"); | |||
| Console.WriteLine($"PlayerID:{playerID} player does not exists!"); | |||
| #endif | |||
| } | |||
| } | |||
| public void Attack(long playerID, double angle) | |||
| { | |||
| } | |||
| public void Attack(long playerID, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| _ = attackManager.Attack(player, angle); | |||
| _ = attackManager.Attack(player, angle); | |||
| } | |||
| } | |||
| public void UseProp(long playerID) | |||
| { | |||
| } | |||
| public void UseProp(long playerID) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| propManager.UseProp(player); | |||
| propManager.UseProp(player); | |||
| } | |||
| } | |||
| public void ThrowProp(long playerID, int timeInmillionSeconds, double angle) | |||
| { | |||
| } | |||
| public void ThrowProp(long playerID, int timeInmillionSeconds, double angle) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| return; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| propManager.ThrowProp(player, timeInmillionSeconds, angle); | |||
| propManager.ThrowProp(player, timeInmillionSeconds, angle); | |||
| } | |||
| } | |||
| public bool PickProp(long playerID, PropType propType = PropType.Null) | |||
| { | |||
| } | |||
| public bool PickProp(long playerID, PropType propType = PropType.Null) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return false; | |||
| return false; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| return propManager.PickProp(player, propType); | |||
| return propManager.PickProp(player, propType); | |||
| } | |||
| return false; | |||
| } | |||
| } | |||
| public bool UseCommonSkill(long playerID) | |||
| { | |||
| public bool UseCommonSkill(long playerID) | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return false; | |||
| return false; | |||
| Character? player = gameMap.FindPlayer(playerID); | |||
| if (player != null) | |||
| { | |||
| return skillManager.UseCommonSkill(player); | |||
| return skillManager.UseCommonSkill(player); | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| return false; | |||
| } | |||
| public void AllPlayerUsePassiveSkill() | |||
| { | |||
| public void AllPlayerUsePassiveSkill() | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| return; | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].EnterWriteLock(); | |||
| try | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| skillManager.UsePassiveSkill(player); | |||
| } | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| skillManager.UsePassiveSkill(player); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| gameMap.GameObjLockDict[GameObjIdx.Player].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| public void ClearLists(GameObjIdx[] objIdxes) | |||
| { | |||
| public void ClearLists(GameObjIdx[] objIdxes) | |||
| { | |||
| foreach (var idx in objIdxes) | |||
| { | |||
| if (idx != GameObjIdx.None) | |||
| { | |||
| gameMap.GameObjLockDict[idx].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[idx].Clear(); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[idx].ExitWriteLock(); | |||
| } | |||
| } | |||
| if (idx != GameObjIdx.None) | |||
| { | |||
| gameMap.GameObjLockDict[idx].EnterWriteLock(); | |||
| try | |||
| { | |||
| gameMap.GameObjDict[idx].Clear(); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[idx].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public void ClearAllLists() | |||
| { | |||
| } | |||
| public void ClearAllLists() | |||
| { | |||
| foreach (var keyValuePair in gameMap.GameObjDict) | |||
| { | |||
| if (keyValuePair.Key != GameObjIdx.Map) | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterWriteLock(); | |||
| try | |||
| { | |||
| if (keyValuePair.Key == GameObjIdx.Player) | |||
| if (keyValuePair.Key != GameObjIdx.Map) | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterWriteLock(); | |||
| try | |||
| { | |||
| if (keyValuePair.Key == GameObjIdx.Player) | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjIdx.Player]) | |||
| { | |||
| player.CanMove = false; | |||
| } | |||
| } | |||
| gameMap.GameObjDict[keyValuePair.Key].Clear(); | |||
| } | |||
| finally | |||
| { | |||
| player.CanMove = false; | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); | |||
| } | |||
| } | |||
| gameMap.GameObjDict[keyValuePair.Key].Clear(); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public int GetTeamScore(long teamID) | |||
| { | |||
| public int GetTeamScore(long teamID) | |||
| { | |||
| return teamList[(int)teamID].Score; | |||
| } | |||
| public List<IGameObj> GetGameObj() | |||
| { | |||
| } | |||
| public List<IGameObj> GetGameObj() | |||
| { | |||
| var gameObjList = new List<IGameObj>(); | |||
| foreach (var keyValuePair in gameMap.GameObjDict) | |||
| { | |||
| if (keyValuePair.Key != GameObjIdx.Map) | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterReadLock(); | |||
| try | |||
| { | |||
| gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key]); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitReadLock(); | |||
| } | |||
| } | |||
| if (keyValuePair.Key != GameObjIdx.Map) | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterReadLock(); | |||
| try | |||
| { | |||
| gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key]); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitReadLock(); | |||
| } | |||
| } | |||
| } | |||
| return gameObjList; | |||
| } | |||
| public Game(uint[,] mapResource, int numOfTeam) | |||
| { | |||
| } | |||
| public Game(uint[,] mapResource, int numOfTeam) | |||
| { | |||
| // if (numOfTeam > maxTeamNum) throw new TeamNumOverFlowException(); | |||
| gameMap = new Map(mapResource); | |||
| @@ -346,13 +347,13 @@ public Game(uint[,] mapResource, int numOfTeam) | |||
| teamList = new List<Team>(); | |||
| for (int i = 0; i < numOfTeam; ++i) | |||
| { | |||
| teamList.Add(new Team()); | |||
| teamList.Add(new Team()); | |||
| } | |||
| skillManager = new SkillManager(); | |||
| attackManager = new AttackManager(gameMap); | |||
| moveManager = new MoveManager(gameMap); | |||
| propManager = new PropManager(gameMap); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -54,7 +54,8 @@ namespace Gaming | |||
| // ActivateMine((Character)obj, (Mine)collisionObj); | |||
| // return MoveEngine.AfterCollision.ContinueCheck; | |||
| //} | |||
| return MoveEngine.AfterCollision.MoveMax; }, | |||
| return MoveEngine.AfterCollision.MoveMax; | |||
| }, | |||
| EndMove: obj => | |||
| { | |||
| // Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| @@ -175,49 +175,49 @@ namespace Gaming | |||
| { | |||
| while (!gameMap.Timer.IsGaming) | |||
| Thread.Sleep(1000); | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameMap.Timer.IsGaming, | |||
| () => | |||
| { | |||
| int rand = r.Next(0, len); | |||
| XY randPos = availableCellForGenerateProp[rand]; | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||
| try | |||
| { | |||
| switch (r.Next(0, 4)) | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameMap.Timer.IsGaming, | |||
| () => | |||
| { | |||
| case 0: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddLIFE(randPos)); | |||
| break; | |||
| case 1: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddSpeed(randPos)); | |||
| break; | |||
| case 2: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Shield(randPos)); | |||
| break; | |||
| case 3: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Spear(randPos)); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||
| } | |||
| }, | |||
| GameData.PropProduceTime, | |||
| () => 0 | |||
| ) | |||
| .Start(); | |||
| } | |||
| int rand = r.Next(0, len); | |||
| XY randPos = availableCellForGenerateProp[rand]; | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].EnterWriteLock(); | |||
| try | |||
| { | |||
| switch (r.Next(0, 4)) | |||
| { | |||
| case 0: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddLIFE(randPos)); | |||
| break; | |||
| case 1: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new AddSpeed(randPos)); | |||
| break; | |||
| case 2: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Shield(randPos)); | |||
| break; | |||
| case 3: | |||
| gameMap.GameObjDict[GameObjIdx.Prop].Add(new Spear(randPos)); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjIdx.Prop].ExitWriteLock(); | |||
| } | |||
| }, | |||
| GameData.PropProduceTime, | |||
| () => 0 | |||
| ) | |||
| .Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| public PropManager(Map gameMap) // 道具不能扔过墙 | |||
| { | |||
| } | |||
| public PropManager(Map gameMap) // 道具不能扔过墙 | |||
| { | |||
| this.gameMap = gameMap; | |||
| this.moveEngine = new MoveEngine( | |||
| gameMap: gameMap, | |||
| @@ -227,20 +227,21 @@ namespace Gaming | |||
| { | |||
| // obj.Place = gameMap.GetPlaceType((GameObj)obj); | |||
| obj.CanMove = false; | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); } | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| } | |||
| ); | |||
| availableCellForGenerateProp = new List<XY>(); | |||
| for (int i = 0; i < gameMap.ProtoGameMap.GetLength(0); i++) | |||
| { | |||
| for (int j = 0; j < gameMap.ProtoGameMap.GetLength(1); j++) | |||
| { | |||
| if (gameMap.ProtoGameMap[i, j] == (int)MapInfo.MapInfoObjType.Null) | |||
| for (int j = 0; j < gameMap.ProtoGameMap.GetLength(1); j++) | |||
| { | |||
| availableCellForGenerateProp.Add(GameData.GetCellCenterPos(i, j)); | |||
| if (gameMap.ProtoGameMap[i, j] == (int)MapInfo.MapInfoObjType.Null) | |||
| { | |||
| availableCellForGenerateProp.Add(GameData.GetCellCenterPos(i, j)); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -4,7 +4,7 @@ namespace Preparation.GameData | |||
| { | |||
| public static class GameData | |||
| { | |||
| #region 基本常数与常方法 | |||
| #region 基本常数与常方法 | |||
| public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 | |||
| public const int numOfStepPerSecond = 20; // 每秒行走的步数 | |||
| public const int lengthOfMap = 50000; // 地图长度 | |||
| @@ -35,8 +35,8 @@ namespace Preparation.GameData | |||
| } | |||
| public static int numOfBirthPoint = 5; | |||
| #endregion | |||
| #region 角色相关 | |||
| #endregion | |||
| #region 角色相关 | |||
| /// <summary> | |||
| /// 玩家相关 | |||
| /// </summary> | |||
| @@ -71,9 +71,9 @@ namespace Preparation.GameData | |||
| public const long GemProduceTime = 10000; | |||
| public const long PropProduceTime = 10000; | |||
| public const int PropDuration = 10000; | |||
| #endregion | |||
| #region 游戏帧相关 | |||
| #endregion | |||
| #region 游戏帧相关 | |||
| public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | |||
| #endregion | |||
| #endregion | |||
| } | |||
| } | |||
| @@ -21,7 +21,7 @@ namespace Preparation.Utility | |||
| { | |||
| return "(" + x.ToString() + "," + y.ToString() + ")"; | |||
| } | |||
| public static int operator*(XY v1, XY v2) | |||
| public static int operator *(XY v1, XY v2) | |||
| { | |||
| return (v1.x * v2.x) + (v1.y * v2.y); | |||
| } | |||
| @@ -18,7 +18,7 @@ namespace Server | |||
| public bool IsGaming | |||
| { | |||
| get => Interlocked.CompareExchange(ref isGaming, 0, 0) != 0; | |||
| set => Interlocked.Exchange(ref isGaming, value? 1: 0); | |||
| set => Interlocked.Exchange(ref isGaming, value ? 1 : 0); | |||
| } | |||
| public MessageToClient GetCopiedGameInfo() | |||
| @@ -36,14 +36,16 @@ namespace Server | |||
| return; | |||
| if (player.PlayerType == PlayerType.HumanPlayer) | |||
| { | |||
| gameInfo.HumanMessage.Add(new MessageOfHuman() { | |||
| gameInfo.HumanMessage.Add(new MessageOfHuman() | |||
| { | |||
| PlayerId = player.PlayerId | |||
| }); | |||
| return; | |||
| } | |||
| if (player.PlayerType == PlayerType.ButcherPlayer) | |||
| { | |||
| gameInfo.ButcherMessage.Add(new MessageOfButcher() { | |||
| gameInfo.ButcherMessage.Add(new MessageOfButcher() | |||
| { | |||
| PlayerId = player.PlayerId | |||
| }); | |||
| return; | |||
| @@ -69,39 +71,39 @@ namespace Server | |||
| () => IsGaming, | |||
| () => | |||
| { | |||
| lock (gameInfo) | |||
| { | |||
| for (int i = 0; i < gameInfo.HumanMessage.Count; i++) | |||
| { | |||
| if (gameInfo.HumanMessage[i] != null) | |||
| { | |||
| gameInfo.HumanMessage[i].X++; | |||
| gameInfo.HumanMessage[i].Y--; | |||
| } | |||
| } | |||
| for (int i = 0; i < gameInfo.ButcherMessage.Count; i++) | |||
| { | |||
| if (gameInfo.ButcherMessage[i] != null) | |||
| { | |||
| gameInfo.ButcherMessage[i].X--; | |||
| gameInfo.ButcherMessage[i].Y++; | |||
| } | |||
| } | |||
| } | |||
| lock (gameInfo) | |||
| { | |||
| for (int i = 0; i < gameInfo.HumanMessage.Count; i++) | |||
| { | |||
| if (gameInfo.HumanMessage[i] != null) | |||
| { | |||
| gameInfo.HumanMessage[i].X++; | |||
| gameInfo.HumanMessage[i].Y--; | |||
| } | |||
| } | |||
| for (int i = 0; i < gameInfo.ButcherMessage.Count; i++) | |||
| { | |||
| if (gameInfo.ButcherMessage[i] != null) | |||
| { | |||
| gameInfo.ButcherMessage[i].X--; | |||
| gameInfo.ButcherMessage[i].Y++; | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| 100, | |||
| () => | |||
| { | |||
| IsGaming = false; | |||
| waitHandle.Release(); | |||
| return 0; | |||
| IsGaming = false; | |||
| waitHandle.Release(); | |||
| return 0; | |||
| }, | |||
| gameTime | |||
| ).Start(); | |||
| } | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return waitHandle; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -80,42 +80,42 @@ namespace Server | |||
| 1000, | |||
| () => | |||
| { | |||
| ReportGame(); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住 | |||
| return 0; | |||
| ReportGame(); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住 | |||
| return 0; | |||
| } | |||
| ).Start(); | |||
| }) | |||
| }) | |||
| { IsBackground = true }.Start(); | |||
| new Thread(() => | |||
| { | |||
| waitHandle.Wait(); | |||
| this.endGameSem.Release(); | |||
| }) | |||
| this.endGameSem.Release(); | |||
| }) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| public void WaitForEnd() | |||
| { | |||
| this.endGameSem.Wait(); | |||
| } | |||
| } | |||
| public void WaitForEnd() | |||
| { | |||
| this.endGameSem.Wait(); | |||
| } | |||
| public void ReportGame() | |||
| { | |||
| currentGameInfo = game.GetCopiedGameInfo(); | |||
| public void ReportGame() | |||
| { | |||
| currentGameInfo = game.GetCopiedGameInfo(); | |||
| foreach (var kvp in semaDict) | |||
| { | |||
| kvp.Value.Item1.Release(); | |||
| } | |||
| foreach (var kvp in semaDict) | |||
| { | |||
| kvp.Value.Item1.Release(); | |||
| } | |||
| foreach (var kvp in semaDict) | |||
| { | |||
| kvp.Value.Item2.Wait(); | |||
| } | |||
| } | |||
| foreach (var kvp in semaDict) | |||
| { | |||
| kvp.Value.Item2.Wait(); | |||
| } | |||
| } | |||
| public GameServer() | |||
| { | |||
| } | |||
| } | |||
| public GameServer() | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -14,7 +14,8 @@ namespace Server | |||
| try | |||
| { | |||
| GameServer gameServer = new(); | |||
| Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) { | |||
| Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) | |||
| { | |||
| Services = { AvailableService.BindService(gameServer) }, | |||
| Ports = { new ServerPort("127.0.0.1", 8888, ServerCredentials.Insecure) } | |||
| }; | |||