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:
parent
7656707177
commit
25a62af483
22 changed files with 240 additions and 59 deletions
|
|
@ -7,11 +7,13 @@
|
|||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventChannel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F384e456bc26f45f5a6a6a20ae50c6e0dd1a400_003Ffb_003Fca10f160_003FEventChannel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGame_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa69b121f85054691b2a8d28643003c23136600_003Fc7_003F517f8541_003FGame_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AINetSerializable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d47105f47a240929625d0f531812b9e1c000_003F0f_003Fe2eeb2cd_003FINetSerializable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AInputManager_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4e0fe18725844db38e9480edfd0e34983e00_003F41_003Fc6f0d8ab_003FInputManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKeyValuePair_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F384e456bc26f45f5a6a6a20ae50c6e0dd1a400_003Fe8_003F7272ae72_003FKeyValuePair_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003Fe4_003F9c3fcf71_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetManager_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d47105f47a240929625d0f531812b9e1c000_003Fd6_003Fec041615_003FNetManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetSerializer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d47105f47a240929625d0f531812b9e1c000_003Fcc_003F8a34584a_003FNetSerializer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThread_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003Fb3_003F92670209_003FThread_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003F48_003F95b0ef9d_003FThrowHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003Ffb_003Fa0fd6fc3_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATitleContainer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa69b121f85054691b2a8d28643003c23136600_003F62_003F374a72ad_003FTitleContainer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AValueTuple_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003F09_003F312b9770_003FValueTuple_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
|
|
@ -96,13 +96,14 @@ public class Client {
|
|||
Player.state = packet.state;
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
private static void OnMapInit(MapInitPacket packet) {
|
||||
(int id1, int id2, ConnectorType type)[] connectorsData = new (int id1, int id2, ConnectorType type)[packet.Connectors.Length / 3];
|
||||
for (int i = 0; i < packet.Connectors.Length / 3; i++){
|
||||
connectorsData[i] = (packet.Connectors[i * 3], packet.Connectors[i * 3 + 1], (ConnectorType)packet.Connectors[i * 3 + 2]);
|
||||
(int id1, int id2, ConnectorType type, ClientPlayer? owner)[] connectorsData = new (int, int , ConnectorType, ClientPlayer?)[packet.Connectors.Length / 4];
|
||||
for (int i = 0; i < packet.Connectors.Length / 4; i++){
|
||||
connectorsData[i] = (packet.Connectors[i * 4], packet.Connectors[i * 4 + 1], (ConnectorType)packet.Connectors[i * 4 + 2], packet.Connectors[i * 4 + 3] == -1 ? null : GetPlayer(packet.Connectors[i * 4 + 3]));
|
||||
}
|
||||
ClientMapManager.InitMap(packet.UpsideDown);
|
||||
TileConnectorProjection[] connectors = connectorsData.Select(c => new TileConnectorProjection(ClientMapManager.Get(c.id1), ClientMapManager.Get(c.id2), c.type)).ToArray();
|
||||
TileConnectorProjection[] connectors = connectorsData.Select(c => new TileConnectorProjection(ClientMapManager.Get(c.id1), ClientMapManager.Get(c.id2), c.type){Owner = c.owner}).ToArray();
|
||||
ClientMapManager.InitConnectors(connectors);
|
||||
|
||||
UIManager.SpawnMapElements(connectors.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray());
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@ public class CommandManager {
|
|||
}
|
||||
|
||||
private static void SendToggleRemoteDoor(Direction direction) {
|
||||
if (!currentDoorBinds.TryGetValue(direction, out var val)) return;
|
||||
TileConnectorProjection connector = val;
|
||||
if (!currentDoorBinds.TryGetValue(direction, out var connector)) return;
|
||||
if (connector.Owner != Client.Player) return;
|
||||
|
||||
connector.Blocked = !connector.Blocked;
|
||||
Client.SendCommands([PlayerCommand.SET_DOOR_REMOTE(connector.Id, connector.Blocked)]);
|
||||
UIManager.ChangeRemoteDoorState(connector.Id, connector.Blocked);
|
||||
|
|
@ -65,6 +66,8 @@ public class CommandManager {
|
|||
}
|
||||
|
||||
public static void SendChangeCamera(int id) {
|
||||
if (id == Client.Player.state.officeTileId || id == Client.Opponent.state.officeTileId) return;
|
||||
|
||||
Client.Player.state.camera = id;
|
||||
UIManager.ChangeCamera(id);
|
||||
Client.SendCommands([PlayerCommand.SWITCH_CAM(id)]);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using FNAF_Clone.GUI;
|
||||
using FNAF_Clone.Map;
|
||||
using GlobalClassLib;
|
||||
using MonoGameLibrary.Input;
|
||||
using PacketLib;
|
||||
|
||||
namespace FNAF_Clone;
|
||||
|
|
@ -102,10 +104,50 @@ public class EventProcessor {
|
|||
break;
|
||||
|
||||
case 12:
|
||||
Console.WriteLine($"E: Game started");
|
||||
Console.WriteLine("E: Game started");
|
||||
UIManager.DisplayGameUI();
|
||||
UIManager.StartTimer();
|
||||
break;
|
||||
|
||||
case 13:
|
||||
Console.WriteLine($"E: power tick {e.Args[0]}: {e.Args[1]}");
|
||||
if (e.Args[0] == Client.Player.state.pid){
|
||||
Client.Player.state.power = e.Args[1];
|
||||
}
|
||||
else{
|
||||
Client.Opponent.state.power = e.Args[1];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 14:
|
||||
Console.WriteLine($"E: Player {e.Args[0]} powered out");
|
||||
ClientMapManager.GetAllConnectors().Where(c =>
|
||||
(c.Type == ConnectorType.DOOR_REMOTE || c.Type == ConnectorType.DOOR_OFFICE) &&
|
||||
c.Owner == Client.GetPlayer(e.Args[0])).ToList().ForEach(c =>
|
||||
{
|
||||
c.Blocked = false;
|
||||
if(c.Type == ConnectorType.DOOR_REMOTE)
|
||||
UIManager.ChangeRemoteDoorState(c.Id, false);
|
||||
});
|
||||
|
||||
if (e.Args[0] == Client.Player.state.pid){
|
||||
UIManager.ChangeDoorState(Direction.EAST, false);
|
||||
UIManager.ChangeDoorState(Direction.NORTH, false);
|
||||
UIManager.ChangeDoorState(Direction.WEST, false);
|
||||
CommandManager.AllowGameControls(false);
|
||||
UIManager.ChangeMonitorState(false);
|
||||
}
|
||||
else{
|
||||
UIManager.ChangeDoorStateOpponent(Direction.EAST, false);
|
||||
UIManager.ChangeDoorStateOpponent(Direction.NORTH, false);
|
||||
UIManager.ChangeDoorStateOpponent(Direction.WEST, false);
|
||||
UIManager.ChangeMonitorStateOpponent(false);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
FNAF_Clone/GUI/PowerIndicator.cs
Normal file
26
FNAF_Clone/GUI/PowerIndicator.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using GlobalClassLib;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace FNAF_Clone.GUI;
|
||||
|
||||
public class PowerIndicator : TextUIElement {
|
||||
private string label;
|
||||
private ClientPlayer player;
|
||||
private int lastPowerValue;
|
||||
|
||||
public PowerIndicator(Point corner1, SpriteFont font, ClientPlayer player, string label, Alignment alignment = Alignment.LEFT) : base(corner1, font, alignment, autoBounds:true) {
|
||||
this.player = player;
|
||||
this.label = label;
|
||||
lastPowerValue = player.state.power;
|
||||
Text = GetText();
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
if (player.state.power == lastPowerValue) return;
|
||||
lastPowerValue = player.state.power;
|
||||
Text = GetText();
|
||||
}
|
||||
|
||||
private string GetText() => $"{label}{(int)(((float)player.state.power / Power.MAX_POWER_VALUE) * 100)}";
|
||||
}
|
||||
|
|
@ -9,8 +9,9 @@ public class TimerUIElement : TextUIElement{
|
|||
private Stopwatch stopwatch = new();
|
||||
|
||||
|
||||
public TimerUIElement(Point corner1, SpriteFont font) : base(corner1, corner1, font) {
|
||||
public TimerUIElement(Point corner1, SpriteFont font) : base(corner1, font) {
|
||||
Text = "00:00.000";
|
||||
Bounds = (corner1, corner1 + new Point((int)Measure().X, (int)Measure().Y));
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
|
|
|
|||
|
|
@ -79,28 +79,18 @@ public class UIManager {
|
|||
|
||||
timerElement = new(new(0, 0), PixelMonoFont);
|
||||
overlayScreen.AddElement("timer", timerElement);
|
||||
officeScreen.AddElement("power-p1-office", new PowerIndicator(new(timerElement.Bounds.Item1.X, timerElement.Bounds.Item2.Y + 5), PixelMonoFont, Client.Player, "POWER: "));
|
||||
|
||||
|
||||
TextUIElement powerLabel = (TextUIElement)
|
||||
monitorScreen.AddElement("power-label", new TextUIElement(new(510, 150), PixelMonoFont){Text = "POWER:"});
|
||||
TextUIElement powerP1 = (TextUIElement)
|
||||
monitorScreen.AddElement("power-p2", new PowerIndicator(new(powerLabel.Bounds.Item1.X + 10, powerLabel.Bounds.Item2.Y + 10), PixelMonoFont, Client.Opponent, ""){Color = new Color(220, 10, 10, 255)});
|
||||
monitorScreen.AddElement("power-p1", new PowerIndicator( new (powerP1.Bounds.Item1.X, powerP1.Bounds.Item2.Y + 5), PixelMonoFont, Client.Player, ""){Color = new Color(15, 190, 247, 255)});
|
||||
|
||||
winScreen.AddElement("win-text", new TextUIElement(new(320, 180), PixelMonoFont, TextUIElement.Alignment.CENTER){Text = "YOU WIN", Color = Color.Green});
|
||||
loseScreen.AddElement("lose-text", new TextUIElement(new(320, 180), PixelMonoFont, TextUIElement.Alignment.CENTER){Text = "YOU LOSE", Color = Color.Red});
|
||||
|
||||
// overlayScreen.AddElement("test", new TextBoxUIElement(PixelMonoFont, Point.Zero, new(200, 100)));
|
||||
|
||||
// Main menu
|
||||
// TextUIElement serverIpLabel = (TextUIElement) menuScreen.AddElement("server-ip-label", new TextUIElement(new (20, 20), PixelMonoFont){Text = "ENTER SERVER IP: ", Color = Color.Gray});
|
||||
// TextBoxUIElement serverIpTextBox = (TextBoxUIElement)menuScreen.AddElement("server-ip-textbox",
|
||||
// new TextBoxUIElement(PixelMonoFont,
|
||||
// new(serverIpLabel.Bounds.Item1.X + (int)serverIpLabel.Measure().X, serverIpLabel.Bounds.Item1.Y),
|
||||
// new(640, serverIpLabel.Bounds.Item2.Y + (int)serverIpLabel.Measure().Y)));
|
||||
// serverIpTextBox.OnFocused = () => {
|
||||
// serverIpTextBox.Color = Color.LightGreen;
|
||||
// serverIpLabel.Color = Color.DarkGreen;
|
||||
// };
|
||||
// serverIpTextBox.OnUnfocused = () => {
|
||||
// serverIpTextBox.Color = Color.White;
|
||||
// serverIpLabel.Color = Color.Gray;
|
||||
// };
|
||||
|
||||
|
||||
MenuInputField usernameField = (MenuInputField)menuScreen.AddElement("username-field", new MenuInputField(PixelMonoFont, new(20, 20), "USERNAME: "));
|
||||
MenuInputField field = (MenuInputField)menuScreen.AddElement("server-ip-field", new MenuInputField(PixelMonoFont, new(usernameField.Bounds.Item1.X, usernameField.Bounds.Item2.Y + 20), "SERVER IP: ", "127.0.0.1"));
|
||||
UIElement connectButton = menuScreen.AddElement("server-ip-submit", new TextUIElement(new Point(field.Bounds.Item1.X, field.Bounds.Item2.Y), PixelMonoFont)
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ public class GameMain() : Core("fnafkooo", 1280, 720, false) {
|
|||
Keyboard.GetState().IsKeyDown(Keys.Escape))
|
||||
Exit();
|
||||
|
||||
// TODO: Add your update logic here
|
||||
|
||||
InputManager.NextInputCycle();
|
||||
Screen.UpdateAll();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices.JavaScript;
|
||||
using GlobalClassLib;
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ public class ClientMapManager {
|
|||
|
||||
for (int i = 0; i < 5; i++){
|
||||
for (int j = 0; j < 2; j++){
|
||||
map[i, j] = new MapTileProjection(CoordsToId(i, j)); // TODO: implement ownership
|
||||
map[i, j] = new MapTileProjection(CoordsToId(i, j));
|
||||
}
|
||||
map[i, 2] = new MapTileProjection(CoordsToId(i, 2));
|
||||
for (int j = 3; j < 5; j++){
|
||||
|
|
@ -26,8 +27,6 @@ public class ClientMapManager {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void InitConnectors(TileConnectorProjection[] connectors) {
|
||||
|
|
@ -42,6 +41,21 @@ public class ClientMapManager {
|
|||
|
||||
public static TileConnectorProjection[] GetConnectors(int tileId) => Get(IdToCoords(tileId)).GetAllConnectors();
|
||||
|
||||
public static TileConnectorProjection[] GetAllConnectors() {
|
||||
List<TileConnectorProjection> connectors = new();
|
||||
|
||||
for (int i = 0; i < 5; i++){
|
||||
for (int j = 0; j < 5; j++){
|
||||
MapTileProjection tile = map[i, j];
|
||||
Array.ForEach(tile.GetAllConnectors(), c => {
|
||||
if(tile.Id < c.OtherTile(tile).Id)
|
||||
connectors.Add(c);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return connectors.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public const int ID_X_OFFSET = 5; // map grid height
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using GlobalClassLib;
|
|||
namespace FNAF_Clone.Map;
|
||||
|
||||
public class MapTileProjection : GlobalMapTile<TileConnectorProjection, MapTileProjection> {
|
||||
public ClientPlayer? Owner { get; set; }
|
||||
public MapTileProjection(int id) : base(id, ClientMapManager.IdToCoords(id)) {
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,12 @@ using GlobalClassLib;
|
|||
namespace FNAF_Clone.Map;
|
||||
|
||||
public class TileConnectorProjection : GlobalTileConnector<MapTileProjection, TileConnectorProjection> {
|
||||
public ClientPlayer? Owner { get; set; }
|
||||
public TileConnectorProjection(MapTileProjection tile1, MapTileProjection tile2, ConnectorType type) : base(tile1, tile2, type) {
|
||||
}
|
||||
|
||||
public TileConnectorProjection(MapTileProjection tile2, ConnectorType type) : base(tile2, type) {
|
||||
}
|
||||
|
||||
public override TileConnectorProjection Clone() => new(Tiles.tile1, Tiles.tile2, Type);
|
||||
public override TileConnectorProjection Clone() => new(Tiles.tile1, Tiles.tile2, Type){Owner = Owner};
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -17,26 +17,41 @@ public class GameLogic {
|
|||
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();
|
||||
|
|
@ -45,6 +60,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();
|
||||
|
||||
NSecondUpdate = false;
|
||||
|
|
@ -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)]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
}
|
||||
|
|
@ -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
|
||||
});
|
||||
|
|
|
|||
5
GlobalClassLib/Power.cs
Normal file
5
GlobalClassLib/Power.cs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
namespace GlobalClassLib;
|
||||
|
||||
public static class Power {
|
||||
public const int MAX_POWER_VALUE = 1000;
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@ namespace PacketLib;
|
|||
|
||||
#nullable disable
|
||||
public struct GameEvent : INetSerializable{
|
||||
public static GameEvent PLAYER_JOIN(int pid) => new(){ID = 0, Args = [pid] }; // TODO: username sync
|
||||
public static GameEvent PLAYER_LEAVE(int pid) => new(){ID = 1, Args = [pid] }; // TODO: id constants
|
||||
public static GameEvent PLAYER_JOIN(int pid) => new(){ID = 0, Args = [pid] };
|
||||
public static GameEvent PLAYER_LEAVE(int pid) => new(){ID = 1, Args = [pid] };
|
||||
public static GameEvent SWITCH_CAM(int pid, int id) => new(){ID = 2, Args = [pid, id] };
|
||||
public static GameEvent TOGGLE_MONITOR(int pid, bool state) => new(){ID = 3, Args = [pid, state ? 1 : 0]};
|
||||
public static GameEvent TOGGLE_DOOR_OFFICE(int pid, int doorId, bool state) => new(){ID = 4, Args = [pid, doorId, state ? 1 : 0]};
|
||||
|
|
@ -21,6 +21,8 @@ public struct GameEvent : INetSerializable{
|
|||
|
||||
public static GameEvent PLAYER_WIN(int pid) => new(){ID = 11, Args = [pid]};
|
||||
public static GameEvent GAME_START() => new(){ID = 12};
|
||||
public static GameEvent POWER_TICK(int pid, int power) => new(){ID = 13, Args = [pid, power]};
|
||||
public static GameEvent POWER_OUT(int pid) => new(){ID = 14, Args = [pid]};
|
||||
|
||||
public int ID{ get; set; }
|
||||
public bool Hideable => ID < 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
namespace PacketLib;
|
||||
|
||||
public class MapInitPacket {
|
||||
public int[] Connectors { get; set; } // triplets (tile1 id, tile2 id, type)
|
||||
public int[] Connectors { get; set; } // quadruplets (tile1 id, tile2 id, type, owner)
|
||||
public int[] YourTiles { get; set; }
|
||||
public int[] OpponentTiles { get; set; }
|
||||
public bool UpsideDown { get; set; }
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ using LiteNetLib.Utils;
|
|||
|
||||
namespace PacketLib;
|
||||
|
||||
public struct PlayerState : INetSerializable { // TODO: separate mutable and immutable data
|
||||
public struct PlayerState : INetSerializable { // TODO: make a constructor
|
||||
public int pid;
|
||||
public int camera;
|
||||
public bool monitorUp;
|
||||
|
|
@ -12,6 +12,9 @@ public struct PlayerState : INetSerializable { // TODO: separate mutable and imm
|
|||
public bool[] doorStates;
|
||||
public int[] neighbouringTiles; // the indexes should correspond in both arrays
|
||||
|
||||
public int power;
|
||||
public bool poweredOut;
|
||||
|
||||
public void Serialize(NetDataWriter writer) {
|
||||
writer.Put(pid);
|
||||
writer.Put(camera);
|
||||
|
|
@ -19,6 +22,8 @@ public struct PlayerState : INetSerializable { // TODO: separate mutable and imm
|
|||
writer.PutArray(doorStates);
|
||||
writer.Put(officeTileId);
|
||||
writer.PutArray(neighbouringTiles);
|
||||
writer.Put(power);
|
||||
writer.Put(poweredOut);
|
||||
}
|
||||
|
||||
public void Deserialize(NetDataReader reader) {
|
||||
|
|
@ -28,6 +33,8 @@ public struct PlayerState : INetSerializable { // TODO: separate mutable and imm
|
|||
doorStates = reader.GetBoolArray();
|
||||
officeTileId = reader.GetInt();
|
||||
neighbouringTiles = reader.GetIntArray();
|
||||
power = reader.GetInt();
|
||||
poweredOut = reader.GetBool();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue