7825fa6d by Barry

Added the feral skills code into the bot.

1 parent b1760e6e
...@@ -413,6 +413,23 @@ def db_convert_soul_plate_to_reflector(member_id, soul_plate, idx): ...@@ -413,6 +413,23 @@ def db_convert_soul_plate_to_reflector(member_id, soul_plate, idx):
413 return True 413 return True
414 414
415 415
416 def db_convert_soul_plate_to_skill(member_id, soul_plate, idx, skill):
417 pankration_data = db_get_pankration_record(member_id)
418
419 skill_data = pankration_data['feral_skills']
420 if not skill_data:
421 feral_skills = []
422 else:
423 feral_skills = pickle.loads(str(skill_data))
424
425 feral_skills.append(skill)
426 db_update_pankration_record(member_id, 'feral_skills', pickle.dumps(feral_skills))
427
428 #if not db_remove_soul_plate(member_id, idx):
429 # return False
430 return True
431
432
416 def db_register_battle(member_id, reflector, idx, target_member_id=None): 433 def db_register_battle(member_id, reflector, idx, target_member_id=None):
417 pan_record = db_get_pankration_record(member_id) 434 pan_record = db_get_pankration_record(member_id)
418 conn = sqlite3.connect('db.sqlite3') 435 conn = sqlite3.connect('db.sqlite3')
......
No preview for this file type
...@@ -87,14 +87,14 @@ registered_commands = {'!help': 'do_help', '!commands': 'do_help', ...@@ -87,14 +87,14 @@ registered_commands = {'!help': 'do_help', '!commands': 'do_help',
87 '!stars': 'do_stars', 87 '!stars': 'do_stars',
88 '!rigged': 'do_rigged', 88 '!rigged': 'do_rigged',
89 '!listzones': 'do_list_zones', 89 '!listzones': 'do_list_zones',
90 '!huntmonster': 'do_hunt_monster', 90 '!huntmonster': 'do_hunt_monster', '!hunt': 'do_hunt_monster',
91 '!listferalskills': 'do_list_feral_skills', '!listferalskill': 'do_list_feral_skills', 91 '!listskills': 'do_list_feral_skills', '!listferalskills': 'do_list_feral_skills', '!listferalskill': 'do_list_feral_skills',
92 '!listreflectors': 'do_list_reflectors', '!listreflector': 'do_list_reflectors', 92 '!listreflectors': 'do_list_reflectors', '!listreflector': 'do_list_reflectors',
93 '!listsoulplates': 'do_list_soul_plates', '!listsoulplate': 'do_list_soul_plates', 93 '!listsoulplates': 'do_list_soul_plates', '!listsoulplate': 'do_list_soul_plates',
94 '!convertplate': 'do_convert_plate', '!convertsoulplate': 'do_convert_plate', 94 '!convert': 'do_convert_plate', '!convertplate': 'do_convert_plate', '!convertsoulplate': 'do_convert_plate',
95 '!assignskill': 'do_assign_skill',
96 '!registerbattle': 'do_register_battle', 95 '!registerbattle': 'do_register_battle',
97 '!setreflectorname': 'do_set_reflector_name', 96 '!setreflectorname': 'do_set_reflector_name',
97 '!equip': 'do_equip_feral_skills', '!equipskill': 'do_equip_feral_skills', '!equipferalskill': 'do_equip_feral_skills',
98 '!pankration': 'do_pankration', 98 '!pankration': 'do_pankration',
99 } 99 }
100 100
...@@ -1044,7 +1044,7 @@ def do_pankration(client, message_parts, message): ...@@ -1044,7 +1044,7 @@ def do_pankration(client, message_parts, message):
1044 1044
1045 *Hunting for Soul Plates:* 1045 *Hunting for Soul Plates:*
1046 **!listzones** - Returns a list of zones available for hunting and how many credits it costs to search in that zone. Depending on the weather and other factors some zones may not always be available. 1046 **!listzones** - Returns a list of zones available for hunting and how many credits it costs to search in that zone. Depending on the weather and other factors some zones may not always be available.
1047 **!huntmonster <zone>** - An attempt will be made to search for a soul plate (monster) in the zone specified. Each search costs a certain amount of credits. Each zone has a different cost. 1047 **!hunt <zone>** - An attempt will be made to search for a soul plate (monster) in the zone specified. Each search costs a certain amount of credits. Each zone has a different cost.
1048 1048
1049 *Viewing Your Inventory:* 1049 *Viewing Your Inventory:*
1050 **!listsoulplates** - Returns a list of all soul plates you have in your posession. 1050 **!listsoulplates** - Returns a list of all soul plates you have in your posession.
...@@ -1052,10 +1052,10 @@ def do_pankration(client, message_parts, message): ...@@ -1052,10 +1052,10 @@ def do_pankration(client, message_parts, message):
1052 **!listferalskills** - Returns a list of all feral skills you have in your inventory 1052 **!listferalskills** - Returns a list of all feral skills you have in your inventory
1053 1053
1054 *Editing Your Collections:* 1054 *Editing Your Collections:*
1055 **!convertplate <plate number> <convert_to>** - From the list of soul plates you can choose to either convert the plate into a \"reflector\" or \"skill\". 1055 **!convert <plate number> <convert_to>** - From the list of soul plates you can choose to either convert the plate into a \"reflector\" or \"skill\".
1056 Ex: **!convertplate 1 reflector** 1056 Ex: **!convertplate 1 reflector**
1057 **!convertplate 4 skill** 1057 **!convertplate 4 skill**
1058 **!assignskill <reflector number> <skill num>** - Assigns a skill to a reflector. Each skill is worth a certain amount of feral points, each monster has a maximum of feral points available. 1058 **!equip <skill num> <reflector number>** - Assigns a skill to a reflector. Each skill is worth a certain amount of feral points, each monster has a maximum of feral points available.
1059 **!setreflectorname <reflector number> <name>** - This will rename a monster in your collection to a custom name. 1059 **!setreflectorname <reflector number> <name>** - This will rename a monster in your collection to a custom name.
1060 1060
1061 *Arena Battle:* 1061 *Arena Battle:*
...@@ -1150,8 +1150,14 @@ def do_convert_plate(client, message_parts, message): ...@@ -1150,8 +1150,14 @@ def do_convert_plate(client, message_parts, message):
1150 else: 1150 else:
1151 send_message(client, message.channel, 'There was an issue converting your soul plate...Conversion failed.') 1151 send_message(client, message.channel, 'There was an issue converting your soul plate...Conversion failed.')
1152 elif convert_to == "skill": 1152 elif convert_to == "skill":
1153 send_message(client, message.channel, '**Feral Skills are not yet supported**') 1153 soul_plates[plate_num].convert_to_feral_skill()
1154 # do skill stuff 1154 skill = soul_plates[plate_num].convert_to_feral_skill()
1155 if not skill:
1156 send_message(client, message.channel, 'The conversion **failed** the soul plate has been destroyed in the process.')
1157 else:
1158 send_message(client, message.channel, 'Congratulations! The soul plate was converted to feral skill: **{}**'.format(byteify(skill)))
1159 data.db_convert_soul_plate_to_skill(member['member_id'], soul_plates[plate_num], plate_num, skill)
1160 do_list_feral_skills(client, message_parts, message)
1155 pass 1161 pass
1156 else: 1162 else:
1157 send_message(client, message.channel, 'A plate can only be converted into a reflector or skill. Please see !pankration for an example.') 1163 send_message(client, message.channel, 'A plate can only be converted into a reflector or skill. Please see !pankration for an example.')
...@@ -1190,6 +1196,44 @@ def do_list_reflectors(client, message_parts, message): ...@@ -1190,6 +1196,44 @@ def do_list_reflectors(client, message_parts, message):
1190 send_message(client, message.channel, 'You have no reflectors.') 1196 send_message(client, message.channel, 'You have no reflectors.')
1191 1197
1192 1198
1199 def do_equip_feral_skills(client, message_parts, message):
1200 member = data.db_get_member(message.author.id)
1201
1202 skill_num = message_parts[0]
1203 reflector_num = message_parts[1]
1204
1205 pankration_data = data.db_get_pankration_record(member['member_id'])
1206 if pankration_data and pankration_data['reflectors']:
1207 reflectors = pickle.loads(str(pankration_data['reflectors']))
1208
1209 if pankration_data and pankration_data['feral_skills']:
1210 feral_skills = pickle.loads(str(pankration_data['feral_skills']))
1211
1212 if not skill_num.isdigit() or int(skill_num) < 1 or int(skill_num) > len(feral_skills):
1213 send_message(client, message.channel, 'The requested feral skill is invalid. Please provide the number from !listferalskills')
1214 return
1215 skill_num = int(skill_num) - 1
1216 if not reflector_num.isdigit() or int(reflector_num) < 1 or int(reflector_num) > len(reflectors):
1217 send_message(client, message.channel, 'The requested reflector is invalid. Please provide the number from !listreflectors')
1218 return
1219 reflector_num = int(reflector_num) - 1
1220
1221 skill_name = feral_skills[skill_num]
1222 print(reflector_num)
1223 print(reflectors[reflector_num])
1224 success, err_message = reflectors[reflector_num].equip_feral_skill(skill_name)
1225 if not success:
1226 send_message(client, message.channel, byteify(err_message))
1227 else:
1228 data.db_update_pankration_record(member['member_id'], 'reflectors', pickle.dumps(reflectors))
1229 send_message(client, message.channel, "{} has been equipped.\n{}".format(skill_name, reflectors[reflector_num]))
1230
1231 else:
1232 send_message(client, message.channel, 'You have no feral skills. You can get more feral skills by hunting for soul plates and converting them into skills.')
1233 else:
1234 send_message(client, message.channel, 'You have no reflectors. You can get more reflectors by hunting monsters and converting soul plates into reflectors.')
1235
1236
1193 def do_list_feral_skills(client, message_parts, message): 1237 def do_list_feral_skills(client, message_parts, message):
1194 member = data.db_get_member(message.author.id) 1238 member = data.db_get_member(message.author.id)
1195 1239
......
...@@ -8,13 +8,33 @@ import operator ...@@ -8,13 +8,33 @@ import operator
8 8
9 def log(message): 9 def log(message):
10 try: 10 try:
11 print(message)
11 logging.warning("{} - {}".format(datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), message)) 12 logging.warning("{} - {}".format(datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), message))
12 except: 13 except:
13 pass 14 pass
14 15
15 ATTACK_EFFECT_PERCENTAGE = 25 16 ATTACK_EFFECT_PERCENTAGE = 25
16 FIND_PERCENTAGE = 100 17 FIND_PERCENTAGE = 80
17 SKILL_PERCENT = 80 18 SKILL_PERCENT = 60
19
20 class WeightedChoice(object):
21 def __init__(self, weights):
22 """Pick items with weighted probabilities.
23
24 weights
25 a sequence of tuples of item and it's weight.
26 """
27 self._total_weight = 0.
28 self._item_levels = []
29 for item, weight in weights.iteritems():
30 self._total_weight += weight
31 self._item_levels.append((self._total_weight, item))
32
33 def pick(self):
34 pick = self._total_weight * (random.randint(1, 10)/10)
35 for level, item in self._item_levels:
36 if level >= pick:
37 return item
18 38
19 class HuntResponse: 39 class HuntResponse:
20 ERROR = -1 40 ERROR = -1
...@@ -85,7 +105,8 @@ class Jobs: ...@@ -85,7 +105,8 @@ class Jobs:
85 WAR = 21 105 WAR = 21
86 WHM = 22 106 WHM = 22
87 107
88 def get_job_name(self, job): 108 @staticmethod
109 def get_job_name(job):
89 members = [attr for attr in dir(Jobs()) if not callable(attr) and not attr.startswith("__") and not attr.startswith("get_job_name")] 110 members = [attr for attr in dir(Jobs()) if not callable(attr) and not attr.startswith("__") and not attr.startswith("get_job_name")]
90 return members[job-1] 111 return members[job-1]
91 112
...@@ -135,95 +156,100 @@ PhysicalDamageTypes = { ...@@ -135,95 +156,100 @@ PhysicalDamageTypes = {
135 'piercing': ['Dagger', 'Polearm', 'Archery', 'Marksmanship', 'Shuriken', 'Boomerang'] 156 'piercing': ['Dagger', 'Polearm', 'Archery', 'Marksmanship', 'Shuriken', 'Boomerang']
136 } 157 }
137 158
138 FeralSkills = { 159 class FeralSkills:
139 # 'Airy Shield': {'fp_cost': 0, 'type': 'Enhancing', 'sub_type': 'arrow shield', 'shadows': 'ignore', 'range': None, 'aoe': False, 'spell': 'arrow shield'}, 160 SkillsList = {
140 # 'Binding Wave': {'type': 'Enfeebling', 'shadows': 'ignore', 'range': 15, 'aoe': True, 'spell': 'bind'}, 161 # 'Airy Shield': {'fp_cost': 0, 'type': 'Enhancing', 'sub_type': 'arrow shield', 'shadows': 'ignore', 'range': None, 'aoe': False, 'spell': 'arrow shield'},
141 # 'Dire Straight': {'type': 'Physical', 'shadows': 'wipe', 'range': None, 'aoe': False}, 162 # 'Binding Wave': {'type': 'Enfeebling', 'shadows': 'ignore', 'range': 15, 'aoe': True, 'spell': 'bind'},
142 # 'Dismemberment': {'type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, # causes the monster to lose a body part 163 # 'Dire Straight': {'type': 'Physical', 'shadows': 'wipe', 'range': None, 'aoe': False},
143 # 'Earthshatter': {'type': 'Piercing', 'shadows': 'wipe', 'range': None, 'aoe': True}, 164 # 'Dismemberment': {'type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, # causes the monster to lose a body part
144 # 'Eyes On Me': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 112, 'shadows': 'absorb', 'range': 13, 'aoe': False}, 165 # 'Earthshatter': {'type': 'Piercing', 'shadows': 'wipe', 'range': None, 'aoe': True},
145 # 'Hypnosis': {'type': 'Enfeebling', 'sub_type': 'sleep', 'shadows': 'ignore', 'range': 'gaze', 'aoe': True}, 166 # 'Eyes On Me': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 112, 'shadows': 'absorb', 'range': 13, 'aoe': False},
146 # 'Magic Barrier': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 29, 'shadows': 'absorb', 'range': None, 'aoe': True}, 167 # 'Hypnosis': {'type': 'Enfeebling', 'sub_type': 'sleep', 'shadows': 'ignore', 'range': 'gaze', 'aoe': True},
147 # 'Sinker Drill': {'type': 'Physical', 'sub_type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False}, 168 # 'Magic Barrier': {'type': 'Magical', 'sub_type': 'Dark', 'mp_cost': 29, 'shadows': 'absorb', 'range': None, 'aoe': True},
148 'Accuracy +15%': {'fp_cost': 23, 'effect': 'acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 169 # 'Sinker Drill': {'type': 'Physical', 'sub_type': 'Piercing', 'shadows': 'absorb', 'range': None, 'aoe': False},
149 'Accuracy +30%': {'fp_cost': 30, 'effect': 'acc', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 170 'Accuracy +15%': {'fp_cost': 23, 'effect': 'acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
150 'Accuracy Bonus': {'fp_cost': 30, 'effect': 'acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 171 'Accuracy +30%': {'fp_cost': 30, 'effect': 'acc', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
151 'AGI +25': {'fp_cost': 17, 'effect': 'agi', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 172 'Accuracy Bonus': {'fp_cost': 30, 'effect': 'acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
152 'AGI +50': {'fp_cost': 23, 'effect': 'agi', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 173 'AGI +25': {'fp_cost': 17, 'effect': 'agi', 'amount': 25, '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}, 174 'AGI +50': {'fp_cost': 23, 'effect': 'agi', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
154 'Amnesia Attack': {'fp_cost': 47, 'effect': 'amnesia', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 175 'AGI Bonus': {'fp_cost': 23, 'effect': 'agi', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
155 'Amorph Killer': {'fp_cost': 8, 'effect': 'amorph_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 176 'Amnesia Attack': {'fp_cost': 47, 'effect': 'amnesia', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
156 'Attack +15%': {'fp_cost': 23, 'effect': 'attack', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 177 'Amorph Killer': {'fp_cost': 8, 'effect': 'amorph_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
157 'Attack Bonus': {'fp_cost': 30, 'effect': 'attack', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 178 'Attack +15%': {'fp_cost': 23, 'effect': 'attack', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
158 'Auto Refresh': {'fp_cost': 38, 'effect': 'auto_refresh', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 179 'Attack Bonus': {'fp_cost': 30, 'effect': 'attack', 'amount': 10, '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}, 180 'Auto Refresh': {'fp_cost': 38, 'effect': 'auto_refresh', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
160 'Auto Regain': {'fp_cost': 70, 'effect': 'auto_regain', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 181 'Auto Refresh +5': {'fp_cost': 30, 'effect': 'auto_refresh', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
161 'Auto Regain +3': {'fp_cost': 58, 'effect': 'auto_regain', 'amount': 3, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 182 'Auto Regain': {'fp_cost': 70, 'effect': 'auto_regain', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
162 'Auto Regen': {'fp_cost': 47, 'effect': 'auto_regen', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 183 'Auto Regain +3': {'fp_cost': 58, 'effect': 'auto_regain', 'amount': 3, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
163 'Auto Regen +5': {'fp_cost': 38, 'effect': 'auto_regen', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 184 'Auto Regen': {'fp_cost': 47, 'effect': 'auto_regen', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
164 'Aquan Killer': {'fp_cost': 8, 'effect': 'aquan_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 185 'Auto Regen +5': {'fp_cost': 38, 'effect': 'auto_regen', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
165 'Bird Killer': {'fp_cost': 8, 'effect': 'bird_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 186 'Aquan Killer': {'fp_cost': 8, 'effect': 'aquan_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}, 187 'Bird Killer': {'fp_cost': 8, 'effect': 'bird_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
167 'CHR +25': {'fp_cost': 17, 'effect': 'cha', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 188 'Blinding Attack': {'fp_cost': 23, 'effect': 'blind', 'amount': -20, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
168 'CHR Bonus': {'fp_cost': 23, 'effect': 'cha', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 189 'CHR +25': {'fp_cost': 17, 'effect': 'cha', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
169 'Curse Attack': {'fp_cost': 23, 'effect': 'curse', 'amount': -20, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 190 'CHR Bonus': {'fp_cost': 23, 'effect': 'cha', 'amount': 15, '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}, 191 'Curse Attack': {'fp_cost': 23, 'effect': 'curse', 'amount': -20, '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}, 192 'Damage Resistance +15%': {'fp_cost': 30, 'effect': 'damage_resist', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
172 'Dark Resistance +2': {'fp_cost': 8, 'effect': 'dark_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 193 'Damage Resistance Bonus': {'fp_cost': 38, 'effect': 'damage_resist', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
173 'Dark Resistance Bonus': {'fp_cost': 12, 'effect': 'dark_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 194 'Dark Resistance +2': {'fp_cost': 8, 'effect': 'dark_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
174 'Defense +15%': {'fp_cost': 23, 'effect': 'def', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 195 'Dark Resistance Bonus': {'fp_cost': 12, 'effect': 'dark_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
175 'Defense Bonus': {'fp_cost': 30, 'effect': 'def', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 196 'Defense +15%': {'fp_cost': 23, 'effect': 'def', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
176 'Defense +30%': {'fp_cost': 30, 'effect': 'def', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 197 'Defense Bonus': {'fp_cost': 30, 'effect': 'def', 'amount': 10, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
177 'DEX +25': {'fp_cost': 17, 'effect': 'dex', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 198 'Defense +30%': {'fp_cost': 30, 'effect': 'def', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
178 'DEX +50': {'fp_cost': 23, 'effect': 'dex', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 199 'DEX +25': {'fp_cost': 17, 'effect': 'dex', 'amount': 25, '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}, 200 'DEX +50': {'fp_cost': 23, 'effect': 'dex', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
180 'Demon Killer': {'fp_cost': 8, 'effect': 'demon_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 201 'DEX Bonus': {'fp_cost': 23, 'effect': 'dex', 'amount': 15, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
181 'Dragon Killer': {'fp_cost': 8, 'effect': 'dragon_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 202 'Demon Killer': {'fp_cost': 8, 'effect': 'demon_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}, 203 'Dragon Killer': {'fp_cost': 8, 'effect': 'dragon_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
183 'Earth Resistance Bonus': {'fp_cost': 12, 'effect': 'earth_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 204 'Earth Resistance +2': {'fp_cost': 8, 'effect': 'earth_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
184 'Evasion +15%': {'fp_cost': 23, 'effect': 'eva', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 205 'Earth Resistance Bonus': {'fp_cost': 12, 'effect': 'earth_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
185 'Evasion Bonus': {'fp_cost': 30, 'effect': 'eva', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 206 'Evasion +15%': {'fp_cost': 23, 'effect': 'eva', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
186 'Fire Resistance +2': {'fp_cost': 8, 'effect': 'fire_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 207 'Evasion Bonus': {'fp_cost': 30, 'effect': 'eva', 'amount': 5, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
187 'Fire Resistance Bonus': {'fp_cost': 12, 'effect': 'fire_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 208 'Fire Resistance +2': {'fp_cost': 8, 'effect': 'fire_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
188 'HP Max Bonus': {'fp_cost': 12, 'effect': 'hp', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 209 'Fire Resistance Bonus': {'fp_cost': 12, 'effect': 'fire_resist', '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}, 210 'HP Max Bonus': {'fp_cost': 12, 'effect': 'hp', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
190 'HP Max +30%': {'fp_cost': 30, 'effect': 'hp', 'amount': 30, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 211 'HP Max +15%': {'fp_cost': 23, 'effect': 'hp', 'amount': 15, '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}, 212 'HP Max +30%': {'fp_cost': 30, 'effect': 'hp', 'amount': 30, 'is_percent': True, '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}, 213 'HP Max +50': {'fp_cost': 8, 'effect': 'hp', 'amount': 50, '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}, 214 'Ice Resistance +2': {'fp_cost': 8, 'effect': 'ice_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
194 'INT Bonus': {'fp_cost': 23, 'effect': 'int', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 215 'Ice Resistance Bonus': {'fp_cost': 12, 'effect': 'ice_resist', '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}, 216 'INT Bonus': {'fp_cost': 23, 'effect': 'int', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
196 'INT +50': {'fp_cost': 23, 'effect': 'int', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 217 'INT +25': {'fp_cost': 17, 'effect': 'int', 'amount': 25, '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}, 218 'INT +50': {'fp_cost': 23, 'effect': 'int', 'amount': 50, '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}, 219 'Light Resistance +2': {'fp_cost': 8, 'effect': 'light_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}, 220 'Lightning Resistance +2': {'fp_cost': 8, 'effect': 'lightning_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
200 'MP Max Bonus': {'fp_cost': 17, 'effect': 'mp', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 221 'Lizard Killer': {'fp_cost': 8, 'effect': 'lizard_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
201 'MP Max +15%': {'fp_cost': 12, 'effect': 'mp', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 222 'MP Max Bonus': {'fp_cost': 17, 'effect': 'mp', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
202 'MP Max +50': {'fp_cost': 5, 'effect': 'mp', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 223 'MP Max +15%': {'fp_cost': 12, 'effect': 'mp', 'amount': 15, 'is_percent': True, '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}, 224 'MP Max +50': {'fp_cost': 5, 'effect': 'mp', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
204 'Magic Accuracy 15%': {'fp_cost': 23, 'effect': 'magic_acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 225 'Magic Accuracy Bonus': {'fp_cost': 30, 'effect': 'magic_acc', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
205 'Magic Attack Bonus': {'fp_cost': 30, 'effect': 'magic_attack', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 226 'Magic Accuracy 15%': {'fp_cost': 23, 'effect': 'magic_acc', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
206 'Magic Attack +15%': {'fp_cost': 23, 'effect': 'magic_attack', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 227 'Magic Attack Bonus': {'fp_cost': 30, 'effect': 'magic_attack', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
207 'MND Bonus': {'fp_cost': 23, 'effect': 'mnd', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 228 'Magic Attack +15%': {'fp_cost': 23, 'effect': 'magic_attack', 'amount': 15, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
208 'MND +25': {'fp_cost': 17, 'effect': 'mnd', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 229 'MND Bonus': {'fp_cost': 23, 'effect': 'mnd', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
209 'MND +50': {'fp_cost': 23, 'effect': 'mnd', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 230 'MND +25': {'fp_cost': 17, 'effect': 'mnd', 'amount': 25, '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}, 231 'MND +50': {'fp_cost': 23, 'effect': 'mnd', 'amount': 50, '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}, 232 'Poisoning Attack': {'fp_cost': 17, 'effect': 'poison', 'amount': -4, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
212 'Silencing Attack': {'fp_cost': 30, 'effect': 'silence', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 233 'Plantoid Killer': {'fp_cost': 8, 'effect': 'plantoid_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
213 'Store TP +10%': {'fp_cost': 38, 'effect': 'store_tp', 'amount': 10, 'is_percent': True, 'expires_seconds': 0, 'levels': False}, 234 'Silencing Attack': {'fp_cost': 30, 'effect': 'silence', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
214 'STR Bonus': {'fp_cost': 23, 'effect': 'str', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 235 'Store TP +10%': {'fp_cost': 38, 'effect': 'store_tp', 'amount': 10, 'is_percent': True, 'expires_seconds': 0, 'levels': False},
215 'STR +25': {'fp_cost': 17, 'effect': 'str', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 236 'STR Bonus': {'fp_cost': 23, 'effect': 'str', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
216 'STR +50': {'fp_cost': 23, 'effect': 'str', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 237 'STR +25': {'fp_cost': 17, 'effect': 'str', 'amount': 25, '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}, 238 'STR +50': {'fp_cost': 23, 'effect': 'str', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
218 'Vermin Killer': {'fp_cost': 8, 'effect': 'vermin_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True}, 239 'Undead Killer': {'fp_cost': 8, 'effect': 'undead_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}, 240 'Vermin Killer': {'fp_cost': 8, 'effect': 'vermin_killer', 'amount': 5, 'is_percent': True, 'expires_seconds': 0, 'levels': True},
220 'VIT +25': {'fp_cost': 17, 'effect': 'vit', 'amount': 25, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 241 'VIT Bonus': {'fp_cost': 23, 'effect': 'vit', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
221 'VIT +50': {'fp_cost': 23, 'effect': 'vit', 'amount': 50, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 242 'VIT +25': {'fp_cost': 17, 'effect': 'vit', 'amount': 25, '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}, 243 'VIT +50': {'fp_cost': 23, 'effect': 'vit', 'amount': 50, '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}, 244 'Water Resistance +2': {'fp_cost': 8, 'effect': 'water_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
224 'Wind Resistance +2': {'fp_cost': 8, 'effect': 'wind_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False}, 245 'Water Resistance Bonus': {'fp_cost': 12, 'effect': 'water_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
225 'Wind Resistance Bonus': {'fp_cost': 12, 'effect': 'wind_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True}, 246 'Wind Resistance +2': {'fp_cost': 8, 'effect': 'wind_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
226 } 247 'Wind Resistance Bonus': {'fp_cost': 12, 'effect': 'wind_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
248 }
249
250 @staticmethod
251 def get_skill(skill_name):
252 return FeralSkills.SkillsList.get(skill_name)
227 253
228 class Spells: 254 class Spells:
229 SpellTypes = { 255 SpellTypes = {
...@@ -310,7 +336,7 @@ Families = { ...@@ -310,7 +336,7 @@ Families = {
310 'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD], 336 'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD],
311 'innate_feral_skills': [],#'Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'], 337 'innate_feral_skills': [],#'Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'],
312 'target_magic_damage_adjustment': 1.00, 338 'target_magic_damage_adjustment': 1.00,
313 'feral_skills_conversion': ['Accuracy +15%'], 339 'feral_skills_conversion': {'Accuracy +15%': 50, 'Attack Bonus': 20},
314 'type': 'Arcana', 340 'type': 'Arcana',
315 'strong_vs': ['Dark'], 341 'strong_vs': ['Dark'],
316 'charmable': False, 342 'charmable': False,
...@@ -357,7 +383,7 @@ Families = { ...@@ -357,7 +383,7 @@ Families = {
357 'available_support_job': [Jobs.BLM, Jobs.RDM, Jobs.WAR], 383 'available_support_job': [Jobs.BLM, Jobs.RDM, Jobs.WAR],
358 'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'], 384 'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'],
359 'type': 'Demon', 385 'type': 'Demon',
360 'feral_skills_conversion': ['Accuracy +15%'], 386 'feral_skills_conversion': {'Accuracy +15%': 50},
361 'traits': ['magic defence bonus +25%'], 387 'traits': ['magic defence bonus +25%'],
362 'target_magic_damage_adjustment': 0.75, 388 'target_magic_damage_adjustment': 0.75,
363 'charmable': False, 389 'charmable': False,
...@@ -402,7 +428,6 @@ Monsters = { ...@@ -402,7 +428,6 @@ Monsters = {
402 'Mechanical Menace': { 428 'Mechanical Menace': {
403 'family': 'acrolith', 429 'family': 'acrolith',
404 'zone': ['abyssea - uleguerand'], 430 'zone': ['abyssea - uleguerand'],
405 'feral_skills_conversion': [],
406 'hp': 20, 431 'hp': 20,
407 'mp': 20, 432 'mp': 20,
408 'weapon_base_damage': 18 433 'weapon_base_damage': 18
...@@ -410,7 +435,6 @@ Monsters = { ...@@ -410,7 +435,6 @@ Monsters = {
410 'Floating Eye': { 435 'Floating Eye': {
411 'family': 'ahriman', 436 'family': 'ahriman',
412 'zone': ['ranguemont pass'], 437 'zone': ['ranguemont pass'],
413 'feral_skills_conversion': [],
414 'hp': 15, 438 'hp': 15,
415 'mp': 24, 439 'mp': 24,
416 'weapon_base_damage': 5, 440 'weapon_base_damage': 5,
...@@ -419,7 +443,6 @@ Monsters = { ...@@ -419,7 +443,6 @@ Monsters = {
419 'Bat Eye': { 443 'Bat Eye': {
420 'family': 'ahriman', 444 'family': 'ahriman',
421 'zone': ['ranguemont pass', 'beaucedine glacier'], 445 'zone': ['ranguemont pass', 'beaucedine glacier'],
422 'feral_skills_conversion': [],
423 'hp': 15, 446 'hp': 15,
424 'mp': 24, 447 'mp': 24,
425 'weapon_base_damage': 5, 448 'weapon_base_damage': 5,
...@@ -428,7 +451,6 @@ Monsters = { ...@@ -428,7 +451,6 @@ Monsters = {
428 'Evil Eye': { 451 'Evil Eye': {
429 'family': 'ahriman', 452 'family': 'ahriman',
430 'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'], 453 'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'],
431 'feral_skills_conversion': [],
432 'hp': 15, 454 'hp': 15,
433 'mp': 24, 455 'mp': 24,
434 'weapon_base_damage': 5, 456 'weapon_base_damage': 5,
...@@ -436,7 +458,6 @@ Monsters = { ...@@ -436,7 +458,6 @@ Monsters = {
436 'Morbid Eye': { 458 'Morbid Eye': {
437 'family': 'ahriman', 459 'family': 'ahriman',
438 'zone': ['castle zvahl baileys', 'castle zvahl keep'], 460 'zone': ['castle zvahl baileys', 'castle zvahl keep'],
439 'feral_skills_conversion': [],
440 'hp': 15, 461 'hp': 15,
441 'mp': 24, 462 'mp': 24,
442 'weapon_base_damage': 5 463 'weapon_base_damage': 5
...@@ -444,7 +465,6 @@ Monsters = { ...@@ -444,7 +465,6 @@ Monsters = {
444 'Deadly Iris': { 465 'Deadly Iris': {
445 'family': 'ahriman', 466 'family': 'ahriman',
446 'zone': ['castle zvahl keep'], 467 'zone': ['castle zvahl keep'],
447 'feral_skills_conversion': [],
448 'hp': 15, 468 'hp': 15,
449 'mp': 24, 469 'mp': 24,
450 'weapon_base_damage': 5 470 'weapon_base_damage': 5
...@@ -452,7 +472,6 @@ Monsters = { ...@@ -452,7 +472,6 @@ Monsters = {
452 'Ahriman': { 472 'Ahriman': {
453 'family': 'ahriman', 473 'family': 'ahriman',
454 'zone': ['castle zvahl baileys'], 474 'zone': ['castle zvahl baileys'],
455 'feral_skills_conversion': [],
456 'hp': 15, 475 'hp': 15,
457 'mp': 24, 476 'mp': 24,
458 'weapon_base_damage': 5 477 'weapon_base_damage': 5
...@@ -460,7 +479,6 @@ Monsters = { ...@@ -460,7 +479,6 @@ Monsters = {
460 'Fachan': { 479 'Fachan': {
461 'family': 'ahriman', 480 'family': 'ahriman',
462 'zone': ['uleguerand range'], 481 'zone': ['uleguerand range'],
463 'feral_skills_conversion': [],
464 'hp': 15, 482 'hp': 15,
465 'mp': 24, 483 'mp': 24,
466 'weapon_base_damage': 5 484 'weapon_base_damage': 5
...@@ -468,7 +486,6 @@ Monsters = { ...@@ -468,7 +486,6 @@ Monsters = {
468 'Gawper': { 486 'Gawper': {
469 'family': 'ahriman', 487 'family': 'ahriman',
470 'zone': ['beaucedine glacier (s)'], 488 'zone': ['beaucedine glacier (s)'],
471 'feral_skills_conversion': [],
472 'hp': 15, 489 'hp': 15,
473 'mp': 24, 490 'mp': 24,
474 'weapon_base_damage': 5 491 'weapon_base_damage': 5
...@@ -476,7 +493,6 @@ Monsters = { ...@@ -476,7 +493,6 @@ Monsters = {
476 'Menacing Eye': { 493 'Menacing Eye': {
477 'family': 'ahriman', 494 'family': 'ahriman',
478 'zone': ['xarcabard (s)'], 495 'zone': ['xarcabard (s)'],
479 'feral_skills_conversion': [],
480 'hp': 15, 496 'hp': 15,
481 'mp': 24, 497 'mp': 24,
482 'weapon_base_damage': 5 498 'weapon_base_damage': 5
...@@ -484,7 +500,6 @@ Monsters = { ...@@ -484,7 +500,6 @@ Monsters = {
484 'Ogler': { 500 'Ogler': {
485 'family': 'ahriman', 501 'family': 'ahriman',
486 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], 502 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'],
487 'feral_skills_conversion': [],
488 'hp': 15, 503 'hp': 15,
489 'mp': 24, 504 'mp': 24,
490 'weapon_base_damage': 5 505 'weapon_base_damage': 5
...@@ -492,7 +507,6 @@ Monsters = { ...@@ -492,7 +507,6 @@ Monsters = {
492 'Smolenkos': { 507 'Smolenkos': {
493 'family': 'ahriman', 508 'family': 'ahriman',
494 'zone': ['uleguerand range'], 509 'zone': ['uleguerand range'],
495 'feral_skills_conversion': [],
496 'hp': 15, 510 'hp': 15,
497 'mp': 24, 511 'mp': 24,
498 'weapon_base_damage': 5 512 'weapon_base_damage': 5
...@@ -500,7 +514,6 @@ Monsters = { ...@@ -500,7 +514,6 @@ Monsters = {
500 'Doom Lens': { 514 'Doom Lens': {
501 'family': 'ahriman', 515 'family': 'ahriman',
502 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'], 516 'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'],
503 'feral_skills_conversion': [],
504 'hp': 15, 517 'hp': 15,
505 'mp': 24, 518 'mp': 24,
506 'weapon_base_damage': 5 519 'weapon_base_damage': 5
...@@ -508,7 +521,6 @@ Monsters = { ...@@ -508,7 +521,6 @@ Monsters = {
508 'Scowlenkos': { 521 'Scowlenkos': {
509 'family': 'ahriman', 522 'family': 'ahriman',
510 'zone': ['uleguerand range'], 523 'zone': ['uleguerand range'],
511 'feral_skills_conversion': [],
512 'hp': 15, 524 'hp': 15,
513 'mp': 24, 525 'mp': 24,
514 'weapon_base_damage': 5 526 'weapon_base_damage': 5
...@@ -631,13 +643,6 @@ class Monster: ...@@ -631,13 +643,6 @@ class Monster:
631 self.innate_feral_skills = innate_feral_skills 643 self.innate_feral_skills = innate_feral_skills
632 self.equipped_feral_skills = equipped_feral_skills 644 self.equipped_feral_skills = equipped_feral_skills
633 645
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
641 self.discipline_level = dicipline_level 646 self.discipline_level = dicipline_level
642 self.temperament_posture = family['temperament_posture']['initial_value'] 647 self.temperament_posture = family['temperament_posture']['initial_value']
643 self.temperament_attitude = family['temperament_attitude']['initial_value'] 648 self.temperament_attitude = family['temperament_attitude']['initial_value']
...@@ -670,11 +675,24 @@ class Monster: ...@@ -670,11 +675,24 @@ class Monster:
670 675
671 def __str__(self): 676 def __str__(self):
672 try: 677 try:
673 return "**{}**\n*Stats:*\nFamily: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nFeral Points: {}\n\nWins: {}\nLosses: {}".format(self.get_monster_name(), self.family_name, self.level, Jobs().get_job_name(self.main_job), Jobs().get_job_name(self.support_job), ', '.join(self.innate_feral_skills), ', '.join(self.equipped_feral_skills), self.get_fp(), self.wins, self.losses) 678 return "**{}**\n*Stats:*\nFamily: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nFeral Points: {}\n\nWins: {}\nLosses: {}".format(self.get_monster_name(), self.family_name, self.level, Jobs.get_job_name(self.main_job), Jobs.get_job_name(self.support_job), ', '.join(self.innate_feral_skills), ', '.join(self.equipped_feral_skills), self.get_fp(), self.wins, self.losses)
674 except AttributeError: 679 except AttributeError:
675 return "Old Format monster, unable to display." 680 return "Old Format monster, unable to display."
676 #return "Family: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nDicipline Level: {}\nTemperament...".format(self.family, self.level, self.main_job, self.support_job, self.innate_feral_skills, self.equipped_feral_skills, self.discipline_level) 681 #return "Family: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nDicipline Level: {}\nTemperament...".format(self.family, self.level, self.main_job, self.support_job, self.innate_feral_skills, self.equipped_feral_skills, self.discipline_level)
677 682
683
684 def pre_fight_init(self):
685 self.status_effects = {}
686 self.hp = self.get_hp()
687 self.mp = self.get_mp()
688 effects = self.get_status_effect_list()
689 for feral_skill in self.innate_feral_skills + self.equipped_feral_skills:
690 effect = effects[FeralSkills.get_skill(feral_skill)['effect']]
691 # Should init = true
692 if effect:
693 self.apply_feral_skill(feral_skill)
694
695
678 def get_monster_name(self): 696 def get_monster_name(self):
679 if self.custom_name: 697 if self.custom_name:
680 return self.custom_name 698 return self.custom_name
...@@ -686,14 +704,14 @@ class Monster: ...@@ -686,14 +704,14 @@ class Monster:
686 704
687 def get_soul_plate_description(self): 705 def get_soul_plate_description(self):
688 try: 706 try:
689 return "*Family:*\n**{}**\nJob Trait: {}\nFeral Points: {}".format(self.family_name, Jobs().get_job_name(self.main_job), self.get_fp()) 707 return "*Family:*\n**{}**\nJob Trait: {}\nFeral Points: {}".format(self.family_name, Jobs.get_job_name(self.main_job), self.get_fp())
690 except AttributeError: 708 except AttributeError:
691 return "Old Format monster, unable to display." 709 return "Old Format monster, unable to display."
692 #return "Family: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nDicipline Level: {}\nTemperament...".format(self.family, self.level, self.main_job, self.support_job, self.innate_feral_skills, self.equipped_feral_skills, self.discipline_level) 710 #return "Family: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nDicipline Level: {}\nTemperament...".format(self.family, self.level, self.main_job, self.support_job, self.innate_feral_skills, self.equipped_feral_skills, self.discipline_level)
693 711
694 def get_reflector_description(self): 712 def get_reflector_description(self):
695 try: 713 try:
696 return "**{}**\n*Stats:*\nFamily: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nFeral Points: {}\n\nWins: {}\nLosses: {}".format(self.get_monster_name(), self.family_name, self.level, Jobs().get_job_name(self.main_job), Jobs().get_job_name(self.support_job), ', '.join(self.innate_feral_skills), ', '.join(self.equipped_feral_skills), self.get_fp(), self.wins, self.losses) 714 return "**{}**\n*Stats:*\nFamily: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nFeral Points: {}\n\nWins: {}\nLosses: {}".format(self.get_monster_name(), self.family_name, self.level, Jobs.get_job_name(self.main_job), Jobs.get_job_name(self.support_job), ', '.join(self.innate_feral_skills), ', '.join(self.equipped_feral_skills), self.get_fp(), self.wins, self.losses)
697 except AttributeError: 715 except AttributeError:
698 return "Old Format monster, unable to display." 716 return "Old Format monster, unable to display."
699 #return "Family: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nDicipline Level: {}\nTemperament...".format(self.family, self.level, self.main_job, self.support_job, self.innate_feral_skills, self.equipped_feral_skills, self.discipline_level) 717 #return "Family: {}\nLevel: {}\nMain Job: {}\nSupport Job: {}\nInnate Feral Skills: {}\nEquipped Feral Skills: {}\nDicipline Level: {}\nTemperament...".format(self.family, self.level, self.main_job, self.support_job, self.innate_feral_skills, self.equipped_feral_skills, self.discipline_level)
...@@ -716,6 +734,15 @@ class Monster: ...@@ -716,6 +734,15 @@ class Monster:
716 self.get_status_effect('mp', main_mp + sub_mp)) 734 self.get_status_effect('mp', main_mp + sub_mp))
717 735
718 736
737 def get_available_fp(self):
738 ttl_used = 0
739 for fs in self.equipped_feral_skills:
740 skill = FeralSkills.SkillsList.get(fs)
741 if not skill:
742 return False
743 ttl_used += skill['fp_cost']
744 return self.get_fp() - ttl_used
745
719 def get_fp(self): 746 def get_fp(self):
720 return int(self.level / self.family['fp_per_level'] + self.family['base_fp']) 747 return int(self.level / self.family['fp_per_level'] + self.family['base_fp'])
721 748
...@@ -966,14 +993,35 @@ class Monster: ...@@ -966,14 +993,35 @@ class Monster:
966 993
967 return base_damage 994 return base_damage
968 995
996 def equip_feral_skill(self, feral_skill):
997 fs = FeralSkills.get_skill(feral_skill)
998 log("{} {}".format(feral_skill, self.equipped_feral_skills))
999 if feral_skill in self.equipped_feral_skills:
1000 return False, "Unable to equip the feral skill. The monster already has this skill equipped."
1001 if self.get_available_fp() >= fs['fp_cost']:
1002 self.equipped_feral_skills.append(feral_skill)
1003 return True, ""
1004 else:
1005 return False, "Your monster does not have enough feral points. {} of {} feral points available.", format(self.get_available_fp(), self.get_fp())
1006
1007 def unequip_feral_skill(self, feral_skill):
1008 self.equipped_feral_skills.remove(feral_skill)
1009
969 def apply_feral_skill(self, feral_skill): 1010 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}, 1011 # 'Amnesia Attack': {'fp_cost': 47, 'effect': 'amnesia', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
971 fs = FeralSkills[feral_skill] 1012 fs = FeralSkills.get_skill(feral_skill)
972 self.set_status_effect(fs['effect'], fs['amount'], fs['is_percent'], fs['expires_seconds']) 1013 self.set_status_effect(fs['effect'], fs['amount'], fs['is_percent'], fs['expires_seconds'])
973 if feral_skill == 'Curse Attack': 1014 if feral_skill == 'Curse Attack':
974 self.hp = min(self.hp, self.get_hp()) 1015 self.hp = min(self.hp, self.get_hp())
975 self.mp = min(self.mp, self.get_mp()) 1016 self.mp = min(self.mp, self.get_mp())
976 1017
1018 def convert_to_feral_skill(self):
1019 if random.randint(1, 100) < SKILL_PERCENT:
1020 log("family: {}".format(self.family))
1021 log("Skills: {}".format(self.family['feral_skills_conversion']))
1022 return WeightedChoice(self.family['feral_skills_conversion']).pick()
1023
1024
977 # it is up to the rest of the system to understand how to read this data and act on it. 1025 # it is up to the rest of the system to understand how to read this data and act on it.
978 # Example Call: ('acc', '10', False, 30) 1026 # Example Call: ('acc', '10', False, 30)
979 def set_status_effect(self, effect, amount, is_percent, expires_seconds): 1027 def set_status_effect(self, effect, amount, is_percent, expires_seconds):
...@@ -1310,14 +1358,12 @@ class Arena: ...@@ -1310,14 +1358,12 @@ class Arena:
1310 self.monster2 = monster2 1358 self.monster2 = monster2
1311 self.battle_type = battle_type 1359 self.battle_type = battle_type
1312 1360
1313 def heal_monsters(self): 1361 def init_monsters(self):
1314 self.monster1.hp = self.monster1.get_hp() 1362 self.monster1.pre_fight_init()
1315 self.monster2.hp = self.monster2.get_hp() 1363 self.monster2.pre_fight_init()
1316 self.monster1.mp = self.monster1.get_mp()
1317 self.monster2.mp = self.monster2.get_mp()
1318 1364
1319 def start(self): 1365 def start(self):
1320 self.heal_monsters() 1366 self.init_monsters()
1321 self.m1_init = self.monster1.get_agility() + random.randint(1, 20) 1367 self.m1_init = self.monster1.get_agility() + random.randint(1, 20)
1322 self.m2_init = self.monster2.get_agility() + random.randint(1, 20) 1368 self.m2_init = self.monster2.get_agility() + random.randint(1, 20)
1323 1369
......