Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0db2a3f
adding idol model to models.py
erys May 20, 2018
a82454f
Adding IdolCollection to magicollections.py
erys May 20, 2018
b4237f9
Making changes requested by db0
erys May 20, 2018
810a757
Merge branch 'idol-model' of https://github.com/MagiCircles/MajiLove …
erys May 20, 2018
48a33e0
fixing translated fields and commenting out things that are not relev…
erys May 20, 2018
7d4dec9
Adding Photo model, still missing "how to obtain field", will add aft…
erys May 20, 2018
51262f2
Adding basic form and slightly changing display nam for the small ima…
erys May 20, 2018
43eccd5
fixing typo: display_bloody_type -> display_blood_type
erys May 20, 2018
e21fe34
Merge branch 'idol-model' of https://github.com/MagiCircles/MajiLove …
erys May 20, 2018
11035e4
adding hobby as translated field to IdolCollection
erys May 20, 2018
16d270e
slightly modified japanese translation for locker skills
erys May 21, 2018
fcbee14
Merge branch 'master' of https://github.com/MagiCircles/MajiLove into…
erys May 21, 2018
efec8d9
missed a spot when merging
erys May 21, 2018
689a2da
Merge branch 'master' of https://github.com/MagiCircles/MajiLove into…
erys May 21, 2018
5865cac
fixing up photo model
erys May 26, 2018
6bf19d4
Added mic image and idols link to navbar
erys May 26, 2018
79e5a2f
fixed translated_fields
erys May 26, 2018
5ea2c6a
cannot figure out how to put astrological_signs into translated_field…
erys May 26, 2018
6bece87
fixing up some properties a little
erys May 26, 2018
ecf7d8b
initial add of collectiblephoto
erys May 28, 2018
60a1db4
fixing up leader skill functions
erys May 28, 2018
9763e2d
Merge branch 'photo-model' of https://github.com/MagiCircles/MajiLove…
erys May 28, 2018
335872d
I think I added all the fields I need for collectible photo
erys May 28, 2018
80520fb
Merge branch 'idol-collection' of https://github.com/MagiCircles/Maji…
erys May 28, 2018
6c1c8a7
adding photo collection
erys May 29, 2018
e76f212
refining skill properties
erys Jun 5, 2018
38abec5
Merge branch 'photo-collection' into collectible-photo-model
erys Jun 5, 2018
f9a46e7
Merge branch 'master' of https://github.com/MagiCircles/MajiLove into…
erys Jun 20, 2018
38bede5
Merge branch 'master' of https://github.com/MagiCircles/MajiLove into…
erys Jun 30, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions majilove/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ class Meta(AutoForm.Meta):
model = models.Idol
fields = '__all__'
save_owner_on_creation = True

class PhotoForm(AutoForm):
class Meta(AutoForm.Meta):
model = models.Photo
fields = '__all__'
save_owner_on_creation = True
88 changes: 88 additions & 0 deletions majilove/magicollections.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.utils.translation import ugettext_lazy as _
from magi.magicollections import MagiCollection, ActivityCollection as _ActivityCollection, BadgeCollection as _BadgeCollection, StaffConfigurationCollection as _StaffConfigurationCollection, DonateCollection as _DonateCollection
from magi.default_settings import RAW_CONTEXT
from majilove import models, forms

############################################################
Expand Down Expand Up @@ -38,8 +39,95 @@ class IdolCollection(MagiCollection):
translated_fields = ('name', 'description', 'instrument', 'hometown', 'hobby')

form_class = forms.IdolForm
multipart = True

reportable = False
blockable = False

############################################################
# Photo Collection

PHOTO_STATS_FIELDS = [
u'{}{}'.format(_st, _sf) for _sf in [
'_min', '_single_copy_max', '_max_copy_max',
] for _st in [
'dance', 'vocal', 'charm', 'overall',
]
]

PHOTO_ICONS = {
'name': 'id',
'release_date': 'date',
}

PHOTO_IMAGES = {
'idol': 'mic',
}

PHOTOS_EXCLUDE = [
'i_skill_type', 'i_leader_skill_stat', 'leader_skill_percentage', 'skill_note_count', 'skill_percentage', 'i_sub_skill_type', 'sub_skill_amount', 'sub_skill_percentage',
] + [
'image', 'image_special_shot', 'art', 'art_special_shot', 'transparent', 'transparent_special_shot', 'full_photo', 'full_photo_special_shot',
]


PHOTOS_ORDER = [
'id', 'name', 'idol', 'rarity', 'color', 'release_date', 'skill', 'sub_skill', 'images', 'full_photos', 'arts', 'transparents',
] + PHOTO_STATS_FIELDS

class PhotoCollection(MagiCollection):
queryset = models.Photo.objects.all()
title = _('Photo')
plural_title = _('Photos')
icon = 'cards'
navbar_title = _('Photos')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should already be the same value as plural_title by default.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean navbar_title does not need to be set?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly :)

multipart = True
form_class = forms.PhotoForm

reportable = False
blockable = False
translated_fields = ('name', 'message_translation')

def to_fields(self, view, item, *args, **kwargs):
_photo_images = PHOTO_IMAGES.copy()
_photo_images.update({'color': '{static_url}img/color/{value}.png'.format(**{'value':item.color, 'static_url':RAW_CONTEXT['static_url']}),
'rarity': '{static_url}img/rarity/{value}.png'.format(**{'value':item.rarity, 'static_url':RAW_CONTEXT['static_url']})})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'{static_url}img... -> u'{static_url}img...

Othwerwise if the name of the image contains special characters it will crash.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you can use staticImageURL in magi.utils:

        _photo_images.update({
            'color': staticImageURL(item.color, folder='color', extension='png'),
            'rarity': staticImageURL(item.rarity, folder='rarity', extension='png'),
        })

fields = super(PhotoCollection, self).to_fields(view, item, *args, icons=PHOTO_ICONS, images=_photo_images, **kwargs)
return fields

class ItemView(MagiCollection.ItemView):
def to_fields(self, item, extra_fields=None, exclude_fields=None, order=None, *args, **kwargs):
if extra_fields is None: extra_fields = []
if exclude_fields is None: exclude_fields = []
if order is None: order = PHOTOS_ORDER
exclude_fields += PHOTOS_EXCLUDE
extra_fields.append(('skill', {
'verbose_name': _('Skill'),
'icon': item.skill_icon,
'type': 'text',
'value': item.skill,
}))
extra_fields.append(('sub_skill', {
'verbose_name': _('Sub skill'),
'type': 'text',
'value': item.sub_skill,
}))
# Add images fields
for image, verbose_name in [('image', _('Icon')), ('art', _('Poster')), ('transparent', _('Transparent')), ('full_photo', (_('Photo')))]:
if getattr(item, image):
extra_fields.append((u'{}s'.format(image), {
'verbose_name': verbose_name,
'type': 'images',
'images': [{
'value': image_url,
'verbose_name': verbose_name,
} for image_url in [
getattr(item, u'{}_url'.format(image)),
getattr(item, u'{}_special_shot_url'.format(image)),
] if image_url],
'icon': 'pictures',
}))
return super(PhotoCollection.ItemView, self).to_fields(item, *args, extra_fields=extra_fields, exclude_fields=exclude_fields, order=order, **kwargs)


############################################################
209 changes: 206 additions & 3 deletions majilove/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from collections import OrderedDict
from math import ceil
from django.utils.translation import ugettext_lazy as _, string_concat, get_language
from django.db import models
from django.conf import settings as django_settings
from magi.models import User, uploadItem
from magi.item_model import MagiModel, i_choices, getInfoFromChoices
from magi.abstract_models import BaseAccount
from magi.abstract_models import AccountAsOwnerModel, BaseAccount
from magi.utils import templateVariables


Expand Down Expand Up @@ -130,6 +131,7 @@ class Photo(MagiModel):

# The square icon
image = models.ImageField(_('Icon'), upload_to=uploadItem('photo'), null=True)

image_special_shot = models.ImageField(string_concat(_('Icon'), ' (', _('Special shot'), ')'), upload_to=uploadItem('photo/specialshot'), null=True)

# Full photo
Expand All @@ -148,7 +150,7 @@ class Photo(MagiModel):

message_text = models.TextField(string_concat(_('Message text'), ' (', _('Japanese') + ')'), max_length=500, null=True)
message_translation = models.TextField(_('Message translation'), max_length=500, null=True)
MESSAGE_TRANSLATIONs_CHOICES = ALL_ALT_LANGUAGES
MESSAGE_TRANSLATIONS_CHOICES = ALL_ALT_LANGUAGES
d_message_translations = models.TextField(_('Message translation'), null=True)
@property
def t_message_translation(self):
Expand Down Expand Up @@ -405,7 +407,6 @@ def japanese_skill(self):
skill_percentage = models.FloatField('{skill_percentage}', null=True)
skill_percentage_int = property(lambda _a: int(_a.skill_percentage))


# Subskills
SUB_SKILL_TYPES = OrderedDict([
('full_combo', {
Expand Down Expand Up @@ -492,3 +493,205 @@ def __unicode__(self):
name=self.t_name,
)
return u''

############################################################
# Collectible Photos

class CollectiblePhoto(AccountAsOwnerModel):
collection_name = 'collectiblephoto'

account = models.ForeignKey(Account, verbose_name=_('Account'), related_name='photoscollectors')
photo = models.ForeignKey(Photo, verbose_name=_('Photo'), related_name='collectedphotos')
level = models.PositiveIntegerField(_('Level'), default=1)
leader_bonus = models.PositiveIntegerField(_('Leader skill percentage'), null=True)
skill_level = models.PositiveIntegerField(_('Skill level'), default=1)

@property
def skill_percentage(self):
return self.photo.skill_percentage + (self.skill_level - 1) * self.photo.skill_increment
@property
def skill_note_count(self):
return self.photo.skill_note_count + (self.skill_level - 1) * self.photo.skill_increment

@property
def skill(self):
return self.photo.skill_template.format({
k: getattr(self, k)
for k in templateVariables(self.photo.skill_template)
})

sub_skill_level = models.PositiveIntegerField(_('Sub skill level'), null=True)
@property
def sub_skill_amount(self):
return self.photo.sub_skill_amount + (self.sub_skill_level - 1) * self.photo.sub_skill_increment

@property
def sub_skill(self):
_sub_skill_variables = {k: getattr(self.photo, k)
for k in templateVariables(self.photo.sub_skill_template
)}
_sub_skill_variables['sub_skill_amount'] = self.sub_skill_amount
return self.photo.sub_skill_template.format(**_sub_skill_variables)

rank = models.PositiveIntegerField(_('Rank'), default=1)

# TODO: moment based things are the same across, do I need an intermediate model for moment things?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean by that, can you tell me which models share the data?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't know what this means...


# percentage displayed on moments page for the card
moments_unlocked = models.PositiveIntegerField(_('Percent of moments unlocked'), default = 0)
# integer number of squares
bonus_moment_squares_unlocked = models.PositiveIntegerField(_('Number of moment squares unlocked past 100%'), default = 0)
@property
def special_shot_unlocked(self):
return self.moments_unlocked >= self.photo.special_shot_percentage

prefer_normal_shot = models.BooleanField(_('Prefer normal shot photo image'), default=False)

@property
def image(self):
return self.photo.image_special_shot if self.special_shot_unlocked and not self.prefer_normal_shot else self.photo.image

@property
def art(self):
return self.photo.art_special_shot if self.special_shot_unlocked and not self.prefer_normal_shot else self.photo.art
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may also need art_url, http_art_url, image_url and http_image_url in the future.


@property
def final_leader_skill_percentage(self):
if self.leader_bonus: return self.leader_bonus
if self.photo.rarity is 'UR' and self.bonus_moment_squares_unlocked is 16: return 70
_extra_squares = self.bonus_moment_squares_unlocked - 1
if self.photo.rarity is 'UR': _extra_squares = (self.bonus_moment_squares_unlocked // 4) - 1
if _extra_squares < 0: _extra_squares = 0
return self.photo.leader_skill_percentage + (_extra_squares * 3)

@property
def leader_skill(self):
_leader_skill_variables = {
k: getattr(self.photo, k)
for k in templateVariables(Photo.LEADER_SKILL_INFO['template'])
}
_leader_skill_variables['leader_skill_percentage'] = self.final_leader_skill_percentage
return Photo.LEADER_SKILL_INFO['template'].format(**_leader_skill_variables)

CROWN_OPTIONS = [150, 200]
CROWN_TYPES = [
'silver',
'gold',
'rainbow',
]
CROWN_TEMPLATE = '+{crown_amount} {crown_attribute}'
SILVER_CROWN_AMOUNT_CHOICES = CROWN_OPTIONS
i_silver_crown_amount = models.PositiveIntegerField(_('Silver crown bonus'), choices=i_choices(SILVER_CROWN_AMOUNT_CHOICES), null=True)
SILVER_CROWN_ATTRIBUTE_CHOICES = Photo.LEADER_SKILL_STAT_CHOICES
i_silver_crown_attribute = models.PositiveIntegerField(_('Silver crown attribute'), choices=i_choices(SILVER_CROWN_ATTRIBUTE_CHOICES), null=True)
@property
def silver_crown(self):
if self.silver_crown_attribute is None: return None
return CROWN_TEMPLATE.format(**{
k: getattr(self, 'silver_{}'.format(k))
for k in templateVariables(CROWN_TEMPLATE)
})

GOLD_CROWN_AMOUNT_CHOICES = CROWN_OPTIONS
i_gold_crown_amount = models.PositiveIntegerField(_('Gold crown bonus'), choices=i_choices(GOLD_CROWN_AMOUNT_CHOICES), null=True)
GOLD_CROWN_ATTRIBUTE_CHOICES = Photo.LEADER_SKILL_STAT_CHOICES
i_gold_crown_attribute = models.PositiveIntegerField(_('Gold crown attribute'), choices=i_choices(GOLD_CROWN_ATTRIBUTE_CHOICES), null=True)
@property
def gold_crown(self):
if self.gold_crown_attribute is None: return None
return CROWN_TEMPLATE.format(**{
k: getattr(self, 'gold_{}'.format(k))
for k in templateVariables(CROWN_TEMPLATE)
})

RAINBOW_CROWN_AMOUNT_CHOICES = CROWN_OPTIONS
i_rainbow_crown_amount = models.PositiveIntegerField(_('Rainbow crown bonus'), choices=i_choices(RAINBOW_CROWN_AMOUNT_CHOICES), null=True)
RAINBOW_CROWN_ATTRIBUTE_CHOICES = Photo.LEADER_SKILL_STAT_CHOICES
i_rainbow_crown_attribute = models.PositiveIntegerField(_('Rainbow crown attribute'), choices=i_choices(RAINBOW_CROWN_ATTRIBUTE_CHOICES), null=True)
@property
def rainbow_crown(self):
if self.rainbow_crown_attribute is None: return None
return CROWN_TEMPLATE.format(**{
k: getattr(self, 'rainbow_{}'.format(k))
for k in templateVariables(CROWN_TEMPLATE)
})

@property
def crown_dance_boost(self):
return sum([getattr(self, '{}_crown_amount'.format(v)) for v in CROWN_TYPES
if getattr(self, '{}_crown_attribute'.format(v)) is 'dance'])
@property
def crown_vocal_boost(self):
return sum([getattr(self, '{}_crown_amount'.format(v)) for v in CROWN_TYPES
if getattr(self, '{}_crown_attribute'.format(v)) is 'vocal'])
@property
def crown_charm_boost(self):
return sum([getattr(self, '{}_crown_amount'.format(v)) for v in CROWN_TYPES
if getattr(self, '{}_crown_attribute'.format(v)) is 'charm'])

custom_dance_stat = models.PositiveIntegerField(_('Dance'), null=True)
custom_vocal_stat = models.PositiveIntegerField(_('Vocal'), null=True)
custom_charm_stat = models.PositiveIntegerField(_('Charm'), null=True)

# pre moment stats
@property
def level_dance_stat(self):
if self.level == 1: return self.photo.dance_min
if self.level == self.photo.single_max_level: return self.photo.dance_single_copy_max
if self.level == self.photo.max_max_level: return self.photo.dance_max_copy_max
if self.level < self.photo.single_max_level:
return self.photo.dance_min + ((self.level - 1) * self.photo.dance_single_copy_increment)
return self.photo.dance_single_copy_max + ((self.level - self.photo.single_max_level) * self.photo.dance_combined_increment)
@property
def level_vocal_stat(self):
if self.level == 1: return self.photo.vocal_min
if self.level == self.photo.single_max_level: return self.photo.vocal_single_copy_max
if self.level == self.photo.max_max_level: return self.photo.vocal_max_copy_max
if self.level < self.photo.single_max_level:
return self.photo.vocal_min + ((self.level - 1) * self.photo.vocal_single_copy_increment)
return self.photo.vocal_single_copy_max + ((self.level - self.photo.single_max_level) * self.photo.vocal_combined_increment)
@property
def level_charm_stat(self):
if self.level == 1: return self.photo.charm_min
if self.level == self.photo.single_max_level: return self.photo.charm_single_copy_max
if self.level == self.photo.max_max_level: return self.photo.charm_max_copy_max
if self.level < self.photo.single_max_level:
return self.photo.charm_min + ((self.level - 1) * self.photo.charm_single_copy_increment)
return self.photo.charm_single_copy_max + ((self.level - self.photo.single_max_level) * self.photo.charm_combined_increment)

@property
def moment_squares_unlocked(self):
return ceil((self.moments_unlocked / 100) * self.photo.rarity_squares_in_moments) + (self.bonus_moment_squares_unlocked if self.photo.rarity is 'UR' else 0)

# squares go +30 dance->vocal->charm->big square
@property
def moment_dance_bonus(self):
return ceil(self.moment_squares_unlocked / 4) * 30
@property
def moment_vocal_bonus(self):
return ((self.moment_squares_unlocked // 4) + (1 if (self.moment_squares_unlocked % 4) >= 2 else 0)) * 30
@property
def moment_charm_bonus(self):
return ((self.moment_squares_unlocked // 4) + (1 if (self.moment_squares_unlocked % 4) >= 3 else 0)) * 30

@property
def display_dance(self):
if self.custom_dance_stat: self.custom_dance_stat
return self.level_dance_stat + self.moment_dance_bonus + self.crown_dance_boost
@property
def display_vocal(self):
if self.custom_vocal_stat: self.custom_vocal_stat
return self.level_vocal_stat + self.moment_vocal_bonus + self.crown_vocal_boost
@property
def display_charm(self):
if self.custom_charm_stat: self.custom_charm_stat
return self.level_charm_stat + self.moment_charm_bonus + self.crown_charm_boost

@property
def total_stats(self):
return self.display_dance + self.display_vocal + self.display_charm

def __unicode__(self):
if self.id:
return unicode(self.photo)
return super(CollectiblePhoto, self).__unicode__()
Binary file added majilove/static/img/color/dream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added majilove/static/img/color/shine.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added majilove/static/img/color/star.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified majilove/static/img/mic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added majilove/static/img/rarity/N.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added majilove/static/img/rarity/R.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added majilove/static/img/rarity/SR.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added majilove/static/img/rarity/UR.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.