ba_data update

This commit is contained in:
Ayush Saini 2024-01-27 21:25:16 +05:30
parent 2174ae566d
commit 7ba24ecbcf
146 changed files with 1756 additions and 347 deletions

View file

@ -9,7 +9,7 @@
"Danish": "Dansk", "Danish": "Dansk",
"Dutch": "Nederlands", "Dutch": "Nederlands",
"Esperanto": "Esperanto", "Esperanto": "Esperanto",
"Filipino": "Tagalog ", "Filipino": "Wikang Tagalog ",
"French": "Français", "French": "Français",
"German": "Deutsch", "German": "Deutsch",
"Gibberish": "Abuktarika", "Gibberish": "Abuktarika",
@ -44,10 +44,12 @@
"\"9۝ÅЇρѺ۝ƬǀGΞЯ", "\"9۝ÅЇρѺ۝ƬǀGΞЯ",
"\"Unknown\"", "\"Unknown\"",
"/in/dev/", "/in/dev/",
"0Globalsters",
"1.4.139", "1.4.139",
"11", "11",
"123", "123",
"123123123", "123123123",
"1234abcdS",
"1Platinumpatty", "1Platinumpatty",
"1SpaZ", "1SpaZ",
"228варенье", "228варенье",
@ -148,12 +150,14 @@
"Shadiq Ali", "Shadiq Ali",
"alireza", "alireza",
"alirezaalidokht", "alirezaalidokht",
"AliSh8787",
"ALISSON", "ALISSON",
"Virgile Allard", "Virgile Allard",
"Allinol", "Allinol",
"ahmed alomari", "ahmed alomari",
"Alonso", "Alonso",
"Alp", "Alp",
"Alpcik910",
"Alper", "Alper",
"Alpha", "Alpha",
"AlphaT", "AlphaT",
@ -250,6 +254,7 @@
"awase2020@gmail.com", "awase2020@gmail.com",
"sev alaslam Awd", "sev alaslam Awd",
"Axel", "Axel",
"Aynursargi",
"ayub", "ayub",
"masoud azad(fireboy)", "masoud azad(fireboy)",
"Md azar", "Md azar",
@ -260,6 +265,7 @@
"Myth B.", "Myth B.",
"B4likeBefore", "B4likeBefore",
"Praveen Babu", "Praveen Babu",
"Badmoss",
"Baechu", "Baechu",
"Balage8", "Balage8",
"BalaguerM", "BalaguerM",
@ -326,6 +332,7 @@
"Daniel Block", "Daniel Block",
"BlueBlur", "BlueBlur",
"bob bobber", "bob bobber",
"Bombay De Bom",
"BomBillo", "BomBillo",
"The Bomboler 💣", "The Bomboler 💣",
"bombsquad", "bombsquad",
@ -346,6 +353,7 @@
"bouabdellah", "bouabdellah",
"Antoine Boulanger", "Antoine Boulanger",
"Thomas Bouwmeester", "Thomas Bouwmeester",
"Boxan",
"Ali x boy", "Ali x boy",
"boyhero7779", "boyhero7779",
"Bořivoj", "Bořivoj",
@ -473,6 +481,7 @@
"Die or Dead", "Die or Dead",
"Привет от детей DeadLine", "Привет от детей DeadLine",
"deepjith", "deepjith",
"DEFENDER",
"Defiant", "Defiant",
"dekarl", "dekarl",
"deliciouspudding43", "deliciouspudding43",
@ -554,6 +563,7 @@
"Emanuel_12", "Emanuel_12",
"Emil", "Emil",
"Kürti Emil", "Kürti Emil",
"55Hamza Emin",
"Muhammed emir", "Muhammed emir",
"Muhammet Emir", "Muhammet Emir",
"EmirSametEr", "EmirSametEr",
@ -825,6 +835,7 @@
"Jacek", "Jacek",
"Jack556", "Jack556",
"Jhon Jairo", "Jhon Jairo",
"jakecato1602@gmail.com",
"wahid jamaludin", "wahid jamaludin",
"Tarun Jangra", "Tarun Jangra",
"Aleksandar Janic", "Aleksandar Janic",
@ -864,6 +875,7 @@
"joke", "joke",
"Jonatas", "Jonatas",
"Jop", "Jop",
"Jor",
"JoseANG3L", "JoseANG3L",
"Joseetion", "Joseetion",
"Joseph", "Joseph",
@ -1025,6 +1037,7 @@
"Loex", "Loex",
"Loko", "Loko",
"Longkencok", "Longkencok",
"longmouses",
"杰瑞 longmouses", "杰瑞 longmouses",
"looooooooou", "looooooooou",
"LordHiohi", "LordHiohi",
@ -1083,6 +1096,8 @@
"Wagdy mamdouh", "Wagdy mamdouh",
"Mani", "Mani",
"Manimutharu", "Manimutharu",
"Manmath",
"ManmathTheGreat",
"Ahmed Mansy", "Ahmed Mansy",
"Manu", "Manu",
"Mapk58", "Mapk58",
@ -1188,6 +1203,7 @@
"mr", "mr",
"mr.Dark", "mr.Dark",
"Mr.Smoothy", "Mr.Smoothy",
"MR0000000001",
"MrDaniel715", "MrDaniel715",
"MrGlu10free", "MrGlu10free",
"Mrmaxmeier", "Mrmaxmeier",
@ -1503,6 +1519,7 @@
"Guilherme Santana", "Guilherme Santana",
"Santiago", "Santiago",
"Ivan Santos :)", "Ivan Santos :)",
"santosamerica880@gmail.com",
"Diamond Sanwich", "Diamond Sanwich",
"SAO_OMH", "SAO_OMH",
"Dimas Saptandi", "Dimas Saptandi",
@ -1654,6 +1671,7 @@
"Tiberiu", "Tiberiu",
"Cristian Ticu", "Cristian Ticu",
"Robert Tieber", "Robert Tieber",
"TieDan",
"TIGEE", "TIGEE",
"Tim", "Tim",
"Tingis2", "Tingis2",
@ -1679,6 +1697,7 @@
"Konstantin Tsvetkov", "Konstantin Tsvetkov",
"Kontantin Tsvetkov", "Kontantin Tsvetkov",
"Tudikk", "Tudikk",
"Romioza TV",
"Jan Tymll", "Jan Tymll",
"Zacker Tz", "Zacker Tz",
"Zoltán Tóth", "Zoltán Tóth",
@ -1730,6 +1749,7 @@
"Vaibhav Wakchaure", "Vaibhav Wakchaure",
"Simon Wang", "Simon Wang",
"Will Wang", "Will Wang",
"WeanCZ",
"Tilman Weber", "Tilman Weber",
"webparham", "webparham",
"Wesley", "Wesley",
@ -1795,6 +1815,7 @@
"Z@p€g@m€r", "Z@p€g@m€r",
"Zac", "Zac",
"Dawn Zac", "Dawn Zac",
"zahra",
"Zaidan64GT", "Zaidan64GT",
"Zain", "Zain",
"Zajle", "Zajle",
@ -1804,6 +1825,7 @@
"ZaraMax", "ZaraMax",
"zecharaiah", "zecharaiah",
"Daniele Zennaro", "Daniele Zennaro",
"Zenotaiko",
"zFliws", "zFliws",
"zfuw668", "zfuw668",
"Alex Zhao", "Alex Zhao",
@ -1819,6 +1841,7 @@
"Lukáš Zounek", "Lukáš Zounek",
"ZOUZ", "ZOUZ",
"ZpeedTube", "ZpeedTube",
"Zwizard",
"|_Jenqa_|", "|_Jenqa_|",
"¥¥S.A.N.A¥", "¥¥S.A.N.A¥",
"Danijel Ćelić", "Danijel Ćelić",
@ -1913,6 +1936,7 @@
"علی", "علی",
"سيد عمر", "سيد عمر",
"عيسى", "عيسى",
"مجتبی",
"اللهم صل على محمد وآل محمد", "اللهم صل على محمد وآل محمد",
"امیر محمد", "امیر محمد",
"هادی مرادی", "هادی مرادی",

View file

@ -336,6 +336,8 @@
"getMoreGamesText": "الحصول على المزيد من الألعاب", "getMoreGamesText": "الحصول على المزيد من الألعاب",
"titleText": "إضافة لعبة" "titleText": "إضافة لعبة"
}, },
"addToFavoritesText": "الإضافة إلى المفضلات",
"addedToFavoritesText": ".إلى المفضلات '${NAME}' تمت إضافة",
"allText": "جميع", "allText": "جميع",
"allowText": "السماح", "allowText": "السماح",
"alreadySignedInText": "تم تسجيل الدخول من حسابك من جهاز آخر.\n يرجى تبديل الحسابات أو إغلاق اللعبة على الأجهزة الأخرى\n وحاول مرة أخرى.", "alreadySignedInText": "تم تسجيل الدخول من حسابك من جهاز آخر.\n يرجى تبديل الحسابات أو إغلاق اللعبة على الأجهزة الأخرى\n وحاول مرة أخرى.",
@ -565,6 +567,8 @@
"disableXInputDescriptionText": "يسمح أكثر من 4 وحدات تحكم ولكن قد لا تعمل كذلك.", "disableXInputDescriptionText": "يسمح أكثر من 4 وحدات تحكم ولكن قد لا تعمل كذلك.",
"disableXInputText": "xinput تعطيل", "disableXInputText": "xinput تعطيل",
"disabledText": "معطل", "disabledText": "معطل",
"discordFriendsText": "تريد المزيد من الناس للعب معهم؟\n!إنضم إلى سيرفر الديسكورد و أوجد اصدقاء جدد",
"discordJoinText": "إنضم إلى الديسكورد",
"doneText": "تم", "doneText": "تم",
"drawText": "تعادل", "drawText": "تعادل",
"duplicateText": "مكرر", "duplicateText": "مكرر",
@ -750,6 +754,7 @@
"manualYourLocalAddressText": "عنوانك المباشر", "manualYourLocalAddressText": "عنوانك المباشر",
"nearbyText": "الأقرب", "nearbyText": "الأقرب",
"noConnectionText": "<لا يوجد اتصال>", "noConnectionText": "<لا يوجد اتصال>",
"noPartiesAddedText": "لا مجموعات مضافة",
"otherVersionsText": "(اصدارات اخرى)", "otherVersionsText": "(اصدارات اخرى)",
"partyCodeText": "رمز السيرفر", "partyCodeText": "رمز السيرفر",
"partyInviteAcceptText": "قبول", "partyInviteAcceptText": "قبول",
@ -1064,6 +1069,7 @@
"noContinuesText": "(لا يستمر)", "noContinuesText": "(لا يستمر)",
"noExternalStorageErrorText": "لم يتم العثور على وحدة تخزين خارجية على هذا الجهاز", "noExternalStorageErrorText": "لم يتم العثور على وحدة تخزين خارجية على هذا الجهاز",
"noGameCircleText": "خطأ: لم يتم تسجيل الدخول الئ gamecircle", "noGameCircleText": "خطأ: لم يتم تسجيل الدخول الئ gamecircle",
"noPluginsInstalledText": "لا إضافات مثبتة",
"noScoresYetText": "لا نقاط حتى الآن.", "noScoresYetText": "لا نقاط حتى الآن.",
"noServersFoundText": "لا توجد اي سيرفرات.", "noServersFoundText": "لا توجد اي سيرفرات.",
"noThanksText": "لا شكرا", "noThanksText": "لا شكرا",

View file

@ -337,6 +337,8 @@
"getMoreGamesText": "Атрымаць больш гульняў...", "getMoreGamesText": "Атрымаць больш гульняў...",
"titleText": "Дадаць гульню" "titleText": "Дадаць гульню"
}, },
"addToFavoritesText": "Дадаць у абранае",
"addedToFavoritesText": "'${NAME}' дададзены ў абранае.",
"allText": "Усё", "allText": "Усё",
"allowText": "Дазволіць", "allowText": "Дазволіць",
"alreadySignedInText": "Ваш уліковы запіс увайшоў з іншай прылады;\nкалі ласка, пераключыце ўліковыя запісы альбо зачыніце гульню на вашым\nіншыя прылады і паспрабуйце яшчэ раз", "alreadySignedInText": "Ваш уліковы запіс увайшоў з іншай прылады;\nкалі ласка, пераключыце ўліковыя запісы альбо зачыніце гульню на вашым\nіншыя прылады і паспрабуйце яшчэ раз",
@ -755,6 +757,7 @@
"manualYourLocalAddressText": "Ваш лакальны адрас:", "manualYourLocalAddressText": "Ваш лакальны адрас:",
"nearbyText": "Побач", "nearbyText": "Побач",
"noConnectionText": "<няма злучэння>", "noConnectionText": "<няма злучэння>",
"noPartiesAddedText": "Партыі не дададзены",
"otherVersionsText": "(іншыя версіі)", "otherVersionsText": "(іншыя версіі)",
"partyCodeText": "Код вечарыны", "partyCodeText": "Код вечарыны",
"partyInviteAcceptText": "Згадзіцца", "partyInviteAcceptText": "Згадзіцца",
@ -1073,6 +1076,7 @@
"noContinuesText": "(без працягу)", "noContinuesText": "(без працягу)",
"noExternalStorageErrorText": "Знешняя памяць не знойдзена", "noExternalStorageErrorText": "Знешняя памяць не знойдзена",
"noGameCircleText": "Памылка: вы не ўвайшлі ў GameCircle", "noGameCircleText": "Памылка: вы не ўвайшлі ў GameCircle",
"noPluginsInstalledText": "Убудовы не ўстаноўлены",
"noProfilesErrorText": "У вас няма ніводнага профіля, таму вас будуць называць '${NAME}'.\nЗайдзіце ў \"Налады -> Профілі\", каб стварыць уласны профіль.", "noProfilesErrorText": "У вас няма ніводнага профіля, таму вас будуць называць '${NAME}'.\nЗайдзіце ў \"Налады -> Профілі\", каб стварыць уласны профіль.",
"noScoresYetText": "Вынікаў пакуль няма.", "noScoresYetText": "Вынікаў пакуль няма.",
"noServersFoundText": "Серверы не знойдзены.", "noServersFoundText": "Серверы не знойдзены.",

View file

@ -339,6 +339,8 @@
"getMoreGamesText": "获取更多游戏模式…", "getMoreGamesText": "获取更多游戏模式…",
"titleText": "添加比赛" "titleText": "添加比赛"
}, },
"addToFavoritesText": "添加到收藏",
"addedToFavoritesText": "将'${NAME}'添加到收藏",
"allText": "全部", "allText": "全部",
"allowText": "允许", "allowText": "允许",
"alreadySignedInText": "您的账号已在其他设备登录;\n请切换账号或者退出已登录的设备\n然后再试一次", "alreadySignedInText": "您的账号已在其他设备登录;\n请切换账号或者退出已登录的设备\n然后再试一次",
@ -758,6 +760,7 @@
"manualYourLocalAddressText": "本地地址:", "manualYourLocalAddressText": "本地地址:",
"nearbyText": "附近", "nearbyText": "附近",
"noConnectionText": "<无连接>", "noConnectionText": "<无连接>",
"noPartiesAddedText": "没有加入派对",
"otherVersionsText": "(其他版本)", "otherVersionsText": "(其他版本)",
"partyCodeText": "派对代码", "partyCodeText": "派对代码",
"partyInviteAcceptText": "接受", "partyInviteAcceptText": "接受",
@ -1075,6 +1078,7 @@
"noContinuesText": "(无可继续)", "noContinuesText": "(无可继续)",
"noExternalStorageErrorText": "该设备上未发现外部存储器", "noExternalStorageErrorText": "该设备上未发现外部存储器",
"noGameCircleText": "错误未登入GameCircle", "noGameCircleText": "错误未登入GameCircle",
"noPluginsInstalledText": "没有安装插件",
"noProfilesErrorText": "您没有玩家档案,所以还得忍受“${NAME}”这个名字。\n进入设置->玩家档案,为自己创建档案。", "noProfilesErrorText": "您没有玩家档案,所以还得忍受“${NAME}”这个名字。\n进入设置->玩家档案,为自己创建档案。",
"noScoresYetText": "还未有得分记录。", "noScoresYetText": "还未有得分记录。",
"noServersFoundText": "未找到服务器", "noServersFoundText": "未找到服务器",
@ -1292,6 +1296,7 @@
"netTestingText": "网络测试", "netTestingText": "网络测试",
"resetText": "恢复默认值", "resetText": "恢复默认值",
"showBombTrajectoriesText": "显示炸弹轨迹", "showBombTrajectoriesText": "显示炸弹轨迹",
"showDemosWhenIdleText": "当游戏空闲时播放演示画面",
"showDevConsoleButtonText": "显示开发者控制台按钮", "showDevConsoleButtonText": "显示开发者控制台按钮",
"showInGamePingText": "显示游戏延迟", "showInGamePingText": "显示游戏延迟",
"showPlayerNamesText": "显示玩家名字", "showPlayerNamesText": "显示玩家名字",

View file

@ -29,6 +29,7 @@
"signInWithGooglePlayText": "用play商店登入", "signInWithGooglePlayText": "用play商店登入",
"signInWithTestAccountInfoText": "(舊有的帳號登入方式;使用後來的創設的帳號)", "signInWithTestAccountInfoText": "(舊有的帳號登入方式;使用後來的創設的帳號)",
"signInWithTestAccountText": "用測試帳號登入", "signInWithTestAccountText": "用測試帳號登入",
"signInWithText": "通過${SERVICE}登錄",
"signInWithV2InfoText": "(可用於所有平臺的賬戶)", "signInWithV2InfoText": "(可用於所有平臺的賬戶)",
"signInWithV2Text": "使用Bombsquad賬戶登入", "signInWithV2Text": "使用Bombsquad賬戶登入",
"signOutText": "登出", "signOutText": "登出",
@ -332,6 +333,8 @@
"getMoreGamesText": "獲取更多比賽模式", "getMoreGamesText": "獲取更多比賽模式",
"titleText": "新增比賽" "titleText": "新增比賽"
}, },
"addToFavoritesText": "添加到收藏",
"addedToFavoritesText": "已將'${NAME}'添加到收藏",
"allText": "全部", "allText": "全部",
"allowText": "允許", "allowText": "允許",
"alreadySignedInText": "你的賬號已在其他設備上登錄\n請退出其他設備的登錄\n然後重試", "alreadySignedInText": "你的賬號已在其他設備上登錄\n請退出其他設備的登錄\n然後重試",
@ -558,6 +561,8 @@
"disableXInputDescriptionText": "允許使用四個以上的控制器,但可能不會正常工作", "disableXInputDescriptionText": "允許使用四個以上的控制器,但可能不會正常工作",
"disableXInputText": "禁用XInput", "disableXInputText": "禁用XInput",
"disabledText": "禁用", "disabledText": "禁用",
"discordFriendsText": "想要尋找新的朋友一起遊玩嗎?\n快來加入我們的Discord社區發現新夥伴",
"discordJoinText": "加入Discord社區",
"doneText": "完成", "doneText": "完成",
"drawText": "平局", "drawText": "平局",
"duplicateText": "複製", "duplicateText": "複製",
@ -743,6 +748,7 @@
"manualYourLocalAddressText": "本地地址:", "manualYourLocalAddressText": "本地地址:",
"nearbyText": "附近", "nearbyText": "附近",
"noConnectionText": "<無連接>", "noConnectionText": "<無連接>",
"noPartiesAddedText": "未添加派對",
"otherVersionsText": "(其他版本)", "otherVersionsText": "(其他版本)",
"partyCodeText": "派對代碼", "partyCodeText": "派對代碼",
"partyInviteAcceptText": "接受", "partyInviteAcceptText": "接受",
@ -814,6 +820,7 @@
"alwaysText": "總是", "alwaysText": "總是",
"fullScreenCmdText": "全屏顯示Cmd-F", "fullScreenCmdText": "全屏顯示Cmd-F",
"fullScreenCtrlText": "全屏顯示Ctrl-F", "fullScreenCtrlText": "全屏顯示Ctrl-F",
"fullScreenText": "全屏",
"gammaText": "Gamma", "gammaText": "Gamma",
"highText": "高", "highText": "高",
"higherText": "最高", "higherText": "最高",
@ -1056,7 +1063,9 @@
"noContinuesText": "(無可繼續)", "noContinuesText": "(無可繼續)",
"noExternalStorageErrorText": "該設備未發現外部存儲器", "noExternalStorageErrorText": "該設備未發現外部存儲器",
"noGameCircleText": "錯誤未登錄GameCircle", "noGameCircleText": "錯誤未登錄GameCircle",
"noPluginsInstalledText": "未安裝插件",
"noScoresYetText": "沒有得分記錄", "noScoresYetText": "沒有得分記錄",
"noServersFoundText": "未找到服務器",
"noThanksText": "不,謝謝", "noThanksText": "不,謝謝",
"noTournamentsInTestBuildText": "注意:此測試版本的比賽分數將會被作廢", "noTournamentsInTestBuildText": "注意:此測試版本的比賽分數將會被作廢",
"noValidMapsErrorText": "沒有發現該比賽類型的有效地圖", "noValidMapsErrorText": "沒有發現該比賽類型的有效地圖",
@ -1358,6 +1367,8 @@
"storeText": "商店", "storeText": "商店",
"submitText": "提交", "submitText": "提交",
"submittingPromoCodeText": "正在提交代碼...", "submittingPromoCodeText": "正在提交代碼...",
"successText": "大功告成!",
"supportEmailText": "如果您在使用應用中遇到任何問題,\n請發送郵件至${EMAIL}.",
"teamNamesColorText": "團隊名稱/顏色...", "teamNamesColorText": "團隊名稱/顏色...",
"telnetAccessGrantedText": "Telnet訪問以啟用", "telnetAccessGrantedText": "Telnet訪問以啟用",
"telnetAccessText": "檢測到Telnet訪問是否允許", "telnetAccessText": "檢測到Telnet訪問是否允許",
@ -1811,6 +1822,7 @@
"unlockThisInTheStoreText": "這必須從商店解鎖", "unlockThisInTheStoreText": "這必須從商店解鎖",
"unlockThisProfilesText": "如需創建超過${NUM}個檔案,你需要", "unlockThisProfilesText": "如需創建超過${NUM}個檔案,你需要",
"unlockThisText": "你需要這些來解鎖", "unlockThisText": "你需要這些來解鎖",
"unsupportedControllerText": "抱歉,不支持控制器\"${NAME}\"",
"unsupportedHardwareText": "抱歉,此版本的遊戲不支持該硬件", "unsupportedHardwareText": "抱歉,此版本的遊戲不支持該硬件",
"upFirstText": "進入第一局", "upFirstText": "進入第一局",
"upNextText": "進入比賽${COUNT}第二局", "upNextText": "進入比賽${COUNT}第二局",
@ -1822,6 +1834,7 @@
"usingItunesText": "使用音樂軟件設置背景音樂...", "usingItunesText": "使用音樂軟件設置背景音樂...",
"v2AccountLinkingInfoText": "要鏈接 V2 帳戶,請使用“管理帳戶”按鈕。", "v2AccountLinkingInfoText": "要鏈接 V2 帳戶,請使用“管理帳戶”按鈕。",
"validatingTestBuildText": "測試版驗證中", "validatingTestBuildText": "測試版驗證中",
"viaText": "其他賬戶",
"victoryText": "勝利!", "victoryText": "勝利!",
"voteDelayText": "你不能在${NUMBER}內發起一個新的投票", "voteDelayText": "你不能在${NUMBER}內發起一個新的投票",
"voteInProgressText": "已經有一個投票正在進行中了", "voteInProgressText": "已經有一個投票正在進行中了",

View file

@ -1297,6 +1297,7 @@
"netTestingText": "Testování sítě", "netTestingText": "Testování sítě",
"resetText": "Obnovit", "resetText": "Obnovit",
"showBombTrajectoriesText": "Ukazovat trajektorii bomb", "showBombTrajectoriesText": "Ukazovat trajektorii bomb",
"showDemosWhenIdleText": "Zobrazit ukázky při nečinnosti",
"showDevConsoleButtonText": "Ukaž tlačítko vývojářské konzoly", "showDevConsoleButtonText": "Ukaž tlačítko vývojářské konzoly",
"showInGamePingText": "Ukazovat ping při hře", "showInGamePingText": "Ukazovat ping při hře",
"showPlayerNamesText": "Ukazovat jména hráčů", "showPlayerNamesText": "Ukazovat jména hráčů",

View file

@ -9,6 +9,7 @@
"changeOncePerSeasonError": "U moet wachten tot het volgende seizoen om dit te veranderen (${NUM} dagen)", "changeOncePerSeasonError": "U moet wachten tot het volgende seizoen om dit te veranderen (${NUM} dagen)",
"customName": "Aangepaste naam", "customName": "Aangepaste naam",
"deviceSpecificAccountText": "U gebruikt nu het apparaat-specifieke account: ${NAME}", "deviceSpecificAccountText": "U gebruikt nu het apparaat-specifieke account: ${NAME}",
"googlePlayGamesAccountSwitchText": "Als je een ander Google-account \nwilt gebruiken, gebruik dan de Google Play Games-app om over te schakelen.",
"linkAccountsEnterCodeText": "Voer Code In", "linkAccountsEnterCodeText": "Voer Code In",
"linkAccountsGenerateCodeText": "Genereer Code", "linkAccountsGenerateCodeText": "Genereer Code",
"linkAccountsInfoText": "(deel voortgang over verschillende platformen)", "linkAccountsInfoText": "(deel voortgang over verschillende platformen)",
@ -16,6 +17,7 @@
"linkAccountsInstructionsText": "Om twee accounts te koppelen, genereer je bij een\ndaar van een code die je invult bij de ander.\nVoortgang en inventaris worden dan samengevoegd.\nJe kan maximaal ${COUNT} accounts koppelen.\n\nBELANGRIJK: Koppel alleen accounts die jij bezit!\nAls je accounts van vrienden koppelt kan je niet \nmeer tegelijkertijd spelen!\n\nOok: Dit kan momenteel niet ongedaan gemaakt worden, dus pas op!", "linkAccountsInstructionsText": "Om twee accounts te koppelen, genereer je bij een\ndaar van een code die je invult bij de ander.\nVoortgang en inventaris worden dan samengevoegd.\nJe kan maximaal ${COUNT} accounts koppelen.\n\nBELANGRIJK: Koppel alleen accounts die jij bezit!\nAls je accounts van vrienden koppelt kan je niet \nmeer tegelijkertijd spelen!\n\nOok: Dit kan momenteel niet ongedaan gemaakt worden, dus pas op!",
"linkAccountsText": "Koppel Accounts", "linkAccountsText": "Koppel Accounts",
"linkedAccountsText": "Verbonden Accounts:", "linkedAccountsText": "Verbonden Accounts:",
"manageAccountText": "Beheer account",
"nameChangeConfirm": "Verander je account naam naar ${NAME}?", "nameChangeConfirm": "Verander je account naam naar ${NAME}?",
"notLoggedInText": "<niet ingelogd>", "notLoggedInText": "<niet ingelogd>",
"resetProgressConfirmNoAchievementsText": "Dit reset uw co-op campagne voortgang en\nlokale high-scores (maar niet uw tickets).\nDit kan niet ongedaan worden gemaakt. Weet u het zeker?", "resetProgressConfirmNoAchievementsText": "Dit reset uw co-op campagne voortgang en\nlokale high-scores (maar niet uw tickets).\nDit kan niet ongedaan worden gemaakt. Weet u het zeker?",
@ -31,6 +33,7 @@
"signInWithGooglePlayText": "Log in met Google Play", "signInWithGooglePlayText": "Log in met Google Play",
"signInWithTestAccountInfoText": "(oudere account type; gebruik device account gaat door)", "signInWithTestAccountInfoText": "(oudere account type; gebruik device account gaat door)",
"signInWithTestAccountText": "Log in met test account", "signInWithTestAccountText": "Log in met test account",
"signInWithText": "Log in met ${SERVICE}",
"signInWithV2InfoText": "(een account dat op alle platforms werkt)", "signInWithV2InfoText": "(een account dat op alle platforms werkt)",
"signInWithV2Text": "Inloggen met een BombSquad rekening", "signInWithV2Text": "Inloggen met een BombSquad rekening",
"signOutText": "Log Uit", "signOutText": "Log Uit",
@ -43,6 +46,7 @@
"titleText": "Profiel", "titleText": "Profiel",
"unlinkAccountsInstructionsText": "Selecteer een account om los te koppelen.", "unlinkAccountsInstructionsText": "Selecteer een account om los te koppelen.",
"unlinkAccountsText": "Koppel accounts los.", "unlinkAccountsText": "Koppel accounts los.",
"unlinkLegacyV1AccountsText": "Ontkoppel oude (V1) accounts",
"v2LinkInstructionsText": "Gebruik deze link om een account aan te maken of in te loggen.", "v2LinkInstructionsText": "Gebruik deze link om een account aan te maken of in te loggen.",
"viaAccount": "(via account ${NAME})", "viaAccount": "(via account ${NAME})",
"youAreLoggedInAsText": "Je bent ingelogd als:", "youAreLoggedInAsText": "Je bent ingelogd als:",
@ -332,10 +336,14 @@
"achievementsRemainingText": "Resterende Prestaties:", "achievementsRemainingText": "Resterende Prestaties:",
"achievementsText": "Prestaties", "achievementsText": "Prestaties",
"achievementsUnavailableForOldSeasonsText": "Sorry, prestatie gegevens voor oude seizoenen zijn niet beschikbaar.", "achievementsUnavailableForOldSeasonsText": "Sorry, prestatie gegevens voor oude seizoenen zijn niet beschikbaar.",
"activatedText": "${THING} geactiveerd.",
"addGameWindow": { "addGameWindow": {
"getMoreGamesText": "Verkrijg Meer Spellen...", "getMoreGamesText": "Verkrijg Meer Spellen...",
"titleText": "Voeg Game toe" "titleText": "Voeg Game toe"
}, },
"addToFavoritesText": "Toevoegen aan favorieten",
"addedToFavoritesText": "'${NAME}' toegevoegd aan Favorieten.",
"allText": "Alle",
"allowText": "Toestaan", "allowText": "Toestaan",
"alreadySignedInText": "Uw account is al ingelogd op een ander apparaat;\nVerander van account of sluit het spel op uw andere\napparaten en probeer het opnieuw.", "alreadySignedInText": "Uw account is al ingelogd op een ander apparaat;\nVerander van account of sluit het spel op uw andere\napparaten en probeer het opnieuw.",
"apiVersionErrorText": "Kan module ${NAME} niet laden; deze gebruikt api-versie ${VERSION_USED}; benodigd is ${VERSION_REQUIRED}.", "apiVersionErrorText": "Kan module ${NAME} niet laden; deze gebruikt api-versie ${VERSION_USED}; benodigd is ${VERSION_REQUIRED}.",
@ -371,6 +379,7 @@
"chatMutedText": "berichten gedempt", "chatMutedText": "berichten gedempt",
"chatUnMuteText": "maak de chat ongedaan", "chatUnMuteText": "maak de chat ongedaan",
"choosingPlayerText": "<speler kiezen>", "choosingPlayerText": "<speler kiezen>",
"codesExplainText": "Codes worden door de \nontwikkelaar verstrekt om accountproblemen te diagnosticeren en te corrigeren.",
"completeThisLevelToProceedText": "U moet dit level voltooien\nom door te gaan!", "completeThisLevelToProceedText": "U moet dit level voltooien\nom door te gaan!",
"completionBonusText": "Voltooiing Bonus", "completionBonusText": "Voltooiing Bonus",
"configControllersWindow": { "configControllersWindow": {
@ -454,6 +463,7 @@
"titleText": "Configureer Touchscreen", "titleText": "Configureer Touchscreen",
"touchControlsScaleText": "Touch Besturing Schalen" "touchControlsScaleText": "Touch Besturing Schalen"
}, },
"configureDeviceInSystemSettingsText": "${DEVICE} kan worden geconfigureerd in de Systeeminstellingen-app.",
"configureItNowText": "Nu configureren?", "configureItNowText": "Nu configureren?",
"configureText": "Configureren", "configureText": "Configureren",
"connectMobileDevicesWindow": { "connectMobileDevicesWindow": {
@ -509,6 +519,7 @@
"welcome2Text": "U kunt ook tickets verdienen van veel van dezelfde activiteiten.\nTickets kunnen gebruikt worden om mee te doen aan toernooien,\nvoor het vrijspelen van nieuwe karakters, speelvelden, mini-spellen en meer.", "welcome2Text": "U kunt ook tickets verdienen van veel van dezelfde activiteiten.\nTickets kunnen gebruikt worden om mee te doen aan toernooien,\nvoor het vrijspelen van nieuwe karakters, speelvelden, mini-spellen en meer.",
"yourPowerRankingText": "Uw Macht Klassement:" "yourPowerRankingText": "Uw Macht Klassement:"
}, },
"copyConfirmText": "Gekopieerd naar het klembord.",
"copyOfText": "${NAME} Kopie", "copyOfText": "${NAME} Kopie",
"copyText": "Kopiëren", "copyText": "Kopiëren",
"copyrightText": "© 2013 Eric Froemling", "copyrightText": "© 2013 Eric Froemling",
@ -562,7 +573,9 @@
"deleteText": "Verwijder", "deleteText": "Verwijder",
"demoText": "demonstratie", "demoText": "demonstratie",
"denyText": "Weigeren", "denyText": "Weigeren",
"deprecatedText": "Verouderd",
"desktopResText": "Bureaublad Resolutie", "desktopResText": "Bureaublad Resolutie",
"deviceAccountUpgradeText": "Waarschuwing: u bent ingelogd met een apparaataccount (${NAME}). \nApparaataccounts worden in een toekomstige update verwijderd. \nUpgrade naar een V2-account als u uw voortgang wilt \nbehouden.",
"difficultyEasyText": "Makkelijk", "difficultyEasyText": "Makkelijk",
"difficultyHardOnlyText": "Alleen moeilijk", "difficultyHardOnlyText": "Alleen moeilijk",
"difficultyHardText": "Moeilijk", "difficultyHardText": "Moeilijk",
@ -571,6 +584,9 @@
"disableRemoteAppConnectionsText": "Schakel Afstandsbediening-App connecties uit", "disableRemoteAppConnectionsText": "Schakel Afstandsbediening-App connecties uit",
"disableXInputDescriptionText": "Staat meer dan 4 controllers toe, maar werkt misschien niet helemaal goed.", "disableXInputDescriptionText": "Staat meer dan 4 controllers toe, maar werkt misschien niet helemaal goed.",
"disableXInputText": "Schakel XInput uit", "disableXInputText": "Schakel XInput uit",
"disabledText": "Gehandicapt",
"discordFriendsText": "Wil je op zoek naar nieuwe mensen om mee te spelen? \nSluit je aan bij onze Discord en vind nieuwe vrienden!",
"discordJoinText": "Sluit je aan bij de onenigheid",
"doneText": "Klaar", "doneText": "Klaar",
"drawText": "Gelijk", "drawText": "Gelijk",
"duplicateText": "Kopieer", "duplicateText": "Kopieer",
@ -644,12 +660,15 @@
"useMusicFolderText": "Map met Muziek Bestanden" "useMusicFolderText": "Map met Muziek Bestanden"
}, },
"editText": "Bewerk", "editText": "Bewerk",
"enabledText": "Ingeschakeld",
"endText": "Einde", "endText": "Einde",
"enjoyText": "Geniet!", "enjoyText": "Geniet!",
"epicDescriptionFilterText": "${DESCRIPTION} In epische slow motion.", "epicDescriptionFilterText": "${DESCRIPTION} In epische slow motion.",
"epicNameFilterText": "Epische ${NAME}", "epicNameFilterText": "Epische ${NAME}",
"errorAccessDeniedText": "toegang geweigerd", "errorAccessDeniedText": "toegang geweigerd",
"errorDeviceTimeIncorrectText": "De tijd van je apparaat is ${HOURS} uur \nonjuist. Dit zal waarschijnlijk problemen \nveroorzaken. Controleer uw tijd- en tijdzone-instellingen.",
"errorOutOfDiskSpaceText": "schuifruimte vol", "errorOutOfDiskSpaceText": "schuifruimte vol",
"errorSecureConnectionFailText": "Kan geen veilige cloudverbinding tot stand brengen; netwerkfunctionaliteit kan mislukken.",
"errorText": "Fout", "errorText": "Fout",
"errorUnknownText": "onbekende fout", "errorUnknownText": "onbekende fout",
"exitGameText": "${APP_NAME} Verlaten?", "exitGameText": "${APP_NAME} Verlaten?",
@ -764,6 +783,7 @@
"manualYourLocalAddressText": "Uw lokale adres:", "manualYourLocalAddressText": "Uw lokale adres:",
"nearbyText": "Dichtbij", "nearbyText": "Dichtbij",
"noConnectionText": "<geen verbinding>", "noConnectionText": "<geen verbinding>",
"noPartiesAddedText": "Geen partijen toegevoegd",
"otherVersionsText": "(andere versies)", "otherVersionsText": "(andere versies)",
"partyCodeText": "Partijcode", "partyCodeText": "Partijcode",
"partyInviteAcceptText": "Accepteren", "partyInviteAcceptText": "Accepteren",
@ -838,15 +858,19 @@
"youHaveText": "U heeft ${COUNT} tickets" "youHaveText": "U heeft ${COUNT} tickets"
}, },
"googleMultiplayerDiscontinuedText": "Sorry, de Google Play multi-player functie is nu even niet beschikbaar. \nIk werk hard aan een vervanger. \nProbeer nu alsjeblieft een andere connectie mogelijkheid.\n-Eric", "googleMultiplayerDiscontinuedText": "Sorry, de Google Play multi-player functie is nu even niet beschikbaar. \nIk werk hard aan een vervanger. \nProbeer nu alsjeblieft een andere connectie mogelijkheid.\n-Eric",
"googlePlayPurchasesNotAvailableText": "Google Play-aankopen zijn niet beschikbaar. \nMogelijk moet u uw winkel-app updaten.",
"googlePlayServicesNotAvailableText": "Google Play-services zijn niet beschikbaar. \nSommige app-functionaliteit is mogelijk uitgeschakeld.",
"googlePlayText": "Google Play", "googlePlayText": "Google Play",
"graphicsSettingsWindow": { "graphicsSettingsWindow": {
"alwaysText": "Altijd", "alwaysText": "Altijd",
"fullScreenCmdText": "Volledig scherm (Cmd-F)", "fullScreenCmdText": "Volledig scherm (Cmd-F)",
"fullScreenCtrlText": "Volledig scherm (Cmd-F)", "fullScreenCtrlText": "Volledig scherm (Cmd-F)",
"fullScreenText": "Volledig scherm",
"gammaText": "Gamma", "gammaText": "Gamma",
"highText": "Hoog", "highText": "Hoog",
"higherText": "Hoger", "higherText": "Hoger",
"lowText": "Laag", "lowText": "Laag",
"maxFPSText": "Maximale FPS",
"mediumText": "Gemiddeld", "mediumText": "Gemiddeld",
"neverText": "Nooit", "neverText": "Nooit",
"resolutionText": "Resolutie", "resolutionText": "Resolutie",
@ -1041,6 +1065,7 @@
"creditsText": "Credits", "creditsText": "Credits",
"demoMenuText": "Voorbeeld Menu", "demoMenuText": "Voorbeeld Menu",
"endGameText": "Beëindig Spel", "endGameText": "Beëindig Spel",
"endTestText": "Einde proef",
"exitGameText": "Verlaat Spel", "exitGameText": "Verlaat Spel",
"exitToMenuText": "Verlaat naar menu?", "exitToMenuText": "Verlaat naar menu?",
"howToPlayText": "Hoe te Spelen", "howToPlayText": "Hoe te Spelen",
@ -1061,6 +1086,7 @@
"maxConnectionsText": "Max Connecties", "maxConnectionsText": "Max Connecties",
"maxPartySizeText": "Max Partij Grootte", "maxPartySizeText": "Max Partij Grootte",
"maxPlayersText": "Max Spelers", "maxPlayersText": "Max Spelers",
"merchText": "Koopwaar!",
"modeArcadeText": "Speelhal Modus", "modeArcadeText": "Speelhal Modus",
"modeClassicText": "Klassieke Modus", "modeClassicText": "Klassieke Modus",
"modeDemoText": "Demo Modus", "modeDemoText": "Demo Modus",
@ -1091,8 +1117,10 @@
"noExternalStorageErrorText": "Geen externe opslag gevonden op dit apparaat", "noExternalStorageErrorText": "Geen externe opslag gevonden op dit apparaat",
"noGameCircleText": "Fout: niet aangemeld bij GameCircle", "noGameCircleText": "Fout: niet aangemeld bij GameCircle",
"noJoinCoopMidwayText": "Je kan niet halverwegen inspringen bij coöperatieve spellen.", "noJoinCoopMidwayText": "Je kan niet halverwegen inspringen bij coöperatieve spellen.",
"noPluginsInstalledText": "Geen plug-ins geïnstalleerd",
"noProfilesErrorText": "U heeeft geen speler profielen, dus zit u vast aan '${NAME}'.\nGa naar Instellingen->Speler Profielen om een profiel te maken voor uzelf.", "noProfilesErrorText": "U heeeft geen speler profielen, dus zit u vast aan '${NAME}'.\nGa naar Instellingen->Speler Profielen om een profiel te maken voor uzelf.",
"noScoresYetText": "Nog geen scores.", "noScoresYetText": "Nog geen scores.",
"noServersFoundText": "Geen servers gevonden.",
"noThanksText": "Nee Bedankt", "noThanksText": "Nee Bedankt",
"noTournamentsInTestBuildText": "PAS OP: De punten van deze test tournament worden niet meegerekend.", "noTournamentsInTestBuildText": "PAS OP: De punten van deze test tournament worden niet meegerekend.",
"noValidMapsErrorText": "Geen geldige gebieden gevonden voor dit speltype.", "noValidMapsErrorText": "Geen geldige gebieden gevonden voor dit speltype.",
@ -1102,6 +1130,7 @@
"notSignedInErrorText": "Je moet inloggen om dit te doen.", "notSignedInErrorText": "Je moet inloggen om dit te doen.",
"notSignedInGooglePlayErrorText": "Je moet ingelogd zijn met Google Play om dit te doen.", "notSignedInGooglePlayErrorText": "Je moet ingelogd zijn met Google Play om dit te doen.",
"notSignedInText": "niet ingelogd", "notSignedInText": "niet ingelogd",
"notUsingAccountText": "Opmerking: ${SERVICE}-account negeren. \nGa naar 'Account -> Inloggen met ${SERVICE}' als je hier gebruik van wilt maken.",
"nothingIsSelectedErrorText": "Er is niks geselecteerd!", "nothingIsSelectedErrorText": "Er is niks geselecteerd!",
"numberText": "#${NUMBER}", "numberText": "#${NUMBER}",
"offText": "Uit", "offText": "Uit",
@ -1163,7 +1192,14 @@
"playlistsText": "Speellijsten", "playlistsText": "Speellijsten",
"pleaseRateText": "Als u geniet van ${APP_NAME}, zou u dan een moment willen\nnemen om een waardering te geven of recensie te schrijven.\nDit geeft ons nuttige feedback voor toekomstige ontwikkelingen.\n\nBedankt!\n-eric", "pleaseRateText": "Als u geniet van ${APP_NAME}, zou u dan een moment willen\nnemen om een waardering te geven of recensie te schrijven.\nDit geeft ons nuttige feedback voor toekomstige ontwikkelingen.\n\nBedankt!\n-eric",
"pleaseWaitText": "Even geduld...", "pleaseWaitText": "Even geduld...",
"pluginClassLoadErrorText": "Fout bij het laden van plug-inklasse '${PLUGIN}': ${ERROR}",
"pluginInitErrorText": "Fout bij het starten van plug-in '${PLUGIN}': ${ERROR}",
"pluginSettingsText": "Plugin-instellingen",
"pluginsAutoEnableNewText": "Schakel nieuwe plug-ins automatisch in",
"pluginsDetectedText": "Nieuw contact gedecteerd. Schakel in/configureer in de instellingen.", "pluginsDetectedText": "Nieuw contact gedecteerd. Schakel in/configureer in de instellingen.",
"pluginsDisableAllText": "Schakel alle plug-ins uit",
"pluginsEnableAllText": "Schakel alle plug-ins in",
"pluginsRemovedText": "${NUM} plug-in(s) niet meer gevonden.",
"pluginsText": "Contacten", "pluginsText": "Contacten",
"practiceText": "Oefenen", "practiceText": "Oefenen",
"pressAnyButtonPlayAgainText": "Druk een knop om opnieuw te spelen...", "pressAnyButtonPlayAgainText": "Druk een knop om opnieuw te spelen...",
@ -1259,6 +1295,8 @@
"runText": "Ren", "runText": "Ren",
"saveText": "Opslaan", "saveText": "Opslaan",
"scanScriptsErrorText": "Fout(en) bij inlezen scripts; zie log voor details.", "scanScriptsErrorText": "Fout(en) bij inlezen scripts; zie log voor details.",
"scanScriptsMultipleModulesNeedUpdatesText": "${PATH} en ${NUM} andere module(s) moeten worden bijgewerkt voor api ${API}.",
"scanScriptsSingleModuleNeedsUpdatesText": "${PATH} moet worden bijgewerkt voor API ${API}.",
"scoreChallengesText": "Score Uitdagingen", "scoreChallengesText": "Score Uitdagingen",
"scoreListUnavailableText": "Score lijst niet beschikbaar.", "scoreListUnavailableText": "Score lijst niet beschikbaar.",
"scoreText": "Score", "scoreText": "Score",
@ -1305,6 +1343,9 @@
"netTestingText": "Netwerk Testen", "netTestingText": "Netwerk Testen",
"resetText": "Reset", "resetText": "Reset",
"showBombTrajectoriesText": "Baan van de bom weergeven", "showBombTrajectoriesText": "Baan van de bom weergeven",
"showDemosWhenIdleText": "Toon demo's wanneer deze niet actief zijn",
"showDevConsoleButtonText": "Toon dev-consoleknop",
"showInGamePingText": "Toon in-game ping",
"showPlayerNamesText": "Toon Namen Spelers", "showPlayerNamesText": "Toon Namen Spelers",
"showUserModsText": "Toon Aanpassingen Map", "showUserModsText": "Toon Aanpassingen Map",
"titleText": "Geavanceerd", "titleText": "Geavanceerd",
@ -1399,6 +1440,8 @@
"storeText": "Winkel", "storeText": "Winkel",
"submitText": "Voorleggen", "submitText": "Voorleggen",
"submittingPromoCodeText": "Code verzenden ...", "submittingPromoCodeText": "Code verzenden ...",
"successText": "Succes!",
"supportEmailText": "Als u problemen ondervindt met de app, \nkunt u een e-mail sturen naar ${EMAIL}.",
"teamNamesColorText": "Teamnamen / kleuren ...", "teamNamesColorText": "Teamnamen / kleuren ...",
"teamsText": "Teams", "teamsText": "Teams",
"telnetAccessGrantedText": "Telnet toegang ingeschakeld.", "telnetAccessGrantedText": "Telnet toegang ingeschakeld.",
@ -1427,6 +1470,7 @@
"tournamentStandingsText": "Toernooi Stand", "tournamentStandingsText": "Toernooi Stand",
"tournamentText": "Toernooi", "tournamentText": "Toernooi",
"tournamentTimeExpiredText": "Toernooi Tijd Verlopen", "tournamentTimeExpiredText": "Toernooi Tijd Verlopen",
"tournamentsDisabledWorkspaceText": "Toernooien zijn uitgeschakeld als werkruimten actief zijn. \nOm toernooien opnieuw in te schakelen, schakelt u uw werkruimte uit en start u opnieuw op.",
"tournamentsText": "Toernooien", "tournamentsText": "Toernooien",
"translations": { "translations": {
"characterNames": { "characterNames": {
@ -1598,6 +1642,7 @@
"Italian": "Italiaans", "Italian": "Italiaans",
"Japanese": "Japans", "Japanese": "Japans",
"Korean": "Koreaans", "Korean": "Koreaans",
"Malay": "Maleis",
"Persian": "Perzisch", "Persian": "Perzisch",
"Polish": "Pools", "Polish": "Pools",
"Portuguese": "Portugees", "Portuguese": "Portugees",
@ -1878,6 +1923,7 @@
"unlockThisInTheStoreText": "Hiervoor moet een aankoop gedaan worden in de winkel.", "unlockThisInTheStoreText": "Hiervoor moet een aankoop gedaan worden in de winkel.",
"unlockThisProfilesText": "Om meer dan ${NUM} profielen te maken heb je nodig:", "unlockThisProfilesText": "Om meer dan ${NUM} profielen te maken heb je nodig:",
"unlockThisText": "Om dit te ontgrendelen, moet u:", "unlockThisText": "Om dit te ontgrendelen, moet u:",
"unsupportedControllerText": "Sorry, controller \"${NAME}\" wordt niet ondersteund.",
"unsupportedHardwareText": "Sorry, deze hardware wordt niet ondersteunt door deze versie van het spel.", "unsupportedHardwareText": "Sorry, deze hardware wordt niet ondersteunt door deze versie van het spel.",
"upFirstText": "Als eerste:", "upFirstText": "Als eerste:",
"upNextText": "Daarna volgt in potje ${COUNT}:", "upNextText": "Daarna volgt in potje ${COUNT}:",
@ -1888,8 +1934,10 @@
"usesExternalControllerText": "Dit spel maakt gebruik van een externe controller als input.", "usesExternalControllerText": "Dit spel maakt gebruik van een externe controller als input.",
"usingItunesText": "De muziek app wordt gebruikt voor de muziek...", "usingItunesText": "De muziek app wordt gebruikt voor de muziek...",
"usingItunesTurnRepeatAndShuffleOnText": "Zorg er er voor dat shuffle AAN staat en herhalen op ALLES staat in iTunes.", "usingItunesTurnRepeatAndShuffleOnText": "Zorg er er voor dat shuffle AAN staat en herhalen op ALLES staat in iTunes.",
"v2AccountLinkingInfoText": "Om V2-accounts te koppelen, gebruikt u de knop 'Account beheren'.",
"validatingBetaText": "Beta wordt Gevalideerd...", "validatingBetaText": "Beta wordt Gevalideerd...",
"validatingTestBuildText": "Valideren Test Versie...", "validatingTestBuildText": "Valideren Test Versie...",
"viaText": "via",
"victoryText": "Overwinning!", "victoryText": "Overwinning!",
"voteDelayText": "Je kan geen andere stemming starten voor ${NUMBER} seconden", "voteDelayText": "Je kan geen andere stemming starten voor ${NUMBER} seconden",
"voteInProgressText": "Er is al een stemming bezig.", "voteInProgressText": "Er is al een stemming bezig.",
@ -1922,6 +1970,7 @@
}, },
"waveText": "Ronde", "waveText": "Ronde",
"wellSureText": "Maar Natuurlijk!", "wellSureText": "Maar Natuurlijk!",
"whatIsThisText": "Wat is dit?",
"wiimoteLicenseWindow": { "wiimoteLicenseWindow": {
"licenseTextScale": 0.62, "licenseTextScale": 0.62,
"titleText": "DarwiinRemote Copyright" "titleText": "DarwiinRemote Copyright"
@ -1946,6 +1995,8 @@
"winsPlayerText": "${NAME} Wint!", "winsPlayerText": "${NAME} Wint!",
"winsTeamText": "${NAME} Wint!", "winsTeamText": "${NAME} Wint!",
"winsText": "${NAME} Wint!", "winsText": "${NAME} Wint!",
"workspaceSyncErrorText": "Fout bij synchroniseren van ${WORKSPACE}. Zie logboek voor details.",
"workspaceSyncReuseText": "Kan ${WORKSPACE} niet synchroniseren. Hergebruik van de vorige gesynchroniseerde versie.",
"worldScoresUnavailableText": "Wereldwijde scores niet beschikbaar.", "worldScoresUnavailableText": "Wereldwijde scores niet beschikbaar.",
"worldsBestScoresText": "'s Werelds Beste Scores", "worldsBestScoresText": "'s Werelds Beste Scores",
"worldsBestTimesText": "'s Werelds Beste Tijden", "worldsBestTimesText": "'s Werelds Beste Tijden",

View file

@ -1277,6 +1277,7 @@
"netTestingText": "Network Testing", "netTestingText": "Network Testing",
"resetText": "Reset", "resetText": "Reset",
"showBombTrajectoriesText": "Show Bomb Trajectories", "showBombTrajectoriesText": "Show Bomb Trajectories",
"showDemosWhenIdleText": "Show Demos When Idle",
"showDevConsoleButtonText": "Show Dev Console Button", "showDevConsoleButtonText": "Show Dev Console Button",
"showInGamePingText": "Show In-Game Ping", "showInGamePingText": "Show In-Game Ping",
"showPlayerNamesText": "Show Player Names", "showPlayerNamesText": "Show Player Names",

View file

@ -331,9 +331,11 @@
"achievementsUnavailableForOldSeasonsText": "Pasensya na, hindi available ang mga detalye ng achievements para sa mga lumang seasons.", "achievementsUnavailableForOldSeasonsText": "Pasensya na, hindi available ang mga detalye ng achievements para sa mga lumang seasons.",
"activatedText": "Na-aktibo ang ${THING}.", "activatedText": "Na-aktibo ang ${THING}.",
"addGameWindow": { "addGameWindow": {
"getMoreGamesText": "Kukuha ng higit pang mga laro…", "getMoreGamesText": "Kumuha ng Higit pang mga Laro…",
"titleText": "Magdagdag Ng Laro" "titleText": "Magdagdag Ng Laro"
}, },
"addToFavoritesText": "Ilagay sa Mga Paborito",
"addedToFavoritesText": "Nakalagay na ang '${NAME}' sa Mga Paborito.",
"allText": "Lahat", "allText": "Lahat",
"allowText": "Payagan", "allowText": "Payagan",
"alreadySignedInText": "Ang iyong account ay naka-sign in mula sa isa pang device;\nMangyaring lumipat ng mga accounts o isara ang laro sa iyong\niba pang mga device at subukan muli.", "alreadySignedInText": "Ang iyong account ay naka-sign in mula sa isa pang device;\nMangyaring lumipat ng mga accounts o isara ang laro sa iyong\niba pang mga device at subukan muli.",
@ -341,16 +343,16 @@
"audioSettingsWindow": { "audioSettingsWindow": {
"headRelativeVRAudioInfoText": "(Lalabas ang “Auto” ng ito kapag nakasaksak ang headphones)", "headRelativeVRAudioInfoText": "(Lalabas ang “Auto” ng ito kapag nakasaksak ang headphones)",
"headRelativeVRAudioText": "Head-Relative VR Audio", "headRelativeVRAudioText": "Head-Relative VR Audio",
"musicVolumeText": "Volume ng Musika", "musicVolumeText": "Lakas ng Musika",
"soundVolumeText": "Lakas ng Tunog", "soundVolumeText": "Lakas ng Tunog",
"soundtrackButtonText": "Mga Soundtrack", "soundtrackButtonText": "Mga Soundtrack",
"soundtrackDescriptionText": "(I-assign ang iyong sariling musika para magtugtug kapag naglalaro)", "soundtrackDescriptionText": "(I-assign ang iyong sariling musika para magtugtug kapag naglalaro)",
"titleText": "Audio" "titleText": "Tugtugan"
}, },
"autoText": "Auto", "autoText": "Auto",
"backText": "Bumalik", "backText": "Bumalik",
"banThisPlayerText": "I-ban ang Manlalarong Ito", "banThisPlayerText": "Bawalin ang Manlalarong Ito",
"bestOfFinalText": "Pinakamahusay-sa-${COUNT} Final", "bestOfFinalText": "Wakas ng Pinakamahusay-sa-${COUNT}",
"bestOfSeriesText": "Pinakamahusay sa ${COUNT} series:", "bestOfSeriesText": "Pinakamahusay sa ${COUNT} series:",
"bestOfUseFirstToInstead": 0, "bestOfUseFirstToInstead": 0,
"bestRankText": "Ang iyong pinakamahusay ay #${RANK}", "bestRankText": "Ang iyong pinakamahusay ay #${RANK}",
@ -366,10 +368,10 @@
"challengeEndedText": "Natapos na ang challenge na ito.", "challengeEndedText": "Natapos na ang challenge na ito.",
"chatMuteText": "Tahimikin Ang Chat Mo", "chatMuteText": "Tahimikin Ang Chat Mo",
"chatMutedText": "Na-mute ang Chat", "chatMutedText": "Na-mute ang Chat",
"chatUnMuteText": "I-unmute ang Chat", "chatUnMuteText": "Ipaganahin Mo Na ang Chat",
"choosingPlayerText": "<pumipili ng manlalaro>", "choosingPlayerText": "<pumipili ng manlalaro>",
"codesExplainText": "Binigay ng developer ang mga codes \npara i-diagnose at i-tama ang mga issues sa account.", "codesExplainText": "Binigay ng developer ang mga kowd \npara kilalanin at maitama ang mga problema sa account.",
"completeThisLevelToProceedText": "I complete mo muna\nang level na ito bago ka mag-proceed!", "completeThisLevelToProceedText": "Tapusin mo muna\nang antas na ito bago tumuloy!",
"completionBonusText": "Bonus sa Pagkumpleto nito:", "completionBonusText": "Bonus sa Pagkumpleto nito:",
"configControllersWindow": { "configControllersWindow": {
"configureControllersText": "I-configure ang mga Controller", "configureControllersText": "I-configure ang mga Controller",
@ -380,7 +382,7 @@
"ps3Text": "PS3 Controllers", "ps3Text": "PS3 Controllers",
"titleText": "Mga Controller", "titleText": "Mga Controller",
"wiimotesText": "Wiimotes", "wiimotesText": "Wiimotes",
"xbox360Text": "Xbox 360 Controllers" "xbox360Text": "Controllers ng Xbox 360"
}, },
"configGamepadSelectWindow": { "configGamepadSelectWindow": {
"androidNoteText": "Tandaan: nag-iiba-iba ang suporta sa controller sa mga devices at bersyon ng Andriod.", "androidNoteText": "Tandaan: nag-iiba-iba ang suporta sa controller sa mga devices at bersyon ng Andriod.",
@ -396,17 +398,17 @@
"autoRecalibrateDescriptionText": "(paganahin ito kung ang iyong karakter ay hindi gumagalaw ng buong bilis)", "autoRecalibrateDescriptionText": "(paganahin ito kung ang iyong karakter ay hindi gumagalaw ng buong bilis)",
"autoRecalibrateText": "Auto-Recalibrate Analog Stick", "autoRecalibrateText": "Auto-Recalibrate Analog Stick",
"axisText": "aksis", "axisText": "aksis",
"clearText": "i-bura", "clearText": "ibura",
"dpadText": "DPAD", "dpadText": "DPAD",
"extraStartButtonText": "Extra na Start Button", "extraStartButtonText": "Extra na Start Button",
"ifNothingHappensTryAnalogText": "Kapag walang gumagana, i-try na i-assign sa analog stick.", "ifNothingHappensTryAnalogText": "Kapag walang gumagana, i-try na i-assign sa analog stick.",
"ifNothingHappensTryDpadText": "Kapag hindi gumana, i-try na i-assign sa d-pad.", "ifNothingHappensTryDpadText": "Kapag hindi gumana, i-try na i-assign sa d-pad.",
"ignoreCompletelyDescriptionText": "(pigilan ang controller na ito na maapektuhan ang alinman sa laro o mga menu)", "ignoreCompletelyDescriptionText": "(pigilan ang controller na ito na maapektuhan ang alinman sa laro o mga menu)",
"ignoreCompletelyText": "Huwag Pansinin", "ignoreCompletelyText": "Huwag Pansinin",
"ignoredButton1Text": "Pindutan Na Di Pansinin 1", "ignoredButton1Text": "Pindutan Na Di Pinansin 1",
"ignoredButton2Text": "Pindutan Na Di Pansinin 2", "ignoredButton2Text": "Pindutan Na Di Pinansin 2",
"ignoredButton3Text": "Pindutan Na Di Pansinin 3", "ignoredButton3Text": "Pindutan Na Di Pinansin 3",
"ignoredButton4Text": "Pindutan Na Di Pansinin 4", "ignoredButton4Text": "Pindutan Na Di Pinansin 4",
"ignoredButtonDescriptionText": "(gamitin ito para ma-prevent ang home o sync buttons na nakakaapekto sa UI)", "ignoredButtonDescriptionText": "(gamitin ito para ma-prevent ang home o sync buttons na nakakaapekto sa UI)",
"pressAnyAnalogTriggerText": "Pindutin ang anumang analog trigger…", "pressAnyAnalogTriggerText": "Pindutin ang anumang analog trigger…",
"pressAnyButtonOrDpadText": "Pindutin ang anumang pindutan o dpad…", "pressAnyButtonOrDpadText": "Pindutin ang anumang pindutan o dpad…",
@ -751,6 +753,7 @@
"manualYourLocalAddressText": "Iyong lokal na address:", "manualYourLocalAddressText": "Iyong lokal na address:",
"nearbyText": "Malapit", "nearbyText": "Malapit",
"noConnectionText": "<walang koneksyon>", "noConnectionText": "<walang koneksyon>",
"noPartiesAddedText": "Walang Nadagdag na mga Partido",
"otherVersionsText": "<iba pang mga bersyon>", "otherVersionsText": "<iba pang mga bersyon>",
"partyCodeText": "Kowd ng Partido", "partyCodeText": "Kowd ng Partido",
"partyInviteAcceptText": "Tanggapin", "partyInviteAcceptText": "Tanggapin",
@ -776,7 +779,7 @@
"publicText": "Publiko", "publicText": "Publiko",
"requestingAPromoCodeText": "Humihiling ng kowd...", "requestingAPromoCodeText": "Humihiling ng kowd...",
"sendDirectInvitesText": "I-send ng direktang imbitasyon", "sendDirectInvitesText": "I-send ng direktang imbitasyon",
"shareThisCodeWithFriendsText": "Ibahagi ang code na ito sa iyong mga kaibigan:", "shareThisCodeWithFriendsText": "Ibahagi ang kowd nito sa iyong mga kaibigan:",
"showMyAddressText": "Ipakita Ang Address Ko", "showMyAddressText": "Ipakita Ang Address Ko",
"startHostingPaidText": "Mag-host ngayon ng ${COST}", "startHostingPaidText": "Mag-host ngayon ng ${COST}",
"startHostingText": "Host", "startHostingText": "Host",
@ -789,7 +792,7 @@
"wifiDirectText": "Wi-Fi Direct", "wifiDirectText": "Wi-Fi Direct",
"worksBetweenAllPlatformsText": "(itoy gumagana sa pagitan ng lahat ng mga platform)", "worksBetweenAllPlatformsText": "(itoy gumagana sa pagitan ng lahat ng mga platform)",
"worksWithGooglePlayDevicesText": "(itoy gumagana sa mga devices na tumatakbo ang bersyon ng Google Play (android) ng larong ito)", "worksWithGooglePlayDevicesText": "(itoy gumagana sa mga devices na tumatakbo ang bersyon ng Google Play (android) ng larong ito)",
"youHaveBeenSentAPromoCodeText": "Pinadalhan ka ng promo code na ${APP_NAME}:" "youHaveBeenSentAPromoCodeText": "Pinadalhan ka ng promo kowd ng ${APP_NAME}:"
}, },
"getTicketsWindow": { "getTicketsWindow": {
"freeText": "LIBRE!", "freeText": "LIBRE!",
@ -887,7 +890,7 @@
"holdAnyButtonText": "<hawakan ang anumang pindutan>", "holdAnyButtonText": "<hawakan ang anumang pindutan>",
"holdAnyKeyText": "<hawakan ang anumang key>", "holdAnyKeyText": "<hawakan ang anumang key>",
"hostIsNavigatingMenusText": "- Ang ${HOST} ay nagna-navigate sa mga menu tulad ng isang boss -", "hostIsNavigatingMenusText": "- Ang ${HOST} ay nagna-navigate sa mga menu tulad ng isang boss -",
"importPlaylistCodeInstructionsText": "Gamitin ang sumusunod na code upang i-import ang playlist na ito sa ibang lugar:", "importPlaylistCodeInstructionsText": "Gamitin ang sumusunod na kowd upang i-import ang playlist na ito sa ibang lugar:",
"importPlaylistSuccessText": "Na-import na ${TYPE} na playlist '${NAME}'", "importPlaylistSuccessText": "Na-import na ${TYPE} na playlist '${NAME}'",
"importText": "I-Import", "importText": "I-Import",
"importingText": "Nag-Iimport…", "importingText": "Nag-Iimport…",
@ -1054,21 +1057,22 @@
"nameDiedText": "${NAME} ay namatay.", "nameDiedText": "${NAME} ay namatay.",
"nameKilledText": "Pinatay ni ${NAME} si ${VICTIM}", "nameKilledText": "Pinatay ni ${NAME} si ${VICTIM}",
"nameNotEmptyText": "Hindi pwede ang walang pangalan!", "nameNotEmptyText": "Hindi pwede ang walang pangalan!",
"nameScoresText": "${NAME} Naka-score!", "nameScoresText": "Nakaiskor si ${NAME}!",
"nameSuicideKidFriendlyText": "Hindi sinasadyang namatay si ${NAME}.", "nameSuicideKidFriendlyText": "Hindi sinasadyang namatay si ${NAME}.",
"nameSuicideText": "Nagpakamatay si ${NAME}.", "nameSuicideText": "Nagpakamatay si ${NAME}.",
"nameText": "Pangalan", "nameText": "Pangalan",
"nativeText": "Natural", "nativeText": "Natural",
"newPersonalBestText": "Bagong personal na pinakamahusay!", "newPersonalBestText": "Bagong personal na pinakamahusay!",
"newTestBuildAvailableText": "Available ang isang mas bagong pagsubok na build! (${VERSION} build ${BUILD}).\nKunin ito sa ${ADDRESS}", "newTestBuildAvailableText": "Available ang isang mas bagong pagsubok na build! (${VERSION} build ${BUILD}).\nKunin ito sa ${ADDRESS}",
"newText": "Bago", "newText": "Gumawa ng Bago",
"newVersionAvailableText": "Available ang isang mas bagong bersyon ng ${APP_NAME}! (${VERSION})", "newVersionAvailableText": "Available ang isang mas bagong bersyon ng ${APP_NAME}! (${VERSION})",
"nextAchievementsText": "Mga Susunod na Nakamit:", "nextAchievementsText": "Mga Susunod na Nakamit:",
"nextLevelText": "Mga Susunod na Level", "nextLevelText": "Susunod na Antas",
"noAchievementsRemainingText": "- wala", "noAchievementsRemainingText": "- wala",
"noContinuesText": "(hindi i-continue)", "noContinuesText": "(hindi i-continue)",
"noExternalStorageErrorText": "Walang nakitang external na storage sa device na ito", "noExternalStorageErrorText": "Walang nakitang external na storage sa device na ito",
"noGameCircleText": "Error: hindi naka-log in sa GameCircle", "noGameCircleText": "Error: hindi naka-log in sa GameCircle",
"noPluginsInstalledText": "Hindi Nakabit ang mga Plugin",
"noScoresYetText": "Wala pang score.", "noScoresYetText": "Wala pang score.",
"noServersFoundText": "Walang nahanap na servers.", "noServersFoundText": "Walang nahanap na servers.",
"noThanksText": "Salamat Nalang", "noThanksText": "Salamat Nalang",
@ -1159,7 +1163,7 @@
"pressToSelectProfileText": "pindutin ang ${BUTTONS} upang pumili ng manlalaro", "pressToSelectProfileText": "pindutin ang ${BUTTONS} upang pumili ng manlalaro",
"pressToSelectTeamText": "pindutin ang ${BUTTONS} para pumili ng team", "pressToSelectTeamText": "pindutin ang ${BUTTONS} para pumili ng team",
"promoCodeWindow": { "promoCodeWindow": {
"codeText": "Code", "codeText": "Kowd",
"enterText": "I-enter" "enterText": "I-enter"
}, },
"promoSubmitErrorText": "Error sa pagsusumite ng kowd; suriin ang iyong koneksyon sa internet", "promoSubmitErrorText": "Error sa pagsusumite ng kowd; suriin ang iyong koneksyon sa internet",
@ -1245,12 +1249,12 @@
"pointsText": "Puntos", "pointsText": "Puntos",
"secondsText": "Segundo" "secondsText": "Segundo"
}, },
"scoreWasText": "(ay nasa ${COUNT})", "scoreWasText": "(mula sa ${COUNT})",
"selectText": "Pilihin", "selectText": "Pilihin",
"seriesWinLine1PlayerText": "ANG NANALO SA", "seriesWinLine1PlayerText": "ANG NANALO SA",
"seriesWinLine1TeamText": "ANG NANALO SA", "seriesWinLine1TeamText": "ANG NANALO SA",
"seriesWinLine1Text": "ANG NANALO SA", "seriesWinLine1Text": "ANG NANALO SA",
"seriesWinLine2Text": "SERYENG NITO!", "seriesWinLine2Text": "SERYE NITO!",
"settingsWindow": { "settingsWindow": {
"accountText": "Account", "accountText": "Account",
"advancedText": "Mga Iba Pa", "advancedText": "Mga Iba Pa",
@ -1269,7 +1273,7 @@
"disableThisNotice": "(maaari mong i-disable ang notice na ito sa mga advanced na setting)", "disableThisNotice": "(maaari mong i-disable ang notice na ito sa mga advanced na setting)",
"enablePackageModsDescriptionText": "(nagpapagana ng mga karagdagang kakayahan sa pag-modding ngunit hindi pinapagana ang net-play)", "enablePackageModsDescriptionText": "(nagpapagana ng mga karagdagang kakayahan sa pag-modding ngunit hindi pinapagana ang net-play)",
"enablePackageModsText": "Paganahin ang Lokal na Package Mods", "enablePackageModsText": "Paganahin ang Lokal na Package Mods",
"enterPromoCodeText": "Ilagay ang Code", "enterPromoCodeText": "Ilagay ang Kowd",
"forTestingText": "Tandaan: ang mga value na ito ay para lamang sa pagsubok at mawawala kapag lumabas ang app.", "forTestingText": "Tandaan: ang mga value na ito ay para lamang sa pagsubok at mawawala kapag lumabas ang app.",
"helpTranslateText": "Ang mga pagsasalin na hindi Ingles ng ${APP_NAME} ay isang komunidad\nsuportadong pagsisikap. Kung gusto mong mag-ambag o magtama\nisang pagsasalin, sundan ang link sa ibaba. Salamat!", "helpTranslateText": "Ang mga pagsasalin na hindi Ingles ng ${APP_NAME} ay isang komunidad\nsuportadong pagsisikap. Kung gusto mong mag-ambag o magtama\nisang pagsasalin, sundan ang link sa ibaba. Salamat!",
"kickIdlePlayersText": "I-kick Ang Mga Idle na Manlalaro", "kickIdlePlayersText": "I-kick Ang Mga Idle na Manlalaro",
@ -1280,6 +1284,7 @@
"netTestingText": "Pagsusuri ng Network", "netTestingText": "Pagsusuri ng Network",
"resetText": "I-reset", "resetText": "I-reset",
"showBombTrajectoriesText": "Ipakita ang Mga Trajectory ng Bomba", "showBombTrajectoriesText": "Ipakita ang Mga Trajectory ng Bomba",
"showDemosWhenIdleText": "Ipakita Ang Demo Habang Nakatigil",
"showDevConsoleButtonText": "Ipakita ang Dev Console Button", "showDevConsoleButtonText": "Ipakita ang Dev Console Button",
"showInGamePingText": "Ipakita ang In-Game Ping", "showInGamePingText": "Ipakita ang In-Game Ping",
"showPlayerNamesText": "Ipakita ang Mga Pangalan ng Manlalaro", "showPlayerNamesText": "Ipakita ang Mga Pangalan ng Manlalaro",
@ -1289,14 +1294,14 @@
"translationFetchErrorText": "hindi available ang katayuan ng wika", "translationFetchErrorText": "hindi available ang katayuan ng wika",
"translationFetchingStatusText": "sinusuri ang status ng lengguwahe…", "translationFetchingStatusText": "sinusuri ang status ng lengguwahe…",
"translationInformMe": "Ipaalam sa akin kapag ang aking wika ay nangangailangan ng mga update", "translationInformMe": "Ipaalam sa akin kapag ang aking wika ay nangangailangan ng mga update",
"translationNoUpdateNeededText": "ang kasalukuyang wika ay makabago; woohoo!", "translationNoUpdateNeededText": "ang kasalukuyang wika ay makabago na muli; yehey!",
"translationUpdateNeededText": "** ang kasalukuyang wika ay nangangailangan ng mga update!! **", "translationUpdateNeededText": "** ang kasalukuyang wika ay nangangailangan ng mga update!! **",
"vrTestingText": "Testing ng VR" "vrTestingText": "Testing ng VR"
}, },
"shareText": "I-share", "shareText": "I-share",
"sharingText": "Nagbabahagi….", "sharingText": "Nagbabahagi….",
"showText": "Ipakita", "showText": "Ipakita",
"signInForPromoCodeText": "Dapat kang mag-sign in sa isang account para magkabisa ang mga code.", "signInForPromoCodeText": "Dapat kang mag-sign in sa isang account para magkabisa ang mga kowd.",
"signInWithGameCenterText": "Para gumamit ng Game Center account,\nmag-sign in gamit ang Game Center app.", "signInWithGameCenterText": "Para gumamit ng Game Center account,\nmag-sign in gamit ang Game Center app.",
"singleGamePlaylistNameText": "${GAME} lang", "singleGamePlaylistNameText": "${GAME} lang",
"singlePlayerCountText": "1 manlalaro", "singlePlayerCountText": "1 manlalaro",
@ -1371,7 +1376,7 @@
}, },
"storeText": "Tindahan", "storeText": "Tindahan",
"submitText": "Ipasa", "submitText": "Ipasa",
"submittingPromoCodeText": "Nagsusumite ng Code...", "submittingPromoCodeText": "Pinapasa ang Kowd...",
"successText": "Wakas!", "successText": "Wakas!",
"supportEmailText": "Pag may problema sa app, \npaki-email ang ${EMAIL}.", "supportEmailText": "Pag may problema sa app, \npaki-email ang ${EMAIL}.",
"teamNamesColorText": "Mga Pangalan/Kulay ng Team…", "teamNamesColorText": "Mga Pangalan/Kulay ng Team…",
@ -1514,7 +1519,7 @@
"Conquest": "Pagsakop", "Conquest": "Pagsakop",
"Death Match": "Laban ng Kamatayan", "Death Match": "Laban ng Kamatayan",
"Easter Egg Hunt": "Paghahanap ng mga Easter Egg", "Easter Egg Hunt": "Paghahanap ng mga Easter Egg",
"Elimination": "Pagbabawas sa away", "Elimination": "Pagbabawasan",
"Football": "Putbol", "Football": "Putbol",
"Hockey": "Hockey", "Hockey": "Hockey",
"Keep Away": "Layuan Mo", "Keep Away": "Layuan Mo",
@ -1522,7 +1527,7 @@
"Meteor Shower": "Ulan ng mga Bulalakaw", "Meteor Shower": "Ulan ng mga Bulalakaw",
"Ninja Fight": "Labanan ng mga Ninja", "Ninja Fight": "Labanan ng mga Ninja",
"Onslaught": "Pagsalakay", "Onslaught": "Pagsalakay",
"Race": "Takbuan", "Race": "Takbuhan",
"Runaround": "Bantayan", "Runaround": "Bantayan",
"Target Practice": "Pagsasanay ng Patamaan", "Target Practice": "Pagsasanay ng Patamaan",
"The Last Stand": "Ang Huling Labanan" "The Last Stand": "Ang Huling Labanan"
@ -1532,44 +1537,44 @@
"Keyboard P2": "Keyboard F2" "Keyboard P2": "Keyboard F2"
}, },
"languages": { "languages": {
"Arabic": "Arabe", "Arabic": "Wikang Arabik",
"Belarussian": "Belaruso", "Belarussian": "Wikang Belaruso",
"Chinese": "Tsino", "Chinese": "Wikang Tsino",
"ChineseTraditional": "Tsinong Tradisyonal", "ChineseTraditional": "Wikang Tsinong Tradisyonal",
"Croatian": "Kroatyano", "Croatian": "Wikang Kroatyano",
"Czech": "Tsek", "Czech": "Wikang Tsek",
"Danish": "Makadenmark", "Danish": "Wikang Denmark",
"Dutch": "Olandes", "Dutch": "Wikang Olandes",
"English": "Ingles", "English": "Wikang Ingles",
"Esperanto": "Esperanto", "Esperanto": "Wikang Esperanto",
"Filipino": "Tagalog", "Filipino": "Wikang Tagalog",
"Finnish": "Finnish", "Finnish": "Wikang Finnish",
"French": "Pranses", "French": "Wikang Pranses",
"German": "Aleman", "German": "Wikang Alemanya",
"Gibberish": "Hindi Naiitindihan na Linguahe", "Gibberish": "Hindi Maintindihan nito",
"Greek": "Griyego", "Greek": "Wikang Griyego",
"Hindi": "Indiyano", "Hindi": "Wikang Indiyano",
"Hungarian": "Hanggaryan", "Hungarian": "Wikang Hanggaryan",
"Indonesian": "Indonesiyo", "Indonesian": "Wikang Indonesiyo",
"Italian": "Italiyano", "Italian": "Wikang Italiyano",
"Japanese": "Nippongo", "Japanese": "Wikang Hapon",
"Korean": "Koreano", "Korean": "Wikang Koreano",
"Malay": "Malay", "Malay": "Wikang Malay",
"Persian": "Persyano", "Persian": "Wikang Persyano",
"Polish": "Polish", "Polish": "Wikang Polish",
"Portuguese": "Portuges", "Portuguese": "Wikang Portuges",
"Romanian": "Rumano", "Romanian": "Wikang Rumano",
"Russian": "Ruso", "Russian": "Wikang Ruso",
"Serbian": "Serbyan", "Serbian": "Wikang Serbyan",
"Slovak": "Eslobako", "Slovak": "Wikang Eslobako",
"Spanish": "Espanyol", "Spanish": "Wikang Espanyol",
"Swedish": "Suweko", "Swedish": "Wikang Suweko",
"Tamil": "Tamil", "Tamil": "Wikang Tamil",
"Thai": "Siyam", "Thai": "Wikang Thai",
"Turkish": "Turko", "Turkish": "Wikang Turko",
"Ukrainian": "Ukranyo", "Ukrainian": "Wikang Ukranyo",
"Venetian": "Benesiya", "Venetian": "Wikang Benesiya",
"Vietnamese": "Byetnam" "Vietnamese": "Wikang Byetnam"
}, },
"leagueNames": { "leagueNames": {
"Bronze": "Tanso", "Bronze": "Tanso",
@ -1580,7 +1585,7 @@
"mapsNames": { "mapsNames": {
"Big G": "Malaking G", "Big G": "Malaking G",
"Bridgit": "Tawiring Tulay", "Bridgit": "Tawiring Tulay",
"Courtyard": "Looban Patyo", "Courtyard": "Loobang Patyo",
"Crag Castle": "Kastilyong Bangin", "Crag Castle": "Kastilyong Bangin",
"Doom Shroom": "Itim na Kabute", "Doom Shroom": "Itim na Kabute",
"Football Stadium": "Istadyum", "Football Stadium": "Istadyum",
@ -1598,7 +1603,7 @@
}, },
"playlistNames": { "playlistNames": {
"Just Epic": "Epic Lang", "Just Epic": "Epic Lang",
"Just Sports": "Shorts Lang" "Just Sports": "Sports Lang"
}, },
"scoreNames": { "scoreNames": {
"Flags": "Watawat", "Flags": "Watawat",
@ -1606,10 +1611,10 @@
"Score": "Iskor", "Score": "Iskor",
"Survived": "Nakaligtas", "Survived": "Nakaligtas",
"Time": "Oras", "Time": "Oras",
"Time Held": "Oras na Nahawak" "Time Held": "Oras na Gaganapin"
}, },
"serverResponses": { "serverResponses": {
"A code has already been used on this account.": "Nagamit na ang isang code sa account na ito.", "A code has already been used on this account.": "Nagamit na ang isang kowd sa account na ito.",
"A reward has already been given for that address.": "Naibigay na ang reward para sa address na iyon.", "A reward has already been given for that address.": "Naibigay na ang reward para sa address na iyon.",
"Account linking successful!": "Matagumpay ang pag-link ng account!", "Account linking successful!": "Matagumpay ang pag-link ng account!",
"Account unlinking successful!": "Matagumpay ang pag-unlink ng account!", "Account unlinking successful!": "Matagumpay ang pag-unlink ng account!",
@ -1628,9 +1633,9 @@
"Could not establish a secure connection.": "Hindi makapagtatag ng secure na koneksyon.", "Could not establish a secure connection.": "Hindi makapagtatag ng secure na koneksyon.",
"Daily maximum reached.": "Naabot na ang pang-araw-araw ng request.", "Daily maximum reached.": "Naabot na ang pang-araw-araw ng request.",
"Entering tournament...": "Papasok sa paligsahan…", "Entering tournament...": "Papasok sa paligsahan…",
"Invalid code.": "Di-wastong code.", "Invalid code.": "Di-wasto ang kowd.",
"Invalid payment; purchase canceled.": "Di-wastong pagbabayad; kinansela ang pagbili.", "Invalid payment; purchase canceled.": "Di-wastong pagbabayad; kinansela ang pagbili.",
"Invalid promo code.": "Di-wastong promo code.", "Invalid promo code.": "Di-wasto ang promo kowd.",
"Invalid purchase.": "Di-wastong bilihin", "Invalid purchase.": "Di-wastong bilihin",
"Invalid tournament entry; score will be ignored.": "Di-wastong entry sa paligsahan; hindi papansinin ang mga iskor.", "Invalid tournament entry; score will be ignored.": "Di-wastong entry sa paligsahan; hindi papansinin ang mga iskor.",
"Item unlocked!": "Na-unlock ang aytem!", "Item unlocked!": "Na-unlock ang aytem!",
@ -1638,7 +1643,7 @@
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "I-link ang account na ${ACCOUNT} sa account na ito?\nMawawala ang lahat ng umiiral na data sa ${ACCOUNT}.\nHindi na ito maaaring bawiin. Sigurado ka ba?", "Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "I-link ang account na ${ACCOUNT} sa account na ito?\nMawawala ang lahat ng umiiral na data sa ${ACCOUNT}.\nHindi na ito maaaring bawiin. Sigurado ka ba?",
"Max number of playlists reached.": "Naabot na ang maximum na bilang ng mga playlist.", "Max number of playlists reached.": "Naabot na ang maximum na bilang ng mga playlist.",
"Max number of profiles reached.": "Naabot na ang maximum na bilang ng mga profile.", "Max number of profiles reached.": "Naabot na ang maximum na bilang ng mga profile.",
"Maximum friend code rewards reached.": "Naabot ang maximum na mga reward sa code ng kaibigan.", "Maximum friend code rewards reached.": "Naabot ang maximum na mga reward sa kowd ng kaibigan.",
"Message is too long.": "Ang mensahe ay napakahaba.", "Message is too long.": "Ang mensahe ay napakahaba.",
"No servers are available. Please try again soon.": "Walang makakuha na mga server. Pakisubukang muli sa lalong madaling oras.", "No servers are available. Please try again soon.": "Walang makakuha na mga server. Pakisubukang muli sa lalong madaling oras.",
"Profile \"${NAME}\" upgraded successfully.": "Matagumpay na na-upgrade ang profile na \"${NAME}\".", "Profile \"${NAME}\" upgraded successfully.": "Matagumpay na na-upgrade ang profile na \"${NAME}\".",
@ -1646,10 +1651,10 @@
"Purchase successful!": "Matagumpay ang pagbili!", "Purchase successful!": "Matagumpay ang pagbili!",
"Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Nakatanggap ng ${COUNT} na tiket para sa pag-sign in.\nBumalik bukas para makatanggap ng ${TOMORROW_COUNT}.", "Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Nakatanggap ng ${COUNT} na tiket para sa pag-sign in.\nBumalik bukas para makatanggap ng ${TOMORROW_COUNT}.",
"Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "Hindi na sinusuportahan ang functionality ng server sa bersyong ito ng laro;\nMangyaring mag-update sa isang mas bagong bersyon.", "Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "Hindi na sinusuportahan ang functionality ng server sa bersyong ito ng laro;\nMangyaring mag-update sa isang mas bagong bersyon.",
"Sorry, there are no uses remaining on this code.": "Pasensya na, wala nang natitirang gamit sa code na ito.", "Sorry, there are no uses remaining on this code.": "Pasensya na, hindi na magagamit ang kowd na ito.",
"Sorry, this code has already been used.": "Pasensya na, nagamit na ang code na ito.", "Sorry, this code has already been used.": "Pasensya na, nagamit na ang kowd na ito.",
"Sorry, this code has expired.": "Pasensya na, nag-expire na ang code na ito.", "Sorry, this code has expired.": "Pasensya na, nag-expire na ang kowd na ito.",
"Sorry, this code only works for new accounts.": "Pasensya na, gumagana lang ang code na ito para sa mga bagong account.", "Sorry, this code only works for new accounts.": "Pasensya na, gumagana lang ang kowd na ito para sa mga bagong account.",
"Still searching for nearby servers; please try again soon.": "Naghahanap pa rin ng mga kalapit na server; mangyaring subukan muli sa lalong madaling oras.", "Still searching for nearby servers; please try again soon.": "Naghahanap pa rin ng mga kalapit na server; mangyaring subukan muli sa lalong madaling oras.",
"Temporarily unavailable; please try again later.": "Pansamantalang hindi magagamit; Subukang muli mamaya.", "Temporarily unavailable; please try again later.": "Pansamantalang hindi magagamit; Subukang muli mamaya.",
"The tournament ended before you finished.": "Natapos ang tournament bago ka natapos.", "The tournament ended before you finished.": "Natapos ang tournament bago ka natapos.",

View file

@ -340,6 +340,8 @@
"getMoreGamesText": "Obtenir plus de jeux...", "getMoreGamesText": "Obtenir plus de jeux...",
"titleText": "Ajouter un Jeu" "titleText": "Ajouter un Jeu"
}, },
"addToFavoritesText": "Ajouter aux favoris",
"addedToFavoritesText": "'${NAME}' a été ajouté aux favoris.",
"allText": "Tous", "allText": "Tous",
"allowText": "Autoriser", "allowText": "Autoriser",
"alreadySignedInText": "Votre compte est connecté sur un autre appareil;\nveuillez changer de compte ou fermez le jeu sur \nles autres appareils et réessayez.", "alreadySignedInText": "Votre compte est connecté sur un autre appareil;\nveuillez changer de compte ou fermez le jeu sur \nles autres appareils et réessayez.",
@ -781,6 +783,7 @@
"manualYourLocalAddressText": "Votre adresse locale:", "manualYourLocalAddressText": "Votre adresse locale:",
"nearbyText": "Proche", "nearbyText": "Proche",
"noConnectionText": "<aucune connexion>", "noConnectionText": "<aucune connexion>",
"noPartiesAddedText": "Aucune partie ajoutée",
"otherVersionsText": "(autres versions)", "otherVersionsText": "(autres versions)",
"partyCodeText": "Code de la partie", "partyCodeText": "Code de la partie",
"partyInviteAcceptText": "Accepter", "partyInviteAcceptText": "Accepter",
@ -1124,6 +1127,7 @@
"noExternalStorageErrorText": "Aucun stockage externe a été trouvé pour cet appareil", "noExternalStorageErrorText": "Aucun stockage externe a été trouvé pour cet appareil",
"noGameCircleText": "Erreur: vous n'êtes pas connecté au GameCircle", "noGameCircleText": "Erreur: vous n'êtes pas connecté au GameCircle",
"noJoinCoopMidwayText": "Vous ne pouvez pas rejoindre une partie co-cop en plein milieu.", "noJoinCoopMidwayText": "Vous ne pouvez pas rejoindre une partie co-cop en plein milieu.",
"noPluginsInstalledText": "Aucun Plug-in installé",
"noProfilesErrorText": "Vous avez aucun profil de joueur, vous êtes donc coincés avec '${NAME}'.\nAllez à Paramètres->Profils des Joueurs pour vous créer un profil.", "noProfilesErrorText": "Vous avez aucun profil de joueur, vous êtes donc coincés avec '${NAME}'.\nAllez à Paramètres->Profils des Joueurs pour vous créer un profil.",
"noScoresYetText": "Aucun score pour le moment.", "noScoresYetText": "Aucun score pour le moment.",
"noServersFoundText": "Aucun serveur trouvé.", "noServersFoundText": "Aucun serveur trouvé.",
@ -1348,6 +1352,7 @@
"netTestingText": "Tester Votre Réseau", "netTestingText": "Tester Votre Réseau",
"resetText": "Réinitialiser", "resetText": "Réinitialiser",
"showBombTrajectoriesText": "Montrer les trajectoires de bombe", "showBombTrajectoriesText": "Montrer les trajectoires de bombe",
"showDemosWhenIdleText": "Afficher les démos en cas d'inactivité",
"showDevConsoleButtonText": "Afficher le Bouton de la Console de Développeur", "showDevConsoleButtonText": "Afficher le Bouton de la Console de Développeur",
"showInGamePingText": "Afficher La Latence En Jeu", "showInGamePingText": "Afficher La Latence En Jeu",
"showPlayerNamesText": "Montrer les Noms des Joueurs", "showPlayerNamesText": "Montrer les Noms des Joueurs",

View file

@ -1385,6 +1385,7 @@
"netTestingText": "Ntwkrz Tsstcg", "netTestingText": "Ntwkrz Tsstcg",
"resetText": "Rsttz", "resetText": "Rsttz",
"showBombTrajectoriesText": "Shzlz Bomf Tfwoejcwoefz", "showBombTrajectoriesText": "Shzlz Bomf Tfwoejcwoefz",
"showDemosWhenIdleText": "Sho cwoefj c wdofdfjdfwf",
"showDevConsoleButtonText": "Sho c weroiw c wo cwoije fwois", "showDevConsoleButtonText": "Sho c weroiw c wo cwoije fwois",
"showInGamePingText": "Shoe o co fowl Png", "showInGamePingText": "Shoe o co fowl Png",
"showPlayerNamesText": "SHzlfjl Plzlrr Nmzlzlls", "showPlayerNamesText": "SHzlfjl Plzlrr Nmzlzlls",

View file

@ -31,6 +31,7 @@
"signInWithGooglePlayText": "गूगल प्ले से साईन ईन करे", "signInWithGooglePlayText": "गूगल प्ले से साईन ईन करे",
"signInWithTestAccountInfoText": "(पुराना खाते का प्ररूप; आगे के लिए यंत्र खाते का प्रयोग करें)", "signInWithTestAccountInfoText": "(पुराना खाते का प्ररूप; आगे के लिए यंत्र खाते का प्रयोग करें)",
"signInWithTestAccountText": "परीक्षण के खाते से साइन इन करें", "signInWithTestAccountText": "परीक्षण के खाते से साइन इन करें",
"signInWithText": "${service} के साथ साइन इन करें",
"signInWithV2InfoText": "(एक खाता जो सभी प्लेटफार्मों पर काम करता है)", "signInWithV2InfoText": "(एक खाता जो सभी प्लेटफार्मों पर काम करता है)",
"signInWithV2Text": "BombSquad खाते से साइन इन करें", "signInWithV2Text": "BombSquad खाते से साइन इन करें",
"signOutText": "साइन आउट", "signOutText": "साइन आउट",
@ -337,6 +338,8 @@
"getMoreGamesText": "और गेम्स कि जानकारी पायें", "getMoreGamesText": "और गेम्स कि जानकारी पायें",
"titleText": "गेम जोड़ें" "titleText": "गेम जोड़ें"
}, },
"addToFavoritesText": "पसंदीदा में जोड़े",
"addedToFavoritesText": "\"${NAME}\"को पसंदीदा में जोड़ा गया।",
"allText": "सभी", "allText": "सभी",
"allowText": "अनुमति दें", "allowText": "अनुमति दें",
"alreadySignedInText": "आपका खाता किसी अन्य डिवाइस से साइन किया गया है; \nकृपया खातों को स्विच करें या अपने गेम को अन्य डिवाइस \nपर बंद करें और फिर से प्रयास करें", "alreadySignedInText": "आपका खाता किसी अन्य डिवाइस से साइन किया गया है; \nकृपया खातों को स्विच करें या अपने गेम को अन्य डिवाइस \nपर बंद करें और फिर से प्रयास करें",
@ -370,6 +373,7 @@
"chatMutedText": "बातचीत मौन हो गई है", "chatMutedText": "बातचीत मौन हो गई है",
"chatUnMuteText": "बातचीत दोबारा शुरू करें", "chatUnMuteText": "बातचीत दोबारा शुरू करें",
"choosingPlayerText": "<खिलाड़ी चुना जा रहा है>", "choosingPlayerText": "<खिलाड़ी चुना जा रहा है>",
"codesExplainText": "डेवलपर द्वारा कोड प्रदान किए जाते हैं\nखाता समस्याओं का निदान और सुधार करें।",
"completeThisLevelToProceedText": "आपको यह पड़ाव पार करना पड़ेगा आगे बढ़ने के लिए !", "completeThisLevelToProceedText": "आपको यह पड़ाव पार करना पड़ेगा आगे बढ़ने के लिए !",
"completionBonusText": "पूर्णता पुरस्कार", "completionBonusText": "पूर्णता पुरस्कार",
"configControllersWindow": { "configControllersWindow": {
@ -450,6 +454,7 @@
"swipeText": "स्वाइप", "swipeText": "स्वाइप",
"titleText": "टच स्क्रीन को कॉन्फ़िगर करें" "titleText": "टच स्क्रीन को कॉन्फ़िगर करें"
}, },
"configureDeviceInSystemSettingsText": "${DEVICE}को सिस्टम सेटिंग्स ऐप में कॉन्फ़िगर किया जा सकता है।",
"configureItNowText": "अभी कॉन्फ़िगर करें ?", "configureItNowText": "अभी कॉन्फ़िगर करें ?",
"configureText": "कॉन्फ़िगर", "configureText": "कॉन्फ़िगर",
"connectMobileDevicesWindow": { "connectMobileDevicesWindow": {
@ -563,6 +568,8 @@
"disableXInputDescriptionText": "4 नियंत्रकों से अधिक की अनुमति देता है लेकिन साथ ही साथ काम नहीं कर सकते", "disableXInputDescriptionText": "4 नियंत्रकों से अधिक की अनुमति देता है लेकिन साथ ही साथ काम नहीं कर सकते",
"disableXInputText": "Xinput अक्षम करें", "disableXInputText": "Xinput अक्षम करें",
"disabledText": "डिसेबल्ड", "disabledText": "डिसेबल्ड",
"discordFriendsText": "क्या आप खेलने के लिए नए लोगों की तलाश करना चाहते हैं?\nहमारे डिस्कोर्ड में शामिल हों और नए दोस्त खोजें!",
"discordJoinText": "डिस्कोर्ड में शामिल हों।",
"doneText": "हो गया", "doneText": "हो गया",
"drawText": "बराबर", "drawText": "बराबर",
"duplicateText": "प्रतिलिपि", "duplicateText": "प्रतिलिपि",
@ -750,6 +757,7 @@
"manualYourLocalAddressText": "आपका स्थानीय पता:", "manualYourLocalAddressText": "आपका स्थानीय पता:",
"nearbyText": "आस/पास", "nearbyText": "आस/पास",
"noConnectionText": "<कोई कनेक्शन नहीं है>", "noConnectionText": "<कोई कनेक्शन नहीं है>",
"noPartiesAddedText": "कोई दल नहीं जोड़ा गया",
"otherVersionsText": "(कोई और संस्करण)", "otherVersionsText": "(कोई और संस्करण)",
"partyCodeText": "दल कोड", "partyCodeText": "दल कोड",
"partyInviteAcceptText": "स्वीकार करें", "partyInviteAcceptText": "स्वीकार करें",
@ -1067,6 +1075,7 @@
"noContinuesText": "(कोई जारी रखना नहीं)", "noContinuesText": "(कोई जारी रखना नहीं)",
"noExternalStorageErrorText": "कोई बाहरी संचयन करने कि जगह नहीं मिली", "noExternalStorageErrorText": "कोई बाहरी संचयन करने कि जगह नहीं मिली",
"noGameCircleText": "त्रुटी: गेम-सर्किल में लॉग-इन नहीं हैं |", "noGameCircleText": "त्रुटी: गेम-सर्किल में लॉग-इन नहीं हैं |",
"noPluginsInstalledText": "कोई प्लगइन्स इंस्टॉल नहीं है",
"noProfilesErrorText": "आपकी कोई खिलाड़ी पार्श्वचित्र नहीं है, इसलिए आप '${NAME}' नाम के साथ फंसे हैं |\nसेटिंग -> खिलाड़ी पार्श्वचित्र में जाके अपने लिए पार्श्वचित्र बनायें |", "noProfilesErrorText": "आपकी कोई खिलाड़ी पार्श्वचित्र नहीं है, इसलिए आप '${NAME}' नाम के साथ फंसे हैं |\nसेटिंग -> खिलाड़ी पार्श्वचित्र में जाके अपने लिए पार्श्वचित्र बनायें |",
"noScoresYetText": "अभी तक कोई स्कोर नहीं है |", "noScoresYetText": "अभी तक कोई स्कोर नहीं है |",
"noServersFoundText": "कोई सरवर्स नहीं मिलें।", "noServersFoundText": "कोई सरवर्स नहीं मिलें।",
@ -1280,6 +1289,7 @@
"netTestingText": "नेटवर्क पर परीक्षण", "netTestingText": "नेटवर्क पर परीक्षण",
"resetText": "रीसेट", "resetText": "रीसेट",
"showBombTrajectoriesText": "बोम्ब का पथ दिखाएँ", "showBombTrajectoriesText": "बोम्ब का पथ दिखाएँ",
"showDemosWhenIdleText": "निष्क्रिय होने पर डेमो दिखाएं",
"showDevConsoleButtonText": "डेव कंसोल बटन दिखाएँ", "showDevConsoleButtonText": "डेव कंसोल बटन दिखाएँ",
"showInGamePingText": "गेम पिंग में दिखाएं", "showInGamePingText": "गेम पिंग में दिखाएं",
"showPlayerNamesText": "खिलाड़ी का नाम दिखाएँ", "showPlayerNamesText": "खिलाड़ी का नाम दिखाएँ",
@ -1373,6 +1383,7 @@
"submitText": "जमा करें", "submitText": "जमा करें",
"submittingPromoCodeText": "संहिता जमा कर रहा है ...", "submittingPromoCodeText": "संहिता जमा कर रहा है ...",
"successText": "सफल!", "successText": "सफल!",
"supportEmailText": "यदि आप किसी भी समस्या का सामना कर रहे हैं\nऐप, कृपया ${EMAIL} को ईमेल करें",
"teamNamesColorText": "टीम के नाम / रंग ...", "teamNamesColorText": "टीम के नाम / रंग ...",
"telnetAccessGrantedText": "टेलनेट एक्सेस सक्षम है", "telnetAccessGrantedText": "टेलनेट एक्सेस सक्षम है",
"telnetAccessText": "टेलनेट पहुंच का पता चला; अनुमति देते हैं?", "telnetAccessText": "टेलनेट पहुंच का पता चला; अनुमति देते हैं?",
@ -1826,6 +1837,7 @@
"unlockThisInTheStoreText": "यह स्टोर में अनलॉक होना चाहिए।", "unlockThisInTheStoreText": "यह स्टोर में अनलॉक होना चाहिए।",
"unlockThisProfilesText": "${NUM} प्रोफ़ाइल बनाने के लिए, आपको इसकी आवश्यकता है:", "unlockThisProfilesText": "${NUM} प्रोफ़ाइल बनाने के लिए, आपको इसकी आवश्यकता है:",
"unlockThisText": "इसे अनलॉक करने के लिए, आपको इसकी आवश्यकता है:", "unlockThisText": "इसे अनलॉक करने के लिए, आपको इसकी आवश्यकता है:",
"unsupportedControllerText": "क्षमा करें, नियंत्रक \"${NAME}\" समर्थित नहीं है।",
"unsupportedHardwareText": "क्षमा करें, यह हार्डवेयर गेम के इस निर्माण द्वारा समर्थित नहीं है।", "unsupportedHardwareText": "क्षमा करें, यह हार्डवेयर गेम के इस निर्माण द्वारा समर्थित नहीं है।",
"upFirstText": "सर्व प्रथम", "upFirstText": "सर्व प्रथम",
"upNextText": "गेम ${COUNT} में अगला:", "upNextText": "गेम ${COUNT} में अगला:",
@ -1837,6 +1849,7 @@
"usingItunesText": "गाने के लिए संगीत ऐप का उपयोग कर रहे है ...", "usingItunesText": "गाने के लिए संगीत ऐप का उपयोग कर रहे है ...",
"v2AccountLinkingInfoText": "V2 खातों को लिंक करने के लिए, 'खाता प्रबंधित करें' बटन का उपयोग करें।", "v2AccountLinkingInfoText": "V2 खातों को लिंक करने के लिए, 'खाता प्रबंधित करें' बटन का उपयोग करें।",
"validatingTestBuildText": "परीक्षण निर्माण मान्य ...", "validatingTestBuildText": "परीक्षण निर्माण मान्य ...",
"viaText": "के जरिए",
"victoryText": "विजय!", "victoryText": "विजय!",
"voteDelayText": "आप ${NUMBER} सेकंड के लिए एक और वोट शुरू नहीं कर सकते हैं", "voteDelayText": "आप ${NUMBER} सेकंड के लिए एक और वोट शुरू नहीं कर सकते हैं",
"voteInProgressText": "एक वोट पहले ही प्रगति पर है।", "voteInProgressText": "एक वोट पहले ही प्रगति पर है।",

View file

@ -335,6 +335,8 @@
"getMoreGamesText": "Game Lain...", "getMoreGamesText": "Game Lain...",
"titleText": "Tambah Game" "titleText": "Tambah Game"
}, },
"addToFavoritesText": "Tambahkan ke Favorit",
"addedToFavoritesText": "Tambah '${NAME}' ke dalam Favorit",
"allText": "Semua", "allText": "Semua",
"allowText": "Izinkan", "allowText": "Izinkan",
"alreadySignedInText": "Akunmu telah masuk di perangkat lain;\nSilakan beralih akun atau menutup permainanmu \ndi perangkat lain dan coba lagi.", "alreadySignedInText": "Akunmu telah masuk di perangkat lain;\nSilakan beralih akun atau menutup permainanmu \ndi perangkat lain dan coba lagi.",
@ -563,6 +565,8 @@
"disableXInputDescriptionText": "Izinkan lebih dari 4 pengontrol tapi mungkin agak lemot.", "disableXInputDescriptionText": "Izinkan lebih dari 4 pengontrol tapi mungkin agak lemot.",
"disableXInputText": "Blokir XInput", "disableXInputText": "Blokir XInput",
"disabledText": "Dimatikan", "disabledText": "Dimatikan",
"discordFriendsText": "Ingin mencari teman baru untuk bermain?\nGabung ke Discord kami dan temukan teman baru kamu!",
"discordJoinText": "Gabung ke Discord",
"doneText": "Selesai", "doneText": "Selesai",
"drawText": "Seri", "drawText": "Seri",
"duplicateText": "Duplikat", "duplicateText": "Duplikat",
@ -748,6 +752,7 @@
"manualYourLocalAddressText": "Alamat lokal Kamu:", "manualYourLocalAddressText": "Alamat lokal Kamu:",
"nearbyText": "Dekat", "nearbyText": "Dekat",
"noConnectionText": "<tidak ada koneksi>", "noConnectionText": "<tidak ada koneksi>",
"noPartiesAddedText": "Tidak ada Acara yang Ditambahkan",
"otherVersionsText": "(Versi lain)", "otherVersionsText": "(Versi lain)",
"partyCodeText": "Kode Acara", "partyCodeText": "Kode Acara",
"partyInviteAcceptText": "Terima", "partyInviteAcceptText": "Terima",
@ -1064,6 +1069,7 @@
"noContinuesText": "(tidak dapat melanjutkan)", "noContinuesText": "(tidak dapat melanjutkan)",
"noExternalStorageErrorText": "Tidak ada penyimpanan eksternal", "noExternalStorageErrorText": "Tidak ada penyimpanan eksternal",
"noGameCircleText": "Kesalahan: tidak masuk ke LingkaranGame", "noGameCircleText": "Kesalahan: tidak masuk ke LingkaranGame",
"noPluginsInstalledText": "Tidak ada plugin yang terinstal",
"noProfilesErrorText": "Kamu tidak punya profil pemain, jadi '${NAME}' dipakai. \nMasuk Pengaturan->Profil Pemain untuk membuat profil. ", "noProfilesErrorText": "Kamu tidak punya profil pemain, jadi '${NAME}' dipakai. \nMasuk Pengaturan->Profil Pemain untuk membuat profil. ",
"noScoresYetText": "Belum ada skor.", "noScoresYetText": "Belum ada skor.",
"noServersFoundText": "Server tidak ditemukan.", "noServersFoundText": "Server tidak ditemukan.",
@ -1277,6 +1283,7 @@
"netTestingText": "Tes Jaringan", "netTestingText": "Tes Jaringan",
"resetText": "Atur ulang", "resetText": "Atur ulang",
"showBombTrajectoriesText": "Lihat Lintasan Bom", "showBombTrajectoriesText": "Lihat Lintasan Bom",
"showDemosWhenIdleText": "Tampilkan Demo saat tidak bergerak",
"showDevConsoleButtonText": "Tampilkan tombol Dev Console", "showDevConsoleButtonText": "Tampilkan tombol Dev Console",
"showInGamePingText": "Tampilkan Ping dalam permainan", "showInGamePingText": "Tampilkan Ping dalam permainan",
"showPlayerNamesText": "Tunjukkan Nama Pemain", "showPlayerNamesText": "Tunjukkan Nama Pemain",

View file

@ -1339,6 +1339,7 @@
"netTestingText": "Collaudo Rete", "netTestingText": "Collaudo Rete",
"resetText": "Reset", "resetText": "Reset",
"showBombTrajectoriesText": "Mostra le traiettorie delle bombe", "showBombTrajectoriesText": "Mostra le traiettorie delle bombe",
"showDemosWhenIdleText": "Riproduci Demo All'Inattività",
"showDevConsoleButtonText": "mostra tasto console sviluppatore", "showDevConsoleButtonText": "mostra tasto console sviluppatore",
"showInGamePingText": "Mostra il Ping in gioco", "showInGamePingText": "Mostra il Ping in gioco",
"showPlayerNamesText": "Mostra i nomi dei giocatori", "showPlayerNamesText": "Mostra i nomi dei giocatori",

View file

@ -336,6 +336,8 @@
"getMoreGamesText": "다른 게임 보기...", "getMoreGamesText": "다른 게임 보기...",
"titleText": "게임 추가" "titleText": "게임 추가"
}, },
"addToFavoritesText": "즐겨찾기에 추가하기",
"addedToFavoritesText": "즐겨찾기에 '${NAME}'을 추가했습니다.",
"allText": "모두", "allText": "모두",
"allowText": "허용", "allowText": "허용",
"alreadySignedInText": "귀하의 계정은 다른 기기에서 로그인되었습니다. \n계정을 전환하거나 다른 기기에서 게임을 종료하고 \n다시 시도하십시오.", "alreadySignedInText": "귀하의 계정은 다른 기기에서 로그인되었습니다. \n계정을 전환하거나 다른 기기에서 게임을 종료하고 \n다시 시도하십시오.",
@ -751,6 +753,7 @@
"manualYourLocalAddressText": "귀하의 로컬 주소:", "manualYourLocalAddressText": "귀하의 로컬 주소:",
"nearbyText": "근처", "nearbyText": "근처",
"noConnectionText": "<연결 없음>", "noConnectionText": "<연결 없음>",
"noPartiesAddedText": "추가한 파티 없음",
"otherVersionsText": "(다른 버전)", "otherVersionsText": "(다른 버전)",
"partyCodeText": "파티 코드", "partyCodeText": "파티 코드",
"partyInviteAcceptText": "수락", "partyInviteAcceptText": "수락",
@ -1065,6 +1068,7 @@
"noContinuesText": "(계속 없음)", "noContinuesText": "(계속 없음)",
"noExternalStorageErrorText": "이 기기에서 외부 저장소를 찾지 못했습니다.", "noExternalStorageErrorText": "이 기기에서 외부 저장소를 찾지 못했습니다.",
"noGameCircleText": "오류: GameCircle에 로그인되지 않았습니다", "noGameCircleText": "오류: GameCircle에 로그인되지 않았습니다",
"noPluginsInstalledText": "설치된 플러그인 없음",
"noScoresYetText": "아직 점수 없음.", "noScoresYetText": "아직 점수 없음.",
"noServersFoundText": "서버를 찾을수 없음.", "noServersFoundText": "서버를 찾을수 없음.",
"noThanksText": "아니요", "noThanksText": "아니요",
@ -1276,6 +1280,7 @@
"netTestingText": "네트워크 테스트", "netTestingText": "네트워크 테스트",
"resetText": "재설정", "resetText": "재설정",
"showBombTrajectoriesText": "폭탄 궤적 표시", "showBombTrajectoriesText": "폭탄 궤적 표시",
"showDemosWhenIdleText": "유휴 상태일 때 데모 표시",
"showDevConsoleButtonText": "개발자 콘솔 버튼 보이기", "showDevConsoleButtonText": "개발자 콘솔 버튼 보이기",
"showInGamePingText": "인게임 핑 보이기", "showInGamePingText": "인게임 핑 보이기",
"showPlayerNamesText": "플레이어 이름 표시", "showPlayerNamesText": "플레이어 이름 표시",

View file

@ -1281,6 +1281,7 @@
"netTestingText": "تست شبکه", "netTestingText": "تست شبکه",
"resetText": "باز گرداندن", "resetText": "باز گرداندن",
"showBombTrajectoriesText": "نمایش خط سیر بمب", "showBombTrajectoriesText": "نمایش خط سیر بمب",
"showDemosWhenIdleText": "نشان دادن دمو ها در وقت بیکاری",
"showDevConsoleButtonText": "نشان دادن دکمه توسعه دهنده کنسول", "showDevConsoleButtonText": "نشان دادن دکمه توسعه دهنده کنسول",
"showInGamePingText": "نمایش پینگ در بازی", "showInGamePingText": "نمایش پینگ در بازی",
"showPlayerNamesText": "نمایش نام بازیکنان", "showPlayerNamesText": "نمایش نام بازیکنان",

View file

@ -340,6 +340,8 @@
"getMoreGamesText": "Mais jogos...", "getMoreGamesText": "Mais jogos...",
"titleText": "Adicionar jogo" "titleText": "Adicionar jogo"
}, },
"addToFavoritesText": "Adicionar aos Favoritos",
"addedToFavoritesText": "Adicionou '${NAME}' aos Favoritos.",
"allText": "Tudo", "allText": "Tudo",
"allowText": "Permitir", "allowText": "Permitir",
"alreadySignedInText": "A conta tem sessão iniciada em outro dispositivo;\nMude de conta ou feche o jogo no seu\noutro dispositivo e tente novamente.", "alreadySignedInText": "A conta tem sessão iniciada em outro dispositivo;\nMude de conta ou feche o jogo no seu\noutro dispositivo e tente novamente.",
@ -788,6 +790,7 @@
"manualYourLocalAddressText": "Seu endereço local:", "manualYourLocalAddressText": "Seu endereço local:",
"nearbyText": "Próximo", "nearbyText": "Próximo",
"noConnectionText": "<sem conexão>", "noConnectionText": "<sem conexão>",
"noPartiesAddedText": "Nenhum grupo adicionado",
"otherVersionsText": "(outras versões)", "otherVersionsText": "(outras versões)",
"partyCodeText": "Código da Sala", "partyCodeText": "Código da Sala",
"partyInviteAcceptText": "Aceitar", "partyInviteAcceptText": "Aceitar",
@ -1134,6 +1137,7 @@
"noExternalStorageErrorText": "Armazenamento externo não encontrado", "noExternalStorageErrorText": "Armazenamento externo não encontrado",
"noGameCircleText": "Erro: não conectado no GameCircle", "noGameCircleText": "Erro: não conectado no GameCircle",
"noJoinCoopMidwayText": "Jogos cooperativos não podem ser afiliados no meio do caminho.", "noJoinCoopMidwayText": "Jogos cooperativos não podem ser afiliados no meio do caminho.",
"noPluginsInstalledText": "Nenhum Plugin instalado",
"noProfilesErrorText": "Você não tem perfis de jogadores, então você está preso com '${NAME}'.\nVá para Configurações->Perfis de Jogador para criar um perfil.", "noProfilesErrorText": "Você não tem perfis de jogadores, então você está preso com '${NAME}'.\nVá para Configurações->Perfis de Jogador para criar um perfil.",
"noScoresYetText": "Ainda sem pontuação.", "noScoresYetText": "Ainda sem pontuação.",
"noServersFoundText": "Servidores não encontrados.", "noServersFoundText": "Servidores não encontrados.",
@ -1363,6 +1367,7 @@
"netTestingText": "Teste de conexão", "netTestingText": "Teste de conexão",
"resetText": "Redefinir", "resetText": "Redefinir",
"showBombTrajectoriesText": "Mostrar trajetórias da bomba", "showBombTrajectoriesText": "Mostrar trajetórias da bomba",
"showDemosWhenIdleText": "Mostrar demonstrações quando ocioso",
"showDevConsoleButtonText": "Mostrar console de desenvolvedor", "showDevConsoleButtonText": "Mostrar console de desenvolvedor",
"showInGamePingText": "Mostrar latência no jogo", "showInGamePingText": "Mostrar latência no jogo",
"showPlayerNamesText": "Mostrar nomes dos jogadores", "showPlayerNamesText": "Mostrar nomes dos jogadores",

View file

@ -341,6 +341,8 @@
"getMoreGamesText": "Еще игры", "getMoreGamesText": "Еще игры",
"titleText": "Добавить игру" "titleText": "Добавить игру"
}, },
"addToFavoritesText": "Добавить в избранное",
"addedToFavoritesText": "Добавлен '${NAME}' в избранное.",
"allText": "Все", "allText": "Все",
"allowText": "Разрешить", "allowText": "Разрешить",
"alreadySignedInText": "С вашего аккаунта играют на другом устройстве;\nпожалуйста зайдите с другого аккаунта или закройте\nигру на другом устройстве и попытайтесь снова.", "alreadySignedInText": "С вашего аккаунта играют на другом устройстве;\nпожалуйста зайдите с другого аккаунта или закройте\nигру на другом устройстве и попытайтесь снова.",
@ -783,6 +785,7 @@
"manualYourLocalAddressText": "Ваш локальный адрес:", "manualYourLocalAddressText": "Ваш локальный адрес:",
"nearbyText": "Поблизости", "nearbyText": "Поблизости",
"noConnectionText": "<нет соединения>", "noConnectionText": "<нет соединения>",
"noPartiesAddedText": "Вечеринки не добавлены",
"otherVersionsText": "(другие версии)", "otherVersionsText": "(другие версии)",
"partyCodeText": "Код лобби", "partyCodeText": "Код лобби",
"partyInviteAcceptText": "Принять", "partyInviteAcceptText": "Принять",
@ -1117,6 +1120,7 @@
"noExternalStorageErrorText": "На данном устройстве не найдено внешней памяти", "noExternalStorageErrorText": "На данном устройстве не найдено внешней памяти",
"noGameCircleText": "Ошибка: не вошли в GameCircle", "noGameCircleText": "Ошибка: не вошли в GameCircle",
"noJoinCoopMidwayText": "К кооперативным играм нельзя присоединиться посреди игры.", "noJoinCoopMidwayText": "К кооперативным играм нельзя присоединиться посреди игры.",
"noPluginsInstalledText": "Плагины не установлены",
"noProfilesErrorText": "У вас нет профиля игрока, так что вас будут звать '${NAME}'.\nСоздать профиль можно перейдя в 'Настройки' > 'Профили игроков'.", "noProfilesErrorText": "У вас нет профиля игрока, так что вас будут звать '${NAME}'.\nСоздать профиль можно перейдя в 'Настройки' > 'Профили игроков'.",
"noScoresYetText": "Счета пока нет.", "noScoresYetText": "Счета пока нет.",
"noServersFoundText": "Серверы не найдены.", "noServersFoundText": "Серверы не найдены.",
@ -1339,6 +1343,7 @@
"netTestingText": "Тестирование сети", "netTestingText": "Тестирование сети",
"resetText": "Сбросить", "resetText": "Сбросить",
"showBombTrajectoriesText": "Показывать траекторию бомбы", "showBombTrajectoriesText": "Показывать траекторию бомбы",
"showDemosWhenIdleText": "Показывать демоверсии в режиме ожидания",
"showDevConsoleButtonText": "Показать кнопку консоли", "showDevConsoleButtonText": "Показать кнопку консоли",
"showInGamePingText": "Показать Ping", "showInGamePingText": "Показать Ping",
"showPlayerNamesText": "Показывать имена игроков", "showPlayerNamesText": "Показывать имена игроков",

View file

@ -128,7 +128,7 @@
}, },
"Mine Games": { "Mine Games": {
"description": "Mata a 3 chicos malos con minas terrestres", "description": "Mata a 3 chicos malos con minas terrestres",
"descriptionComplete": "Mató a 3 enemigos con minas terrestres", "descriptionComplete": "Mató a 3 chicos malos con minas terrestres",
"descriptionFull": "Mata a 3 chicos malos con minas terrestres en ${LEVEL}", "descriptionFull": "Mata a 3 chicos malos con minas terrestres en ${LEVEL}",
"descriptionFullComplete": "Mató a 3 chicos con minas terrestres en ${LEVEL}", "descriptionFullComplete": "Mató a 3 chicos con minas terrestres en ${LEVEL}",
"name": "Juegos De Minas" "name": "Juegos De Minas"
@ -1107,7 +1107,7 @@
"modeClassicText": "Modo Clásico", "modeClassicText": "Modo Clásico",
"modeDemoText": "Modo Demo", "modeDemoText": "Modo Demo",
"mostValuablePlayerText": "Jugador Más Valioso", "mostValuablePlayerText": "Jugador Más Valioso",
"mostViolatedPlayerText": "Jugador Más Violado", "mostViolatedPlayerText": "Jugador Más Agredido",
"mostViolentPlayerText": "Jugador Más Violento", "mostViolentPlayerText": "Jugador Más Violento",
"moveText": "Mover", "moveText": "Mover",
"multiKillText": "¡¡¡COMBO DE ${COUNT}!!!", "multiKillText": "¡¡¡COMBO DE ${COUNT}!!!",
@ -1208,11 +1208,11 @@
"playlistsText": "Listas de juegos", "playlistsText": "Listas de juegos",
"pleaseRateText": "Si te gusta ${APP_NAME}, por favor tomate un momento\npara calificar o escribir una reseña. Esto proporcionará\ninformación útil y ayuda al soporte del futuro desarrollo del juego.\n\n¡gracias!\n-eric", "pleaseRateText": "Si te gusta ${APP_NAME}, por favor tomate un momento\npara calificar o escribir una reseña. Esto proporcionará\ninformación útil y ayuda al soporte del futuro desarrollo del juego.\n\n¡gracias!\n-eric",
"pleaseWaitText": "Por favor, espera...", "pleaseWaitText": "Por favor, espera...",
"pluginClassLoadErrorText": "Error cargando la clase del complemento '${PLUGIN}': ${ERROR}", "pluginClassLoadErrorText": "Error cargando el complemento '${PLUGIN}': ${ERROR}",
"pluginInitErrorText": "Error iniciando complemento '${PLUGIN}': ${ERROR}", "pluginInitErrorText": "Error iniciando complemento '${PLUGIN}': ${ERROR}",
"pluginSettingsText": "Ajustes De Complementos", "pluginSettingsText": "Ajustes De Complementos",
"pluginsAutoEnableNewText": "Auto Habilitar Nuevos Complementos", "pluginsAutoEnableNewText": "Auto Habilitar Nuevos Complementos",
"pluginsDetectedText": "Nuevo(s) complemento(s) detectado(s). Reinicie para activarlo(s), o configuralo(s) en ajustes.", "pluginsDetectedText": "Complemento detectado(s). Reinicia el juego, o ve a ajustes para configurarlo.",
"pluginsDisableAllText": "Deshabilitar Todos Los Complementos", "pluginsDisableAllText": "Deshabilitar Todos Los Complementos",
"pluginsEnableAllText": "Habilitar Todos Los Complementos", "pluginsEnableAllText": "Habilitar Todos Los Complementos",
"pluginsRemovedText": "${NUM} complemento(s) ya no se encuentra(n).", "pluginsRemovedText": "${NUM} complemento(s) ya no se encuentra(n).",
@ -1360,6 +1360,7 @@
"netTestingText": "Prueba De Red", "netTestingText": "Prueba De Red",
"resetText": "Reiniciar", "resetText": "Reiniciar",
"showBombTrajectoriesText": "Mostrar Trayectorias De Las Bombas", "showBombTrajectoriesText": "Mostrar Trayectorias De Las Bombas",
"showDemosWhenIdleText": "Mostrar demostraciones cuando esté inactivo",
"showDevConsoleButtonText": "Mostrar Botón de Consola de Desarrollador", "showDevConsoleButtonText": "Mostrar Botón de Consola de Desarrollador",
"showInGamePingText": "Mostrar Ping En El Juego", "showInGamePingText": "Mostrar Ping En El Juego",
"showPlayerNamesText": "Mostrar Nombres De Los Jugadores", "showPlayerNamesText": "Mostrar Nombres De Los Jugadores",

View file

@ -334,6 +334,8 @@
"getMoreGamesText": "รับเกมเพิ่มเติม", "getMoreGamesText": "รับเกมเพิ่มเติม",
"titleText": "เพิ่มเกม" "titleText": "เพิ่มเกม"
}, },
"addToFavoritesText": "เพื่มในรายการโปรด",
"addedToFavoritesText": "เพื่ม '${NAME}' ในรายการโปรดแล้ว",
"allText": "ทั้งหมด", "allText": "ทั้งหมด",
"allowText": "ยอมรับ", "allowText": "ยอมรับ",
"alreadySignedInText": "บัญชีของคุณลงชื่อเข้าใช้จากอุปกรณ์อื่น\nโปรดเปลี่ยนบัญชีหรือปิดเกมของคุณ\nอุปกรณ์อื่นและลองอีกครั้ง", "alreadySignedInText": "บัญชีของคุณลงชื่อเข้าใช้จากอุปกรณ์อื่น\nโปรดเปลี่ยนบัญชีหรือปิดเกมของคุณ\nอุปกรณ์อื่นและลองอีกครั้ง",

View file

@ -335,6 +335,8 @@
"getMoreGamesText": "Daha Çok Oyun...", "getMoreGamesText": "Daha Çok Oyun...",
"titleText": "Oyun Ekle" "titleText": "Oyun Ekle"
}, },
"addToFavoritesText": "Favorilere ekle",
"addedToFavoritesText": "'${NAME}' Favorilere eklendi.",
"allText": "Hepsi", "allText": "Hepsi",
"allowText": "Kabul Et", "allowText": "Kabul Et",
"alreadySignedInText": "Başka bir cihazda hesabına giriş yapılmış;\nlütfen hesapları değiştir ya da diğer cihazlardaki\noyunu kapat ve tekrar dene.", "alreadySignedInText": "Başka bir cihazda hesabına giriş yapılmış;\nlütfen hesapları değiştir ya da diğer cihazlardaki\noyunu kapat ve tekrar dene.",
@ -751,6 +753,7 @@
"manualYourLocalAddressText": "Yerel adresiniz:", "manualYourLocalAddressText": "Yerel adresiniz:",
"nearbyText": "Yakında", "nearbyText": "Yakında",
"noConnectionText": "<bağlantı yok>", "noConnectionText": "<bağlantı yok>",
"noPartiesAddedText": "Parti Eklenmedi",
"otherVersionsText": "(diğer sürümler)", "otherVersionsText": "(diğer sürümler)",
"partyCodeText": "Parti kodu", "partyCodeText": "Parti kodu",
"partyInviteAcceptText": "Kabul Et", "partyInviteAcceptText": "Kabul Et",
@ -1065,6 +1068,7 @@
"noContinuesText": "(sürdürülemiyor)", "noContinuesText": "(sürdürülemiyor)",
"noExternalStorageErrorText": "Bu cihazda harici depolama bulunamadı", "noExternalStorageErrorText": "Bu cihazda harici depolama bulunamadı",
"noGameCircleText": "Hata: GameCircle girişi yapılamadı", "noGameCircleText": "Hata: GameCircle girişi yapılamadı",
"noPluginsInstalledText": "Yüklü Eklenti Yok",
"noScoresYetText": "Henüz skor yok.", "noScoresYetText": "Henüz skor yok.",
"noServersFoundText": "Sunucu Bulunamadı.", "noServersFoundText": "Sunucu Bulunamadı.",
"noThanksText": "Hayır Teşekkürler", "noThanksText": "Hayır Teşekkürler",
@ -1276,6 +1280,7 @@
"netTestingText": "Ağ Testi", "netTestingText": "Ağ Testi",
"resetText": "Sıfırla", "resetText": "Sıfırla",
"showBombTrajectoriesText": "Bomba Gidişatını Göster", "showBombTrajectoriesText": "Bomba Gidişatını Göster",
"showDemosWhenIdleText": "Boşta İken Demolar Göster",
"showDevConsoleButtonText": "Geliştirici panelini aç", "showDevConsoleButtonText": "Geliştirici panelini aç",
"showInGamePingText": "Oyun İçinde Gecikmeyi Göster", "showInGamePingText": "Oyun İçinde Gecikmeyi Göster",
"showPlayerNamesText": "Oyuncu Adlarını Göster", "showPlayerNamesText": "Oyuncu Adlarını Göster",

View file

@ -337,6 +337,8 @@
"getMoreGamesText": "Ще ігри...", "getMoreGamesText": "Ще ігри...",
"titleText": "Додати гру" "titleText": "Додати гру"
}, },
"addToFavoritesText": "Додати в обране",
"addedToFavoritesText": "Додано '${NAME}' до вибраного.",
"allText": "Все", "allText": "Все",
"allowText": "Дозволити", "allowText": "Дозволити",
"alreadySignedInText": "На вашому акаунті грають на іншому пристрої;\nбудь ласка зайдіть з іншого акаунта або закрийте гру на\nіншому пристрої та спробуйте знову.", "alreadySignedInText": "На вашому акаунті грають на іншому пристрої;\nбудь ласка зайдіть з іншого акаунта або закрийте гру на\nіншому пристрої та спробуйте знову.",
@ -370,6 +372,7 @@
"chatMutedText": "Чат приглушений", "chatMutedText": "Чат приглушений",
"chatUnMuteText": "Включити чат", "chatUnMuteText": "Включити чат",
"choosingPlayerText": "<вибір гравця>", "choosingPlayerText": "<вибір гравця>",
"codesExplainText": "Розробник надає коди для діагностики та\nусунення проблем з обліковим записом.",
"completeThisLevelToProceedText": "Щоб продовжити, потрібно\nпройти цей рівень!", "completeThisLevelToProceedText": "Щоб продовжити, потрібно\nпройти цей рівень!",
"completionBonusText": "Бонус за проходження", "completionBonusText": "Бонус за проходження",
"configControllersWindow": { "configControllersWindow": {
@ -564,6 +567,8 @@
"disableXInputDescriptionText": "Підключення більше 4 контролерів, але може не працювати.", "disableXInputDescriptionText": "Підключення більше 4 контролерів, але може не працювати.",
"disableXInputText": "Відключити XInput", "disableXInputText": "Відключити XInput",
"disabledText": "Виключено", "disabledText": "Виключено",
"discordFriendsText": "Хочете шукати нових людей для гри?\nПриєднуйтесь до нашого Discord і знайдіть нових друзів!",
"discordJoinText": "Приєднуйтесь до Discord",
"doneText": "Готово", "doneText": "Готово",
"drawText": "Нічия", "drawText": "Нічия",
"duplicateText": "Дублювати", "duplicateText": "Дублювати",
@ -749,6 +754,7 @@
"manualYourLocalAddressText": "Ваш локальний адрес:", "manualYourLocalAddressText": "Ваш локальний адрес:",
"nearbyText": "Поблизу", "nearbyText": "Поблизу",
"noConnectionText": "<немає з'єднання>", "noConnectionText": "<немає з'єднання>",
"noPartiesAddedText": "Партії не додано",
"otherVersionsText": "(інші версії)", "otherVersionsText": "(інші версії)",
"partyCodeText": "Код групи", "partyCodeText": "Код групи",
"partyInviteAcceptText": "Прийняти", "partyInviteAcceptText": "Прийняти",
@ -1063,6 +1069,7 @@
"noContinuesText": "(без продовжень)", "noContinuesText": "(без продовжень)",
"noExternalStorageErrorText": "На цьому пристрої не знайдено зовнішньої пам'яті", "noExternalStorageErrorText": "На цьому пристрої не знайдено зовнішньої пам'яті",
"noGameCircleText": "Помилка: не ввійшли в GameCircle", "noGameCircleText": "Помилка: не ввійшли в GameCircle",
"noPluginsInstalledText": "Плагіни не встановлено",
"noScoresYetText": "Рахунка поки немає.", "noScoresYetText": "Рахунка поки немає.",
"noServersFoundText": "Серверів не знайдено", "noServersFoundText": "Серверів не знайдено",
"noThanksText": "Ні дякую", "noThanksText": "Ні дякую",
@ -1367,6 +1374,7 @@
"submitText": "Відправити", "submitText": "Відправити",
"submittingPromoCodeText": "Активація коду...", "submittingPromoCodeText": "Активація коду...",
"successText": "Успішно!", "successText": "Успішно!",
"supportEmailText": "Якщо у вас виникли проблеми з програмою,\nнадішліть електронний лист на ${EMAIL}.",
"teamNamesColorText": "імена/кольори команд", "teamNamesColorText": "імена/кольори команд",
"telnetAccessGrantedText": "Доступ Telnet включений.", "telnetAccessGrantedText": "Доступ Telnet включений.",
"telnetAccessText": "Виявлено доступ Telnet. Дозволити?", "telnetAccessText": "Виявлено доступ Telnet. Дозволити?",
@ -1833,6 +1841,7 @@
"usingItunesTurnRepeatAndShuffleOnText": "Будь ласка, переконайтеся, що випадковий порядок і повтор усіх пісень включений в Itunes.", "usingItunesTurnRepeatAndShuffleOnText": "Будь ласка, переконайтеся, що випадковий порядок і повтор усіх пісень включений в Itunes.",
"v2AccountLinkingInfoText": "Щоб підключити V2-акаунти, використовуйте кнопку 'Керування акаунтом'.", "v2AccountLinkingInfoText": "Щоб підключити V2-акаунти, використовуйте кнопку 'Керування акаунтом'.",
"validatingTestBuildText": "Перевірка тестової збірки...", "validatingTestBuildText": "Перевірка тестової збірки...",
"viaText": "через",
"victoryText": "Перемога!", "victoryText": "Перемога!",
"voteDelayText": "Ви зможете почати голосування через ${NUMBER} секунд", "voteDelayText": "Ви зможете почати голосування через ${NUMBER} секунд",
"voteInProgressText": "Голосування ще триває.", "voteInProgressText": "Голосування ще триває.",

View file

@ -333,6 +333,8 @@
"getMoreGamesText": "Otien pì łevełi...", "getMoreGamesText": "Otien pì łevełi...",
"titleText": "Zonta zugo" "titleText": "Zonta zugo"
}, },
"addToFavoritesText": "Zonta so i prefarìi",
"addedToFavoritesText": "'${NAME}' zontà so i prefarìi.",
"allText": "Tuto", "allText": "Tuto",
"allowText": "Parmeti", "allowText": "Parmeti",
"alreadySignedInText": "El to account el ze in dòparo inte nantro\ndispozidivo: canbia account o sara sù el zugo\ninte chełaltro to dispozidivo e proa danovo.", "alreadySignedInText": "El to account el ze in dòparo inte nantro\ndispozidivo: canbia account o sara sù el zugo\ninte chełaltro to dispozidivo e proa danovo.",
@ -748,6 +750,7 @@
"manualYourLocalAddressText": "El to ndariso łogałe:", "manualYourLocalAddressText": "El to ndariso łogałe:",
"nearbyText": "Łogałe", "nearbyText": "Łogałe",
"noConnectionText": "<gnauna conesion>", "noConnectionText": "<gnauna conesion>",
"noPartiesAddedText": "Gnaun grupo zontà",
"otherVersionsText": "(par altre varsion)", "otherVersionsText": "(par altre varsion)",
"partyCodeText": "Còdaze de'l grupo", "partyCodeText": "Còdaze de'l grupo",
"partyInviteAcceptText": "Và ben", "partyInviteAcceptText": "Và ben",
@ -1062,6 +1065,7 @@
"noContinuesText": "(sensa continui)", "noContinuesText": "(sensa continui)",
"noExternalStorageErrorText": "So sto dispozidivo no ze stà catada gnauna memoria esterna", "noExternalStorageErrorText": "So sto dispozidivo no ze stà catada gnauna memoria esterna",
"noGameCircleText": "Eror: no te si miga conetesto co GameCircle", "noGameCircleText": "Eror: no te si miga conetesto co GameCircle",
"noPluginsInstalledText": "Gnauna estension instałada",
"noScoresYetText": "Gnancora gnaun puntejo.", "noScoresYetText": "Gnancora gnaun puntejo.",
"noServersFoundText": "Gnaun server catà.", "noServersFoundText": "Gnaun server catà.",
"noThanksText": "Nò, grasie", "noThanksText": "Nò, grasie",

View file

@ -86,6 +86,7 @@ __all__ = [
'TYPE_CHECKING', 'TYPE_CHECKING',
'Never', 'Never',
'NoReturn', 'NoReturn',
'ReadOnly',
'Required', 'Required',
'NotRequired', 'NotRequired',
@ -473,6 +474,7 @@ _EXCLUDED_ATTRS = {
"__orig_bases__", "__module__", "_MutableMapping__marker", "__doc__", "__orig_bases__", "__module__", "_MutableMapping__marker", "__doc__",
"__subclasshook__", "__orig_class__", "__init__", "__new__", "__subclasshook__", "__orig_class__", "__init__", "__new__",
"__protocol_attrs__", "__callable_proto_members_only__", "__protocol_attrs__", "__callable_proto_members_only__",
"__match_args__",
} }
if sys.version_info >= (3, 9): if sys.version_info >= (3, 9):
@ -503,9 +505,9 @@ def _caller(depth=2):
return None return None
# The performance of runtime-checkable protocols is significantly improved on Python 3.12, # `__match_args__` attribute was removed from protocol members in 3.13,
# so we backport the 3.12 version of Protocol to Python <=3.11 # we want to backport this change to older Python versions.
if sys.version_info >= (3, 12): if sys.version_info >= (3, 13):
Protocol = typing.Protocol Protocol = typing.Protocol
else: else:
def _allow_reckless_class_checks(depth=3): def _allow_reckless_class_checks(depth=3):
@ -569,8 +571,13 @@ else:
not cls.__callable_proto_members_only__ not cls.__callable_proto_members_only__
and cls.__dict__.get("__subclasshook__") is _proto_hook and cls.__dict__.get("__subclasshook__") is _proto_hook
): ):
non_method_attrs = sorted(
attr for attr in cls.__protocol_attrs__
if not callable(getattr(cls, attr, None))
)
raise TypeError( raise TypeError(
"Protocols with non-method members don't support issubclass()" "Protocols with non-method members don't support issubclass()."
f" Non-method members: {str(non_method_attrs)[1:-1]}."
) )
if not getattr(cls, '_is_runtime_protocol', False): if not getattr(cls, '_is_runtime_protocol', False):
raise TypeError( raise TypeError(
@ -767,7 +774,7 @@ def _ensure_subclassable(mro_entries):
return inner return inner
if sys.version_info >= (3, 13): if hasattr(typing, "ReadOnly"):
# The standard library TypedDict in Python 3.8 does not store runtime information # The standard library TypedDict in Python 3.8 does not store runtime information
# about which (if any) keys are optional. See https://bugs.python.org/issue38834 # about which (if any) keys are optional. See https://bugs.python.org/issue38834
# The standard library TypedDict in Python 3.9.0/1 does not honour the "total" # The standard library TypedDict in Python 3.9.0/1 does not honour the "total"
@ -778,6 +785,7 @@ if sys.version_info >= (3, 13):
# Aaaand on 3.12 we add __orig_bases__ to TypedDict # Aaaand on 3.12 we add __orig_bases__ to TypedDict
# to enable better runtime introspection. # to enable better runtime introspection.
# On 3.13 we deprecate some odd ways of creating TypedDicts. # On 3.13 we deprecate some odd ways of creating TypedDicts.
# PEP 705 proposes adding the ReadOnly[] qualifier.
TypedDict = typing.TypedDict TypedDict = typing.TypedDict
_TypedDictMeta = typing._TypedDictMeta _TypedDictMeta = typing._TypedDictMeta
is_typeddict = typing.is_typeddict is_typeddict = typing.is_typeddict
@ -785,8 +793,29 @@ else:
# 3.10.0 and later # 3.10.0 and later
_TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters
def _get_typeddict_qualifiers(annotation_type):
while True:
annotation_origin = get_origin(annotation_type)
if annotation_origin is Annotated:
annotation_args = get_args(annotation_type)
if annotation_args:
annotation_type = annotation_args[0]
else:
break
elif annotation_origin is Required:
yield Required
annotation_type, = get_args(annotation_type)
elif annotation_origin is NotRequired:
yield NotRequired
annotation_type, = get_args(annotation_type)
elif annotation_origin is ReadOnly:
yield ReadOnly
annotation_type, = get_args(annotation_type)
else:
break
class _TypedDictMeta(type): class _TypedDictMeta(type):
def __new__(cls, name, bases, ns, total=True): def __new__(cls, name, bases, ns, *, total=True):
"""Create new typed dict class object. """Create new typed dict class object.
This method is called when TypedDict is subclassed, This method is called when TypedDict is subclassed,
@ -829,33 +858,46 @@ else:
} }
required_keys = set() required_keys = set()
optional_keys = set() optional_keys = set()
readonly_keys = set()
mutable_keys = set()
for base in bases: for base in bases:
annotations.update(base.__dict__.get('__annotations__', {})) base_dict = base.__dict__
required_keys.update(base.__dict__.get('__required_keys__', ()))
optional_keys.update(base.__dict__.get('__optional_keys__', ())) annotations.update(base_dict.get('__annotations__', {}))
required_keys.update(base_dict.get('__required_keys__', ()))
optional_keys.update(base_dict.get('__optional_keys__', ()))
readonly_keys.update(base_dict.get('__readonly_keys__', ()))
mutable_keys.update(base_dict.get('__mutable_keys__', ()))
annotations.update(own_annotations) annotations.update(own_annotations)
for annotation_key, annotation_type in own_annotations.items(): for annotation_key, annotation_type in own_annotations.items():
annotation_origin = get_origin(annotation_type) qualifiers = set(_get_typeddict_qualifiers(annotation_type))
if annotation_origin is Annotated:
annotation_args = get_args(annotation_type)
if annotation_args:
annotation_type = annotation_args[0]
annotation_origin = get_origin(annotation_type)
if annotation_origin is Required: if Required in qualifiers:
required_keys.add(annotation_key) required_keys.add(annotation_key)
elif annotation_origin is NotRequired: elif NotRequired in qualifiers:
optional_keys.add(annotation_key) optional_keys.add(annotation_key)
elif total: elif total:
required_keys.add(annotation_key) required_keys.add(annotation_key)
else: else:
optional_keys.add(annotation_key) optional_keys.add(annotation_key)
if ReadOnly in qualifiers:
if annotation_key in mutable_keys:
raise TypeError(
f"Cannot override mutable key {annotation_key!r}"
" with read-only key"
)
readonly_keys.add(annotation_key)
else:
mutable_keys.add(annotation_key)
readonly_keys.discard(annotation_key)
tp_dict.__annotations__ = annotations tp_dict.__annotations__ = annotations
tp_dict.__required_keys__ = frozenset(required_keys) tp_dict.__required_keys__ = frozenset(required_keys)
tp_dict.__optional_keys__ = frozenset(optional_keys) tp_dict.__optional_keys__ = frozenset(optional_keys)
tp_dict.__readonly_keys__ = frozenset(readonly_keys)
tp_dict.__mutable_keys__ = frozenset(mutable_keys)
if not hasattr(tp_dict, '__total__'): if not hasattr(tp_dict, '__total__'):
tp_dict.__total__ = total tp_dict.__total__ = total
return tp_dict return tp_dict
@ -936,6 +978,8 @@ else:
raise TypeError("TypedDict takes either a dict or keyword arguments," raise TypeError("TypedDict takes either a dict or keyword arguments,"
" but not both") " but not both")
if kwargs: if kwargs:
if sys.version_info >= (3, 13):
raise TypeError("TypedDict takes no keyword arguments")
warnings.warn( warnings.warn(
"The kwargs-based syntax for TypedDict definitions is deprecated " "The kwargs-based syntax for TypedDict definitions is deprecated "
"in Python 3.11, will be removed in Python 3.13, and may not be " "in Python 3.11, will be removed in Python 3.13, and may not be "
@ -1924,6 +1968,53 @@ else: # 3.8
""") """)
if hasattr(typing, 'ReadOnly'):
ReadOnly = typing.ReadOnly
elif sys.version_info[:2] >= (3, 9): # 3.9-3.12
@_ExtensionsSpecialForm
def ReadOnly(self, parameters):
"""A special typing construct to mark an item of a TypedDict as read-only.
For example:
class Movie(TypedDict):
title: ReadOnly[str]
year: int
def mutate_movie(m: Movie) -> None:
m["year"] = 1992 # allowed
m["title"] = "The Matrix" # typechecker error
There is no runtime checking for this property.
"""
item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
return typing._GenericAlias(self, (item,))
else: # 3.8
class _ReadOnlyForm(_ExtensionsSpecialForm, _root=True):
def __getitem__(self, parameters):
item = typing._type_check(parameters,
f'{self._name} accepts only a single type.')
return typing._GenericAlias(self, (item,))
ReadOnly = _ReadOnlyForm(
'ReadOnly',
doc="""A special typing construct to mark a key of a TypedDict as read-only.
For example:
class Movie(TypedDict):
title: ReadOnly[str]
year: int
def mutate_movie(m: Movie) -> None:
m["year"] = 1992 # allowed
m["title"] = "The Matrix" # typechecker error
There is no runtime checking for this propery.
""")
_UNPACK_DOC = """\ _UNPACK_DOC = """\
Type unpack operator. Type unpack operator.
@ -2251,7 +2342,7 @@ else: # <=3.11
Usage: Usage:
class Base: class Base:
def method(self) -> None: ... def method(self) -> None:
pass pass
class Child(Base): class Child(Base):
@ -2281,20 +2372,17 @@ else: # <=3.11
return arg return arg
if hasattr(typing, "deprecated"): if hasattr(warnings, "deprecated"):
deprecated = typing.deprecated deprecated = warnings.deprecated
else: else:
_T = typing.TypeVar("_T") _T = typing.TypeVar("_T")
def deprecated( class deprecated:
msg: str,
/,
*,
category: typing.Optional[typing.Type[Warning]] = DeprecationWarning,
stacklevel: int = 1,
) -> typing.Callable[[_T], _T]:
"""Indicate that a class, function or overload is deprecated. """Indicate that a class, function or overload is deprecated.
When this decorator is applied to an object, the type checker
will generate a diagnostic on usage of the deprecated object.
Usage: Usage:
@deprecated("Use B instead") @deprecated("Use B instead")
@ -2311,49 +2399,100 @@ else:
@overload @overload
def g(x: str) -> int: ... def g(x: str) -> int: ...
When this decorator is applied to an object, the type checker The warning specified by *category* will be emitted at runtime
will generate a diagnostic on usage of the deprecated object. on use of deprecated objects. For functions, that happens on calls;
for classes, on instantiation and on creation of subclasses.
The warning specified by ``category`` will be emitted on use If the *category* is ``None``, no warning is emitted at runtime.
of deprecated objects. For functions, that happens on calls; The *stacklevel* determines where the
for classes, on instantiation. If the ``category`` is ``None``,
no warning is emitted. The ``stacklevel`` determines where the
warning is emitted. If it is ``1`` (the default), the warning warning is emitted. If it is ``1`` (the default), the warning
is emitted at the direct caller of the deprecated object; if it is emitted at the direct caller of the deprecated object; if it
is higher, it is emitted further up the stack. is higher, it is emitted further up the stack.
Static type checker behavior is not affected by the *category*
and *stacklevel* arguments.
The decorator sets the ``__deprecated__`` The deprecation message passed to the decorator is saved in the
attribute on the decorated object to the deprecation message ``__deprecated__`` attribute on the decorated object.
passed to the decorator. If applied to an overload, the decorator If applied to an overload, the decorator
must be after the ``@overload`` decorator for the attribute to must be after the ``@overload`` decorator for the attribute to
exist on the overload as returned by ``get_overloads()``. exist on the overload as returned by ``get_overloads()``.
See PEP 702 for details. See PEP 702 for details.
""" """
def decorator(arg: _T, /) -> _T: def __init__(
self,
message: str,
/,
*,
category: typing.Optional[typing.Type[Warning]] = DeprecationWarning,
stacklevel: int = 1,
) -> None:
if not isinstance(message, str):
raise TypeError(
"Expected an object of type str for 'message', not "
f"{type(message).__name__!r}"
)
self.message = message
self.category = category
self.stacklevel = stacklevel
def __call__(self, arg: _T, /) -> _T:
# Make sure the inner functions created below don't
# retain a reference to self.
msg = self.message
category = self.category
stacklevel = self.stacklevel
if category is None: if category is None:
arg.__deprecated__ = msg arg.__deprecated__ = msg
return arg return arg
elif isinstance(arg, type): elif isinstance(arg, type):
import functools
from types import MethodType
original_new = arg.__new__ original_new = arg.__new__
has_init = arg.__init__ is not object.__init__
@functools.wraps(original_new) @functools.wraps(original_new)
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
warnings.warn(msg, category=category, stacklevel=stacklevel + 1) if cls is arg:
warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
if original_new is not object.__new__: if original_new is not object.__new__:
return original_new(cls, *args, **kwargs) return original_new(cls, *args, **kwargs)
# Mirrors a similar check in object.__new__. # Mirrors a similar check in object.__new__.
elif not has_init and (args or kwargs): elif cls.__init__ is object.__init__ and (args or kwargs):
raise TypeError(f"{cls.__name__}() takes no arguments") raise TypeError(f"{cls.__name__}() takes no arguments")
else: else:
return original_new(cls) return original_new(cls)
arg.__new__ = staticmethod(__new__) arg.__new__ = staticmethod(__new__)
original_init_subclass = arg.__init_subclass__
# We need slightly different behavior if __init_subclass__
# is a bound method (likely if it was implemented in Python)
if isinstance(original_init_subclass, MethodType):
original_init_subclass = original_init_subclass.__func__
@functools.wraps(original_init_subclass)
def __init_subclass__(*args, **kwargs):
warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
return original_init_subclass(*args, **kwargs)
arg.__init_subclass__ = classmethod(__init_subclass__)
# Or otherwise, which likely means it's a builtin such as
# object's implementation of __init_subclass__.
else:
@functools.wraps(original_init_subclass)
def __init_subclass__(*args, **kwargs):
warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
return original_init_subclass(*args, **kwargs)
arg.__init_subclass__ = __init_subclass__
arg.__deprecated__ = __new__.__deprecated__ = msg arg.__deprecated__ = __new__.__deprecated__ = msg
__init_subclass__.__deprecated__ = msg
return arg return arg
elif callable(arg): elif callable(arg):
import functools
@functools.wraps(arg) @functools.wraps(arg)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
warnings.warn(msg, category=category, stacklevel=stacklevel + 1) warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
@ -2367,8 +2506,6 @@ else:
f"a class or callable, not {arg!r}" f"a class or callable, not {arg!r}"
) )
return decorator
# We have to do some monkey patching to deal with the dual nature of # We have to do some monkey patching to deal with the dual nature of
# Unpack/TypeVarTuple: # Unpack/TypeVarTuple:
@ -2437,11 +2574,35 @@ else:
class_getitem = typing.Generic.__class_getitem__.__func__ class_getitem = typing.Generic.__class_getitem__.__func__
nm_tpl.__class_getitem__ = classmethod(class_getitem) nm_tpl.__class_getitem__ = classmethod(class_getitem)
# update from user namespace without overriding special namedtuple attributes # update from user namespace without overriding special namedtuple attributes
for key in ns: for key, val in ns.items():
if key in _prohibited_namedtuple_fields: if key in _prohibited_namedtuple_fields:
raise AttributeError("Cannot overwrite NamedTuple attribute " + key) raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
elif key not in _special_namedtuple_fields and key not in nm_tpl._fields: elif key not in _special_namedtuple_fields:
setattr(nm_tpl, key, ns[key]) if key not in nm_tpl._fields:
setattr(nm_tpl, key, ns[key])
try:
set_name = type(val).__set_name__
except AttributeError:
pass
else:
try:
set_name(val, nm_tpl, key)
except BaseException as e:
msg = (
f"Error calling __set_name__ on {type(val).__name__!r} "
f"instance {key!r} in {typename!r}"
)
# BaseException.add_note() existed on py311,
# but the __set_name__ machinery didn't start
# using add_note() until py312.
# Making sure exceptions are raised in the same way
# as in "normal" classes seems most important here.
if sys.version_info >= (3, 12):
e.add_note(msg)
raise
else:
raise RuntimeError(msg) from e
if typing.Generic in bases: if typing.Generic in bases:
nm_tpl.__init_subclass__() nm_tpl.__init_subclass__()
return nm_tpl return nm_tpl
@ -2600,7 +2761,7 @@ else:
num = UserId(5) + 1 # type: int num = UserId(5) + 1 # type: int
""" """
def __call__(self, obj): def __call__(self, obj, /):
return obj return obj
def __init__(self, name, tp): def __init__(self, name, tp):

View file

