Power - spotřebovává se když jsou zavřené dveře. Hráči mohou zavírat pouze dveře na svojí polovině mapy. Oprava bugu v MovementOpportunity, který způsoboval zpožďování intervalu.

This commit is contained in:
Perry 2026-03-12 22:33:35 +01:00
parent 7656707177
commit 25a62af483
22 changed files with 240 additions and 59 deletions

View file

@ -21,9 +21,17 @@ public class CommandProcessor {
Server.SendUpdateToAll([GameEvent.TOGGLE_MONITOR(pid, monitorState)]);
break;
case 2:
bool doorState = playerCommand.Args[1] == 1; // TODO: block office doors
bool doorState = playerCommand.Args[1] == 1;
currentPlayer.state.doorStates[playerCommand.Args[0]] = doorState;
MapManager.Get(currentPlayer.state.officeTileId).GetConnector(currentPlayer.state.neighbouringTiles[playerCommand.Args[0]]).Blocked = doorState;
TileConnector? officeDoor = MapManager.Get(currentPlayer.state.officeTileId).GetConnector(currentPlayer.state.neighbouringTiles[playerCommand.Args[0]]);
officeDoor.Blocked = doorState;
if (doorState){
GameLogic.PowerConsumers[officeDoor] = (GameLogic.OfficeDoorUsage, pid);
}
else{
GameLogic.PowerConsumers.Remove(officeDoor);
}
Console.WriteLine($"C: Player {pid} {(doorState ? "closed" : "opened")} door {playerCommand.Args[0]}");
Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_OFFICE(pid,playerCommand.Args[0] ,doorState)]);
@ -31,7 +39,15 @@ public class CommandProcessor {
case 3:
TileConnector? door = MapManager.Get(playerCommand.Args[0]).GetConnector(playerCommand.Args[1]);
if(door == null) return;
door.Blocked = playerCommand.Args[2] == 1;
if (door.Blocked){
GameLogic.PowerConsumers[door] = (GameLogic.RemoteDoorUsage, pid);
}
else{
GameLogic.PowerConsumers.Remove(door);
}
Console.WriteLine($"C: Player {pid} {(door.Blocked ? "closed" : "opened")} door {(playerCommand.Args[0], playerCommand.Args[1])}");
Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_REMOTE(pid, (playerCommand.Args[0], playerCommand.Args[1]), door.Blocked)]);
break;

View file

