mirror of
https://github.com/imayushsaini/Bombsquad-Ballistica-Modded-Server.git
synced 2025-10-20 00:00:39 +00:00
1.7.5 master sync
This commit is contained in:
parent
421c488c6a
commit
62103ea678
61 changed files with 2001 additions and 1364 deletions
27
dist/ba_data/data/langdata.json
vendored
27
dist/ba_data/data/langdata.json
vendored
|
|
@ -50,6 +50,7 @@
|
|||
"5PH3X",
|
||||
"99",
|
||||
"@sametsunal",
|
||||
"_DraXX",
|
||||
"_Fami",
|
||||
"Omar a",
|
||||
"Bruno A.",
|
||||
|
|
@ -75,7 +76,7 @@
|
|||
"adan",
|
||||
"Adeel (AdeZ {@adez_})",
|
||||
"Adel",
|
||||
"Rio adi",
|
||||
"Rio Adi",
|
||||
"Rayhan Adiansyah",
|
||||
"Yonas Adiel",
|
||||
"admin",
|
||||
|
|
@ -194,6 +195,7 @@
|
|||
"Arin",
|
||||
"Arroz",
|
||||
"ARSHAD",
|
||||
"ArshiyDLn",
|
||||
"Artem",
|
||||
"Valentino Artizzu",
|
||||
"Arxyma",
|
||||
|
|
@ -237,6 +239,7 @@
|
|||
"Bank",
|
||||
"Ibrahim Baraka",
|
||||
"Kamil Barański",
|
||||
"Leonan Barcelos",
|
||||
"Bardiaghasedipour",
|
||||
"William Barnak",
|
||||
"William Barnakk",
|
||||
|
|
@ -248,6 +251,7 @@
|
|||
"Bashkot",
|
||||
"Matthias Bastron",
|
||||
"Ralph Bathmann",
|
||||
"Bato",
|
||||
"Florian Bauernfeind",
|
||||
"David BAUMANN",
|
||||
"bayanus",
|
||||
|
|
@ -273,6 +277,7 @@
|
|||
"Anton Bang Berner",
|
||||
"Felix Bernhard",
|
||||
"Davide Bigotto",
|
||||
"bilibili@Medic药",
|
||||
"Bima",
|
||||
"Biytremni",
|
||||
"Blackcat2960",
|
||||
|
|
@ -316,6 +321,7 @@
|
|||
"Buskebam",
|
||||
"Buto11",
|
||||
"ByAdrianYT",
|
||||
"Semih Byzts",
|
||||
"Mohamad Hossein BZ",
|
||||
"Christoffer Bünner",
|
||||
"mvp aka cactus",
|
||||
|
|
@ -382,6 +388,7 @@
|
|||
"D",
|
||||
"Dada",
|
||||
"Daivaras",
|
||||
"Dajo6596YT",
|
||||
"Dakkat",
|
||||
"Mikkel Damgaard",
|
||||
"Danco",
|
||||
|
|
@ -398,6 +405,7 @@
|
|||
"Dasto",
|
||||
"David",
|
||||
"Davide",
|
||||
"DavidPlayzLol",
|
||||
"DavidPlayzloll",
|
||||
"DaymanLP",
|
||||
"Ddávid",
|
||||
|
|
@ -445,6 +453,7 @@
|
|||
"Dustin",
|
||||
"Paul Duvernay",
|
||||
"Emir İslam Dündar",
|
||||
"E.R.A.L",
|
||||
"Ebutahapro07tr",
|
||||
"Edson",
|
||||
"Glen Edwards",
|
||||
|
|
@ -458,6 +467,7 @@
|
|||
"Rezk ElAdawy",
|
||||
"ElCatCaesar",
|
||||
"ElderLink",
|
||||
"elfree",
|
||||
"Elian",
|
||||
"Elsans320_YT",
|
||||
"Elskoser",
|
||||
|
|
@ -466,6 +476,7 @@
|
|||
"Emil",
|
||||
"Kürti Emil",
|
||||
"Muhammed emir",
|
||||
"Muhammet Emir",
|
||||
"EmirSametEr",
|
||||
"emm",
|
||||
"EnderDust123",
|
||||
|
|
@ -686,8 +697,9 @@
|
|||
"Tobias Dencker Israelsen",
|
||||
"Kegyes István",
|
||||
"Itamar",
|
||||
"ivan",
|
||||
"Ivan",
|
||||
"iViietZ",
|
||||
"JaaJ",
|
||||
"Al jabbar",
|
||||
"Jacek",
|
||||
"Jack556",
|
||||
|
|
@ -729,6 +741,7 @@
|
|||
"joke",
|
||||
"Jonatas",
|
||||
"Jop",
|
||||
"JoseANG3L",
|
||||
"Joseetion",
|
||||
"Joseph",
|
||||
"Joshep",
|
||||
|
|
@ -771,6 +784,7 @@
|
|||
"Mani kelidari",
|
||||
"Kelmine",
|
||||
"Kenjie",
|
||||
"Kerfix",
|
||||
"Kerim",
|
||||
"Khaild1717",
|
||||
"muh khairul",
|
||||
|
|
@ -852,8 +866,10 @@
|
|||
"Linux44313",
|
||||
"LiteBalt",
|
||||
"LittleNyanCat",
|
||||
"Lizz",
|
||||
"Lizzetc",
|
||||
"Lkham",
|
||||
"Lobinhofs",
|
||||
"Loex",
|
||||
"Loko",
|
||||
"Longkencok",
|
||||
|
|
@ -871,6 +887,7 @@
|
|||
"Ludicrouswizard",
|
||||
"satrio ludji",
|
||||
"Ludovico",
|
||||
"Luis (GalaxyM4)",
|
||||
"Jose Luis",
|
||||
"luislinares",
|
||||
"luispro25",
|
||||
|
|
@ -933,6 +950,7 @@
|
|||
"Ihsan Maulana ( @ihsanm27)",
|
||||
"Federico Mazzone",
|
||||
"Andrea Mazzucchelli",
|
||||
"Medic",
|
||||
"Medic别闹我有药",
|
||||
"German Medin",
|
||||
"Martin Medina",
|
||||
|
|
@ -1104,12 +1122,14 @@
|
|||
"pett",
|
||||
"Petulakulina",
|
||||
"Pez",
|
||||
"PGIGM",
|
||||
"Đào Xuân Phi",
|
||||
"Philip",
|
||||
"Philipp",
|
||||
"piga",
|
||||
"Stefano Pigozzi",
|
||||
"Mario Donato Pilla",
|
||||
"Pinchidino",
|
||||
"Danilo \"Logan\" Pirrone",
|
||||
"PivotStickfigure12",
|
||||
"Pixelcube",
|
||||
|
|
@ -1321,6 +1341,7 @@
|
|||
"sun.4810",
|
||||
"Samet Sunal",
|
||||
"sundar",
|
||||
"Suprcat",
|
||||
"Indo sus",
|
||||
"Sven",
|
||||
"Shannon Sy",
|
||||
|
|
@ -1329,6 +1350,7 @@
|
|||
"Sz™",
|
||||
"Jorge Luis Sánchez",
|
||||
"Daniel Sýkora",
|
||||
"Aleksandar Tadic",
|
||||
"Arung Taftazani",
|
||||
"taha",
|
||||
"Rasim Eren TAHMAZ",
|
||||
|
|
@ -1394,6 +1416,7 @@
|
|||
"Kontantin Tsvetkov",
|
||||
"Tudikk",
|
||||
"Jan Tymll",
|
||||
"Zacker Tz",
|
||||
"Zoltán Tóth",
|
||||
"uDinnoo",
|
||||
"Cristian Ugalde",
|
||||
|
|
|
|||
49
dist/ba_data/data/languages/arabic.json
vendored
49
dist/ba_data/data/languages/arabic.json
vendored
|
|
@ -327,6 +327,7 @@
|
|||
"achievementsRemainingText": "الإنجازات المتبقية",
|
||||
"achievementsText": "الإنجازات",
|
||||
"achievementsUnavailableForOldSeasonsText": "المعذرة، الإنجازات للمواسم القديمة غير متوفرة",
|
||||
"activatedText": "${THING} تم تفعيله.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "الحصول على المزيد من الألعاب",
|
||||
"titleText": "إضافة لعبة"
|
||||
|
|
@ -625,7 +626,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} بحركة ملحمية بطيئة",
|
||||
"epicNameFilterText": "الملحمي ${NAME}",
|
||||
"errorAccessDeniedText": "تم الرفض",
|
||||
"errorDeviceTimeIncorrectText": "توقف وقت جهازك بمقدار ${HOURS} ساعة.\nهذا قد يتسبب بمشاكل.\nمن فضلك قم بالتحقق من اعدادات الوقت.",
|
||||
"errorOutOfDiskSpaceText": "انتهت مساحة التخزين",
|
||||
"errorSecureConnectionFailText": "تعذر انشاء اتصال سحابي أمن; قد تفشل وظائف الشبكة.",
|
||||
"errorText": "خطا",
|
||||
"errorUnknownText": "خطا غير معروف",
|
||||
"exitGameText": "هل تريد الخروج من ${APP_NAME}؟",
|
||||
|
|
@ -788,7 +791,7 @@
|
|||
"ticketPack4Text": "جمبو تذكرة حزمة",
|
||||
"ticketPack5Text": "ماموث تذكرة حزمة",
|
||||
"ticketPack6Text": "تذكرة حزمة هائلة",
|
||||
"ticketsFromASponsorText": "احصل على تذاكر ${COUNT}\nمن مقدم مشروع القرار",
|
||||
"ticketsFromASponsorText": "شاهد اعلانا\nمن التذاكر ${COUNT} للحصول على",
|
||||
"ticketsText": "${COUNT} بطاقات",
|
||||
"titleText": "أحصل على تذاكر",
|
||||
"unavailableLinkAccountText": "عذرا، لا تتوفر عمليات الشراء على هذا النظام الأساسي.\nوكحل بديل، يمكنك ربط هذا الحساب بحساب في\nمنصة أخرى وجعل عمليات الشراء هناك.",
|
||||
|
|
@ -799,6 +802,7 @@
|
|||
"youHaveText": "لديك ${COUNT} تذاكر"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "عذرًا ، خدمة جوجل متعددة اللاعبين لم تعد متاحة.\n أنا أعمل على بديل بأسرع وقت ممكن.\n حتى ذلك الحين ، يرجى تجربة طريقة اتصال أخرى.\n -إريك",
|
||||
"googlePlayPurchasesNotAvailableText": "عمليات شراء جوجل بلاي غير متوفرة.\nقد تحتاج لتحديث تطبيق المتجر.",
|
||||
"googlePlayText": "جوجل بلاي",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "دائما",
|
||||
|
|
@ -1109,7 +1113,10 @@
|
|||
"playlistsText": "قائمة العب",
|
||||
"pleaseRateText": "يرجى اتخاذ لحظة وتقييمه ${APP_NAME} اذا كنت تستمتع بلعبة\nاو كتابة مراجعة فهاذا يوفر معلومات مفيدة ويوفر التطوير\nفي المستقبل\n\n!شكرًا\nاريك—",
|
||||
"pleaseWaitText": "الرجاء الانتظار . . .",
|
||||
"pluginsDetectedText": "تم العتور على اضافات جديدة. فعلها او عدلها في الاعدادات",
|
||||
"pluginClassLoadErrorText": "فشل في تشغيل الاضافة '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "خطأ في بدء الاضافة '${PLUGIN}: ${ERROR}",
|
||||
"pluginsDetectedText": "تم العثور على اضافات جديدة. اعد التشغيل لتفعيلها، او قم بتخصيصها في الاعدادات.",
|
||||
"pluginsRemovedText": "${NUM} لم تعد الاضافة موجودة.",
|
||||
"pluginsText": "اضافات",
|
||||
"practiceText": "تدريب",
|
||||
"pressAnyButtonPlayAgainText": "اضغط اي زر للعب مجددا...",
|
||||
|
|
@ -1296,8 +1303,8 @@
|
|||
"comingSoonText": "قريبا...",
|
||||
"extrasText": "إضافات",
|
||||
"freeBombSquadProText": "فرقة القنبلة الآن أصبحت مجانية، لكن بما أنك اشتريتها\nبطاقات كشكر لك ${COUNT} ستتلقى فرقة القنبلة القنبلة للمحترفين و\n!استمتع بالميزات الجديدة، وشكرًا لدعمك\n-إيريك",
|
||||
"holidaySpecialText": "عطلة خاصة",
|
||||
"howToSwitchCharactersText": "(انتقل إلى \"${SETTINGS} -> ${PLAYER_PROFILES}\" لتعيين وتخصيص الأحرف)",
|
||||
"holidaySpecialText": "خاص بالعطل",
|
||||
"howToSwitchCharactersText": "(توجه الى \"${SETTINGS} -> ${PLAYER_PROFILES}\" لتخصيص الشخصيات)",
|
||||
"howToUseIconsText": "(إنشاء ملفات تعريف لاعب العالمية (في إطار الحساب) لاستخدام هذه)",
|
||||
"howToUseMapsText": "(استخدم هذه الخرائط في فرقك الخاصة / قوائم التشغيل المجانية للجميع)",
|
||||
"iconsText": "رموز",
|
||||
|
|
@ -1321,7 +1328,7 @@
|
|||
"winterSpecialText": "عرض الشتاء",
|
||||
"youOwnThisText": "- انت تملك هذا -"
|
||||
},
|
||||
"storeDescriptionText": "8 لاعب حفله لعبة الجنون!\n\nتفجير أصدقائك (أو الكمبيوتر) في البطولة من الألعاب المصغرة المتفجرة مثل القبض على العلم، منفذها هوكي، وملحمة بطيئة الحركة الموت الموت!\n\nضوابط بسيطة ودعم وحدة تحكم واسعة تجعل من السهل لمدة تصل إلى 8 أشخاص للحصول على في العمل. يمكنك حتى استخدام الأجهزة النقالة الخاصة بك عن طريق التحكم عن طريق الحرة 'بومبسكاد البعيد' التطبيق!\n\nالقنابل بعيدا!\n\nتحقق من www.froemling.net/bombsquad لمزيد من المعلومات.",
|
||||
"storeDescriptionText": "لعبة لأكثر من 8 لاعبين!\n\nالعب مع اصدقائك (او الحاسوب) في بطولات من الميني جيمز المتفجرة كــإمساك بالعلم، الهوكي و المعركة البطيئة!\n\nتحكم بسيط و لعب باجهزة تحكم يجعلها سهلة لأكثر من 8 لاعبين ليدخلو المعركة; تستطيع ايضا استعمال اجهزة الهاتف كاجهزة تحكم من خلال التطبيق المجاني 'BombSquad Remote' !\n\nوقت رمي القنابل!\n\nتفقد www.froemling.net/bombsquad للمزيد من المعلومات.",
|
||||
"storeDescriptions": {
|
||||
"blowUpYourFriendsText": ".فجر أصدقائك",
|
||||
"competeInMiniGamesText": "تنافس في الألعاب المصغرة بدءا من السباق للطيران.",
|
||||
|
|
@ -1364,31 +1371,31 @@
|
|||
"translations": {
|
||||
"characterNames": {
|
||||
"Agent Johnson": "العميل جونسون",
|
||||
"B-9000": "الآلي الخارق",
|
||||
"Bernard": "الدب القطبي",
|
||||
"B-9000": "B-9000",
|
||||
"Bernard": "بيرنارد",
|
||||
"Bones": "هيكل عظمي",
|
||||
"Butch": "بوتش",
|
||||
"Easter Bunny": "أرنوب",
|
||||
"Easter Bunny": "أرنب عيد الفصح",
|
||||
"Flopsy": "فلوبسي",
|
||||
"Frosty": "مُقاتل ثلجي",
|
||||
"Frosty": "فروستي",
|
||||
"Gretel": "جريتل",
|
||||
"Grumbledorf": "المشعوذ",
|
||||
"Jack Morgan": "خير الدين بارباروسا",
|
||||
"Kronk": "عدنان",
|
||||
"Grumbledorf": "الساحر",
|
||||
"Jack Morgan": "جاك مورجان (قرصان)",
|
||||
"Kronk": "كرونك",
|
||||
"Lee": "لي",
|
||||
"Lucky": "سعيد الحظ",
|
||||
"Mel": "الطباخ",
|
||||
"Mel": "ميل",
|
||||
"Middle-Man": "الرجل المتوسط",
|
||||
"Minimus": "أدنى لا",
|
||||
"Pascal": "البطريق الكبير",
|
||||
"Pixel": "حسناء",
|
||||
"Pascal": "پاسكال",
|
||||
"Pixel": "بيكسل",
|
||||
"Sammy Slam": "سامي سلام",
|
||||
"Santa Claus": "الشيخ",
|
||||
"Snake Shadow": "مُحارب في الصحراء",
|
||||
"Spaz": "Spaz",
|
||||
"Taobao Mascot": "التميمه تاوباو",
|
||||
"Santa Claus": "سانتا كلوس",
|
||||
"Snake Shadow": "نينجا",
|
||||
"Spaz": "سپاز",
|
||||
"Taobao Mascot": "ماسكوت تاوباو",
|
||||
"Todd McBurton": "تود بيرتون",
|
||||
"Zoe": "ليلى",
|
||||
"Zoe": "زوي",
|
||||
"Zola": "زولا"
|
||||
},
|
||||
"coopLevelNames": {
|
||||
|
|
@ -1843,6 +1850,8 @@
|
|||
"winsPlayerText": "${NAME} !يفوز",
|
||||
"winsTeamText": "${NAME} !يفوز فريق",
|
||||
"winsText": "${NAME} !يفوز",
|
||||
"workspaceSyncErrorText": "فشل في مزامنة ${WORKSPACE}. القي نظرة على السجل للتفاصيل.",
|
||||
"workspaceSyncReuseText": "لا يمكن مزامنة ${WORKSPACE}. اعادة استخدام النسخة المتزامنة السابقة.",
|
||||
"worldScoresUnavailableText": "(النتيجة العالمية غير متوفرة (اتصل بالانترنت",
|
||||
"worldsBestScoresText": "افضل نتيجة للعالم",
|
||||
"worldsBestTimesText": "افضل اوقات العالم",
|
||||
|
|
|
|||
11
dist/ba_data/data/languages/chinese.json
vendored
11
dist/ba_data/data/languages/chinese.json
vendored
|
|
@ -330,6 +330,7 @@
|
|||
"achievementsRemainingText": "未完成成就:",
|
||||
"achievementsText": "成就",
|
||||
"achievementsUnavailableForOldSeasonsText": "抱歉,往届的成就细节不可用。",
|
||||
"activatedText": "${THING} 已激活",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "获取更多游戏模式…",
|
||||
"titleText": "添加比赛"
|
||||
|
|
@ -629,7 +630,9 @@
|
|||
"epicDescriptionFilterText": "史诗级慢动作 ${DESCRIPTION}。",
|
||||
"epicNameFilterText": "史诗级${NAME}",
|
||||
"errorAccessDeniedText": "访问被拒绝",
|
||||
"errorDeviceTimeIncorrectText": "您的系统时间与服务器时间相差了${HOURS}小时\n这可能会出现一些问题\n请检查您的系统时间或时区",
|
||||
"errorOutOfDiskSpaceText": "磁盘空间不足",
|
||||
"errorSecureConnectionFailText": "无法建立安全的云链接,网络可能会连接失败",
|
||||
"errorText": "错误",
|
||||
"errorUnknownText": "未知错误",
|
||||
"exitGameText": "退出${APP_NAME}?",
|
||||
|
|
@ -795,7 +798,7 @@
|
|||
"ticketPack4Text": "巨型点券包",
|
||||
"ticketPack5Text": "猛犸象点券包",
|
||||
"ticketPack6Text": "终极点券包",
|
||||
"ticketsFromASponsorText": "从赞助商处\n获得${COUNT}点券",
|
||||
"ticketsFromASponsorText": "观看广告\n白嫖${COUNT}个点券",
|
||||
"ticketsText": "${COUNT}点券",
|
||||
"titleText": "获得点券",
|
||||
"unavailableLinkAccountText": "对不起,该平台上不可进行购买。\n您可将此帐户链接到另一个\n平台,以进行购买。",
|
||||
|
|
@ -806,6 +809,7 @@
|
|||
"youHaveText": "你拥有${COUNT}点券"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "抱歉,Google的多人游戏服务已不可用。\n我将尽快更换新的替代服务。\n在此之前,请尝试其他连接方法。\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Google商店购买不可用!\n请安装谷歌框架或更新Google服务。",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "总是",
|
||||
|
|
@ -1122,7 +1126,10 @@
|
|||
"playlistsText": "列表",
|
||||
"pleaseRateText": "如果你喜欢 ${APP_NAME},请考虑花一点时间\n来评价一下它或为它写一篇评论。这将为我们提供\n有用的反馈建议,为游戏的未来开发给予支持。\n\n感谢您!\n-eric",
|
||||
"pleaseWaitText": "请稍等...",
|
||||
"pluginClassLoadErrorText": "加载'${PLUGIN}'插件时出错了耶: ${ERROR}",
|
||||
"pluginInitErrorText": "初始化'${PLUGIN}'插件失败了啦: ${ERROR}",
|
||||
"pluginsDetectedText": "新插件安装成功,请重启游戏或在设置中设置它们~",
|
||||
"pluginsRemovedText": "有${NUM}个插件被删除了...",
|
||||
"pluginsText": "插件",
|
||||
"practiceText": "练习",
|
||||
"pressAnyButtonPlayAgainText": "按任意按钮再玩一次...",
|
||||
|
|
@ -1863,6 +1870,8 @@
|
|||
"winsPlayerText": "${NAME}获胜!",
|
||||
"winsTeamText": "${NAME}获胜!",
|
||||
"winsText": "${NAME}获胜!",
|
||||
"workspaceSyncErrorText": "同步${WORKSPACE}出错了啦,详情见日志文件",
|
||||
"workspaceSyncReuseText": "同步${WORKSPACE}时出错,正在使用以前同步的数据....",
|
||||
"worldScoresUnavailableText": "全球得分不可用。",
|
||||
"worldsBestScoresText": "全球最高得分",
|
||||
"worldsBestTimesText": "全球最佳时间",
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@
|
|||
"achievementsRemainingText": "未完成的成就",
|
||||
"achievementsText": "成就",
|
||||
"achievementsUnavailableForOldSeasonsText": "抱歉,往屆成就細節不可用",
|
||||
"activatedText": "${THING}已激活",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "獲取更多比賽模式",
|
||||
"titleText": "新增比賽"
|
||||
|
|
@ -621,7 +622,9 @@
|
|||
"epicDescriptionFilterText": "史詩級慢動作${DESCRIPTION}",
|
||||
"epicNameFilterText": "史詩級${NAME}",
|
||||
"errorAccessDeniedText": "訪問被拒絕",
|
||||
"errorDeviceTimeIncorrectText": "您的系統時間與BS伺服器相差了${HOURS}小時\n這可能會出現一些問題\n請檢查你的系統時間或時區",
|
||||
"errorOutOfDiskSpaceText": "磁盤空間不足",
|
||||
"errorSecureConnectionFailText": "無法安全的連接到伺服器,網絡功能可能會失效",
|
||||
"errorText": "錯誤",
|
||||
"errorUnknownText": "未知錯誤",
|
||||
"exitGameText": "退出${APP_NAME}?",
|
||||
|
|
@ -1105,7 +1108,10 @@
|
|||
"playlistsText": "遊戲列表",
|
||||
"pleaseRateText": "如果你喜歡${APP_NAME},請考慮花一些時間\n為Bombsquad寫一篇評論。這將為我們\n提供一些有用的反饋建議,為遊戲的未來開發給予支持\n\nThanks!\n-Eric",
|
||||
"pleaseWaitText": "請稍等....",
|
||||
"pluginsDetectedText": "檢測到新插件。 在設置中啟用/配置它們。",
|
||||
"pluginClassLoadErrorText": "加載插件類'${PLUGIN}'時出錯:${ERROR}",
|
||||
"pluginInitErrorText": "初始化插件'${PLUGIN}'時出錯:${ERROR}",
|
||||
"pluginsDetectedText": "檢測到新插件。重新啓動以激活,或在設置中配置這些插件",
|
||||
"pluginsRemovedText": "${NUM}個插件已丟失",
|
||||
"pluginsText": "外掛程式",
|
||||
"practiceText": "練習",
|
||||
"pressAnyButtonPlayAgainText": "按任意鍵再玩一次...",
|
||||
|
|
@ -1839,6 +1845,8 @@
|
|||
"winsPlayerText": "${NAME}贏了!",
|
||||
"winsTeamText": "${NAME}贏了!",
|
||||
"winsText": "${NAME}贏了!",
|
||||
"workspaceSyncErrorText": "同步${WORKSPACE}時出錯,詳情日志已輸出",
|
||||
"workspaceSyncReuseText": "無法同步${WORKSPACE},重複使用以前的同步版本",
|
||||
"worldScoresUnavailableText": "無法讀入全球分數",
|
||||
"worldsBestScoresText": "全球最佳分數",
|
||||
"worldsBestTimesText": "全球最佳時間",
|
||||
|
|
|
|||
6
dist/ba_data/data/languages/croatian.json
vendored
6
dist/ba_data/data/languages/croatian.json
vendored
|
|
@ -329,6 +329,7 @@
|
|||
"achievementsRemainingText": "Preostala Postignuća:",
|
||||
"achievementsText": "Postignuća",
|
||||
"achievementsUnavailableForOldSeasonsText": "Žao nam je,postignuća pojedinosti nisu dostupni za stare sezone.",
|
||||
"activatedText": "${THING} uključeno.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Još igara...",
|
||||
"titleText": "Dodaj igru"
|
||||
|
|
@ -1117,7 +1118,10 @@
|
|||
"playlistsText": "Liste igara",
|
||||
"pleaseRateText": "Ako ti se sviđa ${APP_NAME}, molim te razmisli o tome\nda ga ocijeniš ili napišeš recenziju.\nOvako šalješ korisnu povratnu informaciju koja pomaže u daljnjem razvoju.\n\nHvala!\n-eric",
|
||||
"pleaseWaitText": "Molimo sačekajte...",
|
||||
"pluginClassLoadErrorText": "Pogreška učitavanja dodatka klase '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Pogreška iniciranja dodatka '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Novi dodatak(ci) detektiran(i) Resetiraj da ih ukljućiš ili ih konfiguriraj u postavkima",
|
||||
"pluginsRemovedText": "${NUM} dodatak/ci više nisu pronađeni.",
|
||||
"pluginsText": "Dodatci",
|
||||
"practiceText": "Vježba",
|
||||
"pressAnyButtonPlayAgainText": "Pritisni bilo koju tipku za ponovnu igru...",
|
||||
|
|
@ -1858,6 +1862,8 @@
|
|||
"winsPlayerText": "${NAME} pobjeđuje!",
|
||||
"winsTeamText": "${NAME} pobjeđuju!",
|
||||
"winsText": "${NAME} pobjeđuje!",
|
||||
"workspaceSyncErrorText": "Pogreška sinkroniziranja ${WORKSPACE}. Pogledaj log za više detalja.",
|
||||
"workspaceSyncReuseText": "Nemoguće sinkronizirati ${WORKSPACE}. Ponovno korištenje stare verzije",
|
||||
"worldScoresUnavailableText": "Svjetski rezultati nedostupni.",
|
||||
"worldsBestScoresText": "Najbolji svjetski rezultati",
|
||||
"worldsBestTimesText": "Najbolja svjetska prolazna vremena",
|
||||
|
|
|
|||
10
dist/ba_data/data/languages/czech.json
vendored
10
dist/ba_data/data/languages/czech.json
vendored
|
|
@ -331,6 +331,7 @@
|
|||
"achievementsRemainingText": "Achievementů Zbývá:",
|
||||
"achievementsText": "Achievementy",
|
||||
"achievementsUnavailableForOldSeasonsText": "Promiňte, ale detaily úspěchu nejsou pro starší sezóny zpřístupněny.",
|
||||
"activatedText": "${THING} aktivováno.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Získat Více Her...",
|
||||
"titleText": "Přidat Hru"
|
||||
|
|
@ -633,7 +634,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} V epickém slow motionu",
|
||||
"epicNameFilterText": "Epické ${NAME}",
|
||||
"errorAccessDeniedText": "přístup zamítnut",
|
||||
"errorDeviceTimeIncorrectText": "Čas vašeho zařízení je mimo o ${HOURS} h.\nTo pravděpodobně způsobí problémy.\nProsím zkontrolujte nastavení času a časového pásma.",
|
||||
"errorOutOfDiskSpaceText": "není místo na disku",
|
||||
"errorSecureConnectionFailText": "Unable to establish secure cloud connection; network functionality may fail.",
|
||||
"errorText": "Chyba",
|
||||
"errorUnknownText": "neznámá chyba",
|
||||
"exitGameText": "Ukončit ${APP_NAME} ???",
|
||||
|
|
@ -1123,7 +1126,10 @@
|
|||
"playlistsText": "Playlisty",
|
||||
"pleaseRateText": "Jestliže Vás ${APP_NAME} baví, zvažte prosím, jestli si nechcete udělat\nchvilku na ohodnocení nebo napsání recenze. Poskytuje to užitečnou\nzpětnou vazbu a pomáhá podporovat budoucí vývoj.\n\nDíky!\n-eric",
|
||||
"pleaseWaitText": "Prosím čekejte...",
|
||||
"pluginsDetectedText": "Nové plugin(y) nalezeny. Zapněte/konfigurujte je v nastavení.",
|
||||
"pluginClassLoadErrorText": "Chyba při načítání třídy pluginu '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Chyba při inicializaci pluginu '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Nové plugin(y) nalezeny. Pro aktivaci restartujte, nebo konfigurujte v nastavení.",
|
||||
"pluginsRemovedText": "${NUM} plugin(y) nenalezeny.",
|
||||
"pluginsText": "Pluginy",
|
||||
"practiceText": "Cvičení",
|
||||
"pressAnyButtonPlayAgainText": "Stiskněte libovolné tlačítko pro opakování hry...",
|
||||
|
|
@ -1864,6 +1870,8 @@
|
|||
"winsPlayerText": "${NAME} Vyhrál!",
|
||||
"winsTeamText": "${NAME} Vyhrál!",
|
||||
"winsText": "${NAME} Vyhrál!",
|
||||
"workspaceSyncErrorText": "Chyba synchronizace ${WORKSPACE}. Podrobnosti v logu.",
|
||||
"workspaceSyncReuseText": "Nelze synchronizovat ${WORKSPACE}. Opětovné použití předchozí synchronizované verze.",
|
||||
"worldScoresUnavailableText": "Světové skóre nepřístupné.",
|
||||
"worldsBestScoresText": "Světové nejlepší skóre",
|
||||
"worldsBestTimesText": "Světové nejlepší časy",
|
||||
|
|
|
|||
5
dist/ba_data/data/languages/english.json
vendored
5
dist/ba_data/data/languages/english.json
vendored
|
|
@ -624,7 +624,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} In epic slow motion.",
|
||||
"epicNameFilterText": "Epic ${NAME}",
|
||||
"errorAccessDeniedText": "access denied",
|
||||
"errorDeviceTimeIncorrectText": "Your device's time is off by ${HOURS} hours.\nThis is likely to cause problems.\nPlease check your time and time-zone settings.",
|
||||
"errorOutOfDiskSpaceText": "out of disk space",
|
||||
"errorSecureConnectionFailText": "Unable to establish secure cloud connection; network functionality may fail.",
|
||||
"errorText": "Error",
|
||||
"errorUnknownText": "unknown error",
|
||||
"exitGameText": "Exit ${APP_NAME}?",
|
||||
|
|
@ -787,7 +789,7 @@
|
|||
"ticketPack4Text": "Jumbo Ticket Pack",
|
||||
"ticketPack5Text": "Mammoth Ticket Pack",
|
||||
"ticketPack6Text": "Ultimate Ticket Pack",
|
||||
"ticketsFromASponsorText": "Get ${COUNT} tickets\nfrom a sponsor",
|
||||
"ticketsFromASponsorText": "Watch an ad\nfor ${COUNT} tickets",
|
||||
"ticketsText": "${COUNT} Tickets",
|
||||
"titleText": "Get Tickets",
|
||||
"unavailableLinkAccountText": "Sorry, purchases are not available on this platform.\nAs a workaround, you can link this account to an account on\nanother platform and make purchases there.",
|
||||
|
|
@ -798,6 +800,7 @@
|
|||
"youHaveText": "you have ${COUNT} tickets"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Sorry, Google’s multiplayer service is no longer available.\nI am working on a replacement as fast as possible.\nUntil then, please try another connection method.\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Google Play purchases are not available.\nYou may need to update your store app.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Always",
|
||||
|
|
|
|||
23
dist/ba_data/data/languages/filipino.json
vendored
23
dist/ba_data/data/languages/filipino.json
vendored
|
|
@ -325,6 +325,7 @@
|
|||
"achievementsRemainingText": "Ang Mga Natitirang Nakamtan:",
|
||||
"achievementsText": "Achievements",
|
||||
"achievementsUnavailableForOldSeasonsText": "Pasensya na, hindi available ang mga detalye ng achievements para sa mga lumang seasons.",
|
||||
"activatedText": "Na-aktibo ang ${THING}.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Kukuha ng higit pang mga laro…",
|
||||
"titleText": "Magdagdag Ng Laro"
|
||||
|
|
@ -623,9 +624,11 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} sa isang epic na slow motion.",
|
||||
"epicNameFilterText": "Epikong ${NAME}",
|
||||
"errorAccessDeniedText": "walang pahintulot",
|
||||
"errorDeviceTimeIncorrectText": "Ang oras ng iyong device ay naka-off nang ${HOURS} na oras.\nIto ay malamang na magdulot ng mga iba’t ibang problema.\nPakisuri ang iyong mga setting ng oras at time-zone.",
|
||||
"errorOutOfDiskSpaceText": "Wala sa puwang ng disk",
|
||||
"errorSecureConnectionFailText": "Hindi mapatunayan ng secure na “cloud connection”; maaaring mabigo ang pagpapagana ng network.",
|
||||
"errorText": "Error",
|
||||
"errorUnknownText": "hindi batid na error",
|
||||
"errorUnknownText": "error na ‘di malaman",
|
||||
"exitGameText": "Exit mula sa ${APP_NAME}?",
|
||||
"exportSuccessText": "Na-export ang '${NAME}'.",
|
||||
"externalStorageText": "External na Storage",
|
||||
|
|
@ -786,7 +789,7 @@
|
|||
"ticketPack4Text": "Malaking Pakete Ng Tiket",
|
||||
"ticketPack5Text": "Mas Malaking Pakete Ng Tiket",
|
||||
"ticketPack6Text": "Pinakamalaking Pakete Ng Tiket",
|
||||
"ticketsFromASponsorText": "Kumuha ng ${COUNT} na tiket\nmula sa isang sponsor",
|
||||
"ticketsFromASponsorText": "Manood ng Ad\npara makuha ang ${COUNT} na tiket",
|
||||
"ticketsText": "${COUNT} Tiket",
|
||||
"titleText": "Kumuha Ng Tiket",
|
||||
"unavailableLinkAccountText": "Pasensya na, hindi available ang pagbili sa platform na ito.\nBilang isang solusyon, maaari mong i-link ang account na ito sa isang account na nasa\nisa pang platform at bumili doon.",
|
||||
|
|
@ -797,6 +800,7 @@
|
|||
"youHaveText": "mayroon kang ${COUNT} na tiket"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Pasensya na, hindi na available ang multiplayer na serbisyo ng Google.\nGumagawa ako ng kapalit sa lalong madaling panahon.\nHanggang doon, mangyaring sumubok ng ibang paraan ng koneksyon.\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Hindi puwede ang mga pagbili sa Google Play nito.\nMaaaring kailanganin mong i-update ang iyong store app.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Palagi",
|
||||
|
|
@ -836,11 +840,11 @@
|
|||
"pickUpInfoTextScale": 0.5,
|
||||
"powerupBombDescriptionText": "Payagan kang maglabas ng tatlong bomba\nsa isang hilera sa halip na isa lamang.",
|
||||
"powerupBombNameText": "Tatlong-Bomba",
|
||||
"powerupCurseDescriptionText": "Malamang na gusto mong iwasan ang mga ito.\n ...o ikaw?",
|
||||
"powerupCurseDescriptionText": "Malamang na gusto mong iwasan ang mga ganito.\n ...o sige lang?",
|
||||
"powerupCurseNameText": "Sumpa",
|
||||
"powerupHealthDescriptionText": "Ibangon ka sa buong kalusugan.\nHindi mo naisip nito.",
|
||||
"powerupHealthNameText": "Medikal-Pakete",
|
||||
"powerupIceBombsDescriptionText": "Mas mahina kaysa sa mga normal na bomba\nngunit nagyelo ang iyong mga kalaban\nat partikular na malutong.",
|
||||
"powerupIceBombsDescriptionText": "Mas mahina kaysa sa mga normal na bomba\nngunit nagyelo ang iyong mga kalaban\nat partikular na mabasag.",
|
||||
"powerupIceBombsNameText": "Bombang-Yelo",
|
||||
"powerupImpactBombsDescriptionText": "Medyo mahina kaysa sa regular\nbomba, ngunit sumasabog ito kapag nabagsak.",
|
||||
"powerupImpactBombsNameText": "Gatilyong-Bomba",
|
||||
|
|
@ -1089,7 +1093,7 @@
|
|||
"titleText": "Maglaro",
|
||||
"twoToEightPlayersText": "2-8 na manlalaro"
|
||||
},
|
||||
"playerCountAbbreviatedText": "${COUNT}n.m",
|
||||
"playerCountAbbreviatedText": "${COUNT}p",
|
||||
"playerDelayedJoinText": "Papasok si ${PLAYER} sa simula ng susunod na round.",
|
||||
"playerInfoText": "Impormasyon ng Manlalaro",
|
||||
"playerLeftText": "Umalis si ${PLAYER} sa laro.",
|
||||
|
|
@ -1110,7 +1114,10 @@
|
|||
"playlistsText": "Mga Playlist",
|
||||
"pleaseRateText": "Kung nae-enjoy mo ang ${APP_NAME}, mangyaring isaalang-alang ang \npagkuha na sandali lang at i-rate ito o pagsulat ng isang pagsusuri. Nagbibigay ito ngkapaki-pakinabang na feedback at \ntumutulong sa pagsuporta sa pag-unlad sa hinaharap.\n\nsalamat!\n-eric",
|
||||
"pleaseWaitText": "Hintay lang…",
|
||||
"pluginClassLoadErrorText": "Error sa paglo-load ang '${PLUGIN}' na klaseng plugin : ${ERROR}",
|
||||
"pluginInitErrorText": "Error sa pagsisimula ang '${PLUGIN}' na plugin: ${ERROR}",
|
||||
"pluginsDetectedText": "May nakitang bagong (mga) plugin. I-restart para i-activate ang mga ito, o i-configure ang mga ito sa mga setting.",
|
||||
"pluginsRemovedText": "Hindi na nahanapan ang ${NUM} ng (mga) plugin.",
|
||||
"pluginsText": "Mga Plugin",
|
||||
"practiceText": "Pagsasagawa",
|
||||
"pressAnyButtonPlayAgainText": "Pindutin ang anumang button para maglaro muli...",
|
||||
|
|
@ -1453,7 +1460,7 @@
|
|||
"kill ${ARG1} enemies": "patayin ang ${ARG1} na mga kalaban.",
|
||||
"last one standing wins": "kung sino ang huling nakatayo ang siyang mananalo",
|
||||
"last team standing wins": "kung sino ang huling katayuan ng team ang siyang mananalo",
|
||||
"return ${ARG1} flags": "ibalik ang ${ARG1} na mga bandera",
|
||||
"return ${ARG1} flags": "Magnakaw ng ${ARG1} na mga bandera",
|
||||
"return 1 flag": "ibalik ang 1 bandila",
|
||||
"run ${ARG1} laps": "Tumakbo ng ${ARG1} ikot",
|
||||
"run 1 lap": "tumakbo ng 1 ikot",
|
||||
|
|
@ -1774,7 +1781,7 @@
|
|||
"randomName3Text": "Stephen",
|
||||
"randomName4Text": "Joshua",
|
||||
"randomName5Text": "Villar",
|
||||
"skipConfirmText": "Sure ka na i-skip ang tutorial? Tap o pindutin para ma i-confirm.",
|
||||
"skipConfirmText": "Sure ka ba na i-skip ang tutorial? Tap o pindutin para ma i-confirm.",
|
||||
"skipVoteCountText": "${COUNT}/${TOTAL} boto na gustong laktawan",
|
||||
"skippingText": "Nilalaktawan ang tutorial",
|
||||
"toSkipPressAnythingText": "(i-tap o pindutin ang anuman para laktawan ang tutorial)"
|
||||
|
|
@ -1844,6 +1851,8 @@
|
|||
"winsPlayerText": "Nanalo si ${NAME}!",
|
||||
"winsTeamText": "Nanalo ang ${NAME}!",
|
||||
"winsText": "${NAME} Nanalo!",
|
||||
"workspaceSyncErrorText": "Error sa pag-sync ng ${WORKSPACE}. Tingnan ang log para sa mga detalye.",
|
||||
"workspaceSyncReuseText": "Hindi ma-sync ang ${WORKSPACE}. Muling paggamit ng nakaraang naka-sync na bersyon.",
|
||||
"worldScoresUnavailableText": "Ang scores sa buong mundo ay hindi pa handa",
|
||||
"worldsBestScoresText": "Pinakamahusay na Iskor ng Mundo",
|
||||
"worldsBestTimesText": "Pinakamahusay na Oras sa Mundo",
|
||||
|
|
|
|||
6
dist/ba_data/data/languages/gibberish.json
vendored
6
dist/ba_data/data/languages/gibberish.json
vendored
|
|
@ -661,7 +661,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} Ín ípic slúw mztíon.",
|
||||
"epicNameFilterText": "${NAME} Epícz",
|
||||
"errorAccessDeniedText": "acczlr dnfflz",
|
||||
"errorDeviceTimeIncorrectText": "Yowruc cowier oowefjwoefj ${HOURS} horewif.\noitwocweojowerjiowejjjfwoef.\nPefjwe wehapeocjjgwghwe w e weofwoefjwe.",
|
||||
"errorOutOfDiskSpaceText": "orz of dkzk spzlfz",
|
||||
"errorSecureConnectionFailText": "Uweorcjwoef ojcowe werryyeoi nowe; jcnwoeroidfowdffdj.dfsdf.",
|
||||
"errorText": "Errórz",
|
||||
"errorUnknownText": "unknznlz errzzz",
|
||||
"exitGameText": "$Excej ${APP_NAME}",
|
||||
|
|
@ -749,6 +751,7 @@
|
|||
"getFriendInviteCodeText": "Gz Frjor Infivo Cdz",
|
||||
"googlePlayDescriptionText": "Invlt Gglglz Plzlz plzlfer tz yzr prtaryz:",
|
||||
"googlePlayInviteText": "Invtlzz",
|
||||
"googlePlayPurchasesNotAvailableText": "JGowej eo owe weoirjweorjf\nYou we r wcowehpaw ecowjeoiwjrperpp.",
|
||||
"googlePlayReInviteText": "Tnz arzs ${COUNT} Gflf Plzz Plalfjdsf oin weojf wfeoyowiufe\nwhiz ewofij woijdoisoic o asodf wfiawje;aoew aoiwfj.\nTIncowjf oweofjao wotonwei oiacoiw eotijweto tat.",
|
||||
"googlePlaySeeInvitesText": "Szz Invtlfz",
|
||||
"googlePlayText": "Gzzlg Plz",
|
||||
|
|
@ -841,7 +844,7 @@
|
|||
"ticketPack4Text": "Jmfpmf Tkckf CPkf",
|
||||
"ticketPack5Text": "Mmthf Tckff Pckc",
|
||||
"ticketPack6Text": "Ulzjtla Tkckdf Pck",
|
||||
"ticketsFromASponsorText": "Gzt ${COUNT} tkckjtz\nfzn a sobfhrkz",
|
||||
"ticketsFromASponsorText": "woejwoe c woeijweo\ncowjeo ${COUNT} weocjw",
|
||||
"ticketsText": "${COUNT} Tckrtzz",
|
||||
"titleText": "Gtz Tckrtz",
|
||||
"unavailableLinkAccountText": "Srryrc, cpofj caodn oiwrj coi weo joweijwoief.\nIf wc woiejf w, cocwi eoiaoth aciw jeojfow iejoijwef\npcoj weo faona omowio wejfowijerwe.",
|
||||
|
|
@ -852,6 +855,7 @@
|
|||
"youHaveText": "yz hv ${COUNT} tickrrz"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Sowoer Gojf wel wouwen weoioc long wf won.\nI wow oe wefwjr pif g wfpawouja c oeij fw ocjaoiejowr.\nUntil. cowier oa j fapefij cpoypt ao coonnec awoiery.\n-Ercff",
|
||||
"googlePlayPurchasesNotAvailableText": "Weofiiwj woe woerd wieofjwe\ncome foe rj eofiaj cpwoe jrowjer..dd",
|
||||
"googlePlayText": "Gzzggl Plzz",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Azlwáys",
|
||||
|
|
|
|||
6
dist/ba_data/data/languages/italian.json
vendored
6
dist/ba_data/data/languages/italian.json
vendored
|
|
@ -332,6 +332,7 @@
|
|||
"achievementsRemainingText": "Trofei rimasti:",
|
||||
"achievementsText": "Trofei",
|
||||
"achievementsUnavailableForOldSeasonsText": "Mi dispiace, ma gli obbiettivi non sono disponibili per le stagioni vecchie.",
|
||||
"activatedText": "${THING} attivato.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Ottieni Giochi...",
|
||||
"titleText": "Aggiungi Partita"
|
||||
|
|
@ -1162,7 +1163,10 @@
|
|||
"playlistsText": "Scalette",
|
||||
"pleaseRateText": "Se ti sta piacendo ${APP_NAME}, prenditi\nun momento per valutarlo o scriverci su una recensione.\nQuesto aiuterà a supportare futuri sviluppi.\n\nGrazie!\n-eric",
|
||||
"pleaseWaitText": "Attendi...",
|
||||
"pluginClassLoadErrorText": "Errore nel caricamento di plugin classe '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Errore inizializzazione plugin '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "nuovo/i plugin rilevato. Riavvia per attivarli, o configurali nelle impostazioni.",
|
||||
"pluginsRemovedText": "${NUM} plugin non trovati.",
|
||||
"pluginsText": "Plugin",
|
||||
"practiceText": "Allenamento",
|
||||
"pressAnyButtonPlayAgainText": "Premi un pulsante qualunque per rigiocare...",
|
||||
|
|
@ -1943,6 +1947,8 @@
|
|||
"winsPlayerText": "${NAME} Ha Vinto!",
|
||||
"winsTeamText": "${NAME} Ha Vinto!",
|
||||
"winsText": "${NAME} vince!",
|
||||
"workspaceSyncErrorText": "Errore nella sincronizzazione di ${WORKSPACE}. Controlla il registro per dettagli.",
|
||||
"workspaceSyncReuseText": "Impossibile sincronizzare ${WORKSPACE}. Riutilizzo della versione sincronizzata precedente.",
|
||||
"worldScoresUnavailableText": "Punteggi mondiali non disponibili.",
|
||||
"worldsBestScoresText": "I punteggi migliori del mondo",
|
||||
"worldsBestTimesText": "I tempi migliori del mondo",
|
||||
|
|
|
|||
12
dist/ba_data/data/languages/persian.json
vendored
12
dist/ba_data/data/languages/persian.json
vendored
|
|
@ -326,6 +326,7 @@
|
|||
"achievementsRemainingText": "دستاورد های باقیمانده:",
|
||||
"achievementsText": "دستاوردها",
|
||||
"achievementsUnavailableForOldSeasonsText": "ببخشید، دستاوردهای مخصوص فصل گذشته در دسترس نیستند",
|
||||
"activatedText": "${THING} فعال شد.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "...بازی های بیشتر",
|
||||
"titleText": "افزودن بازی"
|
||||
|
|
@ -625,7 +626,9 @@
|
|||
"epicDescriptionFilterText": "در حماسهٔ حرکت آهسته ${DESCRIPTION}",
|
||||
"epicNameFilterText": "${NAME} حماسهٔ",
|
||||
"errorAccessDeniedText": "دسترسی رد شد",
|
||||
"errorDeviceTimeIncorrectText": "ساعت گوشی ${HOURS} ساعت خاموش بودهاست.\nممکن است مشکل بهوجود بیاید.\nلطفاً ساعت و منطقهٔ زمانی گوشیتان را بررسی کنید.",
|
||||
"errorOutOfDiskSpaceText": "حافظه جا ندارد",
|
||||
"errorSecureConnectionFailText": "قادر به ایجاد اتصال ابری امن نیست. عملکرد شبکه ممکن است خراب شود.",
|
||||
"errorText": "خطا",
|
||||
"errorUnknownText": "خطای ناشناخته",
|
||||
"exitGameText": "؟${APP_NAME} خروج از",
|
||||
|
|
@ -788,7 +791,7 @@
|
|||
"ticketPack4Text": "پک خیلی بزرگ بلیط",
|
||||
"ticketPack5Text": "پک ماموتی بلیط",
|
||||
"ticketPack6Text": "پک نهایی بلیط",
|
||||
"ticketsFromASponsorText": "بلیط از${COUNT}\nیه اسپانسر بگیرید",
|
||||
"ticketsFromASponsorText": "در ازای ${COUNT} بلیت\nیک آگهی ببینید",
|
||||
"ticketsText": "بلیط${COUNT}",
|
||||
"titleText": "بلیط بگیرید",
|
||||
"unavailableLinkAccountText": ".ببخشید،خرید به وسیله ی این دستگاه در دسترس نمیباشد\nمیتوانید حسابتان بر روی این دستگاه را به حسابی در دستگاهی\n.دیگر متصل کنید و آنجا خرید خود را انجام دهید",
|
||||
|
|
@ -1109,7 +1112,10 @@
|
|||
"playlistsText": "لیست بازی ها",
|
||||
"pleaseRateText": "خوشتان آمده، لطفاً چند لحظهای وقت بگذارید و ${APP_NAME} اگر از\nآن را رتبهبندی کنید یا مروری بر آن بنویسید. این کار بازخوردهای مفیدی\n.را به همراه دارد و به پشتیبانی از توسعهها در آینده کمک خواهد کرد\n\n!با تشکر\nاریک—",
|
||||
"pleaseWaitText": "…لطفاً صبر کنید",
|
||||
"pluginsDetectedText": ".افزونه(ها)ی جدید شناسایی شد. آنها را در تنظیمات فعال/پیکربندی کنید",
|
||||
"pluginClassLoadErrorText": "${ERROR} :«${PLUGIN}» خطا در بارگیری دستهبندی افزونهٔ",
|
||||
"pluginInitErrorText": "${ERROR} :«${PLUGIN}» خطا در راهاندازی افزونهٔ",
|
||||
"pluginsDetectedText": "افزونه(ها)ی جدید شناسایی شد. آنها را در تنظیمات فعال، یا پیکربندی کنید.",
|
||||
"pluginsRemovedText": "${NUM} افزونه دیگر یافت نمیشود.",
|
||||
"pluginsText": "افزونهها",
|
||||
"practiceText": "تمرین",
|
||||
"pressAnyButtonPlayAgainText": "…فشردن هر دکمهای برای بازی دوباره",
|
||||
|
|
@ -1847,6 +1853,8 @@
|
|||
"winsPlayerText": "${NAME} برنده شد",
|
||||
"winsTeamText": "${NAME} برنده شد",
|
||||
"winsText": "${NAME} برنده شد",
|
||||
"workspaceSyncErrorText": "خطا در همگامسازی ${WORKSPACE}. برای جزئیات به لاگ مراجعه کنید.",
|
||||
"workspaceSyncReuseText": "نمیتوان ${WORKSPACE} را همگامسازی کرد. استفادهٔ مجدد از نسخهٔ همگامسازیشده قبلی.",
|
||||
"worldScoresUnavailableText": "امتیاز های جهانی قابل دسترس نیستند.",
|
||||
"worldsBestScoresText": "بهترین امتیازهای جهانی",
|
||||
"worldsBestTimesText": "بهترین زمان های جهانی",
|
||||
|
|
|
|||
11
dist/ba_data/data/languages/portuguese.json
vendored
11
dist/ba_data/data/languages/portuguese.json
vendored
|
|
@ -331,6 +331,7 @@
|
|||
"achievementsRemainingText": "Conquistas restantes:",
|
||||
"achievementsText": "Conquistas",
|
||||
"achievementsUnavailableForOldSeasonsText": "Desculpe, algumas conquistas não estão disponíveis em temporadas antigas.",
|
||||
"activatedText": "${THING} foi ativado.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Mais jogos...",
|
||||
"titleText": "Adicionar jogo"
|
||||
|
|
@ -657,7 +658,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} em câmera lenta épica.",
|
||||
"epicNameFilterText": "${NAME} épico(a)",
|
||||
"errorAccessDeniedText": "acesso negado",
|
||||
"errorDeviceTimeIncorrectText": "A hora do seu dispositivo está atrasada/adiantada em ${HOURS} horas.\nIsso poderá causar problemas.\nPor favor cheque as suas configurações de hora e fuso horário.",
|
||||
"errorOutOfDiskSpaceText": "pouco espaço em disco",
|
||||
"errorSecureConnectionFailText": "Não foi possível estabelecer uma conexão segura à nuvem; a funcionalidade da rede pode falhar.",
|
||||
"errorText": "Erro",
|
||||
"errorUnknownText": "erro desconhecido",
|
||||
"exitGameText": "Sair do ${APP_NAME}?",
|
||||
|
|
@ -832,7 +835,7 @@
|
|||
"ticketPack4Text": "Pacote jumbo de bilhetes",
|
||||
"ticketPack5Text": "Pacote mamute de bilhete",
|
||||
"ticketPack6Text": "Pacote ultimate de bilhetes",
|
||||
"ticketsFromASponsorText": "Ganhe ${COUNT} bilhetes\nde um patrocinador",
|
||||
"ticketsFromASponsorText": "Assista a um anúncio \ne ganhe ${COUNT} bilhetes",
|
||||
"ticketsText": "${COUNT} bilhetes",
|
||||
"titleText": "Obter bilhetes",
|
||||
"unavailableLinkAccountText": "Desculpe, as compras não estão disponíveis nesta plataforma.\nComo solução alternativa, você pode vincular esta conta para\noutra conta de outra plataforma e fazer compras lá.",
|
||||
|
|
@ -843,6 +846,7 @@
|
|||
"youHaveText": "você possui ${COUNT} bilhetes"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Desculpe, o serviço multijogador do Google não está mais disponível.\nEstou trabalhando em uma substituição o mais rápido possível.\nAté lá, tente outro método de conexão.\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Compras pela Google Play não estão disponíveis.\nTalvez seja necessário atualizar sua loja para isso.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Sempre",
|
||||
|
|
@ -1183,7 +1187,10 @@
|
|||
"playlistsText": "Playlists",
|
||||
"pleaseRateText": "Se você está curtindo ${APP_NAME}, por favor, dê um tempinho\npara avaliar e comentar. Isso nos dá uma opinião útil\ne ajuda no desenvolvimento do jogo.\n\nobrigado!\n-eric",
|
||||
"pleaseWaitText": "Por favor, aguarde...",
|
||||
"pluginClassLoadErrorText": "Erro ao carregar a classe de um plugin '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Erro ao inicializar plugin '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Novo(s) plugin(s) detetados. Reinicie o jogo para ativá-los ou configure-os nas configurações.",
|
||||
"pluginsRemovedText": "${NUM} plugin(s) não foram encontrados.",
|
||||
"pluginsText": "Plugins",
|
||||
"practiceText": "Praticar",
|
||||
"pressAnyButtonPlayAgainText": "Aperte qualquer botão para jogar novamente...",
|
||||
|
|
@ -1970,6 +1977,8 @@
|
|||
"winsPlayerText": "${NAME} venceu!",
|
||||
"winsTeamText": "${NAME} venceu!",
|
||||
"winsText": "${NAME} ganhou!",
|
||||
"workspaceSyncErrorText": "Erro ao sincronizar ${WORKSPACE}. Veja o log para mais detalhes.",
|
||||
"workspaceSyncReuseText": "Não pôde sincronizar ${WORKSPACE}. Reusando uma versão anterior sincronizada.",
|
||||
"worldScoresUnavailableText": "Pontuações mundiais indisponíveis.",
|
||||
"worldsBestScoresText": "Melhores pontuações do mundo",
|
||||
"worldsBestTimesText": "Melhores tempos do mundo",
|
||||
|
|
|
|||
43
dist/ba_data/data/languages/romanian.json
vendored
43
dist/ba_data/data/languages/romanian.json
vendored
|
|
@ -330,6 +330,7 @@
|
|||
"achievementsRemainingText": "Realizări Rămase:",
|
||||
"achievementsText": "Realizări",
|
||||
"achievementsUnavailableForOldSeasonsText": "Scuze, dar detaliile realizărilor din sezoanele trecute sunt indisponibile.",
|
||||
"activatedText": "${THING} a fost activat(ă).",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Ia mai multe MiniJocuri...",
|
||||
"titleText": "Adaugă un joc"
|
||||
|
|
@ -349,14 +350,14 @@
|
|||
"autoText": "Automat",
|
||||
"backText": "Înapoi",
|
||||
"banThisPlayerText": "Interzice Accesul Acestui Jucător",
|
||||
"bestOfFinalText": "Finala Primul-La-${COUNT}",
|
||||
"bestOfSeriesText": "Seriile Primul-La-${COUNT}:",
|
||||
"bestOfUseFirstToInstead": 1,
|
||||
"bestOfFinalText": "Finala Cel-Mai-Bun-Din-${COUNT}",
|
||||
"bestOfSeriesText": "Seriile Cel-Mai-Bun-Din-${COUNT}:",
|
||||
"bestOfUseFirstToInstead": 0,
|
||||
"bestRankText": "Cea mai bună poziție a ta este: #${RANK}",
|
||||
"bestRatingText": "Cea mai bună notă a ta este ${RATING}",
|
||||
"bombBoldText": "BOMBĂ",
|
||||
"bombText": "Bombă",
|
||||
"boostText": "Crește-ți",
|
||||
"boostText": "Crește",
|
||||
"bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} este configurat în aplicația în sine.",
|
||||
"buttonText": "buton",
|
||||
"canWeDebugText": "Ai vrea ca BombSquad să trimită automat bug-uri,\ncrash-uri și informații de bază programatorului jocului?\n\nAceste informații nu conțin date personale, ci doar\najută la îmbunătățirea jocului.",
|
||||
|
|
@ -629,7 +630,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} În slow motion epic.",
|
||||
"epicNameFilterText": "${NAME} Epic",
|
||||
"errorAccessDeniedText": "acces respins",
|
||||
"errorDeviceTimeIncorrectText": "Ceasul dispozitivului tău este dat înainte sau înapoi cu ${HOURS} ore.\nAcestu lucru ar putea cauza niște probleme.\nTe rog să verifici setările ceasului și ale fusului orar.",
|
||||
"errorOutOfDiskSpaceText": "ai rămas fără memorie",
|
||||
"errorSecureConnectionFailText": "Nu s-a putut stabili o conexiune sigură cloud; funcționalitatea internetului ar putea eșua.",
|
||||
"errorText": "Eroare",
|
||||
"errorUnknownText": "eroare necunoscută",
|
||||
"exitGameText": "Ieși din ${APP_NAME}?",
|
||||
|
|
@ -705,10 +708,10 @@
|
|||
"friendHasSentPromoCodeText": "${COUNT} Bilete pe ${APP_NAME} de la ${NAME}",
|
||||
"friendPromoCodeAwardText": "Vei primi ${COUNT} de bilete de fiecare dată când este folosit.",
|
||||
"friendPromoCodeExpireText": "Codul va expira în ${EXPIRE_HOURS} de ore şi este valabil doar pentru jucătorii noi.",
|
||||
"friendPromoCodeInstructionsText": "Pentru a-l utiliza, deschide ${APP_NAME} și accesează „Setări-> Avansat-> Introdu codul”.\nConsultă bombsquadgame.com pentru linkuri de descărcare pentru toate platformele acceptate.",
|
||||
"friendPromoCodeInstructionsText": "Pentru a-l utiliza, deschide ${APP_NAME} și accesează „Setări-> Avansat-> Introdu un cod”.\nConsultă bombsquadgame.com pentru linkuri de descărcare pentru toate platformele acceptate.",
|
||||
"friendPromoCodeRedeemLongText": "Poate fi introdus pentru ${COUNT} de bilete gratuite de către un maxim de ${MAX_USES} de persoane.",
|
||||
"friendPromoCodeRedeemShortText": "Poate fi introdus în joc pentru ${COUNT} de bilete.",
|
||||
"friendPromoCodeWhereToEnterText": "(în „Setări-> Avansat-> Introdu codul”)",
|
||||
"friendPromoCodeWhereToEnterText": "(în \"Setări-> Avansat-> Introdu un cod\")",
|
||||
"getFriendInviteCodeText": "Cere un Cod pentru Prieteni",
|
||||
"googlePlayDescriptionText": "Invită jucători Google Play la petrecerea ta:",
|
||||
"googlePlayInviteText": "Invită",
|
||||
|
|
@ -794,7 +797,7 @@
|
|||
"ticketPack4Text": "Super-Pachet de Bilete",
|
||||
"ticketPack5Text": "Pachet de Bilete MAMUT",
|
||||
"ticketPack6Text": "Pachet de Bilete Suprem",
|
||||
"ticketsFromASponsorText": "Ia ${COUNT} bilete\nde la un sponsor",
|
||||
"ticketsFromASponsorText": "Vizionează o reclamă\npentru ${COUNT} bilete",
|
||||
"ticketsText": "${COUNT} de Bilete",
|
||||
"titleText": "Ia Bilete",
|
||||
"unavailableLinkAccountText": "Scuze, dar achizițiile nu sunt disponibile pe această platformă.\nCa soluție, poți conecta acest cont la un alt cont de pe\no altă platformă și să faci cumpărături acolo.",
|
||||
|
|
@ -805,6 +808,7 @@
|
|||
"youHaveText": "ai ${COUNT} (de) bilete"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Ne pare rău, serviciul multiplayer de pe Google nu mai este disponibil.\nLucrez la un înlocuitor cât mai repede posibil.\nPână atunci, te rog să încerci o altă metodă de conectare.\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Achizițiile de pe Google Play nu sunt disponibile.\nÎncearcă să actualizezi Magazin Play și să încerci din nou.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Întotdeauna",
|
||||
|
|
@ -881,7 +885,7 @@
|
|||
"buttonText": "buton",
|
||||
"cantKickHostError": "Nu poți da afară hostul server-ului.",
|
||||
"chatBlockedText": "${NAME} este blocat în chat timp de ${TIME} (de) secunde.",
|
||||
"connectedToGameText": "a intrat în „${NAME}”",
|
||||
"connectedToGameText": "Ai intrat în '${NAME}'",
|
||||
"connectedToPartyText": "Ai intrat în server-ul lui ${NAME}!",
|
||||
"connectingToPartyText": "Se conectează...",
|
||||
"connectionFailedHostAlreadyInPartyText": "Conexiunea a eşuat; hostul este în alt joc.",
|
||||
|
|
@ -915,7 +919,7 @@
|
|||
"kickIdlePlayersKickedText": "${NAME} a fost dat afară deoarece era inactiv.",
|
||||
"kickIdlePlayersWarning1Text": "${NAME} va fi dat afară în următoarele ${COUNT} secunde dacă continuă să fie inactiv.",
|
||||
"kickIdlePlayersWarning2Text": "(Poți dezactiva această setare în Setări -> Avansat)",
|
||||
"leftGameText": "A ieșit din ${NAME}",
|
||||
"leftGameText": "Ai ieșit din '${NAME}'",
|
||||
"leftPartyText": "Ai ieşit din server-ul lui ${NAME}.",
|
||||
"noMusicFilesInFolderText": "Folder-ul nu conține niciun fişier de muzică.",
|
||||
"playerJoinedPartyText": "${NAME} a intrat în joc!",
|
||||
|
|
@ -1026,9 +1030,9 @@
|
|||
"modeArcadeText": "Mod Pentru Arcade",
|
||||
"modeClassicText": "Modul Clasic",
|
||||
"modeDemoText": "Modul Demonstrativ",
|
||||
"mostValuablePlayerText": "Cel mai valoros jucător este:",
|
||||
"mostViolatedPlayerText": "Cel mai ucis jucător este:",
|
||||
"mostViolentPlayerText": "Cel mai violent jucător este:",
|
||||
"mostValuablePlayerText": "Cel mai valoros jucător este",
|
||||
"mostViolatedPlayerText": "Cel mai ucis jucător este",
|
||||
"mostViolentPlayerText": "Cel mai violent jucător este",
|
||||
"moveText": "Te miști din",
|
||||
"multiKillText": "${COUNT} ucideri!!!",
|
||||
"multiPlayerCountText": "${COUNT} jucători",
|
||||
|
|
@ -1119,7 +1123,10 @@
|
|||
"playlistsText": "Liste de Jocuri",
|
||||
"pleaseRateText": "Dacă îți place ${APP_NAME}, te rog să stai\no clipă și să evaluezi jocul, scriind o recenzie pentru acesta.\nAceasta furnizează feedback folositor și ajută la dezvoltarea jocului în viitor.\n\nmulțumesc!\n-Eric",
|
||||
"pleaseWaitText": "Te rog să aștepți...",
|
||||
"pluginClassLoadErrorText": "Nu s-a putut încărca plugin-ul '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Nu s-a putut iniția plugin-ul '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Plugin(uri) noi detectate. Restartează jocul pentru a le activa / configura în setări.",
|
||||
"pluginsRemovedText": "${NUM} plugin(uri) nu mai există.",
|
||||
"pluginsText": "Plugin-uri",
|
||||
"practiceText": "Antrenament",
|
||||
"pressAnyButtonPlayAgainText": "Apasă orice buton pentru a juca din nou...",
|
||||
|
|
@ -1134,7 +1141,7 @@
|
|||
"pressToSelectProfileText": "apasă ${BUTTONS} pentru a-ți selecta profilul",
|
||||
"pressToSelectTeamText": "apasă ${BUTTONS} pentru a-ți selecta echipa",
|
||||
"promoCodeWindow": {
|
||||
"codeText": "Codul:",
|
||||
"codeText": "Codul",
|
||||
"codeTextDescription": "Cod Promoțional",
|
||||
"enterText": "Trimite-l"
|
||||
},
|
||||
|
|
@ -1246,7 +1253,7 @@
|
|||
"disableThisNotice": "(Poți dezactiva această notificare în setările avansate)",
|
||||
"enablePackageModsDescriptionText": "Permite mai multe capabilități pentru modare, dar dezactivează net-play-ul)",
|
||||
"enablePackageModsText": "Activează Moduri cu Pachete Locale",
|
||||
"enterPromoCodeText": "Codul:",
|
||||
"enterPromoCodeText": "Introdu un cod",
|
||||
"forTestingText": "Notă: aceste valori sunt doar pentru teste şi vor fi resetate când jocul va fi închis.",
|
||||
"helpTranslateText": "Translațiile din ${APP_NAME} sunt un efort depus de comunitate.\nDacă ai dori să te implici la translatarea/corectarea unei limbi,\nurmează linkul de mai jos. Mulțumiri anticipate!",
|
||||
"kickIdlePlayersText": "Dă Afară Jucătorii Inactivi",
|
||||
|
|
@ -1713,12 +1720,12 @@
|
|||
"Don't run all the time. Really. You will fall off cliffs.": "Nu fugi tot timpul. Pe bune. Vei cădea de pe hărți.",
|
||||
"Don't spin for too long; you'll become dizzy and fall.": "Nu te învârti prea mult timp; vei ameți și vei fi pus la pământ.",
|
||||
"Hold any button to run. (Trigger buttons work well if you have them)": "Ține apăsat orice buton pentru a fugi. (Butoanele 'Trigger' funcționează bine şi ele dacă le ai)",
|
||||
"Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Pentru a fugi,ține apăsat orice buton. Vei ajunge mai repede unde vrei,\ndar nu vei lua curba prea bine, așa că ai grijă să nu cazi de pe hărți.",
|
||||
"Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Pentru a fugi, ține apăsat orice buton. Vei ajunge mai repede unde vrei,\ndar nu vei lua curba prea bine, așa că ai grijă să nu cazi de pe hărți.",
|
||||
"Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Bombele de gheață nu sunt foarte puternice, dar îngheață\npe oricine lovesc, lăsând victimele vulnerabile la spargere.",
|
||||
"If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Dacă cineva te ia pe sus, dă-i un pumn și îți va da drumul.\n (Apropo, merge și în viața reală)",
|
||||
"If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Dacă cineva te ia pe sus, dă-i un pumn și îți va da drumul.\n (Apropo, merge și în viața reală)",
|
||||
"If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Dacă nu ai destule controllere, instalează aplicația '${REMOTE_APP_NAME}' \npe dispozitivele tale mobile pentru a le folosi drept controllere.",
|
||||
"If you are short on controllers, install the 'BombSquad Remote' app\non your iOS or Android devices to use them as controllers.": "Dacă nu ai destule controllere, instalează 'BombSquad Remote' pe\nun dispozitiv Android sau iOS pentru a-l folosi ca pe un controller.",
|
||||
"If you get a sticky-bomb stuck to you, jump around and spin in circles. You might\nshake the bomb off, or if nothing else your last moments will be entertaining.": "Dacă o bombă lipicioasă se lipește de tine, sari și rotește-te în cercuri. S-ar putea \nsă scapi de aceasta, dar dacă nu, vei face un spectacol minunat din ultimele tale momente rămase în viață.",
|
||||
"If you get a sticky-bomb stuck to you, jump around and spin in circles. You might\nshake the bomb off, or if nothing else your last moments will be entertaining.": "Dacă se atinge vreodată o bombă lipicioasă de tine, sari și rotește-te în cercuri. S-ar putea \nsă scapi de aceasta, dar dacă nu, vei face un spectacol minunat din ultimele tale momente rămase în viață.",
|
||||
"If you kill an enemy in one hit you get double points for it.": "Dacă omori un inamic dintr-o singură lovitură vei primi puncte duble.",
|
||||
"If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Dacă atingi un blestem, singura ta şansă de a trăi este să\nprinzi o trusă de prim-ajutor în următoarele 5 secunde.",
|
||||
"If you stay in one place, you're toast. Run and dodge to survive..": "Dacă stai într-un singur loc, vei muri ca un fraier. Ferește-te și aleargă din loc în loc pentru a supraviețui..",
|
||||
|
|
@ -1863,6 +1870,8 @@
|
|||
"winsPlayerText": "${NAME} Câștigă!",
|
||||
"winsTeamText": "${NAME} Câștigă!",
|
||||
"winsText": "${NAME} Câștigă!",
|
||||
"workspaceSyncErrorText": "Nu s-a putut sincroniza ${WORKSPACE}. Vezi jurnalul de activități pentru detalii.",
|
||||
"workspaceSyncReuseText": "Nu se poate sincroniza ${WORKSPACE}. Se va folosi ultima versiune sincronizată.",
|
||||
"worldScoresUnavailableText": "Scorurile globale sunt indisponibile.",
|
||||
"worldsBestScoresText": "Top Scoruri Mondiale",
|
||||
"worldsBestTimesText": "Top Timpi Mondiali",
|
||||
|
|
|
|||
105
dist/ba_data/data/languages/russian.json
vendored
105
dist/ba_data/data/languages/russian.json
vendored
|
|
@ -39,7 +39,7 @@
|
|||
"testAccountWarningCardboardText": "Внимание: вы подписываете в с \"тест\" счета.\nЭти данные будут заменены со счетами Google сразу\nони становятся поддерживается в картонные приложений.\n\nСейчас вы будете зарабатывать все билеты в игре.\n(вы , тем не менее , получить Pro обновление BombSquad бесплатно )",
|
||||
"testAccountWarningOculusText": "Внимание: вы входите под акканутом \"test\".\nОни будут заменены аккаунтами Oculus позже в этом\nгоду, что позволит совершать покупки билетов и многое другое.\n\nНа данный момент вам придется зарабатывать билеты в игре.\n(однако, вы получаете обновление BombSquad Pro бесплатно)",
|
||||
"testAccountWarningText": "Внимание: вы заходите под аккаунтом \"test\".\nЭтот аккаунт привязан к конкретному устройству и может\nпериодически сбрасываться. (так что лучше особо\nне тратить время на сбор/разблокировку добра в нем)\n\nЧтобы использовать настоящий аккаунт (Game-Center,\nGoogle Plus и т.д.), запустите платную версию. Это также\nпозволит сохранять свой прогресс в облаке и делать его\nдоступным для разных устройств.",
|
||||
"ticketsText": "Билетов: ${COUNT}",
|
||||
"ticketsText": "Количество билетов: ${COUNT}",
|
||||
"titleText": "Аккаунт",
|
||||
"unlinkAccountsInstructionsText": "Выберите аккаунт, который хотите отвязать",
|
||||
"unlinkAccountsText": "Отвязать аккаунты",
|
||||
|
|
@ -49,14 +49,14 @@
|
|||
"youAreSignedInAsText": "Вы вошли как:"
|
||||
},
|
||||
"achievementChallengesText": "Достижения",
|
||||
"achievementText": "Медаль",
|
||||
"achievementText": "Достижение",
|
||||
"achievements": {
|
||||
"Boom Goes the Dynamite": {
|
||||
"description": "Убейте 3 плохих парней с помощью TNT",
|
||||
"descriptionComplete": "С помощью TNT убито 3 плохих парней",
|
||||
"descriptionFull": "Убейте 3 плохих парней с помощью TNT на уровне ${LEVEL}",
|
||||
"descriptionFullComplete": "3 плохих парней убито с помощью TNT на уровне ${LEVEL}",
|
||||
"name": "Сейчас бабахнет"
|
||||
"name": "Динамит сейчас взорвётся!"
|
||||
},
|
||||
"Boxer": {
|
||||
"description": "Победите без использования бомб",
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
"descriptionComplete": "С карты сброшено 3 негодяя",
|
||||
"descriptionFull": "Сбросьте 3 негодяев с карты на уровне ${LEVEL}",
|
||||
"descriptionFullComplete": "3 негодяя сброшено с карты на уровне ${LEVEL}",
|
||||
"name": "Давай отсюда"
|
||||
"name": "Пора учится летать"
|
||||
},
|
||||
"Onslaught God": {
|
||||
"description": "Наберите 5000 очков",
|
||||
|
|
@ -180,7 +180,7 @@
|
|||
},
|
||||
"Pro Football Shutout": {
|
||||
"description": "Победите в сухую",
|
||||
"descriptionComplete": "Победил в сухую",
|
||||
"descriptionComplete": "Уровень был пройден в сухую",
|
||||
"descriptionFull": "Выиграйте матч ${LEVEL} в сухую",
|
||||
"descriptionFullComplete": "Победа в матче ${LEVEL} в сухую",
|
||||
"name": "${LEVEL} в сухую"
|
||||
|
|
@ -194,9 +194,9 @@
|
|||
},
|
||||
"Pro Onslaught Victory": {
|
||||
"description": "Победите все волны",
|
||||
"descriptionComplete": "Побеждены все волны",
|
||||
"descriptionComplete": "Пройдены все волны",
|
||||
"descriptionFull": "Победите все волны на уровне ${LEVEL}",
|
||||
"descriptionFullComplete": "Побеждены все волны на уровне ${LEVEL}",
|
||||
"descriptionFullComplete": "Пройдены все волны на ${LEVEL}",
|
||||
"name": "Победа на уровне ${LEVEL}"
|
||||
},
|
||||
"Pro Runaround Victory": {
|
||||
|
|
@ -215,7 +215,7 @@
|
|||
},
|
||||
"Rookie Football Victory": {
|
||||
"description": "Выиграйте матч",
|
||||
"descriptionComplete": "Матч выигран",
|
||||
"descriptionComplete": "Матч пройден в вашу пользу",
|
||||
"descriptionFull": "Выиграйте матч ${LEVEL}",
|
||||
"descriptionFullComplete": "Выигран матч ${LEVEL}",
|
||||
"name": "Победа в матче ${LEVEL}"
|
||||
|
|
@ -250,7 +250,7 @@
|
|||
},
|
||||
"Sharing is Caring": {
|
||||
"descriptionFull": "Успешно поделиться игрой с другом",
|
||||
"descriptionFullComplete": "Игра успешно поделена с другом",
|
||||
"descriptionFullComplete": "Игра успешно передана другу",
|
||||
"name": "Делиться - значит заботиться"
|
||||
},
|
||||
"Stayin' Alive": {
|
||||
|
|
@ -309,7 +309,7 @@
|
|||
},
|
||||
"Uber Football Victory": {
|
||||
"description": "Выиграйте матч",
|
||||
"descriptionComplete": "Матч выигран",
|
||||
"descriptionComplete": "Матч пройден в вашу пользу",
|
||||
"descriptionFull": "Выиграйте матч ${LEVEL}",
|
||||
"descriptionFullComplete": "Выигран матч ${LEVEL}",
|
||||
"name": "Победа в матче ${LEVEL}"
|
||||
|
|
@ -329,9 +329,10 @@
|
|||
"name": "Победа на уровне ${LEVEL}"
|
||||
}
|
||||
},
|
||||
"achievementsRemainingText": "Оставшиеся медали:",
|
||||
"achievementsText": "Медали",
|
||||
"achievementsRemainingText": "Осталось достижений:",
|
||||
"achievementsText": "Достижения",
|
||||
"achievementsUnavailableForOldSeasonsText": "К сожалению, подробности достижений не доступны для старых сезонов.",
|
||||
"activatedText": "${THING} активировано.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Еще игр...",
|
||||
"titleText": "Добавить игру"
|
||||
|
|
@ -340,7 +341,7 @@
|
|||
"alreadySignedInText": "На вашем аккаунте играют на другом устройстве;\nпожалуйста зайдите с другого аккаунта или закройте\nигру на другом устройстве и попытайтесь снова.",
|
||||
"apiVersionErrorText": "Невозможно загрузить модуль ${NAME}; он предназначен для API версии ${VERSION_USED}; здесь требуется версия ${VERSION_REQUIRED}.",
|
||||
"audioSettingsWindow": {
|
||||
"headRelativeVRAudioInfoText": "(Режим \"Авто\" включает его только когда подключены наушники)",
|
||||
"headRelativeVRAudioInfoText": "(Режим \"Авто\" активируется только при подключении наушников)",
|
||||
"headRelativeVRAudioText": "Позиционно-зависимое ВР-аудио",
|
||||
"musicVolumeText": "Громкость музыки",
|
||||
"soundVolumeText": "Громкость звука",
|
||||
|
|
@ -374,37 +375,37 @@
|
|||
"completeThisLevelToProceedText": "Чтобы продолжить, нужно\nпройти этот уровень!",
|
||||
"completionBonusText": "Бонус за прохождение",
|
||||
"configControllersWindow": {
|
||||
"configureControllersText": "Настройка контроллеров",
|
||||
"configureControllersText": "Настройка геймпада",
|
||||
"configureGamepadsText": "Настройка контроллеров",
|
||||
"configureKeyboard2Text": "Настройка клавиатуры P2",
|
||||
"configureKeyboardText": "Настройка клавиатуры",
|
||||
"configureMobileText": "Мобильные устройства как контроллеры",
|
||||
"configureMobileText": "Использовать мобильные устройства в качестве геймпадов",
|
||||
"configureTouchText": "Настройка сенсорного экрана",
|
||||
"ps3Text": "Контроллеры PS3",
|
||||
"titleText": "Контроллеры",
|
||||
"wiimotesText": "Контроллеры Wii",
|
||||
"xbox360Text": "Контроллеры Xbox 360"
|
||||
"ps3Text": "Геймпады PS3™",
|
||||
"titleText": "Геймпады",
|
||||
"wiimotesText": "Пульт Wii™",
|
||||
"xbox360Text": "Геймпады Xbox 360™"
|
||||
},
|
||||
"configGamepadSelectWindow": {
|
||||
"androidNoteText": "Внимание: поддержка контроллеров различается в зависимости от устройства и версии Android.",
|
||||
"pressAnyButtonText": "Нажмите любую кнопку на контроллере,\n который хотите настроить...",
|
||||
"titleText": "Настроить контроллер"
|
||||
"androidNoteText": "Внимание: поддержка геймпада различается в зависимости от устройства и версии Android.",
|
||||
"pressAnyButtonText": "Нажмите любую кнопку на геймпаде,\n которую хотите настроить...",
|
||||
"titleText": "Настроить геймпад"
|
||||
},
|
||||
"configGamepadWindow": {
|
||||
"advancedText": "Дополнительно",
|
||||
"advancedTitleText": "Дополнительные настройки контроллера",
|
||||
"advancedTitleText": "Дополнительные настройки геймпада",
|
||||
"analogStickDeadZoneDescriptionText": "(Включите, если персонаж продолжает двигаться после того, как стик отпущен)",
|
||||
"analogStickDeadZoneText": "Мертвая зона аналогового стика",
|
||||
"appliesToAllText": "(относится ко всем контроллерам данного типа)",
|
||||
"appliesToAllText": "(настроить ко всем геймпадам данного типа)",
|
||||
"autoRecalibrateDescriptionText": "(включить, если персонаж не двигается на полной скорости)",
|
||||
"autoRecalibrateText": "Авто-перекалибровка аналоговых стиков",
|
||||
"axisText": "ось",
|
||||
"clearText": "очистить",
|
||||
"dpadText": "D-Pad",
|
||||
"extraStartButtonText": "Дополнительная кнопка \"Старт",
|
||||
"extraStartButtonText": "Настроить дополнительную кнопку \"Start\"",
|
||||
"ifNothingHappensTryAnalogText": "Если ничего не происходит, попробуйте вместо этого присвоить аналоговому стику.",
|
||||
"ifNothingHappensTryDpadText": "Если ничего не происходит, попробуйте вместо этого присвоить D-Pad.",
|
||||
"ignoreCompletelyDescriptionText": "(не дайте этому контроллеру воздействовать на игру, или меню)",
|
||||
"ignoreCompletelyDescriptionText": "(запретить геймпаду воздействовать на игру, или меню)",
|
||||
"ignoreCompletelyText": "Игнорировать полностью",
|
||||
"ignoredButton1Text": "Игнорируемая кнопка 1",
|
||||
"ignoredButton2Text": "Игнорируемая кнопка 2",
|
||||
|
|
@ -422,13 +423,13 @@
|
|||
"runTrigger1Text": "Триггер для бега 1",
|
||||
"runTrigger2Text": "Триггер для бега 2",
|
||||
"runTriggerDescriptionText": "(аналоговые триггеры позволяют бегать с разной скоростью)",
|
||||
"secondHalfText": "Используйте это для настройки второй половины\nустройства 'два контроллера в одном',\nкоторое показывается как один контроллер.",
|
||||
"secondHalfText": "Используйте эту опцию для настройки второй\nполовины устройства \"два геймпада в одном\",\nдля использования в качестве одного геймпада.",
|
||||
"secondaryEnableText": "Включить",
|
||||
"secondaryText": "Вторичный контроллер",
|
||||
"secondaryText": "Второй геймпад",
|
||||
"startButtonActivatesDefaultDescriptionText": "(выключить, если ваша кнопка \"старт\" работает больше в качестве кнопки \"меню\")",
|
||||
"startButtonActivatesDefaultText": "Кнопка Старт активирует стандартный виджет",
|
||||
"titleText": "Настройка контроллера",
|
||||
"twoInOneSetupText": "Настройка контроллера 2-в-1",
|
||||
"titleText": "Настройка геймпада",
|
||||
"twoInOneSetupText": "Настройка геймпада 2-в-1",
|
||||
"uiOnlyDescriptionText": "(Запретить этому контроллеру присоединяться к игре)",
|
||||
"uiOnlyText": "Ограничить только для меню",
|
||||
"unassignedButtonsRunText": "Все неприсвоенные кнопки для бега",
|
||||
|
|
@ -481,8 +482,8 @@
|
|||
"challengesText": "Испытания",
|
||||
"currentBestText": "Последний рекорд",
|
||||
"customText": "Другое",
|
||||
"entryFeeText": "Участие",
|
||||
"forfeitConfirmText": "Так просто сдаться?",
|
||||
"entryFeeText": "Участвовать",
|
||||
"forfeitConfirmText": "Сдаться?",
|
||||
"forfeitNotAllowedYetText": "Вы не можете покинуть это состязание.",
|
||||
"forfeitText": "Сдаться",
|
||||
"multipliersText": "Множители",
|
||||
|
|
@ -651,14 +652,16 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} в эпическом замедленном действии.",
|
||||
"epicNameFilterText": "${NAME} в эпическом режиме",
|
||||
"errorAccessDeniedText": "доступ запрещен",
|
||||
"errorDeviceTimeIncorrectText": "Время на устройстве отстает на ${HOURS} часов.\nЭто вызывает проблемы.\nПожалуйста, проверьте настройки времени и часового пояса.",
|
||||
"errorOutOfDiskSpaceText": "нет места на диске",
|
||||
"errorSecureConnectionFailText": "Ошибка установки безопасного облачного соединения; сетевые функции могут дать сбой.",
|
||||
"errorText": "Ошибка",
|
||||
"errorUnknownText": "неизвестная ошибка",
|
||||
"exitGameText": "Выйти из ${APP_NAME}?",
|
||||
"exportSuccessText": "'${NAME}' экспортирован.",
|
||||
"externalStorageText": "Внешняя память",
|
||||
"failText": "Провал",
|
||||
"fatalErrorText": "Ой, что-то потерялось или сломалось.\nПопытайтесь переустановить приложение или\nобратитесь к ${EMAIL} за помощью.",
|
||||
"fatalErrorText": "Файлы игры повреждены или отсутствуют.\nПопробуйте переустановить приложение или\nобратитесь к ${EMAIL} за помощью.",
|
||||
"fileSelectorWindow": {
|
||||
"titleFileFolderText": "Выберите файл или папку",
|
||||
"titleFileText": "Выберите файл",
|
||||
|
|
@ -670,7 +673,7 @@
|
|||
"finalScoresText": "Финальные очки",
|
||||
"finalTimeText": "Финальное время",
|
||||
"finishingInstallText": "Завершается установка, минутку...",
|
||||
"fireTVRemoteWarningText": "* Для лучшего результата используйте\nигровые контроллеры или установите\nприложение '${REMOTE_APP_NAME}'\nна ваших телефонах и планшетах.",
|
||||
"fireTVRemoteWarningText": "* Для лучшего результата используйте\nгеймпады или установите\nприложение '${REMOTE_APP_NAME}'\nна ваших телефонах и планшетах.",
|
||||
"firstToFinalText": "Финал до ${COUNT} очков",
|
||||
"firstToSeriesText": "Серия до ${COUNT} очков",
|
||||
"fiveKillText": "ПЯТЕРЫХ ЗА РАЗ!!!",
|
||||
|
|
@ -708,7 +711,7 @@
|
|||
"addressFetchErrorText": "<ошибка запроса адресов>",
|
||||
"appInviteInfoText": "Пригласите друзей поиграть в BombSquad и они\nполучат ${COUNT} бесплатных билетов. Ты получишь\n${YOU_COUNT} за каждого друга.",
|
||||
"appInviteMessageText": "${NAME} отправил вам ${COUNT} билетов в ${APP_NAME}",
|
||||
"appInviteSendACodeText": "Отправьте им код",
|
||||
"appInviteSendACodeText": "Отправить им код",
|
||||
"appInviteTitleText": "Приглашение в ${APP_NAME}",
|
||||
"bluetoothAndroidSupportText": "(работает с любым устройством, поддерживающим Bluetooth)",
|
||||
"bluetoothDescriptionText": "Создать/войти в лобби через Bluetooth:",
|
||||
|
|
@ -829,7 +832,7 @@
|
|||
"ticketPack4Text": "Огромная пачка билетов",
|
||||
"ticketPack5Text": "Слоновая пачка билетов",
|
||||
"ticketPack6Text": "Максимальная пачка билетов",
|
||||
"ticketsFromASponsorText": "Получить ${COUNT} билетов\nот спонсора",
|
||||
"ticketsFromASponsorText": "Посмотреть рекламу,\nчтобы получить ${COUNT} билетов",
|
||||
"ticketsText": "Билетов: ${COUNT}",
|
||||
"titleText": "Получить билеты",
|
||||
"unavailableLinkAccountText": "Извините, но на этой платформе покупки недоступны.\nВ качестве решения, вы можете привязать этот аккаунт \nк аккаунту на другой платформе, и совершать покупки там.",
|
||||
|
|
@ -840,6 +843,7 @@
|
|||
"youHaveText": "У вас ${COUNT} билетов"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Простите, сервис многопользовательской игры Google больше не поддерживается.\nЯ работаю над заменой так быстро, насколько это возможно.\nДо тех пор, пожалуйста выберете другой способ подключения.\n-Эрик",
|
||||
"googlePlayPurchasesNotAvailableText": "Покупки в Google Play недоступны.\nВозможно, вам необходимо обновить приложение магазина.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Всегда",
|
||||
|
|
@ -1166,7 +1170,10 @@
|
|||
"playlistsText": "Плей-листы",
|
||||
"pleaseRateText": "Если вам нравится игра ${APP_NAME}, пожалуйста, подумайте о том,\nчтобы оценить ее или написать рецензию. Это обеспечивает полезную\nобратную связь и помогает поддержать дальнейшую разработку.\n\nСпасибо!\n- Эрик",
|
||||
"pleaseWaitText": "Пожалуйста, подождите...",
|
||||
"pluginClassLoadErrorText": "Ошибка при попытке загрузить класс плагина '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Ошибка при инициализации плагина '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Обнаружены новые плагины! Перезапустите игру, чтобы активировать их, или настройте их в настройках.",
|
||||
"pluginsRemovedText": "${NUM} плагин(ов) больше не найдены.",
|
||||
"pluginsText": "Плагины",
|
||||
"practiceText": "Тренировка",
|
||||
"pressAnyButtonPlayAgainText": "Нажмите любую кнопку чтобы играть снова...",
|
||||
|
|
@ -1188,10 +1195,10 @@
|
|||
},
|
||||
"promoSubmitErrorText": "Ошибка отправки кода, проверьте своё интернете соединение",
|
||||
"ps3ControllersWindow": {
|
||||
"macInstructionsText": "Выключите питание на задней панели PS3, убедитесь, что Bluetooth\nвключен на вашем компьютере, а затем подключите контроллер к Маку\nс помощью кабеля USB для синхронизации. Теперь можно использовать\nкнопку контроллера 'PS' чтобы подключить его к Маку\nв проводном (USB) или беспроводном (Bluetooth) режиме.\n\nНа некоторых Маках при синхронизации может потребоваться код доступа.\nВ этом случае обратитесь к следующей инструкции или к гуглу.\n\n\n\n\nКонтроллеры PS3, связанные по беспроводной сети, должны появиться\nв списке устройств в Настройках системы -> Bluetooth. Возможно, вам придется\nудалить их из этого списка, если вы хотите снова использовать их с PS3.\n\nТакже всегда отключайте их от Bluetooth, когда он не используется,\nиначе будут садиться батарейки.\n\nBluetooth должен обрабатывать до 7 подключенных устройств,\nхотя у вас может получиться по-другому.",
|
||||
"ouyaInstructionsText": "Чтобы использовать контроллер PS3 с OUYA, просто подключите его один раз\nс помощью кабеля USB для синхронизации. Это может отключить другие\nконтроллеры, тогда нужно перезагрузить OUYA и отсоединить кабель USB.\n\nПосле этого можно использовать кнопку 'PS' контроллера для беспроводного\nподключения. После игры нажмите и удерживайте кнопку 'PS' в течение\n10 секунд чтобы выключить контроллер, в противном случае он может\nостаться включенным и разрядит батарейки.",
|
||||
"macInstructionsText": "Выключите питание на задней панели PS3, убедитесь, что Bluetooth\nвключен на вашем компьютере, а затем подключите геймпад к Mac\nс помощью кабеля USB для синхронизации. Теперь можно использовать\nкнопку геймпад 'PS' чтобы подключить его к Mac\nв проводном (USB) или беспроводном (Bluetooth) режиме.\n\nНа некоторых системах Mac при синхронизации может потребоватьсякод доступа.\nВ этом случае обратитесь к следующей инструкции или к гуглу.\n\n\n\n\nГеймпады PS3, связанные по беспроводной сети, должны появиться\nв списке устройств в Настройках системы -> Bluetooth. Возможно, вам придется\nудалить их из этого списка, если вы хотите снова использовать их с PS3.\n\nТакже всегда отключайте их от Bluetooth, когда он не используется,\nиначе будут садиться батарейки.\n\nBluetooth должен обрабатывать до 7 подключенных устройств,\nхотя у вас может получиться по-другому.",
|
||||
"ouyaInstructionsText": "Чтобы использовать геймпад PS3 с OUYA, просто подключите его один раз\nс помощью кабеля USB для синхронизации. Это может отключить другие\nгеймпады, тогда нужно перезагрузить OUYA и отсоединить кабель USB.\n\nПосле этого можно использовать кнопку 'PS' геймпада для беспроводного\nподключения. После игры нажмите и удерживайте кнопку 'PS' в течение\n10 секунд чтобы выключить геймпад, в противном случае он может\nостаться включенным и разрядит батарейки.",
|
||||
"pairingTutorialText": "видео-тьюториал по синхронизации",
|
||||
"titleText": "Использование контроллеров PS3 с ${APP_NAME}:"
|
||||
"titleText": "Использование геймпада PS3 с ${APP_NAME}:"
|
||||
},
|
||||
"publicBetaText": "ОТКРЫТАЯ БЕТА-ВЕРСИЯ",
|
||||
"punchBoldText": "УДАР",
|
||||
|
|
@ -1201,7 +1208,7 @@
|
|||
"purchasingText": "Покупка...",
|
||||
"quitGameText": "Выйти из ${APP_NAME}?",
|
||||
"quittingIn5SecondsText": "Выход через 5 секунд...",
|
||||
"randomPlayerNamesText": "Дима, Кузя, Вован, Маха, Русский, Какуля, Бибер, Борька, Няшка, Толян, Ержан, Дибисяра, Вася, Морген, Серёга, Ваня, Кеша, Жорик, Стёпа, Эдгар, Циган",
|
||||
"randomPlayerNamesText": "Дима, Кузя, Вован, Маха, Русский, Какуля, Бибер, Борька, Няшка, Толян, Ержан, Дибисяра, Вася, Морген, Серёга, Ваня, Кеша, Жорик, Стёпа, Эдгар, Цыган, Олег, Егор, Ёршик",
|
||||
"randomText": "Случайный",
|
||||
"rankText": "Ранг",
|
||||
"ratingText": "Рейтинг",
|
||||
|
|
@ -1508,9 +1515,9 @@
|
|||
"Get the flag to the enemy end zone.": "Отнесите флаг в зону защиты противника.",
|
||||
"How fast can you defeat the ninjas?": "Как быстро вы сможете победить ниндзя?",
|
||||
"Kill a set number of enemies to win.": "Убейте заданное число врагов, чтобы выиграть.",
|
||||
"Last one standing wins.": "Побеждает последний стоящий на ногах.",
|
||||
"Last remaining alive wins.": "Побеждает последний в живых.",
|
||||
"Last team standing wins.": "Побеждает последняя стоящая на ногах команда.",
|
||||
"Last one standing wins.": "Побеждает последний живой игрок.",
|
||||
"Last remaining alive wins.": "Побеждает последний живой игрок.",
|
||||
"Last team standing wins.": "Побеждает последняя живая команда.",
|
||||
"Prevent enemies from reaching the exit.": "Не дайте врагам дойти до выхода.",
|
||||
"Reach the enemy flag to score.": "Доберитесь до вражеского флага чтобы набрать очки.",
|
||||
"Return the enemy flag to score.": "Принесите вражеский флаг на базу, чтобы набрать очки.",
|
||||
|
|
@ -1536,8 +1543,8 @@
|
|||
"Touch the enemy flag.": "Коснитесь вражеского флага.",
|
||||
"carry the flag for ${ARG1} seconds": "пронесите флаг в течение ${ARG1} секунд",
|
||||
"kill ${ARG1} enemies": "убейте ${ARG1} врагов",
|
||||
"last one standing wins": "побеждает последний стоящий на ногах",
|
||||
"last team standing wins": "побеждает последняя стоящая на ногах команда",
|
||||
"last one standing wins": "побеждает последний живой игрок",
|
||||
"last team standing wins": "побеждает последняя живая команда",
|
||||
"return ${ARG1} flags": "принесите ${ARG1} флагов на базу",
|
||||
"return 1 flag": "принесите 1 флаг на базу",
|
||||
"run ${ARG1} laps": "пробегите ${ARG1} кругов",
|
||||
|
|
@ -1874,7 +1881,7 @@
|
|||
},
|
||||
"twoKillText": "ДВОИХ ЗА РАЗ!",
|
||||
"unavailableText": "недоступно",
|
||||
"unconfiguredControllerDetectedText": "Обнаружен ненастроенный контроллер:",
|
||||
"unconfiguredControllerDetectedText": "Обнаружен ненастроенный геймпад:",
|
||||
"unlockThisInTheStoreText": "Это должно быть разблокировано в магазине.",
|
||||
"unlockThisProfilesText": "Чтобы создать более ${NUM} профиль, Вам необходимо:",
|
||||
"unlockThisText": "Чтобы разблокировать это, вам нужно:",
|
||||
|
|
@ -1940,13 +1947,15 @@
|
|||
"winsPlayerText": "Победил ${NAME}!",
|
||||
"winsTeamText": "Победили ${NAME}!",
|
||||
"winsText": "${NAME} выиграл!",
|
||||
"workspaceSyncErrorText": "Ошибка при попытке синхронизации ${WORKSPACE}. Посмотрите лог для информации.",
|
||||
"workspaceSyncReuseText": "Не может синронизировать ${WORKSPACE}. Будет использоватся прошлая синхронизация.",
|
||||
"worldScoresUnavailableText": "Мировые результаты недоступны.",
|
||||
"worldsBestScoresText": "Лучшие в мире очки",
|
||||
"worldsBestTimesText": "Лучшее в мире время",
|
||||
"xbox360ControllersWindow": {
|
||||
"getDriverText": "Скачать драйвер",
|
||||
"macInstructions2Text": "Для использования контроллеров по беспроводной связи, вам также\nпотребуется ресивер, который поставляется с \"беспроводным контроллером\nXbox 360 для Windows\". Один ресивер позволяет подключить до 4 контроллеров.\n\nВнимание: ресиверы сторонних производителей не будут работать с этим драйвером,\nубедитесь, что на вашем ресивере написано \"Microsoft\", а не \"XBOX 360\".\nMicrosoft больше не продает их отдельно, так что вам нужно будет найти\nресивер в комплекте с контроллером, либо искать на ebay.\n\nЕсли вы считаете это полезным, можете отправить денег разработчику\nдрайвера на его сайте.",
|
||||
"macInstructionsText": "Для использования контроллеров Xbox 360 необходимо\nустановить драйвер Mac, доступный по ссылке ниже.\nОн работает и с проводными и беспроводными контроллерами.",
|
||||
"macInstructions2Text": "Для использования контроллеров по беспроводной связи, вам также\nпотребуется ресивер, который поставляется с \"беспроводным геймпадом\nXbox 360 для Windows\". Один ресивер позволяет подключить до 4 контроллеров.\n\nВнимание: ресиверы сторонних производителей не будут работать с этим драйвером,\nубедитесь, что на вашем ресивере написано \"Microsoft\", а не \"XBOX 360\".\nMicrosoft больше не продает их отдельно, так что вам нужно будет найти\nресивер в комплекте с геймпадом, либо искать на ebay.\n\nЕсли вы считаете это полезным, можете отправить денег разработчику\nдрайвера на его сайте.",
|
||||
"macInstructionsText": "Для использования геймпада Xbox 360 необходимо\nустановить драйвер Mac, доступный по ссылке ниже.\nОн работает и с проводными и беспроводными геймпадами.",
|
||||
"macInstructionsTextScale": 0.8,
|
||||
"ouyaInstructionsText": "Для использования проводных контроллеров Xbox 360 в BombSquad,\nпросто подключите их к USB-порту вашего устройства. Для нескольких\nконтроллеров можно использовать концентратор USB.\n\nДля использования беспроводных контроллеров вам понадобится беспроводной\nресивер который поставляется в наборе \"беспроводного геймпада Xbox 360\nдля Windows\" или продается отдельно. Каждый ресивер подключается\nк порту USB и позволяет подключать до 4 беспроводных контроллеров.",
|
||||
"titleText": "Использование контроллеров Xbox 360 в ${APP_NAME}:"
|
||||
|
|
|
|||
10
dist/ba_data/data/languages/serbian.json
vendored
10
dist/ba_data/data/languages/serbian.json
vendored
|
|
@ -328,6 +328,7 @@
|
|||
"achievementsRemainingText": "Неизвршена достигнућа:",
|
||||
"achievementsText": "Достигнућа",
|
||||
"achievementsUnavailableForOldSeasonsText": "Извини, информације нису доступне за старије сезоне.",
|
||||
"activatedText": "${THING} Активиран",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Додај више игри...",
|
||||
"titleText": "Додај игру"
|
||||
|
|
@ -627,7 +628,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} у епско успореној игри.",
|
||||
"epicNameFilterText": "Епски ${NAME}",
|
||||
"errorAccessDeniedText": "приступ одбијен",
|
||||
"errorDeviceTimeIncorrectText": "Време на твом уређају је нетачно за ${HOURS} сати.\nОво може изазвати проблеме.\nМолимо вас проверите подешавања времена и временску зону.",
|
||||
"errorOutOfDiskSpaceText": "нема места на диску",
|
||||
"errorSecureConnectionFailText": "Немогуће успоставити везу са клаудом; функција мреже може престати.",
|
||||
"errorText": "Грешка",
|
||||
"errorUnknownText": "непозната грешка",
|
||||
"exitGameText": "Изађи из \"${APP_NAME}\"?",
|
||||
|
|
@ -1119,7 +1122,10 @@
|
|||
"playlistsText": "Листе игара",
|
||||
"pleaseRateText": "Ако уживате у \"${APP_NAME}\" игри, молимо вас да издвојите\nмало времена да оцените апликацију или напишете коментар.\nОво нам даје корисне информације и помаже у будућем развоју.\n\nХвала!\n-Ерик",
|
||||
"pleaseWaitText": "Молимо вас сачекајте...",
|
||||
"pluginsDetectedText": "Нови додатак/ци пронађен/и. Укључи/подеси их у подешавањима.",
|
||||
"pluginClassLoadErrorText": "Грешка учитавања плугина класе '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Грешка иницијације плугина '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Нови додатак/ци пронађени. Рестартуј да их активираш,или конфигуришеш у подешавањима.",
|
||||
"pluginsRemovedText": "${NUM} додатак/ више не постоје.",
|
||||
"pluginsText": "Додаци",
|
||||
"practiceText": "Вежбање",
|
||||
"pressAnyButtonPlayAgainText": "Притисни било које дугме да одиграш опет...",
|
||||
|
|
@ -1855,6 +1861,8 @@
|
|||
"winsPlayerText": "${NAME} је победио!",
|
||||
"winsTeamText": "${NAME} је победио!",
|
||||
"winsText": "${NAME} је победио!",
|
||||
"workspaceSyncErrorText": "Грешка синхронизовања ${WORKSPACE}. Погледајте лог за више детаља.",
|
||||
"workspaceSyncReuseText": "Синхронизовање ${WORKSPACE} неуспешно. Коришћење претходно синхронизоване верзије.",
|
||||
"worldScoresUnavailableText": "Светски резултати недоступни.",
|
||||
"worldsBestScoresText": "Најбољи резултати на свету",
|
||||
"worldsBestTimesText": "Најбоља времена на свету",
|
||||
|
|
|
|||
15
dist/ba_data/data/languages/spanish.json
vendored
15
dist/ba_data/data/languages/spanish.json
vendored
|
|
@ -32,7 +32,7 @@
|
|||
"signInWithTestAccountInfoText": "(Cuenta de prueba, usa la cuenta del dispositivo para avanzar)",
|
||||
"signInWithTestAccountText": "Registrarse con una Cuenta de Prueba",
|
||||
"signInWithV2InfoText": "(una cuenta que funciona en todas las plataformas)",
|
||||
"signInWithV2Text": "Inicie cesión con una cuenta de bosquad",
|
||||
"signInWithV2Text": "Inicie sesión con tú cuenta de BombSquad",
|
||||
"signOutText": "Cerrar Sesión",
|
||||
"signingInText": "Iniciando sesión...",
|
||||
"signingOutText": "Cerrando sesión...",
|
||||
|
|
@ -332,6 +332,7 @@
|
|||
"achievementsRemainingText": "Logros pendientes:",
|
||||
"achievementsText": "Logros",
|
||||
"achievementsUnavailableForOldSeasonsText": "Lo sentimos, los logros específicos no están disponibles para temporadas anteriores.",
|
||||
"activatedText": "${THING} activado.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Más Juegos...",
|
||||
"titleText": "Agregar Juego"
|
||||
|
|
@ -651,7 +652,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} En cámara lenta épica.",
|
||||
"epicNameFilterText": "${NAME} - Modo épico",
|
||||
"errorAccessDeniedText": "acceso negado",
|
||||
"errorDeviceTimeIncorrectText": "La hora actual de tu dispositivo es ${HOURS} horas.\nEsto podría causar problemas.\nPorfavor verifica la hora y zona horaria en ajustes.",
|
||||
"errorOutOfDiskSpaceText": "insuficiente espacio en disco",
|
||||
"errorSecureConnectionFailText": "No se puede establecer una conexión segura en la nube; La red podría estar fallando",
|
||||
"errorText": "Error",
|
||||
"errorUnknownText": "error desconocido",
|
||||
"exitGameText": "¿Salir de ${APP_NAME}?",
|
||||
|
|
@ -838,6 +841,7 @@
|
|||
"youHaveText": "tienes ${COUNT} boletos"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Lo siento, Google's multijugador servicio ya no esta mas disponible.\nEstoy trabajando en un reemplazo lo mas rapido posible.\nHasta entonces, por favor intente con otro metodo de conexión.\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Las compras de Google Play no están disponibles.\nEs posible que deba actualizar la aplicación de su tienda.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Siempre",
|
||||
|
|
@ -1079,8 +1083,8 @@
|
|||
"modeArcadeText": "Modo Arcade",
|
||||
"modeClassicText": "Modo Clásico",
|
||||
"modeDemoText": "Modo De Demostración",
|
||||
"mostValuablePlayerText": "Jugador más valorado",
|
||||
"mostViolatedPlayerText": "Jugador más agredido",
|
||||
"mostValuablePlayerText": "Jugador más Valorado",
|
||||
"mostViolatedPlayerText": "Jugador más Violado",
|
||||
"mostViolentPlayerText": "Jugador más Violento",
|
||||
"moveText": "Mover",
|
||||
"multiKillText": "¡¡¡${COUNT}-COMBO!!!",
|
||||
|
|
@ -1178,7 +1182,10 @@
|
|||
"playlistsText": "Listas de Juego",
|
||||
"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...",
|
||||
"pluginClassLoadErrorText": "Error al cargar la clase del plugin '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Error al iniciar el plugin '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Nuevos complemento(s) detectados. Reinicie para activarlos, o configúrelos en la configuración",
|
||||
"pluginsRemovedText": "${NUM} plugin(s) ya no se encuentran.",
|
||||
"pluginsText": "Plugins",
|
||||
"practiceText": "Práctica",
|
||||
"pressAnyButtonPlayAgainText": "Oprime cualquier botón jugar de nuevo...",
|
||||
|
|
@ -1960,6 +1967,8 @@
|
|||
"winsPlayerText": "¡${NAME} Gana!",
|
||||
"winsTeamText": "¡${NAME} Gana!!",
|
||||
"winsText": "¡${NAME} Gana!",
|
||||
"workspaceSyncErrorText": "Error al sincronizar ${WORKSPACE}. Mira el registro para mas detalles.",
|
||||
"workspaceSyncReuseText": "No se puede sincronizar ${WORKSPACE}. Reusando la versión sincronizada anterior.",
|
||||
"worldScoresUnavailableText": "Puntuaciones globales no disponibles.",
|
||||
"worldsBestScoresText": "Mejores puntuaciones Mundiales",
|
||||
"worldsBestTimesText": "Mejores tiempos Mundiales",
|
||||
|
|
|
|||
11
dist/ba_data/data/languages/tamil.json
vendored
11
dist/ba_data/data/languages/tamil.json
vendored
|
|
@ -324,6 +324,7 @@
|
|||
"achievementsRemainingText": "மீதமுள்ள சாதனைகள்:",
|
||||
"achievementsText": "சாதனைகள்",
|
||||
"achievementsUnavailableForOldSeasonsText": "மன்னிக்கவும், சாதனை விவரங்கள் பழைய பருவங்களுக்கு கிடைக்கவில்லை.",
|
||||
"activatedText": "${THING} செயல்படுத்தப்பட்டது.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "மேலும் விளையாட்டுகளைப் பெறுங்கள்...",
|
||||
"titleText": "விளையாட்டைச் சேர்"
|
||||
|
|
@ -623,7 +624,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} காவிய மெதுவான இயக்கத்தில்.",
|
||||
"epicNameFilterText": "காவியம் ${NAME}",
|
||||
"errorAccessDeniedText": "அணுகல் மறுக்கப்பட்டது",
|
||||
"errorDeviceTimeIncorrectText": "உங்கள் சாதனத்தின் நேரம் ${HOURS} மணிநேரம் உள்ளது.\nஇதனால் பிரச்னைகள் ஏற்பட வாய்ப்புள்ளது.\nஉங்கள் நேரம் மற்றும் நேர மண்டல அமைப்புகளைச் சரிபார்க்கவும்.",
|
||||
"errorOutOfDiskSpaceText": "வட்டு இடத்திற்கு வெளியே",
|
||||
"errorSecureConnectionFailText": "பாதுகாப்பான கிளவுட் இணைப்பை நிறுவ முடியவில்லை; பிணைய செயல்பாடு தோல்வியடையலாம்.",
|
||||
"errorText": "பிழை",
|
||||
"errorUnknownText": "அறியப்படாத பிழை",
|
||||
"exitGameText": "${APP_NAME} இலிருந்து வெளியேறவா?",
|
||||
|
|
@ -786,7 +789,7 @@
|
|||
"ticketPack4Text": "ஜம்போ டிக்கெட் பேக்",
|
||||
"ticketPack5Text": "மம்மத் டிக்கெட் பேக்",
|
||||
"ticketPack6Text": "அல்டிமேட் டிக்கெட் பேக்",
|
||||
"ticketsFromASponsorText": "${COUNT} டிக்கெட்டுகளைப் பெறுங்கள்\nஒரு ஸ்பான்சரிடமிருந்து",
|
||||
"ticketsFromASponsorText": "ஒரு விளம்பரத்தைப் பார்த்து\n${COUNT} டிக்கெட்டுகளை பெறுங்கள்",
|
||||
"ticketsText": "${COUNT} டிக்கெட்டுகள்",
|
||||
"titleText": "டிக்கெட்டுகளைப் பெறுங்கள்",
|
||||
"unavailableLinkAccountText": "மன்னிக்கவும், இந்த தளத்தில் கொள்முதல் கிடைக்கவில்லை.\nஒரு தீர்வாக, இந்தக் கணக்கை ஒரு கணக்குடன் இணைக்கலாம்\nமற்றொரு தளம் மற்றும் அங்கு கொள்முதல் செய்யுங்கள்.",
|
||||
|
|
@ -797,6 +800,7 @@
|
|||
"youHaveText": "உங்களிடம் ${COUNT} டிக்கெட்டுகள் உள்ளன"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "மன்னிக்கவும், கூகுளின் மல்டிபிளேயர் சேவை இனி கிடைக்காது.\nநான் முடிந்தவரை விரைவாக மாற்றுவதற்கு வேலை செய்கிறேன்.\nஅதுவரை, வேறு இணைப்பு முறையை முயற்சிக்கவும்.\n-எரிக்",
|
||||
"googlePlayPurchasesNotAvailableText": "Google Play வாங்குதல்கள் கிடைக்கவில்லை.\nஉங்கள் ஸ்டோர் பயன்பாட்டைப் புதுப்பிக்க வேண்டியிருக்கலாம்.",
|
||||
"googlePlayText": "கூகுள் பிளே",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "எப்போதும்",
|
||||
|
|
@ -1108,7 +1112,10 @@
|
|||
"playlistsText": "பிளேலிஸ்ட்கள்",
|
||||
"pleaseRateText": "நீங்கள் ${APP_NAME} ஐ அனுபவிக்கிறீர்கள் என்றால், தயவுசெய்து எடுப்பதைக் கவனியுங்கள்\nதருணம் மற்றும் மதிப்பிடுதல் அல்லது விமர்சனம் எழுதுதல். இது வழங்குகிறது\nபயனுள்ள கருத்து மற்றும் எதிர்கால வளர்ச்சிக்கு உதவுகிறது.\n\nநன்றி!\n-எரிக்",
|
||||
"pleaseWaitText": "தயவுசெய்து காத்திருங்கள்...",
|
||||
"pluginClassLoadErrorText": "செருகுநிரல் வகுப்பை ஏற்றுவதில் பிழை '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "'${PLUGIN}' செருகுநிரலைத் தொடங்குவதில் பிழை: ${ERROR}",
|
||||
"pluginsDetectedText": "புதிய செருகுநிரல்(கள்) கண்டறியப்பட்டது. அவற்றைச் செயல்படுத்த மீண்டும் தொடங்கவும் அல்லது அமைப்புகளில் உள்ளமைக்கவும்.",
|
||||
"pluginsRemovedText": "${NUM} செருகுநிரல்(கள்) இனி காணப்படவில்லை.",
|
||||
"pluginsText": "செருகுநிரல்கள்",
|
||||
"practiceText": "பயிற்சி",
|
||||
"pressAnyButtonPlayAgainText": "மீண்டும் விளையாட எந்த பட்டனையும் அழுத்தவும்...",
|
||||
|
|
@ -1844,6 +1851,8 @@
|
|||
"winsPlayerText": "${NAME} வெற்றி!",
|
||||
"winsTeamText": "${NAME} வெற்றி!",
|
||||
"winsText": "${NAME} வெற்றி!",
|
||||
"workspaceSyncErrorText": "${WORKSPACE} ஐ ஒத்திசைப்பதில் பிழை. விவரங்களுக்கு பதிவைப் பார்க்கவும்.",
|
||||
"workspaceSyncReuseText": "${WORKSPACE} ஐ ஒத்திசைக்க முடியவில்லை. முந்தைய ஒத்திசைக்கப்பட்ட பதிப்பை மீண்டும் பயன்படுத்துகிறது.",
|
||||
"worldScoresUnavailableText": "உலக ஸ்கோர் கிடைக்கவில்லை.",
|
||||
"worldsBestScoresText": "உலகின் சிறந்த மதிப்பெண்கள்",
|
||||
"worldsBestTimesText": "உலகின் சிறந்த நேரங்கள்",
|
||||
|
|
|
|||
11
dist/ba_data/data/languages/turkish.json
vendored
11
dist/ba_data/data/languages/turkish.json
vendored
|
|
@ -326,6 +326,7 @@
|
|||
"achievementsRemainingText": "Kalan Başarılar;",
|
||||
"achievementsText": "Başarı",
|
||||
"achievementsUnavailableForOldSeasonsText": "Üzgünüz, başarı detayları eski sezonlar için kullanılamaz.",
|
||||
"activatedText": "${THING} aktifleştirildi.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Daha Çok Oyun...",
|
||||
"titleText": "Oyun Ekle"
|
||||
|
|
@ -624,7 +625,9 @@
|
|||
"epicDescriptionFilterText": "${DESCRIPTION} epik ağırçekim.",
|
||||
"epicNameFilterText": "Epik ${NAME}",
|
||||
"errorAccessDeniedText": "erişim reddedildi",
|
||||
"errorDeviceTimeIncorrectText": "Eyvah! Cihazın ile sunucu arasındaki zaman farkı ${HOURS} saat.\nBu bazı sorunlara yol açabilir.\nLütfen saat ve saat dilimi ayarlarını kontrol et.",
|
||||
"errorOutOfDiskSpaceText": "disk alanı doldu",
|
||||
"errorSecureConnectionFailText": "Güvenli bulut bağlantısı kurulamadı; ağ işlevi başarısız olabilir.",
|
||||
"errorText": "Hata",
|
||||
"errorUnknownText": "bilinmeyen hata",
|
||||
"exitGameText": "Çık ${APP_NAME}?",
|
||||
|
|
@ -787,7 +790,7 @@
|
|||
"ticketPack4Text": "Dev Bilet Paketi",
|
||||
"ticketPack5Text": "Muazzam Bilet Paketi",
|
||||
"ticketPack6Text": "En Üst Düzey Bilet Paketi",
|
||||
"ticketsFromASponsorText": "Bir sponsordan\n${COUNT} Bilet Al",
|
||||
"ticketsFromASponsorText": "${COUNT} Bilet için\nbir reklam izle",
|
||||
"ticketsText": "${COUNT} Bilet",
|
||||
"titleText": "Bilet Al",
|
||||
"unavailableLinkAccountText": "Üzgünüz, Satın almalar bu patformda kullanılamaz.\nBu geçici oldugu gibi, bu hesabını diğer platformlardaki\nhesablara bağlayabilir oradan satın alma işlemi yapbilirsin.",
|
||||
|
|
@ -798,6 +801,7 @@
|
|||
"youHaveText": "${COUNT} biletin var"
|
||||
},
|
||||
"googleMultiplayerDiscontinuedText": "Üzgünüz, Google'ın çok oyunculu servisi şu anda çalışmıyor.\nBir yer değişimi için olabildiğince hızlı çalışıyorum.\nO zamana kadar, lütfen başka bir bağlantı yöntemi deneyin.\n-Eric",
|
||||
"googlePlayPurchasesNotAvailableText": "Google Play satın alma işlemleri mevcut değildir.\nMağaza uygulamanızı güncellemeniz gerekebilir.",
|
||||
"googlePlayText": "Google Play",
|
||||
"graphicsSettingsWindow": {
|
||||
"alwaysText": "Her Zaman",
|
||||
|
|
@ -1108,7 +1112,10 @@
|
|||
"playlistsText": "ÇalmaListesi",
|
||||
"pleaseRateText": "Eğer ${APP_NAME}'dan zevk aldıysan, lütfen oyunu değerlerdir\nve yorumunu yaz. Bu oyunun daha fazla geliştirilmesine\nyardımcı olur.\n\nteşekkürler!\n-eric",
|
||||
"pleaseWaitText": "Lütfen bekle...",
|
||||
"pluginClassLoadErrorText": "'${PLUGIN}' eklenti sınıfı yüklenirken hata oluştu: ${ERROR}",
|
||||
"pluginInitErrorText": "'${PLUGIN}' eklentisi başlatılırken hata oluştu: ${ERROR}",
|
||||
"pluginsDetectedText": "Yeni eklentiler tespit edildi. Onları etkinleştirmek veya ayarlarda yapılandırmak için oyunu yeniden başlatın.",
|
||||
"pluginsRemovedText": "${NUM} eklenti(ler) artık bulunmuyor.",
|
||||
"pluginsText": "Eklentiler",
|
||||
"practiceText": "Alıştırma",
|
||||
"pressAnyButtonPlayAgainText": "Tekrar oynamak için bir tuşa basın...",
|
||||
|
|
@ -1844,6 +1851,8 @@
|
|||
"winsPlayerText": "${NAME} Kazandı!",
|
||||
"winsTeamText": "${NAME} Kazandı!",
|
||||
"winsText": "${NAME} Kazandı!",
|
||||
"workspaceSyncErrorText": "${WORKSPACE} eşitlemesinde hata oluştu. Detaylar için günlüğü inceleyin.",
|
||||
"workspaceSyncReuseText": "${WORKSPACE} eşitlenemiyor. Önceden eşitlenmiş sürüm kullanılıyor.",
|
||||
"worldScoresUnavailableText": "Global Skorlar Mevcut Değil.",
|
||||
"worldsBestScoresText": "Global En-İyi Skorlar",
|
||||
"worldsBestTimesText": "Global En-İyi Süreler",
|
||||
|
|
|
|||
172
dist/ba_data/data/languages/venetian.json
vendored
172
dist/ba_data/data/languages/venetian.json
vendored
|
|
@ -5,27 +5,27 @@
|
|||
"achievementProgressText": "Obietivi: ${COUNT} de ${TOTAL}",
|
||||
"campaignProgressText": "Progreso canpagna [Defìsiłe]: ${PROGRESS}",
|
||||
"changeOncePerSeason": "A te połi canbiar ’sto dato soło na volta par stajon.",
|
||||
"changeOncePerSeasonError": "Par modifegar (${NUM} days) A te ghè da spetar ła stajon pròsema.",
|
||||
"changeOncePerSeasonError": "Par canbiarlo te ghè da spetar ła pròsema stajon (${NUM} days).",
|
||||
"customName": "Nome parsonałizà",
|
||||
"linkAccountsEnterCodeText": "Insarisi còdaze",
|
||||
"linkAccountsGenerateCodeText": "Jènara còdaze",
|
||||
"linkAccountsInfoText": "(sparpagna progresi infrà dispozitivi defarenti)",
|
||||
"linkAccountsInstructionsNewText": "Par cołegar do account, jènara un còdaze inte'l primo\ndispozitivo e insarìseło inte’l segondo. I dati de’l\nsegondo account i vegnarà sparpagnài so tuti do i account\n(i dati de’l primo account i ndarà perdesti).\n\nA te połi cołegar fin a ${COUNT} account.\n\nINPORTANTE: cołega soło i account de to propiedà.\nSe A te cołeghi account de calche to amigo, A no sarè\npì boni de zugar online inte’l mèdemo momento.",
|
||||
"linkAccountsInfoText": "(sparpagna progresi infrà dispozidivi defarenti)",
|
||||
"linkAccountsInstructionsNewText": "Par cołegar do account, jènara un còdaze inte'l primo\ndispozidivo e insarìseło inte’l segondo. I dati de’l\nsegondo account i vegnarà sparpagnài so tuti do i account\n(i dati de’l primo account i ndarà perdesti).\n\nTe połi cołegar fin a ${COUNT} account.\n\nINPORTANTE: cołega soło i account de to propiedà.\nSe te cołeghi account de calche to amigo, no sarè\npì boni de zugar online inte’l mèdemo momento.",
|
||||
"linkAccountsText": "Cołega account",
|
||||
"linkedAccountsText": "Account cołegài:",
|
||||
"nameChangeConfirm": "Vutu canbiar el nome de’l to account co ${NAME}?",
|
||||
"resetProgressConfirmNoAchievementsText": "A te si drio ełimenar i to progresi so ła modałidà\ncooparadiva e i to punteji łogałi (ma miga i to biłieti).\n’Sta asion no ła połe mìa èsar anułada. Vutu ndar vanti?",
|
||||
"resetProgressConfirmText": "A te si drio ełimenar i to progresi so ła\nmodałidà cooparadiva, i to obietivi e i to punteji\nłogałi (ma miga i to biłieti). ’Sta asion\nno ła połe mìa èsar anułada. Vutu ndar vanti?",
|
||||
"resetProgressConfirmNoAchievementsText": "Te si drio ełimenar i to progresi so ła modałidà\ncooparadiva e i to punteji łogałi (ma miga i to biłieti).\n’Sta asion no ła połe pì èsar anułada. Vutu ndar vanti?",
|
||||
"resetProgressConfirmText": "Te si drio ełimenar i to progresi so ła\nmodałidà cooparadiva, i to obietivi e i to punteji\nłogałi (ma miga i to biłieti). ’Sta asion\nno ła połe pì èsar anułada. Vutu ndar vanti?",
|
||||
"resetProgressText": "Ełìmena progresi",
|
||||
"setAccountName": "Inposta un nome utente",
|
||||
"setAccountNameDesc": "Sełesiona el nome da vizuałizar so’l to account.\nA te połi doparar el nome da uno de i to account\ncołegài o crear un nome parsonałizà ma ùnivogo.",
|
||||
"signInInfoText": "Conétate par tirar sù biłieti, batajar online e\nsparpagnar i to progresi infrà dispozitivi defarenti.",
|
||||
"signInInfoText": "Conétate par tirar sù biłieti, batajar online e\nsparpagnar i to progresi infrà dispozidivi defarenti.",
|
||||
"signInText": "Conétate",
|
||||
"signInWithDeviceInfoText": "(par 'sto dispozitivo A ze disponìbiłe un soło account automàtego)",
|
||||
"signInWithDeviceText": "Conétate co l'account de’l dispozitivo",
|
||||
"signInWithDeviceInfoText": "(par 'sto dispozidivo ze disponìbiłe un soło account automàtego)",
|
||||
"signInWithDeviceText": "Conétate co l'account de’l dispozidivo",
|
||||
"signInWithGameCircleText": "Conétate co Game Circle",
|
||||
"signInWithGooglePlayText": "Conétate co Google Play",
|
||||
"signInWithTestAccountInfoText": "(account de proa vecio: in fuduro dòpara i account de’l dispozitivo)",
|
||||
"signInWithTestAccountInfoText": "(account de proa vecio: in fuduro dòpara i account de’l dispozidivo)",
|
||||
"signInWithTestAccountText": "Conétate co un account de proa",
|
||||
"signInWithV2InfoText": "(un account che fusiona so tute łe piataforme)",
|
||||
"signInWithV2Text": "Acedi co un account BombSquad",
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
"unlinkAccountsText": "Descołega account",
|
||||
"v2LinkInstructionsText": "Acedi o dòpara 'sto link par crear un account.",
|
||||
"viaAccount": "(doparando ${NAME})",
|
||||
"youAreSignedInAsText": "A te zugarè cofà:"
|
||||
"youAreSignedInAsText": "Te zugarè cofà:"
|
||||
},
|
||||
"achievementChallengesText": "Obietivi sfide",
|
||||
"achievementText": "Obietivo",
|
||||
|
|
@ -323,14 +323,15 @@
|
|||
},
|
||||
"achievementsRemainingText": "Obietivi restanti:",
|
||||
"achievementsText": "Obietivi",
|
||||
"achievementsUnavailableForOldSeasonsText": "Ne despiaze, i obietivi de łe stajon pasàe no i ze mìa disponìbiłe.",
|
||||
"achievementsUnavailableForOldSeasonsText": "Ne despiaze, i obietivi de łe stajon pasàe no i ze pì disponìbiłi.",
|
||||
"activatedText": "${THING} ativà.",
|
||||
"addGameWindow": {
|
||||
"getMoreGamesText": "Otien pì łevełi...",
|
||||
"titleText": "Zonta zugo"
|
||||
},
|
||||
"allowText": "Parmeti",
|
||||
"alreadySignedInText": "El to account el ze in dòparo inte n’antro\ndispozitivo: canbia account o sara sù el zugo\ninte cheł’altro to dispozitivo e proa danovo.",
|
||||
"apiVersionErrorText": "A no ze mìa posìbiłe cargar el mòduło ${NAME}, el se refarise a ła varsion ${VERSION_USED}. A serve invese ła ${VERSION_REQUIRED}.",
|
||||
"alreadySignedInText": "El to account el ze in dòparo inte n’antro\ndispozidivo: canbia account o sara sù el zugo\ninte cheł’altro to dispozidivo e proa danovo.",
|
||||
"apiVersionErrorText": "Inposìbiłe cargar el mòduło ${NAME}, el se refarise a ła varsion ${VERSION_USED}. Serve invese ła ${VERSION_REQUIRED}.",
|
||||
"audioSettingsWindow": {
|
||||
"headRelativeVRAudioInfoText": "(Ativa \"Auto\" soło co A te tachi sù łe fonarołe par ła realtà virtuałe)",
|
||||
"headRelativeVRAudioText": "Àudio par fonarołe VR",
|
||||
|
|
@ -354,19 +355,19 @@
|
|||
"buttonText": "boton",
|
||||
"canWeDebugText": "Ghetu caro che BombSquad el reporte in automàtego bai,\nblochi e informasion baze só'l so dòparo a'l dezviłupador?\n\n'Sti dati no i contien miga informasion parsonałi ma i ło\njuta a far ndar ben el zugo sensa blochi o bai.",
|
||||
"cancelText": "Anuła",
|
||||
"cantConfigureDeviceText": "Ne despiaze, ${DEVICE} no'l ze mìa configuràbiłe.",
|
||||
"cantConfigureDeviceText": "Ne despiaze, ${DEVICE} no'l ze miga configuràbiłe.",
|
||||
"challengeEndedText": "'Sta sfida ła ze fenìa.",
|
||||
"chatMuteText": "Siłensia ciacołada",
|
||||
"chatMutedText": "Ciacołada siłensiada",
|
||||
"chatUnMuteText": "Reativa son",
|
||||
"choosingPlayerText": "<sernisi zugador>",
|
||||
"completeThisLevelToProceedText": "A te ghè da conpletar 'sto\nłeveło par ndar vanti!",
|
||||
"completeThisLevelToProceedText": "Par ndar vanti te ghè\nda conpletar 'sto łeveło!",
|
||||
"completionBonusText": "Premio de concruzion",
|
||||
"configControllersWindow": {
|
||||
"configureControllersText": "Configura controładori",
|
||||
"configureKeyboard2Text": "Configura botonera P2",
|
||||
"configureKeyboardText": "Configura botonera",
|
||||
"configureMobileText": "Dòpara dispozitivi cofà controładori",
|
||||
"configureMobileText": "Dòpara dispozidivi cofà controładori",
|
||||
"configureTouchText": "Configura schermo tàtiłe",
|
||||
"ps3Text": "Controładori PS3",
|
||||
"titleText": "Controładori",
|
||||
|
|
@ -374,7 +375,7 @@
|
|||
"xbox360Text": "Controładori Xbox 360"
|
||||
},
|
||||
"configGamepadSelectWindow": {
|
||||
"androidNoteText": "Nota: ła conpatibiłidà par i controładori ła muda drio dispozitivo e varsion de Android.",
|
||||
"androidNoteText": "Nota: ła conpatibiłidà par i controładori ła muda drio dispozidivo e varsion de Android.",
|
||||
"pressAnyButtonText": "Struca un boton calsìase de'l controłador\nche A te vołi configurar...",
|
||||
"titleText": "Configura controładori"
|
||||
},
|
||||
|
|
@ -418,13 +419,13 @@
|
|||
"twoInOneSetupText": "Configurasion controłador 2 so 1",
|
||||
"uiOnlyDescriptionText": "(par evitar che 'sto controłador el posa zontarse inte na partìa)",
|
||||
"uiOnlyText": "Łìmida el dòparo de'l menù",
|
||||
"unassignedButtonsRunText": "Tuti i botoni mìa defenìi i fà córar",
|
||||
"unsetText": "<mìa defenìo>",
|
||||
"unassignedButtonsRunText": "Tuti i botoni miga defenìi i fà córar",
|
||||
"unsetText": "<miga defenìo>",
|
||||
"vrReorientButtonText": "Boton de repozision VR"
|
||||
},
|
||||
"configKeyboardWindow": {
|
||||
"configuringText": "Configurasion ${DEVICE}",
|
||||
"keyboard2NoteText": "Nota: ła parte pì granda de łe botonere łe połe rejistrar\nsoło un fià de comandi a'l colpo. Donca, par zugar in du,\nA se ndarìa mejo doparar do botonere defarenti. Tien daconto\nche A te gavarè da defenir in tuti i cazi botoni unìvoghi\npar i tuti do i zugadori."
|
||||
"keyboard2NoteText": "Nota: ła parte pì granda de łe botonere łe połe rejistrar\nsoło un fià de comandi a'l colpo. Donca, par zugar in du,\nse ndarìa mejo doparar do botonere defarenti. Tien daconto\nche te gavarè da defenir in tuti i cazi botoni unìvoghi\npar i tuti do i zugadori."
|
||||
},
|
||||
"configTouchscreenWindow": {
|
||||
"actionControlScaleText": "Grandesa controło",
|
||||
|
|
@ -445,13 +446,13 @@
|
|||
"connectMobileDevicesWindow": {
|
||||
"amazonText": "Amazon Store",
|
||||
"appStoreText": "App Store",
|
||||
"bestResultsText": "Par zugar co rezultài pì boni A te serve na rede wifi ràpida.\nA te połi redùzar el retardo (lag) de ła rede zugando visin a’l\ntrazmetidor de’l segnałe, desconetendo altri dispozitivi sensa\nfiło o conetendo l’ospitador de’l zugo co un cavo ethernet.",
|
||||
"explanationText": "Par doparar un tełèfono o un tołeto cofà un controłador sensa fiło,\ninstàłaghe rento l’apl \"${REMOTE_APP_NAME}\". Par zugar a ${APP_NAME}\nA te połi conétar co’l wifi tuti i dispozitivi che A te vołi! A ze gratis!",
|
||||
"bestResultsText": "Par zugar co rezultài pì boni te serve na rede wifi ràpida.\nTe połi redùzar el retardo (lag) de ła rede zugando visin a’l\ntrazmetidor de’l segnałe, desconetendo altri dispozidivi sensa\nfiło o conetendo l’ospitador de’l zugo co un cavo ethernet.",
|
||||
"explanationText": "Par doparar un tełèfono o un tołeto cofà un controłador sensa fiło,\ninstàłaghe rento l’apl \"${REMOTE_APP_NAME}\". Par zugar a ${APP_NAME}\nte połi conétar co’l wifi tuti i dispozidivi che te vołi! Ze agratis!",
|
||||
"forAndroidText": "par Android:",
|
||||
"forIOSText": "par iOS:",
|
||||
"getItForText": "Descarga ${REMOTE_APP_NAME} par iOS so l'AppStore de\nApple o par Android so'l Store de Google Play o l'Amazon Store",
|
||||
"googlePlayText": "Google Play",
|
||||
"titleText": "Doparar dispozitivi mòbiłi cofà controładori:"
|
||||
"titleText": "Doparar dispozidivi mòbiłi cofà controładori:"
|
||||
},
|
||||
"continuePurchaseText": "Vutu ndar vanti par ${PRICE}?",
|
||||
"continueText": "Sì!",
|
||||
|
|
@ -466,7 +467,7 @@
|
|||
"currentBestText": "El mejo par deso",
|
||||
"customText": "E in pì...",
|
||||
"entryFeeText": "Costo",
|
||||
"forfeitConfirmText": "Vutu dalvero dàrgheła vinta?",
|
||||
"forfeitConfirmText": "Vutu dabon dàrgheła vinta?",
|
||||
"forfeitNotAllowedYetText": "Deso A no te połi miga dàrgheła vinta suito.",
|
||||
"forfeitText": "Dàgheła vinta",
|
||||
"multipliersText": "Moltiplegadori",
|
||||
|
|
@ -533,7 +534,7 @@
|
|||
"stressTestRoundDurationText": "Durada turno",
|
||||
"stressTestTitleText": "Proa soto sforso",
|
||||
"titleText": "Prestasion e Proe soto sforso",
|
||||
"totalReloadTimeText": "Tenpo totałe recargamento: ${TIME} (par i detaji varda el rejistro)"
|
||||
"totalReloadTimeText": "Tenpo totałe recargamento: ${TIME} (par i detaji varda el rejistro eventi)"
|
||||
},
|
||||
"defaultGameListNameText": "Łista de zugo \"${PLAYMODE}\" predefenìa",
|
||||
"defaultNewGameListNameText": "Ła me łista de zugo ${PLAYMODE}",
|
||||
|
|
@ -623,7 +624,7 @@
|
|||
"errorAccessDeniedText": "aceso refudà",
|
||||
"errorOutOfDiskSpaceText": "spasio so'l disco fenìo",
|
||||
"errorText": "Eror",
|
||||
"errorUnknownText": "eror mìa conosesto",
|
||||
"errorUnknownText": "eror miga conosesto",
|
||||
"exitGameText": "Vutu ndar fora da ${APP_NAME}?",
|
||||
"exportSuccessText": "'${NAME}' esportà.",
|
||||
"externalStorageText": "Memoria esterna",
|
||||
|
|
@ -646,7 +647,7 @@
|
|||
"fiveKillText": "BEN 5 SASINÀI!!!!",
|
||||
"flawlessWaveText": "Ondada parfeta!",
|
||||
"fourKillText": "EŁIMENÀI: 4!!!",
|
||||
"friendScoresUnavailableText": "Punteji de i amighi mìa disponìbiłi.",
|
||||
"friendScoresUnavailableText": "Punteji de i amighi miga disponìbiłi.",
|
||||
"gameCenterText": "GameCenter",
|
||||
"gameCircleText": "GameCircle",
|
||||
"gameLeadersText": "Clasìfega de'l łeveło ${COUNT}",
|
||||
|
|
@ -668,14 +669,14 @@
|
|||
},
|
||||
"gamesToText": "${WINCOUNT} a ${LOSECOUNT}",
|
||||
"gatherWindow": {
|
||||
"aboutDescriptionLocalMultiplayerExtraText": "Recòrdate: se A te ghè bastansa controładori, caun\ndispozitivo de un grupo el połe ospitar pì zugadori.",
|
||||
"aboutDescriptionText": "Dòpara ’ste sesion par far sù un grupo.\n\nI grupi i te parmete de zugar partìe e tornèi\nco i to amighi infrà i vari dispozitivi.\n\nDòpara el boton ${PARTY} insima a drita par\nciacołar e interajir co’l to grupo.\n(so un controłador, struca ${BUTTON} co A te si inte un menù)",
|
||||
"aboutDescriptionLocalMultiplayerExtraText": "Recòrdate: se te ghè bastansa controładori, tuti i\ndispozidivi de un grupo i połe ospitar pì zugadori.",
|
||||
"aboutDescriptionText": "Dòpara 'ste sesion par far sù un grupo.\n\nI grupi i te parmete de zugar partìe e tornèi\nco i to amighi infrà i vari dispozidivi.\n\nDòpara el boton ${PARTY} insima a drita par\nciacołar e interajir co’l to grupo.\n(so un controłador, struca ${BUTTON} co te si inte un menù)",
|
||||
"aboutText": "Info",
|
||||
"addressFetchErrorText": "<eror rancurando sù i ndarisi>",
|
||||
"appInviteMessageText": "L'utente ${NAME} el te ga mandà ${COUNT} biłieti so ${APP_NAME}",
|
||||
"appInviteSendACodeText": "Màndaghe un còdaze",
|
||||
"appInviteTitleText": "Invido a proar ${APP_NAME}",
|
||||
"bluetoothAndroidSupportText": "(el funsiona so tuti i dispozitivi Android co el bluetooth)",
|
||||
"bluetoothAndroidSupportText": "(el funsiona so tuti i dispozidivi Android co el bluetooth)",
|
||||
"bluetoothDescriptionText": "Òspita/zóntate so un grupo co'l bluetooth:",
|
||||
"bluetoothHostText": "Òspita",
|
||||
"bluetoothJoinText": "Zóntate",
|
||||
|
|
@ -708,8 +709,8 @@
|
|||
"googlePlayText": "Google Play",
|
||||
"googlePlayVersionOnlyText": "(soło inte ła varsion Android / Google Play)",
|
||||
"hostPublicPartyDescriptionText": "Òspita un grupo pùblego",
|
||||
"hostingUnavailableText": "Ospitamento mìa disponìbiłe",
|
||||
"inDevelopmentWarningText": "Nota:\n\nEl zugo in rede ła ze na funsion nova e in dezviłupo.\nPar deso, A ze dalvero racomandà che tuti i\nzugadori i sie tuti so ła mèdema rede wifi.",
|
||||
"hostingUnavailableText": "Ospitamento miga disponìbiłe",
|
||||
"inDevelopmentWarningText": "Nota:\n\nEl zugo in rede ła ze na funsion nova e in dezviłupo.\nPar deso, ze dabon racomandà che tuti i\nzugadori i sipie tuti so ła mèdema rede wifi.",
|
||||
"internetText": "Internet",
|
||||
"inviteAFriendText": "I to amighi zełi sensa zugo? Invìdełi a\nproarlo e i resevarà ${COUNT} biłieti gratùidi.",
|
||||
"inviteFriendsText": "Invida amighi",
|
||||
|
|
@ -734,7 +735,7 @@
|
|||
"otherVersionsText": "(par altre varsion)",
|
||||
"partyCodeText": "Còdaze de'l grupo",
|
||||
"partyInviteAcceptText": "Và ben",
|
||||
"partyInviteDeclineText": "Mìa deso",
|
||||
"partyInviteDeclineText": "Miga deso",
|
||||
"partyInviteGooglePlayExtraText": "(varda el paneło 'Google Play' inte ła fenestra 'Crea grupo')",
|
||||
"partyInviteIgnoreText": "Ignora",
|
||||
"partyInviteText": "A te ze rivà un invido de ${NAME}\npar zontarte inte'l só grupo!",
|
||||
|
|
@ -744,7 +745,7 @@
|
|||
"partyStatusCheckingText": "Varìfega condision...",
|
||||
"partyStatusJoinableText": "deso el to grupo el połe èsar catà da internet",
|
||||
"partyStatusNoConnectionText": "A no ze miga posìbiłe conétarse a'l server",
|
||||
"partyStatusNotJoinableText": "el to grupo no'l połe mìa èsar catà da internet",
|
||||
"partyStatusNotJoinableText": "el to grupo no'l połe miga èsar catà da internet",
|
||||
"partyStatusNotPublicText": "el to grupo no'l ze miga pùblego",
|
||||
"pingText": "łatensa",
|
||||
"portText": "Porta",
|
||||
|
|
@ -763,12 +764,12 @@
|
|||
"startStopHostingMinutesText": "Te połi tacar o fermar de ospitar grupi łìbaramente par n'antri ${MINUTES} menuti.",
|
||||
"stopHostingText": "Ferma ospitamento",
|
||||
"titleText": "Crea grupo",
|
||||
"wifiDirectDescriptionBottomText": "Se tuti i dispozitivi i gà ła sesion 'Wifi direto', i sarà boni de dopararlo par\ncatarse e conétarse infrà de łori. Na volta che tuti i dispozitivi i sarà conetesti,\nA te podarè crear grupi inte ła sesion 'Rede łogałe', cofà ła fuse na rede wifi normałe.\n\nPar rezultài pì boni, mejo che l’ospitador de’l wifi direto el sipie l’òspite anca de’l grupo so ${APP_NAME}.",
|
||||
"wifiDirectDescriptionTopText": "El Wifi direto el połe èsar doparà par conétar diretamente dispozitivi Android\nsensa pasar par ła rede wifi. El funsiona mejo so varsion Android 4.2 o pì resenti.\n\nPar dopararlo, verzi łe inpostasion wifi e controła ła funsion 'Wifi direto'.",
|
||||
"wifiDirectDescriptionBottomText": "Se tuti i dispozidivi i gà ła sesion 'Wifi direto', i sarà boni de dopararlo par\ncatarse e conétarse infrà de łori. Na volta che tuti i dispozidivi i sarà conetesti,\nte podarè crear grupi inte ła sesion 'Rede łogałe', cofà ła fuse na rede wifi normałe.\n\nPar rezultài pì boni, mejo che l’ospitador de’l wifi direto el sipie l’òspite anca de’l grupo so ${APP_NAME}.",
|
||||
"wifiDirectDescriptionTopText": "El Wifi direto el połe èsar doparà par conétar diretamente dispozidivi Android\nsensa pasar par ła rede wifi. El funsiona mejo so varsion Android 4.2 o pì resenti.\n\nPar dopararlo, verzi łe inpostasion wifi e controła ła funsion 'Wifi direto'.",
|
||||
"wifiDirectOpenWiFiSettingsText": "Verzi inpostasion wifi",
|
||||
"wifiDirectText": "Wifi direto",
|
||||
"worksBetweenAllPlatformsText": "(el funsiona intrà tute łe piataforme)",
|
||||
"worksWithGooglePlayDevicesText": "(el funsiona co tuti i dispozitivi co ła varsion de’l zugo de Google Play par Android)",
|
||||
"worksWithGooglePlayDevicesText": "(el funsiona co tuti i dispozidivi co ła varsion de’l zugo de Google Play par Android)",
|
||||
"youHaveBeenSentAPromoCodeText": "A te ze stà mandà un còdaze promosionałe de ${APP_NAME}:"
|
||||
},
|
||||
"getTicketsWindow": {
|
||||
|
|
@ -788,8 +789,8 @@
|
|||
"ticketsText": "${COUNT} biłieti",
|
||||
"titleText": "Otien biłieti",
|
||||
"unavailableLinkAccountText": "Ne despiaze, A no se połe miga cronpar so 'sta piataforma.\nVołendo, cofà sołusion, A te połi cołegar 'sto account co\nuno inte n'antra piataforma e cronpar calcosa da łà.",
|
||||
"unavailableTemporarilyText": "'Sta funsion no ła ze mìa disponìbiłe par deso: proa danovo pì tardi.",
|
||||
"unavailableText": "Ne despiaze, 'sta funsion no ła ze mìa disponìbiłe.",
|
||||
"unavailableTemporarilyText": "'Sta funsion no ła ze miga disponìbiłe par deso: proa danovo pì tardi.",
|
||||
"unavailableText": "Ne despiaze, 'sta funsion no ła ze miga disponìbiłe.",
|
||||
"versionTooOldText": "Ne despiaze, 'sta varsion ła ze masa vecia: ajorna el zugo co cheła nova.",
|
||||
"youHaveShortText": "A te ghè ${COUNT}",
|
||||
"youHaveText": "A te ghè ${COUNT} biłieti"
|
||||
|
|
@ -817,13 +818,13 @@
|
|||
"helpWindow": {
|
||||
"bombInfoText": "- Bonbe -\nPì forti de i crogni, ma łe połe\nfarte małe anca a ti. Dopàrełe\nben tràndoghełe doso a i nemighi\nprima che łe salte par aria.",
|
||||
"canHelpText": "${APP_NAME} el połe jutarte!",
|
||||
"controllersInfoText": "A te połi zugar a ${APP_NAME} co i amighi co na rede o, se gavì\ncontroładori che basta, połì zugar tuti insenbre so el mèdemo\ndispozitivo: ${APP_NAME} el ghin suporta racuanti. Połì senpre doparar\ni tełèfoni cofà controładori co l’apl gratùida '${REMOTE_APP_NAME}'.\nPar info in pì varda so Inpostasion > Controładori.",
|
||||
"controllersInfoTextRemoteOnly": "Te połi zugar a ${APP_NAME} co i to amighi doparando na rede,\no zugar tuti so'l mèdemo dispozitivo doparando i tełèfoni cofà\ncontroładori co l'apl gratùida '${REMOTE_APP_NAME}'.",
|
||||
"controllersInfoText": "Te połi zugar a ${APP_NAME} co i amighi co na rede o, se gavì\ncontroładori che basta, połì zugar tuti insenbre so el mèdemo\ndispozidivo: ${APP_NAME} el ghin suporta racuanti. Połì senpre doparar\ni tełèfoni cofà controładori co l’apl gratùida '${REMOTE_APP_NAME}'.\nPar info in pì varda so Inpostasion > Controładori.",
|
||||
"controllersInfoTextRemoteOnly": "Te połi zugar a ${APP_NAME} co i to amighi doparando na rede,\no zugar tuti so'l mèdemo dispozidivo doparando i tełèfoni cofà\ncontroładori co l'apl gratùida '${REMOTE_APP_NAME}'.",
|
||||
"controllersText": "Controładori",
|
||||
"controlsSubtitleText": "El to amighévołe parsonajo de ${APP_NAME} el gà un fià de funsion de baze:",
|
||||
"controlsText": "Controłi",
|
||||
"devicesInfoText": "Ła varsion VR de ${APP_NAME} ła połe èsar zugada so na rede anca\nco ła varsion normałe de l'app, donca tira fora tełèfoni, tołeti\ne computers e taca a zugar! Podarìa èsar ùtiłe conétar na varsion\nnormałe de'l zugo a cheła VR anca soło par parmétarghe a łe parsone\nde poder ndarghe drio a'l zugo da fora.",
|
||||
"devicesText": "Dispozitivi",
|
||||
"devicesText": "Dispozidivi",
|
||||
"friendsGoodText": "A ze senpre bona roba vèrghene. Se se ła gode de pì co pì zugadori\ne ${APP_NAME} el ghin suporta fin a 8, e 'sta roba ła ne mena a:",
|
||||
"friendsText": "Amighi",
|
||||
"jumpInfoText": "- Salto -\nSalta par traversar buzi cełi,\npar trar robe pì alte, o par\nfar védar tuta ła to ałegresa.",
|
||||
|
|
@ -858,18 +859,18 @@
|
|||
},
|
||||
"holdAnyButtonText": "<tien strucà un boton calsìase>",
|
||||
"holdAnyKeyText": "<tien strucà un boton calsìase>",
|
||||
"hostIsNavigatingMenusText": "- ${HOST} l'è drio navegar intrà i menù a zbregabałon! -",
|
||||
"hostIsNavigatingMenusText": "- ${HOST} ze drio navegar intrà i menù a zbregabałon! -",
|
||||
"importPlaylistCodeInstructionsText": "Dòpara 'sto còdaze par inportar 'sta łista de zugo ndove che te vołi:",
|
||||
"importPlaylistSuccessText": "Łista de zugo '${NAME}' a ${TYPE} inportada",
|
||||
"importText": "Inporta",
|
||||
"importingText": "Inportasion...",
|
||||
"inGameClippedNameText": "rento el zugo:\n\"${NAME}\"",
|
||||
"installDiskSpaceErrorText": "EROR: A no ze mìa posìbiłe fenir l’instałasion.\nEl to dispozitivo el podarìa èsar sensa spasio.\nŁìbara un fià de memoria e proa danovo.",
|
||||
"installDiskSpaceErrorText": "EROR: inposìbiłe fenir l’instałasion.\nEl to dispozidivo el podarìa èsar sensa spasio.\nŁìbara un fià de memoria e proa danovo.",
|
||||
"internal": {
|
||||
"arrowsToExitListText": "struca ${LEFT} o ${RIGHT} par ndar fora da ła serie",
|
||||
"buttonText": "boton",
|
||||
"cantKickHostError": "A no te połi miga parar vìa l'ospitador.",
|
||||
"chatBlockedText": "${NAME} l'è stà tajà fora da ła chat par ${TIME} segondi.",
|
||||
"chatBlockedText": "${NAME} ze stà tajà fora da ła chat par ${TIME} segondi.",
|
||||
"connectedToGameText": "A te te si zontà so '${NAME}'",
|
||||
"connectedToPartyText": "A te te si zontà so'l grupo de ${NAME}!",
|
||||
"connectingToPartyText": "Conesion...",
|
||||
|
|
@ -890,10 +891,10 @@
|
|||
"corruptFileText": "A ze stà catài fora file coronpesti. Proa reinstałar el zugo o manda na mail a: ${EMAIL}",
|
||||
"errorPlayingMusicText": "Eror de reprodusion muzegałe: ${MUSIC}",
|
||||
"errorResettingAchievementsText": "A no ze miga posìbiłe reinpostar i obietivi in łinea. Proa danovo pì tardi.",
|
||||
"hasMenuControlText": "${NAME} l'à el controło de'l menù",
|
||||
"hasMenuControlText": "${NAME} gà el controło de'l menù",
|
||||
"incompatibleNewerVersionHostText": "L'ospitador el gà na varsion de'l zugo pì resente.\nAjórneło anca ti a ła varsion ùltema e proa danovo.",
|
||||
"incompatibleVersionHostText": "L'ospitador el gà na varsion de'l zugo defarente.\nSegùreve de ver tuti do l'apl ajornada e provè danovo.",
|
||||
"incompatibleVersionPlayerText": "${NAME} l'à na varsion de'l zugo defarente.\nSegùreve de ver tuti do l'apl ajornada e provè danovo.",
|
||||
"incompatibleVersionPlayerText": "${NAME} gà na varsion de'l zugo defarente.\nSegùreve de ver tuti do l'apl ajornada e provè danovo.",
|
||||
"invalidAddressErrorText": "Eror: ndariso miga vàłido.",
|
||||
"invalidNameErrorText": "Eror: nome miga vàłido.",
|
||||
"invalidPortErrorText": "Eror: porta miga vàłida.",
|
||||
|
|
@ -901,20 +902,20 @@
|
|||
"invitationsSentText": "Mandài ${COUNT} invidi.",
|
||||
"joinedPartyInstructionsText": "Calchedun el se gà zontà inte'l to grupo.\nVà so \"Zuga\" par tacar na partìa.",
|
||||
"keyboardText": "Botonera",
|
||||
"kickIdlePlayersKickedText": "A ze stà parà vìa ${NAME} par masa sonera.",
|
||||
"kickIdlePlayersWarning1Text": "Se ła só sonera ła sèvita, ${NAME} l'vegnarà parà vìa tenpo ${COUNT} segondi.",
|
||||
"kickIdlePlayersKickedText": "Ze stà parà fora ${NAME} par masa sonera.",
|
||||
"kickIdlePlayersWarning1Text": "Se ła só sonera ła sèvita, ${NAME} vegnarà parà fora tenpo ${COUNT} segondi.",
|
||||
"kickIdlePlayersWarning2Text": "(A te połi dezativarlo so Inpostasion > Avansàe)",
|
||||
"leftGameText": "A te si ndà fora da '${NAME}'.",
|
||||
"leftPartyText": "A te si ndà fora da'l grupo de ${NAME}.",
|
||||
"noMusicFilesInFolderText": "Ła carteła no ła gà rento gnaun file muzegałe.",
|
||||
"playerJoinedPartyText": "${NAME} l'se gà zontà inte'l grupo!",
|
||||
"playerLeftPartyText": "${NAME} l'è ndà fora da'l grupo!",
|
||||
"playerLeftPartyText": "${NAME} gà mołà el grupo!",
|
||||
"rejectingInviteAlreadyInPartyText": "Invido refudà (dezà inte un grupo).",
|
||||
"serverRestartingText": "El server el ze drio retacarse. Reconétate infrà na scianta...",
|
||||
"serverShuttingDownText": "El server el ze drio stuarse...",
|
||||
"signInErrorText": "Eror in entrada.",
|
||||
"signInNoConnectionText": "A no ze mìa posìbiłe ndar rento. (gnauna conesion a internet?)",
|
||||
"telnetAccessDeniedText": "EROR: l'utente no'l gà mìa parmeso l'aceso co telnet.",
|
||||
"signInNoConnectionText": "Inposìbiłe acédar. (sensa conesion internet?)",
|
||||
"telnetAccessDeniedText": "EROR: l'utente no'l gà miga parmeso l'aceso co telnet.",
|
||||
"timeOutText": "(tocarà a ti tenpo ${TIME} segondi)",
|
||||
"touchScreenJoinWarningText": "A te te si zontà co'l touchscreen.\nSe ła ze stà na capeła, struca 'Menù > Moła łeveło'.",
|
||||
"touchScreenText": "TouchScreen",
|
||||
|
|
@ -931,9 +932,9 @@
|
|||
"keyboardChangeInstructionsText": "Struca spasio do 'olte par mudar botonera.",
|
||||
"keyboardNoOthersAvailableText": "A no ghe ze miga altre botonere disponìbiłi.",
|
||||
"keyboardSwitchText": "Pasajo a ła botonera \"${NAME}\".",
|
||||
"kickOccurredText": "${NAME} l'è stà parà vìa.",
|
||||
"kickOccurredText": "${NAME} ze stà parà fora.",
|
||||
"kickQuestionText": "Vutu parar vìa ${NAME}?",
|
||||
"kickText": "Para vìa",
|
||||
"kickText": "Para fora",
|
||||
"kickVoteCantKickAdminsText": "I aministradori no i połe mìa èsar parài vìa.",
|
||||
"kickVoteCantKickSelfText": "A no te połi mìa pararte vìa da soło.",
|
||||
"kickVoteFailedNotEnoughVotersText": "A ghe ze masa pochi zugadori par na votasion.",
|
||||
|
|
@ -996,8 +997,8 @@
|
|||
"howToPlayText": "Come zugar",
|
||||
"justPlayerText": "(Soło par ${NAME})",
|
||||
"leaveGameText": "Moła łeveło",
|
||||
"leavePartyConfirmText": "Vutu dalvero ndar fora da'l grupo?",
|
||||
"leavePartyText": "Va fora da'l grupo",
|
||||
"leavePartyConfirmText": "Vutu dabon ndar fora da'l grupo?",
|
||||
"leavePartyText": "Moła grupo",
|
||||
"quitText": "Sortisi",
|
||||
"resumeText": "Continua",
|
||||
"settingsText": "Inpostasion"
|
||||
|
|
@ -1020,9 +1021,9 @@
|
|||
"multiKillText": "CAENA DE ${COUNT} FATI FORA!!!!!",
|
||||
"multiPlayerCountText": "${COUNT} zugadori",
|
||||
"mustInviteFriendsText": "Nota: A te ghè da invidar i amighi\nso'l paneło \"${GATHER}\" o picar pì\ncontroładori par zugar in multizugador.",
|
||||
"nameBetrayedText": "${NAME} l'à tradìo ${VICTIM}.",
|
||||
"nameDiedText": "${NAME} l'è crepà.",
|
||||
"nameKilledText": "${NAME} l'à copà ${VICTIM}.",
|
||||
"nameBetrayedText": "${NAME} gà tradìo ${VICTIM}.",
|
||||
"nameDiedText": "${NAME} ze crepà.",
|
||||
"nameKilledText": "${NAME} gà copà ${VICTIM}.",
|
||||
"nameNotEmptyText": "El nome no'l połe miga star vodo!",
|
||||
"nameScoresText": "Un ponto par ${NAME}!",
|
||||
"nameSuicideKidFriendlyText": "${NAME} par zbałio L ze crepà.",
|
||||
|
|
@ -1037,8 +1038,8 @@
|
|||
"nextLevelText": "Łeveło seguente",
|
||||
"noAchievementsRemainingText": "- gnaun",
|
||||
"noContinuesText": "(sensa continui)",
|
||||
"noExternalStorageErrorText": "Inte ’sto dispozitivo A no ze stà catada gnauna memoria esterna",
|
||||
"noGameCircleText": "Eror: A no te si miga conetesto co GameCircle",
|
||||
"noExternalStorageErrorText": "So ’sto dispozidivo no ze stà catada gnauna memoria esterna",
|
||||
"noGameCircleText": "Eror: no te si miga conetesto co GameCircle",
|
||||
"noScoresYetText": "Gnancora gnaun puntejo.",
|
||||
"noThanksText": "Nò, grasie",
|
||||
"noTournamentsInTestBuildText": "AVERTENSA: i punteji de'l tornèo de 'sta varsion de proa i vegnarà ignorài.",
|
||||
|
|
@ -1087,7 +1088,7 @@
|
|||
"playerCountAbbreviatedText": "${COUNT}z",
|
||||
"playerDelayedJoinText": "Co tacarà el turno che'l vien A se zontarà anca ${PLAYER}.",
|
||||
"playerInfoText": "Informasion zugador",
|
||||
"playerLeftText": "${PLAYER} l'à mołà el łeveło.",
|
||||
"playerLeftText": "${PLAYER} gà mołà el łeveło.",
|
||||
"playerLimitReachedText": "Nùmaro màsemo de ${COUNT} zugadori: A no połe zontarse pì nesun.",
|
||||
"playerProfilesWindow": {
|
||||
"cantDeleteAccountProfileText": "A no te połi miga ełimenar el profiło prinsipałe de'l to account.",
|
||||
|
|
@ -1105,7 +1106,10 @@
|
|||
"playlistsText": "Łiste de zugo",
|
||||
"pleaseRateText": "Se ${APP_NAME} el ze drio piazerte, tote un àtemo par\nłasarghe zó na vałudasion o scrìvarghe zó un comento. 'Ste\nopinion łe tornarà còmode par dezviłupi fuduri de'l zugo.\n\ngrasie!\n-eric",
|
||||
"pleaseWaitText": "Speta n'àtemo...",
|
||||
"pluginClassLoadErrorText": "Eror de cargamento de ła clase de estension '${PLUGIN}': ${ERROR}",
|
||||
"pluginInitErrorText": "Eror de inisiałizasion de l'estension '${PLUGIN}': ${ERROR}",
|
||||
"pluginsDetectedText": "Estension nove rełevàe. Retaca el zugo par ativarle, o configùrełe so łe inpostasion.",
|
||||
"pluginsRemovedText": "Estension miga catàe: ${NUM}",
|
||||
"pluginsText": "Estension",
|
||||
"practiceText": "Pràtega",
|
||||
"pressAnyButtonPlayAgainText": "Struca un boton calsìase par zugar danovo...",
|
||||
|
|
@ -1125,7 +1129,7 @@
|
|||
},
|
||||
"promoSubmitErrorText": "Eror de trazmision de'l còdaze: controła ła to conesion internet",
|
||||
"ps3ControllersWindow": {
|
||||
"macInstructionsText": "Stua ła corente so'l dadrìo de ła to PS3, segùrate che'l\nbluetooth de'l to Mac el sipie ativà, daspò coneti el to controłador\na'l to Mac co un cavo USB par cubiarli. Da deso in vanti A te\npołi doparar el boton \"cao\" de'l controłador par conétarlo co'l to\nMac in modałidà USB (co'l fiło) o bluetooth (sensa fiło).\n\nPar el cubiamento calche Mac el podarìa dimandarte un còdaze.\nSe càpida, varda ła demostrasion seguente o serca juto so Google.\n\n\n\n\nI controładori PS3 conetesti sensa fiło i gavarìa da védarse inte ła łista\nde'l dispozitivo so Prefarense de sistema > Bluetooth. Co te vorè\ndopararli danovo so ła to PS3, te podarisi ver da cavarli vìa da 'sta łista.\n\nSegùrate anca de desconétarli da'l bluetooth co A no te łi\ndòpari o łe só batarìe łe sevitarà a sconsumarse.\n\nEl bluetooth el gavarìa da suportar fin a 7 dispozitivi conetesti,\nanca se ła capasidà ła podarìa variar.",
|
||||
"macInstructionsText": "Stua ła corente so'l dadrìo de ła to PS3, segùrate che'l\nbluetooth de'l to Mac el sipie ativà, daspò coneti el to controłador\na'l to Mac co un cavo USB par cubiarli. Da deso in vanti te\npołi doparar el boton \"cao\" de'l controłador par conétarlo co'l to\nMac in modałidà USB (co'l fiło) o bluetooth (sensa fiło).\n\nPar el cubiamento calche Mac el podarìa dimandarte un còdaze.\nSe càpida, varda ła demostrasion seguente o serca juto so Google.\n\n\n\n\nI controładori PS3 conetesti sensa fiło i gavarìa da védarse inte ła łista\nde'l dispozidivo so Prefarense de sistema > Bluetooth. Co te vorè\ndopararli danovo so ła to PS3, te podarisi ver da cavarli vìa da 'sta łista.\n\nSegùrate anca de desconétarli da'l bluetooth co no te łi\ndòpari o łe só batarìe łe sevitarà a sconsumarse.\n\nEl bluetooth el gavarìa da suportar fin a 7 dispozidivi conetesti,\nanca se ła capasidà ła podarìa variar.",
|
||||
"ouyaInstructionsText": "Par doparar un controłador PS3 co ła to OUYA, conéteło co un cavo USB par\ncubiarlo. 'Sta asion ła podarìa desconétar cheł'altri to controładori, donca\nA podarìa servirte retacar ła to OUYA e destacar el cavo USB.\n\nDa deso in vanti A te dovarisi èsar bon de doparar el boton \"cao\" de'l\ncontrołador par conétarlo sensa fiło. Co A te ghè fenìo de zugar, tien\nstrucà el boton \"cao\" par 10 segondi par stuar el controłador, el\npodarìa restar inpisà e stracar ła batarìa.",
|
||||
"pairingTutorialText": "demostrasion video pa'l cubiamento",
|
||||
"titleText": "Doparar un controłador PS3 co ${APP_NAME}:"
|
||||
|
|
@ -1153,7 +1157,7 @@
|
|||
"cant_resolve_host": "A no ze mìa posìbiłe catar fora l'ospitador.",
|
||||
"capturing": "Drio spetar i zugadori…",
|
||||
"connected": "Conetesto.",
|
||||
"description": "Dòpara el to tełèfono o tołeto cofà controłador par BombSquad.\nA połe conétarse so un schermo ùgnoło fin a 8 dispozitivi insenbre, par un feston bueło multizugador!",
|
||||
"description": "Dòpara el to tełèfono o tołeto cofà controłador par BombSquad.\nPołe conétarse so un schermo ùgnoło fin a 8 dispozidivi insenbre, par un feston bueło multizugador!",
|
||||
"disconnected": "Desconetesto da'l server.",
|
||||
"dpad_fixed": "fiso",
|
||||
"dpad_floating": "mòbiłe",
|
||||
|
|
@ -1206,9 +1210,9 @@
|
|||
},
|
||||
"scoreWasText": "(prima ${COUNT})",
|
||||
"selectText": "Sełesiona",
|
||||
"seriesWinLine1PlayerText": "L'À VINTO ŁA",
|
||||
"seriesWinLine1TeamText": "L'À VINTO ŁA",
|
||||
"seriesWinLine1Text": "L'À VINTO ŁA",
|
||||
"seriesWinLine1PlayerText": "GÀ VINTO ŁA",
|
||||
"seriesWinLine1TeamText": "GÀ VINTO ŁA",
|
||||
"seriesWinLine1Text": "GÀ VINTO ŁA",
|
||||
"seriesWinLine2Text": "DESFIDA!",
|
||||
"settingsWindow": {
|
||||
"accountText": "Account",
|
||||
|
|
@ -1231,7 +1235,7 @@
|
|||
"enterPromoCodeText": "Insarisi còdaze",
|
||||
"forTestingText": "Nota: vałori vàłidi soło par proe. Sortendo da l'apl łi vegnarà perdesti.",
|
||||
"helpTranslateText": "Łe tradusion de ${APP_NAME} łe ze curàe da vołontari.\nSe A te vol darghe na ociada a cheła veneta, struca so'l boton\ncuà soto. Curada da Còdaze Veneto: codazeveneto@gmail.com",
|
||||
"kickIdlePlayersText": "Para vìa zugadori in sonera",
|
||||
"kickIdlePlayersText": "Para fora zugadori in sonera",
|
||||
"kidFriendlyModeText": "Modałidà bocia (viołensa reduzesta, evc)",
|
||||
"languageText": "Łengua",
|
||||
"moddingGuideText": "Guida par modifegasion",
|
||||
|
|
@ -1317,7 +1321,7 @@
|
|||
"winterSpecialText": "Spesiałe inverno",
|
||||
"youOwnThisText": "- dezà tuo -"
|
||||
},
|
||||
"storeDescriptionText": "Feston bueło a 8 zugadori!\n\nFà saltar par aria i to amighi (o el computer) inte un tornèo de minizughi cofà 'Brinca ła bandiera', 'Scravaso de stełe' o 'Scontri mortałi' in movensa camoma!\n\nFin a 8 parsone łe sarà bone de batajar insenbre, grasie a comandi senpi e a ła conpatibiłidà co tanti controładori. Co l'apl gratùida 'BombSquad Remote' A te połi parfin doparar i to dispozitivi mòbiłi cofà controładori!\n\nE deso... tira fora łe bonbe!\n\nPar informasion in pì daghe na ociada so www.froemling.net/bombsquad.",
|
||||
"storeDescriptionText": "Feston bueło a 8 zugadori!\n\nFà saltar par aria i to amighi (o el computer) inte un tornèo de minizughi cofà 'Brinca ła bandiera', 'Scravaso de stełe' o 'Scontri mortałi' in movensa camoma!\n\nFin a 8 parsone łe sarà bone de batajar insenbre, grasie a comandi senpi e a ła conpatibiłidà co tanti controładori. Co l'apl gratùida 'BombSquad Remote' te połi parfin doparar i to dispozidivi mòbiłi cofà controładori!\n\nE deso... tira fora łe bonbe!\n\nPar informasion in pì daghe na ociada so www.froemling.net/bombsquad.",
|
||||
"storeDescriptions": {
|
||||
"blowUpYourFriendsText": "Fà sciopar par aria i to amighi.",
|
||||
"competeInMiniGamesText": "Zuga co tanti minizughi: da corse a zvołi.",
|
||||
|
|
@ -1572,7 +1576,7 @@
|
|||
"An error has occurred; please contact support. (${ERROR})": "A se gà verifegà un eror: contata l'asistensa. (${ERROR})",
|
||||
"An error has occurred; please contact support@froemling.net.": "A se gà verifegà un eror: contata support@froemling.net.",
|
||||
"An error has occurred; please try again later.": "A se gà verifegà un eror: proa danovo pì tardi.",
|
||||
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Vutu dalvero cołegar 'sti profiłi?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\n'Sta asion no ła połe mìa èsar anułada!",
|
||||
"Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Vutu dabon cołegar 'sti profiłi?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\n'Sta asion no ła połe pì èsar anułada!",
|
||||
"BombSquad Pro unlocked!": "BombSquad Pro dezblocà!",
|
||||
"Can't link 2 accounts of this type.": "A no se połe mìa cołegar 2 profiłi de 'sto tipo.",
|
||||
"Can't link 2 diamond league accounts.": "A no se połe mìa cołegar 2 profiłi de ła łega de damante.",
|
||||
|
|
@ -1588,7 +1592,7 @@
|
|||
"Invalid tournament entry; score will be ignored.": "Entrada inte'l tornèo mìa vàłida: el puntejo el vegnarà ignorà.",
|
||||
"Item unlocked!": "Ojeto dezblocà!",
|
||||
"LINKING DENIED. ${ACCOUNT} contains\nsignificant data that would ALL BE LOST.\nYou can link in the opposite order if you'd like\n(and lose THIS account's data instead)": "COŁEGAMENTO REFUDÀ. ${ACCOUNT} el contien dati\ninportanti che i ndarà PERDESTI.\nSe te vołi A te połi cołegarli in òrdane raverso\n(e pèrdar a'l só posto i dati de 'STO account cuà).",
|
||||
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "Vutu dalvero cołegar l'account ${ACCOUNT} a 'sto account?\nTuti i dati so ${ACCOUNT} i ndarà perdesti.\n'Sta asion no ła połe mìa èsar anułada: situ seguro?",
|
||||
"Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "Vutu dabon cołegar l'account ${ACCOUNT} a 'sto account?\nTuti i dati so ${ACCOUNT} i ndarà perdesti.\n'Sta asion no ła połe pì èsar anułada: vutu ndar vanti?",
|
||||
"Max number of playlists reached.": "Nùmaro màsemo de łiste de scolto pasà.",
|
||||
"Max number of profiles reached.": "Nùmaro màsemo de profiłi pasà.",
|
||||
"Maximum friend code rewards reached.": "Brincà el nùmaro màsemo de premi da'l còdaze amigo.",
|
||||
|
|
@ -1610,11 +1614,11 @@
|
|||
"This code cannot be used on the account that created it.": "'Sto còdaze no'l połe mìa èsar doparà inte l'account che'l ło gà creà.",
|
||||
"This is currently unavailable; please try again later.": "Par deso, funsion miga disponìbiłe. Proa danovo pì tardi.",
|
||||
"This requires version ${VERSION} or newer.": "A ghe serve ła varsion ${VERSION} o una pì nova.",
|
||||
"Tournaments disabled due to rooted device.": "Tornèi dezativài parvìa de'l dispozitivo co'l root.",
|
||||
"Tournaments disabled due to rooted device.": "Tornèi dezativài parvìa de'l dispozidivo co'l root.",
|
||||
"Tournaments require ${VERSION} or newer": "Par i tornèi A serve ła varsion ${VERSION} o una pì resente",
|
||||
"Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "Vutu descołegar l'account ${ACCOUNT} da 'sto account?\nTuti i dati de ${ACCOUNT} i vegnarà ełimenài.\n(obietivi a parte in calche cazo)",
|
||||
"WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "AVERTENSA: el to account el ze stà segnałà par el dòparo de truchi.\nI zugaduri catài a doparar truchi i vegnarà blocài. Zuga da gałantomo.",
|
||||
"Would you like to link your device account to this one?\n\nYour device account is ${ACCOUNT1}\nThis account is ${ACCOUNT2}\n\nThis will allow you to keep your existing progress.\nWarning: this cannot be undone!\n": "Ghetu caro cołegar l'account de'l to dispozitivo co 'sto cuà?\n\nL'account de'l to dispozitivo el ze ${ACCOUNT1}\n'Sto account el ze ${ACCOUNT2}\n\n'Sta oparasion ła te parmetarà de mantegner i to progresi ezistenti.\nAvertensa: 'sta asion no ła połe mìa èsar anułada!",
|
||||
"Would you like to link your device account to this one?\n\nYour device account is ${ACCOUNT1}\nThis account is ${ACCOUNT2}\n\nThis will allow you to keep your existing progress.\nWarning: this cannot be undone!\n": "Ghetu caro cołegar l'account de'l to dispozidivo co 'sto cuà?\n\nL'account de'l to dispozidivo el ze ${ACCOUNT1}\n'Sto account el ze ${ACCOUNT2}\n\n'Sta oparasion ła te parmetarà de mantegner i to progresi ezistenti.\nAvertensa: 'sta asion no ła połe pì èsar anułada!",
|
||||
"You already own this!": "Dezà cronpà!",
|
||||
"You can join in ${COUNT} seconds.": "A te połi zontarte tenpo ${COUNT} segondi.",
|
||||
"You don't have enough tickets for this!": "A no te ghè miga biłieti che basta par cronparlo!",
|
||||
|
|
@ -1672,7 +1676,7 @@
|
|||
"Time Limit": "Łìmide de tenpo"
|
||||
},
|
||||
"statements": {
|
||||
"${TEAM} is disqualified because ${PLAYER} left": "Ła scuadra ${TEAM} ła ze scuałifegada parché ${PLAYER} l'à mołà.",
|
||||
"${TEAM} is disqualified because ${PLAYER} left": "Ła scuadra ${TEAM} ła ze scuałifegada parché ${PLAYER} gà mołà.",
|
||||
"Killing ${NAME} for skipping part of the track!": "Copà ${NAME} par ver saltà un toco de'l parcorso!",
|
||||
"Warning to ${NAME}: turbo / button-spamming knocks you out.": "Avertensa par ${NAME}: el turbo / spam co i botoni el te gà fato trar fora."
|
||||
},
|
||||
|
|
@ -1689,19 +1693,19 @@
|
|||
"Curse boxes turn you into a ticking time bomb.\nThe only cure is to quickly grab a health-pack.": "Łe case małedision łe te transforma inte na bonba a tenpo.\nA te połi curarte soło tołendo in presa un pacheto sałude.",
|
||||
"Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "Anca se drio ła siera A no par, łe abiłidà de tuti i parsonaji\nłe ze conpagne, donca tote sù cheło che'l te połe somejar de pì.",
|
||||
"Don't get too cocky with that energy shield; you can still get yourself thrown off a cliff.": "Mai far masa i gałeti co'l scudo nerjètego: A te połi uncora farte trar baso da na croda.",
|
||||
"Don't run all the time. Really. You will fall off cliffs.": "No stà córar tuto el tenpo. Dalvero. A te fenirè zó par na croda.",
|
||||
"Don't run all the time. Really. You will fall off cliffs.": "No stà córar tuto el tenpo. Dabon. Te fenirè zó par na croda.",
|
||||
"Don't spin for too long; you'll become dizzy and fall.": "No stà ndar torno par masa tenpo: te vegnarà na storniroła e te cascarè.",
|
||||
"Hold any button to run. (Trigger buttons work well if you have them)": "Tien strucà un boton calsìase par córar. (I griłeti nałòzeghi i ze i pì adati, se A te łi ghè)",
|
||||
"Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Tien strucà un boton calsìase par córar. A te te movarè pì in\npresa ma no te voltarè miga masa ben, donca ocio a łe crode.",
|
||||
"Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Łe bonbe jaso no łe ze miga tanto potenti, ma łe injasa tuto cheło\nche łe brinca, e cheło che'l ze injasà el ze anca fàsiłe da fracasar.",
|
||||
"If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Se calchedun el te łeva sù, daghe un crogno che'l te\nmołe zó. 'Sta roba ła funsiona anca inte ła vida vera.",
|
||||
"If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Se A te si a curto de controładori, instała l'apl '${REMOTE_APP_NAME}'\nso i to dispozitivi mòbiłi e dopàrełi cofà controładori.",
|
||||
"If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Se te si a curto de controładori, instała l'apl '${REMOTE_APP_NAME}'\nso i to dispozidivi mòbiłi e dopàrełi cofà controładori.",
|
||||
"If you get a sticky-bomb stuck to you, jump around and spin in circles. You might\nshake the bomb off, or if nothing else your last moments will be entertaining.": "Se na bonba petaisa ła te se taca doso, salta in volta e và torno: ła gavarìa da cavarse.\nE se no funsionase, i to momenti ùltemi de vida i gavarà almanco dà spetàgoło!",
|
||||
"If you kill an enemy in one hit you get double points for it.": "Se A te copi un nemigo co un colpo soło A te ciapi el dupio de i punti.",
|
||||
"If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Se A te ciapi na małedision, A te ghè soło na sparansa de salvesa:\ncatar fora un pacheto sałude inte i puchi segondi che A te resta.",
|
||||
"If you stay in one place, you're toast. Run and dodge to survive..": "Se A se stà fermi inte un posto, A se ze friti. Cori e schiva par soravìvar...",
|
||||
"If you've got lots of players coming and going, turn on 'auto-kick-idle-players'\nunder settings in case anyone forgets to leave the game.": "Se A te te cati tanti zugadori che i và e vien, e inte'l cazo che calchedun el se dezménteghe de\nmołar el zugo, ativa ła funsion automàtega 'Para vìa zugadori in sonera' inte łe inpostasion.",
|
||||
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Se'l to dispozitivo el taca scotar o se A te ghè caro sparagnar batarìa,\ncała ła \"Prospetiva\" o ła \"Resołusion\" so Inpostasion > Gràfega",
|
||||
"If you've got lots of players coming and going, turn on 'auto-kick-idle-players'\nunder settings in case anyone forgets to leave the game.": "Se te te cati tanti zugadori che và e vien, e inte'l cazo che calchedun el se dezménteghe de\nmołar el zugo, ativa ła funsion automàtega 'Para fora zugadori in sonera' inte łe inpostasion.",
|
||||
"If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Se'l to dispozidivo el taca scotar o se te ghè caro sparagnar batarìa,\ncała ła \"Prospetiva\" o ła \"Resołusion\" so Inpostasion > Gràfega",
|
||||
"If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "Se el zugo el và a scati, proa całar ła resołusion\no ła prospetiva inte l'inpostasion gràfega.",
|
||||
"In Capture-the-Flag, your own flag must be at your base to score, If the other\nteam is about to score, stealing their flag can be a good way to stop them.": "Par far ponto so 'Brinca ła bandiera', A te ghè da portar ła bandiera fin so ła to\nbaze. Se cheł'altra scuadra ła ze drio far ponto, A te połi fermarla anca robàndogheła.",
|
||||
"In hockey, you'll maintain more speed if you turn gradually.": "Inte l'hockey, voltando gradualmente A te mantien alta ła vełosidà.",
|
||||
|
|
@ -1769,7 +1773,7 @@
|
|||
"randomName3Text": "Teo",
|
||||
"randomName4Text": "Cesco",
|
||||
"randomName5Text": "Stè",
|
||||
"skipConfirmText": "Vutu dalvero saltar ła demostrasion? Toca o struca par confermar.",
|
||||
"skipConfirmText": "Vutu dabon saltar ła demostrasion? Toca o struca par confermar.",
|
||||
"skipVoteCountText": "Voti par saltar ła demostrasion: ${COUNT}/${TOTAL}",
|
||||
"skippingText": "demostrasion saltada...",
|
||||
"toSkipPressAnythingText": "(toca o struca un boton par saltar ła demostrasion)"
|
||||
|
|
@ -1787,7 +1791,7 @@
|
|||
"upgradeText": "Mejora",
|
||||
"upgradeToPlayText": "Par zugarghe, dezbloca \"${PRO}\" inte ła botega.",
|
||||
"useDefaultText": "Reinposta",
|
||||
"usesExternalControllerText": "'Sto zugo el dòpara un controłador esterno cofà dispozitivo de entrada.",
|
||||
"usesExternalControllerText": "'Sto zugo el dòpara un controłador esterno cofà dispozidivo de entrada.",
|
||||
"usingItunesText": "Doparar l'apl de mùzega par el son de fondo...",
|
||||
"validatingTestBuildText": "Confermasion varsion de proa...",
|
||||
"victoryText": "Vitoria!",
|
||||
|
|
@ -1832,21 +1836,23 @@
|
|||
"wiimoteSetupWindow": {
|
||||
"copyrightText": "Deriti d'autor DarwiinRemote",
|
||||
"listenText": "Scolta",
|
||||
"macInstructionsText": "Segùrate che ła to Wii ła sipie stuada e el bluetooth de'l\nto Mac ativà, donca stuca so 'Scolta'. Ła conpatibiłidà co'l\nWiimote ła podarìa èsar un fià inserta, donca te podarisi\ncatarte a proar pì 'olte prima de otegner na conesion.\n\nEl bluetooth el gavarìa da suportar fin a 7 dispozitivi conetesti,\nanca se ła capasidà ła podarìa variar.\n\nBombSquad el suporta el controłador Clàsego e i controładori\norijinałi Wiimotes, Nunchuks.\nAnca el novo Wii Remote Plus el funsiona\nma soło sensa acesori.",
|
||||
"macInstructionsText": "Segùrate che ła to Wii ła sipie stuada e el bluetooth de'l\nto Mac ativà, donca stuca so 'Scolta'. Ła conpatibiłidà co'l\nWiimote ła podarìa èsar un fià inserta, donca te podarisi\ncatarte a proar pì 'olte prima de otegner na conesion.\n\nEl bluetooth el gavarìa da suportar fin a 7 dispozidivi conetesti,\nanca se ła capasidà ła podarìa variar.\n\nBombSquad el suporta el controłador Clàsego e i controładori\norijinałi Wiimotes, Nunchuks.\nAnca el novo Wii Remote Plus el funsiona\nma soło sensa acesori.",
|
||||
"thanksText": "Grasie a ła scuadra DarwiinRemote\npar verlo rendesto posìbiłe.",
|
||||
"titleText": "Configurasion Wiimote"
|
||||
},
|
||||
"winsPlayerText": "Vitoria de ${NAME}!",
|
||||
"winsTeamText": "Vitoria de i ${NAME}!",
|
||||
"winsText": "Vitoria de ${NAME}!",
|
||||
"workspaceSyncErrorText": "Eror de sincronizasion de ${WORKSPACE}. Varda el rejistro eventi par i detaji.",
|
||||
"workspaceSyncReuseText": "Inposìbiłe sinconizar ${WORKSPACE}. Dòparo de ła varsion sincronizada presedente.",
|
||||
"worldScoresUnavailableText": "Punteji mondiałi miga disponìbiłi.",
|
||||
"worldsBestScoresText": "I punteji mejo de'l mondo",
|
||||
"worldsBestTimesText": "I tenpi mejo de'l mondo",
|
||||
"xbox360ControllersWindow": {
|
||||
"getDriverText": "Descarga el driver",
|
||||
"macInstructions2Text": "Par doparar sensa fiło i controładori, A te serve anca el resevidor\nche'l riva co l''Xbox 360 Wireless Controller par Windows'.\nUn resevidor el te parmete de conétar fin a 4 controładori.\n\nInportante: i resevidori de terse parti no i funsionarà mìa co 'sto driver;\nsegùrate che'l to resevidor el sipia 'Microsoft' e miga 'XBOX 360'.\nŁa Microsoft no łi vende pì destacài, donca A te servirà par forsa cheło\nvendesto insebre co'l controłador, o senò, proa sercar so Ebay.\n\nSe A te cati ùtiłe el driver, ciapa in considerasion de farghe na\ndonasion a'l só dezviłupador so 'sto sito.",
|
||||
"macInstructions2Text": "Par doparar sensa fiło i controładori, A te serve anca el resevidor\nche'l riva co l''Xbox 360 Wireless Controller par Windows'.\nUn resevidor el te parmete de conétar fin a 4 controładori.\n\nInportante: i resevidori de terse parti no i funsionarà miga co 'sto driver;\nsegùrate che'l to resevidor el sipia 'Microsoft' e miga 'XBOX 360'.\nŁa Microsoft no łi vende pì destacài, donca te servirà par forsa cheło\nvendesto insebre co'l controłador, o senò, proa sercar so Ebay.\n\nSe te cati ùtiłe el driver, ciapa in considerasion de farghe na\ndonasion a'l só dezviłupador so 'sto sito.",
|
||||
"macInstructionsText": "Per doparar i controładori co'l fiło de ła Xbox 360, A te ghè\nda instałar el driver Mac disponìbiłe so'l link cuà soto.\nEl funsiona co anbo i controładori, co'l fiło o sensa.",
|
||||
"ouyaInstructionsText": "Par doparar so Bombsquad un controłador de l'Xbox 360 co'l fiło,\ntàcheło sù inte ła porta USB de’l to dispozitivo. A te połi anca\ntacar sù pì controładori insenbre doparando un hub USB.\n\nPar doparar i controładori sensa fiło invese, A te serve un resevidor\nde segnałe. A te połi catarlo, o rento ła scàtoła \"Controładori sensa fiło\nXbox 360 par Windows\", o vendesto a parte. Caun resevidor el và tacà so\nna porta USB e el te parmete de conétar fin a 4 controładori.",
|
||||
"ouyaInstructionsText": "Par doparar so Bombsquad un controłador de l'Xbox 360 co'l fiło,\ntàcheło sù inte ła porta USB de’l to dispozidivo. Te połi anca\ntacar sù pì controładori insenbre doparando un hub USB.\n\nPar doparar i controładori sensa fiło invese, te serve un resevidor\nde segnałe. Te połi catarlo, o rento ła scàtoła \"Controładori sensa fiło\nXbox 360 par Windows\", o vendesto a parte. Caun resevidor el và tacà so\nna porta USB e el te parmete de conétar fin a 4 controładori.",
|
||||
"titleText": "Doparar un controłador Xbox 360 co ${APP_NAME}:"
|
||||
},
|
||||
"yesAllowText": "Sì, parmeti!",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from .core import contents, where
|
||||
|
||||
__all__ = ["contents", "where"]
|
||||
__version__ = "2022.05.18.1"
|
||||
__version__ = "2022.06.15"
|
||||
|
|
|
|||
221
dist/ba_data/python-site-packages/certifi/cacert.pem
vendored
221
dist/ba_data/python-site-packages/certifi/cacert.pem
vendored
|
|
@ -1362,39 +1362,6 @@ Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl
|
|||
nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority
|
||||
# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority
|
||||
# Label: "Hellenic Academic and Research Institutions RootCA 2011"
|
||||
# Serial: 0
|
||||
# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9
|
||||
# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d
|
||||
# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix
|
||||
RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
|
||||
dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p
|
||||
YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw
|
||||
NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK
|
||||
EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl
|
||||
cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
|
||||
c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB
|
||||
BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz
|
||||
dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ
|
||||
fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns
|
||||
bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD
|
||||
75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP
|
||||
FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV
|
||||
HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp
|
||||
5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu
|
||||
b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA
|
||||
A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p
|
||||
6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
|
||||
TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7
|
||||
dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys
|
||||
Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI
|
||||
l7WdmplNsDz4SgCbZN2fOUvRJ9e4
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967
|
||||
# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967
|
||||
# Label: "Actalis Authentication Root CA"
|
||||
|
|
@ -4528,3 +4495,191 @@ PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA
|
|||
y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb
|
||||
gfM0agPnIjhQW+0ZT0MW
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc.
|
||||
# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc.
|
||||
# Label: "DigiCert TLS ECC P384 Root G5"
|
||||
# Serial: 13129116028163249804115411775095713523
|
||||
# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed
|
||||
# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee
|
||||
# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw
|
||||
CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp
|
||||
Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2
|
||||
MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
|
||||
bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG
|
||||
ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS
|
||||
7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp
|
||||
0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS
|
||||
B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
|
||||
BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ
|
||||
LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4
|
||||
DXZDjC5Ty3zfDBeWUA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc.
|
||||
# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc.
|
||||
# Label: "DigiCert TLS RSA4096 Root G5"
|
||||
# Serial: 11930366277458970227240571539258396554
|
||||
# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1
|
||||
# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35
|
||||
# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN
|
||||
MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT
|
||||
HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN
|
||||
NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
|
||||
IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi
|
||||
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+
|
||||
ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0
|
||||
2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp
|
||||
wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM
|
||||
pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD
|
||||
nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po
|
||||
sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx
|
||||
Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd
|
||||
Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX
|
||||
KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe
|
||||
XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL
|
||||
tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv
|
||||
TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
|
||||
AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
|
||||
GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H
|
||||
PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF
|
||||
O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ
|
||||
REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik
|
||||
AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv
|
||||
/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+
|
||||
p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw
|
||||
MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF
|
||||
qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK
|
||||
ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Certainly Root R1 O=Certainly
|
||||
# Subject: CN=Certainly Root R1 O=Certainly
|
||||
# Label: "Certainly Root R1"
|
||||
# Serial: 188833316161142517227353805653483829216
|
||||
# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12
|
||||
# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af
|
||||
# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw
|
||||
PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy
|
||||
dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9
|
||||
MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0
|
||||
YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2
|
||||
1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT
|
||||
vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed
|
||||
aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0
|
||||
1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5
|
||||
r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5
|
||||
cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ
|
||||
wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ
|
||||
6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA
|
||||
2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH
|
||||
Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR
|
||||
eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB
|
||||
/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u
|
||||
d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr
|
||||
PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
|
||||
8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi
|
||||
1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd
|
||||
rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di
|
||||
taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7
|
||||
lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj
|
||||
yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn
|
||||
Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy
|
||||
yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n
|
||||
wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6
|
||||
OV+KmalBWQewLK8=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Certainly Root E1 O=Certainly
|
||||
# Subject: CN=Certainly Root E1 O=Certainly
|
||||
# Label: "Certainly Root E1"
|
||||
# Serial: 8168531406727139161245376702891150584
|
||||
# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9
|
||||
# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b
|
||||
# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw
|
||||
CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu
|
||||
bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ
|
||||
BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s
|
||||
eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK
|
||||
+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2
|
||||
QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E
|
||||
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4
|
||||
hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm
|
||||
ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG
|
||||
BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=E-Tugra Global Root CA RSA v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center
|
||||
# Subject: CN=E-Tugra Global Root CA RSA v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center
|
||||
# Label: "E-Tugra Global Root CA RSA v3"
|
||||
# Serial: 75951268308633135324246244059508261641472512052
|
||||
# MD5 Fingerprint: 22:be:10:f6:c2:f8:03:88:73:5f:33:29:47:28:47:a4
|
||||
# SHA1 Fingerprint: e9:a8:5d:22:14:52:1c:5b:aa:0a:b4:be:24:6a:23:8a:c9:ba:e2:a9
|
||||
# SHA256 Fingerprint: ef:66:b0:b1:0a:3c:db:9f:2e:36:48:c7:6b:d2:af:18:ea:d2:bf:e6:f1:17:65:5e:28:c4:06:0d:a1:a3:f4:c2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF8zCCA9ugAwIBAgIUDU3FzRYilZYIfrgLfxUGNPt5EDQwDQYJKoZIhvcNAQEL
|
||||
BQAwgYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUt
|
||||
VHVncmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYw
|
||||
JAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIFJTQSB2MzAeFw0yMDAzMTgw
|
||||
OTA3MTdaFw00NTAzMTIwOTA3MTdaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMG
|
||||
QW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1
|
||||
Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBD
|
||||
QSBSU0EgdjMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiZvCJt3J7
|
||||
7gnJY9LTQ91ew6aEOErxjYG7FL1H6EAX8z3DeEVypi6Q3po61CBxyryfHUuXCscx
|
||||
uj7X/iWpKo429NEvx7epXTPcMHD4QGxLsqYxYdE0PD0xesevxKenhOGXpOhL9hd8
|
||||
7jwH7eKKV9y2+/hDJVDqJ4GohryPUkqWOmAalrv9c/SF/YP9f4RtNGx/ardLAQO/
|
||||
rWm31zLZ9Vdq6YaCPqVmMbMWPcLzJmAy01IesGykNz709a/r4d+ABs8qQedmCeFL
|
||||
l+d3vSFtKbZnwy1+7dZ5ZdHPOrbRsV5WYVB6Ws5OUDGAA5hH5+QYfERaxqSzO8bG
|
||||
wzrwbMOLyKSRBfP12baqBqG3q+Sx6iEUXIOk/P+2UNOMEiaZdnDpwA+mdPy70Bt4
|
||||
znKS4iicvObpCdg604nmvi533wEKb5b25Y08TVJ2Glbhc34XrD2tbKNSEhhw5oBO
|
||||
M/J+JjKsBY04pOZ2PJ8QaQ5tndLBeSBrW88zjdGUdjXnXVXHt6woq0bM5zshtQoK
|
||||
5EpZ3IE1S0SVEgpnpaH/WwAH0sDM+T/8nzPyAPiMbIedBi3x7+PmBvrFZhNb/FAH
|
||||
nnGGstpvdDDPk1Po3CLW3iAfYY2jLqN4MpBs3KwytQXk9TwzDdbgh3cXTJ2w2Amo
|
||||
DVf3RIXwyAS+XF1a4xeOVGNpf0l0ZAWMowIDAQABo2MwYTAPBgNVHRMBAf8EBTAD
|
||||
AQH/MB8GA1UdIwQYMBaAFLK0ruYt9ybVqnUtdkvAG1Mh0EjvMB0GA1UdDgQWBBSy
|
||||
tK7mLfcm1ap1LXZLwBtTIdBI7zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEL
|
||||
BQADggIBAImocn+M684uGMQQgC0QDP/7FM0E4BQ8Tpr7nym/Ip5XuYJzEmMmtcyQ
|
||||
6dIqKe6cLcwsmb5FJ+Sxce3kOJUxQfJ9emN438o2Fi+CiJ+8EUdPdk3ILY7r3y18
|
||||
Tjvarvbj2l0Upq7ohUSdBm6O++96SmotKygY/r+QLHUWnw/qln0F7psTpURs+APQ
|
||||
3SPh/QMSEgj0GDSz4DcLdxEBSL9htLX4GdnLTeqjjO/98Aa1bZL0SmFQhO3sSdPk
|
||||
vmjmLuMxC1QLGpLWgti2omU8ZgT5Vdps+9u1FGZNlIM7zR6mK7L+d0CGq+ffCsn9
|
||||
9t2HVhjYsCxVYJb6CH5SkPVLpi6HfMsg2wY+oF0Dd32iPBMbKaITVaA9FCKvb7jQ
|
||||
mhty3QUBjYZgv6Rn7rWlDdF/5horYmbDB7rnoEgcOMPpRfunf/ztAmgayncSd6YA
|
||||
VSgU7NbHEqIbZULpkejLPoeJVF3Zr52XnGnnCv8PWniLYypMfUeUP95L6VPQMPHF
|
||||
9p5J3zugkaOj/s1YzOrfr28oO6Bpm4/srK4rVJ2bBLFHIK+WEj5jlB0E5y67hscM
|
||||
moi/dkfv97ALl2bSRM9gUgfh1SxKOidhd8rXj+eHDjD/DLsE4mHDosiXYY60MGo8
|
||||
bcIHX0pzLz/5FooBZu+6kcpSV3uu1OYP3Qt6f4ueJiDPO++BcYNZ
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=E-Tugra Global Root CA ECC v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center
|
||||
# Subject: CN=E-Tugra Global Root CA ECC v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center
|
||||
# Label: "E-Tugra Global Root CA ECC v3"
|
||||
# Serial: 218504919822255052842371958738296604628416471745
|
||||
# MD5 Fingerprint: 46:bc:81:bb:f1:b5:1e:f7:4b:96:bc:14:e2:e7:27:64
|
||||
# SHA1 Fingerprint: 8a:2f:af:57:53:b1:b0:e6:a1:04:ec:5b:6a:69:71:6d:f6:1c:e2:84
|
||||
# SHA256 Fingerprint: 87:3f:46:85:fa:7f:56:36:25:25:2e:6d:36:bc:d7:f1:6f:c2:49:51:f2:64:e4:7e:1b:95:4f:49:08:cd:ca:13
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMw
|
||||
gYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVn
|
||||
cmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYD
|
||||
VQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIEVDQyB2MzAeFw0yMDAzMTgwOTQ2
|
||||
NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMGQW5r
|
||||
YXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1Z3Jh
|
||||
IFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBF
|
||||
Q0MgdjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQ
|
||||
KczLWYHMjLiSF4mDKpL2w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YK
|
||||
fWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMB
|
||||
Af8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQzPUwHQYDVR0OBBYEFP+C
|
||||
MXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNp
|
||||
ADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/6
|
||||
7W4WAie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFx
|
||||
vmjkI6TZraE3
|
||||
-----END CERTIFICATE-----
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ __all__ = [
|
|||
'Counter',
|
||||
'Deque',
|
||||
'DefaultDict',
|
||||
'NamedTuple',
|
||||
'OrderedDict',
|
||||
'TypedDict',
|
||||
|
||||
|
|
@ -380,6 +381,46 @@ def _is_callable_members_only(cls):
|
|||
return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls))
|
||||
|
||||
|
||||
def _maybe_adjust_parameters(cls):
|
||||
"""Helper function used in Protocol.__init_subclass__ and _TypedDictMeta.__new__.
|
||||
|
||||
The contents of this function are very similar
|
||||
to logic found in typing.Generic.__init_subclass__
|
||||
on the CPython main branch.
|
||||
"""
|
||||
tvars = []
|
||||
if '__orig_bases__' in cls.__dict__:
|
||||
tvars = typing._collect_type_vars(cls.__orig_bases__)
|
||||
# Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn].
|
||||
# If found, tvars must be a subset of it.
|
||||
# If not found, tvars is it.
|
||||
# Also check for and reject plain Generic,
|
||||
# and reject multiple Generic[...] and/or Protocol[...].
|
||||
gvars = None
|
||||
for base in cls.__orig_bases__:
|
||||
if (isinstance(base, typing._GenericAlias) and
|
||||
base.__origin__ in (typing.Generic, Protocol)):
|
||||
# for error messages
|
||||
the_base = base.__origin__.__name__
|
||||
if gvars is not None:
|
||||
raise TypeError(
|
||||
"Cannot inherit from Generic[...]"
|
||||
" and/or Protocol[...] multiple types.")
|
||||
gvars = base.__parameters__
|
||||
if gvars is None:
|
||||
gvars = tvars
|
||||
else:
|
||||
tvarset = set(tvars)
|
||||
gvarset = set(gvars)
|
||||
if not tvarset <= gvarset:
|
||||
s_vars = ', '.join(str(t) for t in tvars if t not in gvarset)
|
||||
s_args = ', '.join(str(g) for g in gvars)
|
||||
raise TypeError(f"Some type variables ({s_vars}) are"
|
||||
f" not listed in {the_base}[{s_args}]")
|
||||
tvars = gvars
|
||||
cls.__parameters__ = tuple(tvars)
|
||||
|
||||
|
||||
# 3.8+
|
||||
if hasattr(typing, 'Protocol'):
|
||||
Protocol = typing.Protocol
|
||||
|
|
@ -476,43 +517,13 @@ else:
|
|||
return typing._GenericAlias(cls, params)
|
||||
|
||||
def __init_subclass__(cls, *args, **kwargs):
|
||||
tvars = []
|
||||
if '__orig_bases__' in cls.__dict__:
|
||||
error = typing.Generic in cls.__orig_bases__
|
||||
else:
|
||||
error = typing.Generic in cls.__bases__
|
||||
if error:
|
||||
raise TypeError("Cannot inherit from plain Generic")
|
||||
if '__orig_bases__' in cls.__dict__:
|
||||
tvars = typing._collect_type_vars(cls.__orig_bases__)
|
||||
# Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn].
|
||||
# If found, tvars must be a subset of it.
|
||||
# If not found, tvars is it.
|
||||
# Also check for and reject plain Generic,
|
||||
# and reject multiple Generic[...] and/or Protocol[...].
|
||||
gvars = None
|
||||
for base in cls.__orig_bases__:
|
||||
if (isinstance(base, typing._GenericAlias) and
|
||||
base.__origin__ in (typing.Generic, Protocol)):
|
||||
# for error messages
|
||||
the_base = base.__origin__.__name__
|
||||
if gvars is not None:
|
||||
raise TypeError(
|
||||
"Cannot inherit from Generic[...]"
|
||||
" and/or Protocol[...] multiple types.")
|
||||
gvars = base.__parameters__
|
||||
if gvars is None:
|
||||
gvars = tvars
|
||||
else:
|
||||
tvarset = set(tvars)
|
||||
gvarset = set(gvars)
|
||||
if not tvarset <= gvarset:
|
||||
s_vars = ', '.join(str(t) for t in tvars if t not in gvarset)
|
||||
s_args = ', '.join(str(g) for g in gvars)
|
||||
raise TypeError(f"Some type variables ({s_vars}) are"
|
||||
f" not listed in {the_base}[{s_args}]")
|
||||
tvars = gvars
|
||||
cls.__parameters__ = tuple(tvars)
|
||||
_maybe_adjust_parameters(cls)
|
||||
|
||||
# Determine if this is a protocol or a concrete subclass.
|
||||
if not cls.__dict__.get('_is_protocol', None):
|
||||
|
|
@ -613,6 +624,7 @@ if hasattr(typing, "Required"):
|
|||
# keyword with old-style TypedDict(). See https://bugs.python.org/issue42059
|
||||
# The standard library TypedDict below Python 3.11 does not store runtime
|
||||
# information about optional and required keys when using Required or NotRequired.
|
||||
# Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11.
|
||||
TypedDict = typing.TypedDict
|
||||
_TypedDictMeta = typing._TypedDictMeta
|
||||
is_typeddict = typing.is_typeddict
|
||||
|
|
@ -695,8 +707,16 @@ else:
|
|||
# Subclasses and instances of TypedDict return actual dictionaries
|
||||
# via _dict_new.
|
||||
ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new
|
||||
# Don't insert typing.Generic into __bases__ here,
|
||||
# or Generic.__init_subclass__ will raise TypeError
|
||||
# in the super().__new__() call.
|
||||
# Instead, monkey-patch __bases__ onto the class after it's been created.
|
||||
tp_dict = super().__new__(cls, name, (dict,), ns)
|
||||
|
||||
if any(issubclass(base, typing.Generic) for base in bases):
|
||||
tp_dict.__bases__ = (typing.Generic, dict)
|
||||
_maybe_adjust_parameters(tp_dict)
|
||||
|
||||
annotations = {}
|
||||
own_annotations = ns.get('__annotations__', {})
|
||||
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
|
||||
|
|
@ -1958,3 +1978,92 @@ else:
|
|||
if not hasattr(typing, "TypeVarTuple"):
|
||||
typing._collect_type_vars = _collect_type_vars
|
||||
typing._check_generic = _check_generic
|
||||
|
||||
|
||||
# Backport typing.NamedTuple as it exists in Python 3.11.
|
||||
# In 3.11, the ability to define generic `NamedTuple`s was supported.
|
||||
# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8.
|
||||
if sys.version_info >= (3, 11):
|
||||
NamedTuple = typing.NamedTuple
|
||||
else:
|
||||
def _caller():
|
||||
try:
|
||||
return sys._getframe(2).f_globals.get('__name__', '__main__')
|
||||
except (AttributeError, ValueError): # For platforms without _getframe()
|
||||
return None
|
||||
|
||||
def _make_nmtuple(name, types, module, defaults=()):
|
||||
fields = [n for n, t in types]
|
||||
annotations = {n: typing._type_check(t, f"field {n} annotation must be a type")
|
||||
for n, t in types}
|
||||
nm_tpl = collections.namedtuple(name, fields,
|
||||
defaults=defaults, module=module)
|
||||
nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations
|
||||
# The `_field_types` attribute was removed in 3.9;
|
||||
# in earlier versions, it is the same as the `__annotations__` attribute
|
||||
if sys.version_info < (3, 9):
|
||||
nm_tpl._field_types = annotations
|
||||
return nm_tpl
|
||||
|
||||
_prohibited_namedtuple_fields = typing._prohibited
|
||||
_special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'})
|
||||
|
||||
class _NamedTupleMeta(type):
|
||||
def __new__(cls, typename, bases, ns):
|
||||
assert _NamedTuple in bases
|
||||
for base in bases:
|
||||
if base is not _NamedTuple and base is not typing.Generic:
|
||||
raise TypeError(
|
||||
'can only inherit from a NamedTuple type and Generic')
|
||||
bases = tuple(tuple if base is _NamedTuple else base for base in bases)
|
||||
types = ns.get('__annotations__', {})
|
||||
default_names = []
|
||||
for field_name in types:
|
||||
if field_name in ns:
|
||||
default_names.append(field_name)
|
||||
elif default_names:
|
||||
raise TypeError(f"Non-default namedtuple field {field_name} "
|
||||
f"cannot follow default field"
|
||||
f"{'s' if len(default_names) > 1 else ''} "
|
||||
f"{', '.join(default_names)}")
|
||||
nm_tpl = _make_nmtuple(
|
||||
typename, types.items(),
|
||||
defaults=[ns[n] for n in default_names],
|
||||
module=ns['__module__']
|
||||
)
|
||||
nm_tpl.__bases__ = bases
|
||||
if typing.Generic in bases:
|
||||
class_getitem = typing.Generic.__class_getitem__.__func__
|
||||
nm_tpl.__class_getitem__ = classmethod(class_getitem)
|
||||
# update from user namespace without overriding special namedtuple attributes
|
||||
for key in ns:
|
||||
if key in _prohibited_namedtuple_fields:
|
||||
raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
|
||||
elif key not in _special_namedtuple_fields and key not in nm_tpl._fields:
|
||||
setattr(nm_tpl, key, ns[key])
|
||||
if typing.Generic in bases:
|
||||
nm_tpl.__init_subclass__()
|
||||
return nm_tpl
|
||||
|
||||
def NamedTuple(__typename, __fields=None, **kwargs):
|
||||
if __fields is None:
|
||||
__fields = kwargs.items()
|
||||
elif kwargs:
|
||||
raise TypeError("Either list of fields or keywords"
|
||||
" can be provided to NamedTuple, not both")
|
||||
return _make_nmtuple(__typename, __fields, module=_caller())
|
||||
|
||||
NamedTuple.__doc__ = typing.NamedTuple.__doc__
|
||||
_NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {})
|
||||
|
||||
# On 3.8+, alter the signature so that it matches typing.NamedTuple.
|
||||
# The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7,
|
||||
# so just leave the signature as it is on 3.7.
|
||||
if sys.version_info >= (3, 8):
|
||||
NamedTuple.__text_signature__ = '(typename, fields=None, /, **kwargs)'
|
||||
|
||||
def _namedtuple_mro_entries(bases):
|
||||
assert NamedTuple in bases
|
||||
return (_NamedTuple,)
|
||||
|
||||
NamedTuple.__mro_entries__ = _namedtuple_mro_entries
|
||||
|
|
|
|||
30
dist/ba_data/python/ba/_app.py
vendored
30
dist/ba_data/python/ba/_app.py
vendored
|
|
@ -29,6 +29,7 @@ if TYPE_CHECKING:
|
|||
from ba._cloud import CloudSubsystem
|
||||
from bastd.actor import spazappearance
|
||||
from ba._accountv2 import AccountV2Subsystem
|
||||
from ba._level import Level
|
||||
|
||||
|
||||
class App:
|
||||
|
|
@ -274,6 +275,7 @@ class App:
|
|||
|
||||
# Co-op Campaigns.
|
||||
self.campaigns: dict[str, ba.Campaign] = {}
|
||||
self.custom_coop_practice_games: list[str] = []
|
||||
|
||||
# Server Mode.
|
||||
self.server: ba.ServerController | None = None
|
||||
|
|
@ -342,6 +344,7 @@ class App:
|
|||
from bastd.actor import spazappearance
|
||||
from ba._generated.enums import TimeType
|
||||
|
||||
|
||||
self._aioloop = _asyncio.setup_asyncio()
|
||||
|
||||
cfg = self.config
|
||||
|
|
@ -432,8 +435,6 @@ class App:
|
|||
|
||||
# from ba._dependency import test_depset
|
||||
# test_depset()
|
||||
if bool(False):
|
||||
self._test_https()
|
||||
|
||||
def _update_state(self) -> None:
|
||||
if self._app_paused:
|
||||
|
|
@ -527,6 +528,15 @@ class App:
|
|||
# FIXME: This should not be an actor attr.
|
||||
activity.paused_text = None
|
||||
|
||||
def add_coop_practice_level(self, level: Level) -> None:
|
||||
"""Adds an individual level to the 'practice' section in Co-op."""
|
||||
|
||||
# Assign this level to our catch-all campaign.
|
||||
self.campaigns['Challenges'].addlevel(level)
|
||||
|
||||
# Make note to add it to our challenges UI.
|
||||
self.custom_coop_practice_games.append(f'Challenges:{level.name}')
|
||||
|
||||
def return_to_main_menu_session_gracefully(self,
|
||||
reset_ui: bool = True) -> None:
|
||||
"""Attempt to cleanly get back to the main menu."""
|
||||
|
|
@ -643,19 +653,3 @@ class App:
|
|||
"""
|
||||
self._initial_login_completed = True
|
||||
self._update_state()
|
||||
|
||||
def _test_https(self) -> None:
|
||||
"""Testing https support.
|
||||
|
||||
(would be nice to get this working on our custom Python builds; need
|
||||
to wrangle certificates somehow).
|
||||
"""
|
||||
import urllib.request
|
||||
try:
|
||||
with urllib.request.urlopen('https://example.com') as url:
|
||||
val = url.read()
|
||||
_ba.screenmessage('HTTPS SUCCESS!')
|
||||
print('HTTPS TEST SUCCESS', len(val))
|
||||
except Exception as exc:
|
||||
_ba.screenmessage('HTTPS FAIL.')
|
||||
print('HTTPS TEST FAIL:', exc)
|
||||
|
|
|
|||
6
dist/ba_data/python/ba/_assetmanager.py
vendored
6
dist/ba_data/python/ba/_assetmanager.py
vendored
|
|
@ -17,6 +17,7 @@ import sys
|
|||
|
||||
from efro.dataclassio import (ioprepped, IOAttrs, dataclass_from_json,
|
||||
dataclass_to_json)
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bacommon.assets import AssetPackageFlavor
|
||||
|
|
@ -165,7 +166,6 @@ def fetch_url(url: str, filename: Path, asset_gather: AssetGather) -> None:
|
|||
|
||||
"""
|
||||
# pylint: disable=consider-using-with
|
||||
|
||||
import socket
|
||||
|
||||
# We don't want to keep the provided AssetGather alive, but we want
|
||||
|
|
@ -175,7 +175,9 @@ def fetch_url(url: str, filename: Path, asset_gather: AssetGather) -> None:
|
|||
|
||||
# Pass a very short timeout to urllib so we have opportunities
|
||||
# to cancel even with network blockage.
|
||||
req = urllib.request.urlopen(url, timeout=1)
|
||||
req = urllib.request.urlopen(url,
|
||||
context=_ba.app.net.sslcontext,
|
||||
timeout=1)
|
||||
file_size = int(req.headers['Content-Length'])
|
||||
print(f'\nDownloading: {filename} Bytes: {file_size:,}')
|
||||
|
||||
|
|
|
|||
16
dist/ba_data/python/ba/_asyncio.py
vendored
16
dist/ba_data/python/ba/_asyncio.py
vendored
|
|
@ -11,6 +11,9 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
import os
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import ba
|
||||
|
|
@ -19,6 +22,8 @@ if TYPE_CHECKING:
|
|||
_asyncio_timer: ba.Timer | None = None
|
||||
_asyncio_event_loop: asyncio.AbstractEventLoop | None = None
|
||||
|
||||
DEBUG_TIMING = os.environ.get('BA_DEBUG_TIMING') == '1'
|
||||
|
||||
|
||||
def setup_asyncio() -> asyncio.AbstractEventLoop:
|
||||
"""Setup asyncio functionality for the logic thread."""
|
||||
|
|
@ -53,7 +58,18 @@ def setup_asyncio() -> asyncio.AbstractEventLoop:
|
|||
def run_cycle() -> None:
|
||||
assert _asyncio_event_loop is not None
|
||||
_asyncio_event_loop.call_soon(_asyncio_event_loop.stop)
|
||||
starttime = time.monotonic() if DEBUG_TIMING else 0
|
||||
_asyncio_event_loop.run_forever()
|
||||
endtime = time.monotonic() if DEBUG_TIMING else 0
|
||||
|
||||
# Let's aim to have nothing take longer than 1/120 of a second.
|
||||
if DEBUG_TIMING:
|
||||
warn_time = 1.0 / 120
|
||||
duration = endtime - starttime
|
||||
if duration > warn_time:
|
||||
logging.warning(
|
||||
'Asyncio loop step took %.4fs; ideal max is %.4f',
|
||||
duration, warn_time)
|
||||
|
||||
global _asyncio_timer # pylint: disable=invalid-name
|
||||
_asyncio_timer = _ba.Timer(1.0 / 30.0,
|
||||
|
|
|
|||
468
dist/ba_data/python/ba/_campaign.py
vendored
468
dist/ba_data/python/ba/_campaign.py
vendored
|
|
@ -28,10 +28,16 @@ class Campaign:
|
|||
Category: **App Classes**
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, sequential: bool = True):
|
||||
def __init__(self,
|
||||
name: str,
|
||||
sequential: bool = True,
|
||||
levels: list[ba.Level] | None = None):
|
||||
self._name = name
|
||||
self._levels: list[ba.Level] = []
|
||||
self._sequential = sequential
|
||||
self._levels: list[ba.Level] = []
|
||||
if levels is not None:
|
||||
for level in levels:
|
||||
self.addlevel(level)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
|
@ -43,12 +49,15 @@ class Campaign:
|
|||
"""Whether this Campaign's levels must be played in sequence."""
|
||||
return self._sequential
|
||||
|
||||
def addlevel(self, level: ba.Level) -> None:
|
||||
def addlevel(self, level: ba.Level, index: int | None = None) -> None:
|
||||
"""Adds a ba.Level to the Campaign."""
|
||||
if level.campaign is not None:
|
||||
raise RuntimeError('Level already belongs to a campaign.')
|
||||
level.set_campaign(self, len(self._levels))
|
||||
self._levels.append(level)
|
||||
if index is None:
|
||||
self._levels.append(level)
|
||||
else:
|
||||
self._levels.insert(index, level)
|
||||
|
||||
@property
|
||||
def levels(self) -> list[ba.Level]:
|
||||
|
|
@ -91,9 +100,8 @@ class Campaign:
|
|||
|
||||
def init_campaigns() -> None:
|
||||
"""Fill out initial default Campaigns."""
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=cyclic-import
|
||||
from ba import _level
|
||||
from ba._level import Level
|
||||
from bastd.game.onslaught import OnslaughtGame
|
||||
from bastd.game.football import FootballCoopGame
|
||||
from bastd.game.runaround import RunaroundGame
|
||||
|
|
@ -109,244 +117,218 @@ def init_campaigns() -> None:
|
|||
|
||||
# FIXME: Once translations catch up, we can convert these to use the
|
||||
# generic display-name '${GAME} Training' type stuff.
|
||||
campaign = Campaign('Easy')
|
||||
campaign.addlevel(
|
||||
_level.Level('Onslaught Training',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'training_easy'},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Rookie Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'rookie_easy'},
|
||||
preview_texture_name='courtyardPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Rookie Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'rookie_easy'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'pro_easy'},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'pro_easy'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'pro_easy'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'uber_easy'},
|
||||
preview_texture_name='courtyardPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'uber_easy'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'uber_easy'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
register_campaign(campaign)
|
||||
register_campaign(
|
||||
Campaign(
|
||||
'Easy',
|
||||
levels=[
|
||||
Level('Onslaught Training',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'training_easy'},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Rookie Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'rookie_easy'},
|
||||
preview_texture_name='courtyardPreview'),
|
||||
Level('Rookie Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'rookie_easy'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Pro Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'pro_easy'},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Pro Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'pro_easy'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Pro Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'pro_easy'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('Uber Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'uber_easy'},
|
||||
preview_texture_name='courtyardPreview'),
|
||||
Level('Uber Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'uber_easy'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Uber Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'uber_easy'},
|
||||
preview_texture_name='towerDPreview')
|
||||
],
|
||||
))
|
||||
|
||||
# "hard" mode
|
||||
campaign = Campaign('Default')
|
||||
campaign.addlevel(
|
||||
_level.Level('Onslaught Training',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'training'},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Rookie Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'rookie'},
|
||||
preview_texture_name='courtyardPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Rookie Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'rookie'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'uber'},
|
||||
preview_texture_name='courtyardPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'uber'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'uber'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('The Last Stand',
|
||||
gametype=TheLastStandGame,
|
||||
settings={},
|
||||
preview_texture_name='rampagePreview'))
|
||||
register_campaign(campaign)
|
||||
register_campaign(
|
||||
Campaign(
|
||||
'Default',
|
||||
levels=[
|
||||
Level('Onslaught Training',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'training'},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Rookie Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'rookie'},
|
||||
preview_texture_name='courtyardPreview'),
|
||||
Level('Rookie Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'rookie'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Pro Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Pro Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Pro Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('Uber Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'uber'},
|
||||
preview_texture_name='courtyardPreview'),
|
||||
Level('Uber Football',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'uber'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Uber Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'uber'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('The Last Stand',
|
||||
gametype=TheLastStandGame,
|
||||
settings={},
|
||||
preview_texture_name='rampagePreview')
|
||||
],
|
||||
))
|
||||
|
||||
# challenges: our 'official' random extra co-op levels
|
||||
campaign = Campaign('Challenges', sequential=False)
|
||||
campaign.addlevel(
|
||||
_level.Level('Infinite Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'endless'},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Infinite Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'endless'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Race',
|
||||
displayname='${GAME}',
|
||||
gametype=RaceGame,
|
||||
settings={
|
||||
'map': 'Big G',
|
||||
'Laps': 3,
|
||||
'Bomb Spawning': 0
|
||||
},
|
||||
preview_texture_name='bigGPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Race',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=RaceGame,
|
||||
settings={
|
||||
'map': 'Big G',
|
||||
'Laps': 3,
|
||||
'Bomb Spawning': 1000
|
||||
},
|
||||
preview_texture_name='bigGPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Lake Frigid Race',
|
||||
displayname='${GAME}',
|
||||
gametype=RaceGame,
|
||||
settings={
|
||||
'map': 'Lake Frigid',
|
||||
'Laps': 6,
|
||||
'Mine Spawning': 2000,
|
||||
'Bomb Spawning': 0
|
||||
},
|
||||
preview_texture_name='lakeFrigidPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Football',
|
||||
displayname='${GAME}',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'tournament'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Football',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'tournament_pro'},
|
||||
preview_texture_name='footballStadiumPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Runaround',
|
||||
displayname='${GAME}',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'tournament'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Uber Runaround',
|
||||
displayname='Uber ${GAME}',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'tournament_uber'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('The Last Stand',
|
||||
displayname='${GAME}',
|
||||
gametype=TheLastStandGame,
|
||||
settings={'preset': 'tournament'},
|
||||
preview_texture_name='rampagePreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Tournament Infinite Onslaught',
|
||||
displayname='Infinite Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'endless_tournament'},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Tournament Infinite Runaround',
|
||||
displayname='Infinite Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'endless_tournament'},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Target Practice',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=TargetPracticeGame,
|
||||
settings={},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Target Practice B',
|
||||
displayname='${GAME}',
|
||||
gametype=TargetPracticeGame,
|
||||
settings={
|
||||
'Target Count': 2,
|
||||
'Enable Impact Bombs': False,
|
||||
'Enable Triple Bombs': False
|
||||
},
|
||||
preview_texture_name='doomShroomPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Meteor Shower',
|
||||
displayname='${GAME}',
|
||||
gametype=MeteorShowerGame,
|
||||
settings={},
|
||||
preview_texture_name='rampagePreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Epic Meteor Shower',
|
||||
displayname='${GAME}',
|
||||
gametype=MeteorShowerGame,
|
||||
settings={'Epic Mode': True},
|
||||
preview_texture_name='rampagePreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Easter Egg Hunt',
|
||||
displayname='${GAME}',
|
||||
gametype=EasterEggHuntGame,
|
||||
settings={},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level('Pro Easter Egg Hunt',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=EasterEggHuntGame,
|
||||
settings={'Pro Mode': True},
|
||||
preview_texture_name='towerDPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level(
|
||||
name='Ninja Fight', # (unique id not seen by player)
|
||||
displayname='${GAME}', # (readable name seen by player)
|
||||
gametype=NinjaFightGame,
|
||||
settings={'preset': 'regular'},
|
||||
preview_texture_name='courtyardPreview'))
|
||||
campaign.addlevel(
|
||||
_level.Level(name='Pro Ninja Fight',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=NinjaFightGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='courtyardPreview'))
|
||||
register_campaign(campaign)
|
||||
register_campaign(
|
||||
Campaign(
|
||||
'Challenges',
|
||||
sequential=False,
|
||||
levels=[
|
||||
Level('Infinite Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'endless'},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Infinite Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'endless'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('Race',
|
||||
displayname='${GAME}',
|
||||
gametype=RaceGame,
|
||||
settings={
|
||||
'map': 'Big G',
|
||||
'Laps': 3,
|
||||
'Bomb Spawning': 0
|
||||
},
|
||||
preview_texture_name='bigGPreview'),
|
||||
Level('Pro Race',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=RaceGame,
|
||||
settings={
|
||||
'map': 'Big G',
|
||||
'Laps': 3,
|
||||
'Bomb Spawning': 1000
|
||||
},
|
||||
preview_texture_name='bigGPreview'),
|
||||
Level('Lake Frigid Race',
|
||||
displayname='${GAME}',
|
||||
gametype=RaceGame,
|
||||
settings={
|
||||
'map': 'Lake Frigid',
|
||||
'Laps': 6,
|
||||
'Mine Spawning': 2000,
|
||||
'Bomb Spawning': 0
|
||||
},
|
||||
preview_texture_name='lakeFrigidPreview'),
|
||||
Level('Football',
|
||||
displayname='${GAME}',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'tournament'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Pro Football',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=FootballCoopGame,
|
||||
settings={'preset': 'tournament_pro'},
|
||||
preview_texture_name='footballStadiumPreview'),
|
||||
Level('Runaround',
|
||||
displayname='${GAME}',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'tournament'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('Uber Runaround',
|
||||
displayname='Uber ${GAME}',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'tournament_uber'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('The Last Stand',
|
||||
displayname='${GAME}',
|
||||
gametype=TheLastStandGame,
|
||||
settings={'preset': 'tournament'},
|
||||
preview_texture_name='rampagePreview'),
|
||||
Level('Tournament Infinite Onslaught',
|
||||
displayname='Infinite Onslaught',
|
||||
gametype=OnslaughtGame,
|
||||
settings={'preset': 'endless_tournament'},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Tournament Infinite Runaround',
|
||||
displayname='Infinite Runaround',
|
||||
gametype=RunaroundGame,
|
||||
settings={'preset': 'endless_tournament'},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('Target Practice',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=TargetPracticeGame,
|
||||
settings={},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Target Practice B',
|
||||
displayname='${GAME}',
|
||||
gametype=TargetPracticeGame,
|
||||
settings={
|
||||
'Target Count': 2,
|
||||
'Enable Impact Bombs': False,
|
||||
'Enable Triple Bombs': False
|
||||
},
|
||||
preview_texture_name='doomShroomPreview'),
|
||||
Level('Meteor Shower',
|
||||
displayname='${GAME}',
|
||||
gametype=MeteorShowerGame,
|
||||
settings={},
|
||||
preview_texture_name='rampagePreview'),
|
||||
Level('Epic Meteor Shower',
|
||||
displayname='${GAME}',
|
||||
gametype=MeteorShowerGame,
|
||||
settings={'Epic Mode': True},
|
||||
preview_texture_name='rampagePreview'),
|
||||
Level('Easter Egg Hunt',
|
||||
displayname='${GAME}',
|
||||
gametype=EasterEggHuntGame,
|
||||
settings={},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level('Pro Easter Egg Hunt',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=EasterEggHuntGame,
|
||||
settings={'Pro Mode': True},
|
||||
preview_texture_name='towerDPreview'),
|
||||
Level(
|
||||
name='Ninja Fight', # (unique id not seen by player)
|
||||
displayname='${GAME}', # (readable name seen by player)
|
||||
gametype=NinjaFightGame,
|
||||
settings={'preset': 'regular'},
|
||||
preview_texture_name='courtyardPreview'),
|
||||
Level(name='Pro Ninja Fight',
|
||||
displayname='Pro ${GAME}',
|
||||
gametype=NinjaFightGame,
|
||||
settings={'preset': 'pro'},
|
||||
preview_texture_name='courtyardPreview')
|
||||
],
|
||||
))
|
||||
|
|
|
|||
8
dist/ba_data/python/ba/_cloud.py
vendored
8
dist/ba_data/python/ba/_cloud.py
vendored
|
|
@ -56,6 +56,14 @@ class CloudSubsystem:
|
|||
) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.PingMessage,
|
||||
on_response: Callable[[bacommon.cloud.PingResponse | Exception], None],
|
||||
) -> None:
|
||||
...
|
||||
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: Message,
|
||||
|
|
|
|||
6
dist/ba_data/python/ba/_hooks.py
vendored
6
dist/ba_data/python/ba/_hooks.py
vendored
|
|
@ -204,6 +204,12 @@ def no_game_circle_message() -> None:
|
|||
_ba.screenmessage(Lstr(resource='noGameCircleText'), color=(1, 0, 0))
|
||||
|
||||
|
||||
def google_play_purchases_not_available_message() -> None:
|
||||
from ba._language import Lstr
|
||||
_ba.screenmessage(Lstr(resource='googlePlayPurchasesNotAvailableText'),
|
||||
color=(1, 0, 0))
|
||||
|
||||
|
||||
def empty_call() -> None:
|
||||
pass
|
||||
|
||||
|
|
|
|||
20
dist/ba_data/python/ba/_meta.py
vendored
20
dist/ba_data/python/ba/_meta.py
vendored
|
|
@ -44,7 +44,7 @@ class MetadataSubsystem:
|
|||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.metascan: ScanResults | None = None
|
||||
self.scanresults: ScanResults | None = None
|
||||
self.extra_scan_dirs: list[str] = []
|
||||
|
||||
def on_app_running(self) -> None:
|
||||
|
|
@ -58,7 +58,7 @@ class MetadataSubsystem:
|
|||
|
||||
Should be called only once at launch."""
|
||||
app = _ba.app
|
||||
if self.metascan is not None:
|
||||
if self.scanresults is not None:
|
||||
print('WARNING: meta scan run more than once.')
|
||||
pythondirs = ([app.python_directory_app, app.python_directory_user] +
|
||||
self.extra_scan_dirs)
|
||||
|
|
@ -133,7 +133,7 @@ class MetadataSubsystem:
|
|||
|
||||
def get_scan_results(self) -> ScanResults:
|
||||
"""Return meta scan results; block if the scan is not yet complete."""
|
||||
if self.metascan is None:
|
||||
if self.scanresults is None:
|
||||
print('WARNING: ba.meta.get_scan_results()'
|
||||
' called before scan completed.'
|
||||
' This can cause hitches.')
|
||||
|
|
@ -141,12 +141,12 @@ class MetadataSubsystem:
|
|||
# Now wait a bit for the scan to complete.
|
||||
# Eventually error though if it doesn't.
|
||||
starttime = time.time()
|
||||
while self.metascan is None:
|
||||
while self.scanresults is None:
|
||||
time.sleep(0.05)
|
||||
if time.time() - starttime > 10.0:
|
||||
raise TimeoutError(
|
||||
'timeout waiting for meta scan to complete.')
|
||||
return self.metascan
|
||||
return self.scanresults
|
||||
|
||||
def get_game_types(self) -> list[type[ba.GameActivity]]:
|
||||
"""Return available game types."""
|
||||
|
|
@ -206,7 +206,7 @@ class ScanThread(threading.Thread):
|
|||
# We also, however, immediately make results available.
|
||||
# This is because the game thread may be blocked waiting
|
||||
# for them so we can't push a call or we'd get deadlock.
|
||||
_ba.app.meta.metascan = results
|
||||
_ba.app.meta.scanresults = results
|
||||
|
||||
|
||||
class DirectoryScan:
|
||||
|
|
@ -288,7 +288,7 @@ class DirectoryScan:
|
|||
|
||||
# If we find a module requiring a different api version, warn
|
||||
# and ignore.
|
||||
if required_api is not None and required_api < CURRENT_API_VERSION:
|
||||
if required_api is not None and required_api <= CURRENT_API_VERSION:
|
||||
self.results.warnings += (
|
||||
f'Warning: {subpath} requires api {required_api} but'
|
||||
f' we are running {CURRENT_API_VERSION}; ignoring module.\n')
|
||||
|
|
@ -403,13 +403,13 @@ class DirectoryScan:
|
|||
if len(lines) > 1:
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': multiple "# ba_meta api require <NUM>" lines found;'
|
||||
': multiple "# ba_meta require api <NUM>" lines found;'
|
||||
' ignoring module.\n')
|
||||
elif not lines and toplevel and meta_lines:
|
||||
# If we're a top-level module containing meta lines but
|
||||
# no valid api require, complain.
|
||||
# no valid "require api" line found, complain.
|
||||
self.results.warnings += (
|
||||
'Warning: ' + str(subpath) +
|
||||
': no valid "# ba_meta api require <NUM>" line found;'
|
||||
': no valid "# ba_meta require api <NUM>" line found;'
|
||||
' ignoring module.\n')
|
||||
return None
|
||||
|
|
|
|||
2
dist/ba_data/python/ba/_music.py
vendored
2
dist/ba_data/python/ba/_music.py
vendored
|
|
@ -211,7 +211,7 @@ class MusicSubsystem:
|
|||
return 'Mac' in uas
|
||||
if entry_type in ('musicFile', 'musicFolder'):
|
||||
return ('android' in uas
|
||||
and _ba.android_get_external_storage_path() is not None)
|
||||
and _ba.android_get_external_files_dir() is not None)
|
||||
if entry_type == 'default':
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
62
dist/ba_data/python/ba/_net.py
vendored
62
dist/ba_data/python/ba/_net.py
vendored
|
|
@ -3,6 +3,7 @@
|
|||
"""Networking related functionality."""
|
||||
from __future__ import annotations
|
||||
|
||||
import ssl
|
||||
import copy
|
||||
import threading
|
||||
import weakref
|
||||
|
|
@ -29,14 +30,32 @@ class NetworkSubsystem:
|
|||
# as it is updated by a background thread.
|
||||
self.zone_pings_lock = threading.Lock()
|
||||
|
||||
# Region IDs mapped to average pings. This will remain empty
|
||||
# Zone IDs mapped to average pings. This will remain empty
|
||||
# until enough pings have been run to be reasonably certain
|
||||
# that a nearby server has been pinged.
|
||||
self.zone_pings: dict[str, float] = {}
|
||||
|
||||
self._sslcontext: ssl.SSLContext | None = None
|
||||
|
||||
# For debugging.
|
||||
self.v1_test_log: str = ''
|
||||
self.v1_ctest_results: dict[int, str] = {}
|
||||
self.server_time_offset_hours: float | None = None
|
||||
|
||||
@property
|
||||
def sslcontext(self) -> ssl.SSLContext:
|
||||
"""Create/return our shared SSLContext.
|
||||
|
||||
This can be reused for all standard urllib requests/etc.
|
||||
"""
|
||||
# Note: I've run into older Android devices taking upwards of 1 second
|
||||
# to put together a default SSLContext, so recycling one can definitely
|
||||
# be a worthwhile optimization. This was suggested to me in this
|
||||
# thread by one of Python's SSL maintainers:
|
||||
# https://github.com/python/cpython/issues/94637
|
||||
if self._sslcontext is None:
|
||||
self._sslcontext = ssl.create_default_context()
|
||||
return self._sslcontext
|
||||
|
||||
|
||||
def get_ip_address_type(addr: str) -> socket.AddressFamily:
|
||||
|
|
@ -108,30 +127,36 @@ class MasterServerCallThread(threading.Thread):
|
|||
self._callback(arg)
|
||||
|
||||
def run(self) -> None:
|
||||
# pylint: disable=too-many-branches, consider-using-with
|
||||
# pylint: disable=consider-using-with
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
import json
|
||||
|
||||
from efro.error import is_urllib_network_error
|
||||
from efro.error import is_urllib_communication_error
|
||||
from ba import _general
|
||||
|
||||
response_data: Any = None
|
||||
url: str | None = None
|
||||
try:
|
||||
self._data = _general.utf8_all(self._data)
|
||||
_ba.set_thread_name('BA_ServerCallThread')
|
||||
if self._request_type == 'get':
|
||||
url = (_ba.get_master_server_address() + '/' + self._request +
|
||||
'?' + urllib.parse.urlencode(self._data))
|
||||
response = urllib.request.urlopen(
|
||||
urllib.request.Request(
|
||||
(_ba.get_master_server_address() + '/' +
|
||||
self._request + '?' +
|
||||
urllib.parse.urlencode(self._data)), None,
|
||||
{'User-Agent': _ba.app.user_agent_string}),
|
||||
url, None, {'User-Agent': _ba.app.user_agent_string}),
|
||||
context=_ba.app.net.sslcontext,
|
||||
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||||
elif self._request_type == 'post':
|
||||
url = _ba.get_master_server_address() + '/' + self._request
|
||||
response = urllib.request.urlopen(
|
||||
urllib.request.Request(
|
||||
_ba.get_master_server_address() + '/' + self._request,
|
||||
url,
|
||||
urllib.parse.urlencode(self._data).encode(),
|
||||
{'User-Agent': _ba.app.user_agent_string}),
|
||||
context=_ba.app.net.sslcontext,
|
||||
timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS)
|
||||
else:
|
||||
raise TypeError('Invalid request_type: ' + self._request_type)
|
||||
|
|
@ -151,29 +176,18 @@ class MasterServerCallThread(threading.Thread):
|
|||
raise TypeError(f'invalid responsetype: {self._response_type}')
|
||||
|
||||
except Exception as exc:
|
||||
do_print = False
|
||||
response_data = None
|
||||
|
||||
# Ignore common network errors; note unexpected ones.
|
||||
if is_urllib_network_error(exc):
|
||||
pass
|
||||
elif (self._response_type == MasterServerResponseType.JSON
|
||||
and isinstance(exc, json.decoder.JSONDecodeError)):
|
||||
# FIXME: should handle this better; could mean either the
|
||||
# server sent us bad data or it got corrupted along the way.
|
||||
pass
|
||||
else:
|
||||
do_print = True
|
||||
|
||||
if do_print:
|
||||
# Any other error here is unexpected,
|
||||
# so let's make a note of it,
|
||||
if not is_urllib_communication_error(exc, url=url):
|
||||
print(f'Error in MasterServerCallThread'
|
||||
f' (response-type={self._response_type},'
|
||||
f' (url={url},'
|
||||
f' response-type={self._response_type},'
|
||||
f' response-data={response_data}):')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
response_data = None
|
||||
|
||||
if self._callback is not None:
|
||||
_ba.pushcall(_general.Call(self._run_callback, response_data),
|
||||
from_other_thread=True)
|
||||
|
|
|
|||
12
dist/ba_data/python/ba/_plugin.py
vendored
12
dist/ba_data/python/ba/_plugin.py
vendored
|
|
@ -112,13 +112,15 @@ class PluginSubsystem:
|
|||
# or workspaces.
|
||||
if disappeared_plugs:
|
||||
_ba.playsound(_ba.getsound('shieldDown'))
|
||||
_ba.screenmessage(Lstr(resource='pluginsRemovedText',
|
||||
subs=[('${NUM}',
|
||||
str(len(disappeared_plugs)))]),
|
||||
color=(1, 1, 0))
|
||||
_ba.screenmessage(
|
||||
Lstr(resource='pluginsRemovedText',
|
||||
subs=[('${NUM}', str(len(disappeared_plugs)))]),
|
||||
color=(1, 1, 0),
|
||||
)
|
||||
plugnames = ', '.join(disappeared_plugs)
|
||||
_ba.log(
|
||||
f'{len(disappeared_plugs)} plugin(s) no longer found:'
|
||||
f' {disappeared_plugs}',
|
||||
f' {plugnames}.',
|
||||
to_server=False)
|
||||
for goneplug in disappeared_plugs:
|
||||
del _ba.app.config['Plugins'][goneplug]
|
||||
|
|
|
|||
2
dist/ba_data/python/ba/_workspace.py
vendored
2
dist/ba_data/python/ba/_workspace.py
vendored
|
|
@ -115,7 +115,7 @@ class WorkspaceSubsystem:
|
|||
tpartial(
|
||||
self._errmsg,
|
||||
Lstr(resource='workspaceSyncReuseText',
|
||||
subs=[('$WORKSPACE', workspacename)])),
|
||||
subs=[('${WORKSPACE}', workspacename)])),
|
||||
from_other_thread=True,
|
||||
)
|
||||
|
||||
|
|
|
|||
28
dist/ba_data/python/ba/modutils.py
vendored
28
dist/ba_data/python/ba/modutils.py
vendored
|
|
@ -17,23 +17,29 @@ def get_human_readable_user_scripts_path() -> str:
|
|||
|
||||
This is NOT a valid filesystem path; may be something like "(SD Card)".
|
||||
"""
|
||||
from ba import _language
|
||||
app = _ba.app
|
||||
path: str | None = app.python_directory_user
|
||||
if path is None:
|
||||
return '<Not Available>'
|
||||
|
||||
# On newer versions of android, the user's external storage dir is probably
|
||||
# only visible to the user's processes and thus not really useful printed
|
||||
# in its entirety; lets print it as <External Storage>/myfilepath.
|
||||
# These days, on Android, we use getExternalFilesDir() as the base of our
|
||||
# app's user-scripts dir, which gives us paths like:
|
||||
# /storage/emulated/0/Android/data/net.froemling.bombsquad/files
|
||||
# Userspace apps tend to show that as:
|
||||
# Android/data/net.froemling.bombsquad/files
|
||||
# We'd like to display it that way, but I'm not sure if there's a clean
|
||||
# way to get the root of the external storage area (/storage/emulated/0)
|
||||
# so that we could strip it off. There is
|
||||
# Environment.getExternalStorageDirectory() but that is deprecated.
|
||||
# So for now let's just be conservative and trim off recognized prefixes
|
||||
# and show the whole ugly path as a fallback.
|
||||
# Note that we used to use externalStorageText resource but gonna try
|
||||
# without it for now. (simply 'foo' instead of <External Storage>/foo).
|
||||
if app.platform == 'android':
|
||||
ext_storage_path: str | None = (
|
||||
_ba.android_get_external_storage_path())
|
||||
if (ext_storage_path is not None
|
||||
and app.python_directory_user.startswith(ext_storage_path)):
|
||||
path = ('<' +
|
||||
_language.Lstr(resource='externalStorageText').evaluate() +
|
||||
'>' + app.python_directory_user[len(ext_storage_path):])
|
||||
for pre in ['/storage/emulated/0/']:
|
||||
if path.startswith(pre):
|
||||
path = path.removeprefix(pre)
|
||||
break
|
||||
return path
|
||||
|
||||
|
||||
|
|
|
|||
2
dist/ba_data/python/bacommon/bacloud.py
vendored
2
dist/ba_data/python/bacommon/bacloud.py
vendored
|
|
@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
|||
|
||||
# Version is sent to the master-server with all commands. Can be incremented
|
||||
# if we need to change behavior server-side to go along with client changes.
|
||||
BACLOUD_VERSION = 6
|
||||
BACLOUD_VERSION = 7
|
||||
|
||||
|
||||
@ioprepped
|
||||
|
|
|
|||
16
dist/ba_data/python/bacommon/cloud.py
vendored
16
dist/ba_data/python/bacommon/cloud.py
vendored
|
|
@ -76,6 +76,22 @@ class LoginProxyCompleteMessage(Message):
|
|||
proxyid: Annotated[str, IOAttrs('p')]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class PingMessage(Message):
|
||||
"""Standard ping."""
|
||||
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response]]:
|
||||
return [PingResponse]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class PingResponse(Response):
|
||||
"""pong."""
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class TestMessage(Message):
|
||||
|
|
|
|||
4
dist/ba_data/python/bacommon/net.py
vendored
4
dist/ba_data/python/bacommon/net.py
vendored
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING, Any, Annotated
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
|
@ -27,6 +28,9 @@ class ServerNodeEntry:
|
|||
class ServerNodeQueryResponse:
|
||||
"""A response to a query about server-nodes."""
|
||||
|
||||
# The current utc time on the master server.
|
||||
time: Annotated[datetime.datetime, IOAttrs('t')]
|
||||
|
||||
# If present, something went wrong, and this describes it.
|
||||
error: Annotated[str | None, IOAttrs('e', store_default=False)] = None
|
||||
|
||||
|
|
|
|||
23
dist/ba_data/python/bacommon/transfer.py
vendored
23
dist/ba_data/python/bacommon/transfer.py
vendored
|
|
@ -5,13 +5,14 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
from efro.dataclassio import ioprepped, IOAttrs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
pass
|
||||
|
||||
|
||||
@ioprepped
|
||||
|
|
@ -40,15 +41,17 @@ class DirectoryManifest:
|
|||
paths: list[str] = []
|
||||
|
||||
if path.is_dir():
|
||||
# Build the full list of package-relative paths.
|
||||
# Build the full list of relative paths.
|
||||
for basename, _dirnames, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
fullname = os.path.join(basename, filename)
|
||||
assert fullname.startswith(pathstr)
|
||||
paths.append(fullname[len(pathstr) + 1:])
|
||||
# Make sure we end up with forward slashes no matter
|
||||
# what the os.* stuff above here was using.
|
||||
paths.append(Path(fullname[len(pathstr) + 1:]).as_posix())
|
||||
elif path.exists():
|
||||
# Just return a single file entry if path is not a dir.
|
||||
paths.append(pathstr)
|
||||
paths.append(path.as_posix())
|
||||
|
||||
def _get_file_info(filepath: str) -> tuple[str, DirectoryManifestFile]:
|
||||
sha = hashlib.sha256()
|
||||
|
|
@ -70,6 +73,18 @@ class DirectoryManifest:
|
|||
with ThreadPoolExecutor(max_workers=cpus) as executor:
|
||||
return cls(files=dict(executor.map(_get_file_info, paths)))
|
||||
|
||||
def validate(self) -> None:
|
||||
"""Log any odd data in the manifest; for debugging."""
|
||||
import logging
|
||||
for fpath, _fentry in self.files.items():
|
||||
# We want to be dealing in only forward slashes; make sure
|
||||
# that's the case (wondering if we'll ever see backslashes
|
||||
# for escape purposes).
|
||||
if '\\' in fpath:
|
||||
logging.exception("Found unusual path in manifest: '%s'.",
|
||||
fpath)
|
||||
break # 1 error is enough for now.
|
||||
|
||||
@classmethod
|
||||
def get_empty_hash(cls) -> str:
|
||||
"""Return the hash for an empty file."""
|
||||
|
|
|
|||
2
dist/ba_data/python/bastd/actor/spaz.py
vendored
2
dist/ba_data/python/bastd/actor/spaz.py
vendored
|
|
@ -606,6 +606,7 @@ class Spaz(ba.Actor):
|
|||
"""
|
||||
assert self.node
|
||||
self.node.boxing_gloves = True
|
||||
self._has_boxing_gloves = True
|
||||
if self._demo_mode: # Preserve old behavior.
|
||||
self._punch_power_scale = 1.7
|
||||
self._punch_cooldown = 300
|
||||
|
|
@ -754,7 +755,6 @@ class Spaz(ba.Actor):
|
|||
ba.WeakCall(self._bomb_wear_off),
|
||||
timeformat=ba.TimeFormat.MILLISECONDS))
|
||||
elif msg.poweruptype == 'punch':
|
||||
self._has_boxing_gloves = True
|
||||
tex = PowerupBoxFactory.get().tex_punch
|
||||
self._flash_billboard(tex)
|
||||
self.equip_boxing_gloves()
|
||||
|
|
|
|||
3
dist/ba_data/python/bastd/game/onslaught.py
vendored
3
dist/ba_data/python/bastd/game/onslaught.py
vendored
|
|
@ -5,6 +5,9 @@
|
|||
# Yes this is a long one..
|
||||
# pylint: disable=too-many-lines
|
||||
|
||||
# ba_meta require api 7
|
||||
# (see https://ballistica.net/wiki/meta-tag-system)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
|
|
|||
3
dist/ba_data/python/bastd/game/runaround.py
vendored
3
dist/ba_data/python/bastd/game/runaround.py
vendored
|
|
@ -5,6 +5,9 @@
|
|||
# We wear the cone of shame.
|
||||
# pylint: disable=too-many-lines
|
||||
|
||||
# ba_meta require api 7
|
||||
# (see https://ballistica.net/wiki/meta-tag-system)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
|
|
|
|||
799
dist/ba_data/python/bastd/ui/coop/browser.py
vendored
799
dist/ba_data/python/bastd/ui/coop/browser.py
vendored
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import _ba
|
||||
|
|
@ -18,6 +17,8 @@ from bastd.ui.store.browser import StoreBrowserWindow
|
|||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
from bastd.ui.coop.tournamentbutton import TournamentButton
|
||||
|
||||
|
||||
class CoopBrowserWindow(ba.Window):
|
||||
"""Window for browsing co-op levels/games/etc."""
|
||||
|
|
@ -175,8 +176,6 @@ class CoopBrowserWindow(ba.Window):
|
|||
'Selected Coop Campaign Level', None))
|
||||
self._selected_custom_level = (cfg.get('Selected Coop Custom Level',
|
||||
None))
|
||||
self._selected_challenge_level = (cfg.get(
|
||||
'Selected Coop Challenge Level', None))
|
||||
|
||||
# Don't want initial construction affecting our last-selected.
|
||||
self._do_selection_callbacks = False
|
||||
|
|
@ -283,6 +282,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
import bastd.ui.tournamentscores as _unused8
|
||||
import bastd.ui.tournamententry as _unused9
|
||||
import bastd.ui.play as _unused10
|
||||
import bastd.ui.coop.tournamentbutton as _unused11
|
||||
|
||||
def _update(self) -> None:
|
||||
# Do nothing if we've somehow outlived our actual UI.
|
||||
|
|
@ -335,21 +335,21 @@ class CoopBrowserWindow(ba.Window):
|
|||
# Decrement time on our tournament buttons.
|
||||
ads_enabled = _ba.have_incentivized_ad()
|
||||
for tbtn in self._tournament_buttons:
|
||||
tbtn['time_remaining'] = max(0, tbtn['time_remaining'] - 1)
|
||||
if tbtn['time_remaining_value_text'] is not None:
|
||||
tbtn.time_remaining = max(0, tbtn.time_remaining - 1)
|
||||
if tbtn.time_remaining_value_text is not None:
|
||||
ba.textwidget(
|
||||
edit=tbtn['time_remaining_value_text'],
|
||||
text=ba.timestring(tbtn['time_remaining'],
|
||||
edit=tbtn.time_remaining_value_text,
|
||||
text=ba.timestring(tbtn.time_remaining,
|
||||
centi=False,
|
||||
suppress_format_warning=True) if
|
||||
(tbtn['has_time_remaining']
|
||||
(tbtn.has_time_remaining
|
||||
and self._tourney_data_up_to_date) else '-')
|
||||
|
||||
# Also adjust the ad icon visibility.
|
||||
if tbtn.get('allow_ads', False) and _ba.has_video_ads():
|
||||
ba.imagewidget(edit=tbtn['entry_fee_ad_image'],
|
||||
if tbtn.allow_ads and _ba.has_video_ads():
|
||||
ba.imagewidget(edit=tbtn.entry_fee_ad_image,
|
||||
opacity=1.0 if ads_enabled else 0.25)
|
||||
ba.textwidget(edit=tbtn['entry_fee_text_remaining'],
|
||||
ba.textwidget(edit=tbtn.entry_fee_text_remaining,
|
||||
color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2))
|
||||
|
||||
self._update_hard_mode_lock_image()
|
||||
|
|
@ -363,232 +363,21 @@ class CoopBrowserWindow(ba.Window):
|
|||
ba.print_exception('Error updating campaign lock.')
|
||||
|
||||
def _update_for_data(self, data: list[dict[str, Any]] | None) -> None:
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
from ba.internal import getcampaign, get_tournament_prize_strings
|
||||
|
||||
# If the number of tournaments or challenges in the data differs from
|
||||
# our current arrangement, refresh with the new number.
|
||||
if ((data is None and self._tournament_button_count != 0)
|
||||
or (data is not None and
|
||||
(len(data) != self._tournament_button_count))):
|
||||
self._tournament_button_count = len(
|
||||
data) if data is not None else 0
|
||||
self._tournament_button_count = (len(data)
|
||||
if data is not None else 0)
|
||||
ba.app.config['Tournament Rows'] = self._tournament_button_count
|
||||
self._refresh()
|
||||
|
||||
# Update all of our tourney buttons based on whats in data.
|
||||
for i, tbtn in enumerate(self._tournament_buttons):
|
||||
assert data is not None
|
||||
entry: dict[str, Any] = data[i]
|
||||
prize_y_offs = (34 if 'prizeRange3' in entry else
|
||||
20 if 'prizeRange2' in entry else 12)
|
||||
x_offs = 90
|
||||
|
||||
# This seems to be a false alarm.
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
pr1, pv1, pr2, pv2, pr3, pv3 = (
|
||||
get_tournament_prize_strings(entry))
|
||||
# pylint: enable=unbalanced-tuple-unpacking
|
||||
enabled = 'requiredLeague' not in entry
|
||||
ba.buttonwidget(edit=tbtn['button'],
|
||||
color=(0.5, 0.7, 0.2) if enabled else
|
||||
(0.5, 0.5, 0.5))
|
||||
ba.imagewidget(edit=tbtn['lock_image'],
|
||||
opacity=0.0 if enabled else 1.0)
|
||||
ba.textwidget(edit=tbtn['prize_range_1_text'],
|
||||
text='-' if pr1 == '' else pr1,
|
||||
position=(tbtn['button_x'] + 365 + x_offs,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] -
|
||||
93 + prize_y_offs))
|
||||
|
||||
# We want to draw values containing tickets a bit smaller
|
||||
# (scratch that; we now draw medals a bit bigger).
|
||||
ticket_char = ba.charstr(ba.SpecialChar.TICKET_BACKING)
|
||||
prize_value_scale_large = 1.0
|
||||
prize_value_scale_small = 1.0
|
||||
|
||||
ba.textwidget(edit=tbtn['prize_value_1_text'],
|
||||
text='-' if pv1 == '' else pv1,
|
||||
scale=prize_value_scale_large if ticket_char
|
||||
not in pv1 else prize_value_scale_small,
|
||||
position=(tbtn['button_x'] + 380 + x_offs,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] -
|
||||
93 + prize_y_offs))
|
||||
|
||||
ba.textwidget(edit=tbtn['prize_range_2_text'],
|
||||
text=pr2,
|
||||
position=(tbtn['button_x'] + 365 + x_offs,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] -
|
||||
93 - 45 + prize_y_offs))
|
||||
ba.textwidget(edit=tbtn['prize_value_2_text'],
|
||||
text=pv2,
|
||||
scale=prize_value_scale_large if ticket_char
|
||||
not in pv2 else prize_value_scale_small,
|
||||
position=(tbtn['button_x'] + 380 + x_offs,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] -
|
||||
93 - 45 + prize_y_offs))
|
||||
|
||||
ba.textwidget(edit=tbtn['prize_range_3_text'],
|
||||
text=pr3,
|
||||
position=(tbtn['button_x'] + 365 + x_offs,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] -
|
||||
93 - 90 + prize_y_offs))
|
||||
ba.textwidget(edit=tbtn['prize_value_3_text'],
|
||||
text=pv3,
|
||||
scale=prize_value_scale_large if ticket_char
|
||||
not in pv3 else prize_value_scale_small,
|
||||
position=(tbtn['button_x'] + 380 + x_offs,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] -
|
||||
93 - 90 + prize_y_offs))
|
||||
|
||||
leader_name = '-'
|
||||
leader_score: str | ba.Lstr = '-'
|
||||
if entry['scores']:
|
||||
score = tbtn['leader'] = copy.deepcopy(entry['scores'][0])
|
||||
leader_name = score[1]
|
||||
leader_score = (ba.timestring(
|
||||
score[0] * 10,
|
||||
centi=True,
|
||||
timeformat=ba.TimeFormat.MILLISECONDS,
|
||||
suppress_format_warning=True) if entry['scoreType']
|
||||
== 'time' else str(score[0]))
|
||||
else:
|
||||
tbtn['leader'] = None
|
||||
|
||||
ba.textwidget(edit=tbtn['current_leader_name_text'],
|
||||
text=ba.Lstr(value=leader_name))
|
||||
self._tournament_leader_score_type = (entry['scoreType'])
|
||||
ba.textwidget(edit=tbtn['current_leader_score_text'],
|
||||
text=leader_score)
|
||||
ba.buttonwidget(edit=tbtn['more_scores_button'],
|
||||
label=ba.Lstr(resource=self._r + '.seeMoreText'))
|
||||
out_of_time_text: str | ba.Lstr = (
|
||||
'-' if 'totalTime' not in entry else ba.Lstr(
|
||||
resource=self._r + '.ofTotalTimeText',
|
||||
subs=[('${TOTAL}',
|
||||
ba.timestring(entry['totalTime'],
|
||||
centi=False,
|
||||
suppress_format_warning=True))]))
|
||||
ba.textwidget(edit=tbtn['time_remaining_out_of_text'],
|
||||
text=out_of_time_text)
|
||||
|
||||
tbtn['time_remaining'] = entry['timeRemaining']
|
||||
tbtn['has_time_remaining'] = entry is not None
|
||||
tbtn['tournament_id'] = entry['tournamentID']
|
||||
tbtn['required_league'] = (None if 'requiredLeague' not in entry
|
||||
else entry['requiredLeague'])
|
||||
|
||||
game = ba.app.accounts_v1.tournament_info[
|
||||
tbtn['tournament_id']]['game']
|
||||
|
||||
if game is None:
|
||||
ba.textwidget(edit=tbtn['button_text'], text='-')
|
||||
ba.imagewidget(edit=tbtn['image'],
|
||||
texture=ba.gettexture('black'),
|
||||
opacity=0.2)
|
||||
else:
|
||||
campaignname, levelname = game.split(':')
|
||||
campaign = getcampaign(campaignname)
|
||||
max_players = ba.app.accounts_v1.tournament_info[
|
||||
tbtn['tournament_id']]['maxPlayers']
|
||||
txt = ba.Lstr(
|
||||
value='${A} ${B}',
|
||||
subs=[('${A}', campaign.getlevel(levelname).displayname),
|
||||
('${B}',
|
||||
ba.Lstr(resource='playerCountAbbreviatedText',
|
||||
subs=[('${COUNT}', str(max_players))]))])
|
||||
ba.textwidget(edit=tbtn['button_text'], text=txt)
|
||||
ba.imagewidget(
|
||||
edit=tbtn['image'],
|
||||
texture=campaign.getlevel(levelname).get_preview_texture(),
|
||||
opacity=1.0 if enabled else 0.5)
|
||||
|
||||
fee = entry['fee']
|
||||
|
||||
if fee is None:
|
||||
fee_var = None
|
||||
elif fee == 4:
|
||||
fee_var = 'price.tournament_entry_4'
|
||||
elif fee == 3:
|
||||
fee_var = 'price.tournament_entry_3'
|
||||
elif fee == 2:
|
||||
fee_var = 'price.tournament_entry_2'
|
||||
elif fee == 1:
|
||||
fee_var = 'price.tournament_entry_1'
|
||||
else:
|
||||
if fee != 0:
|
||||
print('Unknown fee value:', fee)
|
||||
fee_var = 'price.tournament_entry_0'
|
||||
|
||||
tbtn['allow_ads'] = allow_ads = entry['allowAds']
|
||||
|
||||
final_fee: int | None = (None if fee_var is None else
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
fee_var, '?'))
|
||||
|
||||
final_fee_str: str | ba.Lstr
|
||||
if fee_var is None:
|
||||
final_fee_str = ''
|
||||
else:
|
||||
if final_fee == 0:
|
||||
final_fee_str = ba.Lstr(
|
||||
resource='getTicketsWindow.freeText')
|
||||
else:
|
||||
final_fee_str = (
|
||||
ba.charstr(ba.SpecialChar.TICKET_BACKING) +
|
||||
str(final_fee))
|
||||
|
||||
ad_tries_remaining = ba.app.accounts_v1.tournament_info[
|
||||
tbtn['tournament_id']]['adTriesRemaining']
|
||||
free_tries_remaining = ba.app.accounts_v1.tournament_info[
|
||||
tbtn['tournament_id']]['freeTriesRemaining']
|
||||
|
||||
# Now, if this fee allows ads and we support video ads, show
|
||||
# the 'or ad' version.
|
||||
if allow_ads and _ba.has_video_ads():
|
||||
ads_enabled = _ba.have_incentivized_ad()
|
||||
ba.imagewidget(edit=tbtn['entry_fee_ad_image'],
|
||||
opacity=1.0 if ads_enabled else 0.25)
|
||||
or_text = ba.Lstr(resource='orText',
|
||||
subs=[('${A}', ''),
|
||||
('${B}', '')]).evaluate().strip()
|
||||
ba.textwidget(edit=tbtn['entry_fee_text_or'], text=or_text)
|
||||
ba.textwidget(
|
||||
edit=tbtn['entry_fee_text_top'],
|
||||
position=(tbtn['button_x'] + 360,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] - 60),
|
||||
scale=1.3,
|
||||
text=final_fee_str)
|
||||
|
||||
# Possibly show number of ad-plays remaining.
|
||||
ba.textwidget(
|
||||
edit=tbtn['entry_fee_text_remaining'],
|
||||
position=(tbtn['button_x'] + 360,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] - 146),
|
||||
text='' if ad_tries_remaining in [None, 0] else
|
||||
('' + str(ad_tries_remaining)),
|
||||
color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2))
|
||||
else:
|
||||
ba.imagewidget(edit=tbtn['entry_fee_ad_image'], opacity=0.0)
|
||||
ba.textwidget(edit=tbtn['entry_fee_text_or'], text='')
|
||||
ba.textwidget(
|
||||
edit=tbtn['entry_fee_text_top'],
|
||||
position=(tbtn['button_x'] + 360,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] - 80),
|
||||
scale=1.3,
|
||||
text=final_fee_str)
|
||||
|
||||
# Possibly show number of free-plays remaining.
|
||||
ba.textwidget(
|
||||
edit=tbtn['entry_fee_text_remaining'],
|
||||
position=(tbtn['button_x'] + 360,
|
||||
tbtn['button_y'] + tbtn['button_scale_y'] - 100),
|
||||
text=('' if (free_tries_remaining in [None, 0]
|
||||
or final_fee != 0) else
|
||||
('' + str(free_tries_remaining))),
|
||||
color=(0.6, 0.6, 0.6, 1))
|
||||
tbtn.update_for_data(data[i])
|
||||
|
||||
def _on_tournament_query_response(self,
|
||||
data: dict[str, Any] | None) -> None:
|
||||
|
|
@ -715,10 +504,13 @@ class CoopBrowserWindow(ba.Window):
|
|||
items = [
|
||||
campaignname + ':Onslaught Training',
|
||||
campaignname + ':Rookie Onslaught',
|
||||
campaignname + ':Rookie Football', campaignname + ':Pro Onslaught',
|
||||
campaignname + ':Pro Football', campaignname + ':Pro Runaround',
|
||||
campaignname + ':Uber Onslaught', campaignname + ':Uber Football',
|
||||
campaignname + ':Uber Runaround'
|
||||
campaignname + ':Rookie Football',
|
||||
campaignname + ':Pro Onslaught',
|
||||
campaignname + ':Pro Football',
|
||||
campaignname + ':Pro Runaround',
|
||||
campaignname + ':Uber Onslaught',
|
||||
campaignname + ':Uber Football',
|
||||
campaignname + ':Uber Runaround',
|
||||
]
|
||||
items += [campaignname + ':The Last Stand']
|
||||
if self._selected_campaign_level is None:
|
||||
|
|
@ -772,6 +564,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.coop.gamebutton import GameButton
|
||||
from bastd.ui.coop.tournamentbutton import TournamentButton
|
||||
|
||||
# (Re)create the sub-container if need be.
|
||||
if self._subcontainer is not None:
|
||||
|
|
@ -839,7 +632,7 @@ class CoopBrowserWindow(ba.Window):
|
|||
|
||||
# Tournaments
|
||||
|
||||
self._tournament_buttons: list[dict[str, Any]] = []
|
||||
self._tournament_buttons: list[TournamentButton] = []
|
||||
|
||||
v -= 53
|
||||
# FIXME shouldn't use hard-coded strings here.
|
||||
|
|
@ -919,10 +712,15 @@ class CoopBrowserWindow(ba.Window):
|
|||
v2 = -2
|
||||
is_last_sel = True
|
||||
self._tournament_buttons.append(
|
||||
self._tournament_button(sc2, h, v2, is_last_sel))
|
||||
TournamentButton(sc2,
|
||||
h,
|
||||
v2,
|
||||
is_last_sel,
|
||||
on_pressed=ba.WeakCall(
|
||||
self.run_tournament)))
|
||||
v -= 200
|
||||
|
||||
# Custom Games.
|
||||
# Custom Games. (called 'Practice' in UI these days).
|
||||
v -= 50
|
||||
ba.textwidget(parent=w_parent,
|
||||
position=(h_base + 27, v + 30 + 198),
|
||||
|
|
@ -949,14 +747,13 @@ class CoopBrowserWindow(ba.Window):
|
|||
if _ba.get_v1_account_misc_read_val(
|
||||
'easter', False) or _ba.get_purchased('games.easter_egg_hunt'):
|
||||
items = [
|
||||
'Challenges:Easter Egg Hunt', 'Challenges:Pro Easter Egg Hunt'
|
||||
'Challenges:Easter Egg Hunt',
|
||||
'Challenges:Pro Easter Egg Hunt',
|
||||
] + items
|
||||
|
||||
# add all custom user levels here..
|
||||
# items += [
|
||||
# 'User:' + l.getname()
|
||||
# for l in getcampaign('User').getlevels()
|
||||
# ]
|
||||
# If we've defined custom games, put them at the beginning.
|
||||
if ba.app.custom_coop_practice_games:
|
||||
items = ba.app.custom_coop_practice_games + items
|
||||
|
||||
self._custom_h_scroll = custom_h_scroll = h_scroll = ba.hscrollwidget(
|
||||
parent=w_parent,
|
||||
|
|
@ -995,19 +792,19 @@ class CoopBrowserWindow(ba.Window):
|
|||
|
||||
for i, tbutton in enumerate(self._tournament_buttons):
|
||||
ba.widget(
|
||||
edit=tbutton['button'],
|
||||
edit=tbutton.button,
|
||||
up_widget=self._tournament_info_button
|
||||
if i == 0 else self._tournament_buttons[i - 1]['button'],
|
||||
down_widget=self._tournament_buttons[(i + 1)]['button']
|
||||
if i == 0 else self._tournament_buttons[i - 1].button,
|
||||
down_widget=self._tournament_buttons[(i + 1)].button
|
||||
if i + 1 < len(self._tournament_buttons) else custom_h_scroll)
|
||||
ba.widget(
|
||||
edit=tbutton['more_scores_button'],
|
||||
edit=tbutton.more_scores_button,
|
||||
down_widget=self._tournament_buttons[(
|
||||
i + 1)]['current_leader_name_text']
|
||||
i + 1)].current_leader_name_text
|
||||
if i + 1 < len(self._tournament_buttons) else custom_h_scroll)
|
||||
ba.widget(edit=tbutton['current_leader_name_text'],
|
||||
ba.widget(edit=tbutton.current_leader_name_text,
|
||||
up_widget=self._tournament_info_button if i == 0 else
|
||||
self._tournament_buttons[i - 1]['more_scores_button'])
|
||||
self._tournament_buttons[i - 1].more_scores_button)
|
||||
|
||||
for btn in self._custom_buttons:
|
||||
try:
|
||||
|
|
@ -1037,314 +834,6 @@ class CoopBrowserWindow(ba.Window):
|
|||
def _enable_selectable_callback(self) -> None:
|
||||
self._do_selection_callbacks = True
|
||||
|
||||
def _tournament_button(self, parent: ba.Widget, x: float, y: float,
|
||||
select: bool) -> dict[str, Any]:
|
||||
sclx = 300
|
||||
scly = 195.0
|
||||
data: dict[str, Any] = {
|
||||
'tournament_id': None,
|
||||
'time_remaining': 0,
|
||||
'has_time_remaining': False,
|
||||
'leader': None
|
||||
}
|
||||
data['button'] = btn = ba.buttonwidget(
|
||||
parent=parent,
|
||||
position=(x + 23, y + 4),
|
||||
size=(sclx, scly),
|
||||
label='',
|
||||
button_type='square',
|
||||
autoselect=True,
|
||||
on_activate_call=lambda: self.run(None, tournament_button=data))
|
||||
ba.widget(edit=btn,
|
||||
show_buffer_bottom=50,
|
||||
show_buffer_top=50,
|
||||
show_buffer_left=400,
|
||||
show_buffer_right=200)
|
||||
if select:
|
||||
ba.containerwidget(edit=parent,
|
||||
selected_child=btn,
|
||||
visible_child=btn)
|
||||
image_width = sclx * 0.85 * 0.75
|
||||
|
||||
data['image'] = ba.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
|
||||
size=(image_width, image_width * 0.5),
|
||||
model_transparent=self.lsbt,
|
||||
model_opaque=self.lsbo,
|
||||
texture=ba.gettexture('black'),
|
||||
opacity=0.2,
|
||||
mask_texture=ba.gettexture('mapPreviewMask'))
|
||||
|
||||
data['lock_image'] = ba.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 21 + sclx * 0.5 - image_width * 0.25,
|
||||
y + scly - 150),
|
||||
size=(image_width * 0.5, image_width * 0.5),
|
||||
texture=ba.gettexture('lock'),
|
||||
opacity=0.0)
|
||||
|
||||
data['button_text'] = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 20 + sclx * 0.5,
|
||||
y + scly - 35),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=sclx * 0.76,
|
||||
scale=0.85,
|
||||
color=(0.8, 1.0, 0.8, 1.0))
|
||||
|
||||
header_color = (0.43, 0.4, 0.5, 1)
|
||||
value_color = (0.6, 0.6, 0.6, 1)
|
||||
|
||||
x_offs = 0
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.entryFeeText'),
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
|
||||
data['entry_fee_text_top'] = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360,
|
||||
y + scly - 60),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
scale=1.3,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
data['entry_fee_text_or'] = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360,
|
||||
y + scly - 90),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
scale=0.5,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
data['entry_fee_text_remaining'] = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360, y +
|
||||
scly - 90),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
scale=0.5,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
data['entry_fee_ad_image'] = ba.imagewidget(
|
||||
parent=parent,
|
||||
size=(40, 40),
|
||||
draw_controller=btn,
|
||||
position=(x + 360 - 20, y + scly - 140),
|
||||
opacity=0.0,
|
||||
texture=ba.gettexture('tv'))
|
||||
|
||||
x_offs += 50
|
||||
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 447 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.prizesText'),
|
||||
v_align='center',
|
||||
maxwidth=130,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
|
||||
data['button_x'] = x
|
||||
data['button_y'] = y
|
||||
data['button_scale_y'] = scly
|
||||
|
||||
xo2 = 0
|
||||
prize_value_scale = 1.5
|
||||
|
||||
data['prize_range_1_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
text='-',
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
data['prize_value_1_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
data['prize_range_2_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
data['prize_value_2_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
data['prize_range_3_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
data['prize_value_3_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.currentBestText'),
|
||||
v_align='center',
|
||||
maxwidth=180,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
data['current_leader_name_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs - (170 / 1.4) * 0.5,
|
||||
y + scly - 60 - 40 * 0.5),
|
||||
selectable=True,
|
||||
click_activate=True,
|
||||
autoselect=True,
|
||||
on_activate_call=lambda: self._show_leader(tournament_button=data),
|
||||
size=(170 / 1.4, 40),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=170,
|
||||
scale=1.4,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
data['current_leader_score_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs, y + scly - 113 + 10),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=170,
|
||||
scale=1.8,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
data['more_scores_button'] = ba.buttonwidget(
|
||||
parent=parent,
|
||||
position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
|
||||
color=(0.5, 0.5, 0.6),
|
||||
textcolor=(0.7, 0.7, 0.8),
|
||||
label='-',
|
||||
size=(120, 40),
|
||||
autoselect=True,
|
||||
up_widget=data['current_leader_name_text'],
|
||||
text_scale=0.6,
|
||||
on_activate_call=lambda: self._show_scores(tournament_button=data))
|
||||
ba.widget(edit=data['current_leader_name_text'],
|
||||
down_widget=data['more_scores_button'])
|
||||
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.timeRemainingText'),
|
||||
v_align='center',
|
||||
maxwidth=180,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
data['time_remaining_value_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 68),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=180,
|
||||
scale=2.0,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
data['time_remaining_out_of_text'] = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 110),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=120,
|
||||
scale=0.72,
|
||||
color=(0.4, 0.4, 0.5),
|
||||
flatness=1.0)
|
||||
return data
|
||||
|
||||
def _switch_to_league_rankings(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
|
|
@ -1378,100 +867,20 @@ class CoopBrowserWindow(ba.Window):
|
|||
show_tab=show_tab,
|
||||
back_location='CoopBrowserWindow').get_root_widget())
|
||||
|
||||
def _show_leader(self, tournament_button: dict[str, Any]) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.account.viewer import AccountViewerWindow
|
||||
tournament_id = tournament_button['tournament_id']
|
||||
|
||||
# FIXME: This assumes a single player entry in leader; should expand
|
||||
# this to work with multiple.
|
||||
if tournament_id is None or tournament_button['leader'] is None or len(
|
||||
tournament_button['leader'][2]) != 1:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
ba.playsound(ba.getsound('swish'))
|
||||
AccountViewerWindow(
|
||||
account_id=tournament_button['leader'][2][0].get('a', None),
|
||||
profile_id=tournament_button['leader'][2][0].get('p', None),
|
||||
position=tournament_button['current_leader_name_text'].
|
||||
get_screen_space_center())
|
||||
|
||||
def _show_scores(self, tournament_button: dict[str, Any]) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.tournamentscores import TournamentScoresWindow
|
||||
tournament_id = tournament_button['tournament_id']
|
||||
if tournament_id is None:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
TournamentScoresWindow(
|
||||
tournament_id=tournament_id,
|
||||
position=tournament_button['more_scores_button'].
|
||||
get_screen_space_center())
|
||||
|
||||
def is_tourney_data_up_to_date(self) -> bool:
|
||||
"""Return whether our tourney data is up to date."""
|
||||
return self._tourney_data_up_to_date
|
||||
|
||||
def run(self,
|
||||
game: str | None,
|
||||
tournament_button: dict[str, Any] | None = None) -> None:
|
||||
def run_game(self, game: str) -> None:
|
||||
"""Run the provided game."""
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-return-statements
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.confirm import ConfirmWindow
|
||||
from bastd.ui.tournamententry import TournamentEntryWindow
|
||||
from bastd.ui.purchase import PurchaseWindow
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
args: dict[str, Any] = {}
|
||||
|
||||
# Do a bit of pre-flight for tournament options.
|
||||
if tournament_button is not None:
|
||||
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
|
||||
if not self._tourney_data_up_to_date:
|
||||
ba.screenmessage(
|
||||
ba.Lstr(resource='tournamentCheckingStateText'),
|
||||
color=(1, 1, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if tournament_button['tournament_id'] is None:
|
||||
ba.screenmessage(
|
||||
ba.Lstr(resource='internal.unavailableNoConnectionText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if tournament_button['required_league'] is not None:
|
||||
ba.screenmessage(ba.Lstr(
|
||||
resource='league.tournamentLeagueText',
|
||||
subs=[
|
||||
('${NAME}',
|
||||
ba.Lstr(
|
||||
translate=('leagueNames',
|
||||
tournament_button['required_league'])))
|
||||
]),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if tournament_button['time_remaining'] <= 0:
|
||||
ba.screenmessage(ba.Lstr(resource='tournamentEndedText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
# Game is whatever the tournament tells us it is.
|
||||
game = ba.app.accounts_v1.tournament_info[
|
||||
tournament_button['tournament_id']]['game']
|
||||
|
||||
if tournament_button is None and game == 'Easy:The Last Stand':
|
||||
if game == 'Easy:The Last Stand':
|
||||
ConfirmWindow(ba.Lstr(resource='difficultyHardUnlockOnlyText',
|
||||
fallback_resource='difficultyHardOnlyText'),
|
||||
cancel_button=False,
|
||||
|
|
@ -1479,12 +888,11 @@ class CoopBrowserWindow(ba.Window):
|
|||
height=130)
|
||||
return
|
||||
|
||||
# Infinite onslaught/runaround require pro; bring up a store link if
|
||||
# need be.
|
||||
if tournament_button is None and game in (
|
||||
'Challenges:Infinite Runaround',
|
||||
'Challenges:Infinite Onslaught'
|
||||
) and not ba.app.accounts_v1.have_pro():
|
||||
# Infinite onslaught/runaround require pro; bring up a store link
|
||||
# if need be.
|
||||
if game in ('Challenges:Infinite Runaround',
|
||||
'Challenges:Infinite Onslaught'
|
||||
) and not ba.app.accounts_v1.have_pro():
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
else:
|
||||
|
|
@ -1495,7 +903,8 @@ class CoopBrowserWindow(ba.Window):
|
|||
if game in ['Challenges:Meteor Shower']:
|
||||
required_purchase = 'games.meteor_shower'
|
||||
elif game in [
|
||||
'Challenges:Target Practice', 'Challenges:Target Practice B'
|
||||
'Challenges:Target Practice',
|
||||
'Challenges:Target Practice B',
|
||||
]:
|
||||
required_purchase = 'games.target_practice'
|
||||
elif game in ['Challenges:Ninja Fight']:
|
||||
|
|
@ -1503,13 +912,14 @@ class CoopBrowserWindow(ba.Window):
|
|||
elif game in ['Challenges:Pro Ninja Fight']:
|
||||
required_purchase = 'games.ninja_fight'
|
||||
elif game in [
|
||||
'Challenges:Easter Egg Hunt', 'Challenges:Pro Easter Egg Hunt'
|
||||
'Challenges:Easter Egg Hunt',
|
||||
'Challenges:Pro Easter Egg Hunt',
|
||||
]:
|
||||
required_purchase = 'games.easter_egg_hunt'
|
||||
else:
|
||||
required_purchase = None
|
||||
|
||||
if (tournament_button is None and required_purchase is not None
|
||||
if (required_purchase is not None
|
||||
and not _ba.get_purchased(required_purchase)):
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
|
|
@ -1519,17 +929,57 @@ class CoopBrowserWindow(ba.Window):
|
|||
|
||||
self._save_state()
|
||||
|
||||
# For tournaments, we pop up the entry window.
|
||||
if tournament_button is not None:
|
||||
TournamentEntryWindow(
|
||||
tournament_id=tournament_button['tournament_id'],
|
||||
position=tournament_button['button'].get_screen_space_center())
|
||||
else:
|
||||
# Otherwise just dive right in.
|
||||
assert game is not None
|
||||
if ba.app.launch_coop_game(game, args=args):
|
||||
ba.containerwidget(edit=self._root_widget,
|
||||
transition='out_left')
|
||||
if ba.app.launch_coop_game(game, args=args):
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
def run_tournament(self, tournament_button: TournamentButton) -> None:
|
||||
"""Run the provided tournament game."""
|
||||
from bastd.ui.account import show_sign_in_prompt
|
||||
from bastd.ui.tournamententry import TournamentEntryWindow
|
||||
|
||||
if _ba.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
|
||||
if not self._tourney_data_up_to_date:
|
||||
ba.screenmessage(ba.Lstr(resource='tournamentCheckingStateText'),
|
||||
color=(1, 1, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if tournament_button.tournament_id is None:
|
||||
ba.screenmessage(
|
||||
ba.Lstr(resource='internal.unavailableNoConnectionText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if tournament_button.required_league is not None:
|
||||
ba.screenmessage(
|
||||
ba.Lstr(
|
||||
resource='league.tournamentLeagueText',
|
||||
subs=[('${NAME}',
|
||||
ba.Lstr(
|
||||
translate=('leagueNames',
|
||||
tournament_button.required_league)))
|
||||
]),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
if tournament_button.time_remaining <= 0:
|
||||
ba.screenmessage(ba.Lstr(resource='tournamentEndedText'),
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
|
||||
assert tournament_button.tournament_id is not None
|
||||
TournamentEntryWindow(
|
||||
tournament_id=tournament_button.tournament_id,
|
||||
position=tournament_button.button.get_screen_space_center())
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
|
|
@ -1542,24 +992,6 @@ class CoopBrowserWindow(ba.Window):
|
|||
ba.app.ui.set_main_menu_window(
|
||||
PlayWindow(transition='in_left').get_root_widget())
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
if sel_name == 'Back':
|
||||
sel = self._back_button
|
||||
elif sel_name == 'Scroll':
|
||||
sel = self._scrollwidget
|
||||
elif sel_name == 'PowerRanking':
|
||||
sel = self._league_rank_button_widget
|
||||
elif sel_name == 'Store':
|
||||
sel = self._store_button_widget
|
||||
else:
|
||||
sel = self._scrollwidget
|
||||
ba.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||
except Exception:
|
||||
ba.print_exception(f'Error restoring state for {self}.')
|
||||
|
||||
def _save_state(self) -> None:
|
||||
cfg = ba.app.config
|
||||
try:
|
||||
|
|
@ -1580,16 +1012,31 @@ class CoopBrowserWindow(ba.Window):
|
|||
|
||||
cfg['Selected Coop Row'] = self._selected_row
|
||||
cfg['Selected Coop Custom Level'] = self._selected_custom_level
|
||||
cfg['Selected Coop Challenge Level'] = self._selected_challenge_level
|
||||
cfg['Selected Coop Campaign Level'] = self._selected_campaign_level
|
||||
cfg.commit()
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
try:
|
||||
sel_name = ba.app.ui.window_states.get(type(self),
|
||||
{}).get('sel_name')
|
||||
if sel_name == 'Back':
|
||||
sel = self._back_button
|
||||
elif sel_name == 'Scroll':
|
||||
sel = self._scrollwidget
|
||||
elif sel_name == 'PowerRanking':
|
||||
sel = self._league_rank_button_widget
|
||||
elif sel_name == 'Store':
|
||||
sel = self._store_button_widget
|
||||
else:
|
||||
sel = self._scrollwidget
|
||||
ba.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||
except Exception:
|
||||
ba.print_exception(f'Error restoring state for {self}.')
|
||||
|
||||
def sel_change(self, row: str, game: str) -> None:
|
||||
"""(internal)"""
|
||||
if self._do_selection_callbacks:
|
||||
if row == 'custom':
|
||||
self._selected_custom_level = game
|
||||
if row == 'challenges':
|
||||
self._selected_challenge_level = game
|
||||
elif row == 'campaign':
|
||||
self._selected_campaign_level = game
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class GameButton:
|
|||
position=(x + 23, y + 4),
|
||||
size=(sclx, scly),
|
||||
label='',
|
||||
on_activate_call=ba.Call(window.run, game),
|
||||
on_activate_call=ba.Call(window.run_game, game),
|
||||
button_type='square',
|
||||
autoselect=True,
|
||||
on_select_call=ba.Call(window.sel_change, row, game))
|
||||
|
|
|
|||
561
dist/ba_data/python/bastd/ui/coop/tournamentbutton.py
vendored
Normal file
561
dist/ba_data/python/bastd/ui/coop/tournamentbutton.py
vendored
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Defines button for co-op games."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
import copy
|
||||
|
||||
import ba
|
||||
import _ba
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
class TournamentButton:
|
||||
"""Button showing a tournament in coop window."""
|
||||
|
||||
def __init__(self, parent: ba.Widget, x: float, y: float, select: bool,
|
||||
on_pressed: Callable[[TournamentButton], None]) -> None:
|
||||
self._r = 'coopSelectWindow'
|
||||
sclx = 300
|
||||
scly = 195.0
|
||||
self.on_pressed = on_pressed
|
||||
self.lsbt = ba.getmodel('level_select_button_transparent')
|
||||
self.lsbo = ba.getmodel('level_select_button_opaque')
|
||||
self.allow_ads = False
|
||||
self.tournament_id: str | None = None
|
||||
self.time_remaining: int = 0
|
||||
self.has_time_remaining: bool = False
|
||||
self.leader: Any = None
|
||||
self.required_league: str | None = None
|
||||
self.button = btn = ba.buttonwidget(
|
||||
parent=parent,
|
||||
position=(x + 23, y + 4),
|
||||
size=(sclx, scly),
|
||||
label='',
|
||||
button_type='square',
|
||||
autoselect=True,
|
||||
# on_activate_call=lambda: self.run(None, tournament_button=data)
|
||||
on_activate_call=ba.WeakCall(self._pressed))
|
||||
ba.widget(edit=btn,
|
||||
show_buffer_bottom=50,
|
||||
show_buffer_top=50,
|
||||
show_buffer_left=400,
|
||||
show_buffer_right=200)
|
||||
if select:
|
||||
ba.containerwidget(edit=parent,
|
||||
selected_child=btn,
|
||||
visible_child=btn)
|
||||
image_width = sclx * 0.85 * 0.75
|
||||
|
||||
self.image = ba.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
|
||||
size=(image_width, image_width * 0.5),
|
||||
model_transparent=self.lsbt,
|
||||
model_opaque=self.lsbo,
|
||||
texture=ba.gettexture('black'),
|
||||
opacity=0.2,
|
||||
mask_texture=ba.gettexture('mapPreviewMask'))
|
||||
|
||||
self.lock_image = ba.imagewidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 21 + sclx * 0.5 - image_width * 0.25,
|
||||
y + scly - 150),
|
||||
size=(image_width * 0.5, image_width * 0.5),
|
||||
texture=ba.gettexture('lock'),
|
||||
opacity=0.0)
|
||||
|
||||
self.button_text = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 20 + sclx * 0.5,
|
||||
y + scly - 35),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=sclx * 0.76,
|
||||
scale=0.85,
|
||||
color=(0.8, 1.0, 0.8, 1.0))
|
||||
|
||||
header_color = (0.43, 0.4, 0.5, 1)
|
||||
value_color = (0.6, 0.6, 0.6, 1)
|
||||
|
||||
x_offs = 0
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.entryFeeText'),
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
|
||||
self.entry_fee_text_top = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360,
|
||||
y + scly - 60),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
scale=1.3,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
self.entry_fee_text_or = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360,
|
||||
y + scly - 90),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
scale=0.5,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
self.entry_fee_text_remaining = ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 360,
|
||||
y + scly - 90),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
scale=0.5,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
self.entry_fee_ad_image = ba.imagewidget(parent=parent,
|
||||
size=(40, 40),
|
||||
draw_controller=btn,
|
||||
position=(x + 360 - 20,
|
||||
y + scly - 140),
|
||||
opacity=0.0,
|
||||
texture=ba.gettexture('tv'))
|
||||
|
||||
x_offs += 50
|
||||
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 447 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.prizesText'),
|
||||
v_align='center',
|
||||
maxwidth=130,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
|
||||
self.button_x = x
|
||||
self.button_y = y
|
||||
self.button_scale_y = scly
|
||||
|
||||
xo2 = 0
|
||||
prize_value_scale = 1.5
|
||||
|
||||
self.prize_range_1_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
text='-',
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
self.prize_value_1_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
self.prize_range_2_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
self.prize_value_2_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
self.prize_range_3_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 355 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
maxwidth=50,
|
||||
scale=0.8,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
self.prize_value_3_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 380 + xo2 + x_offs, y + scly - 93),
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
text='',
|
||||
v_align='center',
|
||||
maxwidth=100,
|
||||
scale=prize_value_scale,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.currentBestText'),
|
||||
v_align='center',
|
||||
maxwidth=180,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
self.current_leader_name_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs - (170 / 1.4) * 0.5,
|
||||
y + scly - 60 - 40 * 0.5),
|
||||
selectable=True,
|
||||
click_activate=True,
|
||||
autoselect=True,
|
||||
on_activate_call=ba.WeakCall(self._show_leader),
|
||||
size=(170 / 1.4, 40),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=170,
|
||||
scale=1.4,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
self.current_leader_score_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 620 + x_offs, y + scly - 113 + 10),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=170,
|
||||
scale=1.8,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
|
||||
self.more_scores_button = ba.buttonwidget(
|
||||
parent=parent,
|
||||
position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
|
||||
color=(0.5, 0.5, 0.6),
|
||||
textcolor=(0.7, 0.7, 0.8),
|
||||
label='-',
|
||||
size=(120, 40),
|
||||
autoselect=True,
|
||||
up_widget=self.current_leader_name_text,
|
||||
text_scale=0.6,
|
||||
on_activate_call=ba.WeakCall(self._show_scores))
|
||||
ba.widget(edit=self.current_leader_name_text,
|
||||
down_widget=self.more_scores_button)
|
||||
|
||||
ba.textwidget(parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text=ba.Lstr(resource=self._r + '.timeRemainingText'),
|
||||
v_align='center',
|
||||
maxwidth=180,
|
||||
scale=0.9,
|
||||
color=header_color,
|
||||
flatness=1.0)
|
||||
self.time_remaining_value_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 68),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=180,
|
||||
scale=2.0,
|
||||
color=value_color,
|
||||
flatness=1.0)
|
||||
self.time_remaining_out_of_text = ba.textwidget(
|
||||
parent=parent,
|
||||
draw_controller=btn,
|
||||
position=(x + 820 + x_offs, y + scly - 110),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
text='-',
|
||||
v_align='center',
|
||||
maxwidth=120,
|
||||
scale=0.72,
|
||||
color=(0.4, 0.4, 0.5),
|
||||
flatness=1.0)
|
||||
|
||||
def _pressed(self) -> None:
|
||||
self.on_pressed(self)
|
||||
|
||||
def _show_leader(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.account.viewer import AccountViewerWindow
|
||||
tournament_id = self.tournament_id
|
||||
|
||||
# FIXME: This assumes a single player entry in leader; should expand
|
||||
# this to work with multiple.
|
||||
if tournament_id is None or self.leader is None or len(
|
||||
self.leader[2]) != 1:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
ba.playsound(ba.getsound('swish'))
|
||||
AccountViewerWindow(
|
||||
account_id=self.leader[2][0].get('a', None),
|
||||
profile_id=self.leader[2][0].get('p', None),
|
||||
position=self.current_leader_name_text.get_screen_space_center())
|
||||
|
||||
def _show_scores(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bastd.ui.tournamentscores import TournamentScoresWindow
|
||||
tournament_id = self.tournament_id
|
||||
if tournament_id is None:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
return
|
||||
|
||||
TournamentScoresWindow(
|
||||
tournament_id=tournament_id,
|
||||
position=self.more_scores_button.get_screen_space_center())
|
||||
|
||||
def update_for_data(self, entry: dict[str, Any]) -> None:
|
||||
"""Update for new incoming data."""
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
from ba.internal import getcampaign, get_tournament_prize_strings
|
||||
prize_y_offs = (34 if 'prizeRange3' in entry else
|
||||
20 if 'prizeRange2' in entry else 12)
|
||||
x_offs = 90
|
||||
|
||||
# This seems to be a false alarm.
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
pr1, pv1, pr2, pv2, pr3, pv3 = (get_tournament_prize_strings(entry))
|
||||
# pylint: enable=unbalanced-tuple-unpacking
|
||||
enabled = 'requiredLeague' not in entry
|
||||
ba.buttonwidget(edit=self.button,
|
||||
color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5))
|
||||
ba.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
|
||||
ba.textwidget(edit=self.prize_range_1_text,
|
||||
text='-' if pr1 == '' else pr1,
|
||||
position=(self.button_x + 365 + x_offs, self.button_y +
|
||||
self.button_scale_y - 93 + prize_y_offs))
|
||||
|
||||
# We want to draw values containing tickets a bit smaller
|
||||
# (scratch that; we now draw medals a bit bigger).
|
||||
ticket_char = ba.charstr(ba.SpecialChar.TICKET_BACKING)
|
||||
prize_value_scale_large = 1.0
|
||||
prize_value_scale_small = 1.0
|
||||
|
||||
ba.textwidget(edit=self.prize_value_1_text,
|
||||
text='-' if pv1 == '' else pv1,
|
||||
scale=prize_value_scale_large
|
||||
if ticket_char not in pv1 else prize_value_scale_small,
|
||||
position=(self.button_x + 380 + x_offs, self.button_y +
|
||||
self.button_scale_y - 93 + prize_y_offs))
|
||||
|
||||
ba.textwidget(edit=self.prize_range_2_text,
|
||||
text=pr2,
|
||||
position=(self.button_x + 365 + x_offs, self.button_y +
|
||||
self.button_scale_y - 93 - 45 + prize_y_offs))
|
||||
ba.textwidget(edit=self.prize_value_2_text,
|
||||
text=pv2,
|
||||
scale=prize_value_scale_large
|
||||
if ticket_char not in pv2 else prize_value_scale_small,
|
||||
position=(self.button_x + 380 + x_offs, self.button_y +
|
||||
self.button_scale_y - 93 - 45 + prize_y_offs))
|
||||
|
||||
ba.textwidget(edit=self.prize_range_3_text,
|
||||
text=pr3,
|
||||
position=(self.button_x + 365 + x_offs, self.button_y +
|
||||
self.button_scale_y - 93 - 90 + prize_y_offs))
|
||||
ba.textwidget(edit=self.prize_value_3_text,
|
||||
text=pv3,
|
||||
scale=prize_value_scale_large
|
||||
if ticket_char not in pv3 else prize_value_scale_small,
|
||||
position=(self.button_x + 380 + x_offs, self.button_y +
|
||||
self.button_scale_y - 93 - 90 + prize_y_offs))
|
||||
|
||||
leader_name = '-'
|
||||
leader_score: str | ba.Lstr = '-'
|
||||
if entry['scores']:
|
||||
score = self.leader = copy.deepcopy(entry['scores'][0])
|
||||
leader_name = score[1]
|
||||
leader_score = (ba.timestring(
|
||||
score[0] * 10,
|
||||
centi=True,
|
||||
timeformat=ba.TimeFormat.MILLISECONDS,
|
||||
suppress_format_warning=True)
|
||||
if entry['scoreType'] == 'time' else str(score[0]))
|
||||
else:
|
||||
self.leader = None
|
||||
|
||||
ba.textwidget(edit=self.current_leader_name_text,
|
||||
text=ba.Lstr(value=leader_name))
|
||||
ba.textwidget(edit=self.current_leader_score_text, text=leader_score)
|
||||
ba.buttonwidget(edit=self.more_scores_button,
|
||||
label=ba.Lstr(resource=self._r + '.seeMoreText'))
|
||||
out_of_time_text: str | ba.Lstr = (
|
||||
'-' if 'totalTime' not in entry else ba.Lstr(
|
||||
resource=self._r + '.ofTotalTimeText',
|
||||
subs=[('${TOTAL}',
|
||||
ba.timestring(entry['totalTime'],
|
||||
centi=False,
|
||||
suppress_format_warning=True))]))
|
||||
ba.textwidget(edit=self.time_remaining_out_of_text,
|
||||
text=out_of_time_text)
|
||||
|
||||
self.time_remaining = entry['timeRemaining']
|
||||
self.has_time_remaining = entry is not None
|
||||
self.tournament_id = entry['tournamentID']
|
||||
self.required_league = (None if 'requiredLeague' not in entry else
|
||||
entry['requiredLeague'])
|
||||
|
||||
game = ba.app.accounts_v1.tournament_info[self.tournament_id]['game']
|
||||
|
||||
if game is None:
|
||||
ba.textwidget(edit=self.button_text, text='-')
|
||||
ba.imagewidget(edit=self.image,
|
||||
texture=ba.gettexture('black'),
|
||||
opacity=0.2)
|
||||
else:
|
||||
campaignname, levelname = game.split(':')
|
||||
campaign = getcampaign(campaignname)
|
||||
max_players = ba.app.accounts_v1.tournament_info[
|
||||
self.tournament_id]['maxPlayers']
|
||||
txt = ba.Lstr(value='${A} ${B}',
|
||||
subs=[('${A}',
|
||||
campaign.getlevel(levelname).displayname),
|
||||
('${B}',
|
||||
ba.Lstr(resource='playerCountAbbreviatedText',
|
||||
subs=[('${COUNT}', str(max_players))
|
||||
]))])
|
||||
ba.textwidget(edit=self.button_text, text=txt)
|
||||
ba.imagewidget(
|
||||
edit=self.image,
|
||||
texture=campaign.getlevel(levelname).get_preview_texture(),
|
||||
opacity=1.0 if enabled else 0.5)
|
||||
|
||||
fee = entry['fee']
|
||||
|
||||
if fee is None:
|
||||
fee_var = None
|
||||
elif fee == 4:
|
||||
fee_var = 'price.tournament_entry_4'
|
||||
elif fee == 3:
|
||||
fee_var = 'price.tournament_entry_3'
|
||||
elif fee == 2:
|
||||
fee_var = 'price.tournament_entry_2'
|
||||
elif fee == 1:
|
||||
fee_var = 'price.tournament_entry_1'
|
||||
else:
|
||||
if fee != 0:
|
||||
print('Unknown fee value:', fee)
|
||||
fee_var = 'price.tournament_entry_0'
|
||||
|
||||
self.allow_ads = allow_ads = entry['allowAds']
|
||||
|
||||
final_fee: int | None = (None if fee_var is None else
|
||||
_ba.get_v1_account_misc_read_val(
|
||||
fee_var, '?'))
|
||||
|
||||
final_fee_str: str | ba.Lstr
|
||||
if fee_var is None:
|
||||
final_fee_str = ''
|
||||
else:
|
||||
if final_fee == 0:
|
||||
final_fee_str = ba.Lstr(resource='getTicketsWindow.freeText')
|
||||
else:
|
||||
final_fee_str = (ba.charstr(ba.SpecialChar.TICKET_BACKING) +
|
||||
str(final_fee))
|
||||
|
||||
ad_tries_remaining = ba.app.accounts_v1.tournament_info[
|
||||
self.tournament_id]['adTriesRemaining']
|
||||
free_tries_remaining = ba.app.accounts_v1.tournament_info[
|
||||
self.tournament_id]['freeTriesRemaining']
|
||||
|
||||
# Now, if this fee allows ads and we support video ads, show
|
||||
# the 'or ad' version.
|
||||
if allow_ads and _ba.has_video_ads():
|
||||
ads_enabled = _ba.have_incentivized_ad()
|
||||
ba.imagewidget(edit=self.entry_fee_ad_image,
|
||||
opacity=1.0 if ads_enabled else 0.25)
|
||||
or_text = ba.Lstr(resource='orText',
|
||||
subs=[('${A}', ''),
|
||||
('${B}', '')]).evaluate().strip()
|
||||
ba.textwidget(edit=self.entry_fee_text_or, text=or_text)
|
||||
ba.textwidget(edit=self.entry_fee_text_top,
|
||||
position=(self.button_x + 360,
|
||||
self.button_y + self.button_scale_y - 60),
|
||||
scale=1.3,
|
||||
text=final_fee_str)
|
||||
|
||||
# Possibly show number of ad-plays remaining.
|
||||
ba.textwidget(edit=self.entry_fee_text_remaining,
|
||||
position=(self.button_x + 360,
|
||||
self.button_y + self.button_scale_y - 146),
|
||||
text='' if ad_tries_remaining in [None, 0] else
|
||||
('' + str(ad_tries_remaining)),
|
||||
color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2))
|
||||
else:
|
||||
ba.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
|
||||
ba.textwidget(edit=self.entry_fee_text_or, text='')
|
||||
ba.textwidget(edit=self.entry_fee_text_top,
|
||||
position=(self.button_x + 360,
|
||||
self.button_y + self.button_scale_y - 80),
|
||||
scale=1.3,
|
||||
text=final_fee_str)
|
||||
|
||||
# Possibly show number of free-plays remaining.
|
||||
ba.textwidget(
|
||||
edit=self.entry_fee_text_remaining,
|
||||
position=(self.button_x + 360,
|
||||
self.button_y + self.button_scale_y - 100),
|
||||
text=('' if (free_tries_remaining in [None, 0]
|
||||
or final_fee != 0) else
|
||||
('' + str(free_tries_remaining))),
|
||||
color=(0.6, 0.6, 0.6, 1),
|
||||
)
|
||||
7
dist/ba_data/python/bastd/ui/creditslist.py
vendored
7
dist/ba_data/python/bastd/ui/creditslist.py
vendored
|
|
@ -207,10 +207,15 @@ class CreditsListWindow(ba.Window):
|
|||
'\n' + '\n'.join(translation_names.splitlines()[:146]) +
|
||||
'\n'.join(translation_names.splitlines()[146:]) + '\n'
|
||||
'\n'
|
||||
' Shout Out to Awesome Mods / Modders:\n\n'
|
||||
' Shout Out to Awesome Mods / Modders / Contributors:\n\n'
|
||||
' BombDash ModPack\n'
|
||||
' TheMikirog & SoK - BombSquad Joyride Modpack\n'
|
||||
' Mrmaxmeier - BombSquad-Community-Mod-Manager\n'
|
||||
' Ritiek Malhotra \n'
|
||||
' Dliwk\n'
|
||||
' vishal332008\n'
|
||||
' itsre3\n'
|
||||
' Drooopyyy\n'
|
||||
'\n'
|
||||
' Holiday theme vector art designed by Freepik\n'
|
||||
'\n'
|
||||
|
|
|
|||
|
|
@ -705,8 +705,8 @@ class ManualGatherTab(GatherTab):
|
|||
from_other_thread=True,
|
||||
)
|
||||
except Exception as exc:
|
||||
from efro.error import is_udp_network_error
|
||||
if is_udp_network_error(exc):
|
||||
from efro.error import is_udp_communication_error
|
||||
if is_udp_communication_error(exc):
|
||||
ba.pushcall(ba.Call(
|
||||
_safe_set_text, self._checking_state_text,
|
||||
ba.Lstr(resource='gatherWindow.'
|
||||
|
|
|
|||
|
|
@ -219,9 +219,9 @@ class AddrFetchThread(threading.Thread):
|
|||
sock.close()
|
||||
ba.pushcall(ba.Call(self._call, val), from_other_thread=True)
|
||||
except Exception as exc:
|
||||
from efro.error import is_udp_network_error
|
||||
from efro.error import is_udp_communication_error
|
||||
# Ignore expected network errors; log others.
|
||||
if is_udp_network_error(exc):
|
||||
if is_udp_communication_error(exc):
|
||||
pass
|
||||
else:
|
||||
ba.print_exception()
|
||||
|
|
@ -271,8 +271,8 @@ class PingThread(threading.Thread):
|
|||
ping if accessible else None),
|
||||
from_other_thread=True)
|
||||
except Exception as exc:
|
||||
from efro.error import is_udp_network_error
|
||||
if is_udp_network_error(exc):
|
||||
from efro.error import is_udp_communication_error
|
||||
if is_udp_communication_error(exc):
|
||||
pass
|
||||
else:
|
||||
ba.print_exception('Error on gather ping', once=True)
|
||||
|
|
|
|||
14
dist/ba_data/python/bastd/ui/onscreenkeyboard.py
vendored
14
dist/ba_data/python/bastd/ui/onscreenkeyboard.py
vendored
|
|
@ -213,8 +213,8 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
|
||||
# Show change instructions only if we have more than one
|
||||
# keyboard option.
|
||||
if (ba.app.meta.metascan is not None
|
||||
and len(ba.app.meta.metascan.keyboards) > 1):
|
||||
if (ba.app.meta.scanresults is not None
|
||||
and len(ba.app.meta.scanresults.keyboards) > 1):
|
||||
ba.textwidget(
|
||||
parent=self._root_widget,
|
||||
h_align='center',
|
||||
|
|
@ -238,8 +238,8 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
self._refresh()
|
||||
|
||||
def _get_keyboard(self) -> ba.Keyboard:
|
||||
assert ba.app.meta.metascan is not None
|
||||
classname = ba.app.meta.metascan.keyboards[self._keyboard_index]
|
||||
assert ba.app.meta.scanresults is not None
|
||||
classname = ba.app.meta.scanresults.keyboards[self._keyboard_index]
|
||||
kbclass = ba.getclass(classname, ba.Keyboard)
|
||||
return kbclass()
|
||||
|
||||
|
|
@ -317,11 +317,11 @@ class OnScreenKeyboardWindow(ba.Window):
|
|||
self._refresh()
|
||||
|
||||
def _next_keyboard(self) -> None:
|
||||
assert ba.app.meta.metascan is not None
|
||||
assert ba.app.meta.scanresults is not None
|
||||
self._keyboard_index = (self._keyboard_index + 1) % len(
|
||||
ba.app.meta.metascan.keyboards)
|
||||
ba.app.meta.scanresults.keyboards)
|
||||
self._load_keyboard()
|
||||
if len(ba.app.meta.metascan.keyboards) < 2:
|
||||
if len(ba.app.meta.scanresults.keyboards) < 2:
|
||||
ba.playsound(ba.getsound('error'))
|
||||
ba.screenmessage(ba.Lstr(resource='keyboardNoOthersAvailableText'),
|
||||
color=(1, 0, 0))
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
scale=(2.06 if uiscale is ba.UIScale.SMALL else
|
||||
1.4 if uiscale is ba.UIScale.MEDIUM else 1.0),
|
||||
stack_offset=(0, -25) if uiscale is ba.UIScale.SMALL else (0, 0)))
|
||||
|
||||
self._prev_lang = ''
|
||||
self._prev_lang_list: list[str] = []
|
||||
self._complete_langs_list: list | None = None
|
||||
|
|
@ -423,29 +424,6 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
v -= self._spacing * 2.1
|
||||
|
||||
this_button_width = 410
|
||||
self._show_user_mods_button = ba.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(self._sub_width / 2 - this_button_width / 2, v - 10),
|
||||
size=(this_button_width, 60),
|
||||
autoselect=True,
|
||||
label=ba.Lstr(resource=self._r + '.showUserModsText'),
|
||||
text_scale=1.0,
|
||||
on_activate_call=show_user_scripts)
|
||||
if self._show_always_use_internal_keyboard:
|
||||
assert self._always_use_internal_keyboard_check_box is not None
|
||||
ba.widget(edit=self._always_use_internal_keyboard_check_box.widget,
|
||||
down_widget=self._show_user_mods_button)
|
||||
ba.widget(
|
||||
edit=self._show_user_mods_button,
|
||||
up_widget=self._always_use_internal_keyboard_check_box.widget)
|
||||
else:
|
||||
ba.widget(edit=self._show_user_mods_button,
|
||||
up_widget=self._kick_idle_players_check_box.widget)
|
||||
ba.widget(edit=self._kick_idle_players_check_box.widget,
|
||||
down_widget=self._show_user_mods_button)
|
||||
|
||||
v -= self._spacing * 2.0
|
||||
|
||||
self._modding_guide_button = ba.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(self._sub_width / 2 - this_button_width / 2, v - 10),
|
||||
|
|
@ -454,8 +432,30 @@ class AdvancedSettingsWindow(ba.Window):
|
|||
label=ba.Lstr(resource=self._r + '.moddingGuideText'),
|
||||
text_scale=1.0,
|
||||
on_activate_call=ba.Call(
|
||||
ba.open_url,
|
||||
'http://www.froemling.net/docs/bombsquad-modding-guide'))
|
||||
ba.open_url, 'http://ballistica.net/wiki/modding-guide'))
|
||||
if self._show_always_use_internal_keyboard:
|
||||
assert self._always_use_internal_keyboard_check_box is not None
|
||||
ba.widget(edit=self._always_use_internal_keyboard_check_box.widget,
|
||||
down_widget=self._modding_guide_button)
|
||||
ba.widget(
|
||||
edit=self._modding_guide_button,
|
||||
up_widget=self._always_use_internal_keyboard_check_box.widget)
|
||||
else:
|
||||
ba.widget(edit=self._modding_guide_button,
|
||||
up_widget=self._kick_idle_players_check_box.widget)
|
||||
ba.widget(edit=self._kick_idle_players_check_box.widget,
|
||||
down_widget=self._modding_guide_button)
|
||||
|
||||
v -= self._spacing * 2.0
|
||||
|
||||
self._show_user_mods_button = ba.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(self._sub_width / 2 - this_button_width / 2, v - 10),
|
||||
size=(this_button_width, 60),
|
||||
autoselect=True,
|
||||
label=ba.Lstr(resource=self._r + '.showUserModsText'),
|
||||
text_scale=1.0,
|
||||
on_activate_call=show_user_scripts)
|
||||
|
||||
v -= self._spacing * 2.0
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import weakref
|
|||
from threading import Thread
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.error import CleanError
|
||||
import _ba
|
||||
import ba
|
||||
from bastd.ui.settings.testing import TestingWindow
|
||||
|
|
@ -148,10 +149,12 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
|
|||
call()
|
||||
duration = time.monotonic() - starttime
|
||||
_print(f'Succeeded in {duration:.2f}s.', color=(0, 1, 0))
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
import traceback
|
||||
duration = time.monotonic() - starttime
|
||||
_print(traceback.format_exc(), color=(1.0, 1.0, 0.3))
|
||||
msg = (str(exc)
|
||||
if isinstance(exc, CleanError) else traceback.format_exc())
|
||||
_print(msg, color=(1.0, 1.0, 0.3))
|
||||
_print(f'Failed in {duration:.2f}s.', color=(1, 0, 0))
|
||||
have_error[0] = True
|
||||
|
||||
|
|
@ -193,6 +196,9 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
|
|||
_print(f'\nContacting V2 master-server ({baseaddr})...')
|
||||
_print_test_results(lambda: _test_fetch(baseaddr))
|
||||
|
||||
_print('\nComparing local time to V2 server...')
|
||||
_print_test_results(_test_v2_time)
|
||||
|
||||
# Get V2 nearby zone
|
||||
with ba.app.net.zone_pings_lock:
|
||||
zone_pings = copy.deepcopy(ba.app.net.zone_pings)
|
||||
|
|
@ -206,6 +212,9 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
|
|||
_print(f'\nChecking nearest V2 zone ping ({nearstr})...')
|
||||
_print_test_results(lambda: _test_nearby_zone_ping(nearest_zone))
|
||||
|
||||
_print('\nSending V2 cloud message...')
|
||||
_print_test_results(_test_v2_cloud_message)
|
||||
|
||||
if have_error[0]:
|
||||
_print('\nDiagnostics complete. Some diagnostics failed.',
|
||||
color=(10, 0, 0))
|
||||
|
|
@ -271,12 +280,67 @@ def _test_v1_transaction() -> None:
|
|||
raise RuntimeError(results[0])
|
||||
|
||||
|
||||
def _test_v2_cloud_message() -> None:
|
||||
from dataclasses import dataclass
|
||||
import bacommon.cloud
|
||||
|
||||
@dataclass
|
||||
class _Results:
|
||||
errstr: str | None = None
|
||||
send_time: float | None = None
|
||||
response_time: float | None = None
|
||||
|
||||
results = _Results()
|
||||
|
||||
def _cb(response: bacommon.cloud.PingResponse | Exception) -> None:
|
||||
# Note: this runs in another thread so need to avoid exceptions.
|
||||
results.response_time = time.monotonic()
|
||||
if isinstance(response, Exception):
|
||||
results.errstr = str(response)
|
||||
if not isinstance(response, bacommon.cloud.PingResponse):
|
||||
results.errstr = f'invalid response type: {type(response)}.'
|
||||
|
||||
def _send() -> None:
|
||||
# Note: this runs in another thread so need to avoid exceptions.
|
||||
results.send_time = time.monotonic()
|
||||
ba.app.cloud.send_message_cb(bacommon.cloud.PingMessage(), _cb)
|
||||
|
||||
# This stuff expects to be run from the logic thread.
|
||||
ba.pushcall(_send, from_other_thread=True)
|
||||
|
||||
wait_start_time = time.monotonic()
|
||||
while True:
|
||||
if results.response_time is not None:
|
||||
break
|
||||
time.sleep(0.01)
|
||||
if time.monotonic() - wait_start_time > 10.0:
|
||||
raise RuntimeError('Timeout waiting for cloud message response')
|
||||
if results.errstr is not None:
|
||||
raise RuntimeError(results.errstr)
|
||||
|
||||
|
||||
def _test_v2_time() -> None:
|
||||
offset = ba.app.net.server_time_offset_hours
|
||||
if offset is None:
|
||||
raise RuntimeError('no time offset found;'
|
||||
' perhaps unable to communicate with v2 server?')
|
||||
if abs(offset) >= 2.0:
|
||||
raise CleanError(
|
||||
f'Your device time is off from world time by {offset:.1f} hours.\n'
|
||||
'This may cause network operations to fail due to your device\n'
|
||||
' incorrectly treating SSL certificates as not-yet-valid, etc.\n'
|
||||
'Check your device time and time-zone settings to fix this.\n')
|
||||
|
||||
|
||||
def _test_fetch(baseaddr: str) -> None:
|
||||
# pylint: disable=consider-using-with
|
||||
import urllib.request
|
||||
response = urllib.request.urlopen(urllib.request.Request(
|
||||
f'{baseaddr}/ping', None, {'User-Agent': _ba.app.user_agent_string}),
|
||||
timeout=10.0)
|
||||
response = urllib.request.urlopen(
|
||||
urllib.request.Request(f'{baseaddr}/ping', None,
|
||||
{'User-Agent': _ba.app.user_agent_string}),
|
||||
context=ba.app.net.sslcontext,
|
||||
timeout=10.0,
|
||||
)
|
||||
if response.getcode() != 200:
|
||||
raise RuntimeError(
|
||||
f'Got unexpected response code {response.getcode()}.')
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class PluginSettingsWindow(ba.Window):
|
|||
self._subcontainer = ba.columnwidget(parent=self._scrollwidget,
|
||||
selection_loops_to_parent=True)
|
||||
|
||||
if ba.app.meta.metascan is None:
|
||||
if ba.app.meta.scanresults is None:
|
||||
ba.screenmessage('Still scanning plugins; please try again.',
|
||||
color=(1, 0, 0))
|
||||
ba.playsound(ba.getsound('error'))
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window):
|
|||
from ba.osmusic import OSMusicPlayer
|
||||
from bastd.ui.fileselector import FileSelectorWindow
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
base_path = _ba.android_get_external_storage_path()
|
||||
base_path = _ba.android_get_external_files_dir()
|
||||
ba.app.ui.set_main_menu_window(
|
||||
FileSelectorWindow(
|
||||
base_path,
|
||||
|
|
@ -173,7 +173,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window):
|
|||
def _on_music_folder_press(self) -> None:
|
||||
from bastd.ui.fileselector import FileSelectorWindow
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
base_path = _ba.android_get_external_storage_path()
|
||||
base_path = _ba.android_get_external_files_dir()
|
||||
ba.app.ui.set_main_menu_window(
|
||||
FileSelectorWindow(base_path,
|
||||
callback=self._music_folder_selector_cb,
|
||||
|
|
|
|||
|
|
@ -182,8 +182,9 @@ class TournamentEntryWindow(popup.PopupWindow):
|
|||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.6,
|
||||
text=ba.Lstr(resource='watchAVideoText',
|
||||
fallback_resource='watchAnAdText'),
|
||||
# Note: AdMob now requires rewarded ad usage
|
||||
# specifically says 'Ad' in it.
|
||||
text=ba.Lstr(resource='watchAnAdText'),
|
||||
maxwidth=95,
|
||||
color=(0, 1, 0))
|
||||
ad_plays_remaining_text = (
|
||||
|
|
|
|||
10
dist/ba_data/python/bastd/ui/trophies.py
vendored
10
dist/ba_data/python/bastd/ui/trophies.py
vendored
|
|
@ -112,7 +112,7 @@ class TrophiesWindow(popup.PopupWindow):
|
|||
sub_width: int,
|
||||
trophy_types: list[list[str]]) -> int:
|
||||
from ba.internal import get_trophy_string
|
||||
pts = 0
|
||||
total_pts = 0
|
||||
for i, trophy_type in enumerate(trophy_types):
|
||||
t_count = self._data['t' + trophy_type[0]]
|
||||
t_mult = self._data['t' + trophy_type[0] + 'm']
|
||||
|
|
@ -157,7 +157,7 @@ class TrophiesWindow(popup.PopupWindow):
|
|||
h_align='center',
|
||||
v_align='center')
|
||||
|
||||
pts = t_count * t_mult
|
||||
this_pts = t_count * t_mult
|
||||
ba.textwidget(parent=self._subcontainer,
|
||||
position=(sub_width * 0.88,
|
||||
sub_height - 20 - incr * i),
|
||||
|
|
@ -167,12 +167,12 @@ class TrophiesWindow(popup.PopupWindow):
|
|||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
scale=0.5,
|
||||
text=eq_text.replace('${NUMBER}', str(pts)),
|
||||
text=eq_text.replace('${NUMBER}', str(this_pts)),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center')
|
||||
pts += pts
|
||||
return pts
|
||||
total_pts += this_pts
|
||||
return total_pts
|
||||
|
||||
def _on_cancel_press(self) -> None:
|
||||
self._transition_out()
|
||||
|
|
|
|||
64
dist/ba_data/python/efro/error.py
vendored
64
dist/ba_data/python/efro/error.py
vendored
|
|
@ -4,6 +4,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
import errno
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
|
@ -39,12 +40,13 @@ class CommunicationError(Exception):
|
|||
"""A communication related error has occurred.
|
||||
|
||||
This covers anything network-related going wrong in the sending
|
||||
of data or receiving of a response. This error does not imply
|
||||
of data or receiving of a response. Basically anything that is out
|
||||
of our control should get lumped in here. This error does not imply
|
||||
that data was not received on the other end; only that a full
|
||||
acknowledgement round trip was not completed.
|
||||
|
||||
These errors should be gracefully handled whenever possible, as
|
||||
occasional network outages are generally unavoidable.
|
||||
occasional network issues are unavoidable.
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -55,9 +57,9 @@ class RemoteError(Exception):
|
|||
occurs remotely. The error string can consist of a remote stack
|
||||
trace or a simple message depending on the context.
|
||||
|
||||
Communication systems should raise more specific error types when
|
||||
more introspection/control is needed; this is intended somewhat as
|
||||
a catch-all.
|
||||
Communication systems should raise more specific error types locally
|
||||
when more introspection/control is needed; this is intended somewhat
|
||||
as a catch-all.
|
||||
"""
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
|
@ -69,31 +71,43 @@ class IntegrityError(ValueError):
|
|||
"""Data has been tampered with or corrupted in some form."""
|
||||
|
||||
|
||||
def is_urllib_network_error(exc: BaseException) -> bool:
|
||||
"""Is the provided exception from urllib a network-related error?
|
||||
def is_urllib_communication_error(exc: BaseException, url: str | None) -> bool:
|
||||
"""Is the provided exception from urllib a communication-related error?
|
||||
|
||||
Url, if provided can provide extra context for when to treat an error
|
||||
as such an error.
|
||||
|
||||
This should be passed an exception which resulted from opening or
|
||||
reading a urllib Request. It returns True for any errors that could
|
||||
conceivably arise due to unavailable/poor network connections,
|
||||
firewall/connectivity issues, etc. These issues can often be safely
|
||||
ignored or presented to the user as general 'network-unavailable'
|
||||
states.
|
||||
firewall/connectivity issues, or other issues out of our control.
|
||||
These errors can often be safely ignored or presented to the user
|
||||
as general 'network-unavailable' states.
|
||||
"""
|
||||
import urllib.error
|
||||
import http.client
|
||||
import errno
|
||||
import socket
|
||||
if isinstance(
|
||||
exc,
|
||||
(urllib.error.URLError, ConnectionError, http.client.IncompleteRead,
|
||||
http.client.BadStatusLine, socket.timeout)):
|
||||
if isinstance(exc, (urllib.error.URLError, ConnectionError,
|
||||
http.client.IncompleteRead, http.client.BadStatusLine,
|
||||
http.client.RemoteDisconnected, socket.timeout)):
|
||||
|
||||
# Special case: although an HTTPError is a subclass of URLError,
|
||||
# we don't return True for it. It means we have successfully
|
||||
# communicated with the server but what we are asking for is
|
||||
# not there/etc.
|
||||
# we don't consider it a communication error. It generally means we
|
||||
# have successfully communicated with the server but what we are asking
|
||||
# for is not there/etc.
|
||||
if isinstance(exc, urllib.error.HTTPError):
|
||||
|
||||
# Special sub-case: appspot.com hosting seems to give 403 errors
|
||||
# (forbidden) to some countries. I'm assuming for legal reasons?..
|
||||
# Let's consider that a communication error since its out of our
|
||||
# control so we don't fill up logs with it.
|
||||
if exc.code == 403 and url is not None and '.appspot.com' in url:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
if isinstance(exc, OSError):
|
||||
if exc.errno == 10051: # Windows unreachable network error.
|
||||
return True
|
||||
|
|
@ -106,18 +120,17 @@ def is_urllib_network_error(exc: BaseException) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def is_udp_network_error(exc: BaseException) -> bool:
|
||||
"""Is the provided exception a network-related error?
|
||||
def is_udp_communication_error(exc: BaseException) -> bool:
|
||||
"""Should this udp-related exception be considered a communication error?
|
||||
|
||||
This should be passed an exception which resulted from creating and
|
||||
using a socket.SOCK_DGRAM type socket. It should return True for any
|
||||
errors that could conceivably arise due to unavailable/poor network
|
||||
connections, firewall/connectivity issues, etc. These issues can often
|
||||
conditions, firewall/connectivity issues, etc. These issues can often
|
||||
be safely ignored or presented to the user as general
|
||||
'network-unavailable' states.
|
||||
"""
|
||||
import errno
|
||||
if isinstance(exc, ConnectionRefusedError):
|
||||
if isinstance(exc, ConnectionRefusedError | TimeoutError):
|
||||
return True
|
||||
if isinstance(exc, OSError):
|
||||
if exc.errno == 10051: # Windows unreachable network error.
|
||||
|
|
@ -140,8 +153,8 @@ def is_udp_network_error(exc: BaseException) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def is_asyncio_streams_network_error(exc: BaseException) -> bool:
|
||||
"""Is the provided exception a network-related error?
|
||||
def is_asyncio_streams_communication_error(exc: BaseException) -> bool:
|
||||
"""Should this streams error be considered a communication error?
|
||||
|
||||
This should be passed an exception which resulted from creating and
|
||||
using asyncio streams. It should return True for any errors that could
|
||||
|
|
@ -149,7 +162,6 @@ def is_asyncio_streams_network_error(exc: BaseException) -> bool:
|
|||
firewall/connectivity issues, etc. These issues can often be safely
|
||||
ignored or presented to the user as general 'connection-lost' events.
|
||||
"""
|
||||
import errno
|
||||
import ssl
|
||||
|
||||
if isinstance(exc, (
|
||||
|
|
|
|||
1
dist/ba_data/python/efro/message/_message.py
vendored
1
dist/ba_data/python/efro/message/_message.py
vendored
|
|
@ -56,6 +56,7 @@ class ErrorResponse(Response):
|
|||
OTHER = 0
|
||||
CLEAN = 1
|
||||
LOCAL = 2
|
||||
COMMUNICATION = 3
|
||||
|
||||
error_message: Annotated[str, IOAttrs('m')]
|
||||
error_type: Annotated[ErrorType, IOAttrs('e')] = ErrorType.OTHER
|
||||
|
|
|
|||
49
dist/ba_data/python/efro/message/_protocol.py
vendored
49
dist/ba_data/python/efro/message/_protocol.py
vendored
|
|
@ -25,28 +25,40 @@ class MessageProtocol:
|
|||
"""Wrangles a set of message types, formats, and response types.
|
||||
Both endpoints must be using a compatible Protocol for communication
|
||||
to succeed. To maintain Protocol compatibility between revisions,
|
||||
all message types must retain the same id, message attr storage names must
|
||||
not change, newly added attrs must have default values, etc.
|
||||
all message types must retain the same id, message attr storage
|
||||
names must not change, newly added attrs must have default values,
|
||||
etc.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
message_types: dict[int, type[Message]],
|
||||
response_types: dict[int, type[Response]],
|
||||
preserve_clean_errors: bool = True,
|
||||
log_remote_exceptions: bool = True,
|
||||
trusted_sender: bool = False) -> None:
|
||||
receiver_logs_exceptions: bool = True,
|
||||
receiver_returns_stack_traces: bool = False) -> None:
|
||||
"""Create a protocol with a given configuration.
|
||||
|
||||
Note that common response types are automatically registered
|
||||
with (unchanging negative ids) so they don't need to be passed
|
||||
explicitly (but can be if a different id is desired).
|
||||
|
||||
If 'preserve_clean_errors' is True, efro.error.CleanError errors
|
||||
on the remote end will result in the same error raised locally.
|
||||
All other Exception types come across as efro.error.RemoteError.
|
||||
If 'preserve_clean_errors' is True, efro.error.CleanError
|
||||
exceptions raised on the receiver end will result in a matching
|
||||
CleanError raised back on the sender. All other Exception types
|
||||
come across as efro.error.RemoteError.
|
||||
|
||||
If 'trusted_sender' is True, stringified remote stack traces will
|
||||
be included in the responses if errors occur.
|
||||
When 'receiver_logs_exceptions' is True, any uncaught Exceptions
|
||||
on the receiver end will be logged there via logging.exception()
|
||||
(in addition to the usual behavior of returning an ErrorResponse
|
||||
to the sender). This is good to leave enabled if your
|
||||
intention is to never return ErrorResponses. Looser setups
|
||||
making routine use of CleanErrors or whatnot may want to
|
||||
disable this, however.
|
||||
|
||||
If 'receiver_returns_stack_traces' is True, stringified stack
|
||||
traces will be returned to the sender for exceptions occurring
|
||||
on the receiver end. This can make debugging easier but should
|
||||
only be used when the client is trusted to see such info.
|
||||
"""
|
||||
self.message_types_by_id: dict[int, type[Message]] = {}
|
||||
self.message_ids_by_type: dict[type[Message], int] = {}
|
||||
|
|
@ -102,9 +114,9 @@ class MessageProtocol:
|
|||
assert is_ioprepped_dataclass(cls)
|
||||
assert issubclass(cls, Response)
|
||||
if cls not in self.response_ids_by_type:
|
||||
raise ValueError(f'Possible response type {cls}'
|
||||
f' needs to be included in response_types'
|
||||
f' for this protocol.')
|
||||
raise ValueError(
|
||||
f'Possible response type {cls} needs to be included'
|
||||
f' in response_types for this protocol.')
|
||||
|
||||
# Make sure all registered types have unique base names.
|
||||
# We can take advantage of this to generate cleaner looking
|
||||
|
|
@ -116,8 +128,8 @@ class MessageProtocol:
|
|||
' all types are required to have unique names.')
|
||||
|
||||
self.preserve_clean_errors = preserve_clean_errors
|
||||
self.log_remote_exceptions = log_remote_exceptions
|
||||
self.trusted_sender = trusted_sender
|
||||
self.receiver_logs_exceptions = receiver_logs_exceptions
|
||||
self.receiver_returns_stack_traces = receiver_returns_stack_traces
|
||||
|
||||
@staticmethod
|
||||
def encode_dict(obj: dict) -> str:
|
||||
|
|
@ -134,7 +146,9 @@ class MessageProtocol:
|
|||
|
||||
def error_to_response(self, exc: Exception) -> Response:
|
||||
"""Translate an error to a response."""
|
||||
if self.log_remote_exceptions:
|
||||
|
||||
# Log any errors we got during handling if so desired.
|
||||
if self.receiver_logs_exceptions:
|
||||
logging.exception('Error handling message.')
|
||||
|
||||
# If anything goes wrong, return a ErrorResponse instead.
|
||||
|
|
@ -142,8 +156,9 @@ class MessageProtocol:
|
|||
return ErrorResponse(error_message=str(exc),
|
||||
error_type=ErrorResponse.ErrorType.CLEAN)
|
||||
return ErrorResponse(
|
||||
error_message=(traceback.format_exc() if self.trusted_sender else
|
||||
'An unknown error has occurred.'),
|
||||
error_message=(traceback.format_exc()
|
||||
if self.receiver_returns_stack_traces else
|
||||
'An internal error has occurred.'),
|
||||
error_type=ErrorResponse.ErrorType.OTHER)
|
||||
|
||||
def _to_dict(self, message: Any, ids_by_type: dict[type, int],
|
||||
|
|
|
|||
52
dist/ba_data/python/efro/message/_sender.py
vendored
52
dist/ba_data/python/efro/message/_sender.py
vendored
|
|
@ -9,7 +9,7 @@ from __future__ import annotations
|
|||
import logging
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
from efro.error import CleanError, RemoteError
|
||||
from efro.error import CleanError, RemoteError, CommunicationError
|
||||
from efro.message._message import EmptyResponse, ErrorResponse
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
|
@ -35,7 +35,7 @@ class MessageSender:
|
|||
def send_raw_message(self, message: str) -> str:
|
||||
# Actually send the message here.
|
||||
|
||||
# MyMessageSender class should provide overloads for send(), send_bg(),
|
||||
# MyMessageSender class should provide overloads for send(), send_async(),
|
||||
# etc. to ensure all sending happens with valid types.
|
||||
obj = MyClass()
|
||||
obj.msg.send(SomeMessageType())
|
||||
|
|
@ -54,7 +54,12 @@ class MessageSender:
|
|||
def send_method(
|
||||
self, call: Callable[[Any, str],
|
||||
str]) -> Callable[[Any, str], str]:
|
||||
"""Function decorator for setting raw send method."""
|
||||
"""Function decorator for setting raw send method.
|
||||
|
||||
Send methods take strings and should return strings.
|
||||
Any Exception raised during the send_method manifests as
|
||||
a CommunicationError for the message sender.
|
||||
"""
|
||||
assert self._send_raw_message_call is None
|
||||
self._send_raw_message_call = call
|
||||
return call
|
||||
|
|
@ -62,7 +67,12 @@ class MessageSender:
|
|||
def send_async_method(
|
||||
self, call: Callable[[Any, str], Awaitable[str]]
|
||||
) -> Callable[[Any, str], Awaitable[str]]:
|
||||
"""Function decorator for setting raw send-async method."""
|
||||
"""Function decorator for setting raw send-async method.
|
||||
|
||||
Send methods take strings and should return strings.
|
||||
Any Exception raised during the send_method manifests as
|
||||
a CommunicationError for the message sender.
|
||||
"""
|
||||
assert self._send_async_raw_message_call is None
|
||||
self._send_async_raw_message_call = call
|
||||
return call
|
||||
|
|
@ -123,7 +133,17 @@ class MessageSender:
|
|||
raise RuntimeError('send() is unimplemented for this type.')
|
||||
|
||||
msg_encoded = self._encode_message(bound_obj, message)
|
||||
response_encoded = self._send_raw_message_call(bound_obj, msg_encoded)
|
||||
try:
|
||||
response_encoded = self._send_raw_message_call(
|
||||
bound_obj, msg_encoded)
|
||||
except Exception as exc:
|
||||
# Any error in the raw send call gets recorded as either
|
||||
# a local or communication error.
|
||||
return ErrorResponse(
|
||||
error_message=f'Error in send async method: {exc}',
|
||||
error_type=(ErrorResponse.ErrorType.COMMUNICATION
|
||||
if isinstance(exc, CommunicationError) else
|
||||
ErrorResponse.ErrorType.LOCAL))
|
||||
return self._decode_raw_response(bound_obj, message, response_encoded)
|
||||
|
||||
async def send_split_part_1_async(self, bound_obj: Any,
|
||||
|
|
@ -139,9 +159,17 @@ class MessageSender:
|
|||
raise RuntimeError('send_async() is unimplemented for this type.')
|
||||
|
||||
msg_encoded = self._encode_message(bound_obj, message)
|
||||
response_encoded = await self._send_async_raw_message_call(
|
||||
bound_obj, msg_encoded)
|
||||
|
||||
try:
|
||||
response_encoded = await self._send_async_raw_message_call(
|
||||
bound_obj, msg_encoded)
|
||||
except Exception as exc:
|
||||
# Any error in the raw send call gets recorded as either
|
||||
# a local or communication error.
|
||||
return ErrorResponse(
|
||||
error_message=f'Error in send async method: {exc}',
|
||||
error_type=(ErrorResponse.ErrorType.COMMUNICATION
|
||||
if isinstance(exc, CommunicationError) else
|
||||
ErrorResponse.ErrorType.LOCAL))
|
||||
return self._decode_raw_response(bound_obj, message, response_encoded)
|
||||
|
||||
def send_split_part_2(self, message: Message,
|
||||
|
|
@ -183,8 +211,8 @@ class MessageSender:
|
|||
# If we got to this point, we successfully communicated
|
||||
# with the other end so errors represent protocol mismatches
|
||||
# or other invalid data. For now let's just log it but perhaps
|
||||
# we'd want to somehow embed it in the ErrorResponse to be raised
|
||||
# directly to the user later.
|
||||
# we'd want to somehow embed it in the ErrorResponse to be
|
||||
# available directly to the user later.
|
||||
logging.exception('Error decoding raw response')
|
||||
response = ErrorResponse(
|
||||
error_message=
|
||||
|
|
@ -208,6 +236,10 @@ class MessageSender:
|
|||
# Some error occurred. Raise a local Exception for it.
|
||||
if isinstance(raw_response, ErrorResponse):
|
||||
|
||||
if (raw_response.error_type is
|
||||
ErrorResponse.ErrorType.COMMUNICATION):
|
||||
raise CommunicationError(raw_response.error_message)
|
||||
|
||||
# If something went wrong on our end of the connection,
|
||||
# don't say it was a remote error.
|
||||
if raw_response.error_type is ErrorResponse.ErrorType.LOCAL:
|
||||
|
|
|
|||
5
dist/ba_data/python/efro/rpc.py
vendored
5
dist/ba_data/python/efro/rpc.py
vendored
|
|
@ -13,8 +13,9 @@ from dataclasses import dataclass
|
|||
from threading import current_thread
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
from efro.error import CommunicationError, is_asyncio_streams_network_error
|
||||
from efro.util import assert_never
|
||||
from efro.error import (CommunicationError,
|
||||
is_asyncio_streams_communication_error)
|
||||
from efro.dataclassio import (dataclass_to_json, dataclass_from_json,
|
||||
ioprepped, IOAttrs)
|
||||
|
||||
|
|
@ -596,7 +597,7 @@ class RPCEndpoint:
|
|||
if isinstance(exc, _KeepaliveTimeoutError):
|
||||
return True
|
||||
|
||||
return is_asyncio_streams_network_error(exc)
|
||||
return is_asyncio_streams_communication_error(exc)
|
||||
|
||||
def _check_env(self) -> None:
|
||||
# I was seeing that asyncio stuff wasn't working as expected if
|
||||
|
|
|
|||
4
dist/ba_data/python/efro/util.py
vendored
4
dist/ba_data/python/efro/util.py
vendored
|
|
@ -637,9 +637,11 @@ def compact_id(num: int) -> str:
|
|||
'abcdefghijklmnopqrstuvwxyz')
|
||||
|
||||
|
||||
# NOTE: Even though this is available as part of typing_extensions, keeping
|
||||
# it in here for now so we don't require typing_extensions as a dependency.
|
||||
# Once 3.11 rolls around we can kill this and use typing.assert_never.
|
||||
def assert_never(value: NoReturn) -> NoReturn:
|
||||
"""Trick for checking exhaustive handling of Enums, etc.
|
||||
|
||||
See https://github.com/python/typing/issues/735
|
||||
"""
|
||||
assert False, f'Unhandled value: {value} ({type(value).__name__})'
|
||||
|
|
|
|||
BIN
dist/bombsquad_headless
vendored
BIN
dist/bombsquad_headless
vendored
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue