b1760e6e by Barry

Finished the first round of feral skills.

1 parent 93d98e04
No preview for this file type
...@@ -1282,7 +1282,7 @@ def check_arena(): ...@@ -1282,7 +1282,7 @@ def check_arena():
1282 winner = 1 1282 winner = 1
1283 while fighting: 1283 while fighting:
1284 actions = battle_arena.step() 1284 actions = battle_arena.step()
1285 time.sleep(4) 1285 time.sleep(3)
1286 out_str = "" 1286 out_str = ""
1287 for action in actions: 1287 for action in actions:
1288 # TODO: Decide if I should merge magicresistaction with miss action 1288 # TODO: Decide if I should merge magicresistaction with miss action
...@@ -1306,7 +1306,7 @@ def check_arena(): ...@@ -1306,7 +1306,7 @@ def check_arena():
1306 # give a small amount to the loser 1306 # give a small amount to the loser
1307 if result: 1307 if result:
1308 out_str += xp_msg 1308 out_str += xp_msg
1309 result, xp_msg = monster2.add_xp(5) 1309 result, xp_msg = monster2.add_xp(action.losing_xp)
1310 if result: 1310 if result:
1311 out_str += xp_msg 1311 out_str += xp_msg
1312 winner = 1 1312 winner = 1
...@@ -1318,7 +1318,7 @@ def check_arena(): ...@@ -1318,7 +1318,7 @@ def check_arena():
1318 # give a small amount to the loser 1318 # give a small amount to the loser
1319 if result: 1319 if result:
1320 out_str += xp_msg 1320 out_str += xp_msg
1321 result, xp_msg = monster.add_xp(5) 1321 result, xp_msg = monster.add_xp(action.losing_xp)
1322 if result: 1322 if result:
1323 out_str += xp_msg 1323 out_str += xp_msg
1324 winner = 2 1324 winner = 2
......
...@@ -12,6 +12,7 @@ def log(message): ...@@ -12,6 +12,7 @@ def log(message):
12 except: 12 except:
13 pass 13 pass
14 14
15 ATTACK_EFFECT_PERCENTAGE = 25
15 FIND_PERCENTAGE = 100 16 FIND_PERCENTAGE = 100
16 SKILL_PERCENT = 80 17 SKILL_PERCENT = 80
17 18
...@@ -148,7 +149,80 @@ FeralSkills = { ...@@ -148,7 +149,80 @@ FeralSkills = {
148 'Accuracy +30%': {'fp_cost': 30, 'effect': 'acc', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 149 '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 '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 'AGI +25': {'fp_cost': 17, 'effect': 'agi', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
151 152 'AGI +50': {'fp_cost': 23, 'effect': 'agi', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
153 'AGI Bonus': {'fp_cost': 23, 'effect': 'agi', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
154 'Amnesia Attack': {'fp_cost': 47, 'effect': 'amnesia', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
155 'Amorph Killer': {'fp_cost': 8, 'effect': 'amorph_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
156 'Attack +15%': {'fp_cost': 23, 'effect': 'attack', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
157 'Attack Bonus': {'fp_cost': 30, 'effect': 'attack', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
158 'Auto Refresh': {'fp_cost': 38, 'effect': 'auto_refresh', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
159 'Auto Refresh +5': {'fp_cost': 30, 'effect': 'auto_refresh', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
160 'Auto Regain': {'fp_cost': 70, 'effect': 'auto_regain', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
161 'Auto Regain +3': {'fp_cost': 58, 'effect': 'auto_regain', 'amount': 3, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
162 'Auto Regen': {'fp_cost': 47, 'effect': 'auto_regen', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
163 'Auto Regen +5': {'fp_cost': 38, 'effect': 'auto_regen', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
164 'Aquan Killer': {'fp_cost': 8, 'effect': 'aquan_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
165 'Bird Killer': {'fp_cost': 8, 'effect': 'bird_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
166 'Blinding Attack': {'fp_cost': 23, 'effect': 'blind', 'amount': -20, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
167 'CHR +25': {'fp_cost': 17, 'effect': 'cha', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
168 'CHR Bonus': {'fp_cost': 23, 'effect': 'cha', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
169 'Curse Attack': {'fp_cost': 23, 'effect': 'curse', 'amount': -20, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
170 'Damage Resistance +15%': {'fp_cost': 30, 'effect': 'damage_resist', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
171 'Damage Resistance Bonus': {'fp_cost': 38, 'effect': 'damage_resist', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
172 'Dark Resistance +2': {'fp_cost': 8, 'effect': 'dark_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
173 'Dark Resistance Bonus': {'fp_cost': 12, 'effect': 'dark_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
174 'Defense +15%': {'fp_cost': 23, 'effect': 'def', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
175 'Defense Bonus': {'fp_cost': 30, 'effect': 'def', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
176 'Defense +30%': {'fp_cost': 30, 'effect': 'def', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
177 'DEX +25': {'fp_cost': 17, 'effect': 'dex', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
178 'DEX +50': {'fp_cost': 23, 'effect': 'dex', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
179 'DEX Bonus': {'fp_cost': 23, 'effect': 'dex', 'amount': 15, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
180 'Demon Killer': {'fp_cost': 8, 'effect': 'demon_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
181 'Dragon Killer': {'fp_cost': 8, 'effect': 'dragon_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
182 'Earth Resistance +2': {'fp_cost': 8, 'effect': 'earth_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
183 'Earth Resistance Bonus': {'fp_cost': 12, 'effect': 'earth_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
184 'Evasion +15%': {'fp_cost': 23, 'effect': 'eva', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
185 'Evasion Bonus': {'fp_cost': 30, 'effect': 'eva', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
186 'Fire Resistance +2': {'fp_cost': 8, 'effect': 'fire_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
187 'Fire Resistance Bonus': {'fp_cost': 12, 'effect': 'fire_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
188 'HP Max Bonus': {'fp_cost': 12, 'effect': 'hp', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
189 'HP Max +15%': {'fp_cost': 23, 'effect': 'hp', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
190 'HP Max +30%': {'fp_cost': 30, 'effect': 'hp', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
191 'HP Max +50': {'fp_cost': 8, 'effect': 'hp', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
192 'Ice Resistance +2': {'fp_cost': 8, 'effect': 'ice_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
193 'Ice Resistance Bonus': {'fp_cost': 12, 'effect': 'ice_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
194 'INT Bonus': {'fp_cost': 23, 'effect': 'int', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
195 'INT +25': {'fp_cost': 17, 'effect': 'int', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
196 'INT +50': {'fp_cost': 23, 'effect': 'int', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
197 'Light Resistance +2': {'fp_cost': 8, 'effect': 'light_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
198 'Lightning Resistance +2': {'fp_cost': 8, 'effect': 'lightning_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
199 'Lizard Killer': {'fp_cost': 8, 'effect': 'lizard_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
200 'MP Max Bonus': {'fp_cost': 17, 'effect': 'mp', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
201 'MP Max +15%': {'fp_cost': 12, 'effect': 'mp', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
202 'MP Max +50': {'fp_cost': 5, 'effect': 'mp', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
203 'Magic Accuracy Bonus': {'fp_cost': 30, 'effect': 'magic_acc', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
204 'Magic Accuracy 15%': {'fp_cost': 23, 'effect': 'magic_acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
205 'Magic Attack Bonus': {'fp_cost': 30, 'effect': 'magic_attack', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
206 'Magic Attack +15%': {'fp_cost': 23, 'effect': 'magic_attack', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
207 'MND Bonus': {'fp_cost': 23, 'effect': 'mnd', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
208 'MND +25': {'fp_cost': 17, 'effect': 'mnd', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
209 'MND +50': {'fp_cost': 23, 'effect': 'mnd', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
210 'Poisoning Attack': {'fp_cost': 17, 'effect': 'poison', 'amount': -4, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
211 'Plantoid Killer': {'fp_cost': 8, 'effect': 'plantoid_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
212 'Silencing Attack': {'fp_cost': 30, 'effect': 'silence', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
213 'Store TP +10%': {'fp_cost': 38, 'effect': 'store_tp', 'amount': 10, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
214 'STR Bonus': {'fp_cost': 23, 'effect': 'str', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
215 'STR +25': {'fp_cost': 17, 'effect': 'str', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
216 'STR +50': {'fp_cost': 23, 'effect': 'str', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
217 'Undead Killer': {'fp_cost': 8, 'effect': 'undead_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
218 'Vermin Killer': {'fp_cost': 8, 'effect': 'vermin_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
219 'VIT Bonus': {'fp_cost': 23, 'effect': 'vit', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
220 'VIT +25': {'fp_cost': 17, 'effect': 'vit', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
221 'VIT +50': {'fp_cost': 23, 'effect': 'vit', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
222 'Water Resistance +2': {'fp_cost': 8, 'effect': 'water_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
223 'Water Resistance Bonus': {'fp_cost': 12, 'effect': 'water_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
224 'Wind Resistance +2': {'fp_cost': 8, 'effect': 'wind_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
225 'Wind Resistance Bonus': {'fp_cost': 12, 'effect': 'wind_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
152 } 226 }
153 227
154 class Spells: 228 class Spells:
...@@ -199,9 +273,10 @@ class Spells: ...@@ -199,9 +273,10 @@ class Spells:
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} }, 273 '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} },
200 } 274 }
201 275
202 def get_spell_list(self, mp, level, job = None, support_job = None): 276 @staticmethod
277 def get_spell_list(mp, level, job = None, support_job = None):
203 available_spells = [] 278 available_spells = []
204 for spell_name, spell in self.SpellList.iteritems(): 279 for spell_name, spell in Spells.SpellList.iteritems():
205 if job and job in spell['jobs'] and spell['jobs'][job] <= level: 280 if job and job in spell['jobs'] and spell['jobs'][job] <= level:
206 if spell_name not in available_spells: 281 if spell_name not in available_spells:
207 if spell['mp_cost'] < mp: 282 if spell['mp_cost'] < mp:
...@@ -212,9 +287,10 @@ class Spells: ...@@ -212,9 +287,10 @@ class Spells:
212 available_spells.append(spell_name) 287 available_spells.append(spell_name)
213 return sorted(available_spells) 288 return sorted(available_spells)
214 289
215 def get_spell_data(self, spell): 290 @staticmethod
216 spell = self.SpellList[spell] 291 def get_spell_data(spell):
217 type_data = self.SpellTypes[spell['spell_type']] 292 spell = Spells.SpellList[spell]
293 type_data = Spells.SpellTypes[spell['spell_type']]
218 spell_data = { 294 spell_data = {
219 'type': type_data, 295 'type': type_data,
220 'magic_acc_stat': spell['magic_acc_stat'], 296 'magic_acc_stat': spell['magic_acc_stat'],
...@@ -527,15 +603,16 @@ class Pankration: ...@@ -527,15 +603,16 @@ class Pankration:
527 return "" 603 return ""
528 604
529 class AttackResponse: 605 class AttackResponse:
530 def __init__(self, is_a_hit, damage, is_a_crit, spell, resisted): 606 def __init__(self, is_a_hit, damage, is_a_crit, spell, resisted, intimidated):
531 self.spell = spell 607 self.spell = spell
532 self.is_a_crit = is_a_crit 608 self.is_a_crit = is_a_crit
533 self.is_a_hit = is_a_hit 609 self.is_a_hit = is_a_hit
534 self.resisted = resisted 610 self.resisted = resisted
611 self.intimidated = intimidated
535 self.damage = damage 612 self.damage = damage
536 613
537 def __str__(self): 614 def __str__(self):
538 return "Spell: {} Resisted: {} Is a Hit: {} Is a Crit: {} Damage: {}".format(self.spell, self.resisted, self.is_a_hit, self.is_a_crit, self.damage) 615 return "Spell: {} Resisted: {} Is a Hit: {} Is a Crit: {} Damage: {} intimidated: {}".format(self.spell, self.resisted, self.is_a_hit, self.is_a_crit, self.damage, self.intimidated)
539 616
540 class Monster: 617 class Monster:
541 def __init__(self, monster_type, family_name, family, base_hp, base_mp, level, weapon_base_damage, main_job, 618 def __init__(self, monster_type, family_name, family, base_hp, base_mp, level, weapon_base_damage, main_job,
...@@ -553,6 +630,14 @@ class Monster: ...@@ -553,6 +630,14 @@ class Monster:
553 self.support_job = support_job 630 self.support_job = support_job
554 self.innate_feral_skills = innate_feral_skills 631 self.innate_feral_skills = innate_feral_skills
555 self.equipped_feral_skills = equipped_feral_skills 632 self.equipped_feral_skills = equipped_feral_skills
633
634 effects = self.get_status_effect_list()
635 for feral_skill in innate_feral_skills + equipped_feral_skills:
636 effect = effects[FeralSkills[feral_skill]['effect']]
637 # Should init = true
638 if effect:
639 self.apply_feral_skill(feral_skill)
640
556 self.discipline_level = dicipline_level 641 self.discipline_level = dicipline_level
557 self.temperament_posture = family['temperament_posture']['initial_value'] 642 self.temperament_posture = family['temperament_posture']['initial_value']
558 self.temperament_attitude = family['temperament_attitude']['initial_value'] 643 self.temperament_attitude = family['temperament_attitude']['initial_value']
...@@ -615,7 +700,9 @@ class Monster: ...@@ -615,7 +700,9 @@ class Monster:
615 700
616 def get_hp(self): 701 def get_hp(self):
617 #this is a bit dumb but it's close enough. 702 #this is a bit dumb but it's close enough.
618 return self.get_status_effect('hp', int((self.level * 20) + self.base_hp)) 703 return self.get_status_effect('curse',
704 self.get_status_effect('hp',
705 int((self.level * 20) + self.base_hp)))
619 706
620 def get_mp(self): 707 def get_mp(self):
621 #this is a bit dumb but it's close enough. 708 #this is a bit dumb but it's close enough.
...@@ -625,7 +712,8 @@ class Monster: ...@@ -625,7 +712,8 @@ class Monster:
625 712
626 main_mp = int((self.level * (self.base_mp + main_add_amount)) + self.base_mp) 713 main_mp = int((self.level * (self.base_mp + main_add_amount)) + self.base_mp)
627 sub_mp = int((self.level/2) * sub_add_amount) 714 sub_mp = int((self.level/2) * sub_add_amount)
628 return self.get_status_effect('mp', main_mp + sub_mp) 715 return self.get_status_effect('curse',
716 self.get_status_effect('mp', main_mp + sub_mp))
629 717
630 718
631 def get_fp(self): 719 def get_fp(self):
...@@ -711,6 +799,7 @@ class Monster: ...@@ -711,6 +799,7 @@ class Monster:
711 799
712 def get_hit_rate(self, enemy_eva, level_difference): 800 def get_hit_rate(self, enemy_eva, level_difference):
713 rate = 75 + math.floor(((self.get_accuracy() - enemy_eva)/2)) - (2*level_difference) 801 rate = 75 + math.floor(((self.get_accuracy() - enemy_eva)/2)) - (2*level_difference)
802 rate = self.get_status_effect('blind', rate)
714 if rate < 20: 803 if rate < 20:
715 rate = 20 804 rate = 20
716 elif rate > 95: 805 elif rate > 95:
...@@ -719,7 +808,7 @@ class Monster: ...@@ -719,7 +808,7 @@ class Monster:
719 808
720 def get_magic_hit_rate(self, spell, enemy): 809 def get_magic_hit_rate(self, spell, enemy):
721 # Calculate the magic accuracy 810 # Calculate the magic accuracy
722 spell_data = Spells().get_spell_data(spell) 811 spell_data = Spells.get_spell_data(spell)
723 # Get the stat for the spell and base magic accuracy for that spells MA 812 # Get the stat for the spell and base magic accuracy for that spells MA
724 magic_acc_stat = spell_data['magic_acc_stat'] 813 magic_acc_stat = spell_data['magic_acc_stat']
725 if magic_acc_stat == 'int': 814 if magic_acc_stat == 'int':
...@@ -736,6 +825,7 @@ class Monster: ...@@ -736,6 +825,7 @@ class Monster:
736 dSTAT = self.get_agility() - enemy.get_agility() 825 dSTAT = self.get_agility() - enemy.get_agility()
737 826
738 magic_hit_rate = 50 - 0.5 * (enemy.get_magic_evasion(spell_data['damage_type']) - dSTAT) 827 magic_hit_rate = 50 - 0.5 * (enemy.get_magic_evasion(spell_data['damage_type']) - dSTAT)
828 magic_hit_rate = self.get_status_effect('magic_acc', magic_hit_rate)
739 829
740 if magic_hit_rate < 5: 830 if magic_hit_rate < 5:
741 magic_hit_rate = 5 831 magic_hit_rate = 5
...@@ -848,7 +938,7 @@ class Monster: ...@@ -848,7 +938,7 @@ class Monster:
848 else: 938 else:
849 dINT = self.get_intelligence() - enemy.get_intelligence() 939 dINT = self.get_intelligence() - enemy.get_intelligence()
850 940
851 spell_data = Spells().get_spell_data(spell) 941 spell_data = Spells.get_spell_data(spell)
852 942
853 base_damage = 0 943 base_damage = 0
854 if dINT < 0: 944 if dINT < 0:
...@@ -876,6 +966,14 @@ class Monster: ...@@ -876,6 +966,14 @@ class Monster:
876 966
877 return base_damage 967 return base_damage
878 968
969 def apply_feral_skill(self, feral_skill):
970 # 'Amnesia Attack': {'fp_cost': 47, 'effect': 'amnesia', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
971 fs = FeralSkills[feral_skill]
972 self.set_status_effect(fs['effect'], fs['amount'], fs['is_percent'], fs['expires_seconds'])
973 if feral_skill == 'Curse Attack':
974 self.hp = min(self.hp, self.get_hp())
975 self.mp = min(self.mp, self.get_mp())
976
879 # it is up to the rest of the system to understand how to read this data and act on it. 977 # it is up to the rest of the system to understand how to read this data and act on it.
880 # Example Call: ('acc', '10', False, 30) 978 # Example Call: ('acc', '10', False, 30)
881 def set_status_effect(self, effect, amount, is_percent, expires_seconds): 979 def set_status_effect(self, effect, amount, is_percent, expires_seconds):
...@@ -892,30 +990,52 @@ class Monster: ...@@ -892,30 +990,52 @@ class Monster:
892 else: 990 else:
893 return base_amount 991 return base_amount
894 992
895 # This is a list of all status effects that are available. 993 # This is a list of all status effects that are available and if they should be auto intialized.
896 def get_status_effect_list(self): 994 def get_status_effect_list(self):
897 return [ 995 return {
898 'acc', 996 'acc': True,
899 'agi', 997 'agi': True,
900 'cha', 998 'cha': True,
901 'def', 999 'def': True,
902 'dex', 1000 'dex': True,
903 'eva', 1001 'eva': True,
904 'hp', 1002 'hp': True,
905 'int', 1003 'int': True,
906 'mnd', 1004 'mnd': True,
907 'mp', 1005 'mp': True,
908 'str', 1006 'str': True,
909 'vit', 1007 'vit': True,
910 'fire_resist', 1008 'store_tp': True,
911 'water_resist', 1009 'fire_resist': True,
912 'ice_resist', 1010 'water_resist': True,
913 'wind_resist', 1011 'ice_resist': True,
914 'earth_resist', 1012 'wind_resist': True,
915 'thunder_resist', 1013 'earth_resist': True,
916 'light_resist', 1014 'thunder_resist': True,
917 'dark_resist' 1015 'light_resist': True,
918 ] 1016 'dark_resist': True,
1017 'damage_resist': True,
1018 'auto_refresh': True,
1019 'auto_regain': True,
1020 'auto_regen': True,
1021 'amnesia': False,
1022 'amorph_killer': False,
1023 'aquan_killer': False,
1024 'bird_killer': False,
1025 'demon_killer': False,
1026 'dragon_killer': False,
1027 'lizard_killer': False,
1028 'plantoid_killer': False,
1029 'undead_killer': False,
1030 'vermin_killer': False,
1031 'attack': False,
1032 'blind': False,
1033 'curse': False,
1034 'poison': False,
1035 'silence': False,
1036 'magic_acc': True,
1037 'magic_attack': True,
1038 }
919 1039
920 # Calculate the base damage against the provided defense 1040 # Calculate the base damage against the provided defense
921 # attack_type can be 'ranged' or 'melee' 1041 # attack_type can be 'ranged' or 'melee'
...@@ -942,9 +1062,9 @@ class Monster: ...@@ -942,9 +1062,9 @@ class Monster:
942 1062
943 # Step 2: Do i have a memory of this monster from past battles? Does it have any elemental weakness? 1063 # Step 2: Do i have a memory of this monster from past battles? Does it have any elemental weakness?
944 1064
945 spell_list = Spells().get_spell_list(self.mp, self.level, job=self.main_job, support_job=self.support_job) 1065 spell_list = Spells.get_spell_list(self.mp, self.level, job=self.main_job, support_job=self.support_job)
946 best_spell_name = None 1066 best_spell_name = None
947 if spell_list: 1067 if spell_list and 'silence' not in self.status_effects:
948 if monster.family_name in self.battle_memory: 1068 if monster.family_name in self.battle_memory:
949 battles = self.battle_memory[monster.family_name] 1069 battles = self.battle_memory[monster.family_name]
950 # this assumes spells are: 'spells':{'Fire': 100, 'Stone II': 500} 1070 # this assumes spells are: 'spells':{'Fire': 100, 'Stone II': 500}
...@@ -1001,8 +1121,12 @@ class Monster: ...@@ -1001,8 +1121,12 @@ class Monster:
1001 is_a_hit = False 1121 is_a_hit = False
1002 spell = None 1122 spell = None
1003 resisted = False 1123 resisted = False
1124 intimidated = False
1004 damage = 0 1125 damage = 0
1005 1126
1127 if self.unable_to_move(monster):
1128 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted, True)
1129
1006 # intialize the monster memory for this family name if it isn't already set. 1130 # intialize the monster memory for this family name if it isn't already set.
1007 if monster.family_name not in self.battle_memory: 1131 if monster.family_name not in self.battle_memory:
1008 self.battle_memory[monster.family_name] = {'spells': {}} 1132 self.battle_memory[monster.family_name] = {'spells': {}}
...@@ -1015,9 +1139,10 @@ class Monster: ...@@ -1015,9 +1139,10 @@ class Monster:
1015 damage = self.get_magic_base_damage(spell, monster) 1139 damage = self.get_magic_base_damage(spell, monster)
1016 if damage == 0: 1140 if damage == 0:
1017 resisted = True 1141 resisted = True
1142 damage = self.get_status_effect('magic_attack', damage)
1018 log("MAGIC DAMAGE: {}".format(damage)) 1143 log("MAGIC DAMAGE: {}".format(damage))
1019 is_a_hit = True 1144 is_a_hit = True
1020 spell_data = Spells().get_spell_data(spell) 1145 spell_data = Spells.get_spell_data(spell)
1021 self.mp -= spell_data['mp_cost'] 1146 self.mp -= spell_data['mp_cost']
1022 if self.mp < 0: 1147 if self.mp < 0:
1023 self.mp = 0 1148 self.mp = 0
...@@ -1026,22 +1151,45 @@ class Monster: ...@@ -1026,22 +1151,45 @@ class Monster:
1026 self.battle_memory[monster.family_name]['spells'][spell] = damage + (self.battle_memory[monster.family_name]['spells'][spell]) / 2 1151 self.battle_memory[monster.family_name]['spells'][spell] = damage + (self.battle_memory[monster.family_name]['spells'][spell]) / 2
1027 else: 1152 else:
1028 self.battle_memory[monster.family_name]['spells'][spell] = damage 1153 self.battle_memory[monster.family_name]['spells'][spell] = damage
1029 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted) 1154 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted, intimidated)
1030 else: 1155 else:
1031 if self.is_a_hit(monster): 1156 if self.is_a_hit(monster):
1032 # TODO: Make this follow the behavior in temprament and select the right behavior. 1157 if random.randint(1, 100) < ATTACK_EFFECT_PERCENTAGE: # 50% chance of applying the effects "XXX Attack"
1033 if self.tp >= 1000: 1158 if 'Amnesia Attack' in self.equipped_feral_skills:
1159 monster.apply_feral_skill('Amnesia Attack')
1160 if 'Blinding Attack' in self.equipped_feral_skills:
1161 monster.apply_feral_skill('Blinding Attack')
1162 if 'Curse Attack' in self.equipped_feral_skills:
1163 monster.apply_feral_skill('Curse Attack')
1164 if 'Poisoning Attack' in self.equipped_feral_skills:
1165 monster.apply_feral_skill('Poisoning Attack')
1166 if 'Silencing Attack' in self.equipped_feral_skills:
1167 monster.apply_feral_skill('Silencing Attack')
1168
1169 # TODO: Make this follow the behavior in temperament and select the right behavior.
1170 if self.tp >= 1000 and not self.get_status_effect('amnesia', 0):
1034 damage = self.get_physical_ws_damage(monster.get_base_defense(), 'melee', [1.0, 1.5, 4.0], [], monster.level - self.level, monster.get_vitality()) 1171 damage = self.get_physical_ws_damage(monster.get_base_defense(), 'melee', [1.0, 1.5, 4.0], [], monster.level - self.level, monster.get_vitality())
1035 log("WS DAMAGE: {}".format(damage)) 1172 log("WS DAMAGE: {}".format(damage))
1036 self.tp = 0 1173 self.tp = 0
1037 else: 1174 else:
1038 damage = self.get_physical_base_damage(monster.get_base_defense(), 'melee', monster.level - self.level, monster.get_vitality()) 1175 damage = self.get_physical_base_damage(monster.get_base_defense(), 'melee', monster.level - self.level, monster.get_vitality())
1039 print("STD DAMAGE: {}".format(damage)) 1176 print("STD DAMAGE: {}".format(damage))
1040 self.tp += 64 1177 self.tp += self.get_status_effect('store_tp', 64)
1178 damage = self.get_status_effect('damage_resist', damage)
1041 is_a_hit = True 1179 is_a_hit = True
1042 # Returns the amount of damage and if it is a crit 1180 # Returns the amount of damage and if it is a crit
1043 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted) 1181 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted, intimidated)
1182
1183 # This determines if a monster is paralized or intimidated and unable to act.
1184 def unable_to_move(self, monster):
1185 killer_type = "{}_{}".format(monster.family['type'], "killer").lower()
1186 if killer_type in self.status_effects:
1187 if random.randint(1, 100) < self.status_effects[killer_type]['amount']:
1188 return True
1189 return False
1190 #if
1044 1191
1192 #monster.family['type'] == killer
1045 1193
1046 def is_a_magic_hit(self, spell, monster): 1194 def is_a_magic_hit(self, spell, monster):
1047 hit_rate = self.get_magic_hit_rate(spell, monster) 1195 hit_rate = self.get_magic_hit_rate(spell, monster)
...@@ -1058,6 +1206,15 @@ class Monster: ...@@ -1058,6 +1206,15 @@ class Monster:
1058 else: 1206 else:
1059 self.tp += 30 1207 self.tp += 30
1060 1208
1209 def apply_per_tick_adjustment(self):
1210 # apply all healing first
1211 self.mp = self.get_status_effect('auto_refresh', self.mp)
1212 self.tp = self.get_status_effect('auto_regain', self.tp)
1213 self.hp = self.get_status_effect('auto_regen', self.hp)
1214
1215 # apply DOTs
1216 self.hp = self.get_status_effect('poison', self.hp)
1217
1061 # This should ONLY be executed at the start of battle. 1218 # This should ONLY be executed at the start of battle.
1062 def set_strategy(self, temperament_posture, temperament_attitude): 1219 def set_strategy(self, temperament_posture, temperament_attitude):
1063 distance_from_nature = abs(self.temperament_posture - temperament_posture) 1220 distance_from_nature = abs(self.temperament_posture - temperament_posture)
...@@ -1114,6 +1271,14 @@ class MagicResistAction(Action): ...@@ -1114,6 +1271,14 @@ class MagicResistAction(Action):
1114 self.spell = spell 1271 self.spell = spell
1115 self.message = random.choice(MagicResistAction.MESSAGES) 1272 self.message = random.choice(MagicResistAction.MESSAGES)
1116 1273
1274
1275 class IntimidatedAction(Action):
1276 MESSAGES = ['was unable to act']
1277
1278 def __init__(self, attacker):
1279 self.attacker = attacker
1280 self.message = random.choice(IntimidatedAction.MESSAGES)
1281
1117 class MissAction(Action): 1282 class MissAction(Action):
1118 MAGIC_MESSAGES = ['fizzled the spell against'] 1283 MAGIC_MESSAGES = ['fizzled the spell against']
1119 MESSAGES = ['missed', 'was unable to hit', 'attack went wide of', 'fumbled the hit on'] 1284 MESSAGES = ['missed', 'was unable to hit', 'attack went wide of', 'fumbled the hit on']
...@@ -1130,11 +1295,12 @@ class MissAction(Action): ...@@ -1130,11 +1295,12 @@ class MissAction(Action):
1130 class DefeatAction(Action): 1295 class DefeatAction(Action):
1131 MESSAGES = ['was defeated', 'was smited', 'was conquered', 'was routed', 'was thwarted', 1296 MESSAGES = ['was defeated', 'was smited', 'was conquered', 'was routed', 'was thwarted',
1132 'was vanquished', 'was bested'] 1297 'was vanquished', 'was bested']
1133 def __init__(self, attacker, target, xp): 1298 def __init__(self, attacker, target, xp, losing_xp):
1134 self.attacker = attacker 1299 self.attacker = attacker
1135 self.target = target 1300 self.target = target
1136 self.message = random.choice(DefeatAction.MESSAGES) 1301 self.message = random.choice(DefeatAction.MESSAGES)
1137 self.xp = xp 1302 self.xp = xp
1303 self.losing_xp = xp
1138 1304
1139 1305
1140 class Arena: 1306 class Arena:
...@@ -1167,12 +1333,16 @@ class Arena: ...@@ -1167,12 +1333,16 @@ class Arena:
1167 1333
1168 #if primary.is_a_magic_hit(spell, secondary) 1334 #if primary.is_a_magic_hit(spell, secondary)
1169 result1 = primary.attack(secondary) 1335 result1 = primary.attack(secondary)
1170 if result1.resisted: 1336 if result1.intimidated:
1337 actions.append(IntimidatedAction(primary))
1338 elif result1.resisted:
1171 actions.append(MagicResistAction(primary, secondary, result1.spell)) 1339 actions.append(MagicResistAction(primary, secondary, result1.spell))
1172 elif result1.is_a_hit: 1340 elif result1.is_a_hit:
1173 secondary.apply_damage(result1.damage) 1341 secondary.apply_damage(result1.damage)
1174 actions.append(AttackAction(primary, secondary, result1.damage, result1.is_a_crit, 1342 actions.append(AttackAction(primary, secondary, result1.damage, result1.is_a_crit,
1175 result1.spell)) 1343 result1.spell))
1344 # apply healing then dots to make sure secondary survived.
1345 secondary.apply_per_tick_adjustment()
1176 if secondary.hp <= 0: 1346 if secondary.hp <= 0:
1177 level_difference = secondary.level - primary.level 1347 level_difference = secondary.level - primary.level
1178 if level_difference in exp_table: 1348 if level_difference in exp_table:
...@@ -1181,18 +1351,26 @@ class Arena: ...@@ -1181,18 +1351,26 @@ class Arena:
1181 xp = exp_table[15] 1351 xp = exp_table[15]
1182 else: 1352 else:
1183 xp = 0 1353 xp = 0
1184 actions.append(DefeatAction(primary, secondary, xp)) 1354 losing_xp = max(5, 11*level_difference)
1355 if losing_xp > 75:
1356 losing_xp = 75
1357
1358 actions.append(DefeatAction(primary, secondary, xp, losing_xp))
1185 return actions 1359 return actions
1186 else: 1360 else:
1187 actions.append(MissAction(primary, secondary, result1.spell)) 1361 actions.append(MissAction(primary, secondary, result1.spell))
1188 1362
1189 result2 = secondary.attack(primary) 1363 result2 = secondary.attack(primary)
1190 if result2.resisted: 1364 if result2.intimidated:
1365 actions.append(IntimidatedAction(secondary))
1366 elif result2.resisted:
1191 actions.append(MagicResistAction(secondary, primary, result2.spell)) 1367 actions.append(MagicResistAction(secondary, primary, result2.spell))
1192 elif result2.is_a_hit: 1368 elif result2.is_a_hit:
1193 primary.apply_damage(result2.damage) 1369 primary.apply_damage(result2.damage)
1194 actions.append(AttackAction(secondary, primary, result2.damage, result2.is_a_crit, 1370 actions.append(AttackAction(secondary, primary, result2.damage, result2.is_a_crit,
1195 result2.spell)) 1371 result2.spell))
1372 tick_result = primary.apply_per_tick_adjustment()
1373
1196 if primary.hp <= 0: 1374 if primary.hp <= 0:
1197 level_difference = primary.level - secondary.level 1375 level_difference = primary.level - secondary.level
1198 if level_difference in exp_table: 1376 if level_difference in exp_table:
...@@ -1201,7 +1379,10 @@ class Arena: ...@@ -1201,7 +1379,10 @@ class Arena:
1201 xp = exp_table[15] 1379 xp = exp_table[15]
1202 else: 1380 else:
1203 xp = 0 1381 xp = 0
1204 actions.append(DefeatAction(secondary, primary, xp)) 1382 losing_xp = max(5, 11*level_difference)
1383 if losing_xp > 75:
1384 losing_xp = 75
1385 actions.append(DefeatAction(secondary, primary, xp, losing_xp))
1205 return actions 1386 return actions
1206 else: 1387 else:
1207 actions.append(MissAction(secondary, primary, result2.spell)) 1388 actions.append(MissAction(secondary, primary, result2.spell))
...@@ -1211,7 +1392,7 @@ class Arena: ...@@ -1211,7 +1392,7 @@ class Arena:
1211 if __name__ == "__main__": 1392 if __name__ == "__main__":
1212 #print Families 1393 #print Families
1213 1394
1214 print("Spell List: \n{}\n".format(Spells().get_spell_list(100, 10, job=Jobs.RDM, support_job=Jobs.WAR))) 1395 print("Spell List: \n{}\n".format(Spells.get_spell_list(100, 10, job=Jobs.RDM, support_job=Jobs.WAR)))
1215 hunt_response = None 1396 hunt_response = None
1216 p = Pankration() 1397 p = Pankration()
1217 print("Zones: \n\n{}".format('\n'.join(p.list_zones()))) 1398 print("Zones: \n\n{}".format('\n'.join(p.list_zones())))
...@@ -1226,6 +1407,7 @@ if __name__ == "__main__": ...@@ -1226,6 +1407,7 @@ if __name__ == "__main__":
1226 print(hunt_response.message) 1407 print(hunt_response.message)
1227 monster = hunt_response.monster 1408 monster = hunt_response.monster
1228 monster.set_monster_name('Kickass 1') 1409 monster.set_monster_name('Kickass 1')
1410 monster.set_status_effect('demon_killer', 50, False, None)
1229 1411
1230 print("The Soul Plate Shows: \n\n{}".format(monster)) 1412 print("The Soul Plate Shows: \n\n{}".format(monster))
1231 # print(monster.set_strategy(4, 3)) 1413 # print(monster.set_strategy(4, 3))
...@@ -1253,9 +1435,11 @@ if __name__ == "__main__": ...@@ -1253,9 +1435,11 @@ if __name__ == "__main__":
1253 print("2 The Soul Plate Shows: \n\n{}".format(monster2)) 1435 print("2 The Soul Plate Shows: \n\n{}".format(monster2))
1254 print("MP m1: {}\nMP m2: {}".format(monster.get_mp(), monster2.get_mp())) 1436 print("MP m1: {}\nMP m2: {}".format(monster.get_mp(), monster2.get_mp()))
1255 #print(monster2.add_xp(16900)) 1437 #print(monster2.add_xp(16900))
1256 #monster2.set_status_effect('int', 100, False, None) 1438 monster2.set_status_effect('demon_killer', 50, False, None)
1257 phy_damage = monster2.attack(monster) 1439 phy_damage = monster2.attack(monster)
1258 print("Phys Attack: {}".format(phy_damage)) 1440 print("Phys Attack: {}".format(phy_damage))
1441 phy_damage = monster.attack(monster2)
1442 print("Phys Attack2: {}".format(phy_damage))
1259 1443
1260 1444
1261 print("Acc: {}".format(monster.get_accuracy())) 1445 print("Acc: {}".format(monster.get_accuracy()))
...@@ -1268,8 +1452,10 @@ if __name__ == "__main__": ...@@ -1268,8 +1452,10 @@ if __name__ == "__main__":
1268 fighting = True 1452 fighting = True
1269 while fighting: 1453 while fighting:
1270 actions = battle_arena.step() 1454 actions = battle_arena.step()
1271 time.sleep(2) 1455 time.sleep(3)
1272 for action in actions: 1456 for action in actions:
1457 if isinstance(action, IntimidatedAction):
1458 print("{} {}.".format(action.attacker.get_monster_name(), action.message))
1273 if isinstance(action, MagicResistAction): 1459 if isinstance(action, MagicResistAction):
1274 print("{} {} {} while casting {}.".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.spell)) 1460 print("{} {} {} while casting {}.".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.spell))
1275 if isinstance(action, MissAction): 1461 if isinstance(action, MissAction):
......