Bugfixy, odstranění nepoužívaných tříd CameraSystem a ITargetingEnemy, přidání dedikované třídy ReturnToMenuElement, předělání pathfinding algoritmu z DFS na BFS, přesun správy obtížnosti do abstraktní třídy Enemy, přidání scriptů pro kompilaci na aplikaci nevyžadující dotnet
This commit is contained in:
parent
ceac37920b
commit
e5d746d597
24 changed files with 258 additions and 138 deletions
2
.idea/.idea.OneNightDuel/.idea/indexLayout.xml
generated
2
.idea/.idea.OneNightDuel/.idea/indexLayout.xml
generated
|
|
@ -5,6 +5,8 @@
|
|||
<explicitIncludes>
|
||||
<Path>FNAF_Server</Path>
|
||||
<Path>build-linux.sh</Path>
|
||||
<Path>build-self-contained-linux.sh</Path>
|
||||
<Path>build-self-contained-win.sh</Path>
|
||||
<Path>launch-server.sh</Path>
|
||||
</explicitIncludes>
|
||||
<explicitExcludes />
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
namespace ONDClient;
|
||||
|
||||
public class CameraSystem {
|
||||
public bool Enabled { get; private set; }
|
||||
public int CurrentCamera { get; private set; }
|
||||
|
||||
public void FlipUp() {
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
public void FlipDown() {
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
public void SetCamera(int camera) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@ public class Client {
|
|||
CONNECTED,
|
||||
ACCEPTED,
|
||||
GAME_STARTING,
|
||||
DISCONNECTED,
|
||||
GAME_IN_PROGRESS,
|
||||
SERVER_NOT_FOUND,
|
||||
SERVER_FULL,
|
||||
ERROR
|
||||
}
|
||||
public static string StatusText{ get; private set; }
|
||||
|
||||
public static ConnectionState State { get; private set; } = ConnectionState.IDLE;
|
||||
public static ConnectionState State { get; set; } = ConnectionState.IDLE;
|
||||
|
||||
private static EventBasedNetListener listener = new();
|
||||
private static NetManager client;
|
||||
|
|
@ -68,6 +68,13 @@ public class Client {
|
|||
State = ConnectionState.CONNECTED;
|
||||
SendPacket(new JoinPacket {username = Player.username == "" ? "Anonymous" : Player.username}, DeliveryMethod.ReliableOrdered);
|
||||
};
|
||||
|
||||
listener.PeerDisconnectedEvent += (peer, info) => {
|
||||
State = ConnectionState.IDLE;
|
||||
Console.WriteLine("Disconnected from Server:\n" + info.Reason);
|
||||
State = ConnectionState.DISCONNECTED;
|
||||
StatusText = info.Reason.ToString();
|
||||
};
|
||||
}
|
||||
|
||||
public static void Connect(string endPoint, int port) {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ public class EventProcessor {
|
|||
UIManager.DisplayGameUI();
|
||||
UIManager.StartTimer();
|
||||
SoundManager.StartAmbience();
|
||||
Client.State = Client.ConnectionState.GAME_IN_PROGRESS;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace ONDClient.GUI;
|
||||
|
||||
public class LoadingUIElement : TextUIElement {
|
||||
private string expectedEndpoint;
|
||||
private Func<string> expectedEndpointGetter;
|
||||
private Client.ConnectionState lastState = Client.ConnectionState.IDLE;
|
||||
|
||||
public LoadingUIElement(Point corner1, SpriteFont font, string expectedEndpoint, Alignment alignment = Alignment.CENTER, bool autoBounds = true) : base(corner1, font, alignment, autoBounds) {
|
||||
this.expectedEndpoint = expectedEndpoint;
|
||||
public LoadingUIElement(Point corner1, SpriteFont font, Func<string> expectedEndpointGetter, Alignment alignment = Alignment.CENTER, bool autoBounds = true) : base(corner1, font, alignment, autoBounds) {
|
||||
this.expectedEndpointGetter = expectedEndpointGetter;
|
||||
Active = true;
|
||||
// Color = Color.LightGray;
|
||||
}
|
||||
|
|
@ -19,10 +20,10 @@ public class LoadingUIElement : TextUIElement {
|
|||
|
||||
switch (Client.State){
|
||||
case Client.ConnectionState.CONNECTING:
|
||||
Text = "Connecting to " + expectedEndpoint;
|
||||
Text = "Connecting to " + expectedEndpointGetter();
|
||||
break;
|
||||
case Client.ConnectionState.CONNECTED:
|
||||
Text = "Connected to " + expectedEndpoint;
|
||||
Text = "Connected to " + expectedEndpointGetter();
|
||||
break;
|
||||
case Client.ConnectionState.ACCEPTED:
|
||||
Text = "Waiting for opponent...";
|
||||
|
|
@ -32,6 +33,12 @@ public class LoadingUIElement : TextUIElement {
|
|||
Color = Color.White;
|
||||
// ScaleMultiplier = 1.5f;
|
||||
break;
|
||||
case Client.ConnectionState.IDLE:
|
||||
Text = "Idle";
|
||||
break;
|
||||
case Client.ConnectionState.DISCONNECTED:
|
||||
Text = "Disconnected: " + Client.StatusText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
ONDClient/GUI/ReturnToMenuElement.cs
Normal file
40
ONDClient/GUI/ReturnToMenuElement.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGameLibrary.Input;
|
||||
|
||||
namespace ONDClient.GUI;
|
||||
|
||||
public class ReturnToMenuElement : TextUIElement{
|
||||
private bool listening = false;
|
||||
private InputListenerHook inputHook;
|
||||
|
||||
public ReturnToMenuElement(Point corner1, SpriteFont font, Alignment alignment = Alignment.CENTER) : base(corner1, font, alignment, false) {
|
||||
Visible = false;
|
||||
Text = "Press Space to return to main menu";
|
||||
inputHook = new InputListenerHook(false);
|
||||
InputManager.AddListener("return-to-menu",Keys.Space, () => {
|
||||
UIManager.DisplayMainMenu();
|
||||
listening = false;
|
||||
Visible = false;
|
||||
Client.Disconnect();
|
||||
},
|
||||
InputTiming.PRESS, inputHook);
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
if ((Client.State == Client.ConnectionState.IDLE || Client.State == Client.ConnectionState.DISCONNECTED || Client.State == Client.ConnectionState.ACCEPTED) &&
|
||||
(Screen.CurrentScreen.Label == UIManager.ScreenTypes.LOADING || Screen.CurrentScreen.Label == UIManager.ScreenTypes.LOSE || Screen.CurrentScreen.Label == UIManager.ScreenTypes.WIN)){
|
||||
if (!listening){
|
||||
listening = true;
|
||||
Visible = true;
|
||||
inputHook.Enabled = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Visible = false;
|
||||
listening = false;
|
||||
inputHook.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,13 +27,16 @@ public class TextUIElement : UIElement {
|
|||
Font = font;
|
||||
AutoBounds = autoBounds;
|
||||
Align(alignment);
|
||||
Visible = true;
|
||||
}
|
||||
public TextUIElement(Point corner1, Point corner2, SpriteFont font, Alignment alignment = Alignment.LEFT) : base(corner1, corner2) {
|
||||
Font = font;
|
||||
Align(alignment);
|
||||
Visible = true;
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch) {
|
||||
if(!Visible || !Active) return;
|
||||
base.Draw(spriteBatch);
|
||||
align();
|
||||
spriteBatch.DrawString(Font, Text, screenSpaceBounds.Item1.ToVector2(), Color, 0, origin, pixelScaleMultiplier * UNIVERSAL_TEXT_SCALE_MULTIPLIER, SpriteEffects.None, 0);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Mime;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGameLibrary;
|
||||
|
|
@ -89,9 +90,10 @@ public class UIElement {
|
|||
public virtual void OnMouseHold() { }
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch) {
|
||||
if (!Visible || !Active){
|
||||
if (!Visible || !Active || Textures.Count == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
Textures[currentTextureId].Draw(spriteBatch, screenSpaceBounds.Item1.ToVector2(), Color.White, 0, Vector2.Zero, pixelScaleMultiplier, SpriteEffects.None, 0);
|
||||
// texture.Draw(spriteBatch, bounds.Item1.ToVector2(), Color.White);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,8 +108,12 @@ public class UIManager {
|
|||
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)});
|
||||
|
||||
ReturnToMenuElement returnToMenuElement = new ReturnToMenuElement(new(320, 290), PixelMonoFont);
|
||||
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});
|
||||
winScreen.AddElement("press-space", returnToMenuElement);
|
||||
loseScreen.AddElement("press-space", returnToMenuElement);
|
||||
loadingScreen.AddElement("press-space", returnToMenuElement);
|
||||
|
||||
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"));
|
||||
|
|
@ -118,9 +122,7 @@ public class UIManager {
|
|||
Text = "CONNECT",
|
||||
Pressable = true,
|
||||
OnMousePress = () => {
|
||||
// string[] input = serverIpTextBox.Text.Split(":");
|
||||
// if(input.Length != 2 || !int.TryParse(input[0], out var port)) return;
|
||||
// Client.Connect(input[0], port);
|
||||
|
||||
Client.Player.username = usernameField.Text;
|
||||
Client.Connect(field.Text, 9012);
|
||||
Screen.SetScreen(ScreenTypes.LOADING);
|
||||
|
|
@ -136,7 +138,7 @@ public class UIManager {
|
|||
|
||||
}});
|
||||
|
||||
loadingScreen.AddElement("loading-text", new LoadingUIElement(new(320, 180), PixelMonoFont, field.Text));
|
||||
loadingScreen.AddElement("loading-text", new LoadingUIElement(new(320, 180), PixelMonoFont, () => field.Text));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -319,7 +321,8 @@ public class UIManager {
|
|||
Screen.DisableOverlay();
|
||||
CommandManager.AllowGameControls(false);
|
||||
SoundManager.StopAmbience();
|
||||
InputManager.AddListener(Keys.Space, DisplayMainMenu, InputTiming.PRESS, new InputListenerHook(true, true));
|
||||
SoundManager.StopNekoPurr();
|
||||
// InputManager.AddListener(Keys.Space, DisplayMainMenu, InputTiming.PRESS, new InputListenerHook(true, true));
|
||||
}
|
||||
|
||||
public static void ShowDeathScreen() {
|
||||
|
|
@ -327,8 +330,8 @@ public class UIManager {
|
|||
Screen.DisableOverlay();
|
||||
CommandManager.AllowGameControls(false);
|
||||
SoundManager.StopAmbience();
|
||||
|
||||
InputManager.AddListener(Keys.Space, DisplayMainMenu, InputTiming.PRESS, new InputListenerHook(true, true));
|
||||
SoundManager.StopNekoPurr();
|
||||
// InputManager.AddListener(Keys.Space, DisplayMainMenu, InputTiming.PRESS, new InputListenerHook(true, true));
|
||||
}
|
||||
|
||||
public static void ResetUI() {
|
||||
|
|
@ -345,4 +348,8 @@ public class UIManager {
|
|||
// return new Point(336 + (32 * pos.x), 144 + (32 * pos.y));
|
||||
// }
|
||||
|
||||
public static void SetLoadingScreenMessage(string text) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ using ONDClient.GUI;
|
|||
|
||||
namespace ONDClient;
|
||||
|
||||
public class GameMain() : Core("fnafkooo", 1280, 720, false) {
|
||||
public class GameMain() : Core("OND", 1280, 720, false) {
|
||||
// private GraphicsDeviceManager _graphics;
|
||||
// private SpriteBatch _spriteBatch;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using PacketLib;
|
|||
namespace ONDServer.Enemies;
|
||||
|
||||
public class DashEnemy : Enemy {
|
||||
public DashEnemy(int difficulty) : base(difficulty) {
|
||||
public DashEnemy(int difficulty) : base(difficulty, 5000) {
|
||||
movementOpportunity = new(5000);
|
||||
SetDifficulty(difficulty);
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ public class DashEnemy : Enemy {
|
|||
public override int TypeId{ get; } = (int)EnemyType.DASH;
|
||||
public override bool BlocksTile{ get; set; } = false;
|
||||
|
||||
private MovementOpportunity movementOpportunity;
|
||||
// private MovementOpportunity movementOpportunity;
|
||||
|
||||
private readonly (MapTile tile, Direction p1AttackDir, Direction p2AttackDir)[] positions =[
|
||||
(MapManager.Get(7), Direction.EAST, Direction.WEST),
|
||||
|
|
@ -34,10 +34,10 @@ public class DashEnemy : Enemy {
|
|||
Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);
|
||||
}
|
||||
|
||||
public override void SetDifficulty(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
movementOpportunity.MovementChance = (2 * Math.Sign(difficulty) + difficulty) / 12.0;
|
||||
}
|
||||
// public override void SetDifficulty(int difficulty) {
|
||||
// Difficulty = difficulty;
|
||||
// movementOpportunity.MovementChance = (2 * Math.Sign(difficulty) + difficulty) / 12.0;
|
||||
// }
|
||||
|
||||
public override void Spawn(MapTile location) {
|
||||
currentPosIndex = positions.ToList().FindIndex(p => p.tile == location);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@ namespace ONDServer.Enemies;
|
|||
public abstract class Enemy : GlobalEnemy<MapTile, TileConnector> {
|
||||
public int Difficulty { get; protected set; }
|
||||
|
||||
protected Enemy(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
protected MovementOpportunity movementOpportunity;
|
||||
|
||||
|
||||
protected Enemy(int difficulty, int movementInterval) {
|
||||
movementOpportunity = new(movementInterval);
|
||||
SetDifficulty(difficulty);
|
||||
}
|
||||
|
||||
public abstract bool BlocksTile { get; set; }
|
||||
|
|
@ -31,5 +35,8 @@ public abstract class Enemy : GlobalEnemy<MapTile, TileConnector> {
|
|||
GameLogic.DeclareWinner(Server.OtherPlayer(player));
|
||||
}
|
||||
|
||||
public abstract void SetDifficulty(int difficulty);
|
||||
public virtual void SetDifficulty(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
movementOpportunity.MovementChance = ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
namespace ONDServer.Enemies;
|
||||
|
||||
public interface ITargetingEnemy {
|
||||
ServerPlayer Target { get; set; }
|
||||
}
|
||||
|
|
@ -18,15 +18,13 @@ public class LurkEnemy : Enemy {
|
|||
// private static readonly double CHANCE_DENOMINATOR = 2 + Math.Pow(1.5f, 10); // d10 Lurk will have a 100% chance to move
|
||||
// private double movementChance => (2 + Math.Pow(1.5f, Difficulty)) / CHANCE_DENOMINATOR; // chance scales exponentially using a constant multiplier
|
||||
|
||||
private MovementOpportunity movementOpportunity;
|
||||
|
||||
public ServerPlayer? Target{ get; set; }
|
||||
|
||||
public LurkEnemy(int difficulty) : base(difficulty) {
|
||||
public LurkEnemy(int difficulty) : base(difficulty, 5000) {
|
||||
pathfinder = new LurkPathfinder(this, 1);
|
||||
movementOpportunity = new MovementOpportunity(5000);
|
||||
// movementOpportunity = new MovementOpportunity(5000);
|
||||
Target = null;
|
||||
SetDifficulty(difficulty);
|
||||
// SetDifficulty(difficulty);
|
||||
}
|
||||
public override void Spawn(MapTile location) {
|
||||
base.Spawn(location);
|
||||
|
|
@ -37,20 +35,20 @@ public class LurkEnemy : Enemy {
|
|||
}
|
||||
|
||||
public override void Reset() {
|
||||
pathfinder.TakenPath.Clear();
|
||||
pathfinder.TakenPath.Add(Location);
|
||||
|
||||
Target.state.power -= 30;
|
||||
Target.state.power -= 80;
|
||||
|
||||
MapTile[] resetLocations = new[]{MapManager.Get(7), MapManager.Get(12), MapManager.Get(17)}.Where(t => EnemyManager.GetByLocation(t).Length == 0).ToArray();
|
||||
Location = resetLocations[new Random().Next(resetLocations.Length)];
|
||||
pathfinder.TakenPath.Clear();
|
||||
pathfinder.TakenPath.Add(Location);
|
||||
|
||||
Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);
|
||||
}
|
||||
|
||||
public override void SetDifficulty(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
movementOpportunity.MovementChance = ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
}
|
||||
// public override void SetDifficulty(int difficulty) {
|
||||
// Difficulty = difficulty;
|
||||
// movementOpportunity.MovementChance = ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
// }
|
||||
|
||||
public override void Update() {
|
||||
base.Update();
|
||||
|
|
|
|||
|
|
@ -11,23 +11,14 @@ public class MareEnemy : Enemy {
|
|||
public override bool BlocksTile{ get; set; } = true;
|
||||
|
||||
private MarePathfinder pathfinder;
|
||||
private MovementOpportunity movementOpportunity;
|
||||
// private MovementOpportunity movementOpportunity;
|
||||
|
||||
public ServerPlayer Target{ get; set; }
|
||||
public MareEnemy(int difficulty) : base(difficulty) {
|
||||
public ServerPlayer? Target{ get; set; }
|
||||
public MareEnemy(int difficulty) : base(difficulty, 6000) {
|
||||
pathfinder = new MarePathfinder(this, 1);
|
||||
if (Server.P1.state.power > Server.P2.state.power){
|
||||
Target = Server.P2;
|
||||
}
|
||||
else if(Server.P1.state.power < Server.P2.state.power){
|
||||
Target = Server.P1;
|
||||
}
|
||||
else{
|
||||
Target = new Random().Next(2) == 0 ? Server.P1 : Server.P2;
|
||||
}
|
||||
|
||||
movementOpportunity = new MovementOpportunity(5000);
|
||||
SetDifficulty(difficulty);
|
||||
// movementOpportunity = new MovementOpportunity(5000);
|
||||
// SetDifficulty(difficulty);
|
||||
}
|
||||
|
||||
public override void Reset() {
|
||||
|
|
@ -38,19 +29,28 @@ public class MareEnemy : Enemy {
|
|||
Location = decision.nextTile!;
|
||||
}
|
||||
|
||||
Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);;
|
||||
Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);
|
||||
}
|
||||
|
||||
public override void SetDifficulty(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
movementOpportunity.MovementChance =
|
||||
((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
}
|
||||
// public override void SetDifficulty(int difficulty) {
|
||||
// Difficulty = difficulty;
|
||||
// movementOpportunity.MovementChance =
|
||||
// ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
// }
|
||||
|
||||
|
||||
public override void Spawn(MapTile location) {
|
||||
base.Spawn(location);
|
||||
// stopwatch.Start();
|
||||
// stopwatch.Start()
|
||||
if (Server.P1.state.power > Server.P2.state.power){
|
||||
Target = Server.P2;
|
||||
}
|
||||
else if(Server.P1.state.power < Server.P2.state.power){
|
||||
Target = Server.P1;
|
||||
}
|
||||
else{
|
||||
Target = new Random().Next(2) == 0 ? Server.P1 : Server.P2;
|
||||
}
|
||||
|
||||
movementOpportunity.Start();
|
||||
pathfinder.TakenPath.Add(Location);
|
||||
|
|
@ -65,6 +65,8 @@ public class MareEnemy : Enemy {
|
|||
Attack(Location.Owner);
|
||||
}
|
||||
|
||||
if (Target == null) return;
|
||||
|
||||
Pathfinder.Decision decision = pathfinder.DecideNext(MapManager.Get(Target.state.officeTileId));
|
||||
switch (decision.type){
|
||||
case Pathfinder.Decision.MoveType:
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ using PacketLib;
|
|||
namespace ONDServer.Enemies;
|
||||
|
||||
public class NekoEnemy : Enemy {
|
||||
private MovementOpportunity movementOpportunity;
|
||||
// private MovementOpportunity movementOpportunity;
|
||||
private RoamingPathfinder pathfinder;
|
||||
|
||||
public NekoEnemy(int difficulty) : base(difficulty) {
|
||||
public NekoEnemy(int difficulty) : base(difficulty, 4000) {
|
||||
pathfinder = new RoamingPathfinder(this, 1){AdditionalTileFilter = t => Aggressive || t.Owner == null || !t.Lit};
|
||||
movementOpportunity = new MovementOpportunity(5000);
|
||||
SetDifficulty(difficulty);
|
||||
// movementOpportunity = new MovementOpportunity(5000);
|
||||
// SetDifficulty(difficulty);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -33,19 +33,20 @@ public class NekoEnemy : Enemy {
|
|||
}
|
||||
|
||||
public override void Reset() {
|
||||
pathfinder.TakenPath.Clear();
|
||||
MapTile[] resetLocations = new[]{MapManager.Get(7), MapManager.Get(12), MapManager.Get(17)}.Where(t => EnemyManager.GetByLocation(t).Length == 0).ToArray();
|
||||
Location = resetLocations[new Random().Next(resetLocations.Length)];
|
||||
pathfinder.TakenPath.Clear();
|
||||
pathfinder.TakenPath.Add(Location);
|
||||
Aggressive = false;
|
||||
Target = Server.OtherPlayer(Target);
|
||||
Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);
|
||||
}
|
||||
|
||||
public override void SetDifficulty(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
movementOpportunity.MovementChance =
|
||||
((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
}
|
||||
// public override void SetDifficulty(int difficulty) {
|
||||
// Difficulty = difficulty;
|
||||
// movementOpportunity.MovementChance =
|
||||
// ((5 + Math.Pow(1.5f, Difficulty)) * Math.Sign(Difficulty)) / (5 + Math.Pow(1.5f, 10));
|
||||
// }
|
||||
|
||||
public override void Update() {
|
||||
base.Update();
|
||||
|
|
@ -70,7 +71,8 @@ public class NekoEnemy : Enemy {
|
|||
}
|
||||
}
|
||||
|
||||
if (Target != null && (movementOpportunity.CheckAndRoll() || (Aggressive && GameLogic.NSecondUpdate))){
|
||||
bool succeed = movementOpportunity.CheckAndRoll();
|
||||
if (Target != null && (succeed || (Aggressive && GameLogic.NSecondUpdate))){
|
||||
Pathfinder.Decision decision = pathfinder.DecideNext(MapManager.Get(Target.state.officeTileId));
|
||||
switch (decision.type){
|
||||
case Pathfinder.Decision.MoveType:
|
||||
|
|
|
|||
|
|
@ -12,38 +12,62 @@ public class RoamingPathfinder : Pathfinder {
|
|||
public List<MapTile> TakenPath { get; } = new();
|
||||
|
||||
private Random random = new();
|
||||
|
||||
// private Queue<MapTile> tilesToCrawl = new();
|
||||
// private Dictionary<MapTile, int> distances = new();
|
||||
// private Func<TileConnector, MapTile, bool> defaultConnectorFilter;
|
||||
public RoamingPathfinder(Enemy enemy, int tolerance) : base(enemy) {
|
||||
this.tolerance = tolerance;
|
||||
}
|
||||
|
||||
protected Dictionary<MapTile, int> Crawl(MapTile tile) {
|
||||
Dictionary<MapTile, int> distances = new(){ [tile] = 0 };
|
||||
CrawlStep(tile, distances);
|
||||
return distances;
|
||||
}
|
||||
protected Dictionary<MapTile, int> Search(MapTile startingTile) {
|
||||
Dictionary<MapTile, int> distances = new(){ [startingTile] = 0 };
|
||||
Queue<MapTile> tilesToSearch = new();
|
||||
tilesToSearch.Enqueue(startingTile);
|
||||
|
||||
private void CrawlStep(MapTile tile, Dictionary<MapTile, int> distances) {
|
||||
List<MapTile> neighbours = GetNeighbours(tile,
|
||||
while (tilesToSearch.Count > 0){
|
||||
MapTile currentTile = tilesToSearch.Dequeue();
|
||||
|
||||
List<MapTile> neighbours = GetNeighbours(currentTile,
|
||||
c =>
|
||||
AdditionalConnectorFilter(c) &&
|
||||
(!c.Blocked || c.Type == ConnectorType.DOOR_OFFICE) &&
|
||||
tile != Enemy.Location &&
|
||||
(!distances.ContainsKey(c.OtherTile(tile)) || distances[c.OtherTile(tile)] > distances[tile] + c.Value),
|
||||
(!distances.ContainsKey(c.OtherTile(currentTile)) || distances[c.OtherTile(currentTile)] > distances[currentTile] + c.Value),
|
||||
t =>
|
||||
AdditionalTileFilter(t) &&
|
||||
(!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[currentTile] + currentTile.GetConnector(t)!.Value;
|
||||
tilesToSearch.Enqueue(t);
|
||||
});
|
||||
}
|
||||
|
||||
if (neighbours.Count != 0){
|
||||
neighbours.ForEach(t => CrawlStep(t, distances));
|
||||
}
|
||||
return distances;
|
||||
}
|
||||
|
||||
// private void CrawlStep(MapTile tile) {
|
||||
// List<MapTile> neighbours = GetNeighbours(tile,
|
||||
// c =>
|
||||
// AdditionalConnectorFilter(c) &&
|
||||
// (!c.Blocked || c.Type == ConnectorType.DOOR_OFFICE) &&
|
||||
// tile != Enemy.Location &&
|
||||
// (!distances.ContainsKey(c.OtherTile(tile)) || distances[c.OtherTile(tile)] > distances[tile] + c.Value),
|
||||
// t =>
|
||||
// AdditionalTileFilter(t) &&
|
||||
// (!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);
|
||||
//
|
||||
// if (neighbours.Count != 0){
|
||||
// neighbours.ForEach(t => CrawlStep(t));
|
||||
// }
|
||||
// }
|
||||
|
||||
public override Decision DecideNext(MapTile goal) {
|
||||
Dictionary<MapTile, int> distances = Crawl(goal);
|
||||
Dictionary<MapTile, int> distances = Search(goal);
|
||||
|
||||
List<MapTile> closerTiles = GetNeighbours(Enemy.Location,
|
||||
c => AdditionalConnectorFilter(c) && !c.Blocked || c.Type == ConnectorType.DOOR_OFFICE,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ using PacketLib;
|
|||
namespace ONDServer.Enemies;
|
||||
|
||||
public class SpotEnemy : Enemy {
|
||||
public SpotEnemy(int difficulty) : base(difficulty) {
|
||||
public SpotEnemy(int difficulty) : base(difficulty, 6000) {
|
||||
path = [MapManager.Get(10), MapManager.Get(11), MapManager.Get(12), MapManager.Get(13), MapManager.Get(14)];
|
||||
pathId = 2;
|
||||
movementOpportunity = new(6000);
|
||||
SetDifficulty(difficulty);
|
||||
// movementOpportunity = new(6000);
|
||||
// SetDifficulty(difficulty);
|
||||
}
|
||||
|
||||
public override string Name{ get; } = "Spot";
|
||||
|
|
@ -18,7 +18,7 @@ public class SpotEnemy : Enemy {
|
|||
|
||||
public bool Active{ get; set; } = false;
|
||||
|
||||
private MovementOpportunity movementOpportunity;
|
||||
// private MovementOpportunity movementOpportunity;
|
||||
private MapTile[] path;
|
||||
private int pathId;
|
||||
|
||||
|
|
@ -26,15 +26,18 @@ public class SpotEnemy : Enemy {
|
|||
private int p2WatchCounter = 0;
|
||||
|
||||
public override void Reset() {
|
||||
if (Location.Owner != null){
|
||||
Location.Owner.state.power -= 200;
|
||||
}
|
||||
pathId = 2;
|
||||
Location = path[pathId];
|
||||
Server.SendUpdateToAll([GameEvent.ENEMY_RESET(Id, Location.Id)]);
|
||||
}
|
||||
|
||||
public override void SetDifficulty(int difficulty) {
|
||||
Difficulty = difficulty;
|
||||
movementOpportunity.MovementChance = (2 * Math.Sign(difficulty) + difficulty) / 12.0;
|
||||
}
|
||||
// public override void SetDifficulty(int difficulty) {
|
||||
// Difficulty = difficulty;
|
||||
// movementOpportunity.MovementChance = (2 * Math.Sign(difficulty) + difficulty) / 12.0;
|
||||
// }
|
||||
|
||||
public override void Update() {
|
||||
if (GameLogic.NSecondUpdate){
|
||||
|
|
@ -52,7 +55,7 @@ public class SpotEnemy : Enemy {
|
|||
if (movementOpportunity.CheckAndRoll()){
|
||||
if(!Active) {
|
||||
Active = true;
|
||||
movementOpportunity.Interval = 12_000;
|
||||
movementOpportunity.Interval = 10_000;
|
||||
movementOpportunity.GuaranteeSuccess(true);
|
||||
Server.SendUpdateToAll([GameEvent.SPOT_SET_ACTIVE(Id, true)]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class GameLogic {
|
|||
private static Random random = new();
|
||||
|
||||
private static bool unlimitedPower = false; // Debug
|
||||
private static bool noPhases = true; // Debug
|
||||
|
||||
// public const int POWER_MAX = 1000;
|
||||
// public static int P1Power{ get; set; } = Power.MAX_POWER_VALUE;
|
||||
|
|
@ -71,6 +72,7 @@ public class GameLogic {
|
|||
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = true, YourTiles = p2Tiles.ToArray(), OpponentTiles = p1Tiles.ToArray(), LitTiles = neutralTiles.ToArray()}, Server.P2.peer);
|
||||
|
||||
spawnOrder = [[new SpotEnemy(3), new MareEnemy(3)], [new DashEnemy(6)], [new LurkEnemy(3), new NekoEnemy(3)]];
|
||||
// Enemy test = new SpotEnemy(3);
|
||||
|
||||
Thread.Sleep(3000);
|
||||
secondCycleTimer.Start();
|
||||
|
|
@ -79,12 +81,12 @@ public class GameLogic {
|
|||
|
||||
// EnemyManager.AddEnemy(new SpotEnemy(10)).Spawn(MapManager.Get(12));
|
||||
// EnemyManager.AddEnemy(new LurkEnemy(10)).Spawn(MapManager.Get(12));
|
||||
// EnemyManager.AddEnemy(new NekoEnemy(10)).Spawn(MapManager.Get(2));
|
||||
EnemyManager.AddEnemy(new NekoEnemy(7)).Spawn(MapManager.Get(2));
|
||||
// EnemyManager.AddEnemy(new DashEnemy(10)).Spawn(MapManager.Get(12));
|
||||
// EnemyManager.AddEnemy(new MareEnemy(10)).Spawn(MapManager.Get(22));
|
||||
|
||||
EnemyManager.AddEnemy(new LurkEnemy(4)).Spawn(MapManager.Get(2));
|
||||
EnemyManager.AddEnemy(new NekoEnemy(4)).Spawn(MapManager.Get(22));
|
||||
// EnemyManager.AddEnemy(new LurkEnemy(4)).Spawn(MapManager.Get(2));
|
||||
// EnemyManager.AddEnemy(new NekoEnemy(4)).Spawn(MapManager.Get(22));
|
||||
|
||||
}
|
||||
public static void Update() {
|
||||
|
|
@ -162,6 +164,8 @@ public class GameLogic {
|
|||
}
|
||||
|
||||
private static void NextPhase() {
|
||||
if(noPhases) return;
|
||||
|
||||
PhaseCounter++;
|
||||
Server.SendUpdateToAll([GameEvent.NEXT_PHASE()]);
|
||||
|
||||
|
|
|
|||
|
|
@ -140,10 +140,13 @@ public class Server {
|
|||
}
|
||||
|
||||
public static void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo) {
|
||||
if (Players.Count == 2){
|
||||
GameLogic.DeclareWinner(OtherPlayer(Players.Values.First(p => Equals(p.peer, peer))));
|
||||
}
|
||||
|
||||
if (peer.Tag != null) {
|
||||
Players.Remove(peer.Id);
|
||||
if (Players.Count == 0){
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
<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_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_003F34c341e0ffea43388ce71ea7b328acb678a00_003Fc6_003Fc045192f_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>
|
||||
<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_003Ffd792102e2a04b889c29784ca9de4981d1a000_003F8f_003F6419ac7c_003FThrowHelper_002Ecs_002Fz_003A2_002D1/@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>
|
||||
<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_003Ffd792102e2a04b889c29784ca9de4981d1a000_003F2a_003Fa31b08a3_003FThread_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
|
|
|||
15
build-self-contained-linux.sh
Executable file
15
build-self-contained-linux.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
target_dir=bin/OneNightDuel-linux-x64
|
||||
launch_server_script="while :; do bin/ONDServer; done"
|
||||
|
||||
dotnet publish MonoGameLibrary
|
||||
ln -sfrv MonoGameLibrary/MonoGameLibrary/bin/Release/net9.0/publish/MonoGameLibrary.dll ONDClient/link/MonoGameLibrary.dll
|
||||
|
||||
dotnet publish --runtime linux-x64 --self-contained
|
||||
mkdir -p bin/OneNightDuel-linux-x64/bin/
|
||||
cp -r bin/Client/net9.0/linux-x64/publish/* $target_dir/bin/
|
||||
cp -r bin/Server/net9.0/linux-x64/publish/* $target_dir/bin/
|
||||
|
||||
ln -sfrv $target_dir/bin/ONDClient $target_dir/OneNightDuel
|
||||
|
||||
echo "$launch_server_script" > $target_dir/launch-server-standalone.sh
|
||||
chmod +x $target_dir/launch-server-standalone.sh
|
||||
14
build-self-contained-win.sh
Executable file
14
build-self-contained-win.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
target_dir=bin/OneNightDuel-win-x64
|
||||
launch_server_script="while :; do bin\ONDServer.exe; done"
|
||||
launch_client_script="bin\ONDClient.exe"
|
||||
|
||||
dotnet publish MonoGameLibrary
|
||||
ln -sfrv MonoGameLibrary/MonoGameLibrary/bin/Release/net9.0/publish/MonoGameLibrary.dll ONDClient/link/MonoGameLibrary.dll
|
||||
|
||||
dotnet publish --runtime win-x64 --self-contained
|
||||
mkdir -p bin/OneNightDuel-win-x64/bin/
|
||||
cp -r bin/Client/net9.0/win-x64/publish/* $target_dir/bin/
|
||||
cp -r bin/Server/net9.0/win-x64/publish/* $target_dir/bin/
|
||||
|
||||
echo "$launch_server_script" > $target_dir/launch-server-standalone.bat
|
||||
echo "$launch_client_script" > $target_dir/OneNightDuel.bat
|
||||
Loading…
Add table
Add a link
Reference in a new issue