Whee, the grammar works.
I opted for grammar simplicity and to do more of the semantic work in the backend, instead of trying to parse specific keywords.
As far as I can tell the grammar is correct. Next step is the semantic parsing and attaching actions to nonterminals.
Here is the full grammar:
Code:
actionb (Nullable)
actionb -> , string actionb
actionb ->
actions (Nullable)
actions -> string actionb
actions ->
actionStatement
actionStatement -> ( conditionals ) { actions }
actionStatement -> comment
actionStatement+
actionStatement+ -> actionStatement+ actionStatement
actionStatement+ -> actionStatement
actionStatements (Nullable)
actionStatements ->
actionStatements -> actionStatement+
actorAdd
actorAdd -> actorList += string
actorList
actorList -> *players
actorList -> *targets
boolVar
boolVar -> string boolVarb
boolVarb (Nullable)
boolVarb -> . string boolVarb
boolVarb ->
conditional
conditional -> boolVar test number
conditional -> ! boolVar
conditional -> boolVar
conditionalb (Nullable)
conditionalb -> & conditional conditionalb
conditionalb ->
conditionals (Nullable)
conditionals -> conditional conditionalb
conditionals ->
gcd
gcd -> [GCD] actionStatements
ogcd
ogcd -> [OGCD] actionStatements
precast
precast -> [PRECAST] actionStatements
script
script -> setup precast gcd ogcd
script'
script' -> script EOF
setup
setup -> [SETUP] setupStatements
setupStatement
setupStatement -> actorAdd
setupStatement -> varAssign
setupStatement -> comment
setupStatement+
setupStatement+ -> setupStatement+ setupStatement
setupStatement+ -> setupStatement
setupStatements (Nullable)
setupStatements ->
setupStatements -> setupStatement+
test
test -> ==
test -> !=
test -> <
test -> >
test -> <=
test -> >=
val
val -> number
val -> string
val -> stringLit
var
var -> string varb
varAssign
varAssign -> var = val
varb (Nullable)
varb -> . string varb
varb ->
Here is a sample DRG rotation, not optimal, but it works.
Code:
[SETUP]
#sets up an alias for our player
*players+=p1
#sets up an alias for our target
*targets+=t1
#load skills and traits
p1.class=drg
# setup attributes
# nonlisted attributes are assumed to be 0
p1.attr.str=500
p1.attr.dex=200
p1.attr.sks=400
# setup server variables
sim.duration=600
# execute is duration from end of sim
sim.execute=200
# setup diagnostic or no - diagnostic runs 1 run with log output, for testing your rotation
sim.diagnostic=true
# otherwise setup sim trials
sim.trials=10000
# i/o
sim.output="./output.txt"
[PRECAST]
# place a sequential list of ogcd/gcd actions here
# any action that is offensive will begin the sim timer
# however, you may place as many actions as you like
# if you have a set opener rotation you wish to follow, enter it here
# and the [GCD] actionlists will follow once the action queue is complete
(){x_potion,blood_for_blood,heavy_thrust}
[GCD]
# remaining is set to 0 if an aura does not exist
# you do not need to test for both exists and remaining
# if an action is in the queue, no further actions will be run
# if a condition is satisfied, the sim will attempt to cast the action
# if an action succeeds, no further actions will be run until the queue is empty
# the only supported boolean operator is &
# to do | actions, use multiple action lines
(p1.aura.heavy_thrust.remaining<5.0){heavy_thrust}
(t1.aura.chaos_thrust.remaining<12.0){impulse_drive,disembowel,chaos_thrust}
(t1.aura.phlebotomize<5.0){phlebotomize}
(){true_thrust,vorpal_thrust,full_thrust}
[OGCD]
# you'll need this unless you want to constantly clip GCDs
# actionlist execution stops as soon as a successful action is entered
# blank actions are automatically successful
# be very careful queueing oGCDs. They will automatically be run in sequence, without regard for clipping into a gcd
(p1.nextgcd<1.0){}
(){blood_for_blood}
(p1.nextaction==full_thrust){life_surge}
(!p1.cd.jump){power_surge}
(){jump}
(){dragonfire_dive}
(){leg_sweep}