diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..d60efe4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,437 @@ +Attribution-NonCommercial-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/games.py b/games.py index 17567a2..2a684dc 100644 --- a/games.py +++ b/games.py @@ -590,8 +590,8 @@ class game(object): defense_team = self.teams["away"] if self.weather.name == "Slight Tailwind" and "mulligan" not in self.last_update[0].keys() and not result["ishit"] and result["text"] != appearance_outcomes.walk: - mulligan_roll_target = -((((self.get_batter().stlats["batting_stars"])-7)/7)**2)+1 - if random.random() > mulligan_roll_target: + mulligan_roll_target = -((((self.get_batter().stlats["batting_stars"])-5)/6)**2)+1 + if random.random() > mulligan_roll_target and self.get_batter().stlats["batting_stars"] >= 5: result["mulligan"] = True return (result, 0) diff --git a/leagues.py b/leagues.py index 0551d91..7d3eedc 100644 --- a/leagues.py +++ b/leagues.py @@ -103,9 +103,6 @@ class bracket(object): self.depth += 1 return self.dive(branch[0]), self.dive(branch[1]) - #def set_winners(self, branch, winners_list): - #new_bracket = - def set_winners_dive(self, winners_list, index = 0, branch = None, parent = None): if branch is None: branch = self.this_bracket.copy() diff --git a/main_controller.py b/main_controller.py index 739386d..9f410ee 100644 --- a/main_controller.py +++ b/main_controller.py @@ -32,9 +32,9 @@ def handle_new_conn(data): def update_loop(): while True: game_states = {} - game_times = iter(master_games_dic.copy().keys()) - for game_time in game_times: - this_game, state, discrim_string = master_games_dic[game_time] + game_ids = iter(master_games_dic.copy().keys()) + for game_id in game_ids: + this_game, state, discrim_string = master_games_dic[game_id] test_string = this_game.gamestate_display_full() state["leagueoruser"] = discrim_string state["display_inning"] = this_game.inning #games need to be initialized with the following keys in state: @@ -126,7 +126,7 @@ def update_loop(): state["top_of_inning"] = this_game.top_of_inning - game_states[game_time] = state + game_states[game_id] = state if state["update_pause"] <= 1 and state["start_delay"] < 0: if this_game.over: @@ -136,7 +136,7 @@ def update_loop(): master_games_dic.pop(game_time) else: state["end_delay"] -= 1 - master_games_dic[game_time][1]["end_delay"] -= 1 + master_games_dic[game_id][1]["end_delay"] -= 1 else: this_game.gamestate_update_full() @@ -146,12 +146,12 @@ def update_loop(): data_to_send = [] template = jinja2.Environment(loader=jinja2.FileSystemLoader('templates')).get_template('game_box.html') - for timestamp in game_states: + for id in game_states: data_to_send.append({ - 'timestamp' : timestamp, - 'league' : game_states[timestamp]['leagueoruser'] if game_states[timestamp]['is_league'] else '', - 'state' : game_states[timestamp], - 'html' : template.render(state=game_states[timestamp], timestamp=timestamp) + 'timestamp' : id, + 'league' : game_states[id]['leagueoruser'] if game_states[id]['is_league'] else '', + 'state' : game_states[id], + 'html' : template.render(state=game_states[id], timestamp=id) }) socketio.emit("states_update", data_to_send) diff --git a/static/css/game.css b/static/css/game.css index 2b0aa55..c60f230 100644 --- a/static/css/game.css +++ b/static/css/game.css @@ -8,7 +8,6 @@ .game { align-self: stretch; - justify-self: stretch; text-align: center; display: flex; flex-direction: column; @@ -20,6 +19,9 @@ border-right: none; border-bottom: none; height: min-content; + width: 100%; + min-width: 32rem; + max-width: 44rem; } .header { diff --git a/static/css/game_page.css b/static/css/game_page.css index e707284..69f0cc7 100644 --- a/static/css/game_page.css +++ b/static/css/game_page.css @@ -1,9 +1,7 @@ #game_container { - margin-top: 50px; + margin-top: 3rem; + margin-left: 1rem; + margin-right: 1rem; display: flex; justify-content: space-around; -} - -.game { - width: 33%; } \ No newline at end of file diff --git a/static/css/games_page.css b/static/css/games_page.css index 213fde7..d8d9e02 100644 --- a/static/css/games_page.css +++ b/static/css/games_page.css @@ -1,14 +1,14 @@ .container { display: grid; - grid-template-columns: repeat(3, minmax(500px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(32rem, 1fr)); grid-gap: 50px 30px; /*space between rows, then columns*/ - align-items: center; - justify-items: center; grid-auto-flow: row; } .emptyslot, .game { - min-height: 298px; + min-height: 18.75rem; + justify-self: center; + max-width: 44rem; } #filters { @@ -77,4 +77,4 @@ border: none; min-height: 0px; } -} \ No newline at end of file +} diff --git a/static/js/grid_loader.js b/static/js/grid_loader.js index abaca9a..39ba154 100644 --- a/static/js/grid_loader.js +++ b/static/js/grid_loader.js @@ -58,9 +58,7 @@ const updateGames = (json, filter) => { if (!Array.prototype.slice.call(grid.children).some(x => x.timestamp == game.timestamp)) { for (var slotnum = 0; true; slotnum++) { //this is really a while loop but shh don't tell anyone if (slotnum >= grid.children.length) { - for (var i = 0; i < 3; i ++) { - insertEmpty(grid); - } + insertEmpty(grid); } if (grid.children[slotnum].className == "emptyslot") { insertGame(slotnum, game); @@ -68,17 +66,9 @@ const updateGames = (json, filter) => { }; }; } - }; - //remove last rows if not needed - while (grid.children[grid.children.length-1].className == "emptyslot" && - grid.children[grid.children.length-2].className == "emptyslot" && - grid.children[grid.children.length-3].className == "emptyslot" && - grid.children.length > 3) { - for (var i = 0; i < 3; i++) { - grid.removeChild(grid.children[grid.children.length-1]); - } - } + fillgrid(grid) + }; } const insertEmpty = (grid) => { @@ -98,17 +88,42 @@ const insertGame = (gridboxnum, game) => { const insertLeague = (league) => { var btn = document.createElement("BUTTON"); btn.className = "filter"; - btn.innerHTML = league; + btn.innerHTML = escapeHtml(league); $('#filters').append(btn); return btn; } +function escapeHtml(unsafe) { + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + } + const clearBox = (box) => { box.className = "emptyslot"; box.timestamp = null; box.innerHTML = ""; } +const fillgrid = (grid) => { + var gridwidth = window.getComputedStyle(grid).getPropertyValue('grid-template-columns').split(" ").length //hack to get number of grid columns + + // add cells to fill last row + while (grid.children.length % gridwidth != 0) { + insertEmpty(grid) + } + + //remove last rows if not needed + while (grid.children.length > gridwidth && Array.prototype.slice.call(grid.children).slice(grid.children.length - gridwidth).every( x => x.className == 'emptyslot')) { + for (var i = 0; i < gridwidth; i++) { + grid.removeChild(grid.children[grid.children.length-1]); + } + } +} + const updateLeagues = (games) => { //get all leagues var leagues = [] @@ -165,4 +180,8 @@ window.onpopstate = function(e) { $('#filters .filter').each(function(i) { if (this.textContent == 'All') { this.id = 'selected_filter' }}) updateGames(lastupdate, "All"); } -} \ No newline at end of file +} + +window.addEventListener('resize', function(e) { + fillgrid(grid) +}) \ No newline at end of file diff --git a/templates/game_box.html b/templates/game_box.html index c4d1d1d..d94ac25 100644 --- a/templates/game_box.html +++ b/templates/game_box.html @@ -5,18 +5,18 @@ src={% if state.bases[number] %}"/static/img/base_filled.png" alt="{{state.bases {% if number <= state.outs %}/static/img/out_out.png{% else %}/static/img/out_in.png{% endif %} {%- endmacro %}
-
Inning: {% if state.display_top_of_inning == true %}🔼{% else %}🔽{% endif %} {{ state.display_inning }}/{{ state.max_innings }}
-
{{ state.title }}
-
{{ state.weather_emoji }} {{ state.weather_text }}
+
Inning: {% if state.display_top_of_inning == true %}🔼{% else %}🔽{% endif %} {{ state.display_inning | escape }}/{{ state.max_innings | escape }}
+
{{ state.title | escape }}
+
{{ state.weather_emoji | escape }} {{ state.weather_text | escape }}
-
{{ state.away_name }}
+
{{ state.away_name | escape }}
{{ state.away_score }}
-
{{ state.home_name }}
+
{{ state.home_name | escape }}
{{ state.home_score }}
@@ -38,16 +38,16 @@ src={% if state.bases[number] %}"/static/img/base_filled.png" alt="{{state.bases
PITCHER
-
{{ state.pitcher }}
+
{{ state.pitcher | escape }}
BATTER
-
{{ state.batter }}
+
{{ state.batter | escape }}
-
{{ state.update_emoji }}
-
{{ state.update_text }}
+
{{ state.update_emoji | escape }}
+
{{ state.update_text | escape }}
\ No newline at end of file diff --git a/the_prestige.py b/the_prestige.py index 20d0cd0..17da3af 100644 --- a/the_prestige.py +++ b/the_prestige.py @@ -2,6 +2,7 @@ import discord, json, math, os, roman, games, asyncio, random, main_controller, import database as db import onomancer as ono from flask import Flask +from uuid import uuid4 class Command: @@ -499,17 +500,52 @@ class StartTournamentCommand(Command): return to_parse = command.split("\n")[0] + if "--rounddelay " in to_parse: try: - round_delay = int(to_parse.split("--rounddelay ")[1].split(" ")[0]) + round_delay = int(to_parse.split("--rounddelay ")[1].split("-")[0].strip()) except ValueError: await msg.channel.send("The delay between rounds should be a whole number.") return if round_delay < 1 or round_delay > 120: - await msg.channel.send("The delay between rounds has to be between 1 and 120 minutes.") + await msg.channel.send("The delay between rounds has to bebetween 1 and 120 minutes.") + return else: round_delay = 10 + if "--bestof " in command.split("\n")[0]: + try: + series_length = int(to_parse.split("--bestof ")[1].split("-")[0].strip()) + if series_length % 2 == 0 or series_length < 0: + raise ValueError + except ValueError: + await msg.channel.send("Series length has to be an odd positive integer.") + return + if msg.author.id not in config()["owners"] and series_length > 21: + await msg.channel.send("That's too long, boss. We have to run patches *some* time.") + return + else: + series_length = 5 + + if "--finalsbestof " in command.split("\n")[0]: + try: + finals_series_length = int(to_parse.split("--finalsbestof ")[1].split("-")[0].strip()) + if finals_series_length % 2 == 0 or finals_series_length < 0: + raise ValueError + except ValueError: + await msg.channel.send("Finals series length has to be an odd positive integer.") + return + if msg.author.id not in config()["owners"] and finals_series_length > 21: + await msg.channel.send("That's too long, boss. We have to run patches *some* time.") + return + else: + finals_series_length = 7 + + rand_seed = not "--seeding stars" in command.split("\n")[0] + + + + tourney_name = command.split("\n")[1] list_of_team_names = command.split("\n")[2:] team_dic = {} @@ -529,8 +565,8 @@ class StartTournamentCommand(Command): id = random.randint(1111,9999) - tourney = leagues.tournament(tourney_name, team_dic, id=id, secs_between_rounds = round_delay * 60) - tourney.build_bracket(random_sort = True) + tourney = leagues.tournament(tourney_name, team_dic, series_length = series_length, finals_series_length = finals_series_length, id=id, secs_between_rounds = round_delay * 60) + tourney.build_bracket(random_sort = rand_seed) await start_tournament_round(channel, tourney) @@ -781,15 +817,15 @@ async def watch_game(channel, newgame, user = None, league = None): state_init["is_league"] = False - timestamp = str(time.time() * 1000.0) - ext = "?game="+timestamp + id = str(uuid4()) + ext = "?game="+id if league is not None: ext += "&league=" + urllib.parse.quote_plus(league) await channel.send(f"{newgame.teams['away'].name} vs. {newgame.teams['home'].name}, starting at {config()['simmadome_url']+ext}") - gamesarray.append((newgame, channel, user, timestamp)) + gamesarray.append((newgame, channel, user, id)) - main_controller.master_games_dic[timestamp] = (newgame, state_init, discrim_string) + main_controller.master_games_dic[id] = (newgame, state_init, discrim_string) def prepare_game(newgame, league = None, weather_name = None): if weather_name is None: @@ -836,12 +872,17 @@ async def start_tournament_round(channel, tourney, seeding = None): this_game, state_init = prepare_game(this_game) state_init["is_league"] = True - state_init["title"] = f"0 - 0" + + if tourney.round_check(): + series_string = f"Best of {tourney.finals_length}:" + else: + series_string = f"Best of {tourney.series_length}:" + state_init["title"] = f"{series_string} 0 - 0" discrim_string = tourney.name - timestamp = str(time.time() * 1000.0 + random.randint(0,3000)) - current_games.append((this_game, timestamp)) - main_controller.master_games_dic[timestamp] = (this_game, state_init, discrim_string) + id = str(uuid4()) + current_games.append((this_game, id)) + main_controller.master_games_dic[id] = (this_game, state_init, discrim_string) ext = "?league=" + urllib.parse.quote_plus(tourney.name) @@ -863,13 +904,18 @@ async def continue_tournament_series(tourney, queue, games_list, wins_in_series) state_init["is_league"] = True - state_init["title"] = f"{wins_in_series[oldgame.teams['away'].name]} - {wins_in_series[oldgame.teams['home'].name]}" + if tourney.round_check(): + series_string = f"Best of {tourney.finals_length}:" + else: + series_string = f"Best of {tourney.series_length}:" + + state_init["title"] = f"{series_string} {wins_in_series[oldgame.teams['away'].name]} - {wins_in_series[oldgame.teams['home'].name]}" discrim_string = tourney.name - timestamp = str(time.time() * 1000.0 + random.randint(0,3000)) - games_list.append((this_game, timestamp)) - main_controller.master_games_dic[timestamp] = (this_game, state_init, discrim_string) + id = str(uuid4()) + games_list.append((this_game, id)) + main_controller.master_games_dic[id] = (this_game, state_init, discrim_string) return games_list @@ -884,7 +930,7 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals try: for i in range(0, len(games_list)): game, key = games_list[i] - if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 9: + if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8: if game.teams['home'].name not in wins_in_series.keys(): wins_in_series[game.teams["home"].name] = 0 if game.teams['away'].name not in wins_in_series.keys(): @@ -1047,7 +1093,7 @@ def team_from_collection(newteam_json): raise CommandError("We've given you 100 characters for the slogan. Discord puts limits on us and thus, we put limits on you. C'est la vie.") if len(newteam_json["lineup"]) > 20: raise CommandError("20 players in the lineup, maximum. We're being really generous here.") - if not len(newteam_json["rotation"]) > 8: + if len(newteam_json["rotation"]) > 8: raise CommandError("8 pitchers on the rotation, max. That's a *lot* of pitchers.") for player in newteam_json["lineup"] + newteam_json["rotation"]: if len(player["name"]) > 70: @@ -1059,15 +1105,16 @@ def team_from_collection(newteam_json): newteam.slogan = newteam_json["slogan"] for player in newteam_json["lineup"]: newteam.add_lineup(games.player(json.dumps(player))) - newteam.set_pitcher(games.player(json.dumps(newteam_json["rotation"][0]))) + for player in newteam_json["rotation"]: + newteam.add_pitcher(games.player(json.dumps(player))) return newteam def team_from_message(command): newteam = games.team() roster = command.split("\n",1)[1].split("\n") - newteam.name = roster[0] #first line is team name - newteam.slogan = roster[1] #second line is slogan + newteam.name = roster[0].strip() #first line is team name + newteam.slogan = roster[1].strip() #second line is slogan if not roster[2].strip() == "": raise CommandError("The third line should be blank. It wasn't, so just in case, we've not done anything on our end.") pitchernum = len(roster)-2 @@ -1205,6 +1252,41 @@ async def history_pages(msg, all_games, search_term=None): await teams_list.edit(embed=pages[current_page]) except asyncio.TimeoutError: return +async def game_watcher(): + while True: + try: + this_array = gamesarray.copy() + for i in range(0,len(this_array)): + game, channel, user, key = this_array[i] + if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8: + final_embed = game_over_embed(game) + if isinstance(user, str): + await channel.send(f"A game started by {user} just ended.") + elif user is not None: + await channel.send(f"{user.mention}'s game just ended.") + else: + await channel.send("A game started from this channel just ended.") + await channel.send(embed=final_embed) + gamesarray.pop(i) + break + except: + print("something broke in game_watcher") + await asyncio.sleep(4) + +def game_over_embed(game): + title_string = f"{game.teams['away'].name} at {game.teams['home'].name} ended after {game.inning-1} innings" + if (game.inning - 1) > game.max_innings: #if extra innings + title_string += f" with {game.inning - (game.max_innings+1)} extra innings.\n" + else: + title_string += ".\n" + title_string += game.weather.emoji + game.weather.name + + winning_team = game.teams['home'].name if game.teams['home'].score > game.teams['away'].score else game.teams['away'].name + winstring = f"{game.teams['away'].score} to {game.teams['home'].score}\n" + if game.victory_lap and winning_team == game.teams['home'].name: + winstring += f"{winning_team} wins with a victory lap!" + elif winning_team == game.teams['home'].name: + winstring += f"{winning_team} wins, shaming {game.teams['away'].name}!" def get_team_fuzzy_search(team_name): team = games.get_team(team_name) if team is None: