Introduction
Firstly, in order to install this library execute the following function in your command prompt:
pip install ffxivcalc
In this first page, it will be explained to you how to simulate your first fight using the ffxivcalc library.
Fight Class
The Fight class is one of the most important in the whole library. An instance of Fight represents the simulator and contains all the logic responsible for the execution of the simulation. It contains information such as :
A list of player character present in the simulation
A reference to the Enemy of the simulation, aka the boss of a raid
Time stamp of the simulation
Time limit of the simulation
A list of all failedEvents
etc.
In short, an instance Fight is like a conductor in an orchestra and directs the whole flow of the simulation and makes sure everything goes correctly.
When you want to simulate a fight, you have to first create an instance of Fight. Here is an example of how to do so:
from ffxivcalc.Fight import Fight
from ffxivcalc.Enemy import Enemy
newEnemy = Enemy() # Creating new Enemy instance
ShowGraph = True # We want the simulator to generate graphs
newFight = Fight(newEnemy, ShowGraph) # Creating new Fight instance
newFight.RequirementOn = True # Does NOT ignore requirement during simulation
newFight.IgnoreMana = False # Does NOT ignore Mana requirement during simulation
As you can see in the above example, we are also creating an instance of the class Enemy. For now you don’t need to think much about this class. However, just like any raid needs a boss, a simulation needs an enemy. Furthermore, we also give the constructor of Fight a paramter ShowGraph which is simply a boolean value which if set true tells the simulator to generate graphs at the end.
A Fight instance also contains other parameters for the simulation such as :
RequirementOn -> If set to false the simulator ignores the requirements of an action.
IgnoreMana -> If set to true, the simulator ignore the mana requirements of an action.
These can be changed according to your needs.
Note
Both RequirementOn and IgnoreMana have a default value of true.
Now that our Fight instance is created, we need to add some players to it.
Player class
The player class represents any player character in the simulation. It contains information such as :
The list of actions we want the player to do in the simulation.
A list of all effect on the player at any time.
Current state of the player (If the player is casting, if it can cast a GCD, etc.)
Current HP and mana of the player
The Role and Job of a player
etc.
In order to add a player to the Fight instance we need to create a Player instance and add it to the fight.
from ffxivcalc.Jobs.Player import Player # Importing player class
from ffxivcalc.Jobs.PlayerEnum import JobEnum # Importing JobEnum
ActionSet = [] # List containing actions to be performed. Can be left empty
EffectList = [] # List of all effect on the player at start. Can be left empty
Stat = {"MainStat": 2945, "WD":126, "Det" : 1451, "Ten" : 400, "SS": 840, "SkS" : 400, "Crit" : 2386, "DH" : 1307} # Stats for BlackMage
newBlackMage = Player(ActionSet, EffectList, Stat, JobEnum.BlackMage) # Creating player instance
When creating a Player instance we need to give the constructor 4 inputs:
ActionSet -> List of all actions performed by the player.
EffectList -> List of all effects on the player at start, can be left empty.
Stat -> Dictionnary containing the stats of the player. Follow the same structure as in the above example.
JobEnum -> An enum indicating what Job the player is.
Note
JobEnum is an enum implemented to distinguate between Jobs. You don’t have to be bothered by the exact implementation, but you can read more about it HERE.
Note
The EffectList given when creating the Player instance will generally be left empty. You can read HERE how to and why to not have it empty.
The Player instance we just created has no actions to do. In order to do so we have to fill up the ActionSet with Spell objects.
Spell class
The Spell class represents an action a player can do. In the case of a BlackMage, actions would be Fire I, Fire IV, Xenoglossy, etc. Furthermore, there are 3 different types of actions or spell any player can do.
Base Spell
Actions that can be done by any players. The two mainly used Base_Spell actions are :
potion : This action makes the player take a potion. Boosting its MainStat just like in the game.
WaitAbility(waitingTime : float) : This action makes the player wait for the specified amount of time.
Role Spell
Actions that can be done by players of the same Role. The different roles are Casters, PhysicalRanged, Melee, Healer, Tank. Examples of Role actions are Swiftcast, ArmLength, Esuna, Peloton, Rampart, etc.
Job_Spell
Actions that can be done by players of a specific Job. Job’s could be BlackMage, Machinist, Ninja, Scholar, Gunbreaker, etc.
Here is how you would create an ActionSet for the player :
from ffxivcalc.Jobs.Caster.Blackmage.BlackMage_Spell import * # Importing the Blackmage Actions
from ffxivcalc.Jobs.Caster.Caster_Spell import * # Importing the roles action for Caster
from ffxivcalc.Jobs.Base_Spell import Potion, WaitAbility # Importing the Base actions
newBlackMage.ActionSet = [SharpCast, WaitAbility(20),Fire3, Thunder3, Fire4, Triplecast, Fire4, Potion,
Fire4, Amplifier, LeyLines, Fire4, SharpCast, Swiftcast, Despair, Manafront, Triplecast, Fire4, Despair]
Note
The default path to import any Role actions is ffxivcalc.Jobs.__ROLE__.__ROLE___Spell and the default path to import any Job specific actions is ffxivcalc.Jobs.__Role__.__Job__.__Job___Spell.
As you can see, this action set is asking the player to perform an incomplete BlackMage opener. You can see we are using the Base action WaitAbility() and Potion, the Role action Swiftcast and the Job action such as Fire IV.
Now that the Player object has an ActionSet, we simply need to add the player to the Fight instance.
newFight.AddPlayer([newBlackMage]) # Adding newBlackMage to newFight. Input must be a list and can contain
# more than one Player object.
Warning
When using the AddPlayer function on a Fight object, it is needed to give a list as input. The list can have multiple players object and it will add all player objects in the list given as input to the function.
Now that we have a Fight instance with a Player instance that has a non-empty ActionSet we can finally do our first simulation.
Fight.SimulateFight()
In order to do so, we simply need to call the class function SimulateFight() on our Fight instance.
TimeUnit = 0.01 # Unit of time per frame
TimeLimit = 500 # Max running time of the simulation (time IN the simulation)
# Simulation parameters
newFight.RequirementOn = True # Will check for actions requirement
newFight.IgnoreMana = False # Will check for mana
vocal = True # Want to output data in text
newFight.SimulateFight(TimeUnit, TimeLimit, vocal) # Simulating the fight
The SimulateFight() class function requires 3 inputs:
TimeUnit -> Smallest time unit in seconds in the simulation. The simulator will advance by that much every main loop.
TimeLimit -> Maximum time the simulation will run for in seconds.
vocal -> Boolean value. If true the simulator will show the data in graphs and/or text.
Warning
The recommended value for TimeUnit is 0.01 . Different values of this parameter could result in different number output from the simulator.
Warning
The value given in TimeLimit corresponds to the IN SIMULATION time, and not to the actual time. Meaning that if TimeLimit = 500, the simulation will stop if its time stamp ever reaches 500 and not if there has been 500 in real life seconds that have gone by.
After running all of the above code, you should see this text and have at least this graph show up.
The Fight finishes at: 16.23
The Total Potency done by player BlackMage was : 4499.0
This same player had a Potency Per Second of: 277.2
This same Player had an average of 236.79 Potency/Spell
This same player did 9 GCD.
The DPS is : 14100.31
=======================================================
The Enemy has received a total potency of: 4499.0
The Potency Per Second on the Enemy is: 277.2
The Enemy's total DPS is 14100.31

You have now ran your first simulation using ffxivcalc! This is all the basis you need to know in order to simulate fights. The rest of this tutorial will be some more code examples, after which more complex customization will be discussed.
More code examples
Simulating a BlackMage but with RequirementsOn = False
Say one wants to simulate an action set that is not possible in the base game. Say this is the action sets one wishes to perform on a BlackMage:
newBlackMage.ActionSet = [Fire3, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy]
Obviously such a set of action is not possible in the game. But here we can dream and see the result. The only thing we need to do is to let RequirementOn be false.
from ffxivcalc.Fight import Fight
from ffxivcalc.Enemy import Enemy
newEnemy = Enemy()
ShowGraph = False # We don't want the simulator to generate graphs
newFight = Fight(newEnemy, ShowGraph) # Creating new Fight instance
from ffxivcalc.Jobs.Player import Player # Importing player class
from ffxivcalc.Jobs.PlayerEnum import JobEnum # Importing JobEnum
ActionSet = [] # List containing actions to be performed. Can be left empty
EffectList = [] # List of all effect on the player at start. Can be left empty
Stat = {"MainStat": 2945, "WD":126, "Det" : 1451, "Ten" : 400, "SS": 840, "Crit" : 2386, "DH" : 1307} # Stats for BlackMage
newBlackMage = Player(ActionSet, EffectList, Stat, JobEnum.BlackMage)
from ffxivcalc.Jobs.Caster.Blackmage.BlackMage_Spell import *
from ffxivcalc.Jobs.Caster.Caster_Spell import *
from ffxivcalc.Jobs.Base_Spell import Potion, WaitAbility
newBlackMage.ActionSet = [Fire3, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy, Xenoglossy]
newFight.AddPlayer([newBlackMage])
TimeUnit = 0.01 # Unit of time per frame
TimeLimit = 500 # Max running time of the simulation (time IN the simulation)
# Simulation parameters
newFight.RequirementOn = False # Will check for actions requirement
newFight.IgnoreMana = False # Will check for mana
vocal = True # Want to output data in text
newFight.SimulateFight(TimeUnit, TimeLimit, vocal) # Simulating the fight
Output :
The Fight finishes at: 16.94
========================
Results for BlackMage ID - 1 :
DPS : 20820.84 PPS : 430.93 TP : 7300 GCD : 9 TD : 352705
=================
Total DPS : 20820.84 Total PPS : 430.93 Total Potency : 7300
If instead we had not changed RequirementOn to False, the simulator would have outputed this:
The simulation ran into a problem. You can disable requirements by setting 'Fight.RequirementOn' to 'False'.
=================
List of failed fatal requirements :
Failed Fatal Requirement : PolyglotRequirement Timestamp : 0
The Fight finishes at: 0
========================
Results for BlackMage ID - 1 :
DPS : 54316.0 PPS : 1140.0 TP : 1140 GCD : 2 TD : 54316
=================
Total DPS : 54316.0 Total PPS : 1140.0 Total Potency : 1140
As you can see the fight finishes early and it tells the user the name of the first fatal failed requirement. In this case it is PolyglotRequirement.
Warning
Any value outputted by the simulation when a requirement failed might be wrong because of how the simulator handles some values. Because of that do not take a failed simulation’s number to be accurate. Instead just put RequirementOn to be false and then run the simulation.
The same kind of things can be done by letting IgnoreMana = True.
Simulate a Dancer and Ninja opener with the Ninja being the Dancer’s dance partner.
One thing to make sure you understand here is that some actions are functions that return Spell object. Such examples would be the ClosedPosition(target) actions of Dancer that makes the target its dance partner. Similar actions include DragonSight of a dragoon and an astrologian giving cards.
Code simulating a dancer and a ninja doing their opener :
from ffxivcalc.Fight import Fight
from ffxivcalc.Enemy import Enemy
newEnemy = Enemy()
ShowGraph = True
newFight = Fight(newEnemy, ShowGraph) # Creating new Fight instance
from ffxivcalc.Jobs.Player import Player # Importing player class
from ffxivcalc.Jobs.PlayerEnum import JobEnum # Importing JobEnum
NINStat = {"MainStat": 2921, "WD":126, "Det" : 1669, "Ten" : 400, "SS": 400, "SkS" : 400, "Crit" : 2399, "DH" : 1511} # Stats for Ninja
DNCStat = {"MainStat": 2949, "WD":126, "Det" : 1721, "Ten" : 400, "SS": 400, "SkS" : 536, "Crit" : 2387, "DH" : 1340} # Stats for Dancer
NinjaPlayer = Player([], [], NINStat, JobEnum.Ninja) # Creating Ninja player
DancerPlayer = Player([], [], DNCStat, JobEnum.Dancer) # Creating Dancer player
from ffxivcalc.Jobs.Melee.Ninja.Ninja_Spell import * # Importing ninja actions
from ffxivcalc.Jobs.Melee.Melee_Spell import * # Importing melee actions
from ffxivcalc.Jobs.Ranged.Dancer.Dancer_Spell import * # Importing dancer actions
from ffxivcalc.Jobs.Ranged.Ranged_Spell import * # Importing Ranged actions
from ffxivcalc.Jobs.Base_Spell import Potion, WaitAbility
NinjaPlayer.ActionSet = [WaitAbility(10),Jin, Chi, Ten, Huton, Hide, Ten, Chi, Jin, WaitAbility(5),
Suiton, Kassatsu, SpinningEdge, GustSlash, Mug, Bunshin, PhantomKamaitachi,
TrickAttack, AeolianEdge, DreamWithinADream, Ten, Jin, HyoshoRanryu, Ten, Chi,
Raiton, TenChiJin, Ten2, Chi2, Jin2, Meisui, FleetingRaiju, Bhavacakra,
FleetingRaiju, Bhavacakra, Ten, Chi, Raiton, FleetingRaiju ]
# Ninja action set
DancerPlayer.ActionSet = [ClosedPosition(NinjaPlayer),StandardStep, Pirouette, Jete, WaitAbility(15), StandardFinish, TechnicalStep,
Pirouette, Jete, Entrechat, Emboite, TechnicalFinish, Devilment, StarfallDance, Flourish,
FanDance3, Tillana, FanDance4, FountainFall, FanDance1, FanDance3, StandardStep, Jete, Pirouette, StandardFinish]
# Dancer action set
newFight.AddPlayer([DancerPlayer, NinjaPlayer]) # Adding players to the fight
TimeUnit = 0.01 # Unit of time per frame
TimeLimit = 500 # Max running time of the simulation (time IN the simulation)
# Simulation parameters
newFight.RequirementOn = True # Will check for actions requirement
newFight.IgnoreMana = False # Will check for mana
vocal = True # Want to output data in text
newFight.SimulateFight(TimeUnit, TimeLimit, vocal) # Simulating the fight
Note
As you can see, when using the action ClosedPosition in the dancer’s action set, I am giving as input NinjaPlayer to let the action know that the dancer is targetting the ninja when casting closed position.
It outputs this :
The Fight finishes at: 26.71
========================
Results for Dancer ID - 1 :
DPS : 11120.33 PPS : 209.66 TP : 5600 GCD : 17 TD : 297024
Procs/Gauge result (Used/Expected) :
Silken Symettry : 0/0 Silken Flow : 0/0
Fourfold Feather : 1/0.5 Threefold Fan : 2/1.5
=================
Results for Ninja ID - 2 :
DPS : 19494.05 PPS : 433.92 TP : 11590 GCD : 28 TD : 520686
=================
Total DPS : 30614.38 Total PPS : 643.58 Total Potency : 17190

