|
|
@ -1,5 +1,5 @@ |
|
|
|
from flask import Flask, redirect, flash, session, g, request, get_flashed_messages, Markup |
|
|
|
from wtforms import Form, BooleanField, StringField, PasswordField, validators, SubmitField, IntegerField, DateTimeField, RadioField |
|
|
|
from wtforms import Form, BooleanField, StringField, PasswordField, validators, SubmitField, IntegerField, DateTimeField, RadioField, FloatField |
|
|
|
from wtforms.validators import ValidationError |
|
|
|
from flask_wtf import FlaskForm |
|
|
|
from flask_bootstrap import Bootstrap |
|
|
@ -45,12 +45,22 @@ class OccupyViewConfig(FlaskForm): |
|
|
|
refresh_meta = "Aktualizace pomocí HTML META" |
|
|
|
refresh_js = "Aktualizace pomocí java scriptu" |
|
|
|
|
|
|
|
font_size = IntegerField("Velikost fontu", default=8) |
|
|
|
clickable_down = "Podrobnosti na kliknutí pod mapou" |
|
|
|
clickable_right = "Podrobnosti na kliknutí vpravo vedle mapy" |
|
|
|
clickable_not = "Vypnout podrobnosti kliknutím (zmenší nároky na sít a procesor)" |
|
|
|
|
|
|
|
status_minimalistic = "Minimalistické metadata" |
|
|
|
status_up = "Matadata nahoře" |
|
|
|
status_left = "Metadata vlevo od mapy" |
|
|
|
|
|
|
|
font_size = FloatField("Velikost fontu", default=8.0) |
|
|
|
refresh = RadioField("Aktualizace", choices=(refresh_none, refresh_meta), default=refresh_none) |
|
|
|
not_clickable = BooleanField("Vypnout podrobnosti kliknutím (zmenší nároky na sít a procesor)") |
|
|
|
clickable = RadioField("", choices=(clickable_not, clickable_down, clickable_right), default=clickable_down) |
|
|
|
status = RadioField("", choices=(status_minimalistic, status_left, status_up), default=status_minimalistic) |
|
|
|
big_fields = BooleanField("Široká políčka (trojciferné počty)") |
|
|
|
|
|
|
|
submit = SubmitField("Refresh/Potvrdit") |
|
|
|
show_data_only = SubmitField("Zobrazit stránku pouze s daty") |
|
|
|
|
|
|
|
@add_wlogic |
|
|
|
class Occupy(WLogic): |
|
|
@ -58,59 +68,94 @@ class Occupy(WLogic): |
|
|
|
meta_refresh_without_reaming = 15 |
|
|
|
|
|
|
|
game = state.game |
|
|
|
team_id = team.team_id if team else None |
|
|
|
if game.step_mode == db.StepMode.automatic: |
|
|
|
time_reaming = (state.create_time - datetime.now()).total_seconds() + game.step_every_s |
|
|
|
else: |
|
|
|
time_reaming = None |
|
|
|
s = state.get_state() |
|
|
|
if team is not None: |
|
|
|
s = self.logic.personalize_state(s, team.team_id, state.round) |
|
|
|
conff = OccupyViewConfig(formdata=request.args, csrf_enabled=False) |
|
|
|
q = db.get_session().query(db.Log).order_by(db.Log.log_id.desc()) |
|
|
|
conff.validate() |
|
|
|
|
|
|
|
max_num = 999 if conff.big_fields.data else 99 |
|
|
|
|
|
|
|
b = BasePage() |
|
|
|
b.h2(f"Hra {self.game.print()} kolo {state.round}") |
|
|
|
if not conff.not_clickable.data: |
|
|
|
b.p("Po kliknutí na buňku se zobrazí další informace.") |
|
|
|
if conff.refresh.data == conff.refresh_meta and time_reaming is None: |
|
|
|
b.p(f"Není známo, kdy nastane další kolo, proto může být aktualizace až o {meta_refresh_without_reaming} sekund opožděna.") |
|
|
|
with b.p(): |
|
|
|
b.line().b(_class=f"game_team_{team.team_id}")(f"Pohled týmu {team.print()}") |
|
|
|
with b.line().b(_class="pull-right"): |
|
|
|
if time_reaming is not None: |
|
|
|
b("Čas do konce kola: ", b._span(id="time")(int(time_reaming)), " sekund") |
|
|
|
else: |
|
|
|
b("Konec kola není stanoven") |
|
|
|
with b.p(style="text-align:center;").table(_class="game_table"): |
|
|
|
for i, row in enumerate(s["world"]): |
|
|
|
with b.tr(): |
|
|
|
for j, x in enumerate(row): |
|
|
|
occupied_by_team = x["occupied_by_team"] |
|
|
|
home_for_team = x["home_for_team"] |
|
|
|
members = x["members"] |
|
|
|
with b.td(): |
|
|
|
classes = [] |
|
|
|
with b.a(href=f"#cell_{i}_{j}") if not conff.not_clickable.data else b.bucket(): |
|
|
|
if x["protected_for_team"] is not None: |
|
|
|
classes.append("game_protected") |
|
|
|
if x["hill"]: |
|
|
|
classes.append("game_hill") |
|
|
|
b(Markup(" ")) |
|
|
|
else: |
|
|
|
if home_for_team is not None: |
|
|
|
classes.append(f'game_home') |
|
|
|
if occupied_by_team is not None: |
|
|
|
classes.append(f'game_occupied') |
|
|
|
classes.append(f'game_occupied_by_{occupied_by_team}') |
|
|
|
num = len(members) |
|
|
|
if num: |
|
|
|
b(num if num <= max_num else ("+++" if conff.big_fields.data else "++")) |
|
|
|
else: |
|
|
|
def reaming_time(id="time"): |
|
|
|
if time_reaming is not None: |
|
|
|
b.b("Čas do konce kola: ", b._span(id=id)(int(time_reaming)), " sekund") |
|
|
|
b.script(Markup(f""" |
|
|
|
var intervalID = window.setInterval(update_time, 100); |
|
|
|
var t = { time_reaming*1000 }; |
|
|
|
function update_time() {{ |
|
|
|
document.getElementById("{id}").innerHTML = Math.floor(t/1000);; |
|
|
|
t -= 100; |
|
|
|
}} |
|
|
|
""")) |
|
|
|
else: |
|
|
|
b("Konec kola není stanoven") |
|
|
|
|
|
|
|
def status(): |
|
|
|
members_counts = [0 for _ in teams] |
|
|
|
occupied_counts = [0 for _ in teams] |
|
|
|
|
|
|
|
for x in s["world"]: |
|
|
|
for y in x: |
|
|
|
occupied_by_team = y["occupied_by_team"] |
|
|
|
members = y["members"] |
|
|
|
if occupied_by_team is not None: |
|
|
|
occupied_counts[occupied_by_team] += 1 |
|
|
|
members_counts[occupied_by_team] += len(members) |
|
|
|
|
|
|
|
|
|
|
|
with b.div(_class="game_left_status button form-frame"): |
|
|
|
b.b("Kolo ", state.round) |
|
|
|
with b.p(): |
|
|
|
reaming_time(id="time_left") |
|
|
|
with b.p(): |
|
|
|
for t, occupied_count, members_count in zip(teams, occupied_counts, members_counts): |
|
|
|
with b.line().span(_class=f"game_team_{t.team_id}"): |
|
|
|
b.b("Tým ", t.print()) |
|
|
|
b.br() |
|
|
|
b("Bodů: ", t.get_move(state.round).points) |
|
|
|
b.br() |
|
|
|
b("Políček: ", occupied_count) |
|
|
|
b.br() |
|
|
|
b("Vojáků: ", members_count) |
|
|
|
b.br() |
|
|
|
|
|
|
|
|
|
|
|
def table(): |
|
|
|
with b.table(_class="game_table"): |
|
|
|
for i, row in enumerate(s["world"]): |
|
|
|
with b.tr(): |
|
|
|
for j, x in enumerate(row): |
|
|
|
occupied_by_team = x["occupied_by_team"] |
|
|
|
home_for_team = x["home_for_team"] |
|
|
|
members = x["members"] |
|
|
|
with b.td(): |
|
|
|
classes = [] |
|
|
|
with b.a(href=f"#cell_{i}_{j}") if conff.clickable.data != conff.clickable_not else b.bucket(): |
|
|
|
if x["protected_for_team"] is not None: |
|
|
|
classes.append("game_protected") |
|
|
|
if x["hill"]: |
|
|
|
classes.append("game_hill") |
|
|
|
b(Markup(" ")) |
|
|
|
b(_class=" ".join(classes)) |
|
|
|
else: |
|
|
|
if home_for_team is not None: |
|
|
|
classes.append(f'game_home') |
|
|
|
if occupied_by_team is not None: |
|
|
|
classes.append(f'game_occupied') |
|
|
|
classes.append(f'game_occupied_by_{occupied_by_team}') |
|
|
|
num = len(members) |
|
|
|
if num: |
|
|
|
b(num if num <= max_num else ("+++" if conff.big_fields.data else "++")) |
|
|
|
else: |
|
|
|
b(Markup(" ")) |
|
|
|
b(_class=" ".join(classes)) |
|
|
|
|
|
|
|
if not conff.not_clickable.data: |
|
|
|
def clickable(): |
|
|
|
for i, row in enumerate(s["world"]): |
|
|
|
for j, x in enumerate(row): |
|
|
|
occupied_by_team = x["occupied_by_team"] |
|
|
@ -131,34 +176,60 @@ class Occupy(WLogic): |
|
|
|
b.p().b(f"Počet osob: {len(members)}") |
|
|
|
with b.ul(): |
|
|
|
for m in members: |
|
|
|
b.li(_class=f"game_team_{home_for_team}")(f"Voják {m['id']} týmu {teams[m['team']].print()}") |
|
|
|
b.li(_class=f"game_team_{m['team']}")(f"Voják {m['id']} týmu {teams[m['team']].print()}") |
|
|
|
|
|
|
|
b = BasePage() |
|
|
|
if not conff.show_data_only.data: |
|
|
|
b.h2(f"Hra {self.game.print()} kolo {state.round}") |
|
|
|
if conff.clickable.data != conff.clickable_not: |
|
|
|
b.p("Po kliknutí na buňku se zobrazí další informace.") |
|
|
|
if conff.refresh.data == conff.refresh_meta and time_reaming is None: |
|
|
|
b.p(f"Není známo, kdy nastane další kolo, proto může být aktualizace až o {meta_refresh_without_reaming} sekund opožděna.") |
|
|
|
with b.p(): |
|
|
|
if team is not None: |
|
|
|
b.line().b(_class=f"game_team_{team.team_id}")(f"Pohled týmu {team.print()}") |
|
|
|
with b.line().b(_class="pull-right"): |
|
|
|
reaming_time() |
|
|
|
b.div(style="clear: both; margin-bottom: 1ex")("") |
|
|
|
with b.div().div(style="text-align:center;", id="game_main"): |
|
|
|
if conff.status.data == conff.status_left: |
|
|
|
status() |
|
|
|
table() |
|
|
|
if conff.clickable.data == conff.clickable_right: |
|
|
|
clickable() |
|
|
|
b.div(style="clear: both; margin-bottom: 1ex")("") |
|
|
|
|
|
|
|
if conff.clickable.data == conff.clickable_down: |
|
|
|
clickable() |
|
|
|
|
|
|
|
del conff.csrf_token |
|
|
|
b.p() |
|
|
|
b.div(_class="form-frame")(jinja_mac.quick_form(conff, form_type="horizontal", method="GET")) |
|
|
|
|
|
|
|
b.script(Markup(f""" |
|
|
|
var intervalID = window.setInterval(update_time, 100); |
|
|
|
var t = { time_reaming*1000 }; |
|
|
|
function update_time() {{ |
|
|
|
document.getElementById("time").innerHTML = Math.floor(t/1000);; |
|
|
|
t -= 100; |
|
|
|
}} |
|
|
|
""")) |
|
|
|
if not conff.show_data_only.data: |
|
|
|
b.div(_class="form-frame")(jinja_mac.quick_form(conff, form_type="horizontal", method="GET")) |
|
|
|
|
|
|
|
def head(x): |
|
|
|
style = "" |
|
|
|
page_w = float("inf") if conff.show_data_only.data else 1000 |
|
|
|
refresh_time = time_reaming + 1 if time_reaming is not None else 15 |
|
|
|
font_size = int(conff.font_size.data) |
|
|
|
box_size = int(font_size * 1.3 + 1) |
|
|
|
font_size = float(conff.font_size.data or 8.0) |
|
|
|
box_size = int(font_size * 1.5 + 1) |
|
|
|
left_w = 0 |
|
|
|
if conff.status.data == conff.status_left: |
|
|
|
left_w = 150 |
|
|
|
box_w = box_size |
|
|
|
if conff.big_fields.data: |
|
|
|
box_w *= 1.5 |
|
|
|
table_w = len(s["world"][0]) * box_w |
|
|
|
margin_cmd = "" |
|
|
|
if table_w > 1000: |
|
|
|
margin_cmd = f"margin-left: {(1000-table_w) / 2}px;" |
|
|
|
main_w = table_w + left_w |
|
|
|
if conff.clickable.data == conff.clickable_right: |
|
|
|
right_w = 400 |
|
|
|
main_w += right_w |
|
|
|
style += f".game_tab {{\n width: {right_w}px\n}}\n" |
|
|
|
if main_w > page_w: |
|
|
|
margin_cmd = f"margin-left: {(page_w-main_w) / 2}px;" |
|
|
|
if conff.refresh.data == conff.refresh_meta: |
|
|
|
b.meta(**{"HTTP-EQUIV": "refresh", "CONTENT": f"{refresh_time};{app.url_for(web_game_view.__name__, game_id=game.game_id, team_id=team.team_id, **request.args)}"}) |
|
|
|
b.meta(**{"HTTP-EQUIV": "refresh", "CONTENT": f"{refresh_time};{app.url_for(web_game_view.__name__, game_id=game.game_id, team_id=team_id, **request.args)}"}) |
|
|
|
b.link(rel="stylesheet", href=app.url_for('static', filename='occupy.css'), type='text/css', media="all") |
|
|
|
b.style(Markup(f""" |
|
|
|
table.game_table tr td {{ |
|
|
@ -169,8 +240,15 @@ class Occupy(WLogic): |
|
|
|
}} |
|
|
|
table.game_table {{ |
|
|
|
width: {table_w}px; |
|
|
|
}} |
|
|
|
#game_main {{ |
|
|
|
{margin_cmd} |
|
|
|
width: {main_w}px; |
|
|
|
}} |
|
|
|
.game_left_status {{ |
|
|
|
width: {left_w-20}px; |
|
|
|
}} |
|
|
|
{style} |
|
|
|
""")) |
|
|
|
|
|
|
|
|
|
|
@ -178,5 +256,6 @@ class Occupy(WLogic): |
|
|
|
limited_size=False, |
|
|
|
sticky_head=False, |
|
|
|
head=head, |
|
|
|
empty=conff.show_data_only.data |
|
|
|
) |
|
|
|
return b.print_file() |
|
|
|