Skip to content

Commit

Permalink
Track stronghold battles and use resources earned in payout
Browse files Browse the repository at this point in the history
Resources earned by players are determined from the replay file and stored
in the database. In the payout form the number of points to give for each resource
earned can be entered and is factored into the gold share calculation.

Feature request from #38
  • Loading branch information
ceari committed Nov 8, 2014
1 parent 64fec12 commit 2436be6
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 23 deletions.
24 changes: 24 additions & 0 deletions whyattend/alembic/versions/2413542ce715_stronghold_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Stronghold support
Revision ID: 2413542ce715
Revises: 398cf0b7b8c8
Create Date: 2014-11-08 18:03:01.861716
"""

# revision identifiers, used by Alembic.
revision = '2413542ce715'
down_revision = '398cf0b7b8c8'

from alembic import op
import sqlalchemy as sa


def upgrade():
op.add_column('battle', sa.Column('stronghold', sa.Boolean(), nullable=True))
op.add_column('player_battle', sa.Column('resources_earned', sa.Integer(), nullable=True))


def downgrade():
op.drop_column('player_battle', 'resources_earned')
op.drop_column('battle', 'stronghold')
3 changes: 3 additions & 0 deletions whyattend/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class BattleAttendance(Base):
player = relationship("Player", backref="battles")
battle = relationship("Battle", backref="attendances")
reserve = Column(Boolean)
resources_earned = Column(Integer)

def __init__(self, player, battle, reserve=False):
self.player = player
Expand Down Expand Up @@ -134,6 +135,8 @@ class Battle(Base):
replay_id = Column(Integer, ForeignKey('replay.id'))
replay = relationship("Replay", backref="battle", uselist=False, foreign_keys=[replay_id])

stronghold = Column(Boolean)

battle_group_id = Column(Integer, ForeignKey('battlegroup.id'))
battle_group = relationship("BattleGroup", backref="battles")
# Is this the "final battle" of the group? Exactly one per group should be true
Expand Down
37 changes: 28 additions & 9 deletions whyattend/replays.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,28 @@ def players_list(replay_json, team):


def player_won(replay_json):
own_team = replay_json['first']['vehicles'].values()[0]['team']
own_team = get_own_team(replay_json)
return replay_json['second'][0]['common']['winnerTeam'] == own_team


def get_own_team(replay_json):
player_name = replay_json['first']['playerName']
for v in replay_json['first']['vehicles'].itervalues():
if v['name'] == player_name:
return v['team']


def player_team(replay_json):
own_team = replay_json['first']['vehicles'].values()[0]['team']
""" Returns a list of names of the players on the replay recorder's team """
own_team = get_own_team(replay_json)
return [v['name'] for v in replay_json['first']['vehicles'].values() if v['team'] == own_team]


def is_stronghold(replay_json):
""" Returns whether the replay is from a stronghold battle """
return replay_json['first']['battleType'] == 10


def is_cw(replay_json):
"""
Returns whether the replay is probably from a clan war, i.e.
Expand All @@ -96,11 +109,11 @@ def is_cw(replay_json):
def guess_clan(replay_json):
""" Attempt to guess the friendly clan name from the replay.
Use is_cw(replay_json) before calling this to confirm it was a clan war.
:param replay_json:
:return:
"""
# first chunk should only contain the own team, so first player's clan is the friendly clan
return replay_json['first']['vehicles'].values()[0]['clanAbbrev']
player_name = replay_json['first']['playerName']
for v in replay_json['first']['vehicles'].itervalues():
if v['name'] == player_name:
return v['clanAbbrev']


def guess_enemy_clan(replay_json):
Expand All @@ -110,12 +123,12 @@ def guess_enemy_clan(replay_json):
:param replay_json:
:return:
"""
friendly_team = replay_json['first']['vehicles'].values()[0]['team']
return players_list(replay_json, 1 if friendly_team == 2 else 2)[0]['clanAbbrev']
own_team = get_own_team(replay_json)
return players_list(replay_json, 1 if own_team == 2 else 2)[0]['clanAbbrev']


def score(replay_json):
own_team = replay_json['first']['vehicles'].values()[0]['team']
own_team = get_own_team(replay_json)
own_team_deaths = 0
enemy_team_deaths = 0
for v in replay_json['second'][0]['vehicles'].itervalues():
Expand All @@ -127,6 +140,12 @@ def score(replay_json):
return enemy_team_deaths, own_team_deaths


def resources_earned(json_second, player_id):
for v in json_second[0]['vehicles'].itervalues():
if str(v["accountDBID"]) == str(player_id):
return v["fortResource"]


def player_performance(json_second, vehicles, players):
tank_info_by_player_name = {}
for k, v in json_second[1].iteritems():
Expand Down
8 changes: 8 additions & 0 deletions whyattend/templates/battles/create.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ <h2>Add battle</h2>
{% endif %}
<form class="form-horizontal" action="{{url_for('create_battle')}}" method="POST" role="form" enctype="multipart/form-data">

{% if stronghold %}
<p class="alert alert-info">The replay was determined to be from a stronghold battle.</p>
{% endif %}

<div class="form-group">
<label for="date" class="col-lg-2 control-label">Date &amp; Time</label>
<div class="col-lg-10">
Expand Down Expand Up @@ -107,6 +111,7 @@ <h2>Add battle</h2>
</div>
</div>

{% if not stronghold %}
<div class="form-group">
<label for="province" class="col-lg-2 control-label">Province(s)</label>
<div class="col-lg-10">
Expand All @@ -117,6 +122,7 @@ <h2>Add battle</h2>
</select>
</div>
</div>
{% endif %}

<div class="form-group">
<label for="battle_commander" class="col-lg-2 control-label">Battle commander</label>
Expand Down Expand Up @@ -151,6 +157,7 @@ <h2>Add battle</h2>
</div>
</div>

{% if not stronghold %}
<div class="form-group">
<label for="battle_commander" class="col-lg-2 control-label">Battle Group</label>
<div class="col-lg-10">
Expand All @@ -177,6 +184,7 @@ <h2>Add battle</h2>
</div>
</div>
</div>
{% endif %}

<div class="form-group">
<label for="description" class="col-lg-2 control-label">Description</label>
Expand Down
10 changes: 6 additions & 4 deletions whyattend/templates/payout/payout.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,21 @@
#fromDate { width: 150px; }
#toDate {width: 150px; }
#gold {width: 150px; }
#recruit_factor {width: 50px; }
#recruit_factor {width: 70px; }
#points_per_resource {width: 70px; }
form {margin-bottom: 20px; }
</style>
{% endblock %}
{% block content %}
<h2>Payout <img style="width:32px; height:32px;" src="{{url_for('static', filename='img/clanicons/' + clan + '.png')}}"> </h2>
<h4><a href="{{url_for('reserve_conflicts', clan=clan)}}">Show reserve player conflicts</a></h4>
<form class="form-inline" action="{{url_for('payout_battles', clan=clan)}}" method="GET">
From <input class="form-control" type="datetime" id="fromDate" name="fromDate" placeholder="dd.mm.yyyy">
<form class="form" action="{{url_for('payout_battles', clan=clan)}}" method="GET">
From <input class="form-control" type="datetime" id="fromDate" name="fromDate" placeholder="dd.mm.yyyy">
to <input class="form-control" type="datetime" id="toDate" name="toDate" placeholder="dd.mm.yyyy">
Victories only: <input type="checkbox" name="victories_only" id="victories_only">
Victories only: <input type="checkbox" name="victories_only" id="victories_only"><br/>
Gold: <input id="gold" class="form-control" type="text" name="gold" placeholder="amount of gold" value="0">
Gold/Point factor for recruits: <input id="recruit_factor" class="form-control" type="text" name="recruit_factor" placeholder="Factor for 'gold per point' for recruits" value="1.0">
Points per resource: <input id="points_per_resource" class="form-control" type="text" name="points_per_resource" placeholder="Points per resource" value="0.01">
<h4>Battles in the selected range:</h4>
<table class="table" id="battles">
<thead>
Expand Down
6 changes: 6 additions & 0 deletions whyattend/templates/payout/payout_battles.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
fnShowHide(6);
fnShowHide(7);
fnShowHide(8);
fnShowHide(9);
fnShowHide(10);
};
</script>
{% endblock %}
Expand Down Expand Up @@ -78,6 +80,8 @@ <h3>Summary of {{gold}} gold to pay out for {{battles|length}} battle{{'s' if ba
<th># battles drawn</th>
<th># battles lost</th>
<th># battles reserve</th>
<th>Resources</th>
<th>Points from resources</th>
<th>Points</th>
<th>Gold to pay</th>
</tr>
Expand All @@ -94,6 +98,8 @@ <h3>Summary of {{gold}} gold to pay out for {{battles|length}} battle{{'s' if ba
<td>{{player_draws[player]}}</td>
<td>{{player_defeats[player]}}</td>
<td>{{player_reserve[player]}}</td>
<td>{{player_resources[player]}}</td>
<td>{{(player_resources[player] * points_per_resource)|round(2)}}</td>
<td>{{player_points[player]}}</td>
<td>{{player_gold[player]}}</td>
</tr>
Expand Down
38 changes: 28 additions & 10 deletions whyattend/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,6 @@ def edit_battle(battle_id):
def create_battle():
"""
Create battle form.
:return:
"""
all_players = Player.query.filter_by(clan=g.player.clan, locked=False).order_by('lower(name)').all()
sorted_players = sorted(all_players, reverse=True, key=lambda p: p.player_role_value())
Expand All @@ -670,6 +669,7 @@ def create_battle():
map_name = ''
province = ''
duration = 15 * 60
stronghold = False
battle_commander = None
date = datetime.datetime.now()
battle_groups = BattleGroup.query.filter_by(clan=g.player.clan).order_by('date').all()
Expand Down Expand Up @@ -702,13 +702,14 @@ def create_battle():
if g.player in players:
battle_commander = g.player.id
date = datetime.datetime.strptime(replay['first']['dateTime'], '%d.%m.%Y %H:%M:%S')
stronghold = replays.is_stronghold(replay)

if not replay['second']:
flash(u'Error: Uploaded replay file is incomplete (Battle was left before it ended). ' +
u'Can not determine all information automatically.', 'error')
elif not replays.is_cw(replay):
elif not replays.is_cw(replay) and not replays.is_stronghold(replay):
flash(
u'Error: Uploaded replay file is probably not from a clan war '
u'Error: Uploaded replay file is probably not from a clan war or stronghold battle '
u'(Detected different clan tags in one of the team' +
u' or players from the same clan on both sides)', 'error')
else:
Expand All @@ -735,7 +736,7 @@ def create_battle():
battle_commander = Player.query.get(int(request.form['battle_commander']))
description = request.form.get('description', '')
duration = request.form.get('duration', 15 * 60)
battle_group = int(request.form['battle_group'])
battle_group = request.form.get('battle_group', -2)
battle_group_title = request.form.get('battle_group_title', '')
battle_group_description = request.form.get('battle_group_description', '')
battle_group_final = request.form.get('battle_group_final', '') == 'on'
Expand Down Expand Up @@ -806,6 +807,9 @@ def create_battle():
battle_commander=battle_commander, description=description,
duration=duration)

if replays.is_stronghold(replay):
battle.stronghold = True

if bg:
battle.battle_group_final = battle_group_final
battle.battle_group = bg
Expand All @@ -822,12 +826,13 @@ def create_battle():
else:
battle.score_own_team, battle.score_enemy_team = 0, 0


for player_id in players:
player = Player.query.get(player_id)
if not player:
abort(404)
ba = BattleAttendance(player, battle, reserve=False)
if battle.stronghold:
ba.resources_earned = replays.resources_earned(replay['second'], player.wot_id)
db_session.add(ba)

db_session.add(battle)
Expand All @@ -843,7 +848,7 @@ def create_battle():
battle_result=battle_result, date=date, battle_groups=battle_groups,
battle_group=battle_group, battle_group_title=battle_group_title, duration=duration,
battle_group_description=battle_group_description, battle_group_final=battle_group_final,
sorted_players=sorted_players, battle_group_id=battle_group_id)
sorted_players=sorted_players, battle_group_id=battle_group_id, stronghold=stronghold)


@app.route('/battles/list/<clan>')
Expand Down Expand Up @@ -957,7 +962,9 @@ def battles_list_json(clan):
battles = list(db_session.execute(battles.offset(offset).limit(limit)))

def make_row(battle):
if battle.battle_group_id:
if battle.stronghold:
type = "Stronghold"
elif battle.battle_group_id:
type = '<a href="' + url_for('battle_group_details', group_id=battle.battle_group_id) + '">'
if battle.battle_group_final:
type += 'Final'
Expand Down Expand Up @@ -1441,12 +1448,14 @@ def payout_battles(clan):
gold = int(request.form['gold'])
victories_only = request.form.get('victories_only', False)
recruit_factor = request.form['recruit_factor']
points_per_resource = float(request.form['points_per_resource'])
else:
from_date = request.args.get('fromDate')
to_date = request.args.get('toDate')
gold = int(request.args.get('gold'))
victories_only = request.args.get('victories_only', False) == 'on'
recruit_factor = float(request.args.get('recruit_factor'))
points_per_resource = float(request.args.get('points_per_resource'))

from_date = datetime.datetime.strptime(from_date, '%d.%m.%Y')
to_date = datetime.datetime.strptime(to_date, '%d.%m.%Y') + datetime.timedelta(days=1)
Expand All @@ -1467,6 +1476,8 @@ def payout_battles(clan):
player_victories = defaultdict(int)
player_defeats = defaultdict(int)
player_draws = defaultdict(int)
player_resources = defaultdict(int)

for battle in battles:
if battle.battle_group and not battle.battle_group_final:
continue # only finals count
Expand All @@ -1478,6 +1489,11 @@ def payout_battles(clan):
battle_players = battle.get_players()
battle_reserves = battle.get_reserve_players()

if battle.stronghold:
for ba in battle.attendances:
player_resources[ba.player] += ba.resources_earned
continue

battle_commander = battle.battle_commander
if not battle_commander.locked:
player_fced[battle_commander] += 1
Expand Down Expand Up @@ -1506,13 +1522,14 @@ def payout_battles(clan):

players = set()
for p in clan_members:
if player_played[p] or player_reserve[p] or player_fced[p]:
if player_played[p] or player_reserve[p] or player_fced[p] or player_resources[p]:
players.add(p)

player_points = dict()
for p in players:
player_points[p] = player_fced_win[p] * 6 + player_fced_defeat[p] * 4 + player_fced_draws[p] * 2 + \
player_victories[p] * 3 + player_defeats[p] * 2 + player_draws[p] * 2 + player_reserve[p]
player_victories[p] * 3 + player_defeats[p] * 2 + player_draws[p] * 2 + player_reserve[p] + \
player_resources[p] * points_per_resource

total_points = sum(player_points[p] for p in players)
recruit_points = sum(player_points[p] for p in players if p.is_recruit())
Expand All @@ -1531,7 +1548,8 @@ def payout_battles(clan):
player_gold=player_gold, gold=gold, player_defeats=player_defeats,
player_fced_win=player_fced_win, victories_only=victories_only, recruit_factor=recruit_factor,
player_fced_defeat=player_fced_defeat, player_victories=player_victories,
player_fced_draws=player_fced_draws, player_draws=player_draws, player_points=player_points)
player_fced_draws=player_fced_draws, player_draws=player_draws, player_points=player_points,
player_resources=player_resources, points_per_resource=points_per_resource)


@app.route('/players/json')
Expand Down

0 comments on commit 2436be6

Please sign in to comment.