diff --git a/logic/GameRules.md b/logic/GameRules.md index f49482b..5c032cd 100644 --- a/logic/GameRules.md +++ b/logic/GameRules.md @@ -1,5 +1,5 @@ # 规则 -V4.3 +V4.4 - [规则](#规则) - [简则](#简则) - [地图](#地图) @@ -78,11 +78,10 @@ V4.3 8. 翻窗 ### 攻击 -- 无论近战远程均产生bullet表示攻击 - 攻击类型CommonAttackOfGhost攻击未写完的作业,会造成对应攻击力的损坏 - 捣蛋鬼攻击交互状态或前后摇的学生,将使学生眩晕4.3s -| 攻击类型 |搞蛋鬼的一般攻击CommonAttackOfGhost| 飞刀FlyingKnife | 蹦蹦炸弹BombBomb | 小炸弹JumpyDumpty | +| 攻击(子弹)类型 |搞蛋鬼的一般攻击CommonAttackOfGhost| 飞刀FlyingKnife | 蹦蹦炸弹BombBomb | 小炸弹JumpyDumpty | | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | 子弹爆炸范围 | 0 | 0 | 1000 | 500 | | 子弹攻击距离 | 1100 | 39000 | 1100 | 2200 | @@ -103,13 +102,14 @@ V4.3 - 每张地图都有10间教室,学生需要完成其中的**7间**教室的作业,才可以开启任意校门。 - 开启校门所需时间为18秒,开启的进度不清空 - 当**3间**教室的作业完成时,隐藏校门在3-5个刷新点之一随机显现;当只剩1名学生时,隐藏校门自动打开。 +- 从开启的校门或隐藏校门离开是学生终极目标 #### 勉励 -- 当达到被勉励程度达到1500000或者最大学习毅力与当前学习毅力的差值时,勉励完成,学生毅力增加对应被勉励程度。 +- 当被勉励程度达到当前损失的毅力值或1500000时,勉励完成,学生毅力增加对应被勉励程度。 - 勉励中断时,被勉励程度保留;遭到攻击时被勉励程度清空 #### 沉迷与唤醒 -- 当学生学习毅力归零时,学生原地进入沉迷状态,每毫秒增加1沉迷度 +- 学习毅力归零时,学生原地进入沉迷状态,每毫秒增加1沉迷度 - 唤醒需要时间1秒,之后学习毅力恢复至1/2。沉迷程度不清空。 - 进入沉迷状态时,如果学生原沉迷程度在(0,该玩家最大沉迷度/3)中,沉迷程度直接变为其最大沉迷度/3;原沉迷程度在[其最大沉迷度/3,其最大沉迷度x2/3)中,沉迷程度直接变为其最大沉迷度x2/3;原沉迷程度大于其最大沉迷度x2/3,从游戏中出局; - 当学生沉迷程度达到其最大沉迷程度时,从游戏中出局 @@ -128,8 +128,8 @@ V4.3 ### 信息相关 - Bgm (在structures.h/.py中的student类或Tricker类中作为其属性) 1. 不详的感觉(dangerAlert):如果捣蛋鬼进入(学生的警戒半径/捣蛋鬼的隐蔽度)的距离,则学生的dangerAlert=(int)(警戒半径/二者距离) - 2. 期待搞事的感觉(trickDesire):如果有学生进入(捣蛋鬼的警戒半径/学生的隐蔽度)的距离,则捣蛋鬼trickDesire=(警戒半径/可被发觉的最近的学生距离) - 3. 学习的声音(classVolume): 警戒半径内有人学习时,捣蛋鬼classVolume=(警戒半径x学习进度百分比)/二者距离 + 2. 期待搞事的感觉(trickDesire):如果有学生进入(捣蛋鬼的警戒半径/学生的隐蔽度)的距离,则捣蛋鬼trickDesire=(int)(警戒半径/可被发觉的最近的学生距离) + 3. 学习的声音(classVolume): 警戒半径内有人学习时,捣蛋鬼classVolume=(int)((警戒半径x学习进度百分比)/二者距离) - 可以向其他每一个队友发送不超过256字节的信息 ### 可视范围 @@ -137,8 +137,9 @@ V4.3 - 对于在从草地中的物体,物体与玩家连线上均为草地方可见 ### 道具 -- 玩家最多同时拥有三个道具 -- 可以捡起与自己处于同一个格子(cell)的道具,或将道具扔在原地 +- 玩家同时最多拥有三个道具 +- 可以捡起与自己处于同一个格子(cell)的道具 +- 可将道具扔在玩家位置 | 道具 | 对学生增益 | 学生得分条件 | 对搞蛋鬼增益 | 搞蛋鬼得分条件 | | :-------- | :-------------------------------------- | :-----------------| :-------------------------------------- |:-----------------| @@ -284,61 +285,62 @@ V4.3 ## 细则 ### 特殊说明 -- 不加说明,这里“学生”往往包括职业“教师” + - 不加说明,这里“学生”往往包括职业“教师” ### 移动 - 不鼓励选手面向地图编程,因为移动过程中你可以受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 ### 人物 -- 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 - EndAllAction()及Move指令调用数总和一帧内不超过10次 ### 初始状态 -- 玩家出生点固定且一定为空地 + - 玩家出生点固定且一定为空地 ### 道具 -- 使用钥匙相当于销毁 + - 使用钥匙相当于销毁 ### 交互 - 在指令仍在进行时,重复发出同一类型的交互指令是无效的,你需要先发出Stop指令终止进行的指令 - 实际上唤醒或勉励不同的人是有效的 + - 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 ### 学习与毕业 -- 隐藏校门与校门对于人有碰撞体积 - 一个校门同时最多可以由一人开启 + - 隐藏校门与校门对于人有碰撞体积 ### 攻击 -- 每次学生受到攻击后会损失对应子弹的攻击力的学习毅力 +- 无论近战远程均产生bullet表示攻击 - 前摇期间攻击被打断时,子弹消失。 -- 此处,前摇指 从播放攻击动作开始 攻击者不能交互 的时间 + - 每次学生受到攻击后会损失对应子弹的攻击力的学习毅力 + - 此处,前摇指 从播放攻击动作开始 攻击者不能交互 的时间 ### 沉迷与唤醒 -- 在被救时沉迷度不增加 - 不能两人同时唤醒一个人 + - 在被救时沉迷度不增加 ### 门 - 每个教学区都有2把钥匙 - 一扇门只允许同时一个人开锁门 -- 开锁门未完成前,门状态表现为原来的状态 + - 开锁门未完成前,门状态表现为原来的状态 - 开锁门进度中断后清空 ### 窗 -- 攻击可以穿过窗,道具可以在窗上 - 翻越窗户是一种交互行为,翻窗一共有两个过程 - 跳上窗:从当前位置到窗边缘中点,位置瞬移,时间=距离/爬窗速度。中断时,停留在原位置 - 爬窗:从窗一侧边缘中点到另一侧格子中心,位置渐移,时间=距离/爬窗速度。中断时,停留在另一侧格子中心 -- 通常情况下捣蛋鬼翻越窗户的速度高于学生。 +- 攻击可以穿过窗,道具可以在窗上 - 有人正在翻越窗户时,其他玩家均不可以翻越该窗户。 + - 通常情况下捣蛋鬼翻越窗户的速度高于学生。 ### 箱子 - 地图上有8个箱子 -- 同一时刻只允许一人进行开启 + - 同一时刻只允许一人进行开启 - 未开启完成的箱子在下一次需要重新开始开启。 -- 箱子开启后其中道具才可以被观测和拿取 + - 箱子开启后其中道具才可以被观测和拿取 - 箱子道具不刷新 ### 得分 -- 眩晕或毅力值归零时无牵制得分 + - 眩晕或毅力值归零时无牵制得分 ### 信息相关 - Bgm在没有符合条件的情况下,值为0。 \ No newline at end of file diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 98a0d37..f17ef0d 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -64,6 +64,29 @@ namespace Gaming } } + public bool TryRemoveBullet(Bullet bullet) + { + bullet.CanMove = false; + if (gameMap.Remove(bullet)) + { + if (bullet.BulletBombRange > 0) + { + BombedBullet bombedBullet = new(bullet); + gameMap.Add(bombedBullet); + new Thread + (() => + { + Thread.Sleep(GameData.frameDuration * 5); + gameMap.RemoveJustFromMap(bombedBullet); + } + ) + { IsBackground = true }.Start(); + } + return true; + } + else return false; + } + private void BulletBomb(Bullet bullet, GameObj? objBeingShot) { #if DEBUG @@ -72,11 +95,10 @@ namespace Gaming else Debugger.Output(bullet, "bombed without objBeingShot"); #endif - bullet.CanMove = false; + if (!TryRemoveBullet(bullet)) return; if (bullet.BulletBombRange == 0) { - gameMap.Remove(bullet); if (objBeingShot == null) { characterManager.BackSwing((Character)bullet.Parent, bullet.Backswing); @@ -88,20 +110,6 @@ namespace Gaming return; } - if (gameMap.Remove(bullet)) - { - BombedBullet bombedBullet = new(bullet); - gameMap.Add(bombedBullet); - new Thread - (() => - { - Thread.Sleep(GameData.frameDuration * 5); - gameMap.RemoveJustFromMap(bombedBullet); - } - ) - { IsBackground = true }.Start(); - } - /*if (objBeingShot != null) { else if (objBeingShot is Bullet) //子弹不能相互引爆,若要更改这一设定,取消注释即可。 @@ -178,24 +186,35 @@ namespace Gaming bullet.CanMove = true; gameMap.Add(bullet); moveEngine.MoveObj(bullet, (int)((bullet.BulletAttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms - if (bullet.CastTime > 0) { characterManager.SetPlayerState(player, PlayerStateType.TryingToAttack); - if (bullet.IsRemoteAttack) - { - new Thread + + new Thread (() => { - Thread.Sleep(bullet.CastTime); - if (player.PlayerState == PlayerStateType.TryingToAttack) + new FrameRateTaskExecutor( + loopCondition: () => player.PlayerState == PlayerStateType.TryingToAttack && gameMap.Timer.IsGaming, + loopToDo: () => + { + }, + timeInterval: GameData.checkInterval, + finallyReturn: () => 0, + maxTotalDuration: bullet.CastTime + ) + .Start(); + + if (gameMap.Timer.IsGaming) { - characterManager.SetPlayerState(player); + if (player.PlayerState == PlayerStateType.TryingToAttack) + { + characterManager.SetPlayerState(player); + } + else TryRemoveBullet(bullet); } } ) - { IsBackground = true }.Start(); - } + { IsBackground = true }.Start(); } } if (bullet != null)