Last active
September 21, 2018 03:22
-
-
Save sandersch/2e04a83b3b299dab5c59bb43bca8a28c to your computer and use it in GitHub Desktop.
UAC module with qstrike cost calculation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UAC | |
class << self | |
@@best_move_against ||= {} | |
@@max_tiered ||= [] | |
def best_move_against | |
@@best_move_against | |
end | |
ATTACK_REGEX = Regexp.union( | |
/You have excellent positioning against/, | |
/leaves foe vulnerable to a followup (\w+) attack/, | |
/Roundtime/, | |
) | |
def attack(target, aimed=false) | |
ensure_proper_stance | |
ensure_hands_are_ready | |
if aimed | |
Ranged.autoaim target, "uac" | |
else | |
Ranged.aim "random" | |
end | |
waitrt? | |
attack_move = determine_attack_move_against(target) | |
if ["jab", max_tier_attack].include?(attack_move) && should_mstrike? | |
echo "DEBUG: seems ok to mstrike" if $debug_fite | |
attack_move = "mstrike #{max_tier_attack}" | |
end | |
if should_qstrike?(attack_move) | |
if Spell[506].active? | |
attack_move = "quickstrike 1 #{attack_move}" | |
else | |
secs = determine_qstrike_amount(attack_move) | |
attack_move = "quickstrike #{secs} #{attack_move}" | |
end | |
end | |
attack_result = dothistimeout "#{attack_move} ##{target.id}", 3, ATTACK_REGEX | |
if attack_result =~ /You have excellent positioning against/ | |
@@max_tiered << target.id | |
set_followup_attack_to(target, max_tier_attack) | |
elsif attack_result =~ /leaves foe vulnerable to a followup (\w+) attack/ | |
echo "DEBUG: Should follow up with: #{$1}" if $debug_fite | |
@@max_tiered.delete(target.id) | |
set_followup_attack_to(target, $1) | |
elsif attack_result =~ /Roundtime/ | |
@@max_tiered.delete(target.id) | |
echo "DEBUG: Matched roundtime" if $debug_fite | |
clear_vuln_on target | |
else | |
echo "ERROR: didn't detect an unarmed attack" | |
end | |
attack_result | |
end | |
def clear_vuln_on(target) | |
best_move_against.delete(target.id) | |
end | |
def set_followup_attack_to(target, move) | |
echo "DEBUG: setting next move against ##{target.id} to #{move}" if $debug_fite | |
best_move_against[target.id] = move | |
end | |
def determine_attack_move_against(target) | |
best_move = if @@max_tiered.include? target.id | |
max_tier_attack | |
else | |
best_move_against[target.id] || default_attack_move | |
end | |
echo "DEBUG: best move against ##{target.id} is #{best_move}" if $debug_fite | |
best_move | |
end | |
def default_attack_move | |
"jab".tap do |move| | |
echo "DEBUG: falling back to default attack move of #{move}" if $debug_fite | |
end | |
end | |
def max_tier_attack | |
"kick".tap do |move| | |
echo "DEBUG: using max tier attack of: #{move}" if $debug_fite | |
end | |
end | |
def ensure_proper_stance | |
fput "stance #{proper_stance}" unless checkstance == proper_stance | |
end | |
def proper_stance | |
"offensive" | |
end | |
def ensure_hands_are_ready | |
ensure_ammo_is_stowed | |
end | |
def ensure_ammo_is_stowed | |
if defined?(Ranged) && have_ammo_in_hands? | |
Ranged.stow_ammo | |
end | |
end | |
def have_ammo_in_hands? | |
[GameObj.right_hand, GameObj.left_hand].find do |hand| | |
hand.type.inclde?("ammo") || hand.name.end_with?("arrow") | |
end | |
end | |
def know_how_to_mstrike? | |
Skills.multiopponentcombat >= 30 | |
end | |
MINIMUM_MSTRIKE_ON_COOLDOWN_STAMINA = 50 | |
def have_enough_stamina_to_mstrike? | |
!mstrike_on_cooldown? || # Mstrike Cooldown | |
checkstamina(MINIMUM_MSTRIKE_ON_COOLDOWN_STAMINA) | |
end | |
def no_spell_or_effect_prevents_mstrike? | |
!haste_active? && !muscles_popped? | |
end | |
def haste_active? | |
Spell[506].active? | |
end | |
def mstrike_on_cooldown? | |
Spell[9005].active? | |
end | |
def muscles_popped? | |
Spell[9699].active? | |
end | |
def should_mstrike? | |
know_how_to_mstrike? && | |
no_spell_or_effect_prevents_mstrike? && | |
have_enough_stamina_to_mstrike? | |
end | |
def mstrike | |
ensure_proper_stance | |
ensure_hands_are_ready | |
waitrt? | |
attack_move = "mstrike #{mstrike_move}" | |
if should_qstrike? | |
attack_move = "quickstrike -1 #{attack_move}" | |
end | |
attack_result = dothistimeout attackmove, 3, ATTACK_REGEX | |
if attack_result | |
echo "DEBUG: mstrike successful" | |
attack_result | |
else | |
echo "ERROR: failed to mstrike" | |
nil | |
end | |
end | |
def mstrike_move | |
"punch" | |
end | |
def no_spell_or_effect_prevents_qstrike? | |
!muscles_popped? | |
end | |
MINIMUM_QSTRIKE_STAMINA = 50 | |
# jab = 12 | |
# punch = 13 | |
# grapple = 13 | |
# kick = 14 | |
# mstrike = 100? | |
QSTRIKE_STAMINA_COST_FOR = { | |
"jab" => 12, | |
"punch" => 13, | |
"grapple" => 13, | |
"kick" => 14, | |
"mstrike" => 75, # TODO: maybe figure this out? | |
} | |
def stamina_cost_for_move(attack_move) | |
m = attack_move.split.first | |
cost = QSTRIKE_STAMINA_COST_FOR.fetch(m) | |
if attack_move =~ /mstrike/ && mstrike_on_cooldown? | |
cost += MINIMUM_MSTRIKE_ON_COOLDOWN_STAMINA if mstrike_on_cooldown? | |
end | |
echo "DEBUG: estimated stamina cost for #{attack_move} = #{cost}" | |
cost | |
end | |
def determine_qstrike_amount(attack_move) | |
case (m = attack_move.split.first) | |
when /mstrike/ | |
-2 | |
when /jab/ | |
-1 | |
when /punch/, /grapple/, /kick/ | |
max_possible = (checkstamina - BUFFER_STAMINA) / stamina_cost_for_move(attack_move) | |
if max_possible <= 0 | |
echo "ERROR: not enough stamina to qstrike" | |
0 | |
else | |
limit = if m =~ /kick/ | |
3 | |
else | |
2 | |
end | |
-[limit, max_possible].min | |
end | |
end | |
end | |
BUFFER_STAMINA = 15 | |
def have_enough_stamina_to_qstrike?(attack_move) | |
haste_active? || | |
checkstamina( | |
BUFFER_STAMINA + stamina_cost_for_move(attack_move) | |
) | |
end | |
def should_qstrike?(attack_move="mstrike") | |
no_spell_or_effect_prevents_qstrike? && | |
have_enough_stamina_to_qstrike?(attack_move) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment