示例#1
0
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']))
示例#2
0
    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()
示例#4
0
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'])
示例#5
0
 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))
示例#6
0
 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)
示例#7
0
    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
示例#8
0
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
示例#9
0
 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
示例#10
0
 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
示例#11
0
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
示例#12
0
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
示例#13
0
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
示例#14
0
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
示例#15
0
    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
示例#16
0
    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())
示例#17
0
 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)
示例#18
0
 def apply_mod(self, item):
     self.reverse_mod(item)
     item.status.append(StatusObject.statusparser('Weakened'))
     item.celeste = True
示例#19
0
    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