Skip to content

Commit

Permalink
Merge pull request #44 from Talberon/SOL-45_action_menu_and_spoils_re…
Browse files Browse the repository at this point in the history
…work

Sol 45 action menu and spoils rework
  • Loading branch information
Talberon authored Sep 18, 2019
2 parents f3b6c58 + 901f10a commit 84856af
Show file tree
Hide file tree
Showing 186 changed files with 13,167 additions and 85,980 deletions.
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
# Sol Standard
Sol Standard is a tactical strategy game that pits two players against each other in the pursuit of victory! There are several classes of units available, as well as computer-controlled monsters. Plenty of items and interactable tiles allow for vastly different gameplay experiences on different battle maps.

Check out the project website for media, Discord and credits! https://talberon.github.io/solstandard/

Sol Standard is a competitive tactics game that focuses on allowing players to outmaneuver and outsmart their opponents! There are various units with unique abilities that you can command to achieve victory, each with their own playstyle and synergies with other units. There are lots of multiplayer maps to play with your friends, or you can check out one of the solo maps for some practice.

Each map has various items, AI-controlled monsters and interactable objects that you can leverage to gain the advantage over your foes. Draft your army and form a composition that fits your own playstyle, whether it's super fast and deadly, or strong and stable, and anywhere inbetween.

Keyboard and Gamepads are both supported and the interface will dynamically update based on whichever one you are using. Xbox controllers work best, and you can use a different controller for each player. The keyboard can control both players as well if you want to trade off or play against yourself. Netplay is also available; be sure to port forward if hosting a match over the internet.

