Hra postupně stupňuje obtížnost, spawnuje další monstra. Pokud ani jeden hráč nic neudělá do začátku druhé fáze, Neko si náhodně vybere cíl a zrychlí se.

This commit is contained in:
Perry 2026-03-19 21:18:06 +01:00
parent c5adebb2db
commit c942d23a87
10 changed files with 92 additions and 7 deletions

View file

@ -101,6 +101,12 @@
/processorParam:Quality=Best
/build:sounds/ambience.wav
#begin sounds/bell.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:sounds/bell.wav
#begin sounds/camera-switch.wav
/importer:WavImporter
/processor:SoundEffectProcessor

Binary file not shown.

View file

@ -176,6 +176,9 @@ public class EventProcessor {
SoundManager.PlayVentWalk();
break;
case 18:
SoundManager.PlayBell();
break;
}
}
}

View file

@ -25,6 +25,7 @@ public static class SoundManager {
private static SoundEffect jumpscare;
private static SoundEffect nekoAnger;
private static SoundEffect nekoMove;
private static SoundEffect bell;
private static SoundEffectInstance ambienceInstance;
private static SoundEffectInstance nekoPurrInstance;
@ -51,6 +52,7 @@ public static class SoundManager {
jumpscare = Core.content.Load<SoundEffect>("sounds/jumpscare");
nekoAnger = Core.content.Load<SoundEffect>("sounds/neko-angry");
nekoMove = Core.content.Load<SoundEffect>("sounds/neko-move1");
bell = Core.content.Load<SoundEffect>("sounds/bell");
nekoPurrInstance = nekoPurr.CreateInstance();
ambienceInstance = ambience.CreateInstance();
@ -114,6 +116,8 @@ public static class SoundManager {
public static void PlayVentWalk() => ventWalk.Play();
public static void PlayBell() => bell.Play();
public static void StartNekoPurr() {
nekoPurrInstance = nekoPurr.CreateInstance();
nekoPurrInstance.IsLooped = true;

View file

@ -26,4 +26,7 @@ public class EnemyManager {
return output.ToArray();
}
public static Enemy Get(int id) => enemies[id];
public static Enemy[] GetAll() => enemies.Values.ToArray();
}

View file

@ -49,7 +49,7 @@ public class LurkEnemy : Enemy {
public override void SetDifficulty(int difficulty) {
Difficulty = difficulty;
movementOpportunity.MovementChance = ((2 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (2 + Math.Pow(1.5f, 10));
movementOpportunity.MovementChance = ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
}
public override void Update() {

View file

@ -44,7 +44,7 @@ public class MareEnemy : Enemy {
public override void SetDifficulty(int difficulty) {
Difficulty = difficulty;
movementOpportunity.MovementChance =
((2 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (2 + Math.Pow(1.5f, 10));
((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
}

View file

@ -44,7 +44,7 @@ public class NekoEnemy : Enemy {
public override void SetDifficulty(int difficulty) {
Difficulty = difficulty;
movementOpportunity.MovementChance =
((2 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (2 + Math.Pow(1.5f, 10));
((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
}
public override void Update() {
@ -64,7 +64,13 @@ public class NekoEnemy : Enemy {
Target = Server.P1;
}
else{
return;
if (GameLogic.PhaseCounter > 1){
Target = Server.Players[new Random().Next(2)];
SetDifficulty(8);
}
else{
return;
}
}
}

View file

@ -11,6 +11,7 @@ public class GameLogic {
public const int START_CAMERA = 12;
private static MovementOpportunity secondCycleTimer = new(1000);
private static MovementOpportunity gamePhaseTimer = new(30_000);
public static bool NSecondUpdate{ get; private set; } = false;
public static MapTile P1Office;
@ -20,6 +21,13 @@ public class GameLogic {
public static int OfficeDoorUsage{ get; set; } = 10;
public static int RemoteDoorUsage{ get; set; } = 3;
public static int LightUsage{ get; set; } = 2;
public static int PhaseCounter{ get; private set; } = 1;
private static List<List<Enemy>> spawnOrder;
private static int[] defaultSpawnPoints = [2, 22];
private static Random random = new();
private static bool unlimitedPower = false; // Debug
@ -62,15 +70,22 @@ public class GameLogic {
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = false, YourTiles = p1Tiles.ToArray(), OpponentTiles = p2Tiles.ToArray(), LitTiles = neutralTiles.ToArray()}, Server.P1.peer);
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = true, YourTiles = p2Tiles.ToArray(), OpponentTiles = p1Tiles.ToArray(), LitTiles = neutralTiles.ToArray()}, Server.P2.peer);
spawnOrder = [[new SpotEnemy(3), new MareEnemy(3)], [new DashEnemy(6)], [new LurkEnemy(3), new NekoEnemy(3)]];
Thread.Sleep(3000);
secondCycleTimer.Start();
gamePhaseTimer.Start();
Server.SendUpdateToAll([GameEvent.GAME_START()]);
// EnemyManager.AddEnemy(new SpotEnemy(10)).Spawn(MapManager.Get(12));
// EnemyManager.AddEnemy(new LurkEnemy(10)).Spawn(MapManager.Get(12));
EnemyManager.AddEnemy(new NekoEnemy(10)).Spawn(MapManager.Get(2));
// EnemyManager.AddEnemy(new NekoEnemy(10)).Spawn(MapManager.Get(2));
// EnemyManager.AddEnemy(new DashEnemy(10)).Spawn(MapManager.Get(12));
// EnemyManager.AddEnemy(new MareEnemy(10)).Spawn(MapManager.Get(22));
EnemyManager.AddEnemy(new LurkEnemy(4)).Spawn(MapManager.Get(2));
EnemyManager.AddEnemy(new NekoEnemy(4)).Spawn(MapManager.Get(22));
}
public static void Update() {
if(secondCycleTimer.Check()) NSecondUpdate = true;
@ -96,6 +111,9 @@ public class GameLogic {
Server.SendUpdateToAll([GameEvent.POWER_TICK(Server.P1.state.pid, Server.P1.state.power), GameEvent.POWER_TICK(Server.P2.state.pid, Server.P2.state.power)]);
if (gamePhaseTimer.Check()){
NextPhase();
}
}
EnemyManager.Update();
@ -135,4 +153,48 @@ public class GameLogic {
PowerConsumers.Where(c => c.Value.pid == player.state.pid).ToList().ForEach(c => PowerConsumers.Remove(c.Key));
Server.SendUpdateToAll([GameEvent.POWER_OUT(player.state.pid)]);
}
private static void NextPhase() {
PhaseCounter++;
Server.SendUpdateToAll([GameEvent.NEXT_PHASE()]);
int roll = random.Next(3);
switch (roll){
case 0:
int spawnRoll = random.Next(spawnOrder[0].Count);
SpawnNext(spawnOrder[0][spawnRoll]);
spawnOrder[0].RemoveAt(spawnRoll);
if (spawnOrder[0].Count == 0){
spawnOrder.RemoveAt(0);
}
break;
case 1:
Enemy[] allEnemies = EnemyManager.GetAll();
for (int i = 0; i < 2; i++){
Enemy enemy = allEnemies[random.Next(allEnemies.Length)];
enemy.SetDifficulty(enemy.Difficulty + 2);
}
break;
case 2:
Enemy[] enemies = EnemyManager.GetAll();
for (int i = 0; i < enemies.Length; i++){
enemies[i].SetDifficulty(enemies[i].Difficulty + 1);
}
break;
}
}
private static void SpawnNext(Enemy enemy) {
if ((EnemyType)enemy.TypeId == EnemyType.NEKO || (EnemyType)enemy.TypeId == EnemyType.LURK || (EnemyType)enemy.TypeId == EnemyType.MARE){
MapTile[] spawnLocations = defaultSpawnPoints.Select(i => MapManager.Get(i)).Where(t => EnemyManager.GetByLocation(t).All(e => !e.BlocksTile)).ToArray();
if (spawnLocations.Length == 0){
return;
}
enemy.Spawn(spawnLocations[random.Next(spawnLocations.Length)]);
}
else if ((EnemyType)enemy.TypeId == EnemyType.SPOT || (EnemyType)enemy.TypeId == EnemyType.DASH){
enemy.Spawn(MapManager.Get(12));
}
}
}

View file

@ -26,6 +26,7 @@ public struct GameEvent : INetSerializable{
public static GameEvent TOGGLE_LIGHT(int pid, int camId, bool state) => new(){ID = 15, Args = [pid, camId, state ? 1 : 0]};
public static GameEvent NEKO_ANGERED(int pid, int enemyId) => new(){ID = 16, Args = [pid, enemyId]};
public static GameEvent VENT_USED() => new(){ID = 17};
public static GameEvent NEXT_PHASE() => new(){ID = 18};
public int ID{ get; set; }
public bool Hideable => ID < 0;