예제 #1
0
def explore_pokemon(context, request):
    # TODO should this be part of the api?  it knows if there was "really" a
    # search
    did_search = bool(request.GET)

    if not did_search:
        return dict(
            did_search=did_search,
            results=None,
            all_pokemon=None,
            all_types=None,
            all_generations=None,
        )

    q = api.Query(api.PokemonLocus, session)
    q.parse_multidict(request.GET)


    return dict(
        did_search=did_search,
        results=q.execute(),



        # XXX these really oughta come from the locus, or something.  fix this
        # up yo
        all_types=session.query(t.Type),
        all_generations=session.query(t.Generation),
    )
예제 #2
0
def explore_pokemon(context, request):
    # TODO should this be part of the api?  it knows if there was "really" a
    # search
    did_search = bool(request.GET)

    if not did_search:
        return dict(
            did_search=did_search,
            results=None,
            all_pokemon=None,
            all_types=None,
            all_generations=None,
        )

    q = api.Query(api.PokemonLocus, session)
    q.parse_multidict(request.GET)

    return dict(
        did_search=did_search,
        results=q.execute(),

        # XXX these really oughta come from the locus, or something.  fix this
        # up yo
        all_types=session.query(t.Type),
        all_generations=session.query(t.Generation),
    )
예제 #3
0
def nature_browse(context, request):
    natures = session.query(t.Nature) \
        .join(t.Nature.names_local) \
        .options(
            contains_eager(t.Nature.names_local),
            joinedload(t.Nature.increased_stat),
            joinedload(t.Nature.decreased_stat),
            joinedload(t.Nature.likes_flavor),
            joinedload(t.Nature.hates_flavor),
        ) \
        .order_by(t.Nature.names_table.name.asc())

    # TODO table is kinda fugly still
    # TODO not sure this page is titled correctly given gene hints
    # TODO old page has sort-by-stat

    stat_hint_table = dict()
    stat_hints = session.query(t.StatHint).options(joinedload(t.StatHint.names_local))
    for stat_hint in stat_hints:
        subdict = stat_hint_table.setdefault(stat_hint.stat, {})
        subdict[stat_hint.gene_mod_5] = stat_hint.message

    return dict(
        natures=natures,
        stat_hints=stat_hint_table,
    )
예제 #4
0
def move_search(context, request):
    # XXX
    request._LOCALE_ = 'en'

    # TODO should this be part of the api?  it knows if there was "really" a
    # search
    did_search = bool(request.GET)


    q = api.Query(api.MoveLocus, session)
    q.parse_multidict(request.GET)

    move_groups, moves, move_previews = q.results()


    return dict(
        did_search=did_search,

        move_groups=move_groups,
        moves=moves,
        move_previews=move_previews,



        # XXX these really oughta come from the locus, or something.  fix this
        # up yo
        all_types=session.query(t.Type),
        all_generations=session.query(t.Generation),
    )
예제 #5
0
def nature_browse(context, request):
    natures = session.query(t.Nature) \
        .join(t.Nature.names_local) \
        .options(
            contains_eager(t.Nature.names_local),
            joinedload(t.Nature.increased_stat),
            joinedload(t.Nature.decreased_stat),
            joinedload(t.Nature.likes_flavor),
            joinedload(t.Nature.hates_flavor),
        ) \
        .order_by(t.Nature.names_table.name.asc())

    # TODO table is kinda fugly still
    # TODO not sure this page is titled correctly given gene hints
    # TODO old page has sort-by-stat

    stat_hint_table = dict()
    stat_hints = session.query(t.StatHint).options(
        joinedload(t.StatHint.names_local))
    for stat_hint in stat_hints:
        subdict = stat_hint_table.setdefault(stat_hint.stat, {})
        subdict[stat_hint.gene_mod_5] = stat_hint.message

    return dict(
        natures=natures,
        stat_hints=stat_hint_table,
    )
예제 #6
0
def api_test(context, request):
    print context
    pokemon = session.query(t.Pokemon).join(t.Pokemon.species).filter(t.PokemonSpecies.identifier == 'rhydon').one()

    hardcoded = {
        # TODO specify output language
        'name': dict(en=pokemon.name),

        'base-stats': dict((pokemon_stat.stat.identifier, pokemon_stat.base_stat) for pokemon_stat in pokemon.stats),

        # TODO sprite urls

        # TODO link these?  optionally expand them?  something??
        'types': [type_.identifier for type_ in pokemon.types],

        # TODO what to show here, either?  short effect in output language?
        'abilities': [ability.identifier for ability in pokemon.abilities],

        # TODO damage?
    }

    data = dict()

    locus = a.PokemonLocus(pokemon)
    data['identifier'] = locus.identifier

    data.update(hardcoded)

    return data
예제 #7
0
 def iter_options(self):
     # XXX
     from veekun_pokedex.model import session
     # TODO need to filter this
     # TODO need to order this?
     for row in session.query(self.target_locus):
         yield self.identified_by.__get__(row, type(row)), row
예제 #8
0
def place(context, request):
    location = context

    template_ns = dict()
    template_ns['location'] = location

    # Eagerload
    (session.query(t.Location)
        .filter_by(id=location.id)
        .options(
            joinedload('areas'),
            subqueryload('areas.encounters'),
            joinedload('areas.encounters.condition_values'),
            joinedload('areas.encounters.condition_values.condition'),
        )
        .all()
    )

    encounters = EncounterCollection([
        encounter
        for area in location.areas
        for encounter in area.encounters
    ])
    template_ns['fudged_encounters'] = encounters

    return template_ns
예제 #9
0
def type_browse(context, request):
    types = (
        session.query(t.Type)
            .join(t.Type.names_local)
            # Force inner join here to strip out e.g. Shadow, which has no
            # efficacy
            .join(t.Type.damage_efficacies)
            .order_by(t.Type.names_table.name)
            .options(
                contains_eager(t.Type.names_local),
                contains_eager(t.Type.damage_efficacies),
            )
            .all()
    )

    efficacy_map = {}
    for attacking_type in types:
        submap = efficacy_map[attacking_type] = {}
        for efficacy in attacking_type.damage_efficacies:
            submap[efficacy.target_type] = efficacy.damage_factor


    template_ns = dict(
        types=types,
        efficacy_map=efficacy_map,
    )

    return template_ns
예제 #10
0
def pokemon_search_landing_test(context, request):
    did_search = bool(request.GET)

    if did_search:
        all_pokemon = (session.query(t.Pokemon).filter(
            t.Pokemon.is_default).order_by(t.Pokemon.species_id.asc()).options(
                joinedload(t.Pokemon.species)).all())
예제 #11
0
def api_test(context, request):
    print context
    pokemon = session.query(t.Pokemon).join(t.Pokemon.species).filter(
        t.PokemonSpecies.identifier == 'rhydon').one()

    hardcoded = {
        # TODO specify output language
        'name':
        dict(en=pokemon.name),
        'base-stats':
        dict((pokemon_stat.stat.identifier, pokemon_stat.base_stat)
             for pokemon_stat in pokemon.stats),

        # TODO sprite urls

        # TODO link these?  optionally expand them?  something??
        'types': [type_.identifier for type_ in pokemon.types],

        # TODO what to show here, either?  short effect in output language?
        'abilities': [ability.identifier for ability in pokemon.abilities],

        # TODO damage?
    }

    data = dict()

    locus = a.PokemonLocus(pokemon)
    data['identifier'] = locus.identifier

    data.update(hardcoded)

    return data
예제 #12
0
def item_browse(context, request):
    items = session.query(t.Item)

    template_ns = dict(
        items=items,
    )

    return template_ns
예제 #13
0
    def iter_options(self):
        # XXX
        from veekun_pokedex.model import session

        # TODO need to filter this
        # TODO need to order this?
        for row in session.query(self.target_locus):
            yield self.identified_by.__get__(row, type(row)), row
예제 #14
0
def region_browse(context, request):
    regions = (
        session.query(t.Region)
            .all()
    )

    template_ns = dict(
        regions=regions,
    )

    return template_ns
예제 #15
0
def pokemon_search_landing_test(context, request):
    did_search = bool(request.GET)

    if did_search:
        all_pokemon = (
            session.query(t.Pokemon)
            .filter(t.Pokemon.is_default)
            .order_by(t.Pokemon.species_id.asc())
            .options(joinedload(t.Pokemon.species))
            .all()
        )
예제 #16
0
def render_markdown(context, row, relation, inline=False):
    """Renders a block of Markdown from the database.

    Call with a row and column name SEPARATELY -- then I can handle language
    fallback if we don't have this particular text translated yet.
    """
    # XXX with the way this is set up, pokedex lib will do the markdowning for
    # us, which makes it hard for the linkifier to find the request.

    local = getattr(row, relation, None)
    if local:
        markdown = local
    else:
        # XXX uhm how do i get the original default language
        from veekun_pokedex.model import session
        import pokedex.db.tables as t
        english = session.query(t.Language).get(9)
        english_prose = getattr(row, relation + '_map').get(english)

        if english_prose:
            _ = context['_']
            context.write(u"""<p class="missing-translation">{0}</p>""".format(
                _(u"Sorry, we haven't translated this into your language yet!  "
                  u"Here's the original English.  (If you can help translate, let us know!)"
                  )))
            markdown = english_prose
        else:
            import warnings
            warnings.warn(u"""Can't find {0!r} prose for row {1!r}""".format(
                relation, row))

            context.write(u'<em>(?)</em>')

            return u''

    rendered = markdown.as_html()

    # Remove the <p> wrapper, if requested
    if inline:
        if not rendered.startswith(u'<p>') or not rendered.endswith(u'</p>'):
            raise ValueError(
                u"""Can't make {0!r} inline for row {1!r}""".format(
                    relation, row))

        rendered = rendered[3:-4]

        if u'<p>' in rendered or u'</p>' in rendered:
            raise ValueError(
                u"""Can't make {0!r} inline for row {1!r}""".format(
                    relation, row))

    context.write(rendered)
    return u''
예제 #17
0
def region(context, request):
    region = context.parent_row

    template_ns = dict()
    template_ns['region'] = region

    locations = (session.query(t.Location).with_parent(region).join(
        t.Location.names_local).order_by(t.Location.names_table.name).options(
            contains_eager(t.Location.names_local)))
    template_ns['locations'] = locations

    return template_ns
예제 #18
0
    def __getitem__(self, key):
        if key not in LANGUAGES:
            raise KeyError

        # TODO could cache these in-process...
        language = session.query(t.Language).filter_by(identifier=key).one()
        session.default_language_id = language.id

        # TODO this leaves a request out to dry if it doesn't happen to come
        # through here
        self.request._LOCALE_ = key
        self.request._veekun_language = language
        return localized_resource_root[key]
예제 #19
0
    def __getitem__(self, key):
        if key not in LANGUAGES:
            raise KeyError

        # TODO could cache these in-process...
        language = session.query(t.Language).filter_by(identifier=key).one()
        session.default_language_id = language.id

        # TODO this leaves a request out to dry if it doesn't happen to come
        # through here
        self.request._LOCALE_ = key
        self.request._veekun_language = language
        return localized_resource_root[key]
예제 #20
0
    def __init__(self, locus_cls, session):
        self.locus_cls = locus_cls
        self.session = session
        self.query = (
            session.query(self.locus_cls.__table__)
            # TODO would be nice to raise an exception on read, but that's not
            # what `noload` does
            .options(lazyload('*'))
        )

        self.fetches = set()

        # TODO this is crap
        self.grouper = None
예제 #21
0
    def __init__(self, locus_cls, session):
        self.locus_cls = locus_cls
        self.session = session
        self.query = (
            session.query(self.locus_cls.__table__)
            # TODO would be nice to raise an exception on read, but that's not
            # what `noload` does
            .options(lazyload("*"))
        )

        self.fetches = set()

        # TODO this is crap
        self.grouper = None
예제 #22
0
def move_search(context, request):
    # XXX
    request._LOCALE_ = 'en'

    # TODO should this be part of the api?  it knows if there was "really" a
    # search
    did_search = bool(request.GET)

    q = api.Query(api.MoveLocus, session)
    q.parse_multidict(request.GET)

    move_groups, moves, move_previews = q.results()

    return dict(
        did_search=did_search,
        move_groups=move_groups,
        moves=moves,
        move_previews=move_previews,

        # XXX these really oughta come from the locus, or something.  fix this
        # up yo
        all_types=session.query(t.Type),
        all_generations=session.query(t.Generation),
    )
예제 #23
0
def render_markdown(context, row, relation, inline=False):
    """Renders a block of Markdown from the database.

    Call with a row and column name SEPARATELY -- then I can handle language
    fallback if we don't have this particular text translated yet.
    """
    # XXX with the way this is set up, pokedex lib will do the markdowning for
    # us, which makes it hard for the linkifier to find the request.

    local = getattr(row, relation, None)
    if local:
        markdown = local
    else:
        # XXX uhm how do i get the original default language
        from veekun_pokedex.model import session
        import pokedex.db.tables as t
        english = session.query(t.Language).get(9)
        english_prose = getattr(row, relation + '_map').get(english)

        if english_prose:
            _ = context['_']
            context.write(u"""<p class="missing-translation">{0}</p>""".format(
                _(u"Sorry, we haven't translated this into your language yet!  "
                  u"Here's the original English.  (If you can help translate, let us know!)")
            ))
            markdown = english_prose
        else:
            import warnings
            warnings.warn(u"""Can't find {0!r} prose for row {1!r}""".format(relation, row))

            context.write(u'<em>(?)</em>')

            return u''

    rendered = markdown.as_html()

    # Remove the <p> wrapper, if requested
    if inline:
        if not rendered.startswith(u'<p>') or not rendered.endswith(u'</p>'):
            raise ValueError(u"""Can't make {0!r} inline for row {1!r}""".format(relation, row))

        rendered = rendered[3:-4]

        if u'<p>' in rendered or u'</p>' in rendered:
            raise ValueError(u"""Can't make {0!r} inline for row {1!r}""".format(relation, row))

    context.write(rendered)
    return u''
예제 #24
0
def ability_browse(context, request):
    abilities = (
        session.query(t.Ability)
        .filter_by(is_main_series=True)
        .join(t.Ability.names_local)
        .order_by(t.Ability.names_table.name.asc())
        .options(
            eagerload(t.Ability.prose_local),
            contains_eager(t.Ability.names_local),
        )
    )

    template_ns = dict(
        abilities=abilities,
    )

    return template_ns
예제 #25
0
def api_search_test(context, request):
    q = session.query(t.Pokemon)
    q = q.join(t.Pokemon.species)

    name_crit = request.GET.getall('name')
    name_crit = filter(lambda x: x, name_crit)
    if name_crit:
        # TODO ...
        q = q.filter(t.PokemonSpecies.identifier.in_(name_crit))

    q = q.order_by(t.Pokemon.id.asc())

    results = []
    for row in q:
        results.append(dict(identifier=row.species.identifier))

    return results
예제 #26
0
def region(context, request):
    region = context.parent_row

    template_ns = dict()
    template_ns['region'] = region

    locations = (
        session.query(t.Location)
            .with_parent(region)
            .join(t.Location.names_local)
            .order_by(t.Location.names_table.name)
            .options(
                contains_eager(t.Location.names_local)
            )
    )
    template_ns['locations'] = locations

    return template_ns
