diff --git a/logic/GameClass/GameObj/Areas/AreaFactory.cs b/logic/GameClass/GameObj/Areas/AreaFactory.cs index 3e6fc797..49e93de3 100644 --- a/logic/GameClass/GameObj/Areas/AreaFactory.cs +++ b/logic/GameClass/GameObj/Areas/AreaFactory.cs @@ -6,13 +6,13 @@ public static class AreaFactory { public static Immovable GetArea(XY pos, PlaceType placeType) => placeType switch { - PlaceType.Home => new Home(pos), + //PlaceType.Home => new Home(pos), PlaceType.Ruin => new Ruin(pos), PlaceType.Shadow => new Shadow(pos), PlaceType.Asteroid => new Asteroid(pos), PlaceType.Resource => new Resource(pos), PlaceType.Construction => new Construction(pos), - PlaceType.Wormhole => new Wormhole(pos), + //PlaceType.Wormhole => new Wormhole(pos), _ => new NullArea(pos) }; public static OutOfBoundBlock GetOutOfBoundBlock(XY pos) => new(pos); diff --git a/logic/GameClass/GameObj/Areas/Construction.cs b/logic/GameClass/GameObj/Areas/Construction.cs index b49697da..39070846 100644 --- a/logic/GameClass/GameObj/Areas/Construction.cs +++ b/logic/GameClass/GameObj/Areas/Construction.cs @@ -5,11 +5,50 @@ namespace GameClass.GameObj.Areas; public class Construction : Immovable { - public LongInTheVariableRange HP => throw new NotImplementedException(); + public LongInTheVariableRange HP { get; } = new LongInTheVariableRange(0, GameData.CommunityHP); public override bool IsRigid => constructionType == ConstructionType.Community; public override ShapeType Shape => ShapeType.Square; private ConstructionType constructionType = ConstructionType.Null; public ConstructionType ConstructionType => constructionType; + public AtomicInt ConstructNum { get; } = new AtomicInt(0); + public bool Construct(int constructSpeed, ConstructionType constructionType, Ship ship) + { + if (constructionType == ConstructionType.Null) + { + return false; + } + if (this.constructionType != ConstructionType.Null && this.constructionType != constructionType && this.HP > 0) + { + return false; + } + if (this.constructionType == ConstructionType.Null || this.HP == 0) + { + this.constructionType = constructionType; + switch (constructionType) + { + case ConstructionType.Community: + HP.SetMaxV(GameData.CommunityHP); + break; + case ConstructionType.Factory: + HP.SetMaxV(GameData.FactoryHP); + break; + case ConstructionType.Fort: + HP.SetMaxV(GameData.FortHP); + break; + default: + break; + } + } + return HP.AddV(constructSpeed) > 0; + } + public void AddConstructNum(int add = 1) + { + ConstructNum.Add(add); + } + public void SubConstructNum(int sub = 1) + { + ConstructNum.Sub(sub); + } public Construction(XY initPos) : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Construction) { diff --git a/logic/GameClass/GameObj/Areas/Home.cs b/logic/GameClass/GameObj/Areas/Home.cs index 369477bc..584b030b 100644 --- a/logic/GameClass/GameObj/Areas/Home.cs +++ b/logic/GameClass/GameObj/Areas/Home.cs @@ -6,17 +6,19 @@ namespace GameClass.GameObj.Areas; public class Home : Immovable, IHome { - public AtomicLong TeamID => throw new NotImplementedException(); - public LongInTheVariableRange HP => throw new NotImplementedException(); - public long Score => throw new NotImplementedException(); + private long teamID; + public long TeamID => teamID; + public LongInTheVariableRange HP => new LongInTheVariableRange(GameData.HomeHP); + public AtomicLong Score => new AtomicLong(0); public override bool IsRigid => false; public override ShapeType Shape => ShapeType.Square; public void AddScore(long add) { - throw new NotImplementedException(); + Score.Add(add); } - public Home(XY initPos) + public Home(XY initPos, long teamID) : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Home) { + this.teamID = teamID; } } diff --git a/logic/GameClass/GameObj/Areas/Resource.cs b/logic/GameClass/GameObj/Areas/Resource.cs index 07c7c96a..d0875586 100644 --- a/logic/GameClass/GameObj/Areas/Resource.cs +++ b/logic/GameClass/GameObj/Areas/Resource.cs @@ -6,48 +6,22 @@ namespace GameClass.GameObj.Areas; public class Resource : Immovable { - public LongInTheVariableRange HP => throw new NotImplementedException(); + public LongInTheVariableRange HP { get; } = new LongInTheVariableRange(GameData.ResourceHP); public override bool IsRigid => true; public override ShapeType Shape => ShapeType.Square; - private int producingNum = 0; - public int ProducingNum - { - get => Interlocked.CompareExchange(ref producingNum, 0, 0); - } - public void AddProducingNum() + public AtomicInt ProduceNum { get; } = new AtomicInt(0); + public bool Produce(int produceSpeed, Ship ship) { - Interlocked.Increment(ref producingNum); + // TODO: Add Money + return HP.SubV(produceSpeed) > 0; } - public void SubProducingNum() + public void AddProduceNum(int add = 1) { - Interlocked.Decrement(ref producingNum); + ProduceNum.Add(add); } - public bool Produce(int produceSpeed, Ship ship) + public void SubProduceNum(int sub = 1) { - long orgHP, value; - lock (gameObjLock) - { - if (HP == 0) - { - return false; - } - orgHP = HP.GetValue(); - HP.SubV(produceSpeed); - if (HP > HP.GetMaxV()) - { - HP.SetV(HP.GetMaxV()); - } - else if (HP < 0) - { - HP.SetV(0); - } - value = HP.GetValue(); - } - if (value < orgHP) - { - if (value == 0) return true; - } - return false; + ProduceNum.Sub(sub); } public Resource(XY initPos) : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Resource) diff --git a/logic/GameClass/GameObj/Areas/Wormhole.cs b/logic/GameClass/GameObj/Areas/Wormhole.cs index 83ddda46..4b6c84cb 100644 --- a/logic/GameClass/GameObj/Areas/Wormhole.cs +++ b/logic/GameClass/GameObj/Areas/Wormhole.cs @@ -7,13 +7,27 @@ namespace GameClass.GameObj.Areas; public class Wormhole : Immovable, IWormhole { - public LongInTheVariableRange HP => throw new NotImplementedException(); - public List Entrance => throw new NotImplementedException(); - public List Content => throw new NotImplementedException(); + public LongInTheVariableRange HP = new LongInTheVariableRange(GameData.WormholeHP); + private List grids = new(); + public List Grids => grids; public override bool IsRigid => HP > GameData.WormholeHP / 2; public override ShapeType Shape => ShapeType.Square; - public Wormhole(XY initPos) + public AtomicInt RepairNum { get; } = new AtomicInt(0); + public bool Repair(int constructSpeed, Ship ship) + { + return HP.AddV(constructSpeed) > 0; + } + public void AddRepairNum(int add = 1) + { + RepairNum.Add(add); + } + public void SubRepairNum(int sub = 1) + { + RepairNum.Sub(sub); + } + public Wormhole(XY initPos, List grids) : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Wormhole) { + this.grids = grids; } } \ No newline at end of file diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 5a09727d..14fadab4 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -3,6 +3,8 @@ using Preparation.Interface; using Preparation.Utility; using System; +using GameClass.GameObj.Areas; +using System.Linq; namespace GameClass.GameObj { @@ -94,10 +96,30 @@ public IOutOfBound GetOutOfBound(XY pos) { foreach (GameObj gameObj in GameObjDict[gameObjType]) { - if (GameData.ApproachToInteract(gameObj.Position, Pos)) + if (gameObjType == GameObjType.Wormhole) { - GameObjForInteract = gameObj; - break; + bool flag = false; + foreach (XY xy in ((Wormhole)gameObj).Grids) + { + if (GameData.ApproachToInteract(xy, Pos)) + { + GameObjForInteract = gameObj; + flag = true; + break; + } + } + if (flag) + { + break; + } + } + else + { + if (GameData.ApproachToInteract(gameObj.Position, Pos)) + { + GameObjForInteract = gameObj; + break; + } } } } @@ -286,11 +308,56 @@ public Map(uint[,] mapResource) } protoGameMap = new uint[mapResource.GetLength(0), mapResource.GetLength(1)]; Array.Copy(mapResource, protoGameMap, mapResource.Length); + long teamID = 0; for (int i = 0; i < GameData.MapRows; ++i) { for (int j = 0; j < GameData.MapCols; ++j) { - Add(Areas.AreaFactory.GetArea(GameData.GetCellCenterPos(i, j), (PlaceType)mapResource[i, j])); + bool hasWormhole = false; + switch (mapResource[i, j]) + { + case (uint)PlaceType.Resource: + Add(new Resource(GameData.GetCellCenterPos(i, j))); + break; + case (uint)PlaceType.Construction: + Add(new Construction(GameData.GetCellCenterPos(i, j))); + break; + case (uint)PlaceType.Wormhole: + foreach (Wormhole wormhole in GameObjDict[GameObjType.Wormhole].Cast()) + { + if (wormhole.Grids.Contains(new XY(i, j))) + { + hasWormhole = true; + break; + } + else + { + foreach (XY xy in wormhole.Grids) + { + if (Math.Abs(xy.x - i) <= 1 && Math.Abs(xy.y - j) <= 1) + { + wormhole.Grids.Add(new XY(i, j)); + hasWormhole = true; + break; + } + } + if (hasWormhole) + { + break; + } + } + } + if (!hasWormhole) + { + List grids = new(); + grids.Add(new XY(i, j)); + Add(new Wormhole(GameData.GetCellCenterPos(i, j), grids)); + } + break; + case (uint)PlaceType.Home: + Add(new Home(GameData.GetCellCenterPos(i, j), teamID++)); + break; + } } } } diff --git a/logic/GameClass/GameObj/Ship.cs b/logic/GameClass/GameObj/Ship.cs index 0a640fa3..e835bf21 100644 --- a/logic/GameClass/GameObj/Ship.cs +++ b/logic/GameClass/GameObj/Ship.cs @@ -65,6 +65,9 @@ public override bool IgnoreCollideExecutor(IGameObj targetObj) public IWeapon WeaponModule => weapon; #endregion + public int ProduceSpeed => producer.ProduceSpeed; + public int ConstructSpeed => constructor.ConstructSpeed; + private GameObj? whatInteractingWith = null; public GameObj? WhatInteractingWith { diff --git a/logic/GameClass/GameObj/Team.cs b/logic/GameClass/GameObj/Team.cs index b08385e0..f6e5f59c 100644 --- a/logic/GameClass/GameObj/Team.cs +++ b/logic/GameClass/GameObj/Team.cs @@ -17,16 +17,8 @@ public class Team private readonly Dictionary birthPointList; public Dictionary BirthPointList => birthPointList; private Home home; - private long score = 0; - public long Score - { - get => Interlocked.Read(ref score); - } - private long totalScore; - public long TotalScore - { - get => Interlocked.Read(ref totalScore); - } + public AtomicLong Money { get; } = new AtomicLong(0); + public AtomicLong Score { get; } = new AtomicLong(0); public Ship? GetShip(long shipID) { foreach (Ship ship in shipList) @@ -58,14 +50,14 @@ public bool AddShip(Ship ship) shipList.Add(ship); return true; } - public void AddScore(long add) + public void AddMoney(long add) { - Interlocked.Add(ref score, add); - Interlocked.Add(ref totalScore, add); + Money.Add(add); + Score.Add(add); } - public void SubScore(long sub) + public void SubMoney(long sub) { - Interlocked.Add(ref score, -sub); + Money.Sub(sub); } public void SetHome(Home home) { diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 394b46cd..1ae3e768 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -109,12 +109,18 @@ public bool Produce(Ship ship) () => { ship.ThreadNum.WaitOne(); + if (!resource.Produce(ship.ProduceSpeed, ship)) + { + ship.ThreadNum.Release(); + ship.ResetShipState(stateNum); + return; + } if (!ship.StartThread(stateNum, RunningStateType.RunningActively)) { ship.ThreadNum.Release(); return; } - resource.AddProducingNum(); + resource.AddProduceNum(); Thread.Sleep(GameData.CheckInterval); new FrameRateTaskExecutor ( @@ -132,17 +138,124 @@ public bool Produce(Ship ship) finallyReturn: () => 0 ).Start(); ship.ThreadNum.Release(); - resource.SubProducingNum(); + resource.SubProduceNum(); + } + ) + { IsBackground = true }.Start(); + return false; + } + public bool Construct(Ship ship, ConstructionType constructionType) + { + Construction? construction = (Construction?)gameMap.OneForInteract(ship.Position, GameObjType.Construction); + if (construction == null) + { + return false; + } + if (construction.HP == construction.HP.GetMaxV()) + { + return false; + } + long stateNum = ship.SetShipState(RunningStateType.Waiting, ShipStateType.Constructing); + if (stateNum == -1) + { + return false; + } + new Thread + ( + () => + { + ship.ThreadNum.WaitOne(); + if (!construction.Construct(ship.ConstructSpeed, constructionType, ship)) + { + ship.ThreadNum.Release(); + ship.ResetShipState(stateNum); + return; + } + if (!ship.StartThread(stateNum, RunningStateType.RunningActively)) + { + ship.ThreadNum.Release(); + return; + } + construction.AddConstructNum(); + Thread.Sleep(GameData.CheckInterval); + new FrameRateTaskExecutor + ( + loopCondition: () => stateNum == ship.StateNum && gameMap.Timer.IsGaming, + loopToDo: () => + { + if (construction.HP == construction.HP.GetMaxV()) + { + ship.ResetShipState(stateNum); + return false; + } + return true; + }, + timeInterval: GameData.CheckInterval, + finallyReturn: () => 0 + ).Start(); + ship.ThreadNum.Release(); + construction.SubConstructNum(); } ) { IsBackground = true }.Start(); return false; } - public bool Construct(Ship ship) + public bool Repair(Ship ship) { + Wormhole? wormhole = (Wormhole?)gameMap.OneForInteract(ship.Position, GameObjType.Wormhole); + if (wormhole == null) + { + return false; + } + if (wormhole.HP == wormhole.HP.GetMaxV()) + { + return false; + } + long stateNum = ship.SetShipState(RunningStateType.Waiting, ShipStateType.Constructing); + if (stateNum == -1) + { + return false; + } + new Thread + ( + () => + { + ship.ThreadNum.WaitOne(); + if (!wormhole.Repair(ship.ConstructSpeed, ship)) + { + ship.ThreadNum.Release(); + ship.ResetShipState(stateNum); + return; + } + if (!ship.StartThread(stateNum, RunningStateType.RunningActively)) + { + ship.ThreadNum.Release(); + return; + } + wormhole.AddRepairNum(); + Thread.Sleep(GameData.CheckInterval); + new FrameRateTaskExecutor + ( + loopCondition: () => stateNum == ship.StateNum && gameMap.Timer.IsGaming, + loopToDo: () => + { + if (wormhole.HP == wormhole.HP.GetMaxV()) + { + ship.ResetShipState(stateNum); + return false; + } + return true; + }, + timeInterval: GameData.CheckInterval, + finallyReturn: () => 0 + ).Start(); + ship.ThreadNum.Release(); + wormhole.SubRepairNum(); + } + ) + { IsBackground = true }.Start(); return false; } - } } } diff --git a/logic/Preparation/Interface/IHome.cs b/logic/Preparation/Interface/IHome.cs index 02857a37..bd5f93c9 100644 --- a/logic/Preparation/Interface/IHome.cs +++ b/logic/Preparation/Interface/IHome.cs @@ -4,9 +4,9 @@ namespace Preparation.Interface { public interface IHome { - public AtomicLong TeamID { get; } + public long TeamID { get; } public LongInTheVariableRange HP { get; } - public long Score { get; } + public AtomicLong Score { get; } public void AddScore(long add); } } diff --git a/logic/Preparation/Interface/IWormhole.cs b/logic/Preparation/Interface/IWormhole.cs index e46d6dbf..b5ce16cc 100644 --- a/logic/Preparation/Interface/IWormhole.cs +++ b/logic/Preparation/Interface/IWormhole.cs @@ -5,7 +5,6 @@ namespace Preparation.Interface { public interface IWormhole : IGameObj { - public List Entrance { get; } - public List Content { get; } + public List Grids { get; } } }