def get_skills(class_dict, unit, classes, level, gameStateObj, feat=True, seed=0): class_skills = [] for index, klass in enumerate(classes): for level_needed, class_skill in class_dict[klass]['skills']: # If level is gte level needed for skill or gte max_level if level >= level_needed or index < len(classes) - 1: class_skills.append(class_skill) # === Handle Feats (Naive choice) if feat: for status in class_skills: if status == 'Feat': counter = 0 while StatusObject.feat_list[(seed + counter) % len( StatusObject.feat_list)] in class_skills: counter += 1 class_skills.append( StatusObject.feat_list[(seed + counter) % len(StatusObject.feat_list)]) class_skills = [status for status in class_skills if status != 'Feat'] logger.debug('Class Skills %s', class_skills) # === Actually add statuses status_effects = [ StatusObject.statusparser(status) for status in class_skills ] for status in status_effects: if status: StatusObject.HandleStatusAddition(status, unit, gameStateObj) # handle having a status that gives stats['HP'] unit.set_hp(int(unit.stats['HP']))
def generate_defender_phase(self, gameStateObj): # Assumes Capable of counterattacking result = Result(self.defender, self.attacker) to_hit = self.defender.compute_hit(self.attacker, gameStateObj, self.defender.getMainWeapon(), mode="Defense") if self.event_combat: roll = 0 else: roll = (random.randint(0, 99) + random.randint(0, 99))/2 #if OPTIONS['debug']: print('To Hit:', to_hit, ' Roll:', roll) if roll < to_hit: result.outcome = True result.def_damage = self.defender.compute_damage(self.attacker, gameStateObj, self.defender.getMainWeapon(), mode="Defense") # Missed but does half damage elif self.defender.getMainWeapon().half: result.def_damage = self.defender.compute_damage(self.attacker, gameStateObj, self.defender.getMainWeapon(), mode="Defense")/2 if result.outcome: for status in self.defender.getMainWeapon().status: status_object = StatusObject.statusparser(str(status.id)) result.def_status.append(status_object) # Handle lifelink and vampire if result.def_damage > 0: if self.defender.getMainWeapon().lifelink: result.atk_damage -= result.def_damage # Handle Vampire Status for status in self.defender.status_effects: if status.vampire and self.attacker.currenthp - result.def_damage <= 0 and not any(status.miracle and (not status.count or status.count.count > 0) for status in self.attacker.status_effects): result.atk_damage -= eval(status.vampire) return result
def __init__(self, aura_range, target, child): self.aura_range = int(aura_range) self.child = child self.child_status = StatusObject.statusparser(child) self.child_status.parent_status = self self.target = target self.children = set()
def get_skills(class_dict, statusdata, Unit, classes, level, feat=True): position = Unit.position class_skills = [] for index, klass in enumerate(classes): for level_needed, class_skill in class_dict[klass]['skills']: if index < len(classes) - 1 or level%CONSTANTS['max_level'] >= level_needed or level%CONSTANTS['max_level'] == 0: class_skills.append(class_skill) ### Handle Feats (Naive choice) if feat: for status in class_skills: if status == 'Feat': # If has a mount... '''if len(unitLine) == 12 and not 'fHorsemanship' in class_skills: class_skills.append('fHorsemanship') else:''' counter = 0 while StatusObject.feat_list[(position[0] + position[1] + counter)%10] in class_skills: counter += 1 class_skills.append(StatusObject.feat_list[(position[0] + position[1] + counter)%10]) class_skills = [status for status in class_skills if status != 'Feat'] logger.debug('Class Skills %s', class_skills) ### Actually add statuses status_effects = [StatusObject.statusparser(status, statusdata) for status in class_skills] for status in status_effects: if status: StatusObject.HandleStatusAddition(status, Unit) # handle having a status that gives stats['HP'] Unit.currenthp = int(Unit.stats['HP'])
def apply(self, parent_unit, unit, gameStateObj): if (self.target == 'Ally' and parent_unit.checkIfAlly(unit) and parent_unit is not unit) or \ (self.target == 'Enemy' and parent_unit.checkIfEnemy(unit)) or \ (self.target == 'Weakened_Enemy' and parent_unit.checkIfEnemy(unit) and unit.currenthp < unit.stats['HP']/2): child_status = StatusObject.statusparser(self.child) child_status.parent = self child_status.parent_unit = parent_unit StatusObject.HandleStatusAddition(child_status, unit) self.children.append((unit, child_status))
def add_global_status(self, s_id, gameStateObj=None): if any(status.id == s_id for status in self.status_effects): return # No stacking at all of global statuses status_obj = StatusObject.statusparser(s_id) self.status_effects.add(status_obj) if gameStateObj: for unit in gameStateObj.allunits: if unit.position: StatusObject.HandleStatusAddition(status_obj, unit, gameStateObj)
def generate_attacker_phase(self, gameStateObj, metaDataObj, defender): result = Result(self.attacker, defender) # Start if isinstance(defender, UnitObject.UnitObject) or isinstance(defender, TileObject.TileObject): to_hit = self.attacker.compute_hit(defender, gameStateObj, self.item, mode="Attack") if self.event_combat: roll = 0 else: roll = (random.randint(0, 99) + random.randint(0, 99))/2 #if OPTIONS['debug']: print('To Hit:', to_hit, ' Roll:', roll) if self.item.weapon: if roll < to_hit and not (defender in self.splash and any(status.evasion for status in defender.status_effects)) or isinstance(defender, TileObject.TileObject): result.outcome = True result.def_damage = self.attacker.compute_damage(defender, gameStateObj, self.item, mode='Attack') # Missed but does half damage elif self.item.half: result.def_damage = self.attacker.compute_damage(defender, gameStateObj, self.item, mode='Attack')/2 elif self.item.spell: if not self.item.hit or roll < to_hit: result.outcome = True if self.item.damage is not None: result.def_damage = self.attacker.compute_damage(defender, gameStateObj, self.item, mode='Attack') elif self.item.heal is not None: result.def_damage = -self.attacker.compute_heal(defender, gameStateObj, self.item, mode='Attack') else: result.outcome = True result.def_damage = -int(eval(self.item.heal)) if self.item.heal else 0 if self.attacker is not defender and self.item.heal: result.def_damage -= sum(status.caretaker for status in self.attacker.status_effects if status.caretaker) if self.item.movement: result.def_movement = self.item.movement if self.item.self_movement: result.atk_movement = self.item.self_movement if result.outcome: # Handle status for status in self.item.status: status_object = StatusObject.statusparser(str(status.id)) result.def_status.append(status_object) # Handle summon if self.item.summon: result.summoning.append(SaveLoad.create_summon(metaDataObj, self.item.summon, self.attacker, self.def_pos)) # Handle lifelink and vampire if result.def_damage > 0: if self.item.lifelink: result.atk_damage -= result.def_damage # Handle Vampire Status for status in self.attacker.status_effects: if status.vampire and defender.currenthp - result.def_damage <= 0 and \ not any(status.miracle and (not status.count or status.count.count > 0) for status in defender.status_effects): result.atk_damage -= eval(status.vampire) return result
def create_unit(unitLine, allunits, reinforceUnits, metaDataObj): assert len(unitLine) == 11 or len(unitLine) == 12, "unitLine %s must have length 11 or 12"%(unitLine) class_dict = metaDataObj['class_dict'] itemdata = metaDataObj['itemdata'] statusdata = metaDataObj['statusdata'] u_i = {} global U_ID U_ID += 1 u_i['u_id'] = U_ID u_i['team'] = unitLine[0] u_i['event_id'] = unitLine[2] if unitLine[3].endswith('F'): unitLine[3] = unitLine[3][:-1] # strip off the F u_i['gender'] = 'F' else: u_i['gender'] = 'M' classes = unitLine[3].split(',') u_i['klass'] = classes[-1] u_i['level'] = int(unitLine[4]) u_i['position'] = tuple([int(num) for num in unitLine[6].split(',')]) u_i['name'] = unitLine[8] u_i['faction'] = unitLine[9] stats, u_i['growths'], u_i['growth_points'], u_i['new_items'], u_i['wexp'] = get_unit_info(class_dict, u_i['klass'], u_i['level'], unitLine[5]) u_i['stats'] = build_stat_dict(stats) logger.debug("%s's stats: %s", u_i['name'], u_i['stats']) u_i['desc'] = unitLine[10] u_i['tags'] = class_dict[u_i['klass']]['tags'].split(',') if class_dict[u_i['klass']]['tags'] else [] u_i['ai'] = unitLine[7] u_i['movement_group'] = class_dict[u_i['klass']]['movement_group'] # Mount status stuff mount_status = [] for status in class_dict[u_i['klass']]['mount_status']: mount_status.append(StatusObject.statusparser(status, statusdata)) cur_unit = UnitObject.UnitObject(u_i) # Mount if len(unitLine) == 12: mount_id = unitLine[11] place_mount(mount_id, cur_unit, reinforceUnits) # Reposition units cur_unit.position = u_i['position'] # Status Effects and Skills get_skills(class_dict, statusdata, cur_unit, classes, u_i['level']) if u_i['event_id'] != "0": # Unit does not start on board cur_unit.position = None reinforceUnits[u_i['event_id']] = (cur_unit.id, u_i['position']) allunits.append(cur_unit) return cur_unit
def parse_tile_line(self, coord, property_list): if property_list: for tile_property in property_list: property_name, property_value = tile_property.split('=') # Handle special cases... if property_name == 'Status': # Treasure does not need to be split. It is split by the itemparser function itself. # Turn these string of ids into a list of status objects status_list = [] for status in property_value.split(','): status_list.append(StatusObject.statusparser(status)) property_value = status_list self.tile_info_dict[coord][property_name] = property_value else: self.tile_info_dict[coord] = {'Status': []} # Empty Dictionary
def parse_tile_line(self, coord, property_list): if property_list: for tile_property in property_list: property_name, property_value = tile_property.split('=') # Handle special cases... if property_name == 'Status': # Treasure does not need to be split. It is split by the itemparser function itself. # Turn these string of ids into a list of status objects status_list = [] for status in property_value.split(','): status_list.append(StatusObject.statusparser(status)) property_value = status_list elif property_name in ["Escape", "Arrive"]: self.escape_highlights[coord] = CustomObjects.Highlight( GC.IMAGESDICT["YellowHighlight"]) elif property_name == "Formation": self.formation_highlights[coord] = CustomObjects.Highlight( GC.IMAGESDICT["BlueHighlight"]) self.tile_info_dict[coord][property_name] = property_value else: self.tile_info_dict[coord] = {'Status': []} # Empty Dictionary
def add_unit(unitLine, allunits, reinforceUnits, metaDataObj): assert len(unitLine) == 6 or len(unitLine) == 7, "unitLine %s must have length 6 or 7"%(unitLine) unitdata = metaDataObj['unitdata'] class_dict = metaDataObj['class_dict'] itemdata = metaDataObj['itemdata'] statusdata = metaDataObj['statusdata'] for unit in unitdata.getroot().findall('unit'): if unit.find('id').text == unitLine[3]: u_i = {} u_i['u_id'] = unit.find('id').text u_i['event_id'] = unitLine[2] u_i['position'] = tuple([int(num) for num in unitLine[4].split(',')]) u_i['name'] = unit.get('name') u_i['team'] = unitLine[0] classes = unit.find('class').text.split(',') u_i['klass'] = classes[-1] u_i['gender'] = unit.find('gender').text u_i['level'] = int(unit.find('level').text) u_i['faction'] = unit.find('faction').text stats = intify_comma_list(unit.find('bases').text) if len(stats) == 8: # Add con if not present stats.append(int(class_dict[u_i['klass']]['bases'][8])) assert len(stats) == 9, "bases %s must be exactly 9 integers long"%(stats) stats.append(int(class_dict[u_i['klass']]['movement'])) u_i['stats'] = build_stat_dict(stats) logger.debug("%s's stats: %s", u_i['name'], u_i['stats']) u_i['growths'] = intify_comma_list(unit.find('growths').text) u_i['growth_points'] = [0, 0, 0, 0, 0, 0, 0, 0] u_i['new_items'] = ItemMethods.itemparser(unit.find('inventory').text, itemdata) u_i['wexp'] = intify_comma_list(unit.find('wexp').text) u_i['desc'] = unit.find('desc').text # Tags class_tags = class_dict[u_i['klass']]['tags'].split(',') if class_dict[u_i['klass']]['tags'] else [] personal_tags = unit.find('tags').text.split(',') if unit.find('tags') is not None and unit.find('tags').text is not None else [] u_i['tags'] = class_tags + personal_tags # For mounts... Not yet available in Lex Talionis mount_status = [] for status in class_dict[u_i['klass']]['mount_status']: mount_status.append(StatusObject.statusparser(status, statusdata)) u_i['ai'] = unitLine[5] u_i['movement_group'] = class_dict[u_i['klass']]['movement_group'] Unit = UnitObject.UnitObject(u_i) # Status Effects and Skills get_skills(class_dict, statusdata, Unit, classes, u_i['level'], feat=False) # Personal Skills personal_skills = unit.find('skills').text.split(',') if unit.find('skills') is not None and unit.find('skills').text is not None else [] ### Actually add statuses c_s = [StatusObject.statusparser(status, statusdata) for status in personal_skills] for status in c_s: if status: StatusObject.HandleStatusAddition(status, Unit) # handle having a status that gives stats['HP'] Unit.currenthp = int(Unit.stats['HP']) # Mount if len(unitLine) == 7: mount_id = unitLine[6] place_mount(mount_id, Unit, reinforceUnits) Unit.position = u_i['position'] # Reposition units if u_i['event_id'] != "0": # Unit does not start on board Unit.position = None reinforceUnits[u_i['event_id']] = (u_i['u_id'], u_i['position']) allunits.append(Unit) return allunits, reinforceUnits
def itemparser(itemstring, itemdata=None): if itemdata is None: # Just in case so we don't have to keep passing itemdat around itemdata = ET.parse('Data/items.xml') Items = [] if itemstring: # itemstring needs to exist idlist = itemstring.split(',') for itemid in idlist: droppable = False if itemid.startswith('d'): itemid = itemid[1:] # Strip the first d off droppable = True for item in itemdata.getroot().findall('item'): if item.find('id').text == itemid: spritetype = item.find('spritetype').text spriteid = item.find('spriteid').text components = item.find('components').text if components: components = components.split(',') else: components = [] name = item.get('name') value = item.find('value').text rng = item.find('RNG').text desc = item.find('desc').text aoe = AOEComponent('Normal', 0) if 'weapon' in components or 'spell' in components: weapontype = item.find('weapontype').text if weapontype == 'None': weapontype = [] else: weapontype = weapontype.split(',') else: weapontype = [] if 'locked' in components: locked = True else: locked = False status = [] status_on_hold = [] my_components = {} for component in components: if component == 'uses': uses = item.find('uses').text my_components['uses'] = UsesComponent(int(uses)) elif component == 'c_uses': c_uses = item.find('c_uses').text my_components['c_uses'] = CUsesComponent(int(c_uses)) elif component == 'weapon': stats = [item.find('stats')[0].text, item.find('stats')[1].text, item.find('stats')[2].text] my_components['weapon'] = WeaponComponent(stats) elif component == 'usable': my_components['usable'] = UsableComponent() elif component == 'spell': lvl = item.find('LVL').text targets = item.find('targets').text my_components['spell'] = SpellComponent(lvl, targets) elif component == 'status': statusid = item.find('status').text.split(',') for s_id in statusid: status.append(StatusObject.statusparser(s_id)) # Item now has associated status object. elif component == 'status_on_hold': statusid = item.find('status_on_hold').text.split(',') for s_id in statusid: status_on_hold.append(StatusObject.statusparser(s_id)) # Item now has associated status on hold object elif component == 'effective': effective_against = item.find('effective').text.split(',') my_components['effective'] = EffectiveComponent(effective_against) elif component == 'permanent_stat_increase': stat_increase = SaveLoad.intify_comma_list(item.find('stat_increase').text) my_components['permanent_stat_increase'] = PermanentStatIncreaseComponent(stat_increase) elif component == 'aoe': info_line = item.find('aoe').text.split(',') aoe = AOEComponent(info_line[0], int(info_line[1])) elif component == 'heal': my_components['heal'] = item.find('heal').text elif component == 'damage': my_components['damage'] = int(item.find('damage').text) elif component == 'hit': my_components['hit'] = int(item.find('hit').text) elif component == 'weight': my_components['WT'] = int(item.find('WT').text) elif component == 'exp': my_components['exp'] = int(item.find('exp').text) elif component == 'wexp_increase': my_components['wexp_increase'] = int(item.find('wexp_increase').text) elif component in ['movement', 'self_movement']: mode, magnitude = item.find(component).text.split(',') my_components[component] = MovementComponent(mode, magnitude) elif component == 'summon': summon = item.find('summon') klass = summon.find('klass').text items = summon.find('items').text name = summon.find('name').text desc = summon.find('desc').text ai = summon.find('ai').text s_id = summon.find('s_id').text my_components['summon'] = SummonComponent(klass, items, name, desc, ai, s_id) else: my_components[component] = True currentItem = ItemObject(itemid, name, spritetype, spriteid, my_components, value, rng, desc, \ aoe, weapontype, status, status_on_hold, droppable=droppable, locked=locked) Items.append(currentItem) return Items
def create_unit(unitLine, allunits, groups, reinforceUnits, metaDataObj, gameStateObj): assert len(unitLine) in [ 9, 10 ], "unitLine %s must have length 9 or 10 (if optional status)" % (unitLine) legend = { 'team': unitLine[0], 'unit_type': unitLine[1], 'event_id': unitLine[2], 'class': unitLine[3], 'level': unitLine[4], 'items': unitLine[5], 'position': unitLine[6], 'ai': unitLine[7], 'group': unitLine[8] } class_dict = metaDataObj['class_dict'] u_i = {} GC.U_ID += 1 u_i['u_id'] = GC.U_ID u_i['team'] = legend['team'] u_i['event_id'] = legend['event_id'] if legend['class'].endswith('F'): legend['class'] = legend['class'][:-1] # strip off the F u_i['gender'] = 5 # Default female gender is 5 else: u_i['gender'] = 0 # Default male gender is 0 classes = legend['class'].split(',') u_i['klass'] = classes[-1] # Give default previous class default_previous_classes(u_i['klass'], classes, class_dict) u_i['level'] = int(legend['level']) u_i['position'] = tuple( [int(num) for num in legend['position'].split(',')]) u_i['name'], u_i['faction'], u_i['desc'] = groups[legend['group']] stats, u_i['growths'], u_i['growth_points'], u_i['items'], u_i[ 'wexp'] = get_unit_info(class_dict, u_i['klass'], u_i['level'], legend['items'], gameStateObj) u_i['stats'] = build_stat_dict(stats) logger.debug("%s's stats: %s", u_i['name'], u_i['stats']) u_i['tags'] = class_dict[u_i['klass']]['tags'] u_i['ai'] = legend['ai'] u_i['movement_group'] = class_dict[u_i['klass']]['movement_group'] cur_unit = UnitObject.UnitObject(u_i) # Reposition units if u_i['event_id'] != "0": # Unit does not start on board cur_unit.position = None reinforceUnits[u_i['event_id']] = (cur_unit.id, u_i['position']) else: # Unit does start on board cur_unit.position = u_i['position'] # Status Effects and Skills get_skills(class_dict, cur_unit, classes, u_i['level'], gameStateObj, feat=False) # Extra Skills if len(unitLine) == 10: statuses = [ StatusObject.statusparser(status) for status in unitLine[9].split(',') ] for status in statuses: StatusObject.HandleStatusAddition(status, cur_unit, gameStateObj) allunits.append(cur_unit) return cur_unit
def add_unit(unitLine, allunits, reinforceUnits, metaDataObj, gameStateObj): assert len(unitLine) == 6, "unitLine %s must have length 6" % (unitLine) legend = { 'team': unitLine[0], 'unit_type': unitLine[1], 'event_id': unitLine[2], 'unit_id': unitLine[3], 'position': unitLine[4], 'ai': unitLine[5] } class_dict = metaDataObj['class_dict'] for unit in GC.UNITDATA.getroot().findall('unit'): if unit.find('id').text == legend['unit_id']: u_i = {} u_i['u_id'] = unit.find('id').text u_i['event_id'] = legend['event_id'] u_i['position'] = tuple([ int(num) for num in legend['position'].split(',') ]) if ',' in legend['position'] else None u_i['name'] = unit.get('name') u_i['team'] = legend['team'] classes = unit.find('class').text.split(',') u_i['klass'] = classes[-1] # Give default previous class default_previous_classes(u_i['klass'], classes, class_dict) u_i['gender'] = int(unit.find('gender').text) u_i['level'] = int(unit.find('level').text) u_i['faction'] = unit.find('faction').text stats = intify_comma_list(unit.find('bases').text) for n in xrange(len(stats), cf.CONSTANTS['num_stats']): stats.append(class_dict[u_i['klass']]['bases'][n]) if u_i['team'] == 'player': # Modify stats bases = gameStateObj.modify_stats['player_bases'] growths = gameStateObj.modify_stats['player_growths'] else: bases = gameStateObj.modify_stats['enemy_bases'] growths = gameStateObj.modify_stats['enemy_growths'] stats = [sum(x) for x in zip(stats, bases)] assert len(stats) == cf.CONSTANTS[ 'num_stats'], "bases %s must be exactly %s integers long" % ( stats, cf.CONSTANTS['num_stats']) u_i['stats'] = build_stat_dict(stats) logger.debug("%s's stats: %s", u_i['name'], u_i['stats']) u_i['growths'] = intify_comma_list(unit.find('growths').text) u_i['growths'].extend( [0] * (cf.CONSTANTS['num_stats'] - len(u_i['growths']))) u_i['growths'] = [sum(x) for x in zip(u_i['growths'], growths)] assert len(u_i['growths']) == cf.CONSTANTS[ 'num_stats'], "growths %s must be exactly %s integers long" % ( stats, cf.CONSTANTS['num_stats']) u_i['growth_points'] = [50] * cf.CONSTANTS['num_stats'] u_i['items'] = ItemMethods.itemparser(unit.find('inventory').text) # Parse wexp u_i['wexp'] = unit.find('wexp').text.split(',') for index, wexp in enumerate(u_i['wexp'][:]): if wexp in CustomObjects.WEAPON_EXP.wexp_dict: u_i['wexp'][index] = CustomObjects.WEAPON_EXP.wexp_dict[ wexp] u_i['wexp'] = [int(num) for num in u_i['wexp']] assert len(u_i['wexp']) == len( CustomObjects.WEAPON_TRIANGLE.types ), "%s's wexp must have as many slots as there are weapon types." % ( u_i['name']) u_i['desc'] = unit.find('desc').text # Tags class_tags = class_dict[u_i['klass']]['tags'] personal_tags = set(unit.find('tags').text.split( ',')) if unit.find('tags') is not None and unit.find( 'tags').text is not None else set() u_i['tags'] = class_tags | personal_tags u_i['ai'] = legend['ai'] u_i['movement_group'] = class_dict[u_i['klass']]['movement_group'] cur_unit = UnitObject.UnitObject(u_i) if u_i['event_id'] != "0": # unit does not start on board cur_unit.position = None reinforceUnits[u_i['event_id']] = (u_i['u_id'], u_i['position']) else: # Unit does start on board cur_unit.position = u_i['position'] # Status Effects and Skills get_skills(class_dict, cur_unit, classes, u_i['level'], gameStateObj, feat=False) # Personal Skills personal_skills = unit.find('skills').text.split( ',') if unit.find('skills') is not None and unit.find( 'skills').text is not None else [] c_s = [ StatusObject.statusparser(status) for status in personal_skills ] for status in c_s: if status: StatusObject.HandleStatusAddition(status, cur_unit, gameStateObj) # handle having a status that gives stats['HP'] cur_unit.set_hp(int(cur_unit.stats['HP'])) allunits.append(cur_unit) break return allunits, reinforceUnits
def update(self, gameStateObj, metaDataObj): # Don't do this if there is no exp change if not self.force_level and self.expNew == 0 or (self.unit.level%CONSTANTS['max_level'] == 0 and metaDataObj['class_dict'][self.unit.klass]['turns_into'] is None): return True # We're done here if self.instantiationTime is None: # First time update is called. self.instantiationTime = pygame.time.get_ticks() SOUNDDICT['Experience Gain'].play(-1) #print self.state.getState() #print self.expSet, self.expOld, self.expNew currentTime = pygame.time.get_ticks() if self.state.getState() == 'exp0': self.expSet = self.expOld + (currentTime - self.instantiationTime)/float(self.EXPTIME/100) # 100 is total exp self.expSet = int(min(self.expNew + self.expOld, self.expSet)) if self.expNew + self.expOld <= self.expSet: SOUNDDICT['Experience Gain'].stop() if self.expSet >= 100: if self.unit.level%CONSTANTS['max_level'] == 0: # If I would promote because I am level 20 SOUNDDICT['Experience Gain'].stop() if metaDataObj['class_dict'][self.unit.klass]['turns_into']: # If has at least one class to turn into self.expSet = 0 class_options = metaDataObj['class_dict'][self.unit.klass]['turns_into'] if len(class_options) > 1: gameStateObj.activeMenu = MenuFunctions.ChoiceMenu(self.unit, class_options, 'auto', gameStateObj) gameStateObj.stateMachine.changeState('levelpromote') elif len(class_options) == 1: self.unit.klass = class_options[0] self.state.changeState('promote') else: return True else: # Unit is at the highest point it can be. No more. self.unit.exp = 99 return True else: self.expSet = 0 self.unit.level += 1 self.levelup_list = self.unit.level_up(metaDataObj['class_dict'][self.unit.klass]) self.state.changeState('exp100') elif currentTime - self.instantiationTime >= self.EXPTIME: SOUNDDICT['Experience Gain'].stop() self.unit.exp += self.expNew return True elif self.state.getState() == 'exp100': # Problem... It is not counting time needed to get to this state. Should minus away that time - Time taken to get to this point in (100 - self.expOld)*float(self.EXPTIME/100) self.expSet = (currentTime - self.instantiationTime - (100 - self.expOld)*float(self.EXPTIME/100))/float(self.EXPTIME/100) self.expSet = int(min(self.expNew + self.expOld - 100, self.expSet)) if self.expNew + self.expOld - 100 <= self.expSet: SOUNDDICT['Experience Gain'].stop() if currentTime - self.instantiationTime >= self.EXPTIME: SOUNDDICT['Experience Gain'].stop() #MUSICTHREAD.pause() SOUNDDICT['Level Up'].play() self.state.changeState('levelUp') elif self.state.getState() == 'levelUp': if currentTime - self.instantiationTime >= self.LEVELANIMATIONTIME + self.EXPTIME: self.state.changeState('levelUpWait') else: time = currentTime - self.instantiationTime - self.EXPTIME marker1 = min(4, int(time/(self.LEVELANIMATIONTIME/5))) marker2 = min(4, int((time%(self.LEVELANIMATIONTIME/5))/(self.LEVELANIMATIONTIME/25))) self.animationMarker = (marker1, marker2) elif self.state.getState() == 'levelUpWait': if currentTime - self.instantiationTime >= self.LEVELANIMATIONTIME + self.WAITTIME + self.EXPTIME: self.state.changeState('levelScreen') #MUSICTHREAD.resume() else: self.animationMarker = (4, 4) # Set to last frame elif self.state.getState() == 'levelScreen': # Am i Done displaying? if currentTime - self.instantiationTime >= self.LEVELUPWAIT + self.get_num_sparks()*self.SPARKTIME + self.LEVELANIMATIONTIME + self.WAITTIME + self.EXPTIME: # Handle EXP when the user levels up self.unit.exp += self.expNew if self.unit.exp >= 100: self.unit.exp = self.expNew - (100 - self.expOld) # Remove animations self.animations = [] # check for skill gain for level_needed, class_skill in metaDataObj['class_dict'][self.unit.klass]['skills']: if self.unit.level%CONSTANTS['max_level'] == level_needed: if class_skill == 'Feat': gameStateObj.cursor.currentSelectedUnit = self.unit gameStateObj.stateMachine.changeState('feat_choice') else: skill = StatusObject.statusparser(class_skill) StatusObject.HandleStatusAddition(skill, self.unit) gameStateObj.banners.append(MenuFunctions.gainedSkillBanner(self.unit, skill)) gameStateObj.stateMachine.changeState('itemgain') return True elif self.state.getState() == 'promote': # Class should already have been changed by now in the levelpromote state # Here's where I change all the important information new_class = metaDataObj['class_dict'][self.unit.klass] self.unit.removeSprites() self.unit.loadSprites() # Reset Level - Don't! self.unit.level += 1 # Actually change class # Reset movement speed self.unit.stats['MOV'].base_stat = new_class['movement'] # Reset movement group self.unit.movement_group = new_class['movement_group'] # Add weapon exp gains from that class. self.unit.increase_wexp(new_class['wexp_gain'], gameStateObj) # Add any extra tags if new_class['tags']: # Add any necessary tags. Does not currently take away tags, although it may have to later self.unit.tags.append(new_class['tags'].split(',')) self.unit.tags = list(set(self.unit.tags)) # Remove duplicates # Give promotion self.levelup_list = self.unit.level_up(new_class, apply_level=False) # Level up once, then promote. self.levelup_list = [x + y for x, y in zip(self.levelup_list, new_class['promotion'])] # Add lists together current_stats = [self.unit.stats['HP'], self.unit.stats['STR'], self.unit.stats['MAG'], self.unit.stats['SKL'], self.unit.stats['SPD'], self.unit.stats['LCK'], self.unit.stats['DEF'], self.unit.stats['RES'], self.unit.stats['CON']] assert len(self.levelup_list) == len(new_class['max']) == len(current_stats), "%s %s %s"%(self.levelup_list, new_class['max'], current_stats) for index, stat in enumerate(self.levelup_list): self.levelup_list[index] = min(stat, new_class['max'][index] - current_stats[index]) self.unit.apply_levelup(self.levelup_list) self.state.changeState('levelScreen') self.instantiationTime = currentTime # Reset time so that it doesn't skip right over LevelScreen return False
def clean_up(self, gameStateObj, metaDataObj): # Remove combat state gameStateObj.stateMachine.back() # Reset states if you're not using a solo skill if self.skill_used and self.skill_used.active and self.skill_used.active.mode == 'Solo': self.attacker.hasTraded = True # Can still attack, can't move self.attacker.hasAttacked = False else: self.attacker.hasAttacked = True if not self.attacker.has_canto_plus() and not self.event_combat: gameStateObj.stateMachine.changeState('wait') # Event combats do not cause unit to wait # Handle items that were used a_broke_item, d_broke_item = False, False if self.item.uses and self.item.uses.uses <= 0: a_broke_item = True if self.defender and self.defender.getMainWeapon() and self.defender.getMainWeapon().uses and self.defender.getMainWeapon().uses.uses <= 0: d_broke_item = True # Handle skills that were used if self.skill_used: self.skill_used.active.current_charge = 0 self.skill_used.active.reverse_mod() # Create all_units list all_units = [unit for unit in self.splash] + [self.attacker] if self.defender: all_units += [self.defender] # Handle death for unit in all_units: if unit.currenthp <= 0: unit.isDying = True # === HANDLE STATE STACK == # Handle where we go at very end if self.event_combat: gameStateObj.message[-1].current_state = "Processing" else: if self.attacker.team == 'player': if not self.attacker.hasAttacked: gameStateObj.stateMachine.changeState('menu') elif self.attacker.has_canto_plus() and not self.attacker.isDying: gameStateObj.stateMachine.changeState('move') else: #self.attacker.wait() gameStateObj.stateMachine.clear() gameStateObj.stateMachine.changeState('free') gameStateObj.stateMachine.changeState('wait') #else: #gameStateObj.stateMachine.changeState('ai') ### Handle interact_script interact_script = Dialogue.Dialogue_Scene('Data/Level' + str(gameStateObj.currentLevelIndex) + '/interactScript.txt', self.attacker, event_flag=False) gameStateObj.message.append(interact_script) gameStateObj.stateMachine.changeState('dialogue') # Handle miracle for unit in all_units: if unit.isDying: if any(status.miracle and (not status.count or status.count.count > 0) for status in unit.status_effects): unit.handle_miracle(gameStateObj) ### Handle item gain for unit in all_units: if unit.isDying and isinstance(unit, UnitObject.UnitObject): for item in unit.items: if item.droppable: item.droppable = False if unit in self.splash or unit is self.defender: self.attacker.add_item(item) gameStateObj.banners.append(MenuFunctions.acquiredItemBanner(self.attacker, item)) gameStateObj.stateMachine.changeState('itemgain') elif self.defender: self.defender.add_item(item) gameStateObj.banners.append(MenuFunctions.acquiredItemBanner(self.defender, item)) gameStateObj.stateMachine.changeState('itemgain') ### Handle item loss if a_broke_item and self.attacker.team == 'player' and not self.attacker.isDying: gameStateObj.banners.append(MenuFunctions.brokenItemBanner(self.attacker, self.item)) gameStateObj.stateMachine.changeState('itemgain') if d_broke_item and self.defender.team == 'player' and not self.defender.isDying: gameStateObj.banners.append(MenuFunctions.brokenItemBanner(self.defender, self.defender.getMainWeapon())) gameStateObj.stateMachine.changeState('itemgain') ### Handle exp and stat gain if not self.event_combat and (self.item.weapon or self.item.spell): if self.attacker.team == 'player' and not self.attacker.isDying and not 'Mindless' in self.attacker.tags and not self.attacker.isSummon(): if any(result.attacker is self.attacker and result.outcome for result in self.old_results): self.attacker.increase_wexp(self.item, gameStateObj) my_exp = 0 for other_unit in self.splash + [self.defender]: if any(result.attacker is self.attacker and result.defender is other_unit and result.outcome for result in self.old_results): if self.item.exp: normal_exp = self.item.exp elif self.item.weapon or not self.attacker.checkIfAlly(self.defender): level_diff = max(0, other_unit.level - self.attacker.level + 20) normal_exp = int(CONSTANTS['exp_magnitude']*level_diff**CONSTANTS['exp_curve']) elif self.item.spell: normal_exp = 15 else: normal_exp = 0 if other_unit.isDying: self.attacker.total_kills += 1 my_exp += int(CONSTANTS['kill_multiplier']*normal_exp) + (40 if 'Boss' in other_unit.tags else 0) else: my_exp += normal_exp logger.debug('Attacker gained %s exp', my_exp) # No free exp for affecting myself or being affected by allies if self.attacker.checkIfAlly(self.defender): my_exp = Utility.clamp(my_exp, 0, 100) else: my_exp = Utility.clamp(my_exp, 1, 100) gameStateObj.levelUpScreen.append(LevelUp.levelUpScreen(gameStateObj, unit=self.attacker, exp=my_exp)) #Also handles actually adding the exp to the unit gameStateObj.stateMachine.changeState('expgain') if self.defender.team == 'player' and not self.defender.isDying and not self.defender is self.attacker and not 'Mindless' in self.defender.tags and not self.defender.isSummon(): if any(result.attacker is self.defender and result.outcome for result in self.old_results): self.defender.increase_wexp(self.defender.getMainWeapon(), gameStateObj) my_exp = 0 if any(result.attacker is self.defender and result.outcome for result in self.old_results): level_diff = max(0, self.attacker.level - self.defender.level + 20) normal_exp = max(0, int(CONSTANTS['exp_magnitude']*level_diff**CONSTANTS['exp_curve'])) if self.attacker.isDying: self.defender.total_kills += 1 my_exp += int(CONSTANTS['kill_multiplier']*normal_exp) + (40 if 'Boss' in self.attacker.tags else 0) else: my_exp += normal_exp # No free exp for affecting myself or being affected by allies if self.attacker.checkIfAlly(self.defender): my_exp = Utility.clamp(my_exp, 0, 100) else: my_exp = Utility.clamp(my_exp, 1, 100) gameStateObj.levelUpScreen.append(LevelUp.levelUpScreen(gameStateObj, unit=self.defender, exp=my_exp)) #Also handles actually adding the exp to the unit gameStateObj.stateMachine.changeState('expgain') # Handle after battle statuses for status in self.attacker.status_effects: if status.status_after_battle and not self.attacker.isDying: for unit in [self.defender] + self.splash: if isinstance(unit, UnitObject.UnitObject) and self.attacker.checkIfEnemy(unit) and not unit.isDying: applied_status = StatusObject.statusparser(status.status_after_battle) StatusObject.HandleStatusAddition(applied_status, unit) if status.lost_on_attack and not self.attacker.isDying and (self.item.weapon or self.item.detrimental): StatusObject.HandleStatusRemoval(status, self.attacker) if self.defender: for status in self.defender.status_effects: if status.status_after_battle and self.defender.checkIfEnemy(self.attacker) and not self.defender.isDying and not self.attacker.isDying: applied_status = StatusObject.statusparser(status.status_after_battle) StatusObject.HandleStatusAddition(applied_status, self.attacker) # Handle death for unit in all_units: if unit.isDying: logger.debug('%s is dying.', unit.name) if isinstance(unit, TileObject.TileObject): gameStateObj.map.destroy(unit, gameStateObj) else: gameStateObj.stateMachine.changeState('dying') gameStateObj.message.append(Dialogue.Dialogue_Scene(metaDataObj['death_quotes'], unit, event_flag=False)) gameStateObj.stateMachine.changeState('dialogue') ### Actually remove items if a_broke_item: self.attacker.remove_item(self.item) if d_broke_item: self.defender.remove_item(self.defender.getMainWeapon())
def apply_mod(self, unit, weapon, gameStateObj): if self.item: self.reverse_mod() self.item = weapon self.status = StatusObject.statusparser(str('9')) weapon.status.append(self.status)
def apply_mod(self, item): self.reverse_mod(item) item.status.append(StatusObject.statusparser('Weakened')) item.celeste = True
def update(self, gameStateObj, metaDataObj): # print(self.state.getState()) # Don't do this if there is no exp change if not self.force_level and self.expNew == 0: return True unit_klass = metaDataObj['class_dict'][self.unit.klass] max_level = Utility.find_max_level(unit_klass['tier'], cf.CONSTANTS['max_level']) if self.unit.level >= max_level and unit_klass['turns_into'] is None: return True # We're done here currentTime = Engine.get_time() # Initiating State if self.state.getState() == 'init': self.exp_bar = Exp_Bar(self.expSet, not self.in_combat) # Create exp_bar self.state_time = currentTime self.state.changeState('exp_wait') # Wait before starting to increment exp elif self.state.getState() == 'exp_wait': self.exp_bar.update(self.expSet) if currentTime - self.state_time > 400: self.state.changeState('exp0') self.state_time = currentTime GC.SOUNDDICT['Experience Gain'].play(-1) # Increment exp until done or 100 exp is reached elif self.state.getState() == 'exp0': progress = (currentTime - self.state_time) / float( self.total_time_for_exp) self.expSet = self.expOld + progress * self.expNew self.expSet = int(min(self.expNew + self.expOld, self.expSet)) self.exp_bar.update(self.expSet) # transitions if self.expNew + self.expOld <= self.expSet: GC.SOUNDDICT['Experience Gain'].stop() if self.expSet >= 100: if self.unit.level >= max_level: # If I would promote because I am level 20 GC.SOUNDDICT['Experience Gain'].stop() if cf.CONSTANTS['auto_promote'] and metaDataObj[ 'class_dict'][self.unit.klass][ 'turns_into']: # If has at least one class to turn into self.expSet = 100 GC.SOUNDDICT['Level Up'].play() else: self.expSet = 99 self.state.clear() self.state.changeState('prepare_promote') self.state.changeState('exp_leave') self.exp_bar.fade_out() self.state_time = currentTime else: self.expSet = 0 self.unit.level += 1 self.levelup_list = self.unit.level_up( gameStateObj, metaDataObj['class_dict'][self.unit.klass]) self.state.changeState('exp100') # Do not reset state time # Extra time to account for end pause elif currentTime - self.state_time >= self.total_time_for_exp + 500: self.state.clear() self.state.changeState('exp_leave') self.state_time = currentTime self.exp_bar.fade_out() elif self.state.getState() == 'exp_leave': done = self.exp_bar.update(self.expSet) if done: self.unit.exp += self.expNew self.state.back() self.state_time = currentTime if len(self.state.state) <= 0: return True # Continue incrementing past 100 elif self.state.getState() == 'exp100': progress = (currentTime - self.state_time) / float( self.total_time_for_exp) self.expSet = self.expOld + self.expNew * progress - 100 self.expSet = int(min(self.expNew + self.expOld - 100, self.expSet)) self.exp_bar.update(self.expSet) if self.expNew + self.expOld - 100 <= self.expSet: GC.SOUNDDICT['Experience Gain'].stop() # Extra time to account for pause at end if currentTime - self.state_time >= self.total_time_for_exp + 500: self.state.clear() self.state.changeState('levelUp') self.state.changeState('exp_leave') self.exp_bar.fade_out() self.state_time = currentTime # Display the level up animation initial elif self.state.getState() == 'levelUp': if not self.level_up_sound_played: GC.SOUNDDICT['Level Up'].play() self.level_up_sound_played = True # Update it if self.levelUpAnimation.update(gameStateObj): if self.in_combat: self.in_combat.darken_ui() self.state.changeState('levelScreen') self.state_time = currentTime # Display the level up stat screen elif self.state.getState() == 'levelScreen': time_to_wait = self.LEVELUPWAIT + (self.get_num_sparks() + 1) * self.SPARKTIME + 500 # Am i Done displaying? if currentTime - self.state_time >= time_to_wait: if self.in_combat: self.in_combat.lighten_ui() # Handle EXP when the user levels up, if this is not a forced level if not self.force_level: self.unit.exp += self.expNew if self.unit.exp >= 100: self.unit.exp = self.expNew - (100 - self.expOld) # Remove animations self.animations = [] # check for weapon gain if self.new_wexp: self.unit.increase_wexp(self.new_wexp, gameStateObj) # check for skill gain if not a forced level if not self.force_level: for level_needed, class_skill in metaDataObj['class_dict'][ self.unit.klass]['skills']: if self.unit.level == level_needed: if class_skill == 'Feat': gameStateObj.cursor.currentSelectedUnit = self.unit gameStateObj.stateMachine.changeState( 'feat_choice') else: skill = StatusObject.statusparser(class_skill) # If we don't already have this skill if skill.stack or skill.id not in ( s.id for s in self.unit.status_effects): StatusObject.HandleStatusAddition( skill, self.unit, gameStateObj) gameStateObj.banners.append( Banner.gainedSkillBanner( self.unit, skill)) gameStateObj.stateMachine.changeState( 'itemgain') return True # Wait 100 milliseconds before transferring us to the promotion state elif self.state.getState() == 'prepare_promote': self.exp_bar.update(self.expSet) if currentTime - self.state_time > 100: if cf.CONSTANTS['auto_promote'] and metaDataObj['class_dict'][ self.unit.klass][ 'turns_into']: # If has at least one class to turn into self.expSet = 0 class_options = metaDataObj['class_dict'][ self.unit.klass]['turns_into'] if len(class_options) > 1: gameStateObj.cursor.currentSelectedUnit = self.unit gameStateObj.stateMachine.changeState( 'promotion_choice') gameStateObj.stateMachine.changeState('transition_out') self.state.changeState('wait') self.state_time = currentTime elif len(class_options) == 1: gameStateObj.cursor.currentSelectedUnit = self.unit self.unit.new_klass = class_options[0] gameStateObj.stateMachine.changeState('promotion') gameStateObj.stateMachine.changeState('transition_out') # self.state.changeState('promote') self.state.changeState('wait') self.state_time = currentTime else: self.unit.exp = 99 return True # Done else: # Unit is at the highest point it can be. No more. self.unit.exp = 99 return True # Done elif self.state.getState() == 'item_promote': if metaDataObj['class_dict'][self.unit.klass][ 'turns_into']: # If has at least one class to turn into class_options = metaDataObj['class_dict'][ self.unit.klass]['turns_into'] if len(class_options) > 1: gameStateObj.cursor.currentSelectedUnit = self.unit gameStateObj.stateMachine.changeState('promotion_choice') gameStateObj.stateMachine.changeState('transition_out') self.state.changeState('wait') self.state_time = currentTime elif len(class_options) == 1: gameStateObj.cursor.currentSelectedUnit = self.unit self.unit.new_klass = class_options[0] gameStateObj.stateMachine.changeState('promotion') gameStateObj.stateMachine.changeState('transition_out') # self.state.changeState('promote') self.state.changeState('wait') self.state_time = currentTime else: self.unit.exp = 99 return True # Done else: # Unit is at the highest point it can be. No more. self.unit.exp = 99 return True # Done elif self.state.getState() == 'wait': if currentTime - self.state_time > 1000: # Wait a while return True elif self.state.getState() == 'promote': # Class should already have been changed by now in the levelpromote state # Here's where I change all the important information new_class = metaDataObj['class_dict'][self.unit.klass] old_anim = self.unit.battle_anim self.unit.removeSprites() self.unit.loadSprites() # Reseed the combat animation if self.in_combat and old_anim: item = self.unit.getMainWeapon() magic = Weapons.TRIANGLE.isMagic(item) if item else False anim = GC.ANIMDICT.partake(self.unit.klass, self.unit.gender, item, magic) if anim: # Build animation script = anim['script'] if self.unit.name in anim['images']: frame_dir = anim['images'][self.unit.name] else: frame_dir = anim['images'][ 'Generic' + Utility.get_color(self.unit.team)] import BattleAnimation self.unit.battle_anim = BattleAnimation.BattleAnimation( self.unit, frame_dir, script) self.unit.battle_anim.awake( owner=old_anim.owner, parent=old_anim.parent, partner=old_anim.partner, right=old_anim.right, at_range=old_anim.at_range, init_speed=old_anim.entrance, init_position=old_anim.init_position) else: self.unit.battle_anim = old_anim # Reset Level self.unit.level = 1 # Actually change class # Reset movement group self.unit.movement_group = new_class['movement_group'] # Add weapon exp gains from that class. # This right here! self.new_wexp = new_class['wexp_gain'] # Add any extra tags if new_class[ 'tags']: # Add any necessary tags. Does not currently take away tags, although it may have to later self.unit.tags |= new_class['tags'] # Give promotion # self.levelup_list = self.unit.level_up(new_class, apply_level=False) # Level up once, then promote. # self.levelup_list = [x + y for x, y in zip(self.levelup_list, new_class['promotion'])] # Add lists together self.levelup_list = new_class[ 'promotion'] # No two level ups, too much gain in one level... current_stats = list(self.unit.stats.values()) assert len(self.levelup_list) == len( new_class['max']) == len(current_stats), "%s %s %s" % ( self.levelup_list, new_class['max'], current_stats) for index, stat in enumerate(self.levelup_list): self.levelup_list[index] = min( stat, new_class['max'][index] - current_stats[index].base_stat) self.unit.apply_levelup(self.levelup_list) if self.in_combat: self.in_combat.darken_ui() self.state.changeState('levelScreen') self.state_time = currentTime # Reset time so that it doesn't skip right over LevelScreen return False