예제 #27
0
def api_search_test(context, request):
    q = session.query(t.Pokemon)
    q = q.join(t.Pokemon.species)

    name_crit = request.GET.getall('name')
    name_crit = filter(lambda x: x, name_crit)
    if name_crit:
        # TODO ...
        q = q.filter(t.PokemonSpecies.identifier.in_(name_crit))

    q = q.order_by(t.Pokemon.id.asc())


    results = []
    for row in q:
        results.append(dict(identifier=row.species.identifier))

    return results
예제 #28
0
    def __getitem__(self, key):
        # `key` should be a whatever name
        q = session.query(self.table) \
            .join(self.table.names_local) \
            .filter(func.lower(self.table.names_table.name) == key)

        if self.parent_row is not None:
            q = q.with_parent(self.parent_row)

        try:
            row = q.one()
        except NoResultFound:
            # TODO ought to do a 404 with lookup
            raise KeyError
        else:
            if self.parent_class:
                return self.parent_class(row)
            else:
                return row
예제 #29
0
    def __getitem__(self, key):
        # `key` should be a whatever name
        q = session.query(self.table) \
            .join(self.table.names_local) \
            .filter(func.lower(self.table.names_table.name) == key)

        if self.parent_row is not None:
            q = q.with_parent(self.parent_row)

        try:
            row = q.one()
        except NoResultFound:
            # TODO ought to do a 404 with lookup
            raise KeyError
        else:
            if self.parent_class:
                return self.parent_class(row)
            else:
                return row
예제 #30
0
def place(context, request):
    location = context

    template_ns = dict()
    template_ns['location'] = location

    # Eagerload
    (session.query(t.Location).filter_by(id=location.id).options(
        joinedload('areas'),
        subqueryload('areas.encounters'),
        joinedload('areas.encounters.condition_values'),
        joinedload('areas.encounters.condition_values.condition'),
    ).all())

    encounters = EncounterCollection([
        encounter for area in location.areas for encounter in area.encounters
    ])
    template_ns['fudged_encounters'] = encounters

    return template_ns
예제 #31
0
def item_browse(context, request):
    items = session.query(t.Item)

    template_ns = dict(items=items, )

    return template_ns
예제 #32
0
def _build_evolution_table(evolution_chain_id):
    """Convert an evolution chain into a format more amenable to the HTML table
    model.

    Returns a nested list like:

        [
            [empty, Eevee, Vaporeon, None]
            [None, None, Jolton, None]
            [None, None, Flareon, None]
            ...
        ]

    Each sublist is a physical row in the resulting table, containing one
    element per evolution stage: baby, basic, stage 1, and stage 2.  The
    individual items are simple `EvolutionTableCell` objects: None is a cell
    that should be skipped entirely (due to rowspans) and "empty" is a cell
    object whose `is_empty` is true.
    """

    # Prefetch the evolution details
    q = session.query(t.PokemonSpecies) \
        .filter_by(evolution_chain_id=evolution_chain_id) \
        .order_by(t.PokemonSpecies.id.asc()) \
        .options(
            subqueryload('evolutions'),
            joinedload('evolutions.trigger'),
            joinedload('evolutions.trigger_item'),
            joinedload('evolutions.held_item'),
            joinedload('evolutions.location'),
            joinedload('evolutions.known_move'),
            joinedload('evolutions.party_species'),
            joinedload('parent_species'),
            joinedload('default_form'),
        )
    family = q.all()

    # Strategy: Build a row for each final-form Pokémon.  Intermediate species
    # will naturally get included.
    # We need to replace repeated cells in the same column with None and fix
    # rowspans.  Cute trick: build the table backwards, and propagate rowspans
    # upwards through the table as it's built.
    evolution_table = []

    all_parent_species = set(species.parent_species for species in family)
    final_species = [
        species for species in family if species not in all_parent_species
    ]
    final_species.reverse()

    for species in final_species:
        row = []
        while species:
            row.insert(0, EvolutionTableCell(species))
            species = species.parent_species

        # The last cell in the row is now either a basic or baby.  Insert a
        # blank cell (with species of None) for baby if necessary
        if not row[0].species.is_baby:
            row.insert(0, EvolutionTableCell(None))

        # Pad to four columns
        while len(row) < 4:
            row.append(EvolutionTableCell(None))

        # Compare to the previous row (which is actually the next row).  If
        # anything's repeated, absorb its rowspan and replace it with None.
        if evolution_table:
            for i, (cell, next_cell) in enumerate(zip(row,
                                                      evolution_table[-1])):
                if cell.species == next_cell.species:
                    cell.rowspan += next_cell.rowspan
                    evolution_table[-1][i] = None

        evolution_table.append(row)

    evolution_table.reverse()
    return evolution_table
