Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math
- # BUGS:
- # - if someone is dead, don't let heals work on them
- # - some off by ones
- TARGET_ALL = 1
- TARGET_LINE = 2
- # For defence changes, subtract from 1, and multiply by it.
- dragon_dir = 1
- dragon = {
- 'name': 'dragon',
- 'ai': map(lambda s: s.lower(), ['Claw', 'Heatwave', 'Claw', 'Claw', 'Claw', 'Claw', 'Claw', 'Claw', 'Move', 'Claw', 'Heatwave', 'Claw', 'Claw', 'Claw', 'Claw', 'Claw', 'Move', 'Wait', 'Wait', 'Flamethrower']),
- 'moves': {
- 'claw': {'damage': 20, 'stack': ('claw', 5, 5)},
- 'heatwave': {'damage': 5, 'dps': (20, 3), 'target': TARGET_ALL},
- 'flamethrower': {'damage': 100, 'target': TARGET_LINE},
- 'boss': {'damage': 100, 'target': TARGET_ALL},
- 'move': {'y': lambda: dragon_dir},
- },
- 'state': {
- 'hp': 4000,
- 'mana': 0,
- 'taunt': 0,
- 'dps': [],
- 'attack': [],
- 'defence': [],
- 'stack': {},
- 'y': 5,
- 'move': 0,
- 'boss_used': False,
- 'pending': None,
- 'pending_target': None,
- },
- 'max_hp': 4000,
- 'max_mana': 0,
- }
- knight = {
- 'name': 'knight',
- 'moves': {
- 'taunt': {'taunt': 5},
- 'strike': {'mana': -20, 'damage': 10},
- 'pierce': {'mana': 20, 'damage': 10, 'dps': (10, 5)},
- 'shieldwall': {'mana': 50, 'defence': (.5, 5), 'target': 'knight'},
- 'shieldbash': {'mana': 50, 'damage': 10, 'defence': (1.5, 5), 'target': 'dragon'},
- 'phalanx': {'cooldown': 100, 'defence': (0.0, 5), 'target': 'knight'},
- 'move:up': {'y': lambda: 1},
- 'move:down': {'y': lambda: -1},
- },
- 'state': {
- 'hp': 400,
- 'mana': 0,
- 'dps': [],
- 'attack': [],
- 'defence': [],
- 'stack': {},
- 'y': 4,
- 'cooldown': {
- 'phalanx': 0,
- },
- 'pending': None,
- 'pending_target': None,
- 'last_cast': {
- 'taunt': -1000,
- 'shieldbash': -1000,
- 'shieldwall': -1000,
- }
- },
- 'ai': [],
- 'max_hp': 400,
- 'max_mana': 100,
- }
- priest = {
- 'name': 'priest',
- 'moves': {
- 'greaterheal': {'mana': 5, 'turns': 3, 'damage': -100},
- 'flashheal': {'mana': 5, 'damage': -35},
- 'regen': {'mana': 2, 'damage': -5, 'dps': (-5, 10)},
- 'hymn': {'mana': -10, 'turns': 2, 'damage': -15, 'target': TARGET_ALL},
- 'divineintervention': {'mana': 10, 'cooldown': 100, 'dps': (-100, 5), 'target': TARGET_ALL},
- 'move:up': {'y': lambda: 1},
- 'move:down': {'y': lambda: -1},
- },
- 'state': {
- 'hp': 200,
- 'mana': 300,
- 'dps': [],
- 'attack': [],
- 'defence': [],
- 'stack': {},
- 'y': 3,
- 'cooldown': {
- 'divineintervention': 0,
- },
- 'pending': None,
- 'pending_target': None,
- },
- 'ai': [],
- 'max_hp': 200,
- 'max_mana': 300,
- }
- wizard = {
- 'name': 'wizard',
- 'moves': {
- 'iceshard': {'mana': 4, 'turns': 2, 'damage': 20, 'stack': ('shard', 0, 3)},
- 'icespear': {'mana': 5, 'stack_damage': ('shard', 50)},
- 'frostbite': {'mana': 5, 'cooldown': 20, 'target': 'wizard', 'attack': (1.2, 10)},
- 'waterbarrier': {'mana': -5, 'cooldown': 20, 'defence': (0.8, 10)},
- 'deluge': {'mana': -20, 'cooldown': 100, 'damage': 200},
- 'move:up': {'y': lambda: 1},
- 'move:down': {'y': lambda: -1},
- },
- 'state': {
- 'hp': 200,
- 'mana': 200,
- 'dps': [],
- 'attack': [],
- 'defence': [],
- 'stack': {},
- 'y': 5,
- 'cooldown': {
- 'deluge': 0,
- 'frostbite': 0,
- 'waterbarrier': 0,
- },
- 'pending': None,
- 'pending_target': None,
- },
- 'ai': [],
- 'max_hp': 200,
- 'max_mana': 200,
- }
- def find_d(d, attack, defence):
- n = d
- for x, _ in attack + defence:
- # Only buff damages and not heals.
- if d > 0:
- n += d * (x - 1.0)
- return n
- def use(char, move_name, target=None):
- s = char['state']
- if s['hp'] <= 0:
- print 'skipping as dead'
- print char
- return
- # Special case for wait.
- if move_name == 'wait':
- char['ai'].append(('wait', None))
- print ' ', char['name'], 'wait'
- return
- # Select move.
- if move_name == 'pending':
- m = s['pending']
- pending_target = s['pending_target']
- assert m['turns'] == 1
- s['pending'] = None
- s['pending_target'] = None
- else:
- assert s['pending'] is None
- assert s['pending_target'] is None
- m = char['moves'][move_name]
- # Verify + reset cooldown.
- if 'cooldown' in m:
- assert s['cooldown'][move_name] == 0
- s['cooldown'][move_name] = N * m['cooldown']
- # Only incur mana after pending move invoked.
- if 'mana' in m and ('turns' not in m or m['turns'] <= 1):
- assert s['mana'] >= m['mana']
- s['mana'] -= m['mana']
- # Handle moves.
- if 'y' in m:
- s['y'] += m['y']()
- # Finding targets.
- lookup = {
- 'wizard': wizard,
- 'priest': priest,
- 'knight': knight,
- 'dragon': dragon,
- }
- ts = []
- t_name = None
- if move_name == 'pending':
- ts = pending_target
- elif 'target' in m:
- if m['target'] == TARGET_ALL:
- ts = [knight, priest, wizard]
- elif m['target'] == TARGET_LINE:
- # TODO - work out if this is correct.
- if s['y'] <= 4:
- ts = filter(lambda x: x['state']['y'] <= 4, [knight, priest, wizard])
- else:
- ts = filter(lambda x: x['state']['y'] >= 2, [knight, priest, wizard])
- else:
- ts = [lookup[m['target']]]
- t_name = m['target']
- else:
- # Grab from argument instead.
- assert target
- ts = [lookup[target]]
- t_name = lookup[target]['name']
- # Push move to log.
- if char != dragon and move_name != 'pending':
- char['ai'].append((move_name, t_name))
- print ' ', char['name'], move_name, t_name
- # Defer multi-turn actions.
- if 'turns' in m and m['turns'] > 1:
- s['pending'] = m.copy()
- s['pending_target'] = ts
- return
- # Apply effects: damage, dps, taunt, stack, stack_damage, attack, defence.
- for t in ts:
- if 'damage' in m:
- t['state']['hp'] -= find_d(m['damage'], s['attack'], t['state']['defence'])
- if 'dps' in m:
- # Attack multipliers don't affect DPS.
- t['state']['dps'].append((m['dps'][0], m['dps'][1]*N))
- if 'taunt' in m:
- t['state']['taunt'] = m['taunt']*N
- if 'stack' in m:
- name, dps, max_v = m['stack']
- cur_n, dps2 = t['state']['stack'].get(name, (0, dps))
- assert dps == dps2
- t['state']['stack'][name] = (min(cur_n + 1, max_v), dps)
- if 'stack_damage' in m:
- name, d = m['stack_damage']
- t['state']['hp'] -= find_d(d*t['state']['stack'][name][0], s['attack'], t['state']['defence'])
- del t['state']['stack'][name]
- if 'attack' in m:
- # HACK: needs +1 here and in defence because if you chain buffs every 5 moves, can't lose them.
- t['state']['attack'].append((m['attack'][0], m['attack'][1] * N+1))
- if 'defence' in m:
- t['state']['defence'].append((m['defence'][0], m['defence'][1] * N+1))
- chars = [knight, priest, wizard, dragon]
- N = len(chars)
- def fix_hp_mana():
- for char in chars:
- char['state']['mana'] = min(char['state']['mana'], char['max_mana'])
- char['state']['hp'] = math.ceil(char['state']['hp'])
- char['state']['hp'] = min(char['state']['hp'], char['max_hp'])
- # These need to get processed every turn for accuracy.
- # They're multiplied by N when set.
- def process_any_turn():
- for char in chars:
- new_dps = []
- for dps, turns in char['state']['dps']:
- if turns > 1:
- new_dps.append((dps, turns-1))
- char['state']['dps'] = new_dps
- if 'cooldown' in char['state']:
- for move, cd in char['state']['cooldown'].iteritems():
- char['state']['cooldown'][move] = max(0, cd-1)
- if 'taunt' in char['state']:
- char['state']['taunt'] = max(char['state']['taunt'] - 1, 0)
- if 'attack' in char['state']:
- n = map(lambda x: (x[0], x[1]-1), char['state']['attack'])
- char['state']['attack'] = filter(lambda x: x[1] > 0, n)
- if 'defence' in char['state']:
- n = map(lambda x: (x[0], x[1]-1), char['state']['defence'])
- char['state']['defence'] = filter(lambda x: x[1] > 0, n)
- def process_turn_start(char):
- for dps, turns in char['state']['dps']:
- char['state']['hp'] = char['state']['hp'] - find_d(dps, [], char['state']['defence'])
- for num, dps in char['state']['stack'].values():
- char['state']['hp'] = char['state']['hp'] - find_d(num*dps, [], char['state']['defence'])
- if char['state']['pending']:
- char['state']['pending']['turns'] -= 1
- fix_hp_mana()
- for turn in xrange(200):
- print 'Turn', turn+1
- # Avoiding flamethrower: swap between line 5 and line 1.
- # Have each character act in order, and push moves.
- # Knight.
- # - If flamethrower coming, avoid the line.
- # - Taunt if needed.
- # - Shield bash if needed.
- # - Piece if >= 70 mana.
- # - Strike.
- process_any_turn()
- process_turn_start(knight)
- if knight['state']['pending']:
- if knight['state']['pending']['turns'] <= 1:
- use(knight, 'pending')
- elif turn - knight['state']['last_cast']['taunt'] >= 5:
- use(knight, 'taunt', 'dragon')
- knight['state']['last_cast']['taunt'] = turn
- elif knight['state']['mana'] >= 50 and turn - knight['state']['last_cast']['shieldbash'] >= 5:
- use(knight, 'shieldbash', 'dragon')
- knight['state']['last_cast']['shieldbash'] = turn
- elif knight['state']['mana'] >= 70:
- use(knight, 'pierce', 'dragon')
- else:
- use(knight, 'strike', 'dragon')
- fix_hp_mana()
- # Priest.
- # - If flamethrower coming, avoid the line.
- # - If firestorm coming, divine intervention.
- # - If knight < 200, greater heal it.
- # - If priest < 100, regen it.
- # - If wizard < 100, regen it.
- process_any_turn()
- process_turn_start(priest)
- if priest['state']['pending']:
- if priest['state']['pending']['turns'] <= 1:
- use(priest, 'pending')
- elif knight['state']['hp'] < 100 and priest['state']['hp'] < 100 and wizard['state']['hp'] < 100 and priest['state']['cooldown']['divineintervention'] == 0:
- use(priest, 'divineintervention')
- elif knight['state']['hp'] <= 200:
- use(priest, 'greaterheal', 'knight')
- elif priest['state']['hp'] < 100:
- use(priest, 'regen', 'priest')
- elif wizard['state']['hp'] < 100:
- use(priest, 'regen', 'wizard')
- else:
- use(priest, 'hymn')
- fix_hp_mana()
- # Wizard.
- # - If flamethrower coming, avoid the line.
- # - Frostbite if possible.
- # - Ice shard x3
- # - Ice spear
- # - Deluge if possible.
- # - Water barrier if possible.
- process_any_turn()
- process_turn_start(wizard)
- if wizard['state']['pending']:
- if wizard['state']['pending']['turns'] <= 1:
- use(wizard, 'pending')
- elif wizard['state']['mana'] >= 5 and wizard['state']['cooldown']['frostbite'] == 0:
- use(wizard, 'frostbite')
- elif wizard['state']['mana'] <= 180 and wizard['state']['cooldown']['deluge'] == 0:
- use(wizard, 'deluge', 'dragon')
- elif wizard['state']['mana'] <= 195 and wizard['state']['cooldown']['waterbarrier'] == 0:
- use(wizard, 'waterbarrier', 'knight')
- elif wizard['state']['mana'] >= 4 and dragon['state']['stack'].get('shard', (0, 0))[0] < 3:
- use(wizard, 'iceshard', 'dragon')
- elif wizard['state']['mana'] >= 5 and dragon['state']['stack'].get('shard', (0, 0))[0] == 3:
- use(wizard, 'icespear', 'dragon')
- else:
- use(wizard, 'wait')
- fix_hp_mana()
- # Dragon.
- process_any_turn()
- process_turn_start(dragon)
- if dragon['state']['hp'] <= 2000 and not dragon['state']['boss_used']:
- use(dragon, 'boss')
- dragon['state']['boss_used'] = True
- else:
- # Dragon will attack wizard, priest, knight in preference order.
- target = 'wizard' if dragon['state']['taunt'] == 0 else 'knight'
- move = dragon['ai'][turn % 20]
- use(dragon, dragon['ai'][turn % 20], target)
- # Bounce at ends.
- if move == 'move' and dragon['state']['y'] in (0, 6):
- dragon_dir *= -1
- fix_hp_mana()
- # Check who is alive.
- for char in chars:
- print ' ', char['name'], char['state']['hp'], char['state']['mana'], char['state']['attack'], char['state']['defence']
- if any(c['state']['hp'] <= 0 for c in chars):
- print 'someone died, bailing out'
- break
- for char in [wizard, knight, priest]:
- print '%s:' % char['name']
- print ' ', ' '.join(map(lambda x: ':'.join(filter(lambda x: x, x)), char['ai']))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement