using System; using System.Collections.Generic; using System.Linq; using RimWorld; using rjw; using UnityEngine; using Verse; using Verse.AI; using Verse.Sound; namespace Rimworld_Animations { public class CompExtendedAnimator : ThingComp { // CompExtendedAnimator // Helps manage AnimationQueue, AbsolutePosition //ticks of current animation private int animationTicks; private List animationQueue; private BaseExtendedAnimatorAnchor anchor; private Vector3? offset; private bool isAnimating = false; public bool IsAnimating { get { return isAnimating; } } public bool IsAnchored { get { return anchor != null; } } public Vector3? Offset { get { return offset; } set { this.offset = value; } } public Vector3 getAnchor() { return anchor.getDrawPos(); } public override void CompTick() { if (isAnimating) { animationTicks++; //if animationticks is equal to cur. anim duration, if (animationTicks >= animationQueue[0].durationTicks) { //dequeue; returns false if more animations if (!PopAnimationQueue()) { //play next if more anims still PlayNextAnimation(); } else { StopAnimating(); } } } base.CompTick(); } //returns false if still more animations public bool PopAnimationQueue() { if (!animationQueue.Empty()) { //pop queue animationQueue.RemoveAt(0); } return animationQueue.Empty(); } public void PlayNextAnimation() { if (!animationQueue.Empty()) { isAnimating = true; animationTicks = 0; pawn.Drawer.renderer.SetAnimation(animationQueue[0]); } } public void StopAnimating() { isAnimating = false; animationQueue = null; anchor = null; offset = null; pawn.Drawer.renderer.SetAnimation(null); } public void PlayGroupAnimation(List groupAnimation, Vector3? offset) { this.Offset = offset; animationQueue = groupAnimation; PlayNextAnimation(); } public void PlayGroupAnimation(List groupAnimation, Vector3? offset, BaseExtendedAnimatorAnchor anchor) { this.anchor = anchor; PlayGroupAnimation(groupAnimation, offset); } public override void PostExposeData() { base.PostExposeData(); Scribe_Values.Look(ref this.isAnimating, "animations_isAnimating", false); Scribe_Values.Look(ref this.animationTicks, "animations_ticks", 0); Scribe_Collections.Look(ref animationQueue, "animations_queue"); Scribe_Deep.Look(ref this.anchor, "animations_anchor"); } public override List CompRenderNodes() { //only if pawn is animating for performance if (IsAnimating) { List animRenderNodes = new List(); // for all animationpropdefs, foreach (AnimationPropDef animationProp in DefDatabase.AllDefsListForReading) { //if animation makes use of prop, if (AnimationMakesUseOfProp(animationProp)) { PawnRenderNodeProperties props = animationProp.animPropProperties; if (props.texPath.NullOrEmpty()) { props.texPath = "AnimationProps/Banana/Banana"; } //create new render node PawnRenderNode animRenderNode = (PawnRenderNode)Activator.CreateInstance(props.nodeClass, new object[] { this.pawn, props, pawn.Drawer.renderer.renderTree }); animRenderNodes.Add(animRenderNode); } } //return list of rendernodes that should animate return animRenderNodes; } else { return null; } } public bool AnimationMakesUseOfProp(AnimationPropDef animationProp) { // never true if not animating; anim props shouldn't be attached if (!IsAnimating) return false; //for ONLY THE CURRENT animation, foreach (PawnRenderNodeTagDef propTag in animationQueue[0].animationParts.Keys) { // if that proptag is the same as the one for animationProp, if (propTag == animationProp.animPropProperties.tagDef) { //that prop is being used in the animation return true; } } return false; } private Pawn pawn => base.parent as Pawn; } }