## Project Info
Sol Standard started as a continuation of [@Talberon](https://github.com/Talberon)'s Ars Tactica project before dropping the project entirely to rebuild it in a cleaner project structure. The project is written in C# using the Monogame framework; an open-source continuation of Microsoft's XNA Framework. The project currently runs on .NET Framework 4.7.1, but may be updated to .NET Core in the future.
Sol Standard started as a rewrite of [@Talberon](https://github.com/Talberon)'s Ars Tactica project before dropping the original project to rebuild it in a cleaner structure and with newer tools. This project is written in C# using Monogame; an open-source continuation of Microsoft's XNA Framework. The project currently runs on .NET Framework 4.7.1, but may be updated to .NET Core in the future.

## Gallery

### Gameplay Samples
### Combat

<img src="https://i.imgur.com/OMOhyPU.gif" alt="Combat" width="650" />

### Unit Drafting

<img src="https://i.imgur.com/VyBCvmM.gif" alt="Unit Drafting" width="650" />

### AI Units

#### Combat
![Combat](https://i.imgur.com/v1avMuD.gif)
<img src="https://i.imgur.com/a1zlT7S.gif" alt="AI Units" width="650" />

#### Unit Action
![Unit Action](https://i.imgur.com/Fqr8UsU.gif)
### Interactive Tiles

#### Turn Resolution
![Turn Resolution](https://i.imgur.com/pbYdZy6.gif)
<img src="https://i.imgur.com/k9Md1QX.gif" alt="Interactive Tiles" width="650" />


## A Note About Art Assets
Art assets are amalgamated from a variety of self-made, public domain and paid resources, so none of the art/sound assets are included in this repository for redistribution. Check out `CREDITS.md` for info on licensing and credit for asset work.
Art assets are amalgamated from a variety of self-made, public domain and paid resources, so none of the art/sound assets are included in this repository for redistribution. **Check out `CREDITS.md` for info on licensing and credit for asset work.**
89 changes: 77 additions & 12 deletions SolStandard/Containers/Contexts/BattleContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
using Microsoft.Xna.Framework.Graphics;
using SolStandard.Containers.Contexts.Combat;
using SolStandard.Containers.View;
using SolStandard.Entity;
using SolStandard.Entity.General;
using SolStandard.Entity.General.Item;
using SolStandard.Entity.Unit;
using SolStandard.Entity.Unit.Actions;
using SolStandard.Entity.Unit.Statuses;
Expand All @@ -32,6 +34,8 @@ public enum BattleState
ResolveCombat
}

private const int BountyPerTriumph = 10;

private readonly BattleView battleView;

private CombatDamage attackerDamage;
Expand All @@ -47,6 +51,8 @@ public enum BattleState

private GameUnit attacker;
private GameUnit defender;
private Vector2 attackerCoordinates;
private Vector2 defenderCoordinates;
private UnitStatistics attackerStats;
private UnitStatistics defenderStats;

Expand Down Expand Up @@ -94,10 +100,8 @@ public void StartNewCombat(GameUnit newAttacker, GameUnit newDefender, UnitStati
defender.SetUnitAnimation(UnitAnimationState.Active);

//Treat the unit as off-screen if null
Vector2 attackerCoordinates =
attacker.UnitEntity?.MapCoordinates ?? new Vector2(-1);
Vector2 defenderCoordinates =
defender.UnitEntity?.MapCoordinates ?? new Vector2(-1);
attackerCoordinates = attacker.UnitEntity?.MapCoordinates ?? new Vector2(-1);
defenderCoordinates = defender.UnitEntity?.MapCoordinates ?? new Vector2(-1);

attackerInRange = true;
defenderInRange =
Expand Down Expand Up @@ -177,6 +181,15 @@ public void ContinueCombat()
GlobalEventQueue.QueueSingleEvent(new EndTurnEvent());
}

if (!attacker.IsAlive)
{
TakeAttackerSpoilsAndIncreaseBounty();
}
else if (!defender.IsAlive)
{
TakeDefenderSpoilsAndIncreaseBounty();
}

GameContext.MapCamera.RevertToPreviousZoomLevel();
}

Expand All @@ -186,15 +199,67 @@ public void ContinueCombat()
}
}

private void TakeDefenderSpoilsAndIncreaseBounty()
{
MapSlice defenderSlice = MapContainer.GetMapSliceAtCoordinates(defenderCoordinates);
if (!(defenderSlice.ItemEntity is Spoils defenderSpoils)) return;

GlobalEventQueue.QueueSingleEvent(new TakeSpoilsEvent(defenderSpoils));

string toastMessage = string.Empty;
toastMessage += $"Obtained {defenderSpoils.Gold} {Currency.CurrencyAbbreviation}!";

foreach (IItem item in defenderSpoils.Items)
{
toastMessage += Environment.NewLine;
toastMessage += $"Obtained {item.Name}!";
}

attacker.CurrentBounty += BountyPerTriumph;
toastMessage += Environment.NewLine + Environment.NewLine +
$"{attacker.Id} bounty increased by {BountyPerTriumph}!";

GlobalEventQueue.QueueSingleEvent(
new ToastAtCoordinatesEvent(attackerCoordinates, toastMessage, AssetManager.CoinSFX, 80)
);

GlobalEventQueue.QueueSingleEvent(new WaitFramesEvent(10));
}

private void TakeAttackerSpoilsAndIncreaseBounty()
{
MapSlice attackerSlice = MapContainer.GetMapSliceAtCoordinates(attackerCoordinates);
if (!(attackerSlice.ItemEntity is Spoils attackerSpoils)) return;
GlobalEventQueue.QueueSingleEvent(new TakeSpoilsEvent(attackerSpoils));

string toastMessage = string.Empty;
toastMessage += $"Obtained {attackerSpoils.Gold} {Currency.CurrencyAbbreviation}!";

foreach (IItem item in attackerSpoils.Items)
{
toastMessage += Environment.NewLine;
toastMessage += $"Obtained {item.Name}!";
}

defender.CurrentBounty += BountyPerTriumph;
toastMessage += Environment.NewLine + Environment.NewLine +
$"{defender.Id} bounty increased by {BountyPerTriumph}!";

GlobalEventQueue.QueueSingleEvent(
new ToastAtCoordinatesEvent(defenderCoordinates, toastMessage, AssetManager.CoinSFX, 80)
);
GlobalEventQueue.QueueSingleEvent(new WaitFramesEvent(10));
}

private void SetPromptWindowText(string promptText)
{
IRenderable[,] promptTextContent =
{
{
new RenderText(AssetManager.PromptFont, promptText),
new RenderBlank(),
new RenderBlank(),
new RenderBlank()
RenderBlank.Blank,
RenderBlank.Blank,
RenderBlank.Blank
},
{
new RenderText(AssetManager.PromptFont, "["),
Expand Down Expand Up @@ -223,11 +288,11 @@ private void SetupHelpWindow()
{
{
new RenderText(AssetManager.WindowFont, helpText, Color.White),
new RenderBlank(),
new RenderBlank(),
new RenderBlank(),
new RenderBlank(),
new RenderBlank()
RenderBlank.Blank,
RenderBlank.Blank,
RenderBlank.Blank,
RenderBlank.Blank,
RenderBlank.Blank
},
{
new RenderText(AssetManager.WindowFont, "Dice Legend: ", Color.White),
Expand Down
14 changes: 2 additions & 12 deletions SolStandard/Containers/Contexts/ControlContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ private static void MapControls(ControlMapper controlMapper)
case GameMapContext.TurnState.AdHocDraft:
AdHocDraftControl(controlMapper);
break;
case GameMapContext.TurnState.StealItem:
case GameMapContext.TurnState.TakeItem:
StealItemControl(controlMapper);
break;
case GameMapContext.TurnState.SelectUnit:
Expand Down Expand Up @@ -538,16 +538,6 @@ private static void DecideActionControl(ControlMapper controlMapper)
GlobalEventQueue.QueueSingleEvent(new MoveActionMenuEvent(MenuCursorDirection.Right));
}

if (controlMapper.Press(Input.PreviewUnit, PressType.Single))
{
GlobalEventQueue.QueueSingleEvent(new ToggleCombatMenuEvent());
}

if (controlMapper.Press(Input.PreviewItem, PressType.Single))
{
GlobalEventQueue.QueueSingleEvent(new ToggleCombatMenuEvent());
}

if (controlMapper.Press(Input.Confirm, PressType.Single))
{
GlobalEventQueue.QueueSingleEvent(new SelectActionMenuOptionEvent());
Expand Down Expand Up @@ -651,7 +641,7 @@ private static void UnitTargetingControl(ControlMapper controlMapper)

if (controlMapper.Press(Input.Cancel, PressType.Single))
{
GlobalEventQueue.QueueSingleEvent(new CancelActionEvent());
GlobalEventQueue.QueueSingleEvent(new CancelActionTargetingEvent());
}
}

Expand Down
2 changes: 1 addition & 1 deletion SolStandard/Containers/Contexts/DeploymentContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private void UpdateItemPreview(MapSlice hoverSlice)

public void MoveToNextDeploymentTile()
{
List<MapEntity> mapEntities = MapContainer.GetMapEntities();
IEnumerable<MapEntity> mapEntities = MapContainer.GetMapEntities();
List<MapEntity> deployTiles = mapEntities.Where(tile => tile is DeployTile).ToList();
if (deployTiles.Count == 0) return;

Expand Down
4 changes: 2 additions & 2 deletions SolStandard/Containers/Contexts/DraftContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public void StartNewDraft(int blueTeamUnitMax, int redTeamUnitMax, int maxUnitDu
redUnitCount = new Dictionary<Role, int>();

DraftView.UpdateCommanderPortrait(Role.Silhouette, Team.Creep);
DraftView.UpdateTeamUnitsWindow(new List<IRenderable> {new RenderBlank()}, Team.Blue);
DraftView.UpdateTeamUnitsWindow(new List<IRenderable> {new RenderBlank()}, Team.Red);
DraftView.UpdateTeamUnitsWindow(new List<IRenderable> {RenderBlank.Blank}, Team.Blue);
DraftView.UpdateTeamUnitsWindow(new List<IRenderable> {RenderBlank.Blank}, Team.Red);
DraftView.UpdateUnitSelectMenu(firstTurn, GetRolesEnabled(blueUnitCount, maxDuplicateUnitType));

DraftView.UpdateHelpWindow(
Expand Down
15 changes: 9 additions & 6 deletions SolStandard/Containers/Contexts/GameContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public enum GameState

public static readonly Color PositiveColor = new Color(30, 200, 30);
public static readonly Color NegativeColor = new Color(250, 10, 10);
public static readonly Color NeutralColor = new Color(255, 250, 250);
public static readonly Color NeutralColor = new Color(255, 255, 255);
public static readonly Color DimColor = new Color(100, 100, 100);

private const string MapDirectory = "Content/TmxMaps/";
private const string MapSelectFile = "Map_Select_06.tmx";
Expand All @@ -57,8 +58,8 @@ public enum GameState
public static DeploymentContext DeploymentContext { get; private set; }
public static CodexContext CodexContext { get; private set; }
public static CreditsContext CreditsContext { get; private set; }
public static Team P1Team { get; private set; }

public static Team P1Team { get; private set; }
public static Team P2Team => (P1Team == Team.Blue) ? Team.Red : Team.Blue;

public static GameState CurrentGameState;
Expand All @@ -80,17 +81,17 @@ public static PlayerIndex ActivePlayer
case GameState.Deployment:
return GetPlayerForTeam(DeploymentContext.CurrentTurn);
case GameState.PauseScreen:
return GetPlayerForTeam(InitiativeContext.CurrentActiveTeam);
return GetPlayerForTeam(ActiveTeam);
case GameState.InGame:
return GetPlayerForTeam(InitiativeContext.CurrentActiveTeam);
return GetPlayerForTeam(ActiveTeam);
case GameState.Codex:
return GetPlayerForTeam(CodexContext.CurrentTeam);
case GameState.Results:
return PlayerIndex.Four;
case GameState.Credits:
return PlayerIndex.One;
case GameState.ItemPreview:
return GetPlayerForTeam(InitiativeContext.CurrentActiveTeam);
return GetPlayerForTeam(ActiveTeam);
default:
throw new ArgumentOutOfRangeException();
}
Expand Down Expand Up @@ -185,6 +186,7 @@ public static MapCamera MapCamera
public static List<GameUnit> Units => InitiativeContext.InitiativeList;

public static GameUnit ActiveUnit => InitiativeContext.CurrentActiveUnit;
public static Team ActiveTeam => InitiativeContext.CurrentActiveTeam;

public static void CenterCursorAndCamera()
{
Expand Down Expand Up @@ -291,7 +293,8 @@ private static void InjectCreepsIntoSpawnTiles(List<IItem> mapLoot)
}
}

private static void InjectCreepIntoTile(List<IItem> mapLoot, CreepEntity randomSummon, MapElement creepDeployTile)
private static void InjectCreepIntoTile(List<IItem> mapLoot, CreepEntity randomSummon,
MapElement creepDeployTile)
{
Trace.WriteLine($"Injecting {randomSummon.Name} at {creepDeployTile.MapCoordinates}");

Expand Down
Loading

0 comments on commit 84856af

Please sign in to comment.