예제 #33
0
def pokemon(context, request):
    species = context
    default_pokemon = species.default_pokemon

    # TODO this pokemon is actually a species!!  deal with forms!!!
    template_ns = dict(
        species=species,
        pokemon=default_pokemon,
    )

    # Preload a bunch of stuff we'll always need
    # TODO share this?
    for preload_enum_table in (t.Generation, t.VersionGroup, t.Version):
        session.query(preload_enum_table).all()

    ## Type efficacy
    type_efficacies = defaultdict(lambda: 100)
    for target_type in default_pokemon.types:
        # We start at 100, and every damage factor is a percentage.  Dividing
        # by 100 with every iteration turns the damage factor into a decimal
        # percentage, without any float nonsense
        for type_efficacy in target_type.target_efficacies:
            type_efficacies[type_efficacy.damage_type] = (
                type_efficacies[type_efficacy.damage_type] *
                type_efficacy.damage_factor // 100)

    # Turn that dict of type => efficacy into a dict of efficacy => types.
    efficacy_types = {}
    for type_, efficacy in type_efficacies.items():
        efficacy_types.setdefault(efficacy, []).append(type_)

    template_ns['efficacy_types'] = efficacy_types

    ### Stats
    # This takes a lot of queries  :(
    stat_total = 0
    stat_percentiles = {}
    for pokemon_stat in default_pokemon.stats:
        stat_total += pokemon_stat.base_stat

        less = _countif(t.PokemonStat.base_stat < pokemon_stat.base_stat)
        equal = _countif(t.PokemonStat.base_stat == pokemon_stat.base_stat)
        total = func.count(t.PokemonStat.base_stat)
        q = session.query((less + equal / 2.) / total) \
            .filter_by(stat=pokemon_stat.stat)

        percentile, = q.one()

        # pg gives us fixed-point, which sqla turns into Decimal
        stat_percentiles[pokemon_stat.stat] = float(percentile)

    # Percentile for the total
    # Need to make a derived table that maps pokemon_id to total_stats
    stat_total_subq = session.query(
            t.PokemonStat.pokemon_id,
            func.sum(t.PokemonStat.base_stat).label('stat_total'),
        ) \
        .group_by(t.PokemonStat.pokemon_id) \
        .subquery()

    less = _countif(stat_total_subq.c.stat_total < stat_total)
    equal = _countif(stat_total_subq.c.stat_total == stat_total)
    total = func.count(stat_total_subq.c.stat_total)
    q = session.query((less + equal / 2.) / total)

    percentile, = q.one()
    stat_percentiles['total'] = float(percentile)

    template_ns['stat_percentiles'] = stat_percentiles
    template_ns['stat_total'] = stat_total

    ## Wild held items
    # To date (as of B/W 2), no Pokémon has ever held more than three different
    # items in its history.  So it makes sense to show wild items as a little
    # table like the move table.
    item_table = CollapsibleVersionTable()
    for pokemon_item in default_pokemon.items:
        item_table.add_version_datum(pokemon_item.version, pokemon_item.item,
                                     pokemon_item.rarity)

    template_ns['wild_held_items'] = item_table

    ## Evolution
    template_ns['evolution_table'] = _build_evolution_table(
        species.evolution_chain_id)

    ## Moves
    # XXX yeah this is bad
    q = session.query(t.PokemonMove) \
        .with_parent(default_pokemon) \
        .order_by(
            t.PokemonMove.level.asc(),
            # t.Machine.machine_number.asc(),
            t.PokemonMove.order.asc(),
            t.PokemonMove.version_group_id.asc(),
        )

    moves_table = SectionedCollapsibleVersionTable()
    for pokemove in q:
        moves_table.add_group_datum(pokemove.method, pokemove.version_group,
                                    pokemove.move, pokemove.level)

    _method_order = [
        u'level-up', 'egg', u'tutor', u'stadium-surfing-pikachu', u'machine'
    ]
    moves_table.sort_sections(
        lambda method: _method_order.index(method.identifier))
    template_ns['moves'] = moves_table

    return template_ns
예제 #34
0
def _build_evolution_table(evolution_chain_id):
    """Convert an evolution chain into a format more amenable to the HTML table
    model.

    Returns a nested list like:

        [
            [empty, Eevee, Vaporeon, None]
            [None, None, Jolton, None]
            [None, None, Flareon, None]
            ...
        ]

    Each sublist is a physical row in the resulting table, containing one
    element per evolution stage: baby, basic, stage 1, and stage 2.  The
    individual items are simple `EvolutionTableCell` objects: None is a cell
    that should be skipped entirely (due to rowspans) and "empty" is a cell
    object whose `is_empty` is true.
    """

    # Prefetch the evolution details
    q = session.query(t.PokemonSpecies) \
        .filter_by(evolution_chain_id=evolution_chain_id) \
        .order_by(t.PokemonSpecies.id.asc()) \
        .options(
            subqueryload('evolutions'),
            joinedload('evolutions.trigger'),
            joinedload('evolutions.trigger_item'),
            joinedload('evolutions.held_item'),
            joinedload('evolutions.location'),
            joinedload('evolutions.known_move'),
            joinedload('evolutions.party_species'),
            joinedload('parent_species'),
            joinedload('default_form'),
        )
    family = q.all()

    # Strategy: Build a row for each final-form Pokémon.  Intermediate species
    # will naturally get included.
    # We need to replace repeated cells in the same column with None and fix
    # rowspans.  Cute trick: build the table backwards, and propagate rowspans
    # upwards through the table as it's built.
    evolution_table = []

    all_parent_species = set(species.parent_species for species in family)
    final_species = [
        species for species in family
        if species not in all_parent_species
    ]
    final_species.reverse()

    for species in final_species:
        row = []
        while species:
            row.insert(0, EvolutionTableCell(species))
            species = species.parent_species

        # The last cell in the row is now either a basic or baby.  Insert a
        # blank cell (with species of None) for baby if necessary
        if not row[0].species.is_baby:
            row.insert(0, EvolutionTableCell(None))

        # Pad to four columns
        while len(row) < 4:
            row.append(EvolutionTableCell(None))

        # Compare to the previous row (which is actually the next row).  If
        # anything's repeated, absorb its rowspan and replace it with None.
        if evolution_table:
            for i, (cell, next_cell) in enumerate(zip(row, evolution_table[-1])):
                if cell.species == next_cell.species:
                    cell.rowspan += next_cell.rowspan
                    evolution_table[-1][i] = None

        evolution_table.append(row)

    evolution_table.reverse()
    return evolution_table
예제 #35
0
def pokemon(context, request):
    species = context
    default_pokemon = species.default_pokemon

    # TODO this pokemon is actually a species!!  deal with forms!!!
    template_ns = dict(
        species=species,
        pokemon=default_pokemon,
    )

    # Preload a bunch of stuff we'll always need
    # TODO share this?
    for preload_enum_table in (t.Generation, t.VersionGroup, t.Version):
        session.query(preload_enum_table).all()

    ## Type efficacy
    type_efficacies = defaultdict(lambda: 100)
    for target_type in default_pokemon.types:
        # We start at 100, and every damage factor is a percentage.  Dividing
        # by 100 with every iteration turns the damage factor into a decimal
        # percentage, without any float nonsense
        for type_efficacy in target_type.target_efficacies:
            type_efficacies[type_efficacy.damage_type] = (
                type_efficacies[type_efficacy.damage_type]
                * type_efficacy.damage_factor // 100)

    # Turn that dict of type => efficacy into a dict of efficacy => types.
    efficacy_types = {}
    for type_, efficacy in type_efficacies.items():
        efficacy_types.setdefault(efficacy, []).append(type_)

    template_ns['efficacy_types'] = efficacy_types

    ### Stats
    # This takes a lot of queries  :(
    stat_total = 0
    stat_percentiles = {}
    for pokemon_stat in default_pokemon.stats:
        stat_total += pokemon_stat.base_stat

        less = _countif(t.PokemonStat.base_stat < pokemon_stat.base_stat)
        equal = _countif(t.PokemonStat.base_stat == pokemon_stat.base_stat)
        total = func.count(t.PokemonStat.base_stat)
        q = session.query((less + equal / 2.) / total) \
            .filter_by(stat=pokemon_stat.stat)

        percentile, = q.one()

        # pg gives us fixed-point, which sqla turns into Decimal
        stat_percentiles[pokemon_stat.stat] = float(percentile)

    # Percentile for the total
    # Need to make a derived table that maps pokemon_id to total_stats
    stat_total_subq = session.query(
            t.PokemonStat.pokemon_id,
            func.sum(t.PokemonStat.base_stat).label('stat_total'),
        ) \
        .group_by(t.PokemonStat.pokemon_id) \
        .subquery()

    less = _countif(stat_total_subq.c.stat_total < stat_total)
    equal = _countif(stat_total_subq.c.stat_total == stat_total)
    total = func.count(stat_total_subq.c.stat_total)
    q = session.query((less + equal / 2.) / total)

    percentile, = q.one()
    stat_percentiles['total'] = float(percentile)

    template_ns['stat_percentiles'] = stat_percentiles
    template_ns['stat_total'] = stat_total

    ## Wild held items
    # To date (as of B/W 2), no Pokémon has ever held more than three different
    # items in its history.  So it makes sense to show wild items as a little
    # table like the move table.
    item_table = CollapsibleVersionTable()
    for pokemon_item in default_pokemon.items:
        item_table.add_version_datum(pokemon_item.version, pokemon_item.item, pokemon_item.rarity)

    template_ns['wild_held_items'] = item_table

    ## Evolution
    template_ns['evolution_table'] = _build_evolution_table(
        species.evolution_chain_id)

    ## Moves
    # XXX yeah this is bad
    q = session.query(t.PokemonMove) \
        .with_parent(default_pokemon) \
        .order_by(
            t.PokemonMove.level.asc(),
            # t.Machine.machine_number.asc(),
            t.PokemonMove.order.asc(),
            t.PokemonMove.version_group_id.asc(),
        )

    moves_table = SectionedCollapsibleVersionTable()
    for pokemove in q:
        moves_table.add_group_datum(
            pokemove.method, pokemove.version_group, pokemove.move, pokemove.level)

    _method_order = [u'level-up', 'egg', u'tutor', u'stadium-surfing-pikachu', u'machine']
    moves_table.sort_sections(lambda method: _method_order.index(method.identifier))
    template_ns['moves'] = moves_table

    return template_ns
예제 #36
0
def region_browse(context, request):
    regions = (session.query(t.Region).all())

    template_ns = dict(regions=regions, )

    return template_ns