rimworld-animations/1.6/Source/Animations/GroupAnimations/GroupAnimationContexts/GroupAnimationContext.cs

188 lines
5.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace Rimworld_Animations
{
public class GroupAnimationContext
{
public int priority = 0;
public List<BasePawnTest> whitelist;
public List<BasePawnTest> blacklist;
/*
public virtual bool CanAnimationBeUsed(List<Pawn> actors)
{
if (!whitelist.NullOrEmpty())
{
for (int i = 0; i < whitelist.Count; i++)
{
// check whitelist to make sure pawn can be in this act
//for each whitelist item, pawntest must hold true for that pawn
if (!whitelist[i].PawnTest(actors[i]))
{
return false;
}
}
}
if (!blacklist.NullOrEmpty())
{
for (int i = 0; i < blacklist.Count; i++)
{
// check blacklist to make sure pawn can be in this act
// for each blacklist item, pawntest must hold false for that pawn
if (blacklist[i].PawnTest(actors[i]))
{
return false;
}
}
}
return true;
}
*/
/*
public List<Pawn> FindWorkingPermutation(List<Pawn> pawns, int index = 0)
{
//can't play anim for empty list of pawns
if (pawns.Count == 0) return null;
//pawns list doesn't match number in whitelist
if (index == 0 && pawns.Count != whitelist.Count) return null;
//if list only has one pawn and it works for that index, return it
if (pawns.Count == 1)
{
return CanAnimationBeUsedFor(pawns[0], index) ? pawns : null;
}
for (int i = 0; i < pawns.Count; i++)
{
if (CanAnimationBeUsedFor(pawns[i], index))
{
//remove the pawn that we know works for that context
List<Pawn> smallerSubset = pawns.Where((item, idx) => idx != i).ToList();
//try to find a working subset for the next indices
List<Pawn> newWorkingSubset = FindWorkingPermutation(smallerSubset, index + 1);
if (newWorkingSubset != null)
{
newWorkingSubset.Insert(0, pawns[i]);
return newWorkingSubset;
}
}
}
return null;
}
*/
public List<Pawn> FindAnyWorkingSet(List<Pawn> actors)
{
if (actors.Count != whitelist.Count) return null;
int numActors = actors.Count;
Dictionary<int, List<int>> validPawnContexts = new Dictionary<int, List<int>>();
for (int i = 0; i < numActors; i++)
{
validPawnContexts[i] = new List<int>();
for (int j = 0; j < numActors; j++)
{
if (CanAnimationBeUsedFor(actors[i], j))
{
//give a list of all pawn's valid potential spots
validPawnContexts[i].Add(j);
}
}
}
//set all spots as empty (-1)
int[] indexAssignedToPawn = Enumerable.Repeat(-1, numActors).ToArray();
for (int i = 0; i < numActors; i++)
{
bool[] visited = new bool[numActors];
//try to fill in each space
//try to shove spaces out of the way, get them to look elsewhere
if (!DfsMatch(i, visited, indexAssignedToPawn, validPawnContexts))
{
return null;
}
}
List<Pawn> actorOrder = new List<Pawn>();
foreach (int actorIndex in indexAssignedToPawn)
{
actorOrder.Add(actors[actorIndex]);
}
return actorOrder;
}
public bool DfsMatch(int pawnIndex, bool[] visited, int[] indexAssignedToPawn, Dictionary<int, List<int>> validPawnContexts)
{
foreach (int index in validPawnContexts[pawnIndex])
{
//don't infinte loop
if (visited[index]) continue;
visited[index] = true;
//fill in space or shove something else out of the way
if (indexAssignedToPawn[index] == -1 || DfsMatch(indexAssignedToPawn[index], visited, indexAssignedToPawn, validPawnContexts))
{
indexAssignedToPawn[index] = pawnIndex;
return true;
}
}
return false;
}
public virtual bool CanAnimationBeUsedFor(Pawn actor, int index)
{
if (whitelist.NullOrEmpty()) return false;
if (index < 0 || index >= whitelist.Count)
{
return false;
}
if (!whitelist[index].PawnTest(actor))
{
return false;
}
if (!blacklist.NullOrEmpty() && blacklist[index].PawnTest(actor))
{
return false;
}
return true;
}
public virtual int AnimationPriority()
{
return priority;
}
//cool class for designating contexts for animations
// configure CanAnimationBeUsed to test whether it can be used
}
}