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):
return True
def db_convert_soul_plate_to_skill(member_id, soul_plate, idx, skill):
pankration_data = db_get_pankration_record(member_id)
skill_data = pankration_data['feral_skills']
if not skill_data:
feral_skills = []
else:
feral_skills = pickle.loads(str(skill_data))
feral_skills.append(skill)
db_update_pankration_record(member_id, 'feral_skills', pickle.dumps(feral_skills))
#if not db_remove_soul_plate(member_id, idx):
# return False
return True
def db_register_battle(member_id, reflector, idx, target_member_id=None):
pan_record = db_get_pankration_record(member_id)
conn = sqlite3.connect('db.sqlite3')
......
No preview for this file type
......@@ -87,14 +87,14 @@ registered_commands = {'!help': 'do_help', '!commands': 'do_help',
'!stars': 'do_stars',
'!rigged': 'do_rigged',
'!listzones': 'do_list_zones',
'!huntmonster': 'do_hunt_monster',
'!listferalskills': 'do_list_feral_skills', '!listferalskill': 'do_list_feral_skills',
'!huntmonster': 'do_hunt_monster', '!hunt': 'do_hunt_monster',
'!listskills': 'do_list_feral_skills', '!listferalskills': 'do_list_feral_skills', '!listferalskill': 'do_list_feral_skills',
'!listreflectors': 'do_list_reflectors', '!listreflector': 'do_list_reflectors',
'!listsoulplates': 'do_list_soul_plates', '!listsoulplate': 'do_list_soul_plates',
'!convertplate': 'do_convert_plate', '!convertsoulplate': 'do_convert_plate',
'!assignskill': 'do_assign_skill',
'!convert': 'do_convert_plate', '!convertplate': 'do_convert_plate', '!convertsoulplate': 'do_convert_plate',
'!registerbattle': 'do_register_battle',
'!setreflectorname': 'do_set_reflector_name',
'!equip': 'do_equip_feral_skills', '!equipskill': 'do_equip_feral_skills', '!equipferalskill': 'do_equip_feral_skills',
'!pankration': 'do_pankration',
}
......@@ -1044,7 +1044,7 @@ def do_pankration(client, message_parts, message):
*Hunting for Soul Plates:*
**!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.
**!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.
**!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.
*Viewing Your Inventory:*
**!listsoulplates** - Returns a list of all soul plates you have in your posession.
......@@ -1052,10 +1052,10 @@ def do_pankration(client, message_parts, message):
**!listferalskills** - Returns a list of all feral skills you have in your inventory
*Editing Your Collections:*
**!convertplate <plate number> <convert_to>** - From the list of soul plates you can choose to either convert the plate into a \"reflector\" or \"skill\".
**!convert <plate number> <convert_to>** - From the list of soul plates you can choose to either convert the plate into a \"reflector\" or \"skill\".
Ex: **!convertplate 1 reflector**
**!convertplate 4 skill**
**!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.
**!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.
**!setreflectorname <reflector number> <name>** - This will rename a monster in your collection to a custom name.
*Arena Battle:*
......@@ -1150,8 +1150,14 @@ def do_convert_plate(client, message_parts, message):
else:
send_message(client, message.channel, 'There was an issue converting your soul plate...Conversion failed.')
elif convert_to == "skill":
send_message(client, message.channel, '**Feral Skills are not yet supported**')
# do skill stuff
soul_plates[plate_num].convert_to_feral_skill()
skill = soul_plates[plate_num].convert_to_feral_skill()
if not skill:
send_message(client, message.channel, 'The conversion **failed** the soul plate has been destroyed in the process.')
else:
send_message(client, message.channel, 'Congratulations! The soul plate was converted to feral skill: **{}**'.format(byteify(skill)))
data.db_convert_soul_plate_to_skill(member['member_id'], soul_plates[plate_num], plate_num, skill)
do_list_feral_skills(client, message_parts, message)
pass
else:
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):
send_message(client, message.channel, 'You have no reflectors.')
def do_equip_feral_skills(client, message_parts, message):
member = data.db_get_member(message.author.id)
skill_num = message_parts[0]
reflector_num = message_parts[1]
pankration_data = data.db_get_pankration_record(member['member_id'])
if pankration_data and pankration_data['reflectors']:
reflectors = pickle.loads(str(pankration_data['reflectors']))
if pankration_data and pankration_data['feral_skills']:
feral_skills = pickle.loads(str(pankration_data['feral_skills']))
if not skill_num.isdigit() or int(skill_num) < 1 or int(skill_num) > len(feral_skills):
send_message(client, message.channel, 'The requested feral skill is invalid. Please provide the number from !listferalskills')
return
skill_num = int(skill_num) - 1
if not reflector_num.isdigit() or int(reflector_num) < 1 or int(reflector_num) > len(reflectors):
send_message(client, message.channel, 'The requested reflector is invalid. Please provide the number from !listreflectors')
return
reflector_num = int(reflector_num) - 1
skill_name = feral_skills[skill_num]
print(reflector_num)
print(reflectors[reflector_num])
success, err_message = reflectors[reflector_num].equip_feral_skill(skill_name)
if not success:
send_message(client, message.channel, byteify(err_message))
else:
data.db_update_pankration_record(member['member_id'], 'reflectors', pickle.dumps(reflectors))
send_message(client, message.channel, "{} has been equipped.\n{}".format(skill_name, reflectors[reflector_num]))
else:
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.')
else:
send_message(client, message.channel, 'You have no reflectors. You can get more reflectors by hunting monsters and converting soul plates into reflectors.')
def do_list_feral_skills(client, message_parts, message):
member = data.db_get_member(message.author.id)
......
......@@ -8,13 +8,33 @@ import operator
def log(message):
try:
print(message)
logging.warning("{} - {}".format(datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'), message))
except:
pass
ATTACK_EFFECT_PERCENTAGE = 25
FIND_PERCENTAGE = 100
SKILL_PERCENT = 80
FIND_PERCENTAGE = 80
SKILL_PERCENT = 60
class WeightedChoice(object):
def __init__(self, weights):
"""Pick items with weighted probabilities.
weights
a sequence of tuples of item and it's weight.
"""
self._total_weight = 0.
self._item_levels = []
for item, weight in weights.iteritems():
self._total_weight += weight
self._item_levels.append((self._total_weight, item))
def pick(self):
pick = self._total_weight * (random.randint(1, 10)/10)
for level, item in self._item_levels:
if level >= pick:
return item
class HuntResponse:
ERROR = -1
......@@ -85,7 +105,8 @@ class Jobs:
WAR = 21
WHM = 22
def get_job_name(self, job):
@staticmethod
def get_job_name(job):
members = [attr for attr in dir(Jobs()) if not callable(attr) and not attr.startswith("__") and not attr.startswith("get_job_name")]
return members[job-1]
......@@ -135,7 +156,8 @@ PhysicalDamageTypes = {
'piercing': ['Dagger', 'Polearm', 'Archery', 'Marksmanship', 'Shuriken', 'Boomerang']
}
FeralSkills = {
class FeralSkills:
SkillsList = {
# 'Airy Shield': {'fp_cost': 0, 'type': 'Enhancing', 'sub_type': 'arrow shield', 'shadows': 'ignore', 'range': None, 'aoe': False, 'spell': 'arrow shield'},
# 'Binding Wave': {'type': 'Enfeebling', 'shadows': 'ignore', 'range': 15, 'aoe': True, 'spell': 'bind'},
# 'Dire Straight': {'type': 'Physical', 'shadows': 'wipe', 'range': None, 'aoe': False},
......@@ -223,7 +245,11 @@ FeralSkills = {
'Water Resistance Bonus': {'fp_cost': 12, 'effect': 'water_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
'Wind Resistance +2': {'fp_cost': 8, 'effect': 'wind_resist', 'amount': 2, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
'Wind Resistance Bonus': {'fp_cost': 12, 'effect': 'wind_resist', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': True},
}
}
@staticmethod
def get_skill(skill_name):
return FeralSkills.SkillsList.get(skill_name)
class Spells:
SpellTypes = {
......@@ -310,7 +336,7 @@ Families = {
'available_support_job': [Jobs.WAR, Jobs.DRG, Jobs.DRK, Jobs.PLD],
'innate_feral_skills': [],#'Sinker Drill', 'Dire Straight', 'Dismemberment', 'Earthshatter'],
'target_magic_damage_adjustment': 1.00,
'feral_skills_conversion': ['Accuracy +15%'],
'feral_skills_conversion': {'Accuracy +15%': 50, 'Attack Bonus': 20},
'type': 'Arcana',
'strong_vs': ['Dark'],
'charmable': False,
......@@ -357,7 +383,7 @@ Families = {
'available_support_job': [Jobs.BLM, Jobs.RDM, Jobs.WAR],
'innate_feral_skills': ['Binding Wave', 'Magic Barrier', 'Hypnosis', 'Eyes On Me', 'Airy Shield'],
'type': 'Demon',
'feral_skills_conversion': ['Accuracy +15%'],
'feral_skills_conversion': {'Accuracy +15%': 50},
'traits': ['magic defence bonus +25%'],
'target_magic_damage_adjustment': 0.75,
'charmable': False,
......@@ -402,7 +428,6 @@ Monsters = {
'Mechanical Menace': {
'family': 'acrolith',
'zone': ['abyssea - uleguerand'],
'feral_skills_conversion': [],
'hp': 20,
'mp': 20,
'weapon_base_damage': 18
......@@ -410,7 +435,6 @@ Monsters = {
'Floating Eye': {
'family': 'ahriman',
'zone': ['ranguemont pass'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5,
......@@ -419,7 +443,6 @@ Monsters = {
'Bat Eye': {
'family': 'ahriman',
'zone': ['ranguemont pass', 'beaucedine glacier'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5,
......@@ -428,7 +451,6 @@ Monsters = {
'Evil Eye': {
'family': 'ahriman',
'zone': ['castle zvahl baileys', 'castle zvahl keep', 'xarcabard'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5,
......@@ -436,7 +458,6 @@ Monsters = {
'Morbid Eye': {
'family': 'ahriman',
'zone': ['castle zvahl baileys', 'castle zvahl keep'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -444,7 +465,6 @@ Monsters = {
'Deadly Iris': {
'family': 'ahriman',
'zone': ['castle zvahl keep'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -452,7 +472,6 @@ Monsters = {
'Ahriman': {
'family': 'ahriman',
'zone': ['castle zvahl baileys'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -460,7 +479,6 @@ Monsters = {
'Fachan': {
'family': 'ahriman',
'zone': ['uleguerand range'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -468,7 +486,6 @@ Monsters = {
'Gawper': {
'family': 'ahriman',
'zone': ['beaucedine glacier (s)'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -476,7 +493,6 @@ Monsters = {
'Menacing Eye': {
'family': 'ahriman',
'zone': ['xarcabard (s)'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -484,7 +500,6 @@ Monsters = {
'Ogler': {
'family': 'ahriman',
'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -492,7 +507,6 @@ Monsters = {
'Smolenkos': {
'family': 'ahriman',
'zone': ['uleguerand range'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -500,7 +514,6 @@ Monsters = {
'Doom Lens': {
'family': 'ahriman',
'zone': ['castle zvahl keep (s)', 'castle zvahl baileys (s)'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -508,7 +521,6 @@ Monsters = {
'Scowlenkos': {
'family': 'ahriman',
'zone': ['uleguerand range'],
'feral_skills_conversion': [],
'hp': 15,
'mp': 24,
'weapon_base_damage': 5
......@@ -631,13 +643,6 @@ class Monster:
self.innate_feral_skills = innate_feral_skills
self.equipped_feral_skills = equipped_feral_skills
effects = self.get_status_effect_list()
for feral_skill in innate_feral_skills + equipped_feral_skills:
effect = effects[FeralSkills[feral_skill]['effect']]
# Should init = true
if effect:
self.apply_feral_skill(feral_skill)
self.discipline_level = dicipline_level
self.temperament_posture = family['temperament_posture']['initial_value']
self.temperament_attitude = family['temperament_attitude']['initial_value']
......@@ -670,11 +675,24 @@ class Monster:
def __str__(self):
try:
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)
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)
except AttributeError:
return "Old Format monster, unable to display."
#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)
def pre_fight_init(self):
self.status_effects = {}
self.hp = self.get_hp()
self.mp = self.get_mp()
effects = self.get_status_effect_list()
for feral_skill in self.innate_feral_skills + self.equipped_feral_skills:
effect = effects[FeralSkills.get_skill(feral_skill)['effect']]
# Should init = true
if effect:
self.apply_feral_skill(feral_skill)
def get_monster_name(self):
if self.custom_name:
return self.custom_name
......@@ -686,14 +704,14 @@ class Monster:
def get_soul_plate_description(self):
try:
return "*Family:*\n**{}**\nJob Trait: {}\nFeral Points: {}".format(self.family_name, Jobs().get_job_name(self.main_job), self.get_fp())
return "*Family:*\n**{}**\nJob Trait: {}\nFeral Points: {}".format(self.family_name, Jobs.get_job_name(self.main_job), self.get_fp())
except AttributeError:
return "Old Format monster, unable to display."
#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)
def get_reflector_description(self):
try:
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)
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)
except AttributeError:
return "Old Format monster, unable to display."
#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:
self.get_status_effect('mp', main_mp + sub_mp))
def get_available_fp(self):
ttl_used = 0
for fs in self.equipped_feral_skills:
skill = FeralSkills.SkillsList.get(fs)
if not skill:
return False
ttl_used += skill['fp_cost']
return self.get_fp() - ttl_used
def get_fp(self):
return int(self.level / self.family['fp_per_level'] + self.family['base_fp'])
......@@ -966,14 +993,35 @@ class Monster:
return base_damage
def equip_feral_skill(self, feral_skill):
fs = FeralSkills.get_skill(feral_skill)
log("{} {}".format(feral_skill, self.equipped_feral_skills))
if feral_skill in self.equipped_feral_skills:
return False, "Unable to equip the feral skill. The monster already has this skill equipped."
if self.get_available_fp() >= fs['fp_cost']:
self.equipped_feral_skills.append(feral_skill)
return True, ""
else:
return False, "Your monster does not have enough feral points. {} of {} feral points available.", format(self.get_available_fp(), self.get_fp())
def unequip_feral_skill(self, feral_skill):
self.equipped_feral_skills.remove(feral_skill)
def apply_feral_skill(self, feral_skill):
# 'Amnesia Attack': {'fp_cost': 47, 'effect': 'amnesia', 'amount': 1, 'is_percent': False, 'expires_seconds': 0, 'levels': False},
fs = FeralSkills[feral_skill]
fs = FeralSkills.get_skill(feral_skill)
self.set_status_effect(fs['effect'], fs['amount'], fs['is_percent'], fs['expires_seconds'])
if feral_skill == 'Curse Attack':
self.hp = min(self.hp, self.get_hp())
self.mp = min(self.mp, self.get_mp())
def convert_to_feral_skill(self):
if random.randint(1, 100) < SKILL_PERCENT:
log("family: {}".format(self.family))
log("Skills: {}".format(self.family['feral_skills_conversion']))
return WeightedChoice(self.family['feral_skills_conversion']).pick()
# it is up to the rest of the system to understand how to read this data and act on it.
# Example Call: ('acc', '10', False, 30)
def set_status_effect(self, effect, amount, is_percent, expires_seconds):
......@@ -1310,14 +1358,12 @@ class Arena:
self.monster2 = monster2
self.battle_type = battle_type
def heal_monsters(self):
self.monster1.hp = self.monster1.get_hp()
self.monster2.hp = self.monster2.get_hp()
self.monster1.mp = self.monster1.get_mp()
self.monster2.mp = self.monster2.get_mp()
def init_monsters(self):
self.monster1.pre_fight_init()
self.monster2.pre_fight_init()
def start(self):
self.heal_monsters()
self.init_monsters()
self.m1_init = self.monster1.get_agility() + random.randint(1, 20)
self.m2_init = self.monster2.get_agility() + random.randint(1, 20)
......