From dab6d3a73c07508d43a7085579a0fe35cab4446a Mon Sep 17 00:00:00 2001
From: Touhou <122487411+plskbs@users.noreply.github.com>
Date: Tue, 16 May 2023 22:16:38 -0500
Subject: [PATCH 1/4] Add destructible field
---
RogueEssence/Data/TileData.cs | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/RogueEssence/Data/TileData.cs b/RogueEssence/Data/TileData.cs
index d7714f76..69793234 100644
--- a/RogueEssence/Data/TileData.cs
+++ b/RogueEssence/Data/TileData.cs
@@ -1,7 +1,9 @@
using System;
using RogueEssence.Dungeon;
+using RogueEssence.Dev;
using RogueEssence.Content;
using RogueElements;
+using Newtonsoft.Json;
using Microsoft.Xna.Framework;
namespace RogueEssence.Data
@@ -22,7 +24,8 @@ public enum TriggerType
Trap,
Switch,
Blocker,
- Unlockable
+ Unlockable,
+ Destructible
}
public LocalText Name { get; set; }
@@ -53,6 +56,18 @@ public enum TriggerType
public Loc MinimapIcon;
public Color MinimapColor;
+ ///
+ /// Element for the tile- anything supereffective against this type will destroy it. If this is none, any attack will destroy it. Only used if TriggerType is Destructible.
+ ///
+ [JsonConverter(typeof(ElementConverter))]
+ [Dev.DataType(0, DataManager.DataType.Element, false)]
+ public string TileElement;
+
+ ///
+ /// If true, only attacks of TileElement will destroy the tile, rather than supereffective attacks. Only used if TriggerType is Destructible.
+ ///
+ public bool SpecificElementDestroysTile;
+
public PriorityList LandedOnTiles;
public PriorityList InteractWithTiles;
@@ -65,8 +80,7 @@ public TileData()
LandedOnTiles = new PriorityList();
InteractWithTiles = new PriorityList();
}
-
-
+
public string GetColoredName()
{
return String.Format("[color=#00FF00]{0}[color]", Name.ToLocal());
From aee24ae1ec2228b36e9df798f017ea4525954997 Mon Sep 17 00:00:00 2001
From: Touhou <122487411+plskbs@users.noreply.github.com>
Date: Wed, 17 May 2023 21:12:35 -0500
Subject: [PATCH 2/4] Get destructible tiles working
---
RogueEssence/Data/TileData.cs | 26 ++++++++---
.../Dungeon/GameEffects/BattleContext.cs | 44 +++++++++++++++++++
RogueEssence/Dungeon/Tiles/EffectTile.cs | 17 +++++++
3 files changed, 80 insertions(+), 7 deletions(-)
diff --git a/RogueEssence/Data/TileData.cs b/RogueEssence/Data/TileData.cs
index 69793234..86964c4b 100644
--- a/RogueEssence/Data/TileData.cs
+++ b/RogueEssence/Data/TileData.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using RogueEssence.Dungeon;
using RogueEssence.Dev;
using RogueEssence.Content;
@@ -24,8 +25,7 @@ public enum TriggerType
Trap,
Switch,
Blocker,
- Unlockable,
- Destructible
+ Unlockable
}
public LocalText Name { get; set; }
@@ -55,21 +55,31 @@ public enum TriggerType
public TriggerType StepType;
public Loc MinimapIcon;
public Color MinimapColor;
+
+ ///
+ /// Allows the tile to be destroyed by certain attacks.
+ ///
+ public bool Destructible;
///
- /// Element for the tile- anything supereffective against this type will destroy it. If this is none, any attack will destroy it. Only used if TriggerType is Destructible.
+ /// Any supereffective move used against this tile will destroy it. If this is none, any attack will destroy it. Only used if Destructible is true.
///
- [JsonConverter(typeof(ElementConverter))]
+ [JsonConverter(typeof(ElementListConverter))]
[Dev.DataType(0, DataManager.DataType.Element, false)]
- public string TileElement;
+ public List EffectiveElements;
///
- /// If true, only attacks of TileElement will destroy the tile, rather than supereffective attacks. Only used if TriggerType is Destructible.
+ /// The minimum damage needed to destroy the tile. Only used if Destructible is true.
///
- public bool SpecificElementDestroysTile;
+ public int PowerNeededToDestroy;
public PriorityList LandedOnTiles;
public PriorityList InteractWithTiles;
+
+ ///
+ /// Triggers right before the tile is destroyed. Only used if Destructible is true.
+ ///
+ public PriorityList OnTileDestroyed;
public TileData()
{
@@ -77,8 +87,10 @@ public TileData()
Desc = new LocalText();
Comment = "";
Anim = new ObjAnimData();
+ EffectiveElements = new List();
LandedOnTiles = new PriorityList();
InteractWithTiles = new PriorityList();
+ OnTileDestroyed = new PriorityList();
}
public string GetColoredName()
diff --git a/RogueEssence/Dungeon/GameEffects/BattleContext.cs b/RogueEssence/Dungeon/GameEffects/BattleContext.cs
index dde908f2..4e854998 100644
--- a/RogueEssence/Dungeon/GameEffects/BattleContext.cs
+++ b/RogueEssence/Dungeon/GameEffects/BattleContext.cs
@@ -232,6 +232,28 @@ public IEnumerator ProcessHitLoc(Loc loc)
actionContext.Target = charTarget;
yield return CoroutineManager.Instance.StartCoroutine(DungeonScene.Instance.HitTarget(actionContext, charTarget));//hit the character
}
+
+ Tile tile = ZoneManager.Instance.CurrentMap.GetTile(actionContext.TargetTile);
+ if (!String.IsNullOrEmpty(tile.Effect.ID))
+ {
+ TileData entry = DataManager.Instance.GetTile(tile.Effect.GetID());
+ if (entry != null && entry.Destructible && actionContext.ActionType == BattleActionType.Skill)
+ {
+ BattleData data = actionContext.Data;
+ if (data != null)
+ {
+ BasePowerState powerState = data.SkillStates.GetWithDefault();
+ //Check if the attack is from the specific element or from no element, and deals enough damage
+ if ((entry.EffectiveElements.Contains(data.Element) || entry.EffectiveElements.Count == 0)
+ && powerState != null && powerState.Power >= entry.PowerNeededToDestroy)
+ {
+ yield return CoroutineManager.Instance.StartCoroutine(tile.Effect.OnTileDestroyed(charTarget));
+ tile.Effect = new EffectTile(tile.Effect.TileLoc);
+ }
+ }
+ }
+ }
+
//do thing to tile
yield return CoroutineManager.Instance.StartCoroutine(actionContext.User.HitTile(actionContext));
}
@@ -241,6 +263,28 @@ public IEnumerator ProcessHitTile(Loc loc)
BattleContext actionContext = new BattleContext(this, false);
actionContext.TargetTile = loc;
+ Tile tile = ZoneManager.Instance.CurrentMap.GetTile(actionContext.TargetTile);
+ if (!String.IsNullOrEmpty(tile.Effect.ID))
+ {
+ TileData entry = DataManager.Instance.GetTile(tile.Effect.GetID());
+ if (entry != null && entry.Destructible && actionContext.ActionType == BattleActionType.Skill)
+ {
+ BattleData data = actionContext.Data;
+ Character charTarget = actionContext.User;
+ if (data != null && charTarget != null)
+ {
+ BasePowerState powerState = data.SkillStates.GetWithDefault();
+ //Check if the attack is from the specific element or from no element, and deals enough damage
+ if ((entry.EffectiveElements.Contains(data.Element) || entry.EffectiveElements.Count == 0)
+ && powerState != null && powerState.Power >= entry.PowerNeededToDestroy)
+ {
+ yield return CoroutineManager.Instance.StartCoroutine(tile.Effect.OnTileDestroyed(charTarget));
+ tile.Effect = new EffectTile(tile.Effect.TileLoc);
+ }
+ }
+ }
+ }
+
//do thing to tile
yield return CoroutineManager.Instance.StartCoroutine(actionContext.User.HitTile(actionContext));
}
diff --git a/RogueEssence/Dungeon/Tiles/EffectTile.cs b/RogueEssence/Dungeon/Tiles/EffectTile.cs
index 46f342e6..0a63736d 100644
--- a/RogueEssence/Dungeon/Tiles/EffectTile.cs
+++ b/RogueEssence/Dungeon/Tiles/EffectTile.cs
@@ -120,6 +120,23 @@ public IEnumerator LandedOnTile(Character character)
yield break;
}
}
+
+ public IEnumerator OnTileDestroyed(Character character)
+ {
+ SingleCharContext context = new SingleCharContext(character);
+ // should the context be extended to the caller?
+ DungeonScene.EventEnqueueFunction function = (StablePriorityQueue> queue, Priority maxPriority, ref Priority nextPriority) =>
+ {
+ TileData entry = DataManager.Instance.GetTile(ID);
+ AddEventsToQueue(queue, maxPriority, ref nextPriority, entry.OnTileDestroyed, context.User);
+ };
+ foreach (EventQueueElement effect in DungeonScene.IterateEvents(function))
+ {
+ yield return CoroutineManager.Instance.StartCoroutine(effect.Event.Apply(effect.Owner, effect.OwnerChar, context));
+ if (context.CancelState.Cancel)
+ yield break;
+ }
+ }
public void DrawDebug(SpriteBatch spriteBatch, Loc offset) { }
public void Draw(SpriteBatch spriteBatch, Loc offset)
From 17ce4151a3d07adb07ff7189d0a9052b0921c30c Mon Sep 17 00:00:00 2001
From: Touhou <122487411+plskbs@users.noreply.github.com>
Date: Wed, 17 May 2023 22:01:50 -0500
Subject: [PATCH 3/4] Adding Object classification that blocks movement but NOT
attacks
---
RogueEssence/Data/TileData.cs | 4 +-
RogueEssence/Dungeon/Characters/CharAction.cs | 10 ++---
RogueEssence/Dungeon/Characters/Hitbox.cs | 4 +-
RogueEssence/Dungeon/DSceneAction.cs | 2 +-
RogueEssence/Dungeon/DSceneMap.cs | 4 +-
RogueEssence/Dungeon/Maps/BaseMap.cs | 38 ++++++++++++++++++-
6 files changed, 49 insertions(+), 13 deletions(-)
diff --git a/RogueEssence/Data/TileData.cs b/RogueEssence/Data/TileData.cs
index 86964c4b..f5f49aa6 100644
--- a/RogueEssence/Data/TileData.cs
+++ b/RogueEssence/Data/TileData.cs
@@ -25,7 +25,8 @@ public enum TriggerType
Trap,
Switch,
Blocker,
- Unlockable
+ Unlockable,
+ Object
}
public LocalText Name { get; set; }
@@ -92,7 +93,6 @@ public TileData()
InteractWithTiles = new PriorityList();
OnTileDestroyed = new PriorityList();
}
-
public string GetColoredName()
{
return String.Format("[color=#00FF00]{0}[color]", Name.ToLocal());
diff --git a/RogueEssence/Dungeon/Characters/CharAction.cs b/RogueEssence/Dungeon/Characters/CharAction.cs
index d70c1b4c..674aa3db 100644
--- a/RogueEssence/Dungeon/Characters/CharAction.cs
+++ b/RogueEssence/Dungeon/Characters/CharAction.cs
@@ -802,7 +802,7 @@ private Loc GetLanding(Loc ownerLoc, Dir8 dir, int mod)
for (int ii = 0; ii < modRange; ii++)
{
targetLoc += addLoc;
- if (ZoneManager.Instance.CurrentMap.TileBlocked(targetLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(targetLoc, true))
break;
}
return targetLoc + HitOffset;
@@ -1320,7 +1320,7 @@ public Loc GetFarthestLanding(Character owner, Loc ownerLoc, Dir8 dir, int mod)
for (int ii = 0; ii < modRange; ii++)
{
targetLoc += addLoc;
- if (ZoneManager.Instance.CurrentMap.TileBlocked(targetLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(targetLoc, true))
break;
}
return targetLoc;
@@ -1415,14 +1415,14 @@ public override bool IsWide()
}
- if (ZoneManager.Instance.CurrentMap.TileBlocked(leftLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(leftLoc, true))
sideL[side] = false;
- if (ZoneManager.Instance.CurrentMap.TileBlocked(rightLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(rightLoc, true))
sideR[side] = false;
}
}
- if (ZoneManager.Instance.CurrentMap.TileBlocked(targetLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(targetLoc, true))
sideM = false;
}
return null;
diff --git a/RogueEssence/Dungeon/Characters/Hitbox.cs b/RogueEssence/Dungeon/Characters/Hitbox.cs
index 3573e81e..6db96cc9 100644
--- a/RogueEssence/Dungeon/Characters/Hitbox.cs
+++ b/RogueEssence/Dungeon/Characters/Hitbox.cs
@@ -457,7 +457,7 @@ private void preCalculateCoverage(StablePriorityQueue tilesToHit, int
tilesToHit.Enqueue(calculateTimeToHit(Origin) + delay, Origin);
Loc backup = Origin;
- if (MaxRadius > 0 && ZoneManager.Instance.CurrentMap.TileBlocked(Origin, true))
+ if (MaxRadius > 0 && ZoneManager.Instance.CurrentMap.TileAttackBlocked(Origin, true))
backup += Dir.Reverse().GetLoc();
Grid.FloodFill(new Rect(Origin - new Loc(MaxRadius), new Loc(MaxRadius * 2 + 1)),
@@ -467,7 +467,7 @@ private void preCalculateCoverage(StablePriorityQueue tilesToHit, int
return true;
if (!IsInSquareHitbox(testLoc, Origin, MaxRadius, HitArea, Dir))
return true;
- if (ZoneManager.Instance.CurrentMap.TileBlocked(testLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(testLoc, true))
return true;
return false;
diff --git a/RogueEssence/Dungeon/DSceneAction.cs b/RogueEssence/Dungeon/DSceneAction.cs
index dcb50bf9..5b62eedf 100644
--- a/RogueEssence/Dungeon/DSceneAction.cs
+++ b/RogueEssence/Dungeon/DSceneAction.cs
@@ -684,7 +684,7 @@ public bool IsTargeted(Loc tile, TileAlignment tileAlignment)
return true;
TerrainData.Mobility mobility = TerrainData.Mobility.Lava | TerrainData.Mobility.Water | TerrainData.Mobility.Abyss;
- if (ZoneManager.Instance.CurrentMap.TileBlocked(tile, mobility))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(tile, mobility))
return true;
else
return false;
diff --git a/RogueEssence/Dungeon/DSceneMap.cs b/RogueEssence/Dungeon/DSceneMap.cs
index 42f7b5ba..bbae2284 100644
--- a/RogueEssence/Dungeon/DSceneMap.cs
+++ b/RogueEssence/Dungeon/DSceneMap.cs
@@ -560,7 +560,7 @@ public IEnumerator ProcessObjectInteract(Character character,
if (tile != null && !String.IsNullOrEmpty(tile.Effect.ID))
{
TileData entry = DataManager.Instance.GetTile(tile.Effect.ID);
- if (entry.StepType == TileData.TriggerType.Blocker || entry.StepType == TileData.TriggerType.Unlockable)
+ if (entry.StepType == TileData.TriggerType.Blocker || entry.StepType == TileData.TriggerType.Unlockable || entry.StepType == TileData.TriggerType.Object)
{
yield return CoroutineManager.Instance.StartCoroutine(tile.Effect.LandedOnTile(character));
yield return CoroutineManager.Instance.StartCoroutine(ActivateTraps(character));
@@ -1446,7 +1446,7 @@ public IEnumerator ThrowTo(Character character, Character atta
for (int ii = 0; ii < range; ii++)
{
Loc nextLoc = endLoc + dir.GetLoc();
- if (ZoneManager.Instance.CurrentMap.TileBlocked(nextLoc, true))
+ if (ZoneManager.Instance.CurrentMap.TileAttackBlocked(nextLoc, true))
break;
endLoc = nextLoc;
}
diff --git a/RogueEssence/Dungeon/Maps/BaseMap.cs b/RogueEssence/Dungeon/Maps/BaseMap.cs
index 11fc8601..0e9a837a 100644
--- a/RogueEssence/Dungeon/Maps/BaseMap.cs
+++ b/RogueEssence/Dungeon/Maps/BaseMap.cs
@@ -120,6 +120,42 @@ public int GetItem(Loc loc)
}
return -1;
}
+
+ public bool TileAttackBlocked(Loc loc)
+ {
+ return TileAttackBlocked(loc, false);
+ }
+
+ public bool TileAttackBlocked(Loc loc, bool inclusive)
+ {
+ return TileAttackBlocked(loc, inclusive, false);
+ }
+
+ public bool TileAttackBlocked(Loc loc, bool inclusive, bool diagonal)
+ {
+ return TileAttackBlocked(loc, inclusive ? TerrainData.Mobility.All : TerrainData.Mobility.Passable, diagonal);
+ }
+
+ public bool TileAttackBlocked(Loc loc, TerrainData.Mobility mobility)
+ {
+ return TileAttackBlocked(loc, mobility, false);
+ }
+
+ public bool TileAttackBlocked(Loc loc, TerrainData.Mobility mobility, bool diagonal)
+ {
+ Tile tile = Tiles[loc.X][loc.Y];
+ if (!String.IsNullOrEmpty(tile.Effect.ID))
+ {
+ TileData effect = DataManager.Instance.GetTile(tile.Effect.ID);
+ if (effect.StepType == TileData.TriggerType.Object)
+ {
+ //Objects should allow attacks through but not movement
+ return false;
+ }
+ }
+
+ return TileBlocked(loc, mobility, diagonal);
+ }
public bool TileBlocked(Loc loc)
{
@@ -185,7 +221,7 @@ public bool EffectTileBlocked(TileData effect, bool diagonal)
//doesn't apply here; for now, assume all effects block diagonal if they block at all
//if (diagonal && !effect.BlockDiagonal)
// return false;
- if (effect.StepType == TileData.TriggerType.Unlockable || effect.StepType == TileData.TriggerType.Blocker)
+ if (effect.StepType == TileData.TriggerType.Unlockable || effect.StepType == TileData.TriggerType.Blocker || effect.StepType == TileData.TriggerType.Object)
return true;
return false;
From 36047fcd953d789a218f4b5c0b340330ee11219a Mon Sep 17 00:00:00 2001
From: Touhou <122487411+plskbs@users.noreply.github.com>
Date: Wed, 17 May 2023 23:10:39 -0500
Subject: [PATCH 4/4] Object tiles should be hidden behind objects
---
RogueEssence/Dungeon/BaseDungeonScene.cs | 17 +++++++++++++++--
RogueEssence/Dungeon/DungeonScene.cs | 17 +++++++++++++++--
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/RogueEssence/Dungeon/BaseDungeonScene.cs b/RogueEssence/Dungeon/BaseDungeonScene.cs
index 658820b6..be6bf427 100644
--- a/RogueEssence/Dungeon/BaseDungeonScene.cs
+++ b/RogueEssence/Dungeon/BaseDungeonScene.cs
@@ -237,9 +237,22 @@ protected virtual void DrawItems(SpriteBatch spriteBatch, bool showHiddenItem)
{
foreach(Loc viewLoc in IterateRelevantDraw(wrapped, wrapSize, item))
{
- TerrainTile tile = ZoneManager.Instance.CurrentMap.Tiles[item.TileLoc.X][item.TileLoc.Y].Data;
+ Tile rootTile = ZoneManager.Instance.CurrentMap.Tiles[item.TileLoc.X][item.TileLoc.Y];
+ TerrainTile tile = rootTile.Data;
TerrainData terrain = tile.GetData();
- if (terrain.BlockType == TerrainData.Mobility.Impassable || terrain.BlockType == TerrainData.Mobility.Block)
+
+ //Object tiles should hide items beneath them
+ bool hiddenBehindObject = false;
+ if (!String.IsNullOrEmpty(rootTile.Effect.ID))
+ {
+ TileData effect = DataManager.Instance.GetTile(rootTile.Effect.ID);
+ if (effect.StepType == TileData.TriggerType.Object)
+ {
+ hiddenBehindObject = true;
+ }
+ }
+
+ if (terrain.BlockType == TerrainData.Mobility.Impassable || terrain.BlockType == TerrainData.Mobility.Block || hiddenBehindObject)
{
if (showHiddenItem)
item.Draw(spriteBatch, viewLoc, Color.White * 0.7f);
diff --git a/RogueEssence/Dungeon/DungeonScene.cs b/RogueEssence/Dungeon/DungeonScene.cs
index 1df9fb89..e86a7a62 100644
--- a/RogueEssence/Dungeon/DungeonScene.cs
+++ b/RogueEssence/Dungeon/DungeonScene.cs
@@ -1049,8 +1049,21 @@ protected override void DrawItems(SpriteBatch spriteBatch, bool showHiddenItem)
{
foreach (Loc viewLoc in IterateRelevantDraw(wrapped, wrapSize, item))
{
- TerrainData terrain = ZoneManager.Instance.CurrentMap.Tiles[item.TileLoc.X][item.TileLoc.Y].Data.GetData();
- if (terrain.BlockType == TerrainData.Mobility.Impassable || terrain.BlockType == TerrainData.Mobility.Block)
+ Tile rootTile = ZoneManager.Instance.CurrentMap.Tiles[item.TileLoc.X][item.TileLoc.Y];
+ TerrainData terrain = rootTile.Data.GetData();
+
+ //Object tiles should hide items beneath them
+ bool hiddenBehindObject = false;
+ if (!String.IsNullOrEmpty(rootTile.Effect.ID))
+ {
+ TileData effect = DataManager.Instance.GetTile(rootTile.Effect.ID);
+ if (effect.StepType == TileData.TriggerType.Object)
+ {
+ hiddenBehindObject = true;
+ }
+ }
+
+ if (terrain.BlockType == TerrainData.Mobility.Impassable || terrain.BlockType == TerrainData.Mobility.Block || hiddenBehindObject)
{
if (showHiddenItem)
item.Draw(spriteBatch, viewLoc, Color.White * 0.5f);