612192b6 by Barry

Most of the magic system is now in place.

1 parent 03403a56
...@@ -67,6 +67,7 @@ def db_buy_ticket(member_id, amount): ...@@ -67,6 +67,7 @@ def db_buy_ticket(member_id, amount):
67 return True, int(credits[1]) + int(amount) 67 return True, int(credits[1]) + int(amount)
68 except Exception as e: 68 except Exception as e:
69 log(e) 69 log(e)
70
70 def db_update_credit(member_id, amount): 71 def db_update_credit(member_id, amount):
71 conn = sqlite3.connect('db.sqlite3') 72 conn = sqlite3.connect('db.sqlite3')
72 c = conn.cursor() 73 c = conn.cursor()
...@@ -168,7 +169,6 @@ def db_get_fortune(): ...@@ -168,7 +169,6 @@ def db_get_fortune():
168 try: 169 try:
169 conn = sqlite3.connect('db.sqlite3') 170 conn = sqlite3.connect('db.sqlite3')
170 c = conn.cursor() 171 c = conn.cursor()
171 # TODO: Move this shit to data
172 return c.execute("SELECT fortune FROM fortunes ORDER BY RANDOM() LIMIT 1;").fetchone()[0] 172 return c.execute("SELECT fortune FROM fortunes ORDER BY RANDOM() LIMIT 1;").fetchone()[0]
173 finally: 173 finally:
174 conn.close() 174 conn.close()
...@@ -192,7 +192,6 @@ def db_get_fortune(): ...@@ -192,7 +192,6 @@ def db_get_fortune():
192 try: 192 try:
193 conn = sqlite3.connect('db.sqlite3') 193 conn = sqlite3.connect('db.sqlite3')
194 c = conn.cursor() 194 c = conn.cursor()
195 # TODO: Move this shit to data
196 return c.execute("SELECT fortune FROM fortunes ORDER BY RANDOM() LIMIT 1;").fetchone()[0] 195 return c.execute("SELECT fortune FROM fortunes ORDER BY RANDOM() LIMIT 1;").fetchone()[0]
197 finally: 196 finally:
198 conn.close() 197 conn.close()
......
No preview for this file type
...@@ -27,7 +27,7 @@ import wolframalpha ...@@ -27,7 +27,7 @@ import wolframalpha
27 import sqlite3 27 import sqlite3
28 from blackjack import Blackjack 28 from blackjack import Blackjack
29 import data 29 import data
30 from pankration import Pankration, HuntResponse, Jobs, Action, MissAction, AttackAction, DefeatAction, TemperamentPosture, TemperamentAttitude 30 from pankration import Pankration, HuntResponse, Jobs, Action, MagicResistAction, MissAction, AttackAction, DefeatAction, TemperamentPosture, TemperamentAttitude
31 31
32 VERSION = 2.3 32 VERSION = 2.3
33 33
...@@ -1203,7 +1203,7 @@ def do_hunt_monster(client, message_parts, message): ...@@ -1203,7 +1203,7 @@ def do_hunt_monster(client, message_parts, message):
1203 if not result: 1203 if not result:
1204 send_message(client, message.author, error_message) 1204 send_message(client, message.author, error_message)
1205 return 1205 return
1206 send_message(client, message.channel, 'Soul Plate purchased for {} credits\n Hunting in {}'.format(cost, zone)) 1206 send_message(client, message.channel, '{} Soul Plate purchased for {} credits\n Hunting in {}'.format(message.author.name, cost, zone))
1207 time.sleep(3) 1207 time.sleep(3)
1208 hunt_response = p.hunt_monster(' '.join(message_parts)) 1208 hunt_response = p.hunt_monster(' '.join(message_parts))
1209 str_out = hunt_response.message + "\n\n" 1209 str_out = hunt_response.message + "\n\n"
...@@ -1212,7 +1212,7 @@ def do_hunt_monster(client, message_parts, message): ...@@ -1212,7 +1212,7 @@ def do_hunt_monster(client, message_parts, message):
1212 member = data.db_get_member(message.author.id) 1212 member = data.db_get_member(message.author.id)
1213 data.db_add_soul_plate(member['member_id'], soul_plate) 1213 data.db_add_soul_plate(member['member_id'], soul_plate)
1214 str_out += str(soul_plate.get_soul_plate_description()) 1214 str_out += str(soul_plate.get_soul_plate_description())
1215 send_message(client, message.channel, str_out) 1215 send_message(client, message.channel, "{} {}".format(message.author.name, str_out))
1216 1216
1217 1217
1218 def do_list_zones(client, message_parts, message): 1218 def do_list_zones(client, message_parts, message):
...@@ -1271,12 +1271,20 @@ def check_arena(): ...@@ -1271,12 +1271,20 @@ def check_arena():
1271 time.sleep(4) 1271 time.sleep(4)
1272 out_str = "" 1272 out_str = ""
1273 for action in actions: 1273 for action in actions:
1274 # TODO: Decide if I should merge magicresistaction with miss action
1275 if isinstance(action, MagicResistAction):
1276 out_str += "{} {} {} while casting {}.\n".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.spell)
1274 if isinstance(action, MissAction): 1277 if isinstance(action, MissAction):
1275 out_str += "{} {} {}.\n".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name()) 1278 if action.spell:
1279 out_str += "{} {} {} while casting {}.\n".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.spell)
1280 else:
1281 out_str += "{} {} {}.\n".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name())
1276 if isinstance(action, AttackAction): 1282 if isinstance(action, AttackAction):
1277 out_str += "{} {} {} for {}.\n".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), int(action.damage)) 1283 if action.spell:
1284 out_str += "{} {} {} against {} for {}.\n".format(action.attacker.get_monster_name(), action.message, action.spell, action.target.get_monster_name(), int(action.damage))
1285 else:
1286 out_str += "{} {} {} for {}.\n".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), int(action.damage))
1278 if isinstance(action, DefeatAction): 1287 if isinstance(action, DefeatAction):
1279
1280 out_str += "\n\n**{}** {}. {} gains {} xp.\n\n".format(action.target.get_monster_name(), action.message, action.attacker.get_monster_name(), action.xp) 1288 out_str += "\n\n**{}** {}. {} gains {} xp.\n\n".format(action.target.get_monster_name(), action.message, action.attacker.get_monster_name(), action.xp)
1281 fighting = False 1289 fighting = False
1282 if action.attacker == monster: 1290 if action.attacker == monster:
...@@ -1294,7 +1302,8 @@ def check_arena(): ...@@ -1294,7 +1302,8 @@ def check_arena():
1294 monster2.wins += 1 1302 monster2.wins += 1
1295 monster.losses += 1 1303 monster.losses += 1
1296 break 1304 break
1297 out_str += "\n{} {}% - {} {}%\n".format(monster.get_monster_name(), monster.get_hp_percent(), monster2.get_monster_name(), monster2.get_hp_percent()) 1305 if fighting:
1306 out_str += "\n{} {}% - {} {}%\n".format(monster.get_monster_name(), monster.get_hp_percent(), monster2.get_monster_name(), monster2.get_hp_percent())
1298 log(out_str) 1307 log(out_str)
1299 send_message(client, arena_channel, byteify(out_str)) 1308 send_message(client, arena_channel, byteify(out_str))
1300 # Heal the monsters before they are returned to the player inventory 1309 # Heal the monsters before they are returned to the player inventory
......
...@@ -87,29 +87,30 @@ class Jobs: ...@@ -87,29 +87,30 @@ class Jobs:
87 members = [attr for attr in dir(Jobs()) if not callable(attr) and not attr.startswith("__") and not attr.startswith("get_job_name")] 87 members = [attr for attr in dir(Jobs()) if not callable(attr) and not attr.startswith("__") and not attr.startswith("get_job_name")]
88 return members[job-1] 88 return members[job-1]
89 89
90 evasion_by_job = { 90 # MP Per level is actually the amount added to the multiplier per level for the mp base for that monster.
91 Jobs.BLM: {'base_eva': 4, 'eva_per_level': 2.48}, 91 adjustments_by_job = {
92 Jobs.BLU: {'base_eva': 5, 'eva_per_level': 2.78}, 92 Jobs.BLM: {'base_eva': 4, 'eva_per_level': 2.48, 'mp_per_level': 0.3},
93 Jobs.BRD: {'base_eva': 4, 'eva_per_level': 2.66}, 93 Jobs.BLU: {'base_eva': 5, 'eva_per_level': 2.78, 'mp_per_level': 0.15},
94 Jobs.BST: {'base_eva': 5, 'eva_per_level': 2.78}, 94 Jobs.BRD: {'base_eva': 4, 'eva_per_level': 2.66, 'mp_per_level': 0},
95 Jobs.COR: {'base_eva': 4, 'eva_per_level': 2.66}, 95 Jobs.BST: {'base_eva': 5, 'eva_per_level': 2.78, 'mp_per_level': 0},
96 Jobs.DNC: {'base_eva': 5, 'eva_per_level': 2.88}, 96 Jobs.COR: {'base_eva': 4, 'eva_per_level': 2.66, 'mp_per_level': 0},
97 Jobs.DRG: {'base_eva': 5, 'eva_per_level': 2.88}, 97 Jobs.DNC: {'base_eva': 5, 'eva_per_level': 2.88, 'mp_per_level': 0},
98 Jobs.DRK: {'base_eva': 5, 'eva_per_level': 2.78}, 98 Jobs.DRG: {'base_eva': 5, 'eva_per_level': 2.88, 'mp_per_level': 0},
99 Jobs.GEO: {'base_eva': 4, 'eva_per_level': 2.66}, 99 Jobs.DRK: {'base_eva': 5, 'eva_per_level': 2.78, 'mp_per_level': 0.1},
100 Jobs.MNK: {'base_eva': 5, 'eva_per_level': 2.88}, 100 Jobs.GEO: {'base_eva': 4, 'eva_per_level': 2.66, 'mp_per_level': 0},
101 Jobs.NIN: {'base_eva': 6, 'eva_per_level': 3}, 101 Jobs.MNK: {'base_eva': 5, 'eva_per_level': 2.88, 'mp_per_level': 0},
102 Jobs.PLD: {'base_eva': 5, 'eva_per_level': 2.78}, 102 Jobs.NIN: {'base_eva': 6, 'eva_per_level': 3, 'mp_per_level': 0},
103 Jobs.PUP: {'base_eva': 5, 'eva_per_level': 2.88}, 103 Jobs.PLD: {'base_eva': 5, 'eva_per_level': 2.78, 'mp_per_level': 0.1},
104 Jobs.RDM: {'base_eva': 4, 'eva_per_level': 2.66}, 104 Jobs.PUP: {'base_eva': 5, 'eva_per_level': 2.88, 'mp_per_level': 0},
105 Jobs.RNG: {'base_eva': 4, 'eva_per_level': 2.48}, 105 Jobs.RDM: {'base_eva': 4, 'eva_per_level': 2.66, 'mp_per_level': 0.15},
106 Jobs.RUN: {'base_eva': 5, 'eva_per_level': 2.88}, 106 Jobs.RNG: {'base_eva': 4, 'eva_per_level': 2.48, 'mp_per_level': 0},
107 Jobs.SAM: {'base_eva': 5, 'eva_per_level': 2.88}, 107 Jobs.RUN: {'base_eva': 5, 'eva_per_level': 2.88, 'mp_per_level': 0.1},
108 Jobs.SCH: {'base_eva': 4, 'eva_per_level': 2.48}, 108 Jobs.SAM: {'base_eva': 5, 'eva_per_level': 2.88, 'mp_per_level': 0},
109 Jobs.SMN: {'base_eva': 4, 'eva_per_level': 2.48}, 109 Jobs.SCH: {'base_eva': 4, 'eva_per_level': 2.48, 'mp_per_level': 0.15},
110 Jobs.THF: {'base_eva': 6, 'eva_per_level': 3}, 110 Jobs.SMN: {'base_eva': 4, 'eva_per_level': 2.48, 'mp_per_level': 0.4},
111 Jobs.WAR: {'base_eva': 5, 'eva_per_level': 2.78}, 111 Jobs.THF: {'base_eva': 6, 'eva_per_level': 3, 'mp_per_level': 0},
112 Jobs.WHM: {'base_eva': 4, 'eva_per_level': 2.48}, 112 Jobs.WAR: {'base_eva': 5, 'eva_per_level': 2.78, 'mp_per_level': 0},
113 Jobs.WHM: {'base_eva': 4, 'eva_per_level': 2.48, 'mp_per_level': 0.2},
113 } 114 }
114 115
115 TemperamentPosture = { 116 TemperamentPosture = {
...@@ -143,6 +144,78 @@ FeralSkills = { ...@@ -143,6 +144,78 @@ FeralSkills = {
143 'Magic Barrier': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 29, 'shadows': 'absorb', 'range': None, 'aoe': True}, 144 'Magic Barrier': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 29, 'shadows': 'absorb', 'range': None, 'aoe': True},
144 'Sinker Drill': {'type': 'Physical', 'sub_type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, 145 'Sinker Drill': {'type': 'Physical', 'sub_type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False},
145 } 146 }
147
148 class Spells:
149 SpellTypes = {
150 't1': {'multiplier': 1.0, 'earth': 10, 'water': 16, 'wind': 25, 'fire': 35, 'ice': 46, 'thunder': 60, 'dark': 0, 'light': 14},
151 't2': {'multiplier': 1.0, 'earth': 78, 'water': 95, 'wind': 113, 'fire': 133, 'ice': 155, 'thunder': 178, 'dark': 0, 'light': 85},
152 't3': {'multiplier': 1.5, 'earth': 210, 'water': 236, 'wind': 265, 'fire': 295, 'ice': 320, 'thunder': 345, 'dark': 0, 'light': 198},
153 't4': {'multiplier': 2.0, 'earth': 381, 'water': 410, 'wind': 440, 'fire': 472, 'ice': 506, 'thunder': 541, 'dark': 0, 'light': 0},
154 't5': {'multiplier': 2.299, 'earth': 626, 'water': 680, 'wind': 738, 'fire': 785, 'ice': 828, 'thunder': 874, 'dark': 963, 'light': 0},
155 't1-ga': {'multiplier': 1.0, 'earth': 56, 'water': 74, 'wind': 93, 'fire': 120, 'ice': 145, 'thunder': 172, 'dark': 0, 'light': 50},
156 't2-ga-a': {'multiplier': 1.0, 'earth': 201, 'water': 232, 'wind': 266, 'fire': 312, 'ice': 350, 'thunder': 392, 'dark': 0, 'light': 180},
157 't2-ga-b': {'multiplier': 1.5, 'earth': 201, 'water': 232, 'wind': 266, 'fire': 312, 'ice': 350, 'thunder': 392, 'dark': 0, 'light': 180},
158 't3-ga': {'multiplier': 1.5, 'earth': 434, 'water': 480, 'wind': 527, 'fire': 589, 'ice': 642, 'thunder': 697, 'dark': 0, 'light': 0},
159 'ja': {'multiplier': 1.0, 'earth': 719, 'water': 782, 'wind': 844, 'fire': 902, 'ice': 953, 'thunder': 1004, 'dark': 0, 'light': 0},
160 't1-ra': {'multiplier': 1.0, 'earth': 128, 'water': 153, 'wind': 179, 'fire': 216, 'ice': 247, 'thunder': 282, 'dark': 0, 'light': 0},
161 't2-ra-a': {'multiplier': 1.0, 'earth': 317, 'water': 356, 'wind': 396, 'fire': 450, 'ice': 496, 'thunder': 544, 'dark': 0, 'light': 0},
162 't2-ra-b': {'multiplier': 1.5, 'earth': 317, 'water': 356, 'wind': 396, 'fire': 450, 'ice': 496, 'thunder': 544, 'dark': 0, 'light': 0},
163 't1-am': {'multiplier': 2.0, 'earth': 577, 'water': 630, 'wind': 552, 'fire': 657, 'ice': 526, 'thunder': 603, 'dark': 939, 'light': 125},
164 't2-am': {'multiplier': 2.0, 'earth': 710, 'water': 710, 'wind': 710, 'fire': 710, 'ice': 710, 'thunder': 710, 'dark': 0, 'light': 0},
165 'helix': {'multiplier': 1.0, 'earth': 25, 'water': 25, 'wind': 25, 'fire': 25, 'ice': 25, 'thunder': 25, 'dark': 25, 'light': 25},
166 'ichi': {'multiplier': 1.0, 'earth': 10, 'water': 10, 'wind': 10, 'fire': 10, 'ice': 10, 'thunder': 10, 'dark': 0, 'light': 0},
167 'ni': {'multiplier': 1.0, 'earth': 78, 'water': 78, 'wind': 78, 'fire': 78, 'ice': 78, 'thunder': 78, 'dark': 0, 'light': 0},
168 'san': {'multiplier': 1.5, 'earth': 78, 'water': 78, 'wind': 78, 'fire': 78, 'ice': 78, 'thunder': 78, 'dark': 0, 'light': 0},
169 }
170
171 # TODO: Finish jobs listing for each spell.
172 SpellList = {
173 'Stone': {'mp_cost': 4, 'casting_time': 0.5, 'recast_time': 2, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'earth', 'jobs': {Jobs.BLM: 1, Jobs.RDM: 4, Jobs.SCH: 4, Jobs.GEO: 4, Jobs.DRK: 5, Jobs.PUP: 5} },
174 'Water': {'mp_cost': 5, 'casting_time': 0.5, 'recast_time': 2, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'water', 'jobs': {Jobs.BLM: 5, Jobs.SCH: 8, Jobs.RDM: 9, Jobs.GEO: 9, Jobs.PUP: 10, Jobs.DRK: 11} },
175 'Aero': {'mp_cost': 6, 'casting_time': 0.5, 'recast_time': 2, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'wind', 'jobs': {Jobs.BLM: 9, Jobs.SCH: 12, Jobs.RDM: 14, Jobs.PUP: 15, Jobs.DRK: 17} },
176 'Fire': {'mp_cost': 7, 'casting_time': 0.5, 'recast_time': 2, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'fire', 'jobs': {Jobs.BLM: 13, Jobs.SCH: 16, Jobs.RDM: 19, Jobs.GEO: 19, Jobs.PUP: 20, Jobs.DRK: 23} },
177 'Blizzard': {'mp_cost': 8, 'casting_time': 0.5, 'recast_time': 2, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'ice', 'jobs': {Jobs.BLM: 17, Jobs.SCH: 20, Jobs.RDM: 24, Jobs.PUP: 24, Jobs.DRK: 29} },
178 'Thunder': {'mp_cost': 9, 'casting_time': 0.5, 'recast_time': 2, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'lightning', 'jobs': {Jobs.BLM: 21, Jobs.SCH: 24, Jobs.RDM: 29, Jobs.PUP: 29, Jobs.DRK: 35} },
179 'Banish': {'mp_cost': 15, 'casting_time': 3, 'recast_time': 14, 'magic_acc_stat': 'mnd', 'spell_type': 't1', 'damage_type': 'light', 'jobs': {Jobs.WHM: 5, Jobs.PLD: 7} },
180 'Stone II': {'mp_cost': 16, 'casting_time': 1.5, 'recast_time': 6, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'earth', 'jobs': {Jobs.BLM: 26, Jobs.SCH: 30, Jobs.RDM: 35, Jobs.DRK: 42, Jobs.PUP: 35} },
181 'Water II': {'mp_cost': 19, 'casting_time': 1.5, 'recast_time': 6, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'water', 'jobs': {Jobs.BLM: 30, Jobs.SCH: 34, Jobs.RDM: 40, Jobs.PUP: 40, Jobs.DRK: 48} },
182 'Aero II': {'mp_cost': 22, 'casting_time': 1.5, 'recast_time': 6, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'wind', 'jobs': {Jobs.BLM: 34, Jobs.SCH: 38, Jobs.RDM: 45, Jobs.PUP: 45, Jobs.DRK: 54} },
183 'Fire II': {'mp_cost': 26, 'casting_time': 1.5, 'recast_time': 6, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'fire', 'jobs': {Jobs.BLM: 38, Jobs.SCH: 42, Jobs.RDM: 50, Jobs.PUP: 50, Jobs.DRK: 60} },
184 'Blizzard II': {'mp_cost': 31, 'casting_time': 1.5, 'recast_time': 6, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'ice', 'jobs': {Jobs.BLM: 42, Jobs.SCH: 46, Jobs.RDM: 55, Jobs.PUP: 55, Jobs.DRK: 66} },
185 'Thunder II': {'mp_cost': 37, 'casting_time': 1.5, 'recast_time': 6, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'lightning', 'jobs': {Jobs.BLM: 46, Jobs.SCH: 51, Jobs.RDM: 60, Jobs.PUP: 60, Jobs.DRK: 72} },
186 'Banish II': {'mp_cost': 57, 'casting_time': 2.5, 'recast_time': 21, 'magic_acc_stat': 'mnd', 'spell_type': 't1', 'damage_type': 'light', 'jobs': {Jobs.WHM: 30, Jobs.PLD: 34} },
187 'Stone III': {'mp_cost': 40, 'casting_time': 3, 'recast_time': 15, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'earth', 'jobs': {Jobs.BLM: 51, Jobs.SCH: 54, Jobs.RDM: 65, Jobs.DRK: 76, Jobs.PUP: 65} },
188 'Water III': {'mp_cost': 46, 'casting_time': 3, 'recast_time': 15, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'water', 'jobs': {Jobs.BLM: 55, Jobs.SCH: 57, Jobs.RDM: 67, Jobs.PUP: 67, Jobs.DRK: 80} },
189 'Aero III': {'mp_cost': 54, 'casting_time': 3, 'recast_time': 15, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'wind', 'jobs': {Jobs.BLM: 59, Jobs.SCH: 60, Jobs.RDM: 69, Jobs.PUP: 69, Jobs.DRK: 84} },
190 'Fire III': {'mp_cost': 63, 'casting_time': 3, 'recast_time': 15, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'fire', 'jobs': {Jobs.BLM: 62, Jobs.SCH: 63, Jobs.RDM: 71, Jobs.PUP: 70, Jobs.DRK: 88} },
191 'Blizzard III': {'mp_cost': 75, 'casting_time': 3, 'recast_time': 15, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'ice', 'jobs': {Jobs.BLM: 64, Jobs.SCH: 66, Jobs.RDM: 73, Jobs.PUP: 71, Jobs.DRK: 92} },
192 'Thunder III': {'mp_cost': 91, 'casting_time': 3, 'recast_time': 15, 'magic_acc_stat': 'int', 'spell_type': 't1', 'damage_type': 'lightning', 'jobs': {Jobs.BLM: 66, Jobs.SCH: 69, Jobs.RDM: 75, Jobs.PUP: 72, Jobs.DRK: 96} },
193 'Banish III': {'mp_cost': 96, 'casting_time': 3, 'recast_time': 45, 'magic_acc_stat': 'mnd', 'spell_type': 't1', 'damage_type': 'light', 'jobs': {Jobs.WHM: 65} },
194 }
195
196 def get_spell_list(self, level, job = None, sub_job = None):
197 available_spells = []
198 for spell_name, spell in self.SpellList.iteritems():
199 if job and job in spell['jobs'] and spell['jobs'][job] <= level:
200 if spell_name not in available_spells:
201 available_spells.append(spell_name)
202 if sub_job and sub_job in spell['jobs'] and spell['jobs'][sub_job] <= level / 2:
203 if spell_name not in available_spells:
204 available_spells.append(spell_name)
205 return sorted(available_spells)
206
207 def get_spell_data(self, spell):
208 spell = self.SpellList[spell]
209 type_data = self.SpellTypes[spell['spell_type']]
210 spell_data = {
211 'type': type_data,
212 'magic_acc_stat': spell['magic_acc_stat'],
213 'base_damage': type_data[spell['damage_type']],
214 'multiplier': type_data['multiplier'],
215 'mp_cost': spell['mp_cost']
216 }
217 return spell_data
218
146 Families = { 219 Families = {
147 'acrolith': { 220 'acrolith': {
148 'base_fp': 50, 221 'base_fp': 50,
...@@ -151,6 +224,7 @@ Families = { ...@@ -151,6 +224,7 @@ Families = {
151 'available_main_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], 224 'available_main_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD],
152 'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], 225 'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD],
153 'innate_feral_skills': ['Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'], 226 'innate_feral_skills': ['Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'],
227 'target_magic_damage_adjustment': 1.00,
154 'type': 'Arcana', 228 'type': 'Arcana',
155 'strong_vs': ['Dark'], 229 'strong_vs': ['Dark'],
156 'charmable': False, 230 'charmable': False,
...@@ -168,6 +242,8 @@ Families = { ...@@ -168,6 +242,8 @@ Families = {
168 'mnd_per_level': 0.76, 242 'mnd_per_level': 0.76,
169 'base_int': 8, 243 'base_int': 8,
170 'int_per_level': 0.76, 244 'int_per_level': 0.76,
245 'base_chr': 7,
246 'chr_per_level': 0.76,
171 'temperament_attitude': { 247 'temperament_attitude': {
172 'initial_value': 4, 248 'initial_value': 4,
173 'actions': { 249 'actions': {
...@@ -196,6 +272,7 @@ Families = { ...@@ -196,6 +272,7 @@ Families = {
196 'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'], 272 'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'],
197 'type': 'Demon', 273 'type': 'Demon',
198 'traits': ['magic defence bonus +25%'], 274 'traits': ['magic defence bonus +25%'],
275 'target_magic_damage_adjustment': 0.75,
199 'charmable': False, 276 'charmable': False,
200 'aspir': True, 277 'aspir': True,
201 'drain': True, 278 'drain': True,
...@@ -211,6 +288,8 @@ Families = { ...@@ -211,6 +288,8 @@ Families = {
211 'mnd_per_level': 0.9066, 288 'mnd_per_level': 0.9066,
212 'base_int': 9, 289 'base_int': 9,
213 'int_per_level': 0.9066, 290 'int_per_level': 0.9066,
291 'base_chr': 8,
292 'chr_per_level': 0.84,
214 'temperament_attitude': { 293 'temperament_attitude': {
215 'initial_value': 4, 294 'initial_value': 4,
216 'actions': { 295 'actions': {
...@@ -237,12 +316,14 @@ Monsters = { ...@@ -237,12 +316,14 @@ Monsters = {
237 'family': 'acrolith', 316 'family': 'acrolith',
238 'zone': ['abyssea - uleguerand'], 317 'zone': ['abyssea - uleguerand'],
239 'hp': 20, 318 'hp': 20,
319 'mp': 20,
240 'weapon_base_damage': 18 320 'weapon_base_damage': 18
241 }, 321 },
242 'Floating Eye': { 322 'Floating Eye': {
243 'family': 'ahriman', 323 'family': 'ahriman',
244 'zone': ['ranguemont pass'], 324 'zone': ['ranguemont pass'],
245 'hp': 15, 325 'hp': 15,
326 'mp': 24,
246 'weapon_base_damage': 15, 327 'weapon_base_damage': 15,
247 'image_url': 'http://vignette1.wikia.nocookie.net/ffxi/images/9/94/Floating_Eye.JPG/revision/latest?cb=20070704142439' 328 'image_url': 'http://vignette1.wikia.nocookie.net/ffxi/images/9/94/Floating_Eye.JPG/revision/latest?cb=20070704142439'
248 }, 329 },
...@@ -250,6 +331,7 @@ Monsters = { ...@@ -250,6 +331,7 @@ Monsters = {
250 'family': 'ahriman', 331 'family': 'ahriman',
251 'zone': ['ranguemont pass', 'beaucedine glacier'], 332 'zone': ['ranguemont pass', 'beaucedine glacier'],
252 'hp': 15, 333 'hp': 15,
334 'mp': 24,
253 'weapon_base_damage': 15, 335 'weapon_base_damage': 15,
254 'image_url': 'http://vignette3.wikia.nocookie.net/ffxi/images/4/40/Bat_Eye.jpg/revision/latest?cb=20060909124134', 336 'image_url': 'http://vignette3.wikia.nocookie.net/ffxi/images/4/40/Bat_Eye.jpg/revision/latest?cb=20060909124134',
255 }, 337 },
...@@ -257,66 +339,77 @@ Monsters = { ...@@ -257,66 +339,77 @@ Monsters = {
257 'family': 'ahriman', 339 'family': 'ahriman',
258 'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'], 340 'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'],
259 'hp': 15, 341 'hp': 15,
342 'mp': 24,
260 'weapon_base_damage': 15, 343 'weapon_base_damage': 15,
261 }, 344 },
262 'Morbid Eye': { 345 'Morbid Eye': {
263 'family': 'ahriman', 346 'family': 'ahriman',
264 'zone': ['castle zvahl baileys', 'castle zvahl keep'], 347 'zone': ['castle zvahl baileys', 'castle zvahl keep'],
265 'hp': 15, 348 'hp': 15,
349 'mp': 24,
266 'weapon_base_damage': 15 350 'weapon_base_damage': 15
267 }, 351 },
268 'Deadly Iris': { 352 'Deadly Iris': {
269 'family': 'ahriman', 353 'family': 'ahriman',
270 'zone': ['castle zvahl keep'], 354 'zone': ['castle zvahl keep'],
271 'hp': 15, 355 'hp': 15,
356 'mp': 24,
272 'weapon_base_damage': 15 357 'weapon_base_damage': 15
273 }, 358 },
274 'Ahriman': { 359 'Ahriman': {
275 'family': 'ahriman', 360 'family': 'ahriman',
276 'zone': ['castle zvahl baileys'], 361 'zone': ['castle zvahl baileys'],
277 'hp': 15, 362 'hp': 15,
363 'mp': 24,
278 'weapon_base_damage': 15 364 'weapon_base_damage': 15
279 }, 365 },
280 'Fachan': { 366 'Fachan': {
281 'family': 'ahriman', 367 'family': 'ahriman',
282 'zone': ['uleguerand range'], 368 'zone': ['uleguerand range'],
283 'hp': 15, 369 'hp': 15,
370 'mp': 24,
284 'weapon_base_damage': 15 371 'weapon_base_damage': 15
285 }, 372 },
286 'Gawper': { 373 'Gawper': {
287 'family': 'ahriman', 374 'family': 'ahriman',
288 'zone': ['beaucedine glacier (s)'], 375 'zone': ['beaucedine glacier (s)'],
289 'hp': 15, 376 'hp': 15,
377 'mp': 24,
290 'weapon_base_damage': 15 378 'weapon_base_damage': 15
291 }, 379 },
292 'Menacing Eye': { 380 'Menacing Eye': {
293 'family': 'ahriman', 381 'family': 'ahriman',
294 'zone': ['xarcabard (s)'], 382 'zone': ['xarcabard (s)'],
295 'hp': 15, 383 'hp': 15,
384 'mp': 24,
296 'weapon_base_damage': 15 385 'weapon_base_damage': 15
297 }, 386 },
298 'Ogler': { 387 'Ogler': {
299 'family': 'ahriman', 388 'family': 'ahriman',
300 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], 389 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'],
301 'hp': 15, 390 'hp': 15,
391 'mp': 24,
302 'weapon_base_damage': 15 392 'weapon_base_damage': 15
303 }, 393 },
304 'Smolenkos': { 394 'Smolenkos': {
305 'family': 'ahriman', 395 'family': 'ahriman',
306 'zone': ['uleguerand range'], 396 'zone': ['uleguerand range'],
307 'hp': 15, 397 'hp': 15,
398 'mp': 24,
308 'weapon_base_damage': 15 399 'weapon_base_damage': 15
309 }, 400 },
310 'Doom Lens': { 401 'Doom Lens': {
311 'family': 'ahriman', 402 'family': 'ahriman',
312 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], 403 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'],
313 'hp': 15, 404 'hp': 15,
405 'mp': 24,
314 'weapon_base_damage': 15 406 'weapon_base_damage': 15
315 }, 407 },
316 'Scowlenkos': { 408 'Scowlenkos': {
317 'family': 'ahriman', 409 'family': 'ahriman',
318 'zone': ['uleguerand range'], 410 'zone': ['uleguerand range'],
319 'hp': 15, 411 'hp': 15,
412 'mp': 24,
320 'weapon_base_damage': 15 413 'weapon_base_damage': 15
321 } 414 }
322 415
...@@ -372,6 +465,7 @@ class Pankration: ...@@ -372,6 +465,7 @@ class Pankration:
372 monster_name = random.choice(self.get_monsters(zone)) 465 monster_name = random.choice(self.get_monsters(zone))
373 monster_data = Monsters[monster_name] 466 monster_data = Monsters[monster_name]
374 hp = monster_data['hp'] 467 hp = monster_data['hp']
468 mp = monster_data['mp']
375 weapon_base_damage = monster_data['weapon_base_damage'] 469 weapon_base_damage = monster_data['weapon_base_damage']
376 log("Monster: {} Data: {}".format(monster_name, monster_data)) 470 log("Monster: {} Data: {}".format(monster_name, monster_data))
377 family_name = monster_data['family'] 471 family_name = monster_data['family']
...@@ -391,7 +485,8 @@ class Pankration: ...@@ -391,7 +485,8 @@ class Pankration:
391 feral_skills.append(skills[2]) 485 feral_skills.append(skills[2])
392 dicipline_level = 1 486 dicipline_level = 1
393 487
394 monster = Monster(monster_name, family_name, family, hp, level, weapon_base_damage, main_job, support_job, feral_skills, 488 monster = Monster(monster_name, family_name, family, hp, mp, level,
489 weapon_base_damage, main_job, support_job, feral_skills,
395 [], dicipline_level) 490 [], dicipline_level)
396 url = '' 491 url = ''
397 if 'image_url' in monster_data: 492 if 'image_url' in monster_data:
...@@ -405,15 +500,26 @@ class Pankration: ...@@ -405,15 +500,26 @@ class Pankration:
405 def get_action(): 500 def get_action():
406 return "" 501 return ""
407 502
503 class AttackResponse:
504 def __init__(self, is_a_hit, damage, is_a_crit, spell, resisted):
505 self.spell = spell
506 self.is_a_crit = is_a_crit
507 self.is_a_hit = is_a_hit
508 self.resisted = resisted
509 self.damage = damage
510
511 def __str__(self):
512 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)
408 513
409 class Monster: 514 class Monster:
410 def __init__(self, monster_type, family_name, family, base_hp, level, weapon_base_damage, main_job, support_job, innate_feral_skills, 515 def __init__(self, monster_type, family_name, family, base_hp, base_mp, level, weapon_base_damage, main_job,
411 equipped_feral_skills, dicipline_level): 516 support_job, innate_feral_skills, equipped_feral_skills, dicipline_level):
412 self.custom_name = None 517 self.custom_name = None
413 self.monster_type = monster_type 518 self.monster_type = monster_type
414 self.family_name = family_name 519 self.family_name = family_name
415 self.family = family 520 self.family = family
416 self.base_hp = base_hp 521 self.base_hp = base_hp
522 self.base_mp = base_mp
417 self.level = level 523 self.level = level
418 self.main_job = main_job 524 self.main_job = main_job
419 self.support_job = support_job 525 self.support_job = support_job
...@@ -423,7 +529,8 @@ class Monster: ...@@ -423,7 +529,8 @@ class Monster:
423 self.temperament_posture = family['temperament_posture']['initial_value'] 529 self.temperament_posture = family['temperament_posture']['initial_value']
424 self.temperament_attitude = family['temperament_attitude']['initial_value'] 530 self.temperament_attitude = family['temperament_attitude']['initial_value']
425 self.pre_fight_command = {"temperament_posture": None, "temperament_attitude": None} 531 self.pre_fight_command = {"temperament_posture": None, "temperament_attitude": None}
426 self.exp = exp_to_level[level] + 1 532 self.target_magic_damage_adjustment = family['target_magic_damage_adjustment']
533 self.exp = 200 * (level - 1)
427 # TODO: Setup something more interesting for each monster. 534 # TODO: Setup something more interesting for each monster.
428 self.weapon_base_damage = weapon_base_damage 535 self.weapon_base_damage = weapon_base_damage
429 self.ammo_damage = 0 536 self.ammo_damage = 0
...@@ -439,8 +546,11 @@ class Monster: ...@@ -439,8 +546,11 @@ class Monster:
439 self.mnd_per_level = family['mnd_per_level'] 546 self.mnd_per_level = family['mnd_per_level']
440 self.base_int = family['base_int'] 547 self.base_int = family['base_int']
441 self.int_per_level = family['int_per_level'] 548 self.int_per_level = family['int_per_level']
549 self.base_chr = family['base_chr']
550 self.chr_per_level = family['chr_per_level']
442 self.tp = 0 551 self.tp = 0
443 self.hp = self.get_hp() 552 self.hp = self.get_hp()
553 self.mp = self.get_mp()
444 self.wins = 0 554 self.wins = 0
445 self.losses = 0 555 self.losses = 0
446 556
...@@ -478,20 +588,31 @@ class Monster: ...@@ -478,20 +588,31 @@ class Monster:
478 #this is a bit dumb but it's close enough. 588 #this is a bit dumb but it's close enough.
479 return int((self.level * 20) + self.base_hp) 589 return int((self.level * 20) + self.base_hp)
480 590
591 def get_mp(self):
592 #this is a bit dumb but it's close enough.
593
594 main_add_amount = self.base_mp * adjustments_by_job[self.main_job]['mp_per_level']
595 sub_add_amount = self.base_mp * adjustments_by_job[self.support_job]['mp_per_level']
596
597 main_mp = int((self.level * (self.base_mp + main_add_amount)) + self.base_mp)
598 sub_mp = int((self.level/2) * sub_add_amount)
599 return main_mp + sub_mp
600
601
481 def get_fp(self): 602 def get_fp(self):
482 return int(self.level / self.family['fp_per_level'] + self.family['base_fp']) 603 return int(self.level / self.family['fp_per_level'] + self.family['base_fp'])
483 604
484 def add_xp(self, exp_to_add): 605 def add_xp(self, exp_to_add):
485 self.exp += exp_to_add 606 self.exp += exp_to_add
486 for i in range(self.level, 51): 607 for i in range(self.level, 51):
487 if self.exp > 200 * i: 608 if self.exp >= 200 * i:
488 if i > self.level: 609 if i > self.level:
489 # We leveled up! 610 # We leveled up!
490 self.level = i 611 self.level = i
491 return (True, "Start level: {} New Level: {}".format(self.level, i)) 612 return (True, "Congratulations your monster leveled up!\n\nStart level: {} New Level: {}".format(self.level, i))
492 else: 613 else:
493 break 614 break
494 return (False,) 615 return (False,None)
495 616
496 def get_current_posture(self): 617 def get_current_posture(self):
497 return TemperamentPosture[self.temperament_posture] 618 return TemperamentPosture[self.temperament_posture]
...@@ -524,7 +645,7 @@ class Monster: ...@@ -524,7 +645,7 @@ class Monster:
524 return int(math.floor(3*self.get_dexterity()/4) + self.get_combat_skill()) 645 return int(math.floor(3*self.get_dexterity()/4) + self.get_combat_skill())
525 646
526 def get_evasion(self): 647 def get_evasion(self):
527 job_eva = evasion_by_job[self.main_job] 648 job_eva = adjustments_by_job[self.main_job]
528 base_eva = int(round(max(job_eva['base_eva'], self.level * job_eva['eva_per_level']))) 649 base_eva = int(round(max(job_eva['base_eva'], self.level * job_eva['eva_per_level'])))
529 650
530 return base_eva + int(self.get_agility() / 2) 651 return base_eva + int(self.get_agility() / 2)
...@@ -544,12 +665,17 @@ class Monster: ...@@ -544,12 +665,17 @@ class Monster:
544 def get_intelligence(self): 665 def get_intelligence(self):
545 return int(round(max(self.base_int, self.level * self.int_per_level))) 666 return int(round(max(self.base_int, self.level * self.int_per_level)))
546 667
668 def get_charisma(self):
669 return int(round(max(self.base_chr, self.level * self.chr_per_level)))
670
547 def get_base_defense(self): 671 def get_base_defense(self):
548 return (math.floor(self.get_vitality()/2) + 8 + self.level) 672 return (math.floor(self.get_vitality()/2) + 8 + self.level)
549 673
550 def get_hp_percent(self): 674 def get_hp_percent(self):
551 print(self.hp) 675 return max(1, int(round((self.hp/self.get_hp())*100)))
552 return max(0, int(round((self.hp/self.get_hp())*100))) 676
677 def get_magic_evasion(self):
678 return max(1, int(1+round(self.level/4)))
553 679
554 def get_hit_rate(self, enemy_eva, level_difference): 680 def get_hit_rate(self, enemy_eva, level_difference):
555 rate = 75 + math.floor(((self.get_accuracy() - enemy_eva)/2)) - (2*level_difference) 681 rate = 75 + math.floor(((self.get_accuracy() - enemy_eva)/2)) - (2*level_difference)
...@@ -559,54 +685,34 @@ class Monster: ...@@ -559,54 +685,34 @@ class Monster:
559 rate = 95 685 rate = 95
560 return rate 686 return rate
561 687
562 def get_physical_ws_damage(self, base_damage, modifiers): 688 def get_magic_hit_rate(self, spell, enemy):
563 level_range_alpha = 1.01 - (math.floor(float(self.level) / 5.0) / 100.0) 689 # Calculate the magic accuracy
564 wsc = 0 690 spell_data = Spells().get_spell_data(spell)
565 for modifier in modifiers: 691 # Get the stat for the spell and base magic accuracy for that spells MA
566 if modifier['stat'] == 'str': 692 magic_acc_stat = spell_data['magic_acc_stat']
567 wsc += (modifer['percent'] / 100) * self.get_strength() 693 if magic_acc_stat == 'int':
568 elif modifiers['stat'] == 'vit': 694 dSTAT = self.get_intelligence() - enemy.get_intelligence()
569 wsc += (modifer['percent'] / 100) * self.get_vitality() 695 elif magic_acc_stat == 'mnd':
570 elif modifiers['stat'] == 'dex': 696 dSTAT = self.get_mind() - enemy.get_mind()
571 wsc += (modifer['percent'] / 100) * self.get_dexterity() 697 elif magic_acc_stat == 'chr':
572 elif modifiers['stat'] == 'agi': 698 dSTAT = self.get_charisma() - enemy.get_charisma()
573 wsc += (modifer['percent'] / 100) * self.get_agility() 699 elif magic_acc_stat == 'agi':
574 elif modifiers['stat'] == 'eva': 700 dSTAT = self.get_agility() - enemy.get_agility()
575 wsc += (modifer['percent'] / 100) * self.get_evasion() 701
576 elif modifiers['stat'] == 'int': 702 magic_hit_rate = 50 - 0.5 * (enemy.get_magic_evasion() - dSTAT)
577 wsc += (modifer['percent'] / 100) * self.get_intelligence() 703
578 elif modifiers['stat'] == 'mnd': 704 if magic_hit_rate < 5:
579 wsc += (modifer['percent'] / 100) * self.get_mind() 705 magic_hit_rate = 5
580 wsc = (wsc * level_range_alpha) 706 elif magic_hit_rate > 95:
581 707 magic_hit_rate = 95
582 bd = float(self.weapon_base_damage) 708 return magic_hit_rate
583 if attack_type == 'ranged': 709
584 bd += self.ammo_damage 710 def get_pdif(self, base_damage, defense, attack_type, level_difference):
585
586 fstr = ((self.get_strength() - enemy_vit)+4) / 4
587
588 final_damage = bd + fstr + wsc
589 711
590 return final_damage
591
592 #TODO: Add fTP calculation and PDIF
593 #final_damage = (bd )
594 #return final_damage
595
596
597 # Calculate the base damage against the provided defense
598 # attack_type can be 'ranged' or 'melee'
599 def get_physical_base_damage(self, defense, attack_type, level_difference, enemy_vit):
600 #print("Defense: {} Type: {} Level diff: {}".format(defense, attack_type, level_difference))
601 # Calculate the attack/defense ratio
602 bd = float(self.weapon_base_damage)
603 if attack_type == 'ranged':
604 bd += self.ammo_damage
605
606 if defense == 0: 712 if defense == 0:
607 ratio = 99 713 ratio = 99
608 else: 714 else:
609 ratio = bd / float(defense) 715 ratio = base_damage / float(defense)
610 if attack_type == 'ranged': 716 if attack_type == 'ranged':
611 cap = 3.0 717 cap = 3.0
612 else: 718 else:
...@@ -646,17 +752,151 @@ class Monster: ...@@ -646,17 +752,151 @@ class Monster:
646 752
647 # Some fuckery since python doesn't let you do a rand between decimals 753 # Some fuckery since python doesn't let you do a rand between decimals
648 pDif_rand = float(random.randint(int(pDif_min*100000), int(pDif_max*100000))) / 100000.0 754 pDif_rand = float(random.randint(int(pDif_min*100000), int(pDif_max*100000))) / 100000.0
649 755 return pDif_rand * cRatio
756
757 def get_physical_ws_damage(self, defense, attack_type, fTP, modifiers, level_difference, enemy_vit):
758 level_range_alpha = 1.01 - (math.floor(float(self.level) / 5.0) / 100.0)
759 wsc = 0
760 for modifier in modifiers:
761 if modifier['stat'] == 'str':
762 wsc += (modifer['percent'] / 100) * self.get_strength()
763 elif modifiers['stat'] == 'vit':
764 wsc += (modifer['percent'] / 100) * self.get_vitality()
765 elif modifiers['stat'] == 'dex':
766 wsc += (modifer['percent'] / 100) * self.get_dexterity()
767 elif modifiers['stat'] == 'agi':
768 wsc += (modifer['percent'] / 100) * self.get_agility()
769 elif modifiers['stat'] == 'eva':
770 wsc += (modifer['percent'] / 100) * self.get_evasion()
771 elif modifiers['stat'] == 'int':
772 wsc += (modifer['percent'] / 100) * self.get_intelligence()
773 elif modifiers['stat'] == 'mnd':
774 wsc += (modifer['percent'] / 100) * self.get_mind()
775 wsc = (wsc * level_range_alpha)
776
777 bd = float(self.weapon_base_damage)
778 if attack_type == 'ranged':
779 bd += self.ammo_damage
780
781 fstr = ((self.get_strength() - enemy_vit)+4) / 4
782
783 # These are specific to each WS
784 fTP_1000 = fTP[0]
785 fTP_2000 = fTP[1]
786 fTP_3000 = fTP[2]
787
788 if self.tp < 1000:
789 return
790 if 1000 <= self.tp <= 2000:
791 prev_anchor = fTP_1000
792 next_anchor = fTP_2000
793 dTP = float(self.tp - 1000) / 1000.0
794 elif 2000 <= self.tp <= 3000:
795 prev_anchor = fTP_2000
796 next_anchor = fTP_3000
797 dTP = float(self.tp - 2000) / 1000.0
798
799 fTP = prev_anchor + (dTP * (next_anchor - prev_anchor))
800 pDif = self.get_pdif(bd, defense, attack_type, level_difference)
801
802 final_damage = int((bd + fstr + wsc) * fTP * pDif)
803
804 return final_damage
805
806 def get_magic_base_damage(self, spell, enemy):
807
808 if spell in ['Banish', 'Holy']:
809 dINT = self.get_mind() - enemy.get_mind()
810 else:
811 dINT = self.get_intelligence() - enemy.get_intelligence()
812
813 spell_data = Spells().get_spell_data(spell)
814
815 base_damage = 0
816 if dINT < 0:
817 # multiplier ignored since dINT is too low.
818 base_damage = spell_data['base_damage'] + dINT
819 elif 0 <= dINT <= 150:
820 base_damage = spell_data['base_damage'] + (dINT * spell_data['multiplier'])
821 if base_damage < 0:
822 base_damage = 0
823 # We can skip multi-target damage reduction. There is no such thing since we only have a single enemy.
824
825 # Calculate the hit rate so we can determine if the resistance applied to the base damage.
826 resist_level = 0
827 for i in range(0, 3):
828 if not self.is_a_magic_hit(spell, enemy):
829 resist_level += 1
830 base_damage = base_damage / 2
831 if resist_level == 3:
832 base_damage = 0
833
834 # TODO: Add weather later maybe
835
836 # Not adding in magic burst since it is primarily a player thing
837 base_damage *= enemy.target_magic_damage_adjustment
838
839 return base_damage
840
841 # Calculate the base damage against the provided defense
842 # attack_type can be 'ranged' or 'melee'
843 # TODO: Replace enemyvit with the actual enemy variable
844 def get_physical_base_damage(self, defense, attack_type, level_difference, enemy_vit):
845 #print("Defense: {} Type: {} Level diff: {}".format(defense, attack_type, level_difference))
846 # Calculate the attack/defense ratio
847 bd = float(self.weapon_base_damage)
848 if attack_type == 'ranged':
849 bd += self.ammo_damage
850 pDif = self.get_pdif(bd, defense, attack_type, level_difference)
851
650 fstr = ((self.get_strength() - enemy_vit)+4) / 4 852 fstr = ((self.get_strength() - enemy_vit)+4) / 4
651 log("Str: {} Vit: {} fstr: {}".format(self.get_strength(), enemy_vit, fstr)) 853 log("Str: {} Vit: {} fstr: {}".format(self.get_strength(), enemy_vit, fstr))
652 bd = bd + fstr 854 bd = bd + fstr
653 final_damage = int((bd * (pDif_rand * cRatio))) 855 final_damage = int(bd * pDif)
654 return final_damage 856 return final_damage
655 857
656 def attack(self, monster): 858 def attack(self, monster):
657 phy_damage = self.get_physical_base_damage(monster.get_base_defense(), 'melee', monster.level - self.level, monster.get_vitality()) 859 is_a_crit = False
658 self.tp += 64 860 is_a_hit = False
659 return (phy_damage, 'hits') 861 spell = None
862 resisted = False
863 damage = 0
864
865
866 ######
867 # TODO: Build some type of AI / testing to find the most powerful attack and use that (magic, melee, or ranged)
868 ######
869
870 spell = 'Fire'
871 if self.is_a_magic_hit(spell, monster):
872 damage = self.get_magic_base_damage(spell, monster)
873 if damage == 0:
874 resisted = True
875 log("MAGIC DAMAGE: {}".format(damage))
876 is_a_hit = True
877 spell_data = Spells().get_spell_data(spell)
878 self.mp -= spell_data['mp_cost']
879 if self.mp < 0:
880 self.mp = 0
881 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted)
882
883 if self.is_a_hit(monster):
884 # TODO: Make this follow the behavior in temprament and select the right behavior.
885 if self.tp >= 1000:
886 damage = self.get_physical_ws_damage(monster.get_base_defense(), 'melee', [1.0, 1.5, 4.0], [], monster.level - self.level, monster.get_vitality())
887 log("WS DAMAGE: {}".format(damage))
888 self.tp = 0
889 else:
890 damage = self.get_physical_base_damage(monster.get_base_defense(), 'melee', monster.level - self.level, monster.get_vitality())
891 print("STD DAMAGE: {}".format(damage))
892 self.tp += 64
893 is_a_hit = True
894 # Returns the amount of damage and if it is a crit
895 return AttackResponse(is_a_hit, damage, is_a_crit, spell, resisted)
896
897 def is_a_magic_hit(self, spell, monster):
898 hit_rate = self.get_magic_hit_rate(spell, monster)
899 return random.randint(1, 100) < hit_rate
660 900
661 def is_a_hit(self, monster): 901 def is_a_hit(self, monster):
662 hit_rate = self.get_hit_rate(monster.get_evasion(), monster.level - self.level) 902 hit_rate = self.get_hit_rate(monster.get_evasion(), monster.level - self.level)
...@@ -695,23 +935,56 @@ class Action: ...@@ -695,23 +935,56 @@ class Action:
695 self.monster = monster 935 self.monster = monster
696 936
697 class AttackAction(Action): 937 class AttackAction(Action):
698 def __init__(self, attacker, target, damage, message): 938 STANDARD_MESSAGES = ['hit', 'smashed', 'walloped', 'struck', 'beat',
939 'knocked', 'punched', 'belted', 'decked', 'banged',
940 'battered', 'clipped', 'slapped', 'bashed', 'socked',
941 'smacked', 'thumped', 'cuffed', 'flogged', 'whacked',
942 'clobbered', 'swatted']
943 MAGIC_MESSAGES = ['cast']
944 CRIT_MESSAGES = ['CRITICALLY hit']
945
946 def __init__(self, attacker, target, damage, is_a_crit=False, spell=None):
699 self.attacker = attacker 947 self.attacker = attacker
700 self.target = target 948 self.target = target
701 self.damage = damage 949 self.damage = damage
702 self.message = message 950 self.spell = spell
951 if spell:
952 self.message = random.choice(AttackAction.MAGIC_MESSAGES)
953 elif is_a_crit:
954 self.message = random.choice(AttackAction.CRIT_MESSAGES)
955 else:
956 self.message = random.choice(AttackAction.STANDARD_MESSAGES)
957
958 #TODO: Modify and add resist as part of attacks
959 class MagicResistAction(Action):
960 MESSAGES = ['resisted']
961
962 def __init__(self, attacker, target, spell):
963 self.attacker = attacker
964 self.target = target
965 self.spell = spell
966 self.message = random.choice(MagicResistAction.MESSAGES)
703 967
704 class MissAction(Action): 968 class MissAction(Action):
705 def __init__(self, attacker, target, message): 969 MAGIC_MESSAGES = ['fizzled the spell against']
970 MESSAGES = ['missed', 'was unable to hit', 'attack went wide of', 'fumbled the hit on']
971
972 def __init__(self, attacker, target, spell):
706 self.attacker = attacker 973 self.attacker = attacker
707 self.target = target 974 self.target = target
708 self.message = message 975 self.spell = spell
976 if spell:
977 self.message = random.choice(MissAction.MESSAGES)
978 else:
979 self.message = random.choice(MissAction.MAGIC_MESSAGES)
709 980
710 class DefeatAction(Action): 981 class DefeatAction(Action):
711 def __init__(self, attacker, target, message, xp): 982 MESSAGES = ['was defeated', 'was smited', 'was conquered', 'was routed', 'was thwarted',
983 'was vanquished', 'was bested']
984 def __init__(self, attacker, target, xp):
712 self.attacker = attacker 985 self.attacker = attacker
713 self.target = target 986 self.target = target
714 self.message = message 987 self.message = random.choice(DefeatAction.MESSAGES)
715 self.xp = xp 988 self.xp = xp
716 989
717 990
...@@ -725,7 +998,8 @@ class Arena: ...@@ -725,7 +998,8 @@ class Arena:
725 def heal_monsters(self): 998 def heal_monsters(self):
726 self.monster1.hp = self.monster1.get_hp() 999 self.monster1.hp = self.monster1.get_hp()
727 self.monster2.hp = self.monster2.get_hp() 1000 self.monster2.hp = self.monster2.get_hp()
728 1001 self.monster1.mp = self.monster1.get_mp()
1002 self.monster2.mp = self.monster2.get_mp()
729 1003
730 def start(self): 1004 def start(self):
731 self.heal_monsters() 1005 self.heal_monsters()
...@@ -740,11 +1014,16 @@ class Arena: ...@@ -740,11 +1014,16 @@ class Arena:
740 else: 1014 else:
741 primary = self.monster2 1015 primary = self.monster2
742 secondary = self.monster1 1016 secondary = self.monster1
743 1017 # TODO: Add a way to decide if the monster will use magic or melee or range
744 if primary.is_a_hit(secondary): 1018
745 result1 = primary.attack(secondary) 1019 #if primary.is_a_magic_hit(spell, secondary)
746 secondary.apply_damage(result1[0]) 1020 result1 = primary.attack(secondary)
747 actions.append(AttackAction(primary, secondary, result1[0], result1[1])) 1021 if result1.resisted:
1022 actions.append(MagicResistAction(primary, secondary, result1.spell))
1023 elif result1.is_a_hit:
1024 secondary.apply_damage(result1.damage)
1025 actions.append(AttackAction(primary, secondary, result1.damage, result1.is_a_crit,
1026 result1.spell))
748 if secondary.hp <= 0: 1027 if secondary.hp <= 0:
749 level_difference = secondary.level - primary.level 1028 level_difference = secondary.level - primary.level
750 if level_difference in exp_table: 1029 if level_difference in exp_table:
...@@ -753,15 +1032,18 @@ class Arena: ...@@ -753,15 +1032,18 @@ class Arena:
753 xp = exp_table[15] 1032 xp = exp_table[15]
754 else: 1033 else:
755 xp = 0 1034 xp = 0
756 actions.append(DefeatAction(primary, secondary, 'was defeated', xp)) 1035 actions.append(DefeatAction(primary, secondary, xp))
757 return actions 1036 return actions
758 else: 1037 else:
759 actions.append(MissAction(primary, secondary, 'missed')) 1038 actions.append(MissAction(primary, secondary, result1.spell))
760 1039
761 if secondary.is_a_hit(primary): 1040 result2 = secondary.attack(primary)
762 result2 = secondary.attack(primary) 1041 if result2.resisted:
763 primary.apply_damage(result2[0]) 1042 actions.append(MagicResistAction(secondary, primary, result2.spell))
764 actions.append(AttackAction(secondary, primary, result2[0], result2[1])) 1043 elif result2.is_a_hit:
1044 primary.apply_damage(result2.damage)
1045 actions.append(AttackAction(secondary, primary, result2.damage, result2.is_a_crit,
1046 result2.spell))
765 if primary.hp <= 0: 1047 if primary.hp <= 0:
766 level_difference = primary.level - secondary.level 1048 level_difference = primary.level - secondary.level
767 if level_difference in exp_table: 1049 if level_difference in exp_table:
...@@ -770,16 +1052,17 @@ class Arena: ...@@ -770,16 +1052,17 @@ class Arena:
770 xp = exp_table[15] 1052 xp = exp_table[15]
771 else: 1053 else:
772 xp = 0 1054 xp = 0
773 actions.append(DefeatAction(secondary, primary, 'was defeated', xp)) 1055 actions.append(DefeatAction(secondary, primary, xp))
774 return actions 1056 return actions
775 else: 1057 else:
776 actions.append(MissAction(secondary, primary, 'missed')) 1058 actions.append(MissAction(secondary, primary, result2.spell))
777 return actions 1059 return actions
778 1060
779 1061
780 if __name__ == "__main__": 1062 if __name__ == "__main__":
781 #print Families 1063 #print Families
782 1064
1065 print("Spell List: \n{}\n".format(Spells().get_spell_list(20, job=Jobs.BLM, sub_job=Jobs.WHM)))
783 hunt_response = None 1066 hunt_response = None
784 p = Pankration() 1067 p = Pankration()
785 print("Zones: \n\n{}".format('\n'.join(p.list_zones()))) 1068 print("Zones: \n\n{}".format('\n'.join(p.list_zones())))
...@@ -798,7 +1081,7 @@ if __name__ == "__main__": ...@@ -798,7 +1081,7 @@ if __name__ == "__main__":
798 # print(monster.set_strategy(4, 3)) 1081 # print(monster.set_strategy(4, 3))
799 # print(monster.set_strategy(1, 1)) 1082 # print(monster.set_strategy(1, 1))
800 # print(monster.set_strategy(1, 2)) 1083 # print(monster.set_strategy(1, 2))
801 #monster.add_xp(22900) 1084 monster.add_xp(22900)
802 # phy_damage = monster.get_physical_base_damage(100, 'melee', -15) 1085 # phy_damage = monster.get_physical_base_damage(100, 'melee', -15)
803 # print("Phys Attack: {}".format(phy_damage)) 1086 # print("Phys Attack: {}".format(phy_damage))
804 # print(monster.get_base_defense()) 1087 # print(monster.get_base_defense())
...@@ -818,8 +1101,8 @@ if __name__ == "__main__": ...@@ -818,8 +1101,8 @@ if __name__ == "__main__":
818 monster2.set_monster_name('wreckbutt 2') 1101 monster2.set_monster_name('wreckbutt 2')
819 print("1 The Soul Plate Shows: \n\n{}".format(monster)) 1102 print("1 The Soul Plate Shows: \n\n{}".format(monster))
820 print("2 The Soul Plate Shows: \n\n{}".format(monster2)) 1103 print("2 The Soul Plate Shows: \n\n{}".format(monster2))
821 1104 print("MP m1: {}\nMP m2: {}".format(monster.get_mp(), monster2.get_mp()))
822 #monster2.add_xp(16900) 1105 monster2.add_xp(16900)
823 phy_damage = monster2.attack(monster) 1106 phy_damage = monster2.attack(monster)
824 print("Phys Attack: {}".format(phy_damage)) 1107 print("Phys Attack: {}".format(phy_damage))
825 1108
...@@ -836,17 +1119,19 @@ if __name__ == "__main__": ...@@ -836,17 +1119,19 @@ if __name__ == "__main__":
836 actions = battle_arena.step() 1119 actions = battle_arena.step()
837 time.sleep(2) 1120 time.sleep(2)
838 for action in actions: 1121 for action in actions:
1122 if isinstance(action, MagicResistAction):
1123 print("{} {} {} while casting {}.".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.spell))
839 if isinstance(action, MissAction): 1124 if isinstance(action, MissAction):
840 print("{} {} {}.".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name())) 1125 print("{} {} {} while casting {}.".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.spell))
841 if isinstance(action, AttackAction): 1126 if isinstance(action, AttackAction):
842 print("{} {} {} for {}.".format(action.attacker.get_monster_name(), action.message, action.target.get_monster_name(), action.damage)) 1127 print("{} {} {} against {} for {}.".format(action.attacker.get_monster_name(), action.message, action.spell, action.target.get_monster_name(), action.damage))
843 if isinstance(action, DefeatAction): 1128 if isinstance(action, DefeatAction):
844 print("{} {}. {} gains {} xp.".format(action.target.get_monster_name(), action.message, action.attacker.get_monster_name(), action.xp)) 1129 print("{} {} {} gains {} xp.".format(action.target.get_monster_name(), action.message, action.attacker.get_monster_name(), action.xp))
845 action.attacker.hp = 500 1130 action.attacker.hp = 500
846 print("{} {}".format(action.target.hp, action.attacker.hp)) 1131 print("{} {}".format(action.target.hp, action.attacker.hp))
847 fighting = False 1132 fighting = False
848 break 1133 break
849 print("\n\nhp: {} {}\n\n".format(monster.hp, monster2.hp)) 1134 print("\n\nhp: {} {}\nmp: {} {}\n\n".format(monster.hp, monster2.hp, monster.mp, monster2.mp))
850 print("\n{} {}% - {} {}%\n".format(monster.get_monster_name(), monster.get_hp_percent(), monster2.get_monster_name(), monster2.get_hp_percent())) 1135 print("\n{} {}% - {} {}%\n".format(monster.get_monster_name(), monster.get_hp_percent(), monster2.get_monster_name(), monster2.get_hp_percent()))
851 1136
852 1137
......