@ -12,7 +12,7 @@ public class MovementOpportunity {
public bool ConstantChance{ get; private set; }
private Stopwatch stopwatch = new();
private int stopwatchOffset = 0;
private long stopwatchOffset = 0;
private Random random = new();
@ -37,9 +37,10 @@ public class MovementOpportunity {
}
public bool Check() {
if (stopwatch.ElapsedMilliseconds + stopwatchOffset >= Interval){
stopwatchOffset = (int)(stopwatch.ElapsedMilliseconds - Interval);
stopwatch.Restart();
if (stopwatch.ElapsedMilliseconds - stopwatchOffset >= Interval){
int overshoot = (int)(stopwatch.ElapsedMilliseconds - stopwatchOffset - Interval);
stopwatchOffset = stopwatch.ElapsedMilliseconds - overshoot;
// stopwatch.Restart();
return true;
}
return false;

View file

@ -16,27 +16,42 @@ public class GameLogic {
public static MapTile P1Office;
public static MapTile P2Office;
public static MapTile[] Offices =>[P1Office, P2Office];
public static int OfficeDoorUsage{ get; set; } = 10;
public static int RemoteDoorUsage{ get; set; } = 3;
// public const int POWER_MAX = 1000;
// public static int P1Power{ get; set; } = Power.MAX_POWER_VALUE;
// public static int P2Power{ get; set; } = Power.MAX_POWER_VALUE;
// public static int[] PowerValues =>[P1Power, P2Power];
public static Dictionary<object, (int usage, int pid)> PowerConsumers{ get; set; } = new();
public static void Init() {
// Create map
MapManager.InitMap();
P1Office = MapManager.Get(10);
P2Office = MapManager.Get(14);
//
// foreach (var player in Server.Players.Values){
// player.state.power = Power.MAX_POWER_VALUE;
// }
//Send map to client
TileConnector[] connectors = MapManager.GetAllConnectors();
int[] connectorsConverted = new int[connectors.Length * 3];
int[] connectorsConverted = new int[connectors.Length * 4];
for (int i = 0; i < connectors.Length; i++){
connectorsConverted[i * 3] = connectors[i].Tiles.tile1.Id;
connectorsConverted[i * 3 + 1] = connectors[i].Tiles.tile2.Id;
connectorsConverted[i * 3 + 2] = (int)connectors[i].Type;
connectorsConverted[i * 4] = connectors[i].Tiles.tile1.Id;
connectorsConverted[i * 4 + 1] = connectors[i].Tiles.tile2.Id;
connectorsConverted[i * 4 + 2] = (int)connectors[i].Type;
connectorsConverted[i * 4 + 3] = connectors[i].Owner == null ? -1 : connectors[i].Owner.state.pid;
}
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = false}, Server.P1.peer);
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = true}, Server.P2.peer);
EnemyManager.AddEnemy(new LurkEnemy(0)).Spawn(MapManager.Get(12));
EnemyManager.AddEnemy(new NekoEnemy(0)).Spawn(MapManager.Get(2));
EnemyManager.AddEnemy(new SpotEnemy(10)).Spawn(MapManager.Get(12));
EnemyManager.AddEnemy(new SpotEnemy(0)).Spawn(MapManager.Get(12));
Thread.Sleep(3000);
secondCycleTimer.Start();
@ -44,6 +59,24 @@ public class GameLogic {
}
public static void Update() {
if(secondCycleTimer.Check()) NSecondUpdate = true;
if (NSecondUpdate){
(int p1, int p2) powerUsage = CalculatePowerUsage();
Server.P1.state.power -= powerUsage.p1;
Server.P2.state.power -= powerUsage.p2;
foreach (var player in Server.Players.Values){
if (player.state.power < 0){
player.state.poweredOut = true;
player.state.power = 0;
PowerOut(player);
}
// Server.SendUpdateToAll([GameEvent.POWER_OUT(player.state.pid)]);
}
Server.SendUpdateToAll([GameEvent.POWER_TICK(Server.P1.state.pid, Server.P1.state.power), GameEvent.POWER_TICK(Server.P2.state.pid, Server.P2.state.power)]);
}
EnemyManager.Update();
@ -55,4 +88,28 @@ public class GameLogic {
Server.Stop();
Console.WriteLine("Player " + player.state.pid + " won!");
}
private static (int p1Usage, int p2Usage) CalculatePowerUsage() {
int p1Usage = 0;
int p2Usage = 0;
foreach (var consumer in PowerConsumers){
if (consumer.Value.pid == Server.P1.state.pid){
p1Usage += consumer.Value.usage;
}
else if (consumer.Value.pid == Server.P2.state.pid){
p2Usage += consumer.Value.usage;
}
}
return (p1Usage, p2Usage);
}
private static void PowerOut(ServerPlayer player) {
foreach (var door in MapManager.GetDoors(player)){
door.Blocked = false;
}
PowerConsumers.Where(c => c.Value.pid == player.state.pid).ToList().ForEach(c => PowerConsumers.Remove(c.Key));
Server.SendUpdateToAll([GameEvent.POWER_OUT(player.state.pid)]);
}
}

View file

@ -4,6 +4,9 @@ namespace FNAF_Server.Map;
public static class MapManager {
private static MapTile[,] map = new MapTile[5, 5];
private static List<TileConnector> doors = new();
private static List<TileConnector> doorsP1 = new();
private static List<TileConnector> doorsP2 = new();
public static MapTile Get((int x, int y) coords) => map[coords.x, coords.y];
public static MapTile Get(int tileId) => Get(IdToCoords(tileId));
@ -27,14 +30,14 @@ public static class MapManager {
[(3,2)] = [(4,2,1)]
};
public static void InitMap() { // TODO: make map size not hardcoded
public static void InitMap() {
for (int i = 0; i < 5; i++){
for (int j = 0; j < 2; j++){
map[i, j] = new MapTile(CoordsToId(i, j), null); // TODO: implement ownership
map[i, j] = new MapTile(CoordsToId(i, j)){Owner = Server.P1};
}
map[i, 2] = new MapTile(CoordsToId(i, 2), null);
map[i, 2] = new MapTile(CoordsToId(i, 2));
for (int j = 3; j < 5; j++){
map[i, j] = new MapTile(CoordsToId(i, j), null);
map[i, j] = new MapTile(CoordsToId(i, j)){Owner = Server.P2};
}
}
@ -44,12 +47,15 @@ public static class MapManager {
}
foreach (var con in halfConnectors){
map[con.Key.x1, con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[c.x2, c.y2], c.type, c.value)).ToArray());
map[con.Key.x1, con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[c.x2, c.y2], c.type, c.value){Owner = Server.P1}).ToArray());
}
foreach (var con in halfConnectors){
map[4 - con.Key.x1, 4 - con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[4 - c.x2, 4 - c.y2], c.type, c.value)).ToArray());
map[4 - con.Key.x1, 4 - con.Key.y1].AddConnectors(con.Value.Select(c => new TileConnector(map[4 - c.x2, 4 - c.y2], c.type, c.value){Owner = Server.P2}).ToArray());
}
doors = GetAllConnectors().Where(c => c.Type == ConnectorType.DOOR_OFFICE || c.Type == ConnectorType.DOOR_REMOTE).ToList();
doorsP1 = doors.Where(c => c.Owner == Server.P1).ToList();
doorsP2 = doors.Where(c => c.Owner == Server.P2).ToList();
}
public static TileConnector[] GetAllConnectors() {
@ -72,4 +78,7 @@ public static class MapManager {
public const int ID_X_OFFSET = 5; // map grid height
public static int CoordsToId(int x, int y) => x * ID_X_OFFSET + y;
public static (int, int) IdToCoords(int id) => (id / ID_X_OFFSET, id % ID_X_OFFSET);
public static TileConnector[] GetDoors() => doors.ToArray();
public static TileConnector[] GetDoors(ServerPlayer player) => player == Server.P1 ? doorsP1.ToArray() : doorsP2.ToArray();
}

View file

@ -4,10 +4,9 @@ using GlobalClassLib;
namespace FNAF_Server.Map;
public class MapTile : GlobalMapTile<TileConnector, MapTile> {
public ServerPlayer Owner{ get; private set; }
public ServerPlayer? Owner{ get; set; }
public MapTile(int id, ServerPlayer owner) : base(id, MapManager.IdToCoords(id)) {
Owner = owner;
public MapTile(int id) : base(id, MapManager.IdToCoords(id)) {
}
// public int Id { get; private set; }

View file

@ -4,6 +4,7 @@ namespace FNAF_Server.Map;
public class TileConnector : GlobalTileConnector<MapTile,TileConnector> {
public int Value{ get; set; }
public ServerPlayer? Owner{ get; set; }
public TileConnector(MapTile tile1, MapTile tile2, ConnectorType type, int value) : base(tile1, tile2, type) {
Value = value;
}
@ -40,5 +41,5 @@ public class TileConnector : GlobalTileConnector<MapTile,TileConnector> {
// VENT
// }
public override TileConnector Clone() => new(Tiles.tile1, Tiles.tile2, Type, Value);
public override TileConnector Clone() => new(Tiles.tile1, Tiles.tile2, Type, Value){Owner = Owner};
}

View file

@ -3,6 +3,7 @@ using System.Collections;
using System.Diagnostics;
using System.Threading;
using FNAF_Server.Map;
using GlobalClassLib;
using LiteNetLib;
using LiteNetLib.Utils;
using PacketLib;
@ -104,7 +105,9 @@ public class Server {
state = new PlayerState {
pid = peer.Id,
camera = GameLogic.START_CAMERA,
doorStates = [false, false, false]
doorStates = [false, false, false],
power = Power.MAX_POWER_VALUE,
poweredOut = false
},
username = packet.username
});