fowl/fowl/game/models.py

357 lines
13 KiB
Python

from django.db import models
from django.contrib.auth.models import User
Q = models.Q
# these things are independent of the game
OUTCOMES = (('no contest', 'no contest'),
('normal', 'pinfall/normal'),
('dq', 'disqualification'),
('submission', 'submission'),
('appearance', 'appearance'),
('brawl', 'brawl'),
)
TITLES = (('wwe', 'WWE'),
('world', 'World Heavyweight'),
('ic', 'Intercontinental'),
('us', 'United States'),
('tag', 'Tag Team'),
('diva', 'Divas'),
)
TITLE_DICT = dict(TITLES)
class Star(models.Model):
id = models.CharField(max_length=100, primary_key=True)
name = models.CharField(max_length=200)
photo_url = models.URLField()
division = models.CharField(max_length=100)
@property
def active(self):
return self.division != 'other'
def win_title(self, title, date, tag_partner=None):
# if they have title on that date (or won it then), don't add anything
if (self.has_title(date) or
self.reigns.filter(title=title, begin_date=date).count()):
return
# end current title reigns
TitleReign.objects.filter(title=title).update(end_date=date)
self.reigns.create(title=title, begin_date=date)
if tag_partner:
if title != 'tag':
raise ValueError("can't have tag partner w/ non-tag belt")
tag_partner.reigns.create(title=title, begin_date=date)
def has_title(self, date=None):
if date:
current_title = list(self.reigns.filter(
Q(begin_date__lt=date) & (Q(end_date__gte=date) |
Q(end_date__isnull=True))))
else:
current_title = list(self.reigns.filter(end_date__isnull=True))
if len(current_title) < 1:
return None
elif len(current_title) == 1:
return current_title[0].title
else:
return 'multiple' # FIXME
def titled_name(self, date):
title = self.has_title(date)
name = self.name
if title:
name = '{0} ({1} Champion)'.format(name, TITLE_DICT[title])
return name
def __unicode__(self):
return self.name
class TitleReign(models.Model):
star = models.ForeignKey(Star, related_name='reigns')
title = models.CharField(max_length=20, choices=TITLES)
begin_date = models.DateField()
end_date = models.DateField(null=True)
def __unicode__(self):
return '{0} champion from {1}-{2}'.format(self.get_title_display(),
self.begin_date,
self.end_date or '')
class Event(models.Model):
name = models.CharField(max_length=100)
date = models.DateField()
def to_dict(self):
d = {'id': self.id, 'name': self.name, 'date': self.date,
'matches': [m.to_dict() for m in self.matches.all()]
}
return d
@staticmethod
def from_dict(d):
if d.get('id'):
event = Event.objects.get(pk=d['id'])
event.name = d['name']
event.date = d['date']
event.matches.all().delete()
else:
event = Event.objects.create(name=d['name'], date=d['date'])
for match in d['matches']:
event.add_match(*match['teams'],
winner=match['winner'],
outcome=match['outcome'],
title_at_stake=match['title_at_stake'],
notes=match['notes'])
return event
def add_match(self, *teams, **kwargs):
winner = kwargs.get('winner', None)
outcome = kwargs.get('outcome', 'no contest')
title_at_stake = kwargs.get('title_at_stake', None)
notes = kwargs.get('notes', '')
match = Match.objects.create(event=self,
title_at_stake=title_at_stake,
notes=notes)
for team in teams:
mt = MatchTeam.objects.create(match=match)
if not isinstance(team, (list, tuple)):
team = [team]
for member in team:
try:
member = Star.objects.get(pk=member)
except Star.DoesNotExist:
raise ValueError('invalid star pk {0}'.format(member))
if not mt.title and member.has_title(self.date):
# multiple titles?
mt.title = member.has_title(self.date)
mt.save()
mt.members.add(member)
if winner:
match.record_win(winner, outcome)
else:
match.outcome = outcome
match.save()
return match
def __unicode__(self):
return '{0} {1}'.format(self.name, self.date)
class Match(models.Model):
event = models.ForeignKey(Event, related_name='matches')
winner = models.ForeignKey(Star, null=True)
outcome = models.CharField(max_length=10, choices=OUTCOMES,
default='no contest')
title_at_stake = models.CharField(max_length=50, choices=TITLES, null=True)
notes = models.TextField(blank=True, default='')
def to_dict(self):
d = {'winner': self.winner_id,
'outcome': self.outcome,
'title_at_stake': self.title_at_stake,
'notes': self.notes}
d['teams'] = [[m.id for m in team.members.all()]
for team in self.teams.all()]
return d
def record_win(self, star, outcome):
team = self.teams.get(members__pk=star)
team.victorious = True
team.save()
self.winner_id = star
self.outcome = outcome
self.save()
def do_title_change(self):
if self.title_at_stake:
victors = list(self.teams.get(victorious=True).members.all())
if len(victors) == 1:
victors[0].win_title(self.title_at_stake, self.event.date)
elif len(victors) == 2 and self.title_at_stake == 'tag':
victors[0].win_title(self.title_at_stake, self.event.date,
victors[1])
else:
raise ValueError('invalid number of victors for title change')
def points(self):
points = {}
winners = None
losers = []
title_teams = {}
team_count = 0
for team in self.teams.all():
for star in team.members.all():
points[star.id] = 0
if self.outcome == 'appearance' and not star.active:
points[star.id] += 10
if self.outcome == 'brawl':
points[star.id] += 2
if team.title:
title_teams[team.title] = team
if team.victorious:
winners = team
else:
losers.append(team.members.count())
team_count += 1
# don't worry about winners of appearances or brawls
if self.outcome in ('appearance', 'brawl'):
return points
if winners:
winner_count = winners.members.count()
loser_count = sum(losers)
# figure out base points for winning
# DQ wins are worth 1 point no matter what
if self.outcome == 'dq':
base_points = 1
allies = 0 # allies don't matter in a DQ
# rumble is worth participants/2
elif team_count > 6:
base_points = team_count / 2
allies = 0 # no allies in a rumble
else:
# normal wins are worth 2
allies = winner_count - 1
base_points = max((loser_count - allies) * 2, 1)
# award points to winners
for w in winners.members.all():
points[w.id] = base_points
if self.title_at_stake:
if winners.title == self.title_at_stake:
# title defense
if winners.title in ('world', 'wwe'):
points[w.id] += 5
else:
points[w.id] += 3
elif self.outcome in ('normal', 'submission'):
# title win!
if self.title_at_stake in ('world', 'wwe'):
points[w.id] += 20
else:
points[w.id] += 10
else:
# defense by DQ
for star in title_teams[self.title_at_stake
].members.all():
points[star.id] += 1
else:
# look over titles in match, to score a title-nondefense
for title, title_team in title_teams.iteritems():
# beat someone w/ title in a non-defense
if winners.title != title:
# beat tag champs in tag match w/o tag belt on line
if title == 'tag' and all(c == 2 for c in losers):
points[w.id] += 2
# beat champ in non-handicap match w/o belt on line
elif all(c == 1 for c in losers):
points[w.id] += 2
# if multiple people in this match and this person was credited
# w/ win, give them the bonus points
if allies:
points[self.winner_id] += 1
if self.outcome == 'submission':
points[self.winner_id] += 1
return points
def fancy(self):
teams = [t.fancy(self.event.date) for t in
self.teams.all().order_by('-victorious')
.prefetch_related('members')]
if self.outcome in ('normal', 'dq', 'submission'):
ret = '{0} defeats {1}'.format(teams[0], ', '.join(teams[1:]))
ret += {'normal': '', 'dq': ' via disqualification',
'submission': ' via submission'}[self.outcome]
elif self.outcome == 'appearance':
ret = 'appearance by {0}'.format(', '.join(teams))
elif self.outcome == 'brawl':
ret = 'brawl between {0}'.format(', '.join(teams))
elif self.outcome == 'no contest':
ret = '{0} - fight to a no contest'.format(' vs. '.join(teams))
else:
print self.outcome
return ret
class MatchTeam(models.Model):
members = models.ManyToManyField(Star)
match = models.ForeignKey(Match, related_name='teams')
victorious = models.BooleanField(default=False)
title = models.CharField(max_length=50, choices=TITLES, null=True)
def fancy(self, date):
return ' & '.join([m.titled_name(date) for m in self.members.all()])
# fantasy stuff
class League(models.Model):
name = models.CharField(max_length=100)
active = models.BooleanField(default=True)
raw_picks = models.IntegerField(default=3)
smackdown_picks = models.IntegerField(default=3)
diva_picks = models.IntegerField(default=2)
wildcard_picks = models.IntegerField(default=1)
oldtimer_picks = models.IntegerField(default=2)
def score_event(self, event):
ppv_bonus = 1 if event.name.lower() not in ('raw', 'smackdown') else 0
TeamPoints.objects.filter(match__event=event).delete()
for match in event.matches.all():
for star, points in match.points().iteritems():
try:
team = self.teams.get(stars=star)
TeamPoints.objects.create(points=points + ppv_bonus,
team=team,
star_id=star,
match=match)
except Team.DoesNotExist:
pass
def __unicode__(self):
return self.name
class Team(models.Model):
name = models.CharField(max_length=100)
color = models.CharField(max_length=50)
login = models.ForeignKey(User, related_name='teams')
league = models.ForeignKey(League, related_name='teams')
stars = models.ManyToManyField(Star, related_name='teams')
def add_star(self, pk):
star = Star.objects.get(pk=pk)
if self.league.teams.filter(stars=star).count() >= 1:
raise ValueError('cannot add {0}, already drafted in {1}'.format(
star, self.league))
self.stars.add(star)
def drop_star(self, pk):
member = Star.objects.get(pk=pk)
self.stars.remove(member)
def __unicode__(self):
return self.name
class TeamPoints(models.Model):
points = models.IntegerField()
team = models.ForeignKey(Team, related_name='points')
star = models.ForeignKey(Star)
match = models.ForeignKey(Match)
def __unicode__(self):
return "{0} received {1} points for {2}'s performance in {3}".format(
self.team, self.points, self.star, self.match)