Finally have AI working. Started to add feral skills.
Showing
2 changed files
with
127 additions
and
49 deletions
No preview for this file type
... | @@ -4,6 +4,7 @@ import pickle | ... | @@ -4,6 +4,7 @@ import pickle |
4 | import math | 4 | import math |
5 | import collections | 5 | import collections |
6 | import logging | 6 | import logging |
7 | import operator | ||
7 | 8 | ||
8 | def log(message): | 9 | def log(message): |
9 | try: | 10 | try: |
... | @@ -134,15 +135,20 @@ PhysicalDamageTypes = { | ... | @@ -134,15 +135,20 @@ PhysicalDamageTypes = { |
134 | } | 135 | } |
135 | 136 | ||
136 | FeralSkills = { | 137 | FeralSkills = { |
137 | 'Airy Shield': {'fp_cost': 0, 'type': 'Enhancing', 'sub_type': 'arrow shield', 'shadows': 'ignore', 'range': None, 'aoe': False, 'spell': 'arrow shield'}, | 138 | # 'Airy Shield': {'fp_cost': 0, 'type': 'Enhancing', 'sub_type': 'arrow shield', 'shadows': 'ignore', 'range': None, 'aoe': False, 'spell': 'arrow shield'}, |
138 | 'Binding Wave': {'type': 'Enfeebling', 'shadows': 'ignore', 'range': 15, 'aoe': True, 'spell': 'bind'}, | 139 | # 'Binding Wave': {'type': 'Enfeebling', 'shadows': 'ignore', 'range': 15, 'aoe': True, 'spell': 'bind'}, |
139 | 'Dire Straight': {'type': 'Physical', 'shadows': 'wipe', 'range': None, 'aoe': False}, | 140 | # 'Dire Straight': {'type': 'Physical', 'shadows': 'wipe', 'range': None, 'aoe': False}, |
140 | 'Dismemberment': {'type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, # causes the monster to lose a body part | 141 | # 'Dismemberment': {'type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, # causes the monster to lose a body part |
141 | 'Earthshatter': {'type': 'Piercing', 'shadows': 'wipe', 'range': None, 'aoe': True}, | 142 | # 'Earthshatter': {'type': 'Piercing', 'shadows': 'wipe', 'range': None, 'aoe': True}, |
142 | 'Eyes On Me': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 112, 'shadows': 'absorb', 'range': 13, 'aoe': False}, | 143 | # 'Eyes On Me': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 112, 'shadows': 'absorb', 'range': 13, 'aoe': False}, |
143 | 'Hypnosis': {'type': 'Enfeebling', 'sub_type': 'sleep', 'shadows': 'ignore', 'range': 'gaze', 'aoe': True}, | 144 | # 'Hypnosis': {'type': 'Enfeebling', 'sub_type': 'sleep', 'shadows': 'ignore', 'range': 'gaze', 'aoe': True}, |
144 | 'Magic Barrier': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 29, 'shadows': 'absorb', 'range': None, 'aoe': True}, | 145 | # 'Magic Barrier': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 29, 'shadows': 'absorb', 'range': None, 'aoe': True}, |
145 | 'Sinker Drill': {'type': 'Physical', 'sub_type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, | 146 | # 'Sinker Drill': {'type': 'Physical', 'sub_type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, |
147 | 'Accuracy +15%': {'fp_cost': 23, 'effect': 'acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, | ||
148 | 'Accuracy +30%': {'fp_cost': 30, 'effect': 'acc', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, | ||
149 | 'Accuracy Bonus': {'fp_cost': 30, 'effect': 'acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, | ||
150 | 'AGI +25': {'fp_cost': 17, 'effect': 'agi', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, | ||
151 | |||
146 | } | 152 | } |
147 | 153 | ||
148 | class Spells: | 154 | class Spells: |
... | @@ -193,14 +199,16 @@ class Spells: | ... | @@ -193,14 +199,16 @@ class Spells: |
193 | 'Banish III': {'mp_cost': 96, 'casting_time': 3, 'recast_time': 45, 'magic_acc_stat': 'mnd', 'spell_type': 't3', 'damage_type': 'light', 'jobs': {Jobs.WHM: 65} }, | 199 | 'Banish III': {'mp_cost': 96, 'casting_time': 3, 'recast_time': 45, 'magic_acc_stat': 'mnd', 'spell_type': 't3', 'damage_type': 'light', 'jobs': {Jobs.WHM: 65} }, |
194 | } | 200 | } |
195 | 201 | ||
196 | def get_spell_list(self, level, job = None, sub_job = None): | 202 | def get_spell_list(self, mp, level, job = None, support_job = None): |
197 | available_spells = [] | 203 | available_spells = [] |
198 | for spell_name, spell in self.SpellList.iteritems(): | 204 | for spell_name, spell in self.SpellList.iteritems(): |
199 | if job and job in spell['jobs'] and spell['jobs'][job] <= level: | 205 | if job and job in spell['jobs'] and spell['jobs'][job] <= level: |
200 | if spell_name not in available_spells: | 206 | if spell_name not in available_spells: |
207 | if spell['mp_cost'] < mp: | ||
201 | available_spells.append(spell_name) | 208 | available_spells.append(spell_name) |
202 | if sub_job and sub_job in spell['jobs'] and spell['jobs'][sub_job] <= level / 2: | 209 | if support_job and support_job in spell['jobs'] and spell['jobs'][support_job] <= level / 2: |
203 | if spell_name not in available_spells: | 210 | if spell_name not in available_spells: |
211 | if spell['mp_cost'] < mp: | ||
204 | available_spells.append(spell_name) | 212 | available_spells.append(spell_name) |
205 | return sorted(available_spells) | 213 | return sorted(available_spells) |
206 | 214 | ||
... | @@ -224,8 +232,9 @@ Families = { | ... | @@ -224,8 +232,9 @@ Families = { |
224 | 'max_fp': 55, | 232 | 'max_fp': 55, |
225 | 'available_main_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], | 233 | 'available_main_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], |
226 | 'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], | 234 | 'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], |
227 | 'innate_feral_skills': ['Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'], | 235 | 'innate_feral_skills': [],#'Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'], |
228 | 'target_magic_damage_adjustment': 1.00, | 236 | 'target_magic_damage_adjustment': 1.00, |
237 | 'feral_skills_conversion': ['Accuracy +15%'], | ||
229 | 'type': 'Arcana', | 238 | 'type': 'Arcana', |
230 | 'strong_vs': ['Dark'], | 239 | 'strong_vs': ['Dark'], |
231 | 'charmable': False, | 240 | 'charmable': False, |
... | @@ -272,6 +281,7 @@ Families = { | ... | @@ -272,6 +281,7 @@ Families = { |
272 | 'available_support_job': [Jobs.BLM, Jobs.RDM, Jobs.WAR], | 281 | 'available_support_job': [Jobs.BLM, Jobs.RDM, Jobs.WAR], |
273 | 'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'], | 282 | 'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'], |
274 | 'type': 'Demon', | 283 | 'type': 'Demon', |
284 | 'feral_skills_conversion': ['Accuracy +15%'], | ||
275 | 'traits': ['magic defence bonus +25%'], | 285 | 'traits': ['magic defence bonus +25%'], |
276 | 'target_magic_damage_adjustment': 0.75, | 286 | 'target_magic_damage_adjustment': 0.75, |
277 | 'charmable': False, | 287 | 'charmable': False, |
... | @@ -316,6 +326,7 @@ Monsters = { | ... | @@ -316,6 +326,7 @@ Monsters = { |
316 | 'Mechanical Menace': { | 326 | 'Mechanical Menace': { |
317 | 'family': 'acrolith', | 327 | 'family': 'acrolith', |
318 | 'zone': ['abyssea - uleguerand'], | 328 | 'zone': ['abyssea - uleguerand'], |
329 | 'feral_skills_conversion': [], | ||
319 | 'hp': 20, | 330 | 'hp': 20, |
320 | 'mp': 20, | 331 | 'mp': 20, |
321 | 'weapon_base_damage': 18 | 332 | 'weapon_base_damage': 18 |
... | @@ -323,95 +334,108 @@ Monsters = { | ... | @@ -323,95 +334,108 @@ Monsters = { |
323 | 'Floating Eye': { | 334 | 'Floating Eye': { |
324 | 'family': 'ahriman', | 335 | 'family': 'ahriman', |
325 | 'zone': ['ranguemont pass'], | 336 | 'zone': ['ranguemont pass'], |
337 | 'feral_skills_conversion': [], | ||
326 | 'hp': 15, | 338 | 'hp': 15, |
327 | 'mp': 24, | 339 | 'mp': 24, |
328 | 'weapon_base_damage': 15, | 340 | 'weapon_base_damage': 5, |
329 | 'image_url': 'http://vignette1.wikia.nocookie.net/ffxi/images/9/94/Floating_Eye.JPG/revision/latest?cb=20070704142439' | 341 | 'image_url': 'http://vignette1.wikia.nocookie.net/ffxi/images/9/94/Floating_Eye.JPG/revision/latest?cb=20070704142439' |
330 | }, | 342 | }, |
331 | 'Bat Eye': { | 343 | 'Bat Eye': { |
332 | 'family': 'ahriman', | 344 | 'family': 'ahriman', |
333 | 'zone': ['ranguemont pass', 'beaucedine glacier'], | 345 | 'zone': ['ranguemont pass', 'beaucedine glacier'], |
346 | 'feral_skills_conversion': [], | ||
334 | 'hp': 15, | 347 | 'hp': 15, |
335 | 'mp': 24, | 348 | 'mp': 24, |
336 | 'weapon_base_damage': 15, | 349 | 'weapon_base_damage': 5, |
337 | 'image_url': 'http://vignette3.wikia.nocookie.net/ffxi/images/4/40/Bat_Eye.jpg/revision/latest?cb=20060909124134', | 350 | 'image_url': 'http://vignette3.wikia.nocookie.net/ffxi/images/4/40/Bat_Eye.jpg/revision/latest?cb=20060909124134', |
338 | }, | 351 | }, |
339 | 'Evil Eye': { | 352 | 'Evil Eye': { |
340 | 'family': 'ahriman', | 353 | 'family': 'ahriman', |
341 | 'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'], | 354 | 'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'], |
355 | 'feral_skills_conversion': [], | ||
342 | 'hp': 15, | 356 | 'hp': 15, |
343 | 'mp': 24, | 357 | 'mp': 24, |
344 | 'weapon_base_damage': 15, | 358 | 'weapon_base_damage': 5, |
345 | }, | 359 | }, |
346 | 'Morbid Eye': { | 360 | 'Morbid Eye': { |
347 | 'family': 'ahriman', | 361 | 'family': 'ahriman', |
348 | 'zone': ['castle zvahl baileys', 'castle zvahl keep'], | 362 | 'zone': ['castle zvahl baileys', 'castle zvahl keep'], |
363 | 'feral_skills_conversion': [], | ||
349 | 'hp': 15, | 364 | 'hp': 15, |
350 | 'mp': 24, | 365 | 'mp': 24, |
351 | 'weapon_base_damage': 15 | 366 | 'weapon_base_damage': 5 |
352 | }, | 367 | }, |
353 | 'Deadly Iris': { | 368 | 'Deadly Iris': { |
354 | 'family': 'ahriman', | 369 | 'family': 'ahriman', |
355 | 'zone': ['castle zvahl keep'], | 370 | 'zone': ['castle zvahl keep'], |
371 | 'feral_skills_conversion': [], | ||
356 | 'hp': 15, | 372 | 'hp': 15, |
357 | 'mp': 24, | 373 | 'mp': 24, |
358 | 'weapon_base_damage': 15 | 374 | 'weapon_base_damage': 5 |
359 | }, | 375 | }, |
360 | 'Ahriman': { | 376 | 'Ahriman': { |
361 | 'family': 'ahriman', | 377 | 'family': 'ahriman', |
362 | 'zone': ['castle zvahl baileys'], | 378 | 'zone': ['castle zvahl baileys'], |
379 | 'feral_skills_conversion': [], | ||
363 | 'hp': 15, | 380 | 'hp': 15, |
364 | 'mp': 24, | 381 | 'mp': 24, |
365 | 'weapon_base_damage': 15 | 382 | 'weapon_base_damage': 5 |
366 | }, | 383 | }, |
367 | 'Fachan': { | 384 | 'Fachan': { |
368 | 'family': 'ahriman', | 385 | 'family': 'ahriman', |
369 | 'zone': ['uleguerand range'], | 386 | 'zone': ['uleguerand range'], |
387 | 'feral_skills_conversion': [], | ||
370 | 'hp': 15, | 388 | 'hp': 15, |
371 | 'mp': 24, | 389 | 'mp': 24, |
372 | 'weapon_base_damage': 15 | 390 | 'weapon_base_damage': 5 |
373 | }, | 391 | }, |
374 | 'Gawper': { | 392 | 'Gawper': { |
375 | 'family': 'ahriman', | 393 | 'family': 'ahriman', |
376 | 'zone': ['beaucedine glacier (s)'], | 394 | 'zone': ['beaucedine glacier (s)'], |
395 | 'feral_skills_conversion': [], | ||
377 | 'hp': 15, | 396 | 'hp': 15, |
378 | 'mp': 24, | 397 | 'mp': 24, |
379 | 'weapon_base_damage': 15 | 398 | 'weapon_base_damage': 5 |
380 | }, | 399 | }, |
381 | 'Menacing Eye': { | 400 | 'Menacing Eye': { |
382 | 'family': 'ahriman', | 401 | 'family': 'ahriman', |
383 | 'zone': ['xarcabard (s)'], | 402 | 'zone': ['xarcabard (s)'], |
403 | 'feral_skills_conversion': [], | ||
384 | 'hp': 15, | 404 | 'hp': 15, |
385 | 'mp': 24, | 405 | 'mp': 24, |
386 | 'weapon_base_damage': 15 | 406 | 'weapon_base_damage': 5 |
387 | }, | 407 | }, |
388 | 'Ogler': { | 408 | 'Ogler': { |
389 | 'family': 'ahriman', | 409 | 'family': 'ahriman', |
390 | 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], | 410 | 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], |
411 | 'feral_skills_conversion': [], | ||
391 | 'hp': 15, | 412 | 'hp': 15, |
392 | 'mp': 24, | 413 | 'mp': 24, |
393 | 'weapon_base_damage': 15 | 414 | 'weapon_base_damage': 5 |
394 | }, | 415 | }, |
395 | 'Smolenkos': { | 416 | 'Smolenkos': { |
396 | 'family': 'ahriman', | 417 | 'family': 'ahriman', |
397 | 'zone': ['uleguerand range'], | 418 | 'zone': ['uleguerand range'], |
419 | 'feral_skills_conversion': [], | ||
398 | 'hp': 15, | 420 | 'hp': 15, |
399 | 'mp': 24, | 421 | 'mp': 24, |
400 | 'weapon_base_damage': 15 | 422 | 'weapon_base_damage': 5 |
401 | }, | 423 | }, |
402 | 'Doom Lens': { | 424 | 'Doom Lens': { |
403 | 'family': 'ahriman', | 425 | 'family': 'ahriman', |
404 | 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], | 426 | 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], |
427 | 'feral_skills_conversion': [], | ||
405 | 'hp': 15, | 428 | 'hp': 15, |
406 | 'mp': 24, | 429 | 'mp': 24, |
407 | 'weapon_base_damage': 15 | 430 | 'weapon_base_damage': 5 |
408 | }, | 431 | }, |
409 | 'Scowlenkos': { | 432 | 'Scowlenkos': { |
410 | 'family': 'ahriman', | 433 | 'family': 'ahriman', |
411 | 'zone': ['uleguerand range'], | 434 | 'zone': ['uleguerand range'], |
435 | 'feral_skills_conversion': [], | ||
412 | 'hp': 15, | 436 | 'hp': 15, |
413 | 'mp': 24, | 437 | 'mp': 24, |
414 | 'weapon_base_damage': 15 | 438 | 'weapon_base_damage': 5 |
415 | } | 439 | } |
416 | 440 | ||
417 | } | 441 | } |
... | @@ -477,13 +501,14 @@ class Pankration: | ... | @@ -477,13 +501,14 @@ class Pankration: |
477 | while support_job == main_job: | 501 | while support_job == main_job: |
478 | support_job = random.choice(family['available_support_job']) | 502 | support_job = random.choice(family['available_support_job']) |
479 | feral_skills = [] | 503 | feral_skills = [] |
480 | skills = random.sample(family['innate_feral_skills'], 3) | 504 | # TODO: Add support back in for innate feral skills |
481 | if random.randint(1, 100) < SKILL_PERCENT: | 505 | # skills = random.sample(family['innate_feral_skills'], 3) |
482 | feral_skills.append(skills[0]) | 506 | # if random.randint(1, 100) < SKILL_PERCENT: |
483 | if random.randint(1, 100) < SKILL_PERCENT: | 507 | # feral_skills.append(skills[0]) |
484 | feral_skills.append(skills[1]) | 508 | # if random.randint(1, 100) < SKILL_PERCENT: |
485 | if random.randint(1, 100) < SKILL_PERCENT: | 509 | # feral_skills.append(skills[1]) |
486 | feral_skills.append(skills[2]) | 510 | # if random.randint(1, 100) < SKILL_PERCENT: |
511 | # feral_skills.append(skills[2]) | ||
487 | dicipline_level = 1 | 512 | dicipline_level = 1 |
488 | 513 | ||
489 | monster = Monster(monster_name, family_name, family, hp, mp, level, | 514 | monster = Monster(monster_name, family_name, family, hp, mp, level, |
... | @@ -556,7 +581,7 @@ class Monster: | ... | @@ -556,7 +581,7 @@ class Monster: |
556 | self.mp = self.get_mp() | 581 | self.mp = self.get_mp() |
557 | self.wins = 0 | 582 | self.wins = 0 |
558 | self.losses = 0 | 583 | self.losses = 0 |
559 | self.battle_memory = [] | 584 | self.battle_memory = {} |
560 | 585 | ||
561 | def __str__(self): | 586 | def __str__(self): |
562 | try: | 587 | try: |
... | @@ -608,14 +633,17 @@ class Monster: | ... | @@ -608,14 +633,17 @@ class Monster: |
608 | 633 | ||
609 | def add_xp(self, exp_to_add): | 634 | def add_xp(self, exp_to_add): |
610 | self.exp += exp_to_add | 635 | self.exp += exp_to_add |
636 | original_level = self.level | ||
611 | for i in range(self.level, 51): | 637 | for i in range(self.level, 51): |
612 | if self.exp >= 200 * i: | 638 | if self.exp >= 200 * i: |
613 | if i > self.level: | 639 | if i > self.level: |
614 | # We leveled up! | 640 | # We leveled up! |
615 | self.level = i | 641 | self.level = i |
616 | return (True, "Congratulations your monster leveled up!\n\nStart level: {} New Level: {}".format(self.level, i)) | ||
617 | else: | 642 | else: |
618 | break | 643 | break |
644 | if original_level > self.level: | ||
645 | return (True, "Congratulations your monster leveled up!\n\nStart level: {} New Level: {}".format(original_level, self.level)) | ||
646 | else: | ||
619 | return (False,None) | 647 | return (False,None) |
620 | 648 | ||
621 | def get_current_posture(self): | 649 | def get_current_posture(self): |
... | @@ -695,12 +723,16 @@ class Monster: | ... | @@ -695,12 +723,16 @@ class Monster: |
695 | # Get the stat for the spell and base magic accuracy for that spells MA | 723 | # Get the stat for the spell and base magic accuracy for that spells MA |
696 | magic_acc_stat = spell_data['magic_acc_stat'] | 724 | magic_acc_stat = spell_data['magic_acc_stat'] |
697 | if magic_acc_stat == 'int': | 725 | if magic_acc_stat == 'int': |
726 | print("DSTAT - INT") | ||
698 | dSTAT = self.get_intelligence() - enemy.get_intelligence() | 727 | dSTAT = self.get_intelligence() - enemy.get_intelligence() |
699 | elif magic_acc_stat == 'mnd': | 728 | elif magic_acc_stat == 'mnd': |
729 | print("DSTAT - INT") | ||
700 | dSTAT = self.get_mind() - enemy.get_mind() | 730 | dSTAT = self.get_mind() - enemy.get_mind() |
701 | elif magic_acc_stat == 'chr': | 731 | elif magic_acc_stat == 'chr': |
732 | print("DSTAT - INT") | ||
702 | dSTAT = self.get_charisma() - enemy.get_charisma() | 733 | dSTAT = self.get_charisma() - enemy.get_charisma() |
703 | elif magic_acc_stat == 'agi': | 734 | elif magic_acc_stat == 'agi': |
735 | print("DSTAT - INT") | ||
704 | dSTAT = self.get_agility() - enemy.get_agility() | 736 | dSTAT = self.get_agility() - enemy.get_agility() |
705 | 737 | ||
706 | magic_hit_rate = 50 - 0.5 * (enemy.get_magic_evasion(spell_data['damage_type']) - dSTAT) | 738 | magic_hit_rate = 50 - 0.5 * (enemy.get_magic_evasion(spell_data['damage_type']) - dSTAT) |
... | @@ -709,6 +741,8 @@ class Monster: | ... | @@ -709,6 +741,8 @@ class Monster: |
709 | magic_hit_rate = 5 | 741 | magic_hit_rate = 5 |
710 | elif magic_hit_rate > 95: | 742 | elif magic_hit_rate > 95: |
711 | magic_hit_rate = 95 | 743 | magic_hit_rate = 95 |
744 | print("DSTAT {}\nMagic Evasion: {}\nMagic hit rate: {}".format(dSTAT, enemy.get_magic_evasion(spell_data['damage_type']), magic_hit_rate)) | ||
745 | |||
712 | return magic_hit_rate | 746 | return magic_hit_rate |
713 | 747 | ||
714 | def get_pdif(self, base_damage, defense, attack_type, level_difference): | 748 | def get_pdif(self, base_damage, defense, attack_type, level_difference): |
... | @@ -905,13 +939,48 @@ class Monster: | ... | @@ -905,13 +939,48 @@ class Monster: |
905 | # Step 0: Am I already casting a spell? Is it time to calc damage from that? | 939 | # Step 0: Am I already casting a spell? Is it time to calc damage from that? |
906 | 940 | ||
907 | # Step 1: Is magic possible? | 941 | # Step 1: Is magic possible? |
908 | spell_list = Spells().get_spell_list(self.level, job=self.main_job, sub_job=self.sub_job) | ||
909 | 942 | ||
910 | # Step 2: Do i have a memory of this monster from past battles? Does it have any elemental weakness? | 943 | # Step 2: Do i have a memory of this monster from past battles? Does it have any elemental weakness? |
911 | 944 | ||
945 | spell_list = Spells().get_spell_list(self.mp, self.level, job=self.main_job, support_job=self.support_job) | ||
946 | best_spell_name = None | ||
947 | if spell_list: | ||
948 | if monster.family_name in self.battle_memory: | ||
949 | battles = self.battle_memory[monster.family_name] | ||
950 | # this assumes spells are: 'spells':{'Fire': 100, 'Stone II': 500} | ||
951 | if 'spells' in battles: | ||
952 | # if i have tried all spells then i know the right spell, otherwise try | ||
953 | # one of the ones that i don't know | ||
954 | if len(battles['spells']) == len(spell_list): | ||
955 | # get the sorted spell list by best average damage against this monster. | ||
956 | for i in max(battles['spells'].iteritems(), key=operator.itemgetter(1)): | ||
957 | best_spell_name = i | ||
958 | break | ||
959 | else: | ||
960 | untried_spells = [] | ||
961 | for i in spell_list: | ||
962 | if i not in battles['spells']: | ||
963 | untried_spells.append(i) | ||
964 | best_spell_name = random.choice(untried_spells) | ||
965 | else: | ||
966 | best_spell_name = random.choice(spell_list) | ||
967 | else: | ||
968 | best_spell_name = random.choice(spell_list) | ||
912 | # Step 3: What status effects is the monster currently under? What are the effects(DOTS) we can apply? | 969 | # Step 3: What status effects is the monster currently under? What are the effects(DOTS) we can apply? |
970 | spell_damage = 0 | ||
971 | if best_spell_name: | ||
972 | print("BEST SPELL NAME: {}".format(best_spell_name)) | ||
973 | spell_damage = self.get_magic_base_damage(best_spell_name, monster) | ||
913 | 974 | ||
914 | # find out the avg damage from each type of attack and sort them | 975 | # TODO: Make this follow the behavior in temprament and select the right behavior. |
976 | if self.tp >= 1000: | ||
977 | physical_damage = self.get_physical_ws_damage(monster.get_base_defense(), 'melee', [1.0, 1.5, 4.0], [], monster.level - self.level, monster.get_vitality()) | ||
978 | else: | ||
979 | physical_damage = self.get_physical_base_damage(monster.get_base_defense(), 'melee', monster.level - self.level, monster.get_vitality()) | ||
980 | |||
981 | return (best_spell_name, spell_damage, physical_damage) | ||
982 | |||
983 | # Step 4: find out the avg damage from each type of attack and sort them | ||
915 | 984 | ||
916 | # find out if we need to do defensive actions given the amount of life left in the enemy vs how much damage it does. | 985 | # find out if we need to do defensive actions given the amount of life left in the enemy vs how much damage it does. |
917 | # We should also store how hard the AI has hit previously and adjust accordingly (Store previous average damage per hit). IE project how much damage we will | 986 | # We should also store how hard the AI has hit previously and adjust accordingly (Store previous average damage per hit). IE project how much damage we will |
... | @@ -934,13 +1003,14 @@ class Monster: | ... | @@ -934,13 +1003,14 @@ class Monster: |
934 | resisted = False | 1003 | resisted = False |
935 | damage = 0 | 1004 | damage = 0 |
936 | 1005 | ||
937 | self.get_best_action(monster) | 1006 | # intialize the monster memory for this family name if it isn't already set. |
938 | 1007 | if monster.family_name not in self.battle_memory: | |
939 | ###### | 1008 | self.battle_memory[monster.family_name] = {'spells': {}} |
940 | # TODO: Build some type of AI / testing to find the most powerful attack and use that (magic, melee, or ranged) | 1009 | action_result = self.get_best_action(monster) |
941 | ###### | 1010 | print("AI RESULTS: {}".format(action_result)) |
942 | 1011 | # TODO: Add a nice response object from the action choice to make this code pretty. (no tuple) | |
943 | spell = 'Fire' | 1012 | if action_result[1] > action_result[2]: |
1013 | spell = action_result[0] | ||
944 | if self.is_a_magic_hit(spell, monster): | 1014 | if self.is_a_magic_hit(spell, monster): |
945 | damage = self.get_magic_base_damage(spell, monster) | 1015 | damage = self.get_magic_base_damage(spell, monster) |
946 | if damage == 0: | 1016 | if damage == 0: |
... | @@ -951,8 +1021,13 @@ class Monster: | ... | @@ -951,8 +1021,13 @@ class Monster: |
951 | self.mp -= spell_data['mp_cost'] | 1021 | self.mp -= spell_data['mp_cost'] |
952 | if self.mp < 0: | 1022 | if self.mp < 0: |
953 | self.mp = 0 | 1023 | self.mp = 0 |
1024 | # if the spell already exists then average the two damage amounts. | ||
1025 | if spell in self.battle_memory[monster.family_name]['spells']: | ||
1026 | self.battle_memory[monster.family_name]['spells'][spell] = damage + (self.battle_memory[monster.family_name]['spells'][spell]) / 2 | ||
1027 | else: | ||
1028 | self.battle_memory[monster.family_name]['spells'][spell] = damage | ||
954 | return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted) | 1029 | return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted) |
955 | 1030 | else: | |
956 | if self.is_a_hit(monster): | 1031 | if self.is_a_hit(monster): |
957 | # TODO: Make this follow the behavior in temprament and select the right behavior. | 1032 | # TODO: Make this follow the behavior in temprament and select the right behavior. |
958 | if self.tp >= 1000: | 1033 | if self.tp >= 1000: |
... | @@ -967,6 +1042,7 @@ class Monster: | ... | @@ -967,6 +1042,7 @@ class Monster: |
967 | # Returns the amount of damage and if it is a crit | 1042 | # Returns the amount of damage and if it is a crit |
968 | return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted) | 1043 | return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted) |
969 | 1044 | ||
1045 | |||
970 | def is_a_magic_hit(self, spell, monster): | 1046 | def is_a_magic_hit(self, spell, monster): |
971 | hit_rate = self.get_magic_hit_rate(spell, monster) | 1047 | hit_rate = self.get_magic_hit_rate(spell, monster) |
972 | return random.randint(1, 100) < hit_rate | 1048 | return random.randint(1, 100) < hit_rate |
... | @@ -1135,7 +1211,7 @@ class Arena: | ... | @@ -1135,7 +1211,7 @@ class Arena: |
1135 | if __name__ == "__main__": | 1211 | if __name__ == "__main__": |
1136 | #print Families | 1212 | #print Families |
1137 | 1213 | ||
1138 | print("Spell List: \n{}\n".format(Spells().get_spell_list(20, job=Jobs.BLM, sub_job=Jobs.WHM))) | 1214 | print("Spell List: \n{}\n".format(Spells().get_spell_list(100, 10, job=Jobs.RDM, support_job=Jobs.WAR))) |
1139 | hunt_response = None | 1215 | hunt_response = None |
1140 | p = Pankration() | 1216 | p = Pankration() |
1141 | print("Zones: \n\n{}".format('\n'.join(p.list_zones()))) | 1217 | print("Zones: \n\n{}".format('\n'.join(p.list_zones()))) |
... | @@ -1150,12 +1226,12 @@ if __name__ == "__main__": | ... | @@ -1150,12 +1226,12 @@ if __name__ == "__main__": |
1150 | print(hunt_response.message) | 1226 | print(hunt_response.message) |
1151 | monster = hunt_response.monster | 1227 | monster = hunt_response.monster |
1152 | monster.set_monster_name('Kickass 1') | 1228 | monster.set_monster_name('Kickass 1') |
1153 | monster.set_status_effect('int', 100, False, None) | 1229 | |
1154 | print("The Soul Plate Shows: \n\n{}".format(monster)) | 1230 | print("The Soul Plate Shows: \n\n{}".format(monster)) |
1155 | # print(monster.set_strategy(4, 3)) | 1231 | # print(monster.set_strategy(4, 3)) |
1156 | # print(monster.set_strategy(1, 1)) | 1232 | # print(monster.set_strategy(1, 1)) |
1157 | # print(monster.set_strategy(1, 2)) | 1233 | # print(monster.set_strategy(1, 2)) |
1158 | monster.add_xp(22900) | 1234 | #monster.add_xp(22900) |
1159 | # phy_damage = monster.get_physical_base_damage(100, 'melee', -15) | 1235 | # phy_damage = monster.get_physical_base_damage(100, 'melee', -15) |
1160 | # print("Phys Attack: {}".format(phy_damage)) | 1236 | # print("Phys Attack: {}".format(phy_damage)) |
1161 | # print(monster.get_base_defense()) | 1237 | # print(monster.get_base_defense()) |
... | @@ -1176,7 +1252,8 @@ if __name__ == "__main__": | ... | @@ -1176,7 +1252,8 @@ if __name__ == "__main__": |
1176 | print("1 The Soul Plate Shows: \n\n{}".format(monster)) | 1252 | print("1 The Soul Plate Shows: \n\n{}".format(monster)) |
1177 | print("2 The Soul Plate Shows: \n\n{}".format(monster2)) | 1253 | print("2 The Soul Plate Shows: \n\n{}".format(monster2)) |
1178 | print("MP m1: {}\nMP m2: {}".format(monster.get_mp(), monster2.get_mp())) | 1254 | print("MP m1: {}\nMP m2: {}".format(monster.get_mp(), monster2.get_mp())) |
1179 | monster2.add_xp(16900) | 1255 | #print(monster2.add_xp(16900)) |
1256 | #monster2.set_status_effect('int', 100, False, None) | ||
1180 | phy_damage = monster2.attack(monster) | 1257 | phy_damage = monster2.attack(monster) |
1181 | print("Phys Attack: {}".format(phy_damage)) | 1258 | print("Phys Attack: {}".format(phy_damage)) |
1182 | 1259 | ||
... | @@ -1201,12 +1278,13 @@ if __name__ == "__main__": | ... | @@ -1201,12 +1278,13 @@ if __name__ == "__main__": |
1201 | print("{} {} {} against {} for {}.".format(action.attacker.get_monster_name(), action.message, action.spell, action.target.get_monster_name(), action.damage)) | 1278 | print("{} {} {} against {} for {}.".format(action.attacker.get_monster_name(), action.message, action.spell, action.target.get_monster_name(), action.damage)) |
1202 | if isinstance(action, DefeatAction): | 1279 | if isinstance(action, DefeatAction): |
1203 | print("{} {} {} gains {} xp.".format(action.target.get_monster_name(), action.message, action.attacker.get_monster_name(), action.xp)) | 1280 | print("{} {} {} gains {} xp.".format(action.target.get_monster_name(), action.message, action.attacker.get_monster_name(), action.xp)) |
1204 | action.attacker.hp = 500 | 1281 | #print(action.attacker.add_xp(action.xp)) |
1205 | print("{} {}".format(action.target.hp, action.attacker.hp)) | 1282 | print("{} {}".format(action.target.hp, action.attacker.hp)) |
1206 | fighting = False | 1283 | fighting = False |
1207 | break | 1284 | break |
1208 | print("\n\nhp: {} {}\nmp: {} {}\n\n".format(monster.hp, monster2.hp, monster.mp, monster2.mp)) | 1285 | print("\n\nhp: {} {}\nmp: {} {}\n\n".format(monster.hp, monster2.hp, monster.mp, monster2.mp)) |
1209 | print("\n{} {}% - {} {}%\n".format(monster.get_monster_name(), monster.get_hp_percent(), monster2.get_monster_name(), monster2.get_hp_percent())) | 1286 | print("\n{} {}% - {} {}%\n".format(monster.get_monster_name(), monster.get_hp_percent(), monster2.get_monster_name(), monster2.get_hp_percent())) |
1287 | print("\n{} Memory: {}\n\n{} Memory: {}\n\n".format(monster.get_monster_name(), monster.battle_memory, monster2.get_monster_name(), monster2.battle_memory)) | ||
1210 | 1288 | ||
1211 | 1289 | ||
1212 | 1290 | ... | ... |
-
Please register or sign in to post a comment