I wanted to show yall the current logic for the rotation, by far the most complicated one yet.
Even if you don't understand code the logic should be in place.
Let me know if something is glaringly wrong =D
ps, || means logical OR , and && means logical AND.
Code://this checks to see if we have a GCD to consume
if(bs.isGCD())
{
//this gets the timings for the time since the last time we cast those attacks.
lastGL = currEvent.eventTime() - bs.getLastGL();
lastTwin = currEvent.eventTime() - bs.getLastTwin();
lastDK = currEvent.eventTime() - myTarget.getLastDK();
//basically sets the last time we did demo to a million years ago if we're lacking demo (for PB)
lastDemo = (myTarget.demo()?currEvent.eventTime() - myTarget.getLastDEMO().eventTime():-100000);
//this gets our current GCD (modified by GL stacks)
currGCD = bs.getGCD();
//this just does PB at the start of the fight
if(currEvent.eventTime()==0 && !bs.pbCD())
{
bs.addAction(MNKEvent.EventType.PB, myTarget);
continue;
}
//this tells us what we do inside a PB
if(bs.pb())
{
//setup GL and buffs, first priority during PB
if(bs.gl() < 3)
{
//only Demo during PB only after buffs if we're starting with pb
if(!myTarget.demo() && (currEvent.eventTime() > 1000 || bs.bfb() && bs.ir()))
bs.addAction(MNKEvent.EventType.DEMO, myTarget);
else //otherwise SP
bs.addAction(MNKEvent.EventType.SP, myTarget);
}
else
{
//once we have GL3, setup other buffs, prioritizing DK before OPO form runs out
if(bs.getLastStance() == MNKSimulator.Stance.OPO && !myTarget.dk())
bs.addAction(MNKEvent.EventType.DK, myTarget);
else if(!bs.twin())
bs.addAction(MNKEvent.EventType.TWIN, myTarget);
else //if we have all buffs, just SP for max damage.
{
bs.addAction(MNKEvent.EventType.SP, myTarget);
}
}
}
else
{
//do different timings based on stance
switch(bs.getLastStance())
{
//we only have NONE stance if we just came out of PB or we had to leave target
case NONE:
//basically if we don't have DK, Twin or GL3, or demo, immediately start GL combo
if(!myTarget.dk() || lastDemo >= 1800 - currGCD * 2 || lastGL >= 1200 - currGCD*3 || lastTwin >= 1200 - currGCD * 2 || bs.gl() < 3)
bs.addAction(MNKEvent.EventType.DK, myTarget);
else if(!myTarget.tod()) //otherwise, we have time to ToD
bs.addAction(MNKEvent.EventType.TOD, myTarget);
else if(!myTarget.fr()) //otherwise, we have time to FR
bs.addAction(MNKEvent.EventType.FR, myTarget);
else //otherwise ID filler
bs.addAction(MNKEvent.EventType.ID, myTarget);
break;
case RAPTOR:
if(lastTwin >= 1200 - currGCD*3) //if twin will fall off within next combo
bs.addAction(MNKEvent.EventType.TWIN, myTarget);
//this tests timings to see whether we have time to filler
else if(lastGL < 1200 - currGCD*2 && lastDemo < 1800 - currGCD && lastTwin < 1200 - currGCD && lastDK < 1500 - currGCD*3)
{
//filler priority is ToD > FR > ID
if(!myTarget.tod())
bs.addAction(MNKEvent.EventType.TOD, myTarget);
else if(!myTarget.fr())
bs.addAction(MNKEvent.EventType.FR, myTarget);
else
bs.addAction(MNKEvent.EventType.ID, myTarget);
}
else
bs.addAction(MNKEvent.EventType.TRUE, myTarget);
break;
case COEURL:
//more timings, demo if it will expire in less than 3 seconds (arbitrary number here)
if(!myTarget.demo() || (lastDemo > 1500 && currEvent.numBuffs() > myTarget.getLastDEMO().numBuffs()))
bs.addAction(MNKEvent.EventType.DEMO, myTarget);
//otherwise SP if DK, GL, or Twin will fall off
else if(lastGL >= 1200 - currGCD || lastDK >= 1500 - currGCD*2 || lastTwin >= 1200 - currGCD*3)
bs.addAction(MNKEvent.EventType.SP, myTarget);
else
{
//otherwise filler
if(!myTarget.tod())
bs.addAction(MNKEvent.EventType.TOD, myTarget);
else if(!myTarget.fr())
bs.addAction(MNKEvent.EventType.FR, myTarget);
else
bs.addAction(MNKEvent.EventType.ID, myTarget);
}
break;
case OPO:
//dk if dk is going to fall off
if(!myTarget.dk() || lastDK > 1500 - currGCD*3)
bs.addAction(MNKEvent.EventType.DK, myTarget);
//if nothing's going to fall off we can filler
else if(lastGL < 1200 - currGCD*3 && lastDemo < 1800 - currGCD * 2 && lastTwin < 1200 - currGCD*2 && lastDK < 1500 - currGCD)
{
if(!myTarget.tod())
bs.addAction(MNKEvent.EventType.TOD, myTarget);
else if(!myTarget.fr())
bs.addAction(MNKEvent.EventType.FR, myTarget);
else
bs.addAction(MNKEvent.EventType.ID, myTarget);
}
//if somehow we get here (usually because i've disabled ID filler, we can BS if DK won't fall off
else if(myTarget.dk() && lastDK < 1500 - currGCD*3 && myTarget.canBackstab())
bs.addAction(MNKEvent.EventType.BS, myTarget);
else
//if we run out of stuff to do might as well DK to continue rotation
bs.addAction(MNKEvent.EventType.DK, myTarget);
break;
}
}
}
//this checks to see if there is an oGCD slot for an action
else if(bs.isOGCD())
{
//do all OGCD actions here
//PB if its up, and we are either missing GL stacks or the stance isn't COEURL (so we don't waste a coeurl)
if(!bs.pbCD() && (bs.gl() < 3 || bs.getLastStance() != MNKSimulator.Stance.COEURL))
{
bs.addAction(MNKEvent.EventType.PB, myTarget);
}
//do BfB > IR > HF > Peak > invig cooldowns, too lazy (and not much point) in saving to stack.
else if(!bs.bfbCD())
bs.addAction(MNKEvent.EventType.BFB, myTarget);
else if(!bs.irCD() && (!myTarget.demo() || lastDemo > 1200))
bs.addAction(MNKEvent.EventType.IR, myTarget);
else if(!bs.hfCD())
bs.addAction(MNKEvent.EventType.HF, myTarget);
else if(!bs.peakCD())
bs.addAction(MNKEvent.EventType.PEAK, myTarget);
else if(bs.getTPBalance() < 540)
bs.addAction(MNKEvent.EventType.INVIG, myTarget);
}