Note
For Jobs where procs are an important part of it the simulator will also output data regarding the number of used procs and number of expected procs.
Warning
The simulation starts as soon as 1 player does damage and stops either if it detects a fatal failed requirement or if all players are done with their action set. Because of that, you have to make sure every job starts doing damage at the same time.
Simulating two Ninjas doing the exact same opener
from ffxivcalc.Fight import Fight
from ffxivcalc.Enemy import Enemy
newEnemy = Enemy()
ShowGraph = False
newFight = Fight(newEnemy, ShowGraph) # Creating new Fight instance
from ffxivcalc.Jobs.Player import Player # Importing player class
from ffxivcalc.Jobs.PlayerEnum import JobEnum # Importing JobEnum
NINStat = {"MainStat": 2921, "WD":126, "Det" : 1669, "Ten" : 400, "SS": 400, "SkS": 536, "Crit" : 2399, "DH" : 1511} # Stats for Ninja
DNCStat = {"MainStat": 2949, "WD":126, "Det" : 1721, "Ten" : 400, "SkS": 536, "SS": 400, "Crit" : 2387, "DH" : 1340} # Stats for Dancer
NinjaPlayer1 = Player([], [], NINStat, JobEnum.Ninja) # Creating Ninja player
NinjaPlayer2 = Player([], [], NINStat, JobEnum.Ninja) # Creating Ninja player
#DancerPlayer = Player([], [], DNCStat, JobEnum.Dancer) # Creating Dancer player
from ffxivcalc.Jobs.Melee.Ninja.Ninja_Spell import * # Importing ninja actions
from ffxivcalc.Jobs.Melee.Melee_Spell import * # Importing melee actions
from ffxivcalc.Jobs.Base_Spell import Potion, WaitAbility
NinjaPlayer1.ActionSet = [Jin, Chi, Ten, Huton, Hide, Ten, Chi, Jin, WaitAbility(5),
Suiton, Kassatsu, SpinningEdge, GustSlash, Mug, Bunshin, PhantomKamaitachi,
TrickAttack, AeolianEdge, DreamWithinADream, Ten, Jin, HyoshoRanryu, Ten, Chi,
Raiton, TenChiJin, Ten2, Chi2, Jin2, Meisui, FleetingRaiju, Bhavacakra,
FleetingRaiju, Bhavacakra, Ten, Chi, Raiton, FleetingRaiju ]
NinjaPlayer2.ActionSet = [Jin, Chi, Ten, Huton,Hide, Ten, Chi, Jin, WaitAbility(5),
Suiton, Kassatsu, SpinningEdge, GustSlash, Mug, Bunshin, PhantomKamaitachi,
TrickAttack, AeolianEdge, DreamWithinADream, Ten, Jin, HyoshoRanryu, Ten, Chi,
Raiton, TenChiJin, Ten2, Chi2, Jin2, Meisui, FleetingRaiju, Bhavacakra,
FleetingRaiju, Bhavacakra, Ten, Chi, Raiton, FleetingRaiju ]
newFight.AddPlayer([NinjaPlayer1,NinjaPlayer2]) # Adding players to the fight
TimeUnit = 0.01 # Unit of time per frame
TimeLimit = 500 # Max running time of the simulation (time IN the simulation)
# Simulation parameters
newFight.RequirementOn = True # Will check for actions requirement
newFight.IgnoreMana = False # Will check for mana
vocal = True # Want to output data in text
newFight.SimulateFight(TimeUnit, TimeLimit, vocal) # Simulating the fight
Note
Giving the same Stat dictionnary to two different player is all right since the code makes a deepcopy of the dictionnary when creating the player object.
It ouputs :
The Fight finishes at: 25.09
========================
Results for Ninja ID - 1 :
DPS : 17381.19 PPS : 458.35 TP : 11500 GCD : 28 TD : 436094
=================
Results for Ninja ID - 2 :
DPS : 17391.07 PPS : 458.35 TP : 11500 GCD : 28 TD : 436342
=================
Total DPS : 34772.26 Total PPS : 916.7 Total Potency : 23000
As you can see, both ninjas do not have the exact same DPS. The reason for that lies within how the simulator works. In fact, the simulator process each player in order. Meaning that the DPS gain for the second ninja is because the first ninja casts and applies mug before the 2nd one does. Giving the second ninja a slight DPS bonus over the first one since the second mug’s damage is slightly buffed by the first one. This is an edge case that will always be present since it would be quite hard to fix.
You can in fact see that they both have the same total potency, but that only their DPS differs.
Simulating a standard 8 man raid doing their opener
Now let us try the big advantage of this simulator : to simulate a whole raid group. The team composition will be DRK - GNB - RDM - NIN - DRG - DNC - SCH - WHM and they will all be doing their respective opener.
Here is the code :
from ffxivcalc.Fight import Fight
from ffxivcalc.Enemy import Enemy
newEnemy = Enemy()
ShowGraph = True
newFight = Fight(newEnemy, ShowGraph) # Creating new Fight instance
from ffxivcalc.Jobs.Player import Player # Importing player class
from ffxivcalc.Jobs.PlayerEnum import JobEnum # Importing JobEnum
# Caster
RDMStat = {"MainStat": 2947, "WD":126, "Det" : 1548, "Ten" : 400, "SS": 495,"SkS" : 400, "Crit" : 2397, "DH" : 1544} # Stats for RedMage
# Healer
SCHStat = {"MainStat": 2931, "WD":126, "Det" : 1750, "Ten" : 400, "SS": 1473, "SkS" : 400, "Crit" : 2351, "DH" : 436} # Stats for Scholar
WHMStat = {"MainStat": 2945, "WD":126, "Det" : 1792, "Ten" : 400, "SS": 839, "SkS" : 400, "Crit" : 2313, "DH" : 904} # Stats for WhiteMage
# Physical Ranged
DNCStat = {"MainStat": 2949, "WD":126, "Det" : 1721, "Ten" : 400, "SkS": 536, "SS" : 400,"Crit" : 2387, "DH" : 1340} # Stats for Dancer
# Melee
NINStat = {"MainStat": 2921, "WD":126, "Det" : 1669, "Ten" : 400, "SS": 400,"SkS" : 400, "Crit" : 2399, "DH" : 1511} # Stats for Ninja
DRGStat = {"MainStat": 2949, "WD":126, "Det" : 1545, "Ten" : 400, "SS": 400,"SkS" : 400, "Crit" : 2462, "DH" : 1577} # Stats for Dragoon
# Tank
DRKStat = {"MainStat": 2910, "WD":126, "Det" : 1844, "Ten" : 751, "SS": 400,"SkS" : 400, "Crit" : 2377, "DH" : 1012} # Stats for DarkKnight
GNBStat = {"MainStat": 2891, "WD":126, "Det" : 1883, "Ten" : 631, "SkS": 650,"SS" : 400, "Crit" : 2352, "DH" : 868} # Stats for Gunbreaker
# Caster player object
RDMPlayer = Player([], [], RDMStat, JobEnum.RedMage)
# Healer player object
SCHPlayer = Player([], [], SCHStat, JobEnum.Scholar)
WHMPlayer = Player([], [], WHMStat, JobEnum.WhiteMage)
# Physical Ranged
DNCPlayer = Player([], [], DNCStat, JobEnum.Dancer)
# Melee
NINPlayer = Player([], [], NINStat, JobEnum.Ninja)
DRGPlayer = Player([], [], DRGStat, JobEnum.Dragoon)
# Tank
DRKPlayer = Player([], [], DRKStat, JobEnum.DarkKnight)
GNBPlayer = Player([], [], GNBStat, JobEnum.Gunbreaker)
from ffxivcalc.Jobs.Melee.Ninja.Ninja_Spell import * # Importing ninja actions
from ffxivcalc.Jobs.Melee.Dragoon.Dragoon_Spell import * # Importing dragoon actions
from ffxivcalc.Jobs.Melee.Melee_Spell import * # Importing melee actions
from ffxivcalc.Jobs.Ranged.Dancer.Dancer_Spell import * # Importing dancer actions
from ffxivcalc.Jobs.Ranged.Ranged_Spell import * # Importing physical ranged actions
from ffxivcalc.Jobs.Caster.Redmage.Redmage_Spell import * # Importing redmage actions
from ffxivcalc.Jobs.Caster.Caster_Spell import * # Importing caster actions
from ffxivcalc.Jobs.Healer.Scholar.Scholar_Spell import * # Importing scholar actions
from ffxivcalc.Jobs.Healer.Whitemage.Whitemage_Spell import * # Importing whitemage actions
from ffxivcalc.Jobs.Healer.Healer_Spell import * # Importing healer actions
from ffxivcalc.Jobs.Tank.DarkKnight.DarkKnight_Spell import * # Importing darkknight actions
from ffxivcalc.Jobs.Tank.Gunbreaker.Gunbreaker_Spell import * # Importing gunbreaker actions
from ffxivcalc.Jobs.Tank.Tank_Spell import * # Importing tank actions
from ffxivcalc.Jobs.Base_Spell import Potion, WaitAbility
# Caster
RDMPlayer.ActionSet = [WaitAbility(15), Verthunder, Verareo, Swiftcast,Acceleration, Verthunder, Verthunder, Embolden, Manafication, EnchantedRiposte, Fleche, EnchantedZwerchhau, Contre, EnchantedRedoublement, Corps, Engagement, Verholy, Corps, Engagement, Scorch, Resolution, Verfire, Verthunder, Verstone, Verareo, Jolt, Verthunder, Fleche]
# Healer
SCHPlayer.ActionSet = [WaitAbility(18.5),Broil, Biolysis, Aetherflow, Broil, Swiftcast, Broil, ChainStratagem, EnergyDrain, Broil, EnergyDrain, Broil, EnergyDrain, Broil, Dissipation, Broil, EnergyDrain, Broil, EnergyDrain, Broil, EnergyDrain]
WHMPlayer.ActionSet = [WaitAbility(18.5),Glare, Dia, Glare, Glare, PresenceOfMind, Glare, Assize, Glare, Glare, Glare, Glare, Glare, Glare, Glare, Glare, Glare, Glare, Glare]
# Physical Ranged
DNCPlayer.ActionSet = [ClosedPosition(NINPlayer),StandardStep, Pirouette, Jete, WaitAbility(15), StandardFinish, TechnicalStep, Pirouette, Jete, Entrechat, Emboite, TechnicalFinish, Devilment, StarfallDance, Flourish, FanDance3, Tillana, FanDance4, FountainFall, FanDance1, FanDance3, StandardStep, Jete, Pirouette, StandardFinish]
# Melee
DRGPlayer.ActionSet = [WaitAbility(20),TrueThrust, Disembowel, LanceCharge, DragonSight(NINPlayer), ChaoticSpring, BattleLitany, WheelingThrust, Geirskogul, LifeSurge, FangAndClaw, HighJump, RaidenThrust, DragonFireDive, VorpalThrust, LifeSurge, MirageDive, HeavenThrust, SpineshafterDive, FangAndClaw, SpineshafterDive, WheelingThrust, RaidenThrust, WyrmwindThrust, Disembowel, ChaoticSpring, WheelingThrust]
NINPlayer.ActionSet = [WaitAbility(10), Jin, Chi, Ten, Huton, Hide, Ten, Chi, Jin, WaitAbility(5), Suiton, Kassatsu, SpinningEdge, GustSlash, Mug, Bunshin, PhantomKamaitachi, TrickAttack, AeolianEdge, DreamWithinADream, Ten, Jin, HyoshoRanryu, Ten, Chi, Raiton, TenChiJin, Ten2, Chi2, Jin2, Meisui, FleetingRaiju, Bhavacakra, FleetingRaiju, Bhavacakra, Ten, Chi, Raiton, FleetingRaiju ]
# Tank
DRKPlayer.ActionSet = [WaitAbility(16), BloodWeapon, WaitAbility(4), HardSlash, EdgeShadow, Delirium, SyphonStrike, Souleater, LivingShadow, SaltedEarth, HardSlash, Shadowbringer, EdgeShadow, Bloodspiller, CarveSpit, Plunge, Bloodspiller, Shadowbringer, EdgeShadow, Bloodspiller, SaltDarkness, EdgeShadow, SyphonStrike, Plunge, EdgeShadow]
GNBPlayer.ActionSet = [WaitAbility(20),LightningShot, KeenEdge, BrutalShell, NoMercy, Bloodfest, GnashingFang, JugularRip, SonicBreak, BlastingZone, BowShock, DoubleDown, RoughDivide, SavageClaw, AbdomenTear, RoughDivide, WickedTalon, EyeGouge, SolidBarrel, BurstStrike, Hypervelocity, KeenEdge]
newFight.AddPlayer([GNBPlayer, DRKPlayer, SCHPlayer, WHMPlayer, RDMPlayer, DNCPlayer, DRGPlayer, NINPlayer]) # Adding players to the fight
TimeUnit = 0.01 # Unit of time per frame
TimeLimit = 500 # Max running time of the simulation (time IN the simulation)
# Simulation parameters
newFight.RequirementOn = True # Will check for actions requirement
newFight.IgnoreMana = False # Will check for mana
vocal = True # Want to output data in text
newFight.SimulateFight(TimeUnit, TimeLimit, vocal) # Simulating the fight
Outputs :
The Fight finishes at: 34.97
========================
Results for Gunbreaker ID - 1 :
DPS : 8940.86 PPS : 240.21 TP : 8400 GCD : 11 TD : 312662
=================
Results for DarkKnight ID - 2 :
DPS : 10964.91 PPS : 317.13 TP : 11090 GCD : 8 TD : 383443
=================
Results for Scholar ID - 3 :
DPS : 5450.7 PPS : 113.1 TP : 3955 GCD : 10 TD : 190611
=================
Results for WhiteMage ID - 4 :
DPS : 7905.06 PPS : 163.28 TP : 5710 GCD : 16 TD : 276440
=================
Results for RedMage ID - 5 :
DPS : 12949.93 PPS : 249.64 TP : 8730 GCD : 16 TD : 452859
Procs/Gauge result (Used/Expected) :
Verfire : 1/3.5 Verstone : 1/2.0
=================
Results for Dancer ID - 6 :
DPS : 10018.44 PPS : 167.86 TP : 5870 GCD : 17 TD : 350345
Procs/Gauge result (Used/Expected) :
Silken Symettry : 0/0 Silken Flow : 0/0
Fourfold Feather : 1/0.5 Threefold Fan : 2/1.5
=================
Results for Dragoon ID - 7 :
DPS : 11957.94 PPS : 226.34 TP : 7915 GCD : 14 TD : 418169
=================
Results for Ninja ID - 8 :
DPS : 17974.81 PPS : 339.15 TP : 11860 GCD : 28 TD : 628579
=================
Total DPS : 86162.65 Total PPS : 1816.7 Total Potency : 63530

Note
The simulator automatically computes the team composition bonus depending on what role is present in the fight.
In this case the openers were set up to simulate a 20 seconds countdown before starting to do damage.
The generated graphics (either DPS distribution or DPS Vs. Time) will be saved in the same directory where the script was executed.
The rest of the documentation will focus on stuff that is not mandatory. But feel free to stop by anyway!