Twilight's Call DungeonCrawler uses a variation of the press turn system popularised by Shin Megami Tensei Nocturne. Hitting the enemys weakness will give you more turns but hitting the enemys strength will make you lose your turns. The combat moves in a much more fervent pace and was a great choice to create engaging combat.
public class Attack : Skills
{
public override void Start()
{
m_ElementalType = ElementalType.Null;
m_SkillType = SkillType.Attack;
m_Damagetype = DamageType.Strength;
m_Damage = 110;
m_SkillName = "Attack";
m_SkillDescription = "Attack a single enemy";
m_AnimationName = "t_IsAttack";
m_SkillRange = 1;
}
// Update is called once per frame
public override List UseSkill(List aVictum, Creatures aAttacker )
{
List AllSkillActions = new List();
for (int i = 0; i < aVictum.Count; i++)
{
AllSkillActions.Add(aVictum[i].DecrementHealth(m_Damage + aAttacker.GetAllStrength() / 3, GetElementalType(),
0.1f, 0.1f, 1));
}
return AllSkillActions;
}
public override IEnumerator UseSkill(Creatures aVictum, Creatures aAttacker )
{
return aVictum.DecrementHealth(m_Damage + aAttacker.GetAllStrength() /3, GetElementalType(),
0.1f, 0.1f, 1);
}
}
//Skill Execution Manager
public void ExecuteSkill(Skills aSkill, bool aSkillRange,int aSkillPosition, Creatures aAttacker)
{
aAttacker.CurrentMana -= aSkillRange ? aSkill.m_MultiTargetCost : aSkill.m_SingleTargetCost;
//Single Target Attack
if (aSkill.m_SkillType == Skills.SkillType.Attack && !aSkillRange)
{
SingleTargetAttack(aSkill, aAttacker, aSkillPosition);
}
//Party Wide Attacks
if (aSkill.m_SkillType == Skills.SkillType.Attack && aSkillRange)
{
PartyWideAttack(aSkill, aAttacker);
}
// Single target Heals
if (aSkill.m_SkillType == Skills.SkillType.Heal && !aSkillRange)
{
SingleTargetHeal(aSkill, aAttacker, aSkillPosition);
}
// Party Wide Heals
if (aSkill.m_SkillType == Skills.SkillType.Heal && aSkillRange)
{
PartyWideHeal( aSkill, aAttacker);
}
// Single target Heals
if (aSkill.m_SkillType == Skills.SkillType.Buff && !aSkillRange)
{
SingleTargetBuff(aSkill, aAttacker, aSkillPosition);
}
// Party Wide Heals
if (aSkill.m_SkillType == Skills.SkillType.Buff && aSkillRange)
{
PartyWideBuff( aSkill, aAttacker);
}
}
//Press Turn Manager
//This method will be used at the end when all is activated
public void ProcessTurn(List aAllTurnReactions)
{
//Null Skills Consume all pressturns completely
foreach (PressTurnReactions reaction in aAllTurnReactions)
{
if (reaction == PressTurnReactions.Null)
{
NulledPressTurn();
return;
}
}
//If Dodged Consume two pressturns if empowered only take the empowered and the next token
foreach (PressTurnReactions reaction in aAllTurnReactions)
{
if (reaction == PressTurnReactions.Dodge ||
reaction == PressTurnReactions.Strong )
{
DodgedPressTurn();
return;
}
}
//If weakness is hit correctly then the turn that was used will be empowered
foreach (PressTurnReactions reaction in aAllTurnReactions)
{
if (reaction == PressTurnReactions.Weak ||
reaction == PressTurnReactions.Pass)
{
WeaknessPressTurn();
return;
}
}
//Normal action Consume 1 empowered or normal pressturn
NormalPressTurn();
//Passing will turn a whole icon into a empowered one but will consume an empowered one if it is
}
// This is the array that contains the floor, each number represents an avaliable direction
short tableinit[] =
{
0, 10, 15, 9, 10, 15, 9, 0, 2, 0, 0, 0, 0, 0, 0, 4, 11, 15, 3, 0, //1
4, 5, 5, 13, 14, 5, 5, 15, 5, 9, 11, 11, 11, 11, 11, 15, 9, 14, 11, 3, //2
0, 8, 5, 13, 8, 12, 7, 8, 5, 7, 0, 0, 0, 0, 0, 8, 13, 6, 0, 0, //3
10, 11, 7, 6, 0, 0, 0, 0, 6, 0, 0, 0, 0, 10, 15, 9, 6, 14, 15, 9, //4
6, 10, 15, 13, 0, 10, 9, 10, 5, 9, 10, 9, 0, 14, 5, 13, 6, 8, 5, 7, //5
6, 14, 12, 13, 2, 14, 5, 5, 5, 5, 5, 13, 0, 8, 5, 7, 6, 10, 5, 9, //6
6, 6, 0, 6, 6, 8, 7, 14, 5, 13, 8, 7, 0, 0, 14, 15, 13, 14, 5, 13, //7
6, 6, 0, 6, 6, 10, 9, 14, 5, 13, 10, 9, 0, 0, 8, 12, 13, 6, 6, 6, //8
6, 6, 0, 6, 6, 14, 5, 5, 5, 5, 5, 13, 0, 2, 10, 9, 8, 7, 6, 6, //9
6, 6, 0, 6, 6, 8, 7, 14, 5, 13, 8, 7, 0, 14, 5, 5, 11, 11, 7, 6, //10
6, 6, 0, 6, 6, 10, 9, 14, 5, 13, 10, 9, 0, 6, 8, 7, 10, 15, 9, 6, //11
6, 14, 15, 5, 13, 14, 5, 5, 5, 5, 5, 13, 0, 6, 10, 9, 6, 8, 7, 6, //12
6, 8, 12, 7, 1, 8, 7, 8, 5, 7, 8, 7, 0, 6, 8, 7, 5, 11, 9, 6, //13
8, 11, 15, 9, 0, 0, 4, 15, 5, 15, 3, 0, 0, 8, 9, 4, 13, 10, 13, 6, //14
10, 9, 14, 13, 0, 0, 0, 8, 5, 7, 0, 0, 0, 0, 14, 9, 6, 8, 7, 6, //15
8, 12, 12, 12, 11, 11, 11, 11, 12, 11, 11, 11, 15, 3, 14, 7, 8, 11, 11, 7, //16
0, 0, 0, 0, 0, 10, 9, 0, 0, 0, 0, 10, 5, 9, 8, 11, 11, 9, 0, 0, //17
0, 0, 0, 0, 0, 14, 5, 11, 15, 11, 11, 12, 5, 7, 0, 2, 0, 6, 0, 2, //18
0, 0, 0, 0, 0, 8, 7, 10, 5, 9, 10, 15, 13, 0, 0, 14, 11, 12, 11, 7, //19
0, 0, 0, 0, 0, 0, 0, 8, 12, 7, 8, 7, 1, 0, 0, 1, 0, 0, 0, 0 //20
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
};
// Floor Generator
public void SetLevelNodes(short[] aLevelBlueprint)
{
for (int x = 0; x < m_FloorCore.GridDimensionX; x++)
{
for (int y = 0; y < m_FloorCore.GridDimensionY; y++)
{
int LevelIndex = m_FloorCore.GetIndex(x, y);
//If there is no node then continue
if (aLevelBlueprint[LevelIndex] == (short) Floor.LevelCreationDirections.Empty)
{
continue;
}
SpawnNode(x , y,LevelIndex );
m_FloorNodes[LevelIndex].Initialize(aLevelBlueprint[LevelIndex]);
}
}
}
public void SpawnNode(int aRow, int aColumn,int aIndex)
{
FloorNode tempFloorNode = Instantiate(m_FloorNodePrefab);
m_FloorNodes[aIndex] = tempFloorNode;
m_FloorNodes[aIndex].m_PositionInGrid = new Vector2Int(aRow,aColumn);
m_FloorNodes[aIndex].gameObject.transform.parent = transform;
m_FloorNodes[aIndex].gameObject.name = aRow + " " + aColumn;
m_FloorNodes[aIndex].transform.position = new Vector3(4 * aRow, 0.5f, 4 * aColumn);
m_FloorNodes[aIndex].m_NodeFloorManager = this;
// m_GridPathArray[x, y].m_Grid = m_Grid;
}
//This function was shortened for the sake of it being an example
public void SetWalkableDirections(short aWalkabledirections)
{
switch (aWalkabledirections)
{
case CardinalNodeDirections::Up:
m_WalkableDirections.Add( CardinalNodeDirections::Up);
break;
case CardinalNodeDirections::Down:
m_WalkableDirections.Add( CardinalNodeDirections::Down);
break;
case CardinalNodeDirections::Left:
m_WalkableDirections.Add( CardinalNodeDirections::Left);
break;
case CardinalNodeDirections::Right:
m_WalkableDirections.Add( CardinalNodeDirections::Right);
break;
case CardinalNodeDirections::AllSidesOpen:
m_WalkableDirections.Add( CardinalNodeDirections::Up);
m_WalkableDirections.Add( CardinalNodeDirections::Down);
m_WalkableDirections.Add( CardinalNodeDirections::Right);
m_WalkableDirections.Add( CardinalNodeDirections::Left);
break;
}
SetLevelNode(m_WalkableDirections);
}
Each level is created with multiple Floors. Each floor is created using tools I have setup to make the entire system modular. Levels are generated in a grid and each number represents the amount of directions avaliable for the node. This is done to modularly set up the player so it knows what directions is it can go to.