1
1
# -*- coding: utf-8 -*-
2
2
from collections import OrderedDict
3
+ from math import ceil
3
4
from django .utils .translation import ugettext_lazy as _ , string_concat , get_language
4
- from django .core .validators import MaxValueValidator , MinValueValidator
5
5
from django .db import models
6
6
from django .conf import settings as django_settings
7
7
from magi .models import User , uploadItem
8
8
from magi .item_model import MagiModel , i_choices , getInfoFromChoices
9
- from magi .abstract_models import BaseAccount
9
+ from magi .abstract_models import AccountAsOwnerModel , BaseAccount
10
10
from magi .utils import templateVariables
11
11
12
12
@@ -131,6 +131,7 @@ class Photo(MagiModel):
131
131
132
132
# The square icon
133
133
image = models .ImageField (_ ('Icon' ), upload_to = uploadItem ('photo' ), null = True )
134
+
134
135
image_special_shot = models .ImageField (string_concat (_ ('Icon' ), ' (' , _ ('Special shot' ), ')' ), upload_to = uploadItem ('photo/specialshot' ), null = True )
135
136
136
137
# Full photo
@@ -149,7 +150,7 @@ class Photo(MagiModel):
149
150
150
151
message_text = models .TextField (string_concat (_ ('Message text' ), ' (' , _ ('Japanese' ) + ')' ), max_length = 500 , null = True )
151
152
message_translation = models .TextField (_ ('Message translation' ), max_length = 500 , null = True )
152
- MESSAGE_TRANSLATIONs_CHOICES = ALL_ALT_LANGUAGES
153
+ MESSAGE_TRANSLATIONS_CHOICES = ALL_ALT_LANGUAGES
153
154
d_message_translations = models .TextField (_ ('Message translation' ), null = True )
154
155
@property
155
156
def t_message_translation (self ):
@@ -406,7 +407,6 @@ def japanese_skill(self):
406
407
skill_percentage = models .FloatField ('{skill_percentage}' , null = True )
407
408
skill_percentage_int = property (lambda _a : int (_a .skill_percentage ))
408
409
409
-
410
410
# Subskills
411
411
SUB_SKILL_TYPES = OrderedDict ([
412
412
('full_combo' , {
@@ -495,61 +495,204 @@ def __unicode__(self):
495
495
return u''
496
496
497
497
############################################################
498
- # Songs
498
+ # Collectible Photos
499
499
500
- class Song ( MagiModel ):
501
- collection_name = 'song '
500
+ class CollectiblePhoto ( AccountAsOwnerModel ):
501
+ collection_name = 'collectiblephoto '
502
502
503
- owner = models .ForeignKey (User , related_name = 'added_songs' )
503
+ account = models .ForeignKey (Account , verbose_name = _ ('Account' ), related_name = 'photoscollectors' )
504
+ photo = models .ForeignKey (Photo , verbose_name = _ ('Photo' ), related_name = 'collectedphotos' )
505
+ level = models .PositiveIntegerField (_ ('Level' ), default = 1 )
506
+ leader_bonus = models .PositiveIntegerField (_ ('Leader skill percentage' ), null = True )
507
+ skill_level = models .PositiveIntegerField (_ ('Skill level' ), default = 1 )
504
508
505
- name = models .CharField (string_concat (_ ('Title' ), ' (' , _ ('Translation' ), ')' ), max_length = 100 , null = True )
506
- japanese_name = models .CharField (_ ('Title' ), max_length = 100 , null = True )
507
- NAMES_CHOICES = ALL_ALT_LANGUAGES
508
- d_names = models .TextField (_ ('Title' ), null = True )
509
509
@property
510
- def t_name (self ):
511
- if get_language () == 'ja' : return self .japanese_name
512
- return self .names .get (get_language (), self .name )
510
+ def skill_percentage (self ):
511
+ return self .photo .skill_percentage + (self .skill_level - 1 ) * self .photo .skill_increment
512
+ @property
513
+ def skill_note_count (self ):
514
+ return self .photo .skill_note_count + (self .skill_level - 1 ) * self .photo .skill_increment
515
+
516
+ @property
517
+ def skill (self ):
518
+ return self .photo .skill_template .format ({
519
+ k : getattr (self , k )
520
+ for k in templateVariables (self .photo .skill_template )
521
+ })
513
522
514
- image = models .ImageField ('Album cover' , upload_to = uploadItem ('song' ), null = True )
523
+ sub_skill_level = models .PositiveIntegerField (_ ('Sub skill level' ), null = True )
524
+ @property
525
+ def sub_skill_amount (self ):
526
+ return self .photo .sub_skill_amount + (self .sub_skill_level - 1 ) * self .photo .sub_skill_increment
515
527
516
- composer = models .CharField (_ ('Composer' ), max_length = 100 , null = True )
517
- COMPOSERS_CHOICES = LANGUAGES_NEED_OWN_NAME
518
- d_composers = models .TextField (_ ('Composer' ), null = True )
519
- lyricist = models .CharField (_ ('Lyricist' ), max_length = 100 , null = True )
520
- LYRICISTS_CHOICES = LANGUAGES_NEED_OWN_NAME
521
- d_lyricists = models .TextField (_ ('Lyricist' ), null = True )
522
- arranger = models .CharField (_ ('Arranger' ), max_length = 100 , null = True )
523
- ARRANGERS_CHOICES = LANGUAGES_NEED_OWN_NAME
524
- d_arrangers = models .TextField (_ ('Arranger' ), null = True )
528
+ @property
529
+ def sub_skill (self ):
530
+ _sub_skill_variables = {k : getattr (self .photo , k )
531
+ for k in templateVariables (self .photo .sub_skill_template
532
+ )}
533
+ _sub_skill_variables ['sub_skill_amount' ] = self .sub_skill_amount
534
+ return self .photo .sub_skill_template .format (** _sub_skill_variables )
525
535
526
- singers = models .ManyToManyField ( Idol , related_name = "sung_songs" , verbose_name = _ ('Singers' ) )
536
+ rank = models .PositiveIntegerField ( _ ('Rank' ), default = 1 )
527
537
528
- COLOR_CHOICES = Photo .COLOR_CHOICES
529
- i_color = models .PositiveIntegerField (_ ('Color' ), choices = i_choices (COLOR_CHOICES ))
538
+ # TODO: moment based things are the same across, do I need an intermediate model for moment things?
530
539
531
- DIFFICULTY_VALIDATORS = [
532
- MinValueValidator (1 ),
533
- MaxValueValidator (13 ),
540
+ # percentage displayed on moments page for the card
541
+ moments_unlocked = models .PositiveIntegerField (_ ('Percent of moments unlocked' ), default = 0 )
542
+ # integer number of squares
543
+ bonus_moment_squares_unlocked = models .PositiveIntegerField (_ ('Number of moment squares unlocked past 100%' ), default = 0 )
544
+ @property
545
+ def special_shot_unlocked (self ):
546
+ return self .moments_unlocked >= self .photo .special_shot_percentage
547
+
548
+ prefer_normal_shot = models .BooleanField (_ ('Prefer normal shot photo image' ), default = False )
549
+
550
+ @property
551
+ def image (self ):
552
+ return self .photo .image_special_shot if self .special_shot_unlocked and not self .prefer_normal_shot else self .photo .image
553
+
554
+ @property
555
+ def art (self ):
556
+ return self .photo .art_special_shot if self .special_shot_unlocked and not self .prefer_normal_shot else self .photo .art
557
+
558
+ @property
559
+ def final_leader_skill_percentage (self ):
560
+ if self .leader_bonus : return self .leader_bonus
561
+ if self .photo .rarity is 'UR' and self .bonus_moment_squares_unlocked is 16 : return 70
562
+ _extra_squares = self .bonus_moment_squares_unlocked - 1
563
+ if self .photo .rarity is 'UR' : _extra_squares = (self .bonus_moment_squares_unlocked // 4 ) - 1
564
+ if _extra_squares < 0 : _extra_squares = 0
565
+ return self .photo .leader_skill_percentage + (_extra_squares * 3 )
566
+
567
+ @property
568
+ def leader_skill (self ):
569
+ _leader_skill_variables = {
570
+ k : getattr (self .photo , k )
571
+ for k in templateVariables (Photo .LEADER_SKILL_INFO ['template' ])
572
+ }
573
+ _leader_skill_variables ['leader_skill_percentage' ] = self .final_leader_skill_percentage
574
+ return Photo .LEADER_SKILL_INFO ['template' ].format (** _leader_skill_variables )
575
+
576
+ CROWN_OPTIONS = [150 , 200 ]
577
+ CROWN_TYPES = [
578
+ 'silver' ,
579
+ 'gold' ,
580
+ 'rainbow' ,
534
581
]
582
+ CROWN_TEMPLATE = '+{crown_amount} {crown_attribute}'
583
+ SILVER_CROWN_AMOUNT_CHOICES = CROWN_OPTIONS
584
+ i_silver_crown_amount = models .PositiveIntegerField (_ ('Silver crown bonus' ), choices = i_choices (SILVER_CROWN_AMOUNT_CHOICES ), null = True )
585
+ SILVER_CROWN_ATTRIBUTE_CHOICES = Photo .LEADER_SKILL_STAT_CHOICES
586
+ i_silver_crown_attribute = models .PositiveIntegerField (_ ('Silver crown attribute' ), choices = i_choices (SILVER_CROWN_ATTRIBUTE_CHOICES ), null = True )
587
+ @property
588
+ def silver_crown (self ):
589
+ if self .silver_crown_attribute is None : return None
590
+ return CROWN_TEMPLATE .format (** {
591
+ k : getattr (self , 'silver_{}' .format (k ))
592
+ for k in templateVariables (CROWN_TEMPLATE )
593
+ })
535
594
536
- easy_notes = models .PositiveIntegerField (string_concat (_ ('Easy' ), ' - ' , _ ('Notes' )), null = True )
537
- easy_difficulty = models .PositiveIntegerField (string_concat (_ ('Easy' ), ' - ' , _ ('Difficulty' )), validators = DIFFICULTY_VALIDATORS , null = True )
538
- normal_notes = models .PositiveIntegerField (string_concat (_ ('Normal' ), ' - ' , _ ('Notes' )), null = True )
539
- normal_difficulty = models .PositiveIntegerField (string_concat (_ ('Normal' ), ' - ' , _ ('Difficulty' )), validators = DIFFICULTY_VALIDATORS , null = True )
540
- hard_notes = models .PositiveIntegerField (string_concat (_ ('Hard' ), ' - ' , _ ('Notes' )), null = True )
541
- hard_difficulty = models .PositiveIntegerField (string_concat (_ ('Hard' ), ' - ' , _ ('Difficulty' )), validators = DIFFICULTY_VALIDATORS , null = True )
542
- pro_notes = models .PositiveIntegerField (string_concat (_ ('Pro' ), ' - ' , _ ('Notes' )), null = True )
543
- pro_difficulty = models .PositiveIntegerField (string_concat (_ ('Pro' ), ' - ' , _ ('Difficulty' )), validators = DIFFICULTY_VALIDATORS , null = True )
595
+ GOLD_CROWN_AMOUNT_CHOICES = CROWN_OPTIONS
596
+ i_gold_crown_amount = models .PositiveIntegerField (_ ('Gold crown bonus' ), choices = i_choices (GOLD_CROWN_AMOUNT_CHOICES ), null = True )
597
+ GOLD_CROWN_ATTRIBUTE_CHOICES = Photo .LEADER_SKILL_STAT_CHOICES
598
+ i_gold_crown_attribute = models .PositiveIntegerField (_ ('Gold crown attribute' ), choices = i_choices (GOLD_CROWN_ATTRIBUTE_CHOICES ), null = True )
599
+ @property
600
+ def gold_crown (self ):
601
+ if self .gold_crown_attribute is None : return None
602
+ return CROWN_TEMPLATE .format (** {
603
+ k : getattr (self , 'gold_{}' .format (k ))
604
+ for k in templateVariables (CROWN_TEMPLATE )
605
+ })
606
+
607
+ RAINBOW_CROWN_AMOUNT_CHOICES = CROWN_OPTIONS
608
+ i_rainbow_crown_amount = models .PositiveIntegerField (_ ('Rainbow crown bonus' ), choices = i_choices (RAINBOW_CROWN_AMOUNT_CHOICES ), null = True )
609
+ RAINBOW_CROWN_ATTRIBUTE_CHOICES = Photo .LEADER_SKILL_STAT_CHOICES
610
+ i_rainbow_crown_attribute = models .PositiveIntegerField (_ ('Rainbow crown attribute' ), choices = i_choices (RAINBOW_CROWN_ATTRIBUTE_CHOICES ), null = True )
611
+ @property
612
+ def rainbow_crown (self ):
613
+ if self .rainbow_crown_attribute is None : return None
614
+ return CROWN_TEMPLATE .format (** {
615
+ k : getattr (self , 'rainbow_{}' .format (k ))
616
+ for k in templateVariables (CROWN_TEMPLATE )
617
+ })
618
+
619
+ @property
620
+ def crown_dance_boost (self ):
621
+ return sum ([getattr (self , '{}_crown_amount' .format (v )) for v in CROWN_TYPES
622
+ if getattr (self , '{}_crown_attribute' .format (v )) is 'dance' ])
623
+ @property
624
+ def crown_vocal_boost (self ):
625
+ return sum ([getattr (self , '{}_crown_amount' .format (v )) for v in CROWN_TYPES
626
+ if getattr (self , '{}_crown_attribute' .format (v )) is 'vocal' ])
627
+ @property
628
+ def crown_charm_boost (self ):
629
+ return sum ([getattr (self , '{}_crown_amount' .format (v )) for v in CROWN_TYPES
630
+ if getattr (self , '{}_crown_attribute' .format (v )) is 'charm' ])
631
+
632
+ custom_dance_stat = models .PositiveIntegerField (_ ('Dance' ), null = True )
633
+ custom_vocal_stat = models .PositiveIntegerField (_ ('Vocal' ), null = True )
634
+ custom_charm_stat = models .PositiveIntegerField (_ ('Charm' ), null = True )
635
+
636
+ # pre moment stats
637
+ @property
638
+ def level_dance_stat (self ):
639
+ if self .level == 1 : return self .photo .dance_min
640
+ if self .level == self .photo .single_max_level : return self .photo .dance_single_copy_max
641
+ if self .level == self .photo .max_max_level : return self .photo .dance_max_copy_max
642
+ if self .level < self .photo .single_max_level :
643
+ return self .photo .dance_min + ((self .level - 1 ) * self .photo .dance_single_copy_increment )
644
+ return self .photo .dance_single_copy_max + ((self .level - self .photo .single_max_level ) * self .photo .dance_combined_increment )
645
+ @property
646
+ def level_vocal_stat (self ):
647
+ if self .level == 1 : return self .photo .vocal_min
648
+ if self .level == self .photo .single_max_level : return self .photo .vocal_single_copy_max
649
+ if self .level == self .photo .max_max_level : return self .photo .vocal_max_copy_max
650
+ if self .level < self .photo .single_max_level :
651
+ return self .photo .vocal_min + ((self .level - 1 ) * self .photo .vocal_single_copy_increment )
652
+ return self .photo .vocal_single_copy_max + ((self .level - self .photo .single_max_level ) * self .photo .vocal_combined_increment )
653
+ @property
654
+ def level_charm_stat (self ):
655
+ if self .level == 1 : return self .photo .charm_min
656
+ if self .level == self .photo .single_max_level : return self .photo .charm_single_copy_max
657
+ if self .level == self .photo .max_max_level : return self .photo .charm_max_copy_max
658
+ if self .level < self .photo .single_max_level :
659
+ return self .photo .charm_min + ((self .level - 1 ) * self .photo .charm_single_copy_increment )
660
+ return self .photo .charm_single_copy_max + ((self .level - self .photo .single_max_level ) * self .photo .charm_combined_increment )
544
661
545
- length = models .PositiveIntegerField (_ ('Length' ), null = True )
662
+ @property
663
+ def moment_squares_unlocked (self ):
664
+ 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 )
546
665
547
- # just going to have unlock method for regular permanent songs for now
548
- unlock_chapter = models .CharField (_ ('Unlock Chapter' ), max_length = 100 , null = True )
549
- UNLOCK_CHAPTERS_CHOICES = ALL_ALT_LANGUAGES
550
- d_unlock_chapters = models .TextField (_ ('Unlock Chapter' ), null = True )
666
+ # squares go +30 dance->vocal->charm->big square
667
+ @property
668
+ def moment_dance_bonus (self ):
669
+ return ceil (self .moment_squares_unlocked / 4 ) * 30
670
+ @property
671
+ def moment_vocal_bonus (self ):
672
+ return ((self .moment_squares_unlocked // 4 ) + (1 if (self .moment_squares_unlocked % 4 ) >= 2 else 0 )) * 30
673
+ @property
674
+ def moment_charm_bonus (self ):
675
+ return ((self .moment_squares_unlocked // 4 ) + (1 if (self .moment_squares_unlocked % 4 ) >= 3 else 0 )) * 30
551
676
552
- #TODO: other unlock methods
677
+ @property
678
+ def display_dance (self ):
679
+ if self .custom_dance_stat : self .custom_dance_stat
680
+ return self .level_dance_stat + self .moment_dance_bonus + self .crown_dance_boost
681
+ @property
682
+ def display_vocal (self ):
683
+ if self .custom_vocal_stat : self .custom_vocal_stat
684
+ return self .level_vocal_stat + self .moment_vocal_bonus + self .crown_vocal_boost
685
+ @property
686
+ def display_charm (self ):
687
+ if self .custom_charm_stat : self .custom_charm_stat
688
+ return self .level_charm_stat + self .moment_charm_bonus + self .crown_charm_boost
689
+
690
+ @property
691
+ def total_stats (self ):
692
+ return self .display_dance + self .display_vocal + self .display_charm
553
693
554
694
def __unicode__ (self ):
555
- return unicode (self .t_name )
695
+ if self .id :
696
+ return unicode (self .photo )
697
+ return super (CollectiblePhoto , self ).__unicode__ ()
698
+
0 commit comments