@ -48,6 +48,7 @@ from _babase import (
fatal_error, fatal_error,
get_display_resolution, get_display_resolution,
get_immediate_return_code, get_immediate_return_code,
get_input_idle_time,
get_low_level_config_value, get_low_level_config_value,
get_max_graphics_quality, get_max_graphics_quality,
get_replays_dir, get_replays_dir,
@ -60,6 +61,7 @@ from _babase import (
have_permission, have_permission,
in_logic_thread, in_logic_thread,
increment_analytics_count, increment_analytics_count,
invoke_main_menu,
is_os_playing_music, is_os_playing_music,
is_xcode_build, is_xcode_build,
lock_all_input, lock_all_input,
@ -116,7 +118,6 @@ from babase._apputils import (
get_remote_app_name, get_remote_app_name,
AppHealthMonitor, AppHealthMonitor,
) )
from babase._cloud import CloudSubsystem
from babase._devconsole import ( from babase._devconsole import (
DevConsoleTab, DevConsoleTab,
DevConsoleTabEntry, DevConsoleTabEntry,
@ -211,7 +212,6 @@ __all__ = [
'clipboard_has_text', 'clipboard_has_text',
'clipboard_is_supported', 'clipboard_is_supported',
'clipboard_set_text', 'clipboard_set_text',
'CloudSubsystem',
'commit_app_config', 'commit_app_config',
'ContextCall', 'ContextCall',
'ContextError', 'ContextError',
@ -235,6 +235,7 @@ __all__ = [
'garbage_collect', 'garbage_collect',
'get_display_resolution', 'get_display_resolution',
'get_immediate_return_code', 'get_immediate_return_code',
'get_input_idle_time',
'get_ip_address_type', 'get_ip_address_type',
'get_low_level_config_value', 'get_low_level_config_value',
'get_max_graphics_quality', 'get_max_graphics_quality',
@ -254,6 +255,7 @@ __all__ = [
'increment_analytics_count', 'increment_analytics_count',
'InputDeviceNotFoundError', 'InputDeviceNotFoundError',
'InputType', 'InputType',
'invoke_main_menu',
'is_browser_likely_available', 'is_browser_likely_available',
'is_browser_likely_available', 'is_browser_likely_available',
'is_os_playing_music', 'is_os_playing_music',

View file

@ -1,15 +1,17 @@
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
# pylint: disable=too-many-lines
"""Functionality related to the high level state of the app.""" """Functionality related to the high level state of the app."""
from __future__ import annotations from __future__ import annotations
import os import os
import logging import logging
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, TypeVar
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from functools import cached_property from functools import cached_property
from typing_extensions import override
from efro.call import tpartial from efro.call import tpartial
import _babase import _babase
@ -26,7 +28,7 @@ from babase._devconsole import DevConsoleSubsystem
if TYPE_CHECKING: if TYPE_CHECKING:
import asyncio import asyncio
from typing import Any, Callable, Coroutine from typing import Any, Callable, Coroutine, Generator, Awaitable
from concurrent.futures import Future from concurrent.futures import Future
import babase import babase
@ -42,6 +44,8 @@ if TYPE_CHECKING:
# __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__ # __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__
T = TypeVar('T')
class App: class App:
"""A class for high level app functionality and state. """A class for high level app functionality and state.
@ -124,6 +128,7 @@ class App:
statically in a spinoff project. statically in a spinoff project.
""" """
@override
def app_mode_for_intent( def app_mode_for_intent(
self, intent: AppIntent self, intent: AppIntent
) -> type[AppMode] | None: ) -> type[AppMode] | None:
@ -199,7 +204,8 @@ class App:
self._called_on_running = False self._called_on_running = False
self._subsystem_registration_ended = False self._subsystem_registration_ended = False
self._pending_apply_app_config = False self._pending_apply_app_config = False
self._aioloop: asyncio.AbstractEventLoop | None = None self._asyncio_loop: asyncio.AbstractEventLoop | None = None
self._asyncio_tasks: set[asyncio.Task] = set()
self._asyncio_timer: babase.AppTimer | None = None self._asyncio_timer: babase.AppTimer | None = None
self._config: babase.AppConfig | None = None self._config: babase.AppConfig | None = None
self._pending_intent: AppIntent | None = None self._pending_intent: AppIntent | None = None
@ -239,18 +245,68 @@ class App:
return _babase.app_is_active() return _babase.app_is_active()
@property @property
def aioloop(self) -> asyncio.AbstractEventLoop: def asyncio_loop(self) -> asyncio.AbstractEventLoop:
"""The logic thread's asyncio event loop. """The logic thread's asyncio event loop.
This allow async tasks to be run in the logic thread. This allow async tasks to be run in the logic thread.
Generally you should call App.create_async_task() to schedule
async code to run instead of using this directly. That will
handle retaining the task and logging errors automatically.
Only schedule tasks onto asyncio_loop yourself when you intend
to hold on to the returned task and await its results. Releasing
the task reference can lead to subtle bugs such as unreported
errors and garbage-collected tasks disappearing before their
work is done.
Note that, at this time, the asyncio loop is encapsulated Note that, at this time, the asyncio loop is encapsulated
and explicitly stepped by the engine's logic thread loop and and explicitly stepped by the engine's logic thread loop and
thus things like asyncio.get_running_loop() will not return this thus things like asyncio.get_running_loop() will unintuitively
loop from most places in the logic thread; only from within a *not* return this loop from most places in the logic thread;
task explicitly created in this loop. only from within a task explicitly created in this loop.
Hopefully this situation will be improved in the future with a
unified event loop.
""" """
assert self._aioloop is not None assert _babase.in_logic_thread()
return self._aioloop assert self._asyncio_loop is not None
return self._asyncio_loop
def create_async_task(
self,
coro: Generator[Any, Any, T] | Coroutine[Any, Any, T],
*,
name: str | None = None,
) -> None:
"""Create a fully managed async task.
This will automatically retain and release a reference to the task
and log any exceptions that occur in it. If you need to await a task
or otherwise need more control, schedule a task directly using
App.asyncio_loop.
"""
assert _babase.in_logic_thread()
# Hold a strong reference to the task until it is done.
# Otherwise it is possible for it to be garbage collected and
# disappear midway if the caller does not hold on to the
# returned task, which seems like a great way to introduce
# hard-to-track bugs.
task = self.asyncio_loop.create_task(coro, name=name)
self._asyncio_tasks.add(task)
task.add_done_callback(self._on_task_done)
# return task
def _on_task_done(self, task: asyncio.Task) -> None:
# Report any errors that occurred.
try:
exc = task.exception()
if exc is not None:
logging.error(
"Error in async task '%s'.", task.get_name(), exc_info=exc
)
except Exception:
logging.exception('Error reporting async task error.')
self._asyncio_tasks.remove(task)
@property @property
def config(self) -> babase.AppConfig: def config(self) -> babase.AppConfig:
@ -437,6 +493,12 @@ class App:
self._native_shutdown_complete_called = True self._native_shutdown_complete_called = True
self._update_state() self._update_state()
def on_native_active_changed(self) -> None:
"""Called by the native layer when the app active state changes."""
assert _babase.in_logic_thread()
if self._mode is not None:
self._mode.on_app_active_changed()
def read_config(self) -> None: def read_config(self) -> None:
"""(internal)""" """(internal)"""
from babase._appconfig import read_app_config from babase._appconfig import read_app_config
@ -588,7 +650,7 @@ class App:
_env.on_app_state_initing() _env.on_app_state_initing()
self._aioloop = _asyncio.setup_asyncio() self._asyncio_loop = _asyncio.setup_asyncio()
self.health_monitor = AppHealthMonitor() self.health_monitor = AppHealthMonitor()
# __FEATURESET_APP_SUBSYSTEM_CREATE_BEGIN__ # __FEATURESET_APP_SUBSYSTEM_CREATE_BEGIN__
@ -868,8 +930,8 @@ class App:
) )
# Now kick off any async shutdown task(s). # Now kick off any async shutdown task(s).
assert self._aioloop is not None assert self._asyncio_loop is not None
self._shutdown_task = self._aioloop.create_task(self._shutdown()) self._shutdown_task = self._asyncio_loop.create_task(self._shutdown())
def _on_shutdown_complete(self) -> None: def _on_shutdown_complete(self) -> None:
"""(internal)""" """(internal)"""

View file

@ -52,3 +52,10 @@ class AppMode:
def on_deactivate(self) -> None: def on_deactivate(self) -> None:
"""Called when the mode is being deactivated.""" """Called when the mode is being deactivated."""
def on_app_active_changed(self) -> None:
"""Called when babase.app.active changes.
The app-mode may want to take action such as pausing a running
game in such cases.
"""

View file

@ -40,16 +40,16 @@ class AppSubsystem:
"""Called when the app reaches the running state.""" """Called when the app reaches the running state."""
def on_app_suspend(self) -> None: def on_app_suspend(self) -> None:
"""Called when the app enters the paused state.""" """Called when the app enters the suspended state."""
def on_app_unsuspend(self) -> None: def on_app_unsuspend(self) -> None:
"""Called when the app exits the paused state.""" """Called when the app exits the suspended state."""
def on_app_shutdown(self) -> None: def on_app_shutdown(self) -> None:
"""Called when the app is shutting down.""" """Called when the app begins shutting down."""
def on_app_shutdown_complete(self) -> None: def on_app_shutdown_complete(self) -> None:
"""Called when the app is done shutting down.""" """Called when the app completes shutting down."""
def do_apply_app_config(self) -> None: def do_apply_app_config(self) -> None:
"""Called when the app config should be applied.""" """Called when the app config should be applied."""

View file

@ -10,9 +10,11 @@ from threading import Thread
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from efro.call import tpartial from efro.call import tpartial
from efro.log import LogLevel from efro.log import LogLevel
from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json from efro.dataclassio import ioprepped, dataclass_to_json, dataclass_from_json
import _babase import _babase
from babase._appsubsystem import AppSubsystem from babase._appsubsystem import AppSubsystem
@ -386,6 +388,7 @@ class AppHealthMonitor(AppSubsystem):
self._response = False self._response = False
self._first_check = True self._first_check = True
@override
def on_app_loading(self) -> None: def on_app_loading(self) -> None:
# If any traceback dumps happened last run, log and clear them. # If any traceback dumps happened last run, log and clear them.
log_dumped_app_state(from_previous_run=True) log_dumped_app_state(from_previous_run=True)
@ -449,10 +452,12 @@ class AppHealthMonitor(AppSubsystem):
self._first_check = False self._first_check = False
@override
def on_app_suspend(self) -> None: def on_app_suspend(self) -> None:
assert _babase.in_logic_thread() assert _babase.in_logic_thread()
self._running = False self._running = False
@override
def on_app_unsuspend(self) -> None: def on_app_unsuspend(self) -> None:
assert _babase.in_logic_thread() assert _babase.in_logic_thread()
self._running = True self._running = True

View file

@ -8,6 +8,8 @@ from typing import TYPE_CHECKING
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from typing_extensions import override
import _babase import _babase
if TYPE_CHECKING: if TYPE_CHECKING:
@ -96,6 +98,7 @@ class DevConsoleTab:
class DevConsoleTabPython(DevConsoleTab): class DevConsoleTabPython(DevConsoleTab):
"""The Python dev-console tab.""" """The Python dev-console tab."""
@override
def refresh(self) -> None: def refresh(self) -> None:
self.python_terminal() self.python_terminal()
@ -103,6 +106,7 @@ class DevConsoleTabPython(DevConsoleTab):
class DevConsoleTabTest(DevConsoleTab): class DevConsoleTabTest(DevConsoleTab):
"""Test dev-console tab.""" """Test dev-console tab."""
@override
def refresh(self) -> None: def refresh(self) -> None:
import random import random

View file

@ -5,6 +5,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from bacommon.app import AppExperience from bacommon.app import AppExperience
import _babase import _babase
@ -18,15 +19,18 @@ if TYPE_CHECKING:
class EmptyAppMode(AppMode): class EmptyAppMode(AppMode):
"""An empty app mode that can be used as a fallback/etc.""" """An empty app mode that can be used as a fallback/etc."""
@override
@classmethod @classmethod
def get_app_experience(cls) -> AppExperience: def get_app_experience(cls) -> AppExperience:
return AppExperience.EMPTY return AppExperience.EMPTY
@override
@classmethod @classmethod
def _supports_intent(cls, intent: AppIntent) -> bool: def _supports_intent(cls, intent: AppIntent) -> bool:
# We support default and exec intents currently. # We support default and exec intents currently.
return isinstance(intent, AppIntentExec | AppIntentDefault) return isinstance(intent, AppIntentExec | AppIntentDefault)
@override
def handle_intent(self, intent: AppIntent) -> None: def handle_intent(self, intent: AppIntent) -> None:
if isinstance(intent, AppIntentExec): if isinstance(intent, AppIntentExec):
_babase.empty_app_mode_handle_intent_exec(intent.code) _babase.empty_app_mode_handle_intent_exec(intent.code)
@ -34,10 +38,12 @@ class EmptyAppMode(AppMode):
assert isinstance(intent, AppIntentDefault) assert isinstance(intent, AppIntentDefault)
_babase.empty_app_mode_handle_intent_default() _babase.empty_app_mode_handle_intent_default()
@override
def on_activate(self) -> None: def on_activate(self) -> None:
# Let the native layer do its thing. # Let the native layer do its thing.
_babase.on_empty_app_mode_activate() _babase.on_empty_app_mode_activate()
@override
def on_deactivate(self) -> None: def on_deactivate(self) -> None:
# Let the native layer do its thing. # Let the native layer do its thing.
_babase.on_empty_app_mode_deactivate() _babase.on_empty_app_mode_deactivate()

View file

@ -9,6 +9,7 @@ import logging
import warnings import warnings
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from efro.log import LogLevel from efro.log import LogLevel
if TYPE_CHECKING: if TYPE_CHECKING:
@ -216,6 +217,7 @@ def _feed_logs_to_babase(log_handler: LogHandler) -> None:
class _CustomHelper: class _CustomHelper:
"""Replacement 'help' that behaves better for our setup.""" """Replacement 'help' that behaves better for our setup."""
@override
def __repr__(self) -> str: def __repr__(self) -> str:
return 'Type help(object) for help about object.' return 'Type help(object) for help about object.'

View file

@ -10,6 +10,7 @@ import logging
import inspect import inspect
from typing import TYPE_CHECKING, TypeVar, Protocol, NewType from typing import TYPE_CHECKING, TypeVar, Protocol, NewType
from typing_extensions import override
from efro.terminal import Clr from efro.terminal import Clr
import _babase import _babase
@ -178,6 +179,7 @@ class _WeakCall:
def __call__(self, *args_extra: Any) -> Any: def __call__(self, *args_extra: Any) -> Any:
return self._call(*self._args + args_extra, **self._keywds) return self._call(*self._args + args_extra, **self._keywds)
@override
def __str__(self) -> str: def __str__(self) -> str:
return ( return (
'<ba.WeakCall object; _call=' '<ba.WeakCall object; _call='
@ -224,6 +226,7 @@ class _Call:
def __call__(self, *args_extra: Any) -> Any: def __call__(self, *args_extra: Any) -> Any:
return self._call(*self._args + args_extra, **self._keywds) return self._call(*self._args + args_extra, **self._keywds)
@override
def __str__(self) -> str: def __str__(self) -> str:
return ( return (
'<ba.Call object; _call=' '<ba.Call object; _call='
@ -268,6 +271,7 @@ class WeakMethod:
return None return None
return self._func(*((obj,) + args), **keywds) return self._func(*((obj,) + args), **keywds)
@override
def __str__(self) -> str: def __str__(self) -> str:
return '<ba.WeakMethod object; call=' + str(self._func) + '>' return '<ba.WeakMethod object; call=' + str(self._func) + '>'

View file

@ -8,6 +8,8 @@ import json
import logging import logging
from typing import TYPE_CHECKING, overload from typing import TYPE_CHECKING, overload
from typing_extensions import override
import _babase import _babase
from babase._appsubsystem import AppSubsystem from babase._appsubsystem import AppSubsystem
@ -217,6 +219,7 @@ class LanguageSubsystem(AppSubsystem):
color=(0, 1, 0), color=(0, 1, 0),
) )
@override
def do_apply_app_config(self) -> None: def do_apply_app_config(self) -> None:
assert _babase.in_logic_thread() assert _babase.in_logic_thread()
assert isinstance(_babase.app.config, dict) assert isinstance(_babase.app.config, dict)
@ -598,9 +601,11 @@ class Lstr:
_error.print_exception('_get_json failed for', self.args) _error.print_exception('_get_json failed for', self.args)
return 'JSON_ERR' return 'JSON_ERR'
@override
def __str__(self) -> str: def __str__(self) -> str:
return '<ba.Lstr: ' + self._get_json() + '>' return '<ba.Lstr: ' + self._get_json() + '>'
@override
def __repr__(self) -> str: def __repr__(self) -> str:
return '<ba.Lstr: ' + self._get_json() + '>' return '<ba.Lstr: ' + self._get_json() + '>'
@ -648,5 +653,6 @@ class AttrDict(dict):
assert not isinstance(val, bytes) assert not isinstance(val, bytes)
return val return val
@override
def __setattr__(self, attr: str, value: Any) -> None: def __setattr__(self, attr: str, value: Any) -> None:
raise AttributeError() raise AttributeError()

View file

@ -9,6 +9,7 @@ import logging
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING, final from typing import TYPE_CHECKING, final
from typing_extensions import override
from bacommon.login import LoginType from bacommon.login import LoginType
import _babase import _babase
@ -353,6 +354,7 @@ class LoginAdapterNative(LoginAdapter):
self._sign_in_attempt_num = 123 self._sign_in_attempt_num = 123
self._sign_in_attempts: dict[int, Callable[[str | None], None]] = {} self._sign_in_attempts: dict[int, Callable[[str | None], None]] = {}
@override
def get_sign_in_token( def get_sign_in_token(
self, completion_cb: Callable[[str | None], None] self, completion_cb: Callable[[str | None], None]
) -> None: ) -> None:
@ -363,6 +365,7 @@ class LoginAdapterNative(LoginAdapter):
self.login_type.value, attempt_id self.login_type.value, attempt_id
) )
@override
def on_back_end_active_change(self, active: bool) -> None: def on_back_end_active_change(self, active: bool) -> None:
_babase.login_adapter_back_end_active_change( _babase.login_adapter_back_end_active_change(
self.login_type.value, active self.login_type.value, active

View file

@ -26,7 +26,7 @@ EXPORT_CLASS_NAME_SHORTCUTS: dict[str, str] = {
'plugin': 'babase.Plugin', 'plugin': 'babase.Plugin',
# DEPRECATED as of 12/2023. Currently am warning if finding these # DEPRECATED as of 12/2023. Currently am warning if finding these
# but should take this out eventually. # but should take this out eventually.
'keyboard': 'babase.Keyboard', 'keyboard': 'bauiv1.Keyboard',
} }
T = TypeVar('T') T = TypeVar('T')

View file

@ -149,78 +149,84 @@ class SpecialChar(Enum):
PLAY_PAUSE_BUTTON = 13 PLAY_PAUSE_BUTTON = 13
FAST_FORWARD_BUTTON = 14 FAST_FORWARD_BUTTON = 14
DPAD_CENTER_BUTTON = 15 DPAD_CENTER_BUTTON = 15
OUYA_BUTTON_O = 16 PLAY_STATION_CROSS_BUTTON = 16
OUYA_BUTTON_U = 17 PLAY_STATION_CIRCLE_BUTTON = 17
OUYA_BUTTON_Y = 18 PLAY_STATION_TRIANGLE_BUTTON = 18
OUYA_BUTTON_A = 19 PLAY_STATION_SQUARE_BUTTON = 19
OUYA_LOGO = 20 PLAY_BUTTON = 20
LOGO = 21 PAUSE_BUTTON = 21
TICKET = 22 OUYA_BUTTON_O = 22
GOOGLE_PLAY_GAMES_LOGO = 23 OUYA_BUTTON_U = 23
GAME_CENTER_LOGO = 24 OUYA_BUTTON_Y = 24
DICE_BUTTON1 = 25 OUYA_BUTTON_A = 25
DICE_BUTTON2 = 26 OUYA_LOGO = 26
DICE_BUTTON3 = 27 LOGO = 27
DICE_BUTTON4 = 28 TICKET = 28
GAME_CIRCLE_LOGO = 29 GOOGLE_PLAY_GAMES_LOGO = 29
PARTY_ICON = 30 GAME_CENTER_LOGO = 30
TEST_ACCOUNT = 31 DICE_BUTTON1 = 31
TICKET_BACKING = 32 DICE_BUTTON2 = 32
TROPHY1 = 33 DICE_BUTTON3 = 33
TROPHY2 = 34 DICE_BUTTON4 = 34
TROPHY3 = 35 GAME_CIRCLE_LOGO = 35
TROPHY0A = 36 PARTY_ICON = 36
TROPHY0B = 37 TEST_ACCOUNT = 37
TROPHY4 = 38 TICKET_BACKING = 38
LOCAL_ACCOUNT = 39 TROPHY1 = 39
EXPLODINARY_LOGO = 40 TROPHY2 = 40
FLAG_UNITED_STATES = 41 TROPHY3 = 41
FLAG_MEXICO = 42 TROPHY0A = 42
FLAG_GERMANY = 43 TROPHY0B = 43
FLAG_BRAZIL = 44 TROPHY4 = 44
FLAG_RUSSIA = 45 LOCAL_ACCOUNT = 45
FLAG_CHINA = 46 EXPLODINARY_LOGO = 46
FLAG_UNITED_KINGDOM = 47 FLAG_UNITED_STATES = 47
FLAG_CANADA = 48 FLAG_MEXICO = 48
FLAG_INDIA = 49 FLAG_GERMANY = 49
FLAG_JAPAN = 50 FLAG_BRAZIL = 50
FLAG_FRANCE = 51 FLAG_RUSSIA = 51
FLAG_INDONESIA = 52 FLAG_CHINA = 52
FLAG_ITALY = 53 FLAG_UNITED_KINGDOM = 53
FLAG_SOUTH_KOREA = 54 FLAG_CANADA = 54
FLAG_NETHERLANDS = 55 FLAG_INDIA = 55
FEDORA = 56 FLAG_JAPAN = 56
HAL = 57 FLAG_FRANCE = 57
CROWN = 58 FLAG_INDONESIA = 58
YIN_YANG = 59 FLAG_ITALY = 59
EYE_BALL = 60 FLAG_SOUTH_KOREA = 60
SKULL = 61 FLAG_NETHERLANDS = 61
HEART = 62 FEDORA = 62
DRAGON = 63 HAL = 63
HELMET = 64 CROWN = 64
MUSHROOM = 65 YIN_YANG = 65
NINJA_STAR = 66 EYE_BALL = 66
VIKING_HELMET = 67 SKULL = 67
MOON = 68 HEART = 68
SPIDER = 69 DRAGON = 69
FIREBALL = 70 HELMET = 70
FLAG_UNITED_ARAB_EMIRATES = 71 MUSHROOM = 71
FLAG_QATAR = 72 NINJA_STAR = 72
FLAG_EGYPT = 73 VIKING_HELMET = 73
FLAG_KUWAIT = 74 MOON = 74
FLAG_ALGERIA = 75 SPIDER = 75
FLAG_SAUDI_ARABIA = 76 FIREBALL = 76
FLAG_MALAYSIA = 77 FLAG_UNITED_ARAB_EMIRATES = 77
FLAG_CZECH_REPUBLIC = 78 FLAG_QATAR = 78
FLAG_AUSTRALIA = 79 FLAG_EGYPT = 79
FLAG_SINGAPORE = 80 FLAG_KUWAIT = 80
OCULUS_LOGO = 81 FLAG_ALGERIA = 81
STEAM_LOGO = 82 FLAG_SAUDI_ARABIA = 82
NVIDIA_LOGO = 83 FLAG_MALAYSIA = 83
FLAG_IRAN = 84 FLAG_CZECH_REPUBLIC = 84
FLAG_POLAND = 85 FLAG_AUSTRALIA = 85
FLAG_ARGENTINA = 86 FLAG_SINGAPORE = 86
FLAG_PHILIPPINES = 87 OCULUS_LOGO = 87
FLAG_CHILE = 88 STEAM_LOGO = 88
MIKIROG = 89 NVIDIA_LOGO = 89
V2_LOGO = 90 FLAG_IRAN = 90
FLAG_POLAND = 91
FLAG_ARGENTINA = 92
FLAG_PHILIPPINES = 93
FLAG_CHILE = 94
MIKIROG = 95
V2_LOGO = 96

View file

@ -8,6 +8,8 @@ import logging
import importlib.util import importlib.util
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import _babase import _babase
from babase._appsubsystem import AppSubsystem from babase._appsubsystem import AppSubsystem
@ -158,6 +160,7 @@ class PluginSubsystem(AppSubsystem):
if config_changed: if config_changed:
_babase.app.config.commit() _babase.app.config.commit()
@override
def on_app_running(self) -> None: def on_app_running(self) -> None:
# Load up our plugins and go ahead and call their on_app_running # Load up our plugins and go ahead and call their on_app_running
# calls. # calls.
@ -170,6 +173,7 @@ class PluginSubsystem(AppSubsystem):
_error.print_exception('Error in plugin on_app_running()') _error.print_exception('Error in plugin on_app_running()')
@override
def on_app_suspend(self) -> None: def on_app_suspend(self) -> None:
for plugin in self.active_plugins: for plugin in self.active_plugins:
try: try:
@ -179,6 +183,7 @@ class PluginSubsystem(AppSubsystem):
_error.print_exception('Error in plugin on_app_suspend()') _error.print_exception('Error in plugin on_app_suspend()')
@override
def on_app_unsuspend(self) -> None: def on_app_unsuspend(self) -> None:
for plugin in self.active_plugins: for plugin in self.active_plugins:
try: try:
@ -188,6 +193,7 @@ class PluginSubsystem(AppSubsystem):
_error.print_exception('Error in plugin on_app_unsuspend()') _error.print_exception('Error in plugin on_app_unsuspend()')
@override
def on_app_shutdown(self) -> None: def on_app_shutdown(self) -> None:
for plugin in self.active_plugins: for plugin in self.active_plugins:
try: try:
@ -197,6 +203,7 @@ class PluginSubsystem(AppSubsystem):
_error.print_exception('Error in plugin on_app_shutdown()') _error.print_exception('Error in plugin on_app_shutdown()')
@override
def on_app_shutdown_complete(self) -> None: def on_app_shutdown_complete(self) -> None:
for plugin in self.active_plugins: for plugin in self.active_plugins:
try: try:

View file

@ -5,6 +5,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from babase._stringedit import StringEditAdapter from babase._stringedit import StringEditAdapter
import _babase import _babase
@ -24,9 +26,11 @@ class DevConsoleStringEditAdapter(StringEditAdapter):
description, initial_text, max_length, screen_space_center description, initial_text, max_length, screen_space_center
) )
@override
def _do_apply(self, new_text: str) -> None: def _do_apply(self, new_text: str) -> None:
_babase.set_dev_console_input_text(new_text) _babase.set_dev_console_input_text(new_text)
_babase.dev_console_input_adapter_finish() _babase.dev_console_input_adapter_finish()
@override
def _do_cancel(self) -> None: def _do_cancel(self) -> None:
_babase.dev_console_input_adapter_finish() _babase.dev_console_input_adapter_finish()

View file

@ -229,9 +229,7 @@ class AdsSubsystem:
await asyncio.sleep(1.0) await asyncio.sleep(1.0)
payload.run(fallback=True) payload.run(fallback=True)
_fallback_task = babase.app.aioloop.create_task( babase.app.create_async_task(add_fallback_task())
add_fallback_task()
)
self.show_ad('between_game', on_completion_call=payload.run) self.show_ad('between_game', on_completion_call=payload.run)
else: else:
babase.pushcall(call) # Just run the callback without the ad. babase.pushcall(call) # Just run the callback without the ad.

View file

@ -4,8 +4,10 @@
from __future__ import annotations from __future__ import annotations
import random import random
from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import bascenev1 import bascenev1
import _baclassic import _baclassic
@ -42,70 +44,81 @@ def run_cpu_benchmark() -> None:
cfg['Graphics Quality'] = self._old_quality cfg['Graphics Quality'] = self._old_quality
cfg.apply() cfg.apply()
@override
def on_player_request(self, player: bascenev1.SessionPlayer) -> bool: def on_player_request(self, player: bascenev1.SessionPlayer) -> bool:
return False return False
bascenev1.new_host_session(BenchmarkSession, benchmark_type='cpu') bascenev1.new_host_session(BenchmarkSession, benchmark_type='cpu')
@dataclass
class _StressTestArgs:
playlist_type: str
playlist_name: str
player_count: int
round_duration: int
attract_mode: bool
def run_stress_test( def run_stress_test(
playlist_type: str = 'Random', playlist_type: str = 'Random',
playlist_name: str = '__default__', playlist_name: str = '__default__',
player_count: int = 8, player_count: int = 8,
round_duration: int = 30, round_duration: int = 30,
attract_mode: bool = False,
) -> None: ) -> None:
"""Run a stress test.""" """Run a stress test."""
babase.screenmessage(
"Beginning stress test.. use 'End Test' to stop testing.",
color=(1, 1, 0),
)
with babase.ContextRef.empty(): with babase.ContextRef.empty():
start_stress_test( if not attract_mode:
{ babase.screenmessage(
'playlist_type': playlist_type, "Beginning stress test.. use 'End Test' to stop testing.",
'playlist_name': playlist_name, color=(1, 1, 0),
'player_count': player_count, )
'round_duration': round_duration, _start_stress_test(
} _StressTestArgs(
playlist_type=playlist_type,
playlist_name=playlist_name,
player_count=player_count,
round_duration=round_duration,
attract_mode=attract_mode,
)
) )
def stop_stress_test() -> None: def stop_stress_test() -> None:
"""End a running stress test.""" """End a running stress test."""
_baclassic.set_stress_testing(False, 0)
assert babase.app.classic is not None assert babase.app.classic is not None
try:
if babase.app.classic.stress_test_reset_timer is not None: _baclassic.set_stress_testing(False, 0, False)
babase.screenmessage('Ending stress test...', color=(1, 1, 0)) babase.app.classic.stress_test_update_timer = None
except Exception: babase.app.classic.stress_test_update_timer_2 = None
pass
babase.app.classic.stress_test_reset_timer = None
def start_stress_test(args: dict[str, Any]) -> None: def _start_stress_test(args: _StressTestArgs) -> None:
"""(internal)""" """(internal)"""
from bascenev1 import DualTeamSession, FreeForAllSession from bascenev1 import DualTeamSession, FreeForAllSession
assert babase.app.classic is not None assert babase.app.classic is not None
appconfig = babase.app.config appconfig = babase.app.config
playlist_type = args['playlist_type'] playlist_type = args.playlist_type
if playlist_type == 'Random': if playlist_type == 'Random':
if random.random() < 0.5: if random.random() < 0.5:
playlist_type = 'Teams' playlist_type = 'Teams'
else: else:
playlist_type = 'Free-For-All' playlist_type = 'Free-For-All'
babase.screenmessage( if not args.attract_mode:
'Running Stress Test (listType="' babase.screenmessage(
+ playlist_type 'Running Stress Test (listType="'
+ '", listName="' + playlist_type
+ args['playlist_name'] + '", listName="'
+ '")...' + args.playlist_name
) + '")...'
)
if playlist_type == 'Teams': if playlist_type == 'Teams':
appconfig['Team Tournament Playlist Selection'] = args['playlist_name'] appconfig['Team Tournament Playlist Selection'] = args.playlist_name
appconfig['Team Tournament Playlist Randomize'] = 1 appconfig['Team Tournament Playlist Randomize'] = 1
babase.apptimer( babase.apptimer(
1.0, 1.0,
@ -115,7 +128,7 @@ def start_stress_test(args: dict[str, Any]) -> None:
), ),
) )
else: else:
appconfig['Free-for-All Playlist Selection'] = args['playlist_name'] appconfig['Free-for-All Playlist Selection'] = args.playlist_name
appconfig['Free-for-All Playlist Randomize'] = 1 appconfig['Free-for-All Playlist Randomize'] = 1
babase.apptimer( babase.apptimer(
1.0, 1.0,
@ -124,19 +137,38 @@ def start_stress_test(args: dict[str, Any]) -> None:
babase.Call(bascenev1.new_host_session, FreeForAllSession), babase.Call(bascenev1.new_host_session, FreeForAllSession),
), ),
) )
_baclassic.set_stress_testing(True, args['player_count']) _baclassic.set_stress_testing(True, args.player_count, args.attract_mode)
babase.app.classic.stress_test_reset_timer = babase.AppTimer( babase.app.classic.stress_test_update_timer = babase.AppTimer(
args['round_duration'], babase.Call(_reset_stress_test, args) args.round_duration, babase.Call(_reset_stress_test, args)
) )
if args.attract_mode:
babase.app.classic.stress_test_update_timer_2 = babase.AppTimer(
0.48, babase.Call(_update_attract_mode_test, args), repeat=True
)
def _reset_stress_test(args: dict[str, Any]) -> None: def _update_attract_mode_test(args: _StressTestArgs) -> None:
_baclassic.set_stress_testing(False, args['player_count']) if babase.get_input_idle_time() < 5.0:
babase.screenmessage('Resetting stress test...') _reset_stress_test(args)
def _reset_stress_test(args: _StressTestArgs) -> None:
_baclassic.set_stress_testing(False, args.player_count, False)
if not args.attract_mode:
babase.screenmessage('Resetting stress test...')
session = bascenev1.get_foreground_host_session() session = bascenev1.get_foreground_host_session()
assert session is not None assert session is not None
session.end() session.end()
babase.apptimer(1.0, babase.Call(start_stress_test, args))
assert babase.app.classic is not None
babase.app.classic.stress_test_update_timer = None
babase.app.classic.stress_test_update_timer_2 = None
# For regular stress tests we keep the party going. For attract-mode
# we just end back at the main menu. If things are idle there then
# we'll get sent back to a new stress test.
if not args.attract_mode:
babase.apptimer(1.0, babase.Call(_start_stress_test, args))
def run_gpu_benchmark() -> None: def run_gpu_benchmark() -> None:

View file

@ -9,6 +9,7 @@ import threading
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import bascenev1 import bascenev1
@ -68,6 +69,7 @@ class MasterServerV1CallThread(threading.Thread):
with self._context: with self._context:
self._callback(arg) self._callback(arg)
@override
def run(self) -> None: def run(self) -> None:
# pylint: disable=consider-using-with # pylint: disable=consider-using-with
# pylint: disable=too-many-branches # pylint: disable=too-many-branches

View file

@ -8,6 +8,7 @@ import random
import logging import logging
import weakref import weakref
from typing_extensions import override
from efro.dataclassio import dataclass_from_dict from efro.dataclassio import dataclass_from_dict
import babase import babase
import bauiv1 import bauiv1
@ -69,7 +70,8 @@ class ClassicSubsystem(babase.AppSubsystem):
# Misc. # Misc.
self.tips: list[str] = [] self.tips: list[str] = []
self.stress_test_reset_timer: babase.AppTimer | None = None self.stress_test_update_timer: babase.AppTimer | None = None
self.stress_test_update_timer_2: babase.AppTimer | None = None
self.value_test_defaults: dict = {} self.value_test_defaults: dict = {}
self.special_offer: dict | None = None self.special_offer: dict | None = None
self.ping_thread_count = 0 self.ping_thread_count = 0
@ -148,6 +150,7 @@ class ClassicSubsystem(babase.AppSubsystem):
assert isinstance(self._env['legacy_user_agent_string'], str) assert isinstance(self._env['legacy_user_agent_string'], str)
return self._env['legacy_user_agent_string'] return self._env['legacy_user_agent_string']
@override
def on_app_loading(self) -> None: def on_app_loading(self) -> None:
from bascenev1lib.actor import spazappearance from bascenev1lib.actor import spazappearance
from bascenev1lib import maps as stdmaps from bascenev1lib import maps as stdmaps
@ -229,13 +232,16 @@ class ClassicSubsystem(babase.AppSubsystem):
self.accounts.on_app_loading() self.accounts.on_app_loading()
@override
def on_app_suspend(self) -> None: def on_app_suspend(self) -> None:
self.accounts.on_app_suspend() self.accounts.on_app_suspend()
@override
def on_app_unsuspend(self) -> None: def on_app_unsuspend(self) -> None:
self.accounts.on_app_unsuspend() self.accounts.on_app_unsuspend()
self.music.on_app_unsuspend() self.music.on_app_unsuspend()
@override
def on_app_shutdown(self) -> None: def on_app_shutdown(self) -> None:
self.music.on_app_shutdown() self.music.on_app_shutdown()
@ -555,11 +561,18 @@ class ClassicSubsystem(babase.AppSubsystem):
playlist_name: str = '__default__', playlist_name: str = '__default__',
player_count: int = 8, player_count: int = 8,
round_duration: int = 30, round_duration: int = 30,
attract_mode: bool = False,
) -> None: ) -> None:
"""Run a stress test.""" """Run a stress test."""
from baclassic._benchmark import run_stress_test as run from baclassic._benchmark import run_stress_test as run
run(playlist_type, playlist_name, player_count, round_duration) run(
playlist_type=playlist_type,
playlist_name=playlist_name,
player_count=player_count,
round_duration=round_duration,
attract_mode=attract_mode,
)
def get_input_device_mapped_value( def get_input_device_mapped_value(
self, device: bascenev1.InputDevice, name: str self, device: bascenev1.InputDevice, name: str

View file

@ -8,6 +8,7 @@ import threading
from collections import deque from collections import deque
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
from baclassic._music import MusicPlayer from baclassic._music import MusicPlayer
@ -27,6 +28,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
self._thread = _MacMusicAppThread() self._thread = _MacMusicAppThread()
self._thread.start() self._thread.start()
@override
def on_select_entry( def on_select_entry(
self, self,
callback: Callable[[Any], None], callback: Callable[[Any], None],
@ -40,6 +42,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
callback, current_entry, selection_target_name callback, current_entry, selection_target_name
) )
@override
def on_set_volume(self, volume: float) -> None: def on_set_volume(self, volume: float) -> None:
self._thread.set_volume(volume) self._thread.set_volume(volume)
@ -47,6 +50,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
"""Asynchronously fetch the list of available iTunes playlists.""" """Asynchronously fetch the list of available iTunes playlists."""
self._thread.get_playlists(callback) self._thread.get_playlists(callback)
@override
def on_play(self, entry: Any) -> None: def on_play(self, entry: Any) -> None:
assert babase.app.classic is not None assert babase.app.classic is not None
music = babase.app.classic.music music = babase.app.classic.music
@ -59,9 +63,11 @@ class MacMusicAppMusicPlayer(MusicPlayer):
entry_type, entry_type,
) )
@override
def on_stop(self) -> None: def on_stop(self) -> None:
self._thread.play_playlist(None) self._thread.play_playlist(None)
@override
def on_app_shutdown(self) -> None: def on_app_shutdown(self) -> None:
self._thread.shutdown() self._thread.shutdown()
@ -77,6 +83,7 @@ class _MacMusicAppThread(threading.Thread):
self._current_playlist: str | None = None self._current_playlist: str | None = None
self._orig_volume: int | None = None self._orig_volume: int | None = None
@override
def run(self) -> None: def run(self) -> None:
"""Run the Music.app thread.""" """Run the Music.app thread."""
babase.set_thread_name('BA_MacMusicAppThread') babase.set_thread_name('BA_MacMusicAppThread')

View file

@ -9,6 +9,7 @@ import logging
import threading import threading
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
from baclassic._music import MusicPlayer from baclassic._music import MusicPlayer
@ -33,6 +34,7 @@ class OSMusicPlayer(MusicPlayer):
# FIXME: should ask the C++ layer for these; just hard-coding for now. # FIXME: should ask the C++ layer for these; just hard-coding for now.
return ['mp3', 'ogg', 'm4a', 'wav', 'flac', 'mid'] return ['mp3', 'ogg', 'm4a', 'wav', 'flac', 'mid']
@override
def on_select_entry( def on_select_entry(
self, self,
callback: Callable[[Any], None], callback: Callable[[Any], None],
@ -48,9 +50,11 @@ class OSMusicPlayer(MusicPlayer):
callback, current_entry, selection_target_name callback, current_entry, selection_target_name
) )
@override
def on_set_volume(self, volume: float) -> None: def on_set_volume(self, volume: float) -> None:
babase.music_player_set_volume(volume) babase.music_player_set_volume(volume)
@override
def on_play(self, entry: Any) -> None: def on_play(self, entry: Any) -> None:
assert babase.app.classic is not None assert babase.app.classic is not None
music = babase.app.classic.music music = babase.app.classic.music
@ -99,11 +103,13 @@ class OSMusicPlayer(MusicPlayer):
self._actually_playing = True self._actually_playing = True
babase.music_player_play(result) babase.music_player_play(result)
@override
def on_stop(self) -> None: def on_stop(self) -> None:
self._want_to_play = False self._want_to_play = False
self._actually_playing = False self._actually_playing = False
babase.music_player_stop() babase.music_player_stop()
@override
def on_app_shutdown(self) -> None: def on_app_shutdown(self) -> None:
babase.music_player_shutdown() babase.music_player_shutdown()
@ -120,6 +126,7 @@ class _PickFolderSongThread(threading.Thread):
self._callback = callback self._callback = callback
self._path = path self._path = path
@override
def run(self) -> None: def run(self) -> None:
do_log_error = True do_log_error = True
try: try:

View file

@ -21,7 +21,7 @@ class BuildInfoSet:
@dataclass @dataclass
class Entry: class Entry:
"""Info about a particular build.""" """Info about a particular app build."""
filename: Annotated[str, IOAttrs('fname')] filename: Annotated[str, IOAttrs('fname')]
size: Annotated[int, IOAttrs('size')] size: Annotated[int, IOAttrs('size')]

View file

@ -7,6 +7,7 @@ from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Annotated from typing import TYPE_CHECKING, Annotated
from enum import Enum from enum import Enum
from typing_extensions import override
from efro.message import Message, Response from efro.message import Message, Response
from efro.dataclassio import ioprepped, IOAttrs from efro.dataclassio import ioprepped, IOAttrs
from bacommon.transfer import DirectoryManifest from bacommon.transfer import DirectoryManifest
@ -21,6 +22,7 @@ if TYPE_CHECKING:
class LoginProxyRequestMessage(Message): class LoginProxyRequestMessage(Message):
"""Request send to the cloud to ask for a login-proxy.""" """Request send to the cloud to ask for a login-proxy."""
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [LoginProxyRequestResponse] return [LoginProxyRequestResponse]
@ -49,6 +51,7 @@ class LoginProxyStateQueryMessage(Message):
proxyid: Annotated[str, IOAttrs('p')] proxyid: Annotated[str, IOAttrs('p')]
proxykey: Annotated[str, IOAttrs('k')] proxykey: Annotated[str, IOAttrs('k')]
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [LoginProxyStateQueryResponse] return [LoginProxyStateQueryResponse]
@ -85,6 +88,7 @@ class LoginProxyCompleteMessage(Message):
class PingMessage(Message): class PingMessage(Message):
"""Standard ping.""" """Standard ping."""
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [PingResponse] return [PingResponse]
@ -103,6 +107,7 @@ class TestMessage(Message):
testfoo: Annotated[int, IOAttrs('f')] testfoo: Annotated[int, IOAttrs('f')]
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [TestResponse] return [TestResponse]
@ -116,6 +121,28 @@ class TestResponse(Response):
testfoo: Annotated[int, IOAttrs('f')] testfoo: Annotated[int, IOAttrs('f')]
@ioprepped
@dataclass
class PromoCodeMessage(Message):
"""User is entering a promo code"""
code: Annotated[str, IOAttrs('c')]
@override
@classmethod
def get_response_types(cls) -> list[type[Response] | None]:
return [PromoCodeResponse]
@ioprepped
@dataclass
class PromoCodeResponse(Response):
"""Applied that promo code for ya, boss."""
valid: Annotated[bool, IOAttrs('v')]
message: Annotated[str | None, IOAttrs('m', store_default=False)] = None
@ioprepped @ioprepped
@dataclass @dataclass
class WorkspaceFetchState: class WorkspaceFetchState:
@ -136,6 +163,7 @@ class WorkspaceFetchMessage(Message):
workspaceid: Annotated[str, IOAttrs('w')] workspaceid: Annotated[str, IOAttrs('w')]
state: Annotated[WorkspaceFetchState, IOAttrs('s')] state: Annotated[WorkspaceFetchState, IOAttrs('s')]
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [WorkspaceFetchResponse] return [WorkspaceFetchResponse]
@ -162,6 +190,7 @@ class WorkspaceFetchResponse(Response):
class MerchAvailabilityMessage(Message): class MerchAvailabilityMessage(Message):
"""Can we show merch link?""" """Can we show merch link?"""
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [MerchAvailabilityResponse] return [MerchAvailabilityResponse]
@ -187,6 +216,7 @@ class SignInMessage(Message):
description: Annotated[str, IOAttrs('d', soft_default='-')] description: Annotated[str, IOAttrs('d', soft_default='-')]
apptime: Annotated[float, IOAttrs('at', soft_default=-1.0)] apptime: Annotated[float, IOAttrs('at', soft_default=-1.0)]
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [SignInResponse] return [SignInResponse]
@ -205,6 +235,7 @@ class SignInResponse(Response):
class ManageAccountMessage(Message): class ManageAccountMessage(Message):
"""Message asking for a manage-account url.""" """Message asking for a manage-account url."""
@override
@classmethod @classmethod
def get_response_types(cls) -> list[type[Response] | None]: def get_response_types(cls) -> list[type[Response] | None]:
return [ManageAccountResponse] return [ManageAccountResponse]

View file

@ -31,7 +31,7 @@ class DirectoryManifest:
files: Annotated[dict[str, DirectoryManifestFile], IOAttrs('f')] files: Annotated[dict[str, DirectoryManifestFile], IOAttrs('f')]
_empty_hash: str | None = None # _empty_hash: str | None = None
@classmethod @classmethod
def create_from_disk(cls, path: Path) -> DirectoryManifest: def create_from_disk(cls, path: Path) -> DirectoryManifest:
@ -92,12 +92,12 @@ class DirectoryManifest:
) )
break # 1 error is enough for now. break # 1 error is enough for now.
@classmethod # @classmethod
def get_empty_hash(cls) -> str: # def get_empty_hash(cls) -> str:
"""Return the hash for an empty file.""" # """Return the hash for an empty file."""
if cls._empty_hash is None: # if cls._empty_hash is None:
import hashlib # import hashlib
sha = hashlib.sha256() # sha = hashlib.sha256()
cls._empty_hash = sha.hexdigest() # cls._empty_hash = sha.hexdigest()
return cls._empty_hash # return cls._empty_hash

View file

@ -52,8 +52,8 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be # Build number and version of the ballistica binary we expect to be
# using. # using.
TARGET_BALLISTICA_BUILD = 21739 TARGET_BALLISTICA_BUILD = 21762
TARGET_BALLISTICA_VERSION = '1.7.32' TARGET_BALLISTICA_VERSION = '1.7.33'
@dataclass @dataclass
@ -350,9 +350,15 @@ def _setup_paths(
# platforms where there is no write access to said built-in # platforms where there is no write access to said built-in
# stuff. # stuff.
check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION) check_dir = Path(user_python_dir, 'sys', TARGET_BALLISTICA_VERSION)
if check_dir.is_dir(): try:
app_python_dir = str(check_dir) if check_dir.is_dir():
is_user_app_python_dir = True app_python_dir = str(check_dir)
is_user_app_python_dir = True
except PermissionError:
logging.warning(
"PermissionError checking user-app-python-dir path '%s'.",
check_dir,
)
# Ok, now apply these to sys.path. # Ok, now apply these to sys.path.

View file

@ -16,9 +16,11 @@ from __future__ import annotations
import logging import logging
from baplus._cloud import CloudSubsystem
from baplus._subsystem import PlusSubsystem from baplus._subsystem import PlusSubsystem
__all__ = [ __all__ = [
'CloudSubsystem',
'PlusSubsystem', 'PlusSubsystem',
] ]

214
dist/ba_data/python/baplus/_cloud.py vendored Normal file
View file

@ -0,0 +1,214 @@
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to the cloud."""
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, overload
import babase
if TYPE_CHECKING:
from typing import Callable, Any
from efro.message import Message, Response
import bacommon.cloud
DEBUG_LOG = False
# TODO: Should make it possible to define a protocol in bacommon.cloud and
# autogenerate this. That would give us type safety between this and
# internal protocols.
class CloudSubsystem(babase.AppSubsystem):
"""Manages communication with cloud components."""
@property
def connected(self) -> bool:
"""Property equivalent of CloudSubsystem.is_connected()."""
return self.is_connected()
def is_connected(self) -> bool:
"""Return whether a connection to the cloud is present.
This is a good indicator (though not for certain) that sending
messages will succeed.
"""
return False # Needs to be overridden
def on_connectivity_changed(self, connected: bool) -> None:
"""Called when cloud connectivity state changes."""
if DEBUG_LOG:
logging.debug('CloudSubsystem: Connectivity is now %s.', connected)
plus = babase.app.plus
assert plus is not None
# Inform things that use this.
# (TODO: should generalize this into some sort of registration system)
plus.accounts.on_cloud_connectivity_changed(connected)
@overload
def send_message_cb(
self,
msg: bacommon.cloud.LoginProxyRequestMessage,
on_response: Callable[
[bacommon.cloud.LoginProxyRequestResponse | Exception], None
],
) -> None:
...
@overload
def send_message_cb(
self,
msg: bacommon.cloud.LoginProxyStateQueryMessage,
on_response: Callable[
[bacommon.cloud.LoginProxyStateQueryResponse | Exception], None
],
) -> None:
...
@overload
def send_message_cb(
self,
msg: bacommon.cloud.LoginProxyCompleteMessage,
on_response: Callable[[None | Exception], None],
) -> None:
...
@overload
def send_message_cb(
self,
msg: bacommon.cloud.PingMessage,
on_response: Callable[[bacommon.cloud.PingResponse | Exception], None],
) -> None:
...
@overload
def send_message_cb(
self,
msg: bacommon.cloud.SignInMessage,
on_response: Callable[
[bacommon.cloud.SignInResponse | Exception], None
],
) -> None:
...
@overload
def send_message_cb(
self,
msg: bacommon.cloud.ManageAccountMessage,
on_response: Callable[
[bacommon.cloud.ManageAccountResponse | Exception], None
],
) -> None:
...
def send_message_cb(
self,
msg: Message,
on_response: Callable[[Any], None],
) -> None:
"""Asynchronously send a message to the cloud from the logic thread.
The provided on_response call will be run in the logic thread
and passed either the response or the error that occurred.
"""
del msg # Unused.
babase.pushcall(
babase.Call(
on_response,
RuntimeError('Cloud functionality is not available.'),
)
)
@overload
def send_message(
self, msg: bacommon.cloud.WorkspaceFetchMessage
) -> bacommon.cloud.WorkspaceFetchResponse:
...
@overload
def send_message(
self, msg: bacommon.cloud.MerchAvailabilityMessage
) -> bacommon.cloud.MerchAvailabilityResponse:
...
@overload
def send_message(
self, msg: bacommon.cloud.TestMessage
) -> bacommon.cloud.TestResponse:
...
def send_message(self, msg: Message) -> Response | None:
"""Synchronously send a message to the cloud.
Must be called from a background thread.
"""
raise RuntimeError('Cloud functionality is not available.')
@overload
async def send_message_async(
self, msg: bacommon.cloud.PromoCodeMessage
) -> bacommon.cloud.PromoCodeResponse:
...
@overload
async def send_message_async(
self, msg: bacommon.cloud.TestMessage
) -> bacommon.cloud.TestResponse:
...
async def send_message_async(self, msg: Message) -> Response | None:
"""Synchronously send a message to the cloud.
Must be called from the logic thread.
"""
raise RuntimeError('Cloud functionality is not available.')
def cloud_console_exec(code: str) -> None:
"""Called by the cloud console to run code in the logic thread."""
import sys
import __main__
try:
# First try it as eval.
try:
evalcode = compile(code, '<console>', 'eval')
except SyntaxError:
evalcode = None
except Exception:
# hmm; when we can't compile it as eval will we always get
# syntax error?
logging.exception(
'unexpected error compiling code for cloud-console eval.'
)
evalcode = None
if evalcode is not None:
# pylint: disable=eval-used
value = eval(evalcode, vars(__main__), vars(__main__))
# For eval-able statements, print the resulting value if
# it is not None (just like standard Python interpreter).
if value is not None:
print(repr(value), file=sys.stderr)
# Fall back to exec if we couldn't compile it as eval.
else:
execcode = compile(code, '<console>', 'exec')
# pylint: disable=exec-used
exec(execcode, vars(__main__), vars(__main__))
except Exception:
import traceback
apptime = babase.apptime()
print(f'Exec error at time {apptime:.2f}.', file=sys.stderr)
traceback.print_exc()
# This helps the logging system ship stderr back to the
# cloud promptly.
sys.stderr.flush()

View file

@ -5,13 +5,17 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _baplus from typing_extensions import override
from babase import AppSubsystem from babase import AppSubsystem
import _baplus
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Callable, Any from typing import Callable, Any
from babase import CloudSubsystem, AccountV2Subsystem from babase import AccountV2Subsystem
from baplus._cloud import CloudSubsystem
class PlusSubsystem(AppSubsystem): class PlusSubsystem(AppSubsystem):
@ -32,6 +36,7 @@ class PlusSubsystem(AppSubsystem):
accounts: AccountV2Subsystem accounts: AccountV2Subsystem
cloud: CloudSubsystem cloud: CloudSubsystem
@override
def on_app_loading(self) -> None: def on_app_loading(self) -> None:
_baplus.on_app_loading() _baplus.on_app_loading()
self.accounts.on_app_loading() self.accounts.on_app_loading()

View file

@ -103,6 +103,7 @@ from _bascenev1 import (
host_scan_cycle, host_scan_cycle,
InputDevice, InputDevice,
is_in_replay, is_in_replay,
is_replay_paused,
ls_input_devices, ls_input_devices,
ls_objects, ls_objects,
Material, Material,
@ -112,11 +113,13 @@ from _bascenev1 import (
newactivity, newactivity,
newnode, newnode,
Node, Node,
pause_replay,
printnodes, printnodes,
protocol_version, protocol_version,
release_gamepad_input, release_gamepad_input,
release_keyboard_input, release_keyboard_input,
reset_random_player_names, reset_random_player_names,
resume_replay,
broadcastmessage, broadcastmessage,
SessionData, SessionData,
SessionPlayer, SessionPlayer,
@ -352,6 +355,7 @@ __all__ = [
'IntSetting', 'IntSetting',
'is_in_replay', 'is_in_replay',
'is_point_in_box', 'is_point_in_box',
'is_replay_paused',
'JoinActivity', 'JoinActivity',
'Level', 'Level',
'Lobby', 'Lobby',
@ -374,6 +378,7 @@ __all__ = [
'normalized_color', 'normalized_color',
'NotFoundError', 'NotFoundError',
'OutOfBoundsMessage', 'OutOfBoundsMessage',
'pause_replay',
'PickedUpMessage', 'PickedUpMessage',
'PickUpMessage', 'PickUpMessage',
'Player', 'Player',
@ -394,6 +399,7 @@ __all__ = [
'release_gamepad_input', 'release_gamepad_input',
'release_keyboard_input', 'release_keyboard_input',
'reset_random_player_names', 'reset_random_player_names',
'resume_replay',
'safecolor', 'safecolor',
'screenmessage', 'screenmessage',
'SceneV1AppMode', 'SceneV1AppMode',

View file

@ -5,6 +5,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -34,11 +35,13 @@ class EndSessionActivity(Activity[EmptyPlayer, EmptyTeam]):
self.inherits_vr_camera_offset = True self.inherits_vr_camera_offset = True
self.inherits_vr_overlay_center = True self.inherits_vr_overlay_center = True
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
babase.fade_screen(False) babase.fade_screen(False)
babase.lock_all_input() babase.lock_all_input()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
@ -77,6 +80,7 @@ class JoinActivity(Activity[EmptyPlayer, EmptyTeam]):
self._tips_text: bascenev1.Actor | None = None self._tips_text: bascenev1.Actor | None = None
self._join_info: JoinInfo | None = None self._join_info: JoinInfo | None = None
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bascenev1lib.actor.tipstext import TipsText from bascenev1lib.actor.tipstext import TipsText
@ -110,6 +114,7 @@ class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]):
super().__init__(settings) super().__init__(settings)
self._background: bascenev1.Actor | None = None self._background: bascenev1.Actor | None = None
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bascenev1lib.actor.background import Background from bascenev1lib.actor.background import Background
@ -119,6 +124,7 @@ class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]):
fade_time=0.5, start_faded=False, show_logo=False fade_time=0.5, start_faded=False, show_logo=False
) )
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
@ -152,6 +158,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
self._custom_continue_message: babase.Lstr | None = None self._custom_continue_message: babase.Lstr | None = None
self._server_transitioning: bool | None = None self._server_transitioning: bool | None = None
@override
def on_player_join(self, player: EmptyPlayer) -> None: def on_player_join(self, player: EmptyPlayer) -> None:
super().on_player_join(player) super().on_player_join(player)
time_till_assign = max( time_till_assign = max(
@ -164,6 +171,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
time_till_assign, babase.WeakCall(self._safe_assign, player) time_till_assign, babase.WeakCall(self._safe_assign, player)
) )
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
from bascenev1lib.actor.tipstext import TipsText from bascenev1lib.actor.tipstext import TipsText
from bascenev1lib.actor.background import Background from bascenev1lib.actor.background import Background
@ -176,6 +184,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]):
self._tips_text = TipsText() self._tips_text = TipsText()
setmusic(self.default_music) setmusic(self.default_music)
@override
def on_begin(self) -> None: def on_begin(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bascenev1lib.actor.text import Text from bascenev1lib.actor.text import Text

View file

@ -5,8 +5,15 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from bacommon.app import AppExperience from bacommon.app import AppExperience
from babase import AppMode, AppIntentExec, AppIntentDefault from babase import (
app,
AppMode,
AppIntentExec,
AppIntentDefault,
invoke_main_menu,
)
import _bascenev1 import _bascenev1
@ -17,15 +24,18 @@ if TYPE_CHECKING:
class SceneV1AppMode(AppMode): class SceneV1AppMode(AppMode):
"""Our app-mode.""" """Our app-mode."""
@override
@classmethod @classmethod
def get_app_experience(cls) -> AppExperience: def get_app_experience(cls) -> AppExperience:
return AppExperience.MELEE return AppExperience.MELEE
@override
@classmethod @classmethod
def _supports_intent(cls, intent: AppIntent) -> bool: def _supports_intent(cls, intent: AppIntent) -> bool:
# We support default and exec intents currently. # We support default and exec intents currently.
return isinstance(intent, AppIntentExec | AppIntentDefault) return isinstance(intent, AppIntentExec | AppIntentDefault)
@override
def handle_intent(self, intent: AppIntent) -> None: def handle_intent(self, intent: AppIntent) -> None:
if isinstance(intent, AppIntentExec): if isinstance(intent, AppIntentExec):
_bascenev1.handle_app_intent_exec(intent.code) _bascenev1.handle_app_intent_exec(intent.code)
@ -33,10 +43,19 @@ class SceneV1AppMode(AppMode):
assert isinstance(intent, AppIntentDefault) assert isinstance(intent, AppIntentDefault)
_bascenev1.handle_app_intent_default() _bascenev1.handle_app_intent_default()
@override
def on_activate(self) -> None: def on_activate(self) -> None:
# Let the native layer do its thing. # Let the native layer do its thing.
_bascenev1.on_app_mode_activate() _bascenev1.on_app_mode_activate()
@override
def on_deactivate(self) -> None: def on_deactivate(self) -> None:
# Let the native layer do its thing. # Let the native layer do its thing.
_bascenev1.on_app_mode_deactivate() _bascenev1.on_app_mode_deactivate()
@override
def on_app_active_changed(self) -> None:
# If we've gone inactive, bring up the main menu, which has the
# side effect of pausing the action (when possible).
if not app.active:
invoke_main_menu()

View file

@ -6,6 +6,7 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING, TypeVar from typing import TYPE_CHECKING, TypeVar
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -31,6 +32,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
# We can assume our session is a CoopSession. # We can assume our session is a CoopSession.
session: bascenev1.CoopSession session: bascenev1.CoopSession
@override
@classmethod @classmethod
def supports_session_type( def supports_session_type(
cls, sessiontype: type[bascenev1.Session] cls, sessiontype: type[bascenev1.Session]
@ -49,6 +51,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
self._life_warning_beep_timer: bascenev1.Timer | None = None self._life_warning_beep_timer: bascenev1.Timer | None = None
self._warn_beeps_sound = _bascenev1.getsound('warnBeeps') self._warn_beeps_sound = _bascenev1.getsound('warnBeeps')
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
@ -139,6 +142,7 @@ class CoopGameActivity(GameActivity[PlayerT, TeamT]):
) )
vval -= 55 vval -= 55
@override
def spawn_player_spaz( def spawn_player_spaz(
self, self,
player: PlayerT, player: PlayerT,

View file

@ -5,6 +5,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -97,6 +98,7 @@ class CoopSession(Session):
"""Get the game instance currently being played.""" """Get the game instance currently being played."""
return self._current_game_instance return self._current_game_instance
@override
def should_allow_mid_activity_joins( def should_allow_mid_activity_joins(
self, activity: bascenev1.Activity self, activity: bascenev1.Activity
) -> bool: ) -> bool:
@ -174,9 +176,11 @@ class CoopSession(Session):
self._tutorial_activity = _bascenev1.newactivity(TutorialActivity) self._tutorial_activity = _bascenev1.newactivity(TutorialActivity)
@override
def get_custom_menu_entries(self) -> list[dict[str, Any]]: def get_custom_menu_entries(self) -> list[dict[str, Any]]:
return self._custom_menu_ui return self._custom_menu_ui
@override
def on_player_leave(self, sessionplayer: bascenev1.SessionPlayer) -> None: def on_player_leave(self, sessionplayer: bascenev1.SessionPlayer) -> None:
super().on_player_leave(sessionplayer) super().on_player_leave(sessionplayer)
@ -256,6 +260,7 @@ class CoopSession(Session):
activity.end(results={'outcome': 'restart'}, force=True) activity.end(results={'outcome': 'restart'}, force=True)
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
@override
def on_activity_end( def on_activity_end(
self, activity: bascenev1.Activity, results: Any self, activity: bascenev1.Activity, results: Any
) -> None: ) -> None:

View file

@ -7,6 +7,7 @@ from __future__ import annotations
import weakref import weakref
from typing import Generic, TypeVar, TYPE_CHECKING from typing import Generic, TypeVar, TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -313,6 +314,7 @@ class AssetPackage(DependencyComponent):
self.package_id = entry.config self.package_id = entry.config
print(f'LOADING ASSET PACKAGE {self.package_id}') print(f'LOADING ASSET PACKAGE {self.package_id}')
@override
@classmethod @classmethod
def dep_is_present(cls, config: Any = None) -> bool: def dep_is_present(cls, config: Any = None) -> bool:
assert isinstance(config, str) assert isinstance(config, str)

View file

@ -5,6 +5,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -32,6 +33,7 @@ class DualTeamSession(MultiTeamSession):
babase.increment_analytics_count('Teams session start') babase.increment_analytics_count('Teams session start')
super().__init__() super().__init__()
@override
def _switch_to_score_screen(self, results: bascenev1.GameResults) -> None: def _switch_to_score_screen(self, results: bascenev1.GameResults) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bascenev1lib.activity.multiteamvictory import ( from bascenev1lib.activity.multiteamvictory import (

View file

@ -6,6 +6,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -53,6 +54,7 @@ class FreeForAllSession(MultiTeamSession):
babase.increment_analytics_count('Free-for-all session start') babase.increment_analytics_count('Free-for-all session start')
super().__init__() super().__init__()
@override
def _switch_to_score_screen(self, results: bascenev1.GameResults) -> None: def _switch_to_score_screen(self, results: bascenev1.GameResults) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from efro.util import asserttype from efro.util import asserttype

View file

@ -9,6 +9,7 @@ import random
import logging import logging
from typing import TYPE_CHECKING, TypeVar from typing import TYPE_CHECKING, TypeVar
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -377,6 +378,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
""" """
return '' return ''
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
@ -488,6 +490,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
self.end_game() self.end_game()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
@ -536,12 +539,14 @@ class GameActivity(Activity[PlayerT, TeamT]):
max(5, data_t[0]['timeRemaining']) max(5, data_t[0]['timeRemaining'])
) )
@override
def on_player_join(self, player: PlayerT) -> None: def on_player_join(self, player: PlayerT) -> None:
super().on_player_join(player) super().on_player_join(player)
# By default, just spawn a dude. # By default, just spawn a dude.
self.spawn_player(player) self.spawn_player(player)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, PlayerDiedMessage): if isinstance(msg, PlayerDiedMessage):
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
@ -835,6 +840,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0}) animate(combine, 'input3', {0: 0, 1.0: 1, 4.0: 1, 5.0: 0})
_bascenev1.timer(5.0, tnode.delete) _bascenev1.timer(5.0, tnode.delete)
@override
def end( def end(
self, results: Any = None, delay: float = 0.0, force: bool = False self, results: Any = None, delay: float = 0.0, force: bool = False
) -> None: ) -> None:

View file

@ -7,6 +7,7 @@ import copy
import weakref import weakref
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
if TYPE_CHECKING: if TYPE_CHECKING:
@ -38,6 +39,7 @@ class Level:
self._index: int | None = None self._index: int | None = None
self._score_version_string: str | None = None self._score_version_string: str | None = None
@override
def __repr__(self) -> str: def __repr__(self) -> str:
cls = type(self) cls = type(self)
return f"<{cls.__module__}.{cls.__name__} '{self._name}'>" return f"<{cls.__module__}.{cls.__name__} '{self._name}'>"

View file

@ -441,7 +441,7 @@ class Chooser:
# list might have changed. # list might have changed.
input_device = self._sessionplayer.inputdevice input_device = self._sessionplayer.inputdevice
is_remote = input_device.is_remote_client is_remote = input_device.is_remote_client
is_test_input = input_device.name.startswith('TestInput') is_test_input = input_device.is_test_input
# Pull this player's list of unlocked characters. # Pull this player's list of unlocked characters.
if is_remote: if is_remote:

View file

@ -6,6 +6,7 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -353,9 +354,11 @@ class Map(Actor):
return self.flag_points_default[:3] return self.flag_points_default[:3]
return self.flag_points[team_index % len(self.flag_points)][:3] return self.flag_points[team_index % len(self.flag_points)][:3]
@override
def exists(self) -> bool: def exists(self) -> bool:
return bool(self.node) return bool(self.node)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
from bascenev1 import _messages from bascenev1 import _messages

View file

@ -8,7 +8,9 @@ import random
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
from bascenev1._session import Session from bascenev1._session import Session
@ -70,6 +72,10 @@ class MultiTeamSession(Session):
show_tutorial = cfg.get('Show Tutorial', True) show_tutorial = cfg.get('Show Tutorial', True)
# Special case: don't show tutorial while stress testing.
if classic.stress_test_update_timer is not None:
show_tutorial = False
self._tutorial_activity_instance: bascenev1.Activity | None self._tutorial_activity_instance: bascenev1.Activity | None
if show_tutorial: if show_tutorial:
from bascenev1lib.tutorial import TutorialActivity from bascenev1lib.tutorial import TutorialActivity
@ -164,6 +170,7 @@ class MultiTeamSession(Session):
"""Returns which game in the series is currently being played.""" """Returns which game in the series is currently being played."""
return self._game_number return self._game_number
@override
def on_team_join(self, team: bascenev1.SessionTeam) -> None: def on_team_join(self, team: bascenev1.SessionTeam) -> None:
team.customdata['previous_score'] = team.customdata['score'] = 0 team.customdata['previous_score'] = team.customdata['score'] = 0
@ -182,6 +189,7 @@ class MultiTeamSession(Session):
self._next_game_spec['settings'], self._next_game_spec['settings'],
) )
@override
def on_activity_end( def on_activity_end(
self, activity: bascenev1.Activity, results: Any self, activity: bascenev1.Activity, results: Any
) -> None: ) -> None:

View file

@ -6,6 +6,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from bascenev1._messages import DieMessage from bascenev1._messages import DieMessage
from bascenev1._actor import Actor from bascenev1._actor import Actor
@ -28,6 +30,7 @@ class NodeActor(Actor):
super().__init__() super().__init__()
self.node = node self.node = node
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, DieMessage): if isinstance(msg, DieMessage):
if self.node: if self.node:
@ -35,5 +38,6 @@ class NodeActor(Actor):
return None return None
return super().handlemessage(msg) return super().handlemessage(msg)
@override
def exists(self) -> bool: def exists(self) -> bool:
return bool(self.node) return bool(self.node)

View file

@ -253,7 +253,7 @@ class Session:
# Limit player counts *unless* we're in a stress test. # Limit player counts *unless* we're in a stress test.
if ( if (
babase.app.classic is not None babase.app.classic is not None
and babase.app.classic.stress_test_reset_timer is None and babase.app.classic.stress_test_update_timer is None
): ):
if len(self.sessionplayers) >= self.max_players: if len(self.sessionplayers) >= self.max_players:
# Print a rejection message *only* to the client trying to # Print a rejection message *only* to the client trying to

View file

@ -7,6 +7,7 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING, TypeVar from typing import TYPE_CHECKING, TypeVar
from typing_extensions import override
import babase import babase
import _bascenev1 import _bascenev1
@ -35,6 +36,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
bascenev1.Player has their own bascenev1.Team) bascenev1.Player has their own bascenev1.Team)
""" """
@override
@classmethod @classmethod
def supports_session_type( def supports_session_type(
cls, sessiontype: type[bascenev1.Session] cls, sessiontype: type[bascenev1.Session]
@ -57,6 +59,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
if isinstance(self.session, FreeForAllSession): if isinstance(self.session, FreeForAllSession):
self.show_kill_points = False self.show_kill_points = False
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
# pylint: disable=cyclic-import # pylint: disable=cyclic-import
from bascenev1._coopsession import CoopSession from bascenev1._coopsession import CoopSession
@ -67,7 +70,9 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
# On the first game, show the controls UI momentarily. # On the first game, show the controls UI momentarily.
# (unless we're being run in co-op mode, in which case we leave # (unless we're being run in co-op mode, in which case we leave
# it up to them) # it up to them)
if not isinstance(self.session, CoopSession): if not isinstance(self.session, CoopSession) and getattr(
self, 'show_controls_guide', True
):
attrname = '_have_shown_ctrl_help_overlay' attrname = '_have_shown_ctrl_help_overlay'
if not getattr(self.session, attrname, False): if not getattr(self.session, attrname, False):
delay = 4.0 delay = 4.0
@ -83,6 +88,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
).autoretain() ).autoretain()
setattr(self.session, attrname, True) setattr(self.session, attrname, True)
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
try: try:
@ -102,6 +108,7 @@ class TeamGameActivity(GameActivity[PlayerT, TeamT]):
except Exception: except Exception:
logging.exception('Error in on_begin.') logging.exception('Error in on_begin.')
@override
def spawn_player_spaz( def spawn_player_spaz(
self, self,
player: PlayerT, player: PlayerT,

View file

@ -4,6 +4,7 @@
from __future__ import annotations from __future__ import annotations
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
@ -18,6 +19,7 @@ class CoopJoinActivity(bs.JoinActivity):
session = self.session session = self.session
assert isinstance(session, bs.CoopSession) assert isinstance(session, bs.CoopSession)
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
from bascenev1lib.actor.controlsguide import ControlsGuide from bascenev1lib.actor.controlsguide import ControlsGuide
from bascenev1lib.actor.text import Text from bascenev1lib.actor.text import Text

View file

@ -9,6 +9,7 @@ import random
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
from bacommon.login import LoginType from bacommon.login import LoginType
import bascenev1 as bs import bascenev1 as bs
import bauiv1 as bui import bauiv1 as bui
@ -186,6 +187,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
self._victory: bool = settings['outcome'] == 'victory' self._victory: bool = settings['outcome'] == 'victory'
@override
def __del__(self) -> None: def __del__(self) -> None:
super().__del__() super().__del__()
@ -194,6 +196,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
with bui.ContextRef.empty(): with bui.ContextRef.empty():
bui.containerwidget(edit=self._root_ui, transition='out_left') bui.containerwidget(edit=self._root_ui, transition='out_left')
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
from bascenev1lib.actor import background # FIXME NO BSSTD from bascenev1lib.actor import background # FIXME NO BSSTD
@ -574,6 +577,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
self._player_press, self._player_press,
) )
@override
def on_player_join(self, player: bs.Player) -> None: def on_player_join(self, player: bs.Player) -> None:
super().on_player_join(player) super().on_player_join(player)
@ -585,6 +589,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
bs.timer(time_till_assign, bs.WeakCall(self._safe_assign, player)) bs.timer(time_till_assign, bs.WeakCall(self._safe_assign, player))
@override
def on_begin(self) -> None: def on_begin(self) -> None:
# FIXME: Clean this up. # FIXME: Clean this up.
# pylint: disable=too-many-statements # pylint: disable=too-many-statements

View file

@ -4,7 +4,9 @@
from __future__ import annotations from __future__ import annotations
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
from bascenev1lib.actor.zoomtext import ZoomText from bascenev1lib.actor.zoomtext import ZoomText
@ -14,6 +16,7 @@ class DrawScoreScreenActivity(MultiTeamScoreScreenActivity):
default_music = None # Awkward silence... default_music = None # Awkward silence...
@override
def on_begin(self) -> None: def on_begin(self) -> None:
bs.set_analytics_screen('Draw Score Screen') bs.set_analytics_screen('Draw Score Screen')
super().on_begin() super().on_begin()

View file

@ -4,7 +4,9 @@
from __future__ import annotations from __future__ import annotations
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
from bascenev1lib.actor.zoomtext import ZoomText from bascenev1lib.actor.zoomtext import ZoomText
@ -17,6 +19,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
self._winner: bs.SessionTeam = settings['winner'] self._winner: bs.SessionTeam = settings['winner']
assert isinstance(self._winner, bs.SessionTeam) assert isinstance(self._winner, bs.SessionTeam)
@override
def on_begin(self) -> None: def on_begin(self) -> None:
bs.set_analytics_screen('Teams Score Screen') bs.set_analytics_screen('Teams Score Screen')
super().on_begin() super().on_begin()

View file

@ -6,9 +6,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any from typing import Any
@ -23,6 +25,7 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
self.transition_time = 0.5 self.transition_time = 0.5
self._cymbal_sound = bs.getsound('cymbal') self._cymbal_sound = bs.getsound('cymbal')
@override
def on_begin(self) -> None: def on_begin(self) -> None:
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
# pylint: disable=too-many-statements # pylint: disable=too-many-statements

View file

@ -4,7 +4,9 @@
from __future__ import annotations from __future__ import annotations
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.actor.text import Text from bascenev1lib.actor.text import Text
@ -15,6 +17,7 @@ class MultiTeamJoinActivity(bs.JoinActivity):
super().__init__(settings) super().__init__(settings)
self._next_up_text: Text | None = None self._next_up_text: Text | None = None
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
from bascenev1lib.actor.controlsguide import ControlsGuide from bascenev1lib.actor.controlsguide import ControlsGuide

View file

@ -3,7 +3,9 @@
"""Functionality related to teams mode score screen.""" """Functionality related to teams mode score screen."""
from __future__ import annotations from __future__ import annotations
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.actor.text import Text from bascenev1lib.actor.text import Text
from bascenev1lib.actor.image import Image from bascenev1lib.actor.image import Image
@ -18,6 +20,7 @@ class MultiTeamScoreScreenActivity(bs.ScoreScreenActivity):
self._show_up_next: bool = True self._show_up_next: bool = True
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
session = self.session session = self.session

View file

@ -4,7 +4,9 @@
from __future__ import annotations from __future__ import annotations
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity
@ -22,6 +24,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
self._tips_text = None self._tips_text = None
self._default_show_tips = False self._default_show_tips = False
@override
def on_begin(self) -> None: def on_begin(self) -> None:
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
# pylint: disable=too-many-locals # pylint: disable=too-many-locals

View file

@ -9,6 +9,7 @@ import weakref
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -104,6 +105,7 @@ class Background(bs.Actor):
timeval += random.random() * 0.1 timeval += random.random() * 0.1
bs.animate(cmb, 'input1', keys, loop=True) bs.animate(cmb, 'input1', keys, loop=True)
@override
def __del__(self) -> None: def __del__(self) -> None:
# Normal actors don't get sent DieMessages when their # Normal actors don't get sent DieMessages when their
# activity is shutting down, but we still need to do so # activity is shutting down, but we still need to do so
@ -138,6 +140,7 @@ class Background(bs.Actor):
) )
bs.timer(self.fade_time + 0.1, self.node.delete) bs.timer(self.fade_time + 0.1, self.node.delete)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -10,7 +10,9 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING, TypeVar from typing import TYPE_CHECKING, TypeVar
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
@ -661,6 +663,7 @@ class Blast(bs.Actor):
bs.timer(0.4, _extra_debris_sound) bs.timer(0.4, _extra_debris_sound)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
@ -935,6 +938,7 @@ class Bomb(bs.Actor):
else None else None
) )
@override
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()
@ -1140,19 +1144,18 @@ class Bomb(bs.Actor):
if msg.srcnode: if msg.srcnode:
pass pass
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ExplodeMessage): if isinstance(msg, ExplodeMessage):
self.explode() self.explode()
elif isinstance(msg, ImpactMessage): elif isinstance(msg, ImpactMessage):
self._handle_impact() self._handle_impact()
# Ok the logic below looks like it was backwards to me. elif isinstance(msg, bs.PickedUpMessage):
# Disabling for now; can bring back if need be. # Change our source to whoever just picked us up *only* if it
# elif isinstance(msg, bs.PickedUpMessage): # is None. This way we can get points for killing bots with their
# # Change our source to whoever just picked us up *only* if it # own bombs. Hmm would there be a downside to this?
# # is None. This way we can get points for killing bots with their if self._source_player is None:
# # own bombs. Hmm would there be a downside to this? self._source_player = msg.node.source_player
# if self._source_player is not None:
# self._source_player = msg.node.source_player
elif isinstance(msg, SplatMessage): elif isinstance(msg, SplatMessage):
self._handle_splat() self._handle_splat()
elif isinstance(msg, bs.DroppedMessage): elif isinstance(msg, bs.DroppedMessage):

View file

@ -6,6 +6,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -547,9 +548,11 @@ class ControlsGuide(bs.Actor):
self._update_timer = None self._update_timer = None
self._dead = True self._dead = True
@override
def exists(self) -> bool: def exists(self) -> bool:
return not self._dead return not self._dead
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -7,9 +7,11 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from bascenev1lib.gameutils import SharedObjects from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -328,6 +330,7 @@ class Flag(bs.Actor):
1.0, bs.WeakCall(self._hide_score_text) 1.0, bs.WeakCall(self._hide_score_text)
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -7,6 +7,7 @@ from __future__ import annotations
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -165,6 +166,7 @@ class Image(bs.Actor):
bs.WeakCall(self.handlemessage, bs.DieMessage()), bs.WeakCall(self.handlemessage, bs.DieMessage()),
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -6,6 +6,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -72,6 +73,7 @@ class OnScreenCountdown(bs.Actor):
) )
self._timer = bs.Timer(1.0, self._update, repeat=True) self._timer = bs.Timer(1.0, self._update, repeat=True)
@override
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()

View file

@ -6,6 +6,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import logging import logging
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -93,6 +94,7 @@ class OnScreenTimer(bs.Actor):
"""Shortcut for start time in seconds.""" """Shortcut for start time in seconds."""
return self.getstarttime() return self.getstarttime()
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# if we're asked to die, just kill our node/timer # if we're asked to die, just kill our node/timer
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -6,7 +6,9 @@ from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, overload from typing import TYPE_CHECKING, TypeVar, overload
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.actor.spaz import Spaz from bascenev1lib.actor.spaz import Spaz
if TYPE_CHECKING: if TYPE_CHECKING:
@ -183,6 +185,7 @@ class PlayerSpaz(Spaz):
' non-connected player' ' non-connected player'
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# FIXME: Tidy this up. # FIXME: Tidy this up.
# pylint: disable=too-many-branches # pylint: disable=too-many-branches

View file

@ -7,6 +7,7 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -118,6 +119,7 @@ class PopupText(bs.Actor):
lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()) lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage())
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -7,7 +7,9 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING: if TYPE_CHECKING:
@ -278,6 +280,7 @@ class PowerupBox(bs.Actor):
if self.node: if self.node:
self.node.flashing = True self.node.flashing = True
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired

View file

@ -9,11 +9,13 @@ import random
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.bomb import Bomb, Blast from bascenev1lib.actor.bomb import Bomb, Blast
from bascenev1lib.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.actor.spazfactory import SpazFactory from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence, Callable from typing import Any, Sequence, Callable
@ -228,9 +230,11 @@ class Spaz(bs.Actor):
self.punch_callback: Callable[[Spaz], Any] | None = None self.punch_callback: Callable[[Spaz], Any] | None = None
self.pick_up_powerup_callback: Callable[[Spaz], Any] | None = None self.pick_up_powerup_callback: Callable[[Spaz], Any] | None = None
@override
def exists(self) -> bool: def exists(self) -> bool:
return bool(self.node) return bool(self.node)
@override
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()
@ -249,6 +253,7 @@ class Spaz(bs.Actor):
assert not self.expired assert not self.expired
self._dropped_bomb_callbacks.append(call) self._dropped_bomb_callbacks.append(call)
@override
def is_alive(self) -> bool: def is_alive(self) -> bool:
""" """
Method override; returns whether ol' spaz is still kickin'. Method override; returns whether ol' spaz is still kickin'.
@ -694,6 +699,7 @@ class Spaz(bs.Actor):
else: else:
self.shield_decay_timer = None self.shield_decay_timer = None
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# pylint: disable=too-many-return-statements # pylint: disable=too-many-return-statements
# pylint: disable=too-many-statements # pylint: disable=too-many-statements

View file

@ -10,6 +10,7 @@ import weakref
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
from bascenev1lib.actor.spaz import Spaz from bascenev1lib.actor.spaz import Spaz
@ -489,6 +490,7 @@ class SpazBot(Spaz):
self.on_punch_press() self.on_punch_press()
self.on_punch_release() self.on_punch_release()
@override
def on_punched(self, damage: int) -> None: def on_punched(self, damage: int) -> None:
""" """
Method override; sends bs.SpazBotPunchedMessage Method override; sends bs.SpazBotPunchedMessage
@ -496,6 +498,7 @@ class SpazBot(Spaz):
""" """
bs.getactivity().handlemessage(SpazBotPunchedMessage(self, damage)) bs.getactivity().handlemessage(SpazBotPunchedMessage(self, damage))
@override
def on_expire(self) -> None: def on_expire(self) -> None:
super().on_expire() super().on_expire()
@ -503,6 +506,7 @@ class SpazBot(Spaz):
# no chance of them keeping activities or other things alive. # no chance of them keeping activities or other things alive.
self.update_callback = None self.update_callback = None
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
assert not self.expired assert not self.expired

View file

@ -7,6 +7,7 @@ from __future__ import annotations
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -221,6 +222,7 @@ class Text(bs.Actor):
bs.WeakCall(self.handlemessage, bs.DieMessage()), bs.WeakCall(self.handlemessage, bs.DieMessage()),
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -6,6 +6,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -95,6 +96,7 @@ class TipsText(bs.Actor):
) )
self.node.text = next_tip self.node.text = next_tip
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -8,6 +8,7 @@ import random
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
@ -158,6 +159,7 @@ class ZoomText(bs.Actor):
if lifespan is not None: if lifespan is not None:
bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage())) bs.timer(lifespan, bs.WeakCall(self.handlemessage, bs.DieMessage()))
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
assert not self.expired assert not self.expired
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):

View file

@ -10,11 +10,13 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.flag import Flag from bascenev1lib.actor.flag import Flag
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -71,10 +73,12 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -96,16 +100,19 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
if self._score_to_win == 1: if self._score_to_win == 1:
return 'Touch the enemy flag.' return 'Touch the enemy flag.'
return 'Touch the enemy flag ${ARG1} times.', self._score_to_win return 'Touch the enemy flag ${ARG1} times.', self._score_to_win
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
if self._score_to_win == 1: if self._score_to_win == 1:
return 'touch 1 flag' return 'touch 1 flag'
return 'touch ${ARG1} flags', self._score_to_win return 'touch ${ARG1} flags', self._score_to_win
@override
def create_team(self, sessionteam: bs.SessionTeam) -> Team: def create_team(self, sessionteam: bs.SessionTeam) -> Team:
shared = SharedObjects.get() shared = SharedObjects.get()
base_pos = self.map.get_flag_position(sessionteam.id) base_pos = self.map.get_flag_position(sessionteam.id)
@ -151,16 +158,19 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
return team return team
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
# Can't do this in create_team because the team's color/etc. have # Can't do this in create_team because the team's color/etc. have
# not been wired up yet at that point. # not been wired up yet at that point.
self._update_scoreboard() self._update_scoreboard()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
self.setup_standard_powerup_drops() self.setup_standard_powerup_drops()
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg) # Augment standard. super().handlemessage(msg) # Augment standard.
@ -249,6 +259,7 @@ class AssaultGame(bs.TeamGameActivity[Player, Team]):
if player_team.score >= self._score_to_win: if player_team.score >= self._score_to_win:
self.end_game() self.end_game()
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:

View file

@ -10,6 +10,9 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.flag import ( from bascenev1lib.actor.flag import (
@ -19,7 +22,6 @@ from bascenev1lib.actor.flag import (
FlagDroppedMessage, FlagDroppedMessage,
FlagDiedMessage, FlagDiedMessage,
) )
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -141,10 +143,12 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -173,16 +177,19 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FLAG_CATCHER bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FLAG_CATCHER
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
if self._score_to_win == 1: if self._score_to_win == 1:
return 'Steal the enemy flag.' return 'Steal the enemy flag.'
return 'Steal the enemy flag ${ARG1} times.', self._score_to_win return 'Steal the enemy flag ${ARG1} times.', self._score_to_win
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
if self._score_to_win == 1: if self._score_to_win == 1:
return 'return 1 flag' return 'return 1 flag'
return 'return ${ARG1} flags', self._score_to_win return 'return ${ARG1} flags', self._score_to_win
@override
def create_team(self, sessionteam: bs.SessionTeam) -> Team: def create_team(self, sessionteam: bs.SessionTeam) -> Team:
# Create our team instance and its initial values. # Create our team instance and its initial values.
@ -272,12 +279,14 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
return team return team
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
# Can't do this in create_team because the team's color/etc. have # Can't do this in create_team because the team's color/etc. have
# not been wired up yet at that point. # not been wired up yet at that point.
self._spawn_flag_for_team(team) self._spawn_flag_for_team(team)
self._update_scoreboard() self._update_scoreboard()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
@ -406,6 +415,7 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
if team.score >= self._score_to_win: if team.score >= self._score_to_win:
self.end_game() self.end_game()
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
@ -532,6 +542,7 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
bs.animate(light, 'intensity', {0.0: 0, 0.25: 2.0, 0.5: 0}, loop=True) bs.animate(light, 'intensity', {0.0: 0, 0.25: 2.0, 0.5: 0}, loop=True)
bs.timer(length, light.delete) bs.timer(length, light.delete)
@override
def spawn_player_spaz( def spawn_player_spaz(
self, self,
player: Player, player: Player,
@ -576,6 +587,7 @@ class CaptureTheFlagGame(bs.TeamGameActivity[Player, Team]):
team, team.score, self._score_to_win team, team.score, self._score_to_win
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg) # Augment standard behavior. super().handlemessage(msg) # Augment standard behavior.

View file

@ -10,11 +10,13 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.flag import Flag from bascenev1lib.actor.flag import Flag
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -83,6 +85,7 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
] ]
scoreconfig = bs.ScoreConfig(label='Time Held') scoreconfig = bs.ScoreConfig(label='Time Held')
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -121,20 +124,25 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.CHOSEN_ONE bs.MusicType.EPIC if self._epic_mode else bs.MusicType.CHOSEN_ONE
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return 'There can be only one.' return 'There can be only one.'
@override
def create_team(self, sessionteam: bs.SessionTeam) -> Team: def create_team(self, sessionteam: bs.SessionTeam) -> Team:
return Team(time_remaining=self._chosen_one_time) return Team(time_remaining=self._chosen_one_time)
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
@override
def on_player_leave(self, player: Player) -> None: def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player) super().on_player_leave(player)
if self._get_chosen_one_player() is player: if self._get_chosen_one_player() is player:
self._set_chosen_one_player(None) self._set_chosen_one_player(None)
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
shared = SharedObjects.get() shared = SharedObjects.get()
@ -251,6 +259,7 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
logging.error('got nonexistent player as chosen one in _tick') logging.error('got nonexistent player as chosen one in _tick')
self._set_chosen_one_player(None) self._set_chosen_one_player(None)
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
@ -335,6 +344,7 @@ class ChosenOneGame(bs.TeamGameActivity[Player, Team]):
'position', light.node, 'position' 'position', light.node, 'position'
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.

View file

@ -10,12 +10,14 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.flag import Flag from bascenev1lib.actor.flag import Flag
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.respawnicon import RespawnIcon from bascenev1lib.actor.respawnicon import RespawnIcon
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -108,10 +110,12 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -143,16 +147,20 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
), ),
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return 'Secure all ${ARG1} flags.', len(self.map.flag_points) return 'Secure all ${ARG1} flags.', len(self.map.flag_points)
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
return 'secure all ${ARG1} flags', len(self.map.flag_points) return 'secure all ${ARG1} flags', len(self.map.flag_points)
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
if self.has_begun(): if self.has_begun():
self._update_scores() self._update_scores()
@override
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
player.respawn_timer = None player.respawn_timer = None
@ -160,6 +168,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
if player.team.flags_held > 0: if player.team.flags_held > 0:
self.spawn_player(player) self.spawn_player(player)
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
@ -221,6 +230,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
team, team.flags_held, len(self._flags) team, team.flags_held, len(self._flags)
) )
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
@ -272,6 +282,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
): ):
self.spawn_player(otherplayer) self.spawn_player(otherplayer)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.
@ -287,6 +298,7 @@ class ConquestGame(bs.TeamGameActivity[Player, Team]):
else: else:
super().handlemessage(msg) super().handlemessage(msg)
@override
def spawn_player(self, player: Player) -> bs.Actor: def spawn_player(self, player: Player) -> bs.Actor:
# We spawn players at different places based on what flags are held. # We spawn players at different places based on what flags are held.
return self.spawn_player_spaz( return self.spawn_player_spaz(

View file

@ -9,9 +9,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -38,6 +40,7 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
# Print messages when players die since it matters here. # Print messages when players die since it matters here.
announce_player_deaths = True announce_player_deaths = True
@override
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[bs.Session] cls, sessiontype: type[bs.Session]
@ -87,12 +90,14 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
return settings return settings
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) or issubclass( return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
sessiontype, bs.FreeForAllSession sessiontype, bs.FreeForAllSession
) )
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -116,16 +121,20 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH bs.MusicType.EPIC if self._epic_mode else bs.MusicType.TO_THE_DEATH
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return 'Crush ${ARG1} of your enemies.', self._score_to_win return 'Crush ${ARG1} of your enemies.', self._score_to_win
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
return 'kill ${ARG1} enemies', self._score_to_win return 'kill ${ARG1} enemies', self._score_to_win
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
if self.has_begun(): if self.has_begun():
self._update_scoreboard() self._update_scoreboard()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
@ -137,6 +146,7 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
) )
self._update_scoreboard() self._update_scoreboard()
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.
@ -197,6 +207,7 @@ class DeathMatchGame(bs.TeamGameActivity[Player, Team]):
team, team.score, self._score_to_win team, team.score, self._score_to_win
) )
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:

View file

@ -10,6 +10,9 @@ from __future__ import annotations
import random import random
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.bomb import Bomb from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage from bascenev1lib.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage
@ -17,7 +20,6 @@ from bascenev1lib.actor.onscreencountdown import OnScreenCountdown
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.respawnicon import RespawnIcon from bascenev1lib.actor.respawnicon import RespawnIcon
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any from typing import Any
@ -51,11 +53,13 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
scoreconfig = bs.ScoreConfig(label='Score', scoretype=bs.ScoreType.POINTS) scoreconfig = bs.ScoreConfig(label='Score', scoretype=bs.ScoreType.POINTS)
# We're currently hard-coded for one map. # We're currently hard-coded for one map.
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
return ['Tower D'] return ['Tower D']
# We support teams, free-for-all, and co-op sessions. # We support teams, free-for-all, and co-op sessions.
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return ( return (
@ -93,11 +97,13 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FORWARD_MARCH
) )
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
if self.has_begun(): if self.has_begun():
self._update_scoreboard() self._update_scoreboard()
# Called when our game actually starts. # Called when our game actually starts.
@override
def on_begin(self) -> None: def on_begin(self) -> None:
from bascenev1lib.maps import TowerD from bascenev1lib.maps import TowerD
@ -118,6 +124,7 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
self._spawn_evil_bunny() self._spawn_evil_bunny()
# Overriding the default character spawning. # Overriding the default character spawning.
@override
def spawn_player(self, player: Player) -> bs.Actor: def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz(player) spaz = self.spawn_player_spaz(player)
spaz.connect_controls_to_player() spaz.connect_controls_to_player()
@ -191,6 +198,7 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
self._eggs.append(Egg(position=(xpos, ypos, zpos))) self._eggs.append(Egg(position=(xpos, ypos, zpos)))
# Various high-level game events come through this method. # Various high-level game events come through this method.
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# Respawn dead players. # Respawn dead players.
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
@ -231,6 +239,7 @@ class EasterEggHuntGame(bs.TeamGameActivity[Player, Team]):
for team in self.teams: for team in self.teams:
self._scoreboard.set_team_value(team, team.score) self._scoreboard.set_team_value(team, team.score)
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
@ -271,9 +280,11 @@ class Egg(bs.Actor):
}, },
) )
@override
def exists(self) -> bool: def exists(self) -> bool:
return bool(self.node) return bool(self.node)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node: if self.node:

View file

@ -10,9 +10,11 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.spazfactory import SpazFactory from bascenev1lib.actor.spazfactory import SpazFactory
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -157,6 +159,7 @@ class Icon(bs.Actor):
if lives == 0: if lives == 0:
bs.timer(0.6, self.update_for_lives) bs.timer(0.6, self.update_for_lives)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):
self.node.delete() self.node.delete()
@ -194,6 +197,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
allow_mid_activity_joins = False allow_mid_activity_joins = False
@override
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: type[bs.Session] cls, sessiontype: type[bs.Session]
@ -238,12 +242,14 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
) )
return settings return settings
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) or issubclass( return issubclass(sessiontype, bs.DualTeamSession) or issubclass(
sessiontype, bs.FreeForAllSession sessiontype, bs.FreeForAllSession
) )
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -269,6 +275,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
return ( return (
'Last team standing wins.' 'Last team standing wins.'
@ -276,6 +283,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
else 'Last one standing wins.' else 'Last one standing wins.'
) )
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
return ( return (
'last team standing wins' 'last team standing wins'
@ -283,6 +291,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
else 'last one standing wins' else 'last one standing wins'
) )
@override
def on_player_join(self, player: Player) -> None: def on_player_join(self, player: Player) -> None:
player.lives = self._lives_per_player player.lives = self._lives_per_player
@ -299,6 +308,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
if self.has_begun(): if self.has_begun():
self._update_icons() self._update_icons()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self._start_time = bs.time() self._start_time = bs.time()
@ -473,6 +483,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
return points[-1][1] return points[-1][1]
return None return None
@override
def spawn_player(self, player: Player) -> bs.Actor: def spawn_player(self, player: Player) -> bs.Actor:
actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) actor = self.spawn_player_spaz(player, self._get_spawn_point(player))
if not self._solo_mode: if not self._solo_mode:
@ -499,6 +510,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
position=player.node.position, position=player.node.position,
).autoretain() ).autoretain()
@override
def on_player_leave(self, player: Player) -> None: def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player) super().on_player_leave(player)
player.icons = [] player.icons = []
@ -522,6 +534,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
def _get_total_team_lives(self, team: Team) -> int: def _get_total_team_lives(self, team: Team) -> int:
return sum(player.lives for player in team.players) return sum(player.lives for player in team.players)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
# Augment standard behavior. # Augment standard behavior.
@ -592,6 +605,7 @@ class EliminationGame(bs.TeamGameActivity[Player, Team]):
and any(player.lives > 0 for player in team.players) and any(player.lives > 0 for player in team.players)
] ]
@override
def end_game(self) -> None: def end_game(self) -> None:
if self.has_ended(): if self.has_ended():
return return

View file

@ -1,5 +1,6 @@
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
# #
# pylint: disable=too-many-lines
"""Implements football games (both co-op and teams varieties).""" """Implements football games (both co-op and teams varieties)."""
# ba_meta require api 8 # ba_meta require api 8
@ -12,6 +13,9 @@ import random
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.bomb import TNTSpawner from bascenev1lib.actor.bomb import TNTSpawner
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
@ -39,7 +43,6 @@ from bascenev1lib.actor.spazbot import (
StickyBot, StickyBot,
ExplodeyBot, ExplodeyBot,
) )
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -128,11 +131,13 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
# We only support two-team play. # We only support two-team play.
return issubclass(sessiontype, bs.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -170,6 +175,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FOOTBALL bs.MusicType.EPIC if self._epic_mode else bs.MusicType.FOOTBALL
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
touchdowns = self._score_to_win / 7 touchdowns = self._score_to_win / 7
@ -181,6 +187,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
return 'Score ${ARG1} touchdowns.', touchdowns return 'Score ${ARG1} touchdowns.', touchdowns
return 'Score a touchdown.' return 'Score a touchdown.'
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
touchdowns = self._score_to_win / 7 touchdowns = self._score_to_win / 7
touchdowns = math.ceil(touchdowns) touchdowns = math.ceil(touchdowns)
@ -188,6 +195,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
return 'score ${ARG1} touchdowns', touchdowns return 'score ${ARG1} touchdowns', touchdowns
return 'score a touchdown' return 'score a touchdown'
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
self.setup_standard_time_limit(self._time_limit) self.setup_standard_time_limit(self._time_limit)
@ -224,6 +232,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
self._update_scoreboard() self._update_scoreboard()
self._chant_sound.play() self._chant_sound.play()
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
@ -285,6 +294,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
bs.cameraflash(duration=10.0) bs.cameraflash(duration=10.0)
self._update_scoreboard() self._update_scoreboard()
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
@ -298,6 +308,7 @@ class FootballTeamGame(bs.TeamGameActivity[Player, Team]):
team, team.score, self._score_to_win team, team.score, self._score_to_win
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, FlagPickedUpMessage): if isinstance(msg, FlagPickedUpMessage):
assert isinstance(msg.flag, FootballFlag) assert isinstance(msg.flag, FootballFlag)
@ -379,9 +390,11 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
default_music = bs.MusicType.FOOTBALL default_music = bs.MusicType.FOOTBALL
# FIXME: Need to update co-op games to use getscoreconfig. # FIXME: Need to update co-op games to use getscoreconfig.
@override
def get_score_type(self) -> str: def get_score_type(self) -> str:
return 'time' return 'time'
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
touchdowns = self._score_to_win / 7 touchdowns = self._score_to_win / 7
touchdowns = math.ceil(touchdowns) touchdowns = math.ceil(touchdowns)
@ -389,6 +402,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
return 'Score ${ARG1} touchdowns.', touchdowns return 'Score ${ARG1} touchdowns.', touchdowns
return 'Score a touchdown.' return 'Score a touchdown.'
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
touchdowns = self._score_to_win / 7 touchdowns = self._score_to_win / 7
touchdowns = math.ceil(touchdowns) touchdowns = math.ceil(touchdowns)
@ -444,6 +458,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
self._flag_respawn_light: bs.Actor | None = None self._flag_respawn_light: bs.Actor | None = None
self._flag: FootballFlag | None = None self._flag: FootballFlag | None = None
@override
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
self._scoreboard = Scoreboard() self._scoreboard = Scoreboard()
@ -480,6 +495,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
) )
self._chant_sound.play() self._chant_sound.play()
@override
def on_begin(self) -> None: def on_begin(self) -> None:
# FIXME: Split this up a bit. # FIXME: Split this up a bit.
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
@ -795,11 +811,13 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
if i == 0: if i == 0:
bs.cameraflash(duration=10.0) bs.cameraflash(duration=10.0)
@override
def end_game(self) -> None: def end_game(self) -> None:
bs.setmusic(None) bs.setmusic(None)
self._bots.final_celebrate() self._bots.final_celebrate()
bs.timer(0.001, bs.Call(self.do_end, 'defeat')) bs.timer(0.001, bs.Call(self.do_end, 'defeat'))
@override
def on_continue(self) -> None: def on_continue(self) -> None:
# Subtract one touchdown from the bots and get them moving again. # Subtract one touchdown from the bots and get them moving again.
assert self._bot_team is not None assert self._bot_team is not None
@ -897,6 +915,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
}, },
) )
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
"""handle high-level game messages""" """handle high-level game messages"""
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):
@ -959,6 +978,7 @@ class FootballCoopGame(bs.CoopGameActivity[Player, Team]):
del player # Unused. del player # Unused.
self._player_has_punched = True self._player_has_punched = True
@override
def spawn_player(self, player: Player) -> bs.Actor: def spawn_player(self, player: Player) -> bs.Actor:
spaz = self.spawn_player_spaz( spaz = self.spawn_player_spaz(
player, position=self.map.get_start_position(player.team.id) player, position=self.map.get_start_position(player.team.id)

View file

@ -9,11 +9,13 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import override
import bascenev1 as bs
from bascenev1lib.actor.playerspaz import PlayerSpaz from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1lib.actor.powerupbox import PowerupBoxFactory from bascenev1lib.actor.powerupbox import PowerupBoxFactory
from bascenev1lib.gameutils import SharedObjects from bascenev1lib.gameutils import SharedObjects
import bascenev1 as bs
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Sequence from typing import Any, Sequence
@ -58,6 +60,7 @@ class Puck(bs.Actor):
) )
bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1}) bs.animate(self.node, 'mesh_scale', {0: 0, 0.2: 1.3, 0.26: 1})
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage): if isinstance(msg, bs.DieMessage):
if self.node: if self.node:
@ -152,10 +155,12 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
bs.BoolSetting('Epic Mode', default=False), bs.BoolSetting('Epic Mode', default=False),
] ]
@override
@classmethod @classmethod
def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool: def supports_session_type(cls, sessiontype: type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession) return issubclass(sessiontype, bs.DualTeamSession)
@override
@classmethod @classmethod
def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]: def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
assert bs.app.classic is not None assert bs.app.classic is not None
@ -231,16 +236,19 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
bs.MusicType.EPIC if self._epic_mode else bs.MusicType.HOCKEY bs.MusicType.EPIC if self._epic_mode else bs.MusicType.HOCKEY
) )
@override
def get_instance_description(self) -> str | Sequence: def get_instance_description(self) -> str | Sequence:
if self._score_to_win == 1: if self._score_to_win == 1:
return 'Score a goal.' return 'Score a goal.'
return 'Score ${ARG1} goals.', self._score_to_win return 'Score ${ARG1} goals.', self._score_to_win
@override
def get_instance_description_short(self) -> str | Sequence: def get_instance_description_short(self) -> str | Sequence:
if self._score_to_win == 1: if self._score_to_win == 1:
return 'score a goal' return 'score a goal'
return 'score ${ARG1} goals', self._score_to_win return 'score ${ARG1} goals', self._score_to_win
@override
def on_begin(self) -> None: def on_begin(self) -> None:
super().on_begin() super().on_begin()
@ -281,6 +289,7 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
self._update_scoreboard() self._update_scoreboard()
self._chant_sound.play() self._chant_sound.play()
@override
def on_team_join(self, team: Team) -> None: def on_team_join(self, team: Team) -> None:
self._update_scoreboard() self._update_scoreboard()
@ -364,6 +373,7 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
bs.cameraflash(duration=10.0) bs.cameraflash(duration=10.0)
self._update_scoreboard() self._update_scoreboard()
@override
def end_game(self) -> None: def end_game(self) -> None:
results = bs.GameResults() results = bs.GameResults()
for team in self.teams: for team in self.teams:
@ -375,6 +385,7 @@ class HockeyGame(bs.TeamGameActivity[Player, Team]):
for team in self.teams: for team in self.teams:
self._scoreboard.set_team_value(team, team.score, winscore) self._scoreboard.set_team_value(team, team.score, winscore)
@override
def handlemessage(self, msg: Any) -> Any: def handlemessage(self, msg: Any) -> Any:
# Respawn dead players if they're still in the game. # Respawn dead players if they're still in the game.
if isinstance(msg, bs.PlayerDiedMessage): if isinstance(msg, bs.PlayerDiedMessage):

Some files were not shown because too many files have changed in this diff Show more