Rozsvěcení a zhasínání světel, sprity pro místnosti, indikátory rozsvícených světel, po konci hry je hráč vrácen do hlavního menu

This commit is contained in:
Perry 2026-03-16 20:43:53 +01:00
parent 25a62af483
commit 55fd052072
27 changed files with 338 additions and 113 deletions

View file

@ -12,6 +12,7 @@
<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_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_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_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_003ASpriteBatch_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa69b121f85054691b2a8d28643003c23136600_003F98_003F17ad8de4_003FSpriteBatch_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_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_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_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>

View file

@ -98,16 +98,7 @@ public class Client {
#nullable enable #nullable enable
private static void OnMapInit(MapInitPacket packet) { private static void OnMapInit(MapInitPacket packet) {
(int id1, int id2, ConnectorType type, ClientPlayer? owner)[] connectorsData = new (int, int , ConnectorType, ClientPlayer?)[packet.Connectors.Length / 4]; ClientMapManager.InitMap(packet.Connectors, packet.YourTiles, packet.OpponentTiles, packet.LitTiles, packet.UpsideDown);
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){Owner = c.owner}).ToArray();
ClientMapManager.InitConnectors(connectors);
UIManager.SpawnMapElements(connectors.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray());
} }
public static void Update() { public static void Update() {

View file

@ -6,7 +6,7 @@ using MonoGameLibrary.Graphics;
namespace FNAF_Clone; namespace FNAF_Clone;
public class ClientEnemy : GlobalEnemy<MapTileProjection, TileConnectorProjection> { public class ClientEnemy : GlobalEnemy<MapTileProjection, TileConnectorProjection> {
public ClientEnemy(int typeId, string name, int id, UIElement sprite, int difficulty, MapTileProjection location, JumpscareUIElement jumpscareSprite) : base(difficulty, id) { public ClientEnemy(int typeId, string name, int id, EnemyUIElement sprite, int difficulty, MapTileProjection location, JumpscareUIElement jumpscareSprite) : base(difficulty, id) {
Name = name; Name = name;
TypeId = typeId; TypeId = typeId;
Sprite = sprite; Sprite = sprite;

View file

@ -6,12 +6,13 @@ using FNAF_Clone.GUI;
using FNAF_Clone.Map; using FNAF_Clone.Map;
using GlobalClassLib; using GlobalClassLib;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using MonoGameLibrary.Graphics;
namespace FNAF_Clone; namespace FNAF_Clone;
public static class ClientEnemyManager { public static class ClientEnemyManager {
private static Dictionary<int, ClientEnemy> enemies = new(); private static Dictionary<int, ClientEnemy> enemies = new();
private static Point cameraCorner = new Point(64, 64); private static Point cameraCorner = new(64, 64);
private static Action defaultAfterJumpscare = UIManager.ShowDeathScreen; private static Action defaultAfterJumpscare = UIManager.ShowDeathScreen;
public static void AddEnemy(ClientEnemy enemy) { public static void AddEnemy(ClientEnemy enemy) {
@ -26,25 +27,27 @@ public static class ClientEnemyManager {
(int)type, (int)type,
"Lurk", "Lurk",
id, id,
new UIElement(UIManager.EnemyAtlas[0], cameraCorner), new EnemyUIElement(UIManager.EnemyAtlas["lurk-lit"], UIManager.EnemyAtlas["lurk-unlit"], cameraCorner),
difficulty, difficulty,
location, location,
new JumpscareUIElement(UIManager.EnemyAtlas[0], new(0, 0), 3, 2, 2, 0.1f, afterStop:defaultAfterJumpscare))); new JumpscareUIElement(UIManager.EnemyAtlas["lurk-lit"], new(0, 0), 3, 2, 2, 0.1f, afterStop:defaultAfterJumpscare)
));
break; break;
case EnemyType.NEKO: case EnemyType.NEKO:
AddEnemy(new ClientEnemy( AddEnemy(new ClientEnemy(
(int)type, (int)type,
"Neko", "Neko",
id, id,
new UIElement(UIManager.EnemyAtlas[1], cameraCorner), new EnemyUIElement(UIManager.EnemyAtlas["neko-lit"], UIManager.EnemyAtlas["neko-unlit"], cameraCorner, 1),
difficulty, difficulty,
location, location,
new JumpscareUIElement(UIManager.EnemyAtlas[1], new(0, -30), 3, 2, 2, 0.1f, afterStop:defaultAfterJumpscare))); new JumpscareUIElement(UIManager.EnemyAtlas["neko-lit"], new(0, -30), 3, 2, 2, 0.1f, afterStop:defaultAfterJumpscare)
));
break; break;
case EnemyType.SPOT: case EnemyType.SPOT:
UIElement element = EnemyUIElement element =
new UIElement([UIManager.EnemyAtlas[2], UIManager.EnemyAtlas[3], UIManager.EnemyAtlas[4], UIManager.EnemyAtlas[5]], cameraCorner); new EnemyUIElement([UIManager.EnemyAtlas["spot-awake-lit"], UIManager.EnemyAtlas["spot-asleep-lit"]],[UIManager.EnemyAtlas["spot-awake-unlit"], UIManager.EnemyAtlas["spot-asleep-unlit"]], cameraCorner, 2);
element.SetTexture(2); element.SetTexture(true, 1);
AddEnemy(new ClientEnemy( AddEnemy(new ClientEnemy(
(int)type, (int)type,
"Spot", "Spot",
@ -52,7 +55,8 @@ public static class ClientEnemyManager {
element, element,
difficulty, difficulty,
location, location,
new JumpscareUIElement(UIManager.EnemyAtlas[2], new(0, 0), 3, 2, 2, 0.1f, afterStop:defaultAfterJumpscare))); new JumpscareUIElement(UIManager.EnemyAtlas["spot-awake-lit"], new(0, 0), 3, 2, 2, 0.1f, afterStop:defaultAfterJumpscare)
));
break; break;
} }
} }

View file

@ -16,7 +16,8 @@ public class CommandManager {
("Toggle left door", Keys.A, ToggleDoorLeft), ("Toggle left door", Keys.A, ToggleDoorLeft),
("Toggle centre door", Keys.W, ToggleDoorCentre), ("Toggle centre door", Keys.W, ToggleDoorCentre),
("Toggle right door", Keys.D, ToggleDoorRight), ("Toggle right door", Keys.D, ToggleDoorRight),
("Toggle back door", Keys.S, ToggleDoorBack) ("Toggle back door", Keys.S, ToggleDoorBack),
("Toggle light", Keys.F, ToggleLight)
]; ];
private static InputListenerHook allControlsHook{ get; } = new(true); private static InputListenerHook allControlsHook{ get; } = new(true);
@ -42,6 +43,8 @@ public class CommandManager {
private static Dictionary<Direction, TileConnectorProjection> currentDoorBinds = new(); private static Dictionary<Direction, TileConnectorProjection> currentDoorBinds = new();
private static void ToggleLight() => SendToggleLight(Client.Player.state.camera, !ClientMapManager.Get(Client.Player.state.camera).Lit);
private static void SendToggleDoor(Direction direction) { private static void SendToggleDoor(Direction direction) {
if (Screen.CurrentScreen.Label == UIManager.ScreenTypes.CAMERAS){ if (Screen.CurrentScreen.Label == UIManager.ScreenTypes.CAMERAS){
SendToggleRemoteDoor(direction); SendToggleRemoteDoor(direction);
@ -80,4 +83,11 @@ public class CommandManager {
currentDoorBinds.Add(dir, c); currentDoorBinds.Add(dir, c);
} }
} }
private static void SendToggleLight(int id, bool state) {
if(!Client.Player.state.monitorUp || ClientMapManager.Get(id).Owner != Client.Player) return;
ClientMapManager.Get(id).Lit = state;
UIManager.UpdateCameras([id]);
Client.SendCommands([PlayerCommand.SET_LIGHT(id, state)]);
}
} }

View file

@ -22,6 +22,9 @@
#begin images/office-definition.xml #begin images/office-definition.xml
/copy:images/office-definition.xml /copy:images/office-definition.xml
#begin images/rooms-definition.xml
/copy:images/rooms-definition.xml
#begin images/SpriteSheet_enemies.png #begin images/SpriteSheet_enemies.png
/importer:TextureImporter /importer:TextureImporter
/processor:TextureProcessor /processor:TextureProcessor
@ -58,6 +61,18 @@
/processorParam:TextureFormat=Color /processorParam:TextureFormat=Color
/build:images/SpriteSheet_office.png /build:images/SpriteSheet_office.png
#begin images/SpriteSheet_rooms.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:images/SpriteSheet_rooms.png;images/SpriteSheet_map.png
#begin images/SpriteSheet_testBlocks.png #begin images/SpriteSheet_testBlocks.png
/importer:TextureImporter /importer:TextureImporter
/processor:TextureProcessor /processor:TextureProcessor

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -1,15 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TextureAtlas count="9"> <TextureAtlas>
<Texture>images/SpriteSheet_enemies</Texture> <Texture>images/SpriteSheet_enemies</Texture>
<Regions> <Regions>
<Region id = "0" name="lurk" x="0" y="0" width="240" height="240"/> <Region name="lurk-lit" x="0" y="0" width="240" height="240"/>
<Region id = "1" name="neko" x="0" y="240" width="240" height="240"/> <Region name="lurk-unlit" x="240" y="0" width="240" height="240"/>
<Region id = "2" name="spot-awake-lit" x="0" y="480" width="240" height="240"/> <Region name="neko-lit" x="0" y="240" width="240" height="240"/>
<Region id = "3" name="spot-awake-unlit" x="240" y="480" width="240" height="240"/> <Region name="neko-unlit" x="240" y="240" width="240" height="240"/>
<Region id = "4" name="spot-asleep-lit" x="0" y="720" width="240" height="240"/> <Region name="spot-awake-lit" x="0" y="480" width="240" height="240"/>
<Region id = "5" name="spot-asleep-unlit" x="240" y="720" width="240" height="240"/> <Region name="spot-awake-unlit" x="240" y="480" width="240" height="240"/>
<Region id = "6" name="dash" x="0" y="960" width="240" height="240"/> <Region name="spot-asleep-lit" x="0" y="720" width="240" height="240"/>
<Region id = "7" name="mare-lit" x="0" y="1200" width="240" height="240"/> <Region name="spot-asleep-unlit" x="240" y="720" width="240" height="240"/>
<Region id = "8" name="mare-unlit" x="240" y="1200" width="240" height="240"/> <Region name="dash" x="0" y="960" width="240" height="240"/>
<Region name="mare-lit" x="0" y="1200" width="240" height="240"/>
<Region name="mare-unlit" x="240" y="1200" width="240" height="240"/>
</Regions> </Regions>
</TextureAtlas> </TextureAtlas>

View file

@ -1,37 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TextureAtlas count="25"> <TextureAtlas>
<Texture>images/SpriteSheet_monitor</Texture> <Texture>images/SpriteSheet_monitor</Texture>
<Regions> <Regions>
<Region id = "0" name="screen" x="0" y="0" width="640" height="360"/> <Region name="screen" x="0" y="0" width="640" height="360"/>
<Region id = "1" name="view-frame" x="0" y="360" width="244" height="251"/> <Region name="view-frame" x="0" y="360" width="244" height="251"/>
<Region id = "2" name="map-frame" x="244" y="360" width="164" height="171"/> <Region name="map-frame" x="244" y="360" width="164" height="171"/>
<Region id = "3" name="map" x="408" y="360" width="164" height="171"/> <Region name="map" x="408" y="360" width="164" height="171"/>
<Region id = "4" name="light-button" x="244" y="531" width="36" height="42"/> <Region name="light-button" x="244" y="531" width="36" height="42"/>
<Region id = "5" name="door-remote-open" x="280" y="531" width="32" height="33"/> <Region name="door-remote-open" x="280" y="531" width="32" height="33"/>
<Region id = "6" name="door-remote-closed" x="312" y="531" width="32" height="33"/> <Region name="door-remote-closed" x="312" y="531" width="32" height="33"/>
<Region id = "7" name="door-office-p1-left-open" x="344" y="531" width="32" height="33"/> <Region name="door-office-p1-left-open" x="344" y="531" width="32" height="33"/>
<Region id = "8" name="door-office-p1-left-closed" x="376" y="531" width="32" height="33"/> <Region name="door-office-p1-left-closed" x="376" y="531" width="32" height="33"/>
<Region id = "9" name="door-office-p1-centre-open" x="408" y="531" width="32" height="33"/> <Region name="door-office-p1-centre-open" x="408" y="531" width="32" height="33"/>
<Region id = "10" name="door-office-p1-centre-closed" x="440" y="531" width="32" height="33"/> <Region name="door-office-p1-centre-closed" x="440" y="531" width="32" height="33"/>
<Region id = "11" name="door-office-p1-right-open" x="472" y="531" width="32" height="33"/> <Region name="door-office-p1-right-open" x="472" y="531" width="32" height="33"/>
<Region id = "12" name="door-office-p1-right-closed" x="504" y="531" width="32" height="33"/> <Region name="door-office-p1-right-closed" x="504" y="531" width="32" height="33"/>
<Region id = "13" name="door-office-p2-right-open" x="344" y="564" width="32" height="33"/> <Region name="door-office-p2-right-open" x="344" y="564" width="32" height="33"/>
<Region id = "14" name="door-office-p2-right-closed" x="376" y="564" width="32" height="33"/> <Region name="door-office-p2-right-closed" x="376" y="564" width="32" height="33"/>
<Region id = "15" name="door-office-p2-centre-open" x="408" y="564" width="32" height="33"/> <Region name="door-office-p2-centre-open" x="408" y="564" width="32" height="33"/>
<Region id = "16" name="door-office-p2-centre-closed" x="440" y="564" width="32" height="33"/> <Region name="door-office-p2-centre-closed" x="440" y="564" width="32" height="33"/>
<Region id = "17" name="door-office-p2-left-open" x="472" y="564" width="32" height="33"/> <Region name="door-office-p2-left-open" x="472" y="564" width="32" height="33"/>
<Region id = "18" name="door-office-p2-left-closed" x="504" y="564" width="32" height="33"/> <Region name="door-office-p2-left-closed" x="504" y="564" width="32" height="33"/>
<Region id = "19" name="eye-opponent-open" x="572" y="360" width="32" height="14"/> <Region name="eye-opponent-open" x="572" y="360" width="32" height="14"/>
<Region id = "20" name="eye-opponent-open" x="604" y="360" width="32" height="14"/> <Region name="eye-opponent-open" x="604" y="360" width="32" height="14"/>
<Region id = "21" name="eye-player-open" x="572" y="374" width="32" height="14"/> <Region name="eye-player-open" x="572" y="374" width="32" height="14"/>
<Region name="eye-small-opponent-open" x="572" y="402" width="32" height="9"/>
<Region name="eye-small-opponent-closed" x="604" y="402" width="32" height="9"/>
<Region name="eye-small-player" x="572" y="411" width="32" height="9"/>
<Region name="map-light-indicator" x="280" y="564" width="32" height="32"/>
<Region id = "22" name="eye-small-opponent-open" x="572" y="402" width="32" height="9"/>
<Region id = "23" name="eye-small-opponent-closed" x="604" y="402" width="32" height="9"/>
<Region id = "24" name="eye-small-player" x="572" y="411" width="32" height="9"/>

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TextureAtlas count="6"> <TextureAtlas>
<Texture>images/SpriteSheet_office</Texture> <Texture>images/SpriteSheet_office</Texture>
<Regions> <Regions>
<Region id = "0" name="llc" x="0" y="0" width="200" height="360"/> <Region name="left-closed" x="0" y="0" width="200" height="360"/>
<Region id = "1" name="lmc" x="200" y="0" width="240" height="360"/> <Region name="centre-closed" x="200" y="0" width="240" height="360"/>
<Region id = "2" name="lrc" x="440" y="0" width="200" height="360"/> <Region name="right-closed" x="440" y="0" width="200" height="360"/>
<Region id = "3" name="llo" x="0" y="360" width="200" height="360"/> <Region name="left-open" x="0" y="360" width="200" height="360"/>
<Region id = "4" name="lmo" x="200" y="360" width="240" height="360"/> <Region name="centre-open" x="200" y="360" width="240" height="360"/>
<Region id = "5" name="lro" x="440" y="360" width="200" height="360"/> <Region name="right-open" x="440" y="360" width="200" height="360"/>
</Regions> </Regions>
</TextureAtlas> </TextureAtlas>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<TextureAtlas>
<Texture>images/SpriteSheet_map</Texture>
<Regions>
<Region name="room4" x="0" y="0" width="240" height="240"/>
<Region name="room3" x="0" y="240" width="240" height="240"/>
<Region name="room2" x="0" y="480" width="240" height="240"/>
<Region name="room1" x="0" y="720" width="240" height="240"/>
<Region name="room0" x="0" y="960" width="240" height="240"/>
<Region name="room9" x="240" y="0" width="240" height="240"/>
<Region name="room8" x="240" y="240" width="240" height="240"/>
<Region name="room7" x="240" y="480" width="240" height="240"/>
<Region name="room6" x="240" y="720" width="240" height="240"/>
<Region name="room5" x="240" y="960" width="240" height="240"/>
<Region name="room14" x="480" y="0" width="240" height="240"/>
<Region name="room13" x="480" y="240" width="240" height="240"/>
<Region name="room12" x="480" y="480" width="240" height="240"/>
<Region name="room11" x="480" y="720" width="240" height="240"/>
<Region name="room10" x="480" y="960" width="240" height="240"/>
<Region name="room19" x="720" y="0" width="240" height="240"/>
<Region name="room18" x="720" y="240" width="240" height="240"/>
<Region name="room17" x="720" y="480" width="240" height="240"/>
<Region name="room16" x="720" y="720" width="240" height="240"/>
<Region name="room15" x="720" y="960" width="240" height="240"/>
<Region name="room24" x="960" y="0" width="240" height="240"/>
<Region name="room23" x="960" y="240" width="240" height="240"/>
<Region name="room22" x="960" y="480" width="240" height="240"/>
<Region name="room21" x="960" y="720" width="240" height="240"/>
<Region name="room20" x="960" y="960" width="240" height="240"/>
</Regions>
</TextureAtlas>

View file

@ -95,7 +95,7 @@ public class EventProcessor {
case 10: case 10:
Console.WriteLine($"E: Spot:{e.Args[0]} turned {(e.Args[1] == 1 ? "on" : " off")}"); Console.WriteLine($"E: Spot:{e.Args[0]} turned {(e.Args[1] == 1 ? "on" : " off")}");
ClientEnemyManager.Get(e.Args[0]).Sprite.SetTexture(e.Args[1] == 1 ? 0 : 2); ClientEnemyManager.Get(e.Args[0]).Sprite.SetTexture(e.Args[1] == 1 ? 0 : 1);
break; break;
case 11: case 11:
@ -110,7 +110,7 @@ public class EventProcessor {
break; break;
case 13: case 13:
Console.WriteLine($"E: power tick {e.Args[0]}: {e.Args[1]}"); // Console.WriteLine($"E: power tick {e.Args[0]}: {e.Args[1]}");
if (e.Args[0] == Client.Player.state.pid){ if (e.Args[0] == Client.Player.state.pid){
Client.Player.state.power = e.Args[1]; Client.Player.state.power = e.Args[1];
} }
@ -120,7 +120,7 @@ public class EventProcessor {
break; break;
case 14: case 14: // powerout
Console.WriteLine($"E: Player {e.Args[0]} powered out"); Console.WriteLine($"E: Player {e.Args[0]} powered out");
ClientMapManager.GetAllConnectors().Where(c => ClientMapManager.GetAllConnectors().Where(c =>
(c.Type == ConnectorType.DOOR_REMOTE || c.Type == ConnectorType.DOOR_OFFICE) && (c.Type == ConnectorType.DOOR_REMOTE || c.Type == ConnectorType.DOOR_OFFICE) &&
@ -130,6 +130,9 @@ public class EventProcessor {
if(c.Type == ConnectorType.DOOR_REMOTE) if(c.Type == ConnectorType.DOOR_REMOTE)
UIManager.ChangeRemoteDoorState(c.Id, false); UIManager.ChangeRemoteDoorState(c.Id, false);
}); });
foreach (var tile in ClientMapManager.GetAllTiles()){
tile.Lit = false;
}
if (e.Args[0] == Client.Player.state.pid){ if (e.Args[0] == Client.Player.state.pid){
UIManager.ChangeDoorState(Direction.EAST, false); UIManager.ChangeDoorState(Direction.EAST, false);
@ -147,6 +150,16 @@ public class EventProcessor {
break; break;
case 15: // light
bool lightState = e.Args[2] == 1;
Console.WriteLine($"E: Player {e.Args[0]} {(lightState ? "lit": "unlit")} tile {e.Args[1]}");
if (e.Args[0] == Client.Player.state.pid){
if (ClientMapManager.Get(e.Args[1]).Lit != lightState) Console.WriteLine("!!! DESYNC: LIGHT STATE");
break;
}
ClientMapManager.Get(e.Args[1]).Lit = lightState;
break;
} }
} }

View file

@ -0,0 +1,33 @@
using System.Linq;
using Microsoft.Xna.Framework;
using MonoGameLibrary.Graphics;
namespace FNAF_Clone.GUI;
public class EnemyUIElement : UIElement {
private int unlitTexturesId;
private bool currentlyLit = true;
public EnemyUIElement(TextureRegion litTexture, TextureRegion unlitTexture, Point position, int drawPriority = 0) : base([litTexture, unlitTexture], position, drawPriority) {
unlitTexturesId = 1;
}
public EnemyUIElement(TextureRegion[] litTextures, TextureRegion[] unlitTextures, Point position, int drawPriority = 0) : base(litTextures.Concat(unlitTextures).ToArray(), position, drawPriority) {
unlitTexturesId = litTextures.Length;
}
public void SetTexture(bool lit, int id) {
currentlyLit = lit;
base.SetTexture(lit ? id : id + unlitTexturesId);
}
public override void SetTexture(int id) {
base.SetTexture(currentlyLit ? id : id + unlitTexturesId);
}
public void SetTexture(bool lit) {
if(lit == currentlyLit) return;
currentlyLit = lit;
SetTexture(lit ? currentTextureId - unlitTexturesId : currentTextureId);
}
}

View file

@ -68,6 +68,8 @@ public class Screen {
public string Label{ get; } public string Label{ get; }
private Dictionary<string, UIElement> elements = new(); private Dictionary<string, UIElement> elements = new();
private List<UIElement> elementsInDrawOrder = new();
public bool Active { get; private set; } = false; public bool Active { get; private set; } = false;
private InputListenerHook mouseInputHook = new(true); private InputListenerHook mouseInputHook = new(true);
private bool temporary = false; private bool temporary = false;
@ -87,6 +89,15 @@ public class Screen {
public UIElement AddElement(string id, UIElement element) { public UIElement AddElement(string id, UIElement element) {
elements.Add(id, element); elements.Add(id, element);
int insertIndex = elementsInDrawOrder.FindLastIndex(e => e.DrawPriority == element.DrawPriority);
if (insertIndex == -1){
elementsInDrawOrder.Add(element);
}
else{
elementsInDrawOrder.Insert(insertIndex + 1, element);
}
return element; return element;
} }
@ -120,7 +131,7 @@ public class Screen {
} }
public void Draw(SpriteBatch spriteBatch) { public void Draw(SpriteBatch spriteBatch) {
foreach (var val in elements.Values){ foreach (var val in elementsInDrawOrder){
val.Draw(spriteBatch); val.Draw(spriteBatch);
} }
} }

View file

@ -13,6 +13,7 @@ public class UIElement {
public bool Active { get; set; } = true; public bool Active { get; set; } = true;
public bool Pressable { get; set; } = false; public bool Pressable { get; set; } = false;
public bool Visible { get; set; } = true; public bool Visible { get; set; } = true;
public int DrawPriority { get; } = 0;
protected (Point, Point) _bounds; protected (Point, Point) _bounds;
public (Point, Point) Bounds{ public (Point, Point) Bounds{
@ -45,14 +46,16 @@ public class UIElement {
screenSpaceBounds = (Bounds.Item1.MultiplyByScalar(pixelScaleMultiplier), Bounds.Item2.MultiplyByScalar(pixelScaleMultiplier)); screenSpaceBounds = (Bounds.Item1.MultiplyByScalar(pixelScaleMultiplier), Bounds.Item2.MultiplyByScalar(pixelScaleMultiplier));
} }
public UIElement(TextureRegion texture, Point position) { public UIElement(TextureRegion texture, Point position, int drawPriority = 0) {
Textures.Add(texture); Textures.Add(texture);
Bounds = (position, position + new Point(texture.Width, texture.Height)); Bounds = (position, position + new Point(texture.Width, texture.Height));
DrawPriority = drawPriority;
LoadPixelScaleMultiplier(); LoadPixelScaleMultiplier();
} }
public UIElement(TextureRegion[] textures, Point position) { public UIElement(TextureRegion[] textures, Point position, int drawPriority = 0) {
this.Textures.AddRange(textures); this.Textures.AddRange(textures);
Bounds = (position, position + new Point(textures[0].Width, textures[0].Height)); Bounds = (position, position + new Point(textures[0].Width, textures[0].Height));
DrawPriority = drawPriority;
LoadPixelScaleMultiplier(); LoadPixelScaleMultiplier();
} }
@ -62,7 +65,7 @@ public class UIElement {
LoadPixelScaleMultiplier(); LoadPixelScaleMultiplier();
} }
public void SetTexture(int textureId) { public virtual void SetTexture(int textureId) {
if (textureId >= Textures.Count){ if (textureId >= Textures.Count){
Console.WriteLine($"WARNING: TEXTURE {textureId} OUT OF BOUNDS"); Console.WriteLine($"WARNING: TEXTURE {textureId} OUT OF BOUNDS");
return; return;

View file

@ -7,6 +7,7 @@ using FNAF_Clone.Map;
using GlobalClassLib; using GlobalClassLib;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGameLibrary; using MonoGameLibrary;
using MonoGameLibrary.Graphics; using MonoGameLibrary.Graphics;
using MonoGameLibrary.Input; using MonoGameLibrary.Input;
@ -37,6 +38,7 @@ public class UIManager {
public static TextureAtlas OfficeAtlas{ get; private set; } public static TextureAtlas OfficeAtlas{ get; private set; }
public static TextureAtlas MonitorAtlas{ get; private set; } public static TextureAtlas MonitorAtlas{ get; private set; }
public static TextureAtlas EnemyAtlas{ get; private set; } public static TextureAtlas EnemyAtlas{ get; private set; }
public static TextureAtlas RoomAtlas{ get; private set; }
public static SpriteFont PixelMonoFont{ get; private set; } public static SpriteFont PixelMonoFont{ get; private set; }
public static int GlobalPixelMultiplier{ get; private set; } public static int GlobalPixelMultiplier{ get; private set; }
@ -44,6 +46,8 @@ public class UIManager {
// private Dictionary<(int, int), UIElement> doorElements = new(); // private Dictionary<(int, int), UIElement> doorElements = new();
private static Dictionary<int, UIElement> enemyElements = new(); private static Dictionary<int, UIElement> enemyElements = new();
private static TimerUIElement timerElement; private static TimerUIElement timerElement;
private static UIElement cameraView;
private static Dictionary<int, UIElement> lightIndicators = new();
private static InputListenerHook monitorSwitchHook; private static InputListenerHook monitorSwitchHook;
@ -52,6 +56,7 @@ public class UIManager {
OfficeAtlas = TextureAtlas.FromFile(Core.content, "images/office-definition.xml"); OfficeAtlas = TextureAtlas.FromFile(Core.content, "images/office-definition.xml");
MonitorAtlas = TextureAtlas.FromFile(Core.content, "images/monitor-definition.xml"); MonitorAtlas = TextureAtlas.FromFile(Core.content, "images/monitor-definition.xml");
EnemyAtlas = TextureAtlas.FromFile(Core.content, "images/enemies-definition.xml"); EnemyAtlas = TextureAtlas.FromFile(Core.content, "images/enemies-definition.xml");
RoomAtlas = TextureAtlas.FromFile(Core.content, "images/rooms-definition.xml");
PixelMonoFont = Core.content.Load<SpriteFont>("ponderosa"); PixelMonoFont = Core.content.Load<SpriteFont>("ponderosa");
} }
@ -62,21 +67,28 @@ public class UIManager {
// Screen.SetScreen(ScreenTypes.OFFICE); // Screen.SetScreen(ScreenTypes.OFFICE);
// Screen.SetOverlayScreen(ScreenTypes.OVERLAY); // Screen.SetOverlayScreen(ScreenTypes.OVERLAY);
officeScreen.AddElement("office_left", new UIElement([OfficeAtlas[3], OfficeAtlas[0]], Point.Zero)); officeScreen.AddElement("office_left", new UIElement([OfficeAtlas["left-open"], OfficeAtlas["left-closed"]], Point.Zero));
officeScreen.AddElement("office_centre", new UIElement([OfficeAtlas[4], OfficeAtlas[1]], new Point(200, 0))); officeScreen.AddElement("office_centre", new UIElement([OfficeAtlas["centre-open"], OfficeAtlas["centre-closed"]], new Point(200, 0)));
officeScreen.AddElement("office_right", new UIElement([OfficeAtlas[5], OfficeAtlas[2]], new Point(440, 0))); officeScreen.AddElement("office_right", new UIElement([OfficeAtlas["right-open"], OfficeAtlas["right-closed"]], new Point(440, 0)));
// officeScreen.AddElement("test", // officeScreen.AddElement("test",
// new UIElement(testAtlas[0], Point.Zero) // new UIElement(testAtlas[0], Point.Zero)
// {Pressable = true, OnMousePress = () => Console.WriteLine("Pressed!")} // {Pressable = true, OnMousePress = () => Console.WriteLine("Pressed!")}
// ); // );
monitorScreen.AddElement("screen", new UIElement(MonitorAtlas[0], Point.Zero)); monitorScreen.AddElement("screen", new UIElement(MonitorAtlas["screen"], Point.Zero));
monitorScreen.AddElement("view-frame", new UIElement(MonitorAtlas[1], new Point(62, 55))); monitorScreen.AddElement("view-frame", new UIElement(MonitorAtlas["view-frame"], new Point(62, 55)));
monitorScreen.AddElement("map-frame", new UIElement(MonitorAtlas[2], new Point(334, 135))); monitorScreen.AddElement("map-frame", new UIElement(MonitorAtlas["map-frame"], new Point(334, 135)));
monitorScreen.AddElement("map", new UIElement(MonitorAtlas[3], new Point(334, 135))); monitorScreen.AddElement("map", new UIElement(MonitorAtlas["map"], new Point(334, 135)));
List<TextureRegion> rooms = new();
for (int i = 0; i < ClientMapManager.MAP_SIDE_LENGTH * ClientMapManager.MAP_SIDE_LENGTH; i++){
rooms.Add(RoomAtlas["room" + i]);
}
cameraView = new UIElement(rooms.ToArray(), new(64, 64));
monitorScreen.AddElement("camera-view", cameraView);
// main menu
timerElement = new(new(0, 0), PixelMonoFont); timerElement = new(new(0, 0), PixelMonoFont);
overlayScreen.AddElement("timer", timerElement); 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: ")); officeScreen.AddElement("power-p1-office", new PowerIndicator(new(timerElement.Bounds.Item1.X, timerElement.Bounds.Item2.Y + 5), PixelMonoFont, Client.Player, "POWER: "));
@ -126,22 +138,23 @@ public class UIManager {
CommandManager.AllowGameControls(true); CommandManager.AllowGameControls(true);
UpdateCameras([Client.Player.state.camera]); // in case there is an enemy on the default camera UpdateCameras([Client.Player.state.camera]); // in case there is an enemy on the default camera
cameraView.SetTexture(Client.Player.state.camera);
} }
public static void StartTimer() { public static void StartTimer() {
timerElement.Start(); timerElement.Start();
} }
public static void SpawnMapElements(TileConnectorProjection[] doors) { public static void SpawnMapElements(TileConnectorProjection[] doors) {
for (int i = 0; i < 5; i++){ // NOTE: this loop does y in reverse, y labels are inverted to match server for (int i = 0; i < 5; i++){ // NOTE: this loop does y in reverse, y labels are inverted to match server
for (int j = 0; j < 5; j++){ for (int j = 0; j < 5; j++){
int i1 = i; int id = ClientMapManager.CoordsToId(i, 4 - j);
int j1 = j; if (Client.Player.state.officeTileId == id || Client.Opponent.state.officeTileId == id) continue; // TODO: remove the other check for office
Point point1 = new Point(336 + (32 * i), 144 + (32 * j)); Point point1 = new Point(336 + (32 * i), 144 + (32 * j));
Point point2 = new Point(367 + (32 * i), 175 + (32 * j)); Point point2 = new Point(367 + (32 * i), 175 + (32 * j));
monitorScreen.AddElement($"room{ClientMapManager.CoordsToId(i, 4 - j)}", new UIElement(point1, point2) monitorScreen.AddElement($"room{id}", new UIElement(point1, point2)
{Pressable = true, OnMousePress = (() => CommandManager.SendChangeCamera(ClientMapManager.Get((i1, 4 - j1)).Id))}); {Pressable = true, OnMousePress = (() => CommandManager.SendChangeCamera(id))});
lightIndicators.Add(id, monitorScreen.AddElement($"light{id}", new UIElement(MonitorAtlas["map-light-indicator"], point1){Visible = false}));
// //
// if (doorPositions.ContainsKey((i, j))){ // if (doorPositions.ContainsKey((i, j))){
// monitorScreen.AddElement("door"+doorPositions[(i, j)], new UIElement([monitorAtlas[5], monitorAtlas[6]], point1)); // monitorScreen.AddElement("door"+doorPositions[(i, j)], new UIElement([monitorAtlas[5], monitorAtlas[6]], point1));
@ -149,8 +162,8 @@ public class UIManager {
} }
} }
monitorScreen.AddElement("eye-player", new UIElement(MonitorAtlas[24], monitorScreen["room"+Client.Player.state.camera].Bounds.Item1)); monitorScreen.AddElement("eye-player", new UIElement(MonitorAtlas["eye-small-player"], monitorScreen["room"+Client.Player.state.camera].Bounds.Item1));
monitorScreen.AddElement("eye-opponent", new UIElement([MonitorAtlas[23], MonitorAtlas[22]], monitorScreen["room"+Client.Opponent.state.camera].Bounds.Item1)); monitorScreen.AddElement("eye-opponent", new UIElement([MonitorAtlas["eye-small-opponent-closed"], MonitorAtlas["eye-small-opponent-open"]], monitorScreen["room"+Client.Opponent.state.camera].Bounds.Item1));
foreach (var door in doors){ foreach (var door in doors){
if(door.Type != ConnectorType.DOOR_REMOTE) continue; if(door.Type != ConnectorType.DOOR_REMOTE) continue;
@ -161,16 +174,16 @@ public class UIManager {
int targetId = door.Tiles.tile1.GridPosition.y > door.Tiles.tile2.GridPosition.y ? door.Tiles.tile1.Id : door.Tiles.tile2.Id; int targetId = door.Tiles.tile1.GridPosition.y > door.Tiles.tile2.GridPosition.y ? door.Tiles.tile1.Id : door.Tiles.tile2.Id;
UIElement tile = monitorScreen["room"+targetId]; UIElement tile = monitorScreen["room"+targetId];
monitorScreen.AddElement("door"+Math.Max(door.Tiles.tile1.Id, door.Tiles.tile2.Id)+"-"+Math.Min(door.Tiles.tile1.Id, door.Tiles.tile2.Id), new UIElement([MonitorAtlas[5], MonitorAtlas[6]], tile.Bounds.Item1)); monitorScreen.AddElement("door"+Math.Max(door.Tiles.tile1.Id, door.Tiles.tile2.Id)+"-"+Math.Min(door.Tiles.tile1.Id, door.Tiles.tile2.Id), new UIElement([MonitorAtlas["door-remote-open"], MonitorAtlas["door-remote-closed"]], tile.Bounds.Item1));
} }
} }
monitorScreen.AddElement("p1-office-door-left", new UIElement([MonitorAtlas[7], MonitorAtlas[8]], new Point(400, 272))); monitorScreen.AddElement("p1-office-door-left", new UIElement([MonitorAtlas["door-office-p1-left-open"], MonitorAtlas["door-office-p1-left-closed"]], new Point(400, 272)));
monitorScreen.AddElement("p1-office-door-centre", new UIElement([MonitorAtlas[9], MonitorAtlas[10]], new Point(400, 272))); monitorScreen.AddElement("p1-office-door-centre", new UIElement([MonitorAtlas["door-office-p1-centre-open"], MonitorAtlas["door-office-p1-centre-closed"]], new Point(400, 272)));
monitorScreen.AddElement("p1-office-door-right", new UIElement([MonitorAtlas[11], MonitorAtlas[12]], new Point(400, 272))); monitorScreen.AddElement("p1-office-door-right", new UIElement([MonitorAtlas["door-office-p1-right-open"], MonitorAtlas["door-office-p1-right-closed"]], new Point(400, 272)));
monitorScreen.AddElement("p2-office-door-right", new UIElement([MonitorAtlas[13], MonitorAtlas[14]], new Point(400, 144))); monitorScreen.AddElement("p2-office-door-right", new UIElement([MonitorAtlas["door-office-p2-right-open"], MonitorAtlas["door-office-p2-right-closed"]], new Point(400, 144)));
monitorScreen.AddElement("p2-office-door-centre", new UIElement([MonitorAtlas[15], MonitorAtlas[16]], new Point(400, 144))); monitorScreen.AddElement("p2-office-door-centre", new UIElement([MonitorAtlas["door-office-p2-centre-open"], MonitorAtlas["door-office-p2-centre-closed"]], new Point(400, 144)));
monitorScreen.AddElement("p2-office-door-left", new UIElement([MonitorAtlas[17], MonitorAtlas[18]], new Point(400, 144))); monitorScreen.AddElement("p2-office-door-left", new UIElement([MonitorAtlas["door-office-p2-left-open"], MonitorAtlas["door-office-p2-left-closed"]], new Point(400, 144)));
} }
@ -235,17 +248,28 @@ public class UIManager {
public static void ChangeCamera(int id) { public static void ChangeCamera(int id) {
monitorScreen["eye-player"].SetPosition(monitorScreen["room"+id].Bounds.Item1); monitorScreen["eye-player"].SetPosition(monitorScreen["room"+id].Bounds.Item1);
cameraView.SetTexture(id);
UpdateCameras([id]); UpdateCameras([id]);
} }
public static void UpdateCameras(int[] camIds) { public static void UpdateCameras(int[] camIds) {
foreach (var id in camIds){
MapTileProjection tile = ClientMapManager.Get(id);
if(tile.Owner == null) continue;
lightIndicators[id].Visible = tile.Lit;
}
if (camIds.Contains(Client.Player.state.camera)){ if (camIds.Contains(Client.Player.state.camera)){
bool lit = ClientMapManager.Get(Client.Player.state.camera).Lit;
cameraView.Visible = lit;
enemyElements.Values.Where(e => e.Visible).ToList().ForEach(e => e.Visible = false); enemyElements.Values.Where(e => e.Visible).ToList().ForEach(e => e.Visible = false);
ClientEnemy[] enemies = ClientEnemyManager.GetByLocation(ClientMapManager.Get(Client.Player.state.camera));; ClientEnemy[] enemies = ClientEnemyManager.GetByLocation(ClientMapManager.Get(Client.Player.state.camera));
foreach (var enemy in enemies){ foreach (var enemy in enemies){
enemyElements.TryGetValue(enemy.Id, out var element); enemyElements.TryGetValue(enemy.Id, out var element);
if (element == null) continue; if (element == null) continue;
element.Visible = true; EnemyUIElement enemyElement = (EnemyUIElement)element;
enemyElement.Visible = true;
enemyElement.SetTexture(lit);
} }
} }
} }
@ -269,15 +293,16 @@ public class UIManager {
Screen.SetScreen(ScreenTypes.WIN); Screen.SetScreen(ScreenTypes.WIN);
Screen.DisableOverlay(); Screen.DisableOverlay();
CommandManager.AllowGameControls(false); CommandManager.AllowGameControls(false);
InputManager.AddListener(Keys.Space, DisplayMainMenu, InputTiming.PRESS, new InputListenerHook(true, true));
} }
public static void ShowDeathScreen() { public static void ShowDeathScreen() {
Screen.SetScreen(ScreenTypes.LOSE); Screen.SetScreen(ScreenTypes.LOSE);
Screen.DisableOverlay(); Screen.DisableOverlay();
CommandManager.AllowGameControls(false); CommandManager.AllowGameControls(false);
InputManager.AddListener(Keys.Space, DisplayMainMenu, InputTiming.PRESS, new InputListenerHook(true, true));
} }
// private static Point GetRoomUIPos((int x, int y) pos) { // private static Point GetRoomUIPos((int x, int y) pos) {
// return new Point(336 + (32 * pos.x), 144 + (32 * pos.y)); // return new Point(336 + (32 * pos.x), 144 + (32 * pos.y));
// } // }

View file

@ -1,7 +1,11 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.JavaScript; using System.Runtime.InteropServices.JavaScript;
using FNAF_Clone.GUI;
using GlobalClassLib; using GlobalClassLib;
using PacketLib;
namespace FNAF_Clone.Map; namespace FNAF_Clone.Map;
@ -11,11 +15,18 @@ public class ClientMapManager {
public static MapTileProjection Get(int tileId) => Get(IdToCoords(tileId)); public static MapTileProjection Get(int tileId) => Get(IdToCoords(tileId));
private static bool inverted; private static bool inverted;
public static void InitMap(bool invert = false) { public static void InitMap(int[] connectors, int[] yourTiles, int[] opponentTiles, int[] litTiles, bool upsideDown ) {
inverted = invert;
IdToCoords = invert ? _IdToCoordsInverse : _IdToCoords; (int id1, int id2, ConnectorType type, ClientPlayer? owner)[] connectorsData = new (int, int , ConnectorType, ClientPlayer?)[connectors.Length / 4];
CoordsToId = invert ? _CoordsToIdInverse : _CoordsToId; for (int i = 0; i < connectors.Length / 4; i++){
connectorsData[i] = (connectors[i * 4], connectors[i * 4 + 1], (ConnectorType)connectors[i * 4 + 2], connectors[i * 4 + 3] == -1 ? null : Client.GetPlayer(connectors[i * 4 + 3]));
}
// ClientMapManager.InitMap(upsideDown);
inverted = upsideDown;
IdToCoords = upsideDown ? _IdToCoordsInverse : _IdToCoords;
CoordsToId = upsideDown ? _CoordsToIdInverse : _CoordsToId;
for (int i = 0; i < 5; i++){ for (int i = 0; i < 5; i++){
for (int j = 0; j < 2; j++){ for (int j = 0; j < 2; j++){
@ -27,6 +38,26 @@ public class ClientMapManager {
} }
} }
foreach (var tileId in yourTiles){
Get(tileId).Owner = Client.Player;
}
foreach (var tileId in opponentTiles){
Get(tileId).Owner = Client.Opponent;
}
foreach (var tileId in litTiles){
Get(tileId).Lit = true;
}
TileConnectorProjection[] connectorProjections = connectorsData.Select(c => new TileConnectorProjection(Get(c.id1), Get(c.id2), c.type){Owner = c.owner}).ToArray();
InitConnectors(connectorProjections);
UIManager.SpawnMapElements(connectorProjections.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray());
} }
public static void InitConnectors(TileConnectorProjection[] connectors) { public static void InitConnectors(TileConnectorProjection[] connectors) {
@ -58,12 +89,21 @@ public class ClientMapManager {
} }
public const int ID_X_OFFSET = 5; // map grid height public const int MAP_SIDE_LENGTH = 5; // map grid height
public static Func<int, int, int> CoordsToId{ get; private set; } public static Func<int, int, int> CoordsToId{ get; private set; }
public static Func<int, (int x, int y)> IdToCoords{ get; private set; } public static Func<int, (int x, int y)> IdToCoords{ get; private set; }
private static Func<int, (int x, int y)> _IdToCoords = id => (id / ID_X_OFFSET, id % ID_X_OFFSET); private static Func<int, (int x, int y)> _IdToCoords = id => (id / MAP_SIDE_LENGTH, id % MAP_SIDE_LENGTH);
private static Func<int, (int x, int y)> _IdToCoordsInverse = id => (ID_X_OFFSET - 1 - (id / ID_X_OFFSET), ID_X_OFFSET - 1 - (id % ID_X_OFFSET)); private static Func<int, (int x, int y)> _IdToCoordsInverse = id => (MAP_SIDE_LENGTH - 1 - (id / MAP_SIDE_LENGTH), MAP_SIDE_LENGTH - 1 - (id % MAP_SIDE_LENGTH));
private static Func<int, int, int> _CoordsToId = (x, y) => x * ID_X_OFFSET + y; private static Func<int, int, int> _CoordsToId = (x, y) => x * MAP_SIDE_LENGTH + y;
private static Func<int, int, int> _CoordsToIdInverse = (x, y) => (ID_X_OFFSET - 1 - x) * ID_X_OFFSET + (ID_X_OFFSET - 1 - y); private static Func<int, int, int> _CoordsToIdInverse = (x, y) => (MAP_SIDE_LENGTH - 1 - x) * MAP_SIDE_LENGTH + (MAP_SIDE_LENGTH - 1 - y);
public static MapTileProjection[] GetAllTiles() {
List<MapTileProjection> tiles = new();
foreach (var tile in map){
tiles.Add(tile);
}
return tiles.ToArray();
}
} }

View file

@ -4,6 +4,8 @@ namespace FNAF_Clone.Map;
public class MapTileProjection : GlobalMapTile<TileConnectorProjection, MapTileProjection> { public class MapTileProjection : GlobalMapTile<TileConnectorProjection, MapTileProjection> {
public ClientPlayer? Owner { get; set; } public ClientPlayer? Owner { get; set; }
public MapTileProjection(int id) : base(id, ClientMapManager.IdToCoords(id)) { public MapTileProjection(int id) : base(id, ClientMapManager.IdToCoords(id)) {
Lit = false;
} }
} }

View file

@ -51,6 +51,19 @@ public class CommandProcessor {
Console.WriteLine($"C: Player {pid} {(door.Blocked ? "closed" : "opened")} door {(playerCommand.Args[0], playerCommand.Args[1])}"); 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)]); Server.SendUpdateToAll([GameEvent.TOGGLE_DOOR_REMOTE(pid, (playerCommand.Args[0], playerCommand.Args[1]), door.Blocked)]);
break; break;
case 4:
bool lit = playerCommand.Args[1] == 1;
MapTile lightTile = MapManager.Get(playerCommand.Args[0]);
lightTile.Lit = lit;
if (lit){
GameLogic.PowerConsumers[lightTile] = (GameLogic.LightUsage, pid);
}
else{
GameLogic.PowerConsumers.Remove(lightTile);
}
Server.SendUpdateToAll([GameEvent.TOGGLE_LIGHT(pid, playerCommand.Args[0], lit)]);
break;
} }
} }
} }

View file

@ -18,7 +18,8 @@ public abstract class RoamingPathfinder : Pathfinder{
c => (!c.Blocked || c.Type == ConnectorType.DOOR_OFFICE) && tile != Enemy.Location, c => (!c.Blocked || c.Type == ConnectorType.DOOR_OFFICE) && tile != Enemy.Location,
t => t =>
(!distances.ContainsKey(t) || distances[t] > distances[tile]) && (!distances.ContainsKey(t) || distances[t] > distances[tile]) &&
(!Enemy.BlocksTile || EnemyManager.GetByLocation(t).All(e => !e.BlocksTile || e == Enemy))); (!Enemy.BlocksTile || EnemyManager.GetByLocation(t).All(e => !e.BlocksTile || e == Enemy)) &&
Server.Players.All(p => p.Value.state.officeTileId != t.Id));
neighbours.ForEach(t => distances[t] = distances[tile] + tile.GetConnector(t)!.Value); neighbours.ForEach(t => distances[t] = distances[tile] + tile.GetConnector(t)!.Value);

View file

@ -19,6 +19,7 @@ public class GameLogic {
public static int OfficeDoorUsage{ get; set; } = 10; public static int OfficeDoorUsage{ get; set; } = 10;
public static int RemoteDoorUsage{ get; set; } = 3; public static int RemoteDoorUsage{ get; set; } = 3;
public static int LightUsage{ get; set; } = 2;
// public const int POWER_MAX = 1000; // public const int POWER_MAX = 1000;
// public static int P1Power{ get; set; } = Power.MAX_POWER_VALUE; // public static int P1Power{ get; set; } = Power.MAX_POWER_VALUE;
@ -46,12 +47,22 @@ public class GameLogic {
connectorsConverted[i * 4 + 2] = (int)connectors[i].Type; connectorsConverted[i * 4 + 2] = (int)connectors[i].Type;
connectorsConverted[i * 4 + 3] = connectors[i].Owner == null ? -1 : connectors[i].Owner.state.pid; 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); List<int> p1Tiles = new();
List<int> p2Tiles = new();
List<int> neutralTiles = new();
foreach (var tile in MapManager.GetAllTiles()){
if(tile.Owner == null) neutralTiles.Add(tile.Id);
else if(tile.Owner == Server.P1) p1Tiles.Add(tile.Id);
else if(tile.Owner == Server.P2) p2Tiles.Add(tile.Id);
}
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);
EnemyManager.AddEnemy(new LurkEnemy(0)).Spawn(MapManager.Get(12));
EnemyManager.AddEnemy(new NekoEnemy(0)).Spawn(MapManager.Get(2));
EnemyManager.AddEnemy(new SpotEnemy(0)).Spawn(MapManager.Get(12)); EnemyManager.AddEnemy(new SpotEnemy(0)).Spawn(MapManager.Get(12));
EnemyManager.AddEnemy(new LurkEnemy(0)).Spawn(MapManager.Get(12));
EnemyManager.AddEnemy(new NekoEnemy(10)).Spawn(MapManager.Get(2));
Thread.Sleep(3000); Thread.Sleep(3000);
secondCycleTimer.Start(); secondCycleTimer.Start();
@ -109,6 +120,9 @@ public class GameLogic {
foreach (var door in MapManager.GetDoors(player)){ foreach (var door in MapManager.GetDoors(player)){
door.Blocked = false; door.Blocked = false;
} }
foreach (var tile in MapManager.GetAllTiles().Where(t => t.Owner == player)){
tile.Lit = false;
}
PowerConsumers.Where(c => c.Value.pid == player.state.pid).ToList().ForEach(c => PowerConsumers.Remove(c.Key)); PowerConsumers.Where(c => c.Value.pid == player.state.pid).ToList().ForEach(c => PowerConsumers.Remove(c.Key));
Server.SendUpdateToAll([GameEvent.POWER_OUT(player.state.pid)]); Server.SendUpdateToAll([GameEvent.POWER_OUT(player.state.pid)]);
} }

View file

@ -73,7 +73,16 @@ public static class MapManager {
return connectors.ToArray(); return connectors.ToArray();
} }
public static MapTile[] GetAllTiles() {
List<MapTile> tiles = new();
foreach (var tile in map){
tiles.Add(tile);
}
return tiles.ToArray();
}
public const int ID_X_OFFSET = 5; // map grid height 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 CoordsToId(int x, int y) => x * ID_X_OFFSET + y;

@ -1 +1 @@
Subproject commit 182ebfc31c37c0759b5a41c1921273f1ba55b759 Subproject commit 8f241032d24da10a497b5923f532641253c9b84c

View file

@ -23,6 +23,7 @@ public struct GameEvent : INetSerializable{
public static GameEvent GAME_START() => new(){ID = 12}; 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_TICK(int pid, int power) => new(){ID = 13, Args = [pid, power]};
public static GameEvent POWER_OUT(int pid) => new(){ID = 14, Args = [pid]}; public static GameEvent POWER_OUT(int pid) => new(){ID = 14, Args = [pid]};
public static GameEvent TOGGLE_LIGHT(int pid, int camId, bool state) => new(){ID = 15, Args = [pid, camId, state ? 1 : 0]};
public int ID{ get; set; } public int ID{ get; set; }
public bool Hideable => ID < 0; public bool Hideable => ID < 0;

View file

@ -4,5 +4,6 @@ public class MapInitPacket {
public int[] Connectors { get; set; } // quadruplets (tile1 id, tile2 id, type, owner) public int[] Connectors { get; set; } // quadruplets (tile1 id, tile2 id, type, owner)
public int[] YourTiles { get; set; } public int[] YourTiles { get; set; }
public int[] OpponentTiles { get; set; } public int[] OpponentTiles { get; set; }
public int[] LitTiles{ get; set; }
public bool UpsideDown { get; set; } public bool UpsideDown { get; set; }
} }

View file

@ -8,6 +8,7 @@ public struct PlayerCommand : INetSerializable {
public static PlayerCommand SET_MONITOR(bool state) => new(){ID = 1, Args = [state ? 1 : 0]}; public static PlayerCommand SET_MONITOR(bool state) => new(){ID = 1, Args = [state ? 1 : 0]};
public static PlayerCommand SET_DOOR_OFFICE(Direction direction, bool state) => new(){ID = 2, Args = [(int)direction, state ? 1 : 0]}; public static PlayerCommand SET_DOOR_OFFICE(Direction direction, bool state) => new(){ID = 2, Args = [(int)direction, state ? 1 : 0]};
public static PlayerCommand SET_DOOR_REMOTE((int, int) remoteDoorId, bool state) => new(){ID = 3, Args = [remoteDoorId.Item1, remoteDoorId.Item2, state ? 1 : 0]}; public static PlayerCommand SET_DOOR_REMOTE((int, int) remoteDoorId, bool state) => new(){ID = 3, Args = [remoteDoorId.Item1, remoteDoorId.Item2, state ? 1 : 0]};
public static PlayerCommand SET_LIGHT(int camId, bool state) => new(){ID = 4, Args = [camId, state ? 1 : 0]};
public int ID{ get; set; } public int ID{ get; set; }
public bool Hideable => ID < 0; public bool Hideable => ID < 0;
public int[] Args{ get; private set; } public int[] Args{ get